Skip to content

Commit

Permalink
[FAB-11354] Process issue request with a plain issuer
Browse files Browse the repository at this point in the history
- Implement TMSManager to return a plain issuer
- Implement tests to issue tokens with a plain issuer
- Implement tests to simulate a client calling prover grpc service

Change-Id: I1dd069e1582bed2c7fba802df40b48c4298092dd
Signed-off-by: Wenjian Qiao <wenjianq@gmail.com>
  • Loading branch information
wenjianqiao committed Oct 30, 2018
1 parent 6be0455 commit 60f968d
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 2 deletions.
23 changes: 23 additions & 0 deletions token/server/manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package server

import (
"github.com/hyperledger/fabric/token/tms/plain"
)

// Manager implements token/server/TMSManager interface
// TODO: it will be updated after lscc-baased tms configuration is available
type Manager struct {
}

// For now it returns a plain issuer.
// After lscc-based tms configuration is available, it will be updated
// to return an issuer configured for the specific channel
func (t *Manager) GetIssuer(channel string, privateCredential, publicCredential []byte) (Issuer, error) {
return &plain.Issuer{}, nil
}
25 changes: 25 additions & 0 deletions token/server/manager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package server_test

import (
"github.com/hyperledger/fabric/token/server"
"github.com/hyperledger/fabric/token/tms/plain"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Manager", func() {
Describe("GetIssuer", func() {
It("returns a plain issuer", func() {
Manager := &server.Manager{}
issuer, err := Manager.GetIssuer("test-channel", []byte("private-credential"), []byte("public-credential"))
Expect(err).NotTo(HaveOccurred())
Expect(issuer).To(Equal(&plain.Issuer{}))
})
})
})
176 changes: 174 additions & 2 deletions token/server/prover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ package server_test

import (
"context"
"net"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/protos/token"
"github.com/hyperledger/fabric/token/server"
"github.com/hyperledger/fabric/token/server/mock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/pkg/errors"
"google.golang.org/grpc"
)

var _ = Describe("Prover", func() {
Expand Down Expand Up @@ -294,7 +297,7 @@ var _ = Describe("Prover", func() {
fakeTMSManager.GetIssuerReturns(nil, errors.New("boing boing"))
})

It("retuns the error", func() {
It("returns the error", func() {
_, err := prover.RequestImport(context.Background(), command.Header, importRequest)
Expect(err).To(MatchError("boing boing"))
})
Expand All @@ -305,10 +308,179 @@ var _ = Describe("Prover", func() {
fakeIssuer.RequestImportReturns(nil, errors.New("watermelon"))
})

It("retuns the error", func() {
It("returns the error", func() {
_, err := prover.RequestImport(context.Background(), command.Header, importRequest)
Expect(err).To(MatchError("watermelon"))
})
})
})

Describe("Issue tokens by a plain issuer", func() {
var (
manager *server.Manager
expectedTokenTx *token.TokenTransaction
)

BeforeEach(func() {
prover = &server.Prover{
PolicyChecker: fakePolicyChecker,
Marshaler: fakeMarshaler,
TMSManager: manager,
}
importRequest = &token.ImportRequest{
Credential: []byte("credential"),
TokensToIssue: []*token.TokenToIssue{
{
Recipient: []byte("recipient1"),
Type: "XYZ1",
Quantity: 10,
},
{
Recipient: []byte("recipient2"),
Type: "XYZ2",
Quantity: 200,
},
},
}

plainOutputs := []*token.PlainOutput{
{
Owner: []byte("recipient1"),
Type: "XYZ1",
Quantity: 10,
},
{
Owner: []byte("recipient2"),
Type: "XYZ2",
Quantity: 200,
},
}
expectedTokenTx = &token.TokenTransaction{
Action: &token.TokenTransaction_PlainAction{
PlainAction: &token.PlainTokenAction{
Data: &token.PlainTokenAction_PlainImport{
PlainImport: &token.PlainImport{
Outputs: plainOutputs,
},
},
},
},
}
})

Describe("RequestImport", func() {
It("returns a TokenTransaction response", func() {
resp, err := prover.RequestImport(context.Background(), command.Header, importRequest)
Expect(err).NotTo(HaveOccurred())
Expect(resp).To(Equal(&token.CommandResponse_TokenTransaction{
TokenTransaction: expectedTokenTx,
}))
Expect(fakeIssuer.RequestImportCallCount()).To(Equal(0))
})
})

Describe("ProcessCommand", func() {
It("marshals a TokenTransaction response", func() {
command = &token.Command{
Header: &token.Header{
ChannelId: "channel-id",
Creator: []byte("creator"),
Nonce: []byte("nonce"),
},
Payload: &token.Command_ImportRequest{
ImportRequest: importRequest,
},
}
marshaledCommand = ProtoMarshal(command)
signedCommand = &token.SignedCommand{
Command: marshaledCommand,
Signature: []byte("command-signature"),
}

resp, err := prover.ProcessCommand(context.Background(), signedCommand)
Expect(err).NotTo(HaveOccurred())
Expect(resp).To(Equal(marshaledResponse))

Expect(fakeIssuer.RequestImportCallCount()).To(Equal(0))
Expect(fakeMarshaler.MarshalCommandResponseCallCount()).To(Equal(1))
cmd, payload := fakeMarshaler.MarshalCommandResponseArgsForCall(0)
Expect(cmd).To(Equal(marshaledCommand))
Expect(payload).To(Equal(&token.CommandResponse_TokenTransaction{
TokenTransaction: expectedTokenTx,
}))
})
})

Describe("ProcessCommand via prover client", func() {
var (
fakeSignerIdentity *mock.SignerIdentity
marshaler *server.ResponseMarshaler
proverEndpoint string
grpcSrv *grpc.Server
)

BeforeEach(func() {
fakeSignerIdentity = &mock.SignerIdentity{}
fakeSignerIdentity.SerializeReturns([]byte("response_creator"), nil)
fakeSignerIdentity.SignReturns([]byte("response_signature"), nil)
marshaler, _ = server.NewResponseMarshaler(fakeSignerIdentity)

prover = &server.Prover{
PolicyChecker: fakePolicyChecker,
Marshaler: marshaler,
TMSManager: manager,
}

// start grpc server for prover
listener, err := net.Listen("tcp", "127.0.0.1:")
Expect(err).To(BeNil())
grpcSrv = grpc.NewServer()
token.RegisterProverServer(grpcSrv, prover)
go grpcSrv.Serve(listener)

proverEndpoint = listener.Addr().String()

// prepare SignedCommand for grpc request
command = &token.Command{
Header: &token.Header{
ChannelId: "channel-id",
Creator: []byte("response_creator"),
Nonce: []byte("nonce"),
},
Payload: &token.Command_ImportRequest{
ImportRequest: importRequest,
},
}
signedCommand = &token.SignedCommand{
Command: ProtoMarshal(command),
Signature: []byte("command-signature"),
}
})

AfterEach(func() {
grpcSrv.Stop()
})

It("returns expected response", func() {
// create grpc client
clientConn, err := grpc.Dial(proverEndpoint, grpc.WithInsecure())
Expect(err).To(BeNil())
defer clientConn.Close()
proverClient := token.NewProverClient(clientConn)

resp, err := proverClient.ProcessCommand(context.Background(), signedCommand)
Expect(err).NotTo(HaveOccurred())

// cannot compare entire response because Timestamp field has dynamic value
// compare TokenTransanction, header field and signature individually
commandResp := &token.CommandResponse{}
err = proto.Unmarshal(resp.Response, commandResp)
Expect(err).NotTo(HaveOccurred())
Expect(commandResp.GetTokenTransaction()).To(Equal(expectedTokenTx))
Expect(commandResp.Header.Creator).To(Equal([]byte("response_creator")))
Expect(commandResp.Header.CommandHash).To(Equal(util.ComputeSHA256(ProtoMarshal(command))))
Expect(resp.Signature).To(Equal([]byte("response_signature")))
})
})
})
})

0 comments on commit 60f968d

Please sign in to comment.