From bed99499fee2ada7ea5dfd085530c1f253b6e78d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Martinovi=C4=87?= Date: Fri, 17 May 2019 13:30:04 +0200 Subject: [PATCH] Tests for extended cpaper example and improved docs (#16) * Improve example comments * Fix some grammar and formatting issues * Better explained what List method does * Simplify cpaper example and add tests * cpaper example follows the basic logic from original example * remove proto schema data from basic example * cpaper tests provide usage and further explanation * Fix docs function names, add single identity load method * Implement revoke for cpaper extended example and add tests * cpaper extended contains additional features * minor formatting fixes in proto files * Fix lint error about SNAKE_CASE, correct BuyerName * Better variable names, add event checks in cpaper_extended tests * Add more info into READMEs for cpaper and cpaper_extended * Add new mapping test proto schema and regenerate proto files * Add test chaincode for proto mapping and uniq key * Add tests with proto mapping and uniq key --- examples/cpaper/README.md | 9 +- examples/cpaper/chaincode.go | 241 +++++++++++------- examples/cpaper/chaincode_test.go | 100 +++++++- examples/cpaper/schema/Makefile | 5 - examples/cpaper/schema/payload.pb.go | 216 ---------------- examples/cpaper/schema/payload.proto | 31 --- examples/cpaper/schema/state.pb.go | 177 ------------- examples/cpaper/schema/state.proto | 35 --- examples/cpaper/testdata/testdata.go | 32 --- examples/cpaper_extended/README.md | 12 +- examples/cpaper_extended/chaincode.go | 144 +++++++---- examples/cpaper_extended/chaincode_test.go | 175 ++++++++++++- .../schema/payload.validator.pb.go | 77 +++--- examples/cpaper_extended/schema/state.pb.go | 7 +- examples/cpaper_extended/schema/state.proto | 10 +- .../schema/state.validator.pb.go | 24 +- .../testdata/admin/admin.key.pem | 6 + .../cpaper_extended/testdata/admin/admin.pem | 15 ++ examples/cpaper_extended/testdata/testdata.go | 36 +-- state/mapping/mapping_test.go | 220 +++++++--------- state/mapping/testdata/cc_proto_entity.go | 93 +++++++ .../mapping/testdata/schema/complex_id.pb.go | 6 + .../testdata/schema/proto_schema.pb.go | 208 +++++++++++++++ .../testdata/schema/proto_schema.proto | 37 +++ state/mapping/testdata/schema/slice_id.pb.go | 6 +- state/mapping/testdata/testdata.go | 36 +++ testing/identity.go | 14 +- 27 files changed, 1099 insertions(+), 873 deletions(-) delete mode 100644 examples/cpaper/schema/Makefile delete mode 100644 examples/cpaper/schema/payload.pb.go delete mode 100644 examples/cpaper/schema/payload.proto delete mode 100644 examples/cpaper/schema/state.pb.go delete mode 100644 examples/cpaper/schema/state.proto delete mode 100644 examples/cpaper/testdata/testdata.go create mode 100644 examples/cpaper_extended/testdata/admin/admin.key.pem create mode 100644 examples/cpaper_extended/testdata/admin/admin.pem create mode 100644 state/mapping/testdata/cc_proto_entity.go create mode 100644 state/mapping/testdata/schema/proto_schema.pb.go create mode 100644 state/mapping/testdata/schema/proto_schema.proto create mode 100644 state/mapping/testdata/testdata.go diff --git a/examples/cpaper/README.md b/examples/cpaper/README.md index a25bece8..02439898 100644 --- a/examples/cpaper/README.md +++ b/examples/cpaper/README.md @@ -1,8 +1,5 @@ -# Commercial paper Hyperledger Fabric chaincode example with protobuf based state schema +# Commercial paper Hyperledger Fabric chaincode example -https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/scenario.html +This is an faithful reimplementation of the official example [Commercial paper scenario](https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/scenario.html) - -At the heart of a blockchain network is a smart contract. In PaperNet, the code in the commercial paper smart -contract defines the valid states for commercial paper, and the transaction logic that transition -a paper from one state to another. \ No newline at end of file +Original code written in JavaScript using the Fabric Chaincode Node SDK is available [here](https://github.com/hyperledger/fabric-samples/tree/release-1.4/commercial-paper/organization/digibank/contract) diff --git a/examples/cpaper/chaincode.go b/examples/cpaper/chaincode.go index 0143b987..28bdbad4 100644 --- a/examples/cpaper/chaincode.go +++ b/examples/cpaper/chaincode.go @@ -2,145 +2,200 @@ package cpaper import ( "fmt" + "github.com/s7techlab/cckit/router/param" + "time" "github.com/pkg/errors" - "github.com/s7techlab/cckit/examples/cpaper/schema" - "github.com/s7techlab/cckit/extensions/debug" - "github.com/s7techlab/cckit/extensions/owner" "github.com/s7techlab/cckit/router" - "github.com/s7techlab/cckit/router/param/defparam" - m "github.com/s7techlab/cckit/state/mapping" ) -var ( - // State mappings - StateMappings = m.StateMappings{}.Add( - &schema.CommercialPaper{}, // define mapping for this structure - m.PKeySchema(&schema.CommercialPaperId{}), // key will be <`CommercialPaper`, Issuer, PaperNumber> - m.List(&schema.CommercialPaperList{})) // structure-result of list method - - // EventMappings - EventMappings = m.EventMappings{}. - Add(&schema.IssueCommercialPaper{}). // event name will be `IssueCommercialPaper`, payload - same as issue payload - Add(&schema.BuyCommercialPaper{}). - Add(&schema.RedeemCommercialPaper{}) +type TaskState string + +const ( + CommercialPaperTypeName = "CommercialPaper" + + CommercialPaperIssued TaskState = "issued" + CommercialPaperTrading TaskState = "trading" + CommercialPaperRedeemed TaskState = "redeemed" ) -func NewCC() *router.Chaincode { +type CommercialPaper struct { + Issuer string `json:"issuer,omitempty"` + PaperNumber string `json:"paper_number,omitempty"` + Owner string `json:"owner,omitempty"` + IssueDate time.Time `json:"issue_date,omitempty"` + MaturityDate time.Time `json:"maturity_date,omitempty"` + FaceValue int32 `json:"face_value,omitempty"` + State TaskState `json:"state,omitempty"` +} - r := router.New(`commercial_paper`) +// Comercial paper has a composite key <`CommercialPaper`, Issuer, PaperNumber> +func (c CommercialPaper) Key() ([]string, error) { + return []string{CommercialPaperTypeName, c.Issuer, c.PaperNumber}, nil +} - // Mappings for chaincode state - r.Use(m.MapStates(StateMappings)) +type IssueCommercialPaper struct { + Issuer string `json:"issuer,omitempty"` + PaperNumber string `json:"paper_number,omitempty"` + IssueDate time.Time `json:"issue_date,omitempty"` + MaturityDate time.Time `json:"maturity_date,omitempty"` + FaceValue int32 `json:"face_value,omitempty"` +} - // Mappings for chaincode events - r.Use(m.MapEvents(EventMappings)) +type BuyCommercialPaper struct { + Issuer string `json:"issuer,omitempty"` + PaperNumber string `json:"paper_number,omitempty"` + CurrentOwner string `json:"current_owner,omitempty"` + NewOwner string `json:"new_owner,omitempty"` + Price int32 `json:"price,omitempty"` + PurchaseDate time.Time `json:"purchase_date,omitempty"` +} - // store in chaincode state information about chaincode first instantiator - r.Init(owner.InvokeSetFromCreator) +type RedeemCommercialPaper struct { + Issuer string `json:"issuer,omitempty"` + PaperNumber string `json:"paper_number,omitempty"` + RedeemingOwner string `json:"redeeming_owner,omitempty"` + RedeemDate time.Time `json:"redeem_date,omitempty"` +} - // method for debug chaincode state - debug.AddHandlers(r, `debug`, owner.Only) +func NewCC() *router.Chaincode { + r := router.New(`commercial_paper`) - r. - // read methods - Query(`list`, cpaperList). + r.Init(func(context router.Context) (i interface{}, e error) { + // No implementation required with this example + // It could be where data migration is performed, if necessary + return nil, nil + }) + r. + // Read methods + Query(`list`, list). // Get method has 2 params - commercial paper primary key components - Query(`get`, cpaperGet, defparam.Proto(&schema.CommercialPaperId{})). + Query(`get`, get, param.String("issuer"), param.String("paper_number")). - // txn methods - Invoke(`issue`, cpaperIssue, defparam.Proto(&schema.IssueCommercialPaper{})). - Invoke(`buy`, cpaperBuy, defparam.Proto(&schema.BuyCommercialPaper{})). - Invoke(`redeem`, cpaperRedeem, defparam.Proto(&schema.RedeemCommercialPaper{})). - Invoke(`delete`, cpaperDelete, defparam.Proto(&schema.CommercialPaperId{})) + // Transaction methods + Invoke(`issue`, issue, param.Struct("issueData", &IssueCommercialPaper{})). + Invoke(`buy`, buy, param.Struct("buyData", &BuyCommercialPaper{})). + Invoke(`redeem`, redeem, param.Struct("redeemData", &RedeemCommercialPaper{})) return router.NewChaincode(r) } -func cpaperList(c router.Context) (interface{}, error) { - // commercial paper key is composite key <`CommercialPaper`>, {Issuer}, {PaperNumber} > - // where `CommercialPaper` - namespace of this type - // list method retrieves entries from chaincode state - // using GetStateByPartialCompositeKey method, then unmarshal received from state bytes via proto.Ummarshal method - // and creates slice of *schema.CommercialPaper - return c.State().List(&schema.CommercialPaper{}) -} - -func cpaperIssue(c router.Context) (interface{}, error) { +func get(c router.Context) (interface{}, error) { var ( - issue = c.Param().(*schema.IssueCommercialPaper) //default parameter - cpaper = &schema.CommercialPaper{ - Issuer: issue.Issuer, - PaperNumber: issue.PaperNumber, - Owner: issue.Issuer, - IssueDate: issue.IssueDate, - MaturityDate: issue.MaturityDate, - FaceValue: issue.FaceValue, - State: schema.CommercialPaper_ISSUED, // initial state - } - err error + issuer = c.ParamString("issuer") + paperNumber = c.ParamString("paper_number") ) - if err = c.Event().Set(issue); err != nil { - return nil, err - } - - return cpaper, c.State().Insert(cpaper) + return c.State().Get(&CommercialPaper{ + Issuer: issuer, + PaperNumber: paperNumber, + }) } -func cpaperBuy(c router.Context) (interface{}, error) { +func list(c router.Context) (interface{}, error) { + // List method retrieves all entries from the ledger using GetStateByPartialCompositeKey method and passing it the + // namespace of our contract type, in this example that's `CommercialPaper`, then it unmarshals received bytes via + // json.Ummarshal method and creates a JSON array of CommercialPaper entities + return c.State().List(CommercialPaperTypeName, &CommercialPaper{}) +} +func issue(c router.Context) (interface{}, error) { var ( - cpaper *schema.CommercialPaper + issueData = c.Param("issueData").(IssueCommercialPaper) // Assert the chaincode parameter + commercialPaper = &CommercialPaper{ + Issuer: issueData.Issuer, + PaperNumber: issueData.PaperNumber, + Owner: issueData.Issuer, + IssueDate: issueData.IssueDate, + MaturityDate: issueData.MaturityDate, + FaceValue: issueData.FaceValue, + State: CommercialPaperIssued, // Initial state + } + ) - // but tx payload - buy = c.Param().(*schema.BuyCommercialPaper) + return commercialPaper, c.State().Insert(commercialPaper) +} - // current commercial paper state - cp, err = c.State().Get( - &schema.CommercialPaperId{Issuer: buy.Issuer, PaperNumber: buy.PaperNumber}, - &schema.CommercialPaper{}) +func buy(c router.Context) (interface{}, error) { + var ( + commercialPaper CommercialPaper + // Buy transaction payload + buyData = c.Param("buyData").(BuyCommercialPaper) + + // Get the current commercial paper state + cp, err = c.State().Get(&CommercialPaper{ + Issuer: buyData.Issuer, + PaperNumber: buyData.PaperNumber, + }, &CommercialPaper{}) ) if err != nil { - return nil, errors.Wrap(err, `not found`) + return nil, errors.Wrap(err, "paper not found") } - cpaper = cp.(*schema.CommercialPaper) + + commercialPaper = cp.(CommercialPaper) // Validate current owner - if cpaper.Owner != buy.CurrentOwner { - return nil, fmt.Errorf(`paper %s %s is not owned by %s`, cpaper.Issuer, cpaper.PaperNumber, buy.CurrentOwner) + if commercialPaper.Owner != buyData.CurrentOwner { + return nil, fmt.Errorf( + "paper %s %s is not owned by %s", + commercialPaper.Issuer, commercialPaper.PaperNumber, buyData.CurrentOwner) } - // First buy moves state from ISSUED to TRADING - if cpaper.State == schema.CommercialPaper_ISSUED { - cpaper.State = schema.CommercialPaper_TRADING + // First buyData moves state from ISSUED to TRADING + if commercialPaper.State == CommercialPaperIssued { + commercialPaper.State = CommercialPaperTrading } // Check paper is not already REDEEMED - if cpaper.State == schema.CommercialPaper_TRADING { - cpaper.Owner = buy.NewOwner + if commercialPaper.State == CommercialPaperTrading { + commercialPaper.Owner = buyData.NewOwner } else { - return nil, fmt.Errorf(`paper %s %s is not trading.current state = %s`, cpaper.Issuer, cpaper.PaperNumber, cpaper.State) + return nil, fmt.Errorf( + "paper %s %s is not trading.current state = %s", + commercialPaper.Issuer, commercialPaper.PaperNumber, commercialPaper.State) } - if err = c.Event().Set(buy); err != nil { - return nil, err + return commercialPaper, c.State().Put(commercialPaper) +} + +func redeem(c router.Context) (interface{}, error) { + var ( + commercialPaper CommercialPaper + + // Buy transaction payload + redeemData = c.Param("redeemData").(RedeemCommercialPaper) + + // Get the current commercial paper state + cp, err = c.State().Get(&CommercialPaper{ + Issuer: redeemData.Issuer, + PaperNumber: redeemData.PaperNumber, + }, &CommercialPaper{}) + ) + + if err != nil { + return nil, errors.Wrap(err, "paper not found") } - return cpaper, c.State().Put(cpaper) -} + commercialPaper = cp.(CommercialPaper) -func cpaperRedeem(c router.Context) (interface{}, error) { - // implement me - return nil, nil -} + // Check paper is not REDEEMED + if commercialPaper.State == CommercialPaperRedeemed { + return nil, fmt.Errorf( + "paper %s %s is already redeemed", + commercialPaper.Issuer, commercialPaper.PaperNumber) + } -func cpaperGet(c router.Context) (interface{}, error) { - return c.State().Get(c.Param().(*schema.CommercialPaperId)) -} + // Verify that the redeemer owns the commercial paper before redeeming it + if commercialPaper.Owner == redeemData.RedeemingOwner { + commercialPaper.Owner = redeemData.Issuer + commercialPaper.State = CommercialPaperRedeemed + } else { + return nil, fmt.Errorf( + "redeeming owner does not own paper %s %s", + commercialPaper.Issuer, commercialPaper.PaperNumber) + } -func cpaperDelete(c router.Context) (interface{}, error) { - return nil, c.State().Delete(c.Param().(*schema.CommercialPaperId)) + return commercialPaper, c.State().Put(commercialPaper) } diff --git a/examples/cpaper/chaincode_test.go b/examples/cpaper/chaincode_test.go index 7962ebc1..d8d3be14 100644 --- a/examples/cpaper/chaincode_test.go +++ b/examples/cpaper/chaincode_test.go @@ -1 +1,99 @@ -package cpaper_test +package cpaper + +import ( + "testing" + "time" + + testcc "github.com/s7techlab/cckit/testing" + expectcc "github.com/s7techlab/cckit/testing/expect" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +const ( + IssuerName = "SomeIssuer" + BuyerName = "SomeBuyer" +) + +func TestCommercialPaper(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Commercial Paper Suite") +} + +var _ = Describe(`CommercialPaper`, func() { + paperChaincode := testcc.NewMockStub(`commercial_paper`, NewCC()) + + BeforeSuite(func() { + expectcc.ResponseOk(paperChaincode.Init()) + }) + + Describe("Commercial Paper lifecycle", func() { + + It("Allow issuer to issue new commercial paper", func() { + //invoke chaincode method from authority actor + expectcc.ResponseOk(paperChaincode.Invoke(`issue`, &IssueCommercialPaper{ + Issuer: IssuerName, + PaperNumber: "0001", + IssueDate: time.Now(), + MaturityDate: time.Now().Add(time.Hour * 24 * 30 * 6), // Six months later + FaceValue: 100000, + })) + }) + + It("Allow issuer to get commercial paper", func() { + queryResponse := paperChaincode.Query("get", IssuerName, "0001") + paper := expectcc.PayloadIs(queryResponse, &CommercialPaper{}).(CommercialPaper) + + Expect(paper.Issuer).To(Equal(IssuerName)) + Expect(paper.Owner).To(Equal(IssuerName)) + Expect(paper.State).To(Equal(CommercialPaperIssued)) + Expect(paper.PaperNumber).To(Equal("0001")) + Expect(paper.FaceValue).To(BeNumerically("==", 100000)) + }) + + It("Allow issuer to get a list of commercial papers", func() { + queryResponse := paperChaincode.Query("list") + papers := expectcc.PayloadIs(queryResponse, &[]CommercialPaper{}).([]CommercialPaper) + + Expect(len(papers)).To(BeNumerically("==", 1)) + Expect(papers[0].Issuer).To(Equal(IssuerName)) + Expect(papers[0].Owner).To(Equal(IssuerName)) + Expect(papers[0].State).To(Equal(CommercialPaperIssued)) + Expect(papers[0].PaperNumber).To(Equal("0001")) + Expect(papers[0].FaceValue).To(BeNumerically("==", 100000)) + }) + + It("Allow buyer to buy commercial paper", func() { + //invoke chaincode method from authority actor + expectcc.ResponseOk(paperChaincode.Invoke(`buy`, &BuyCommercialPaper{ + Issuer: IssuerName, + PaperNumber: "0001", + CurrentOwner: IssuerName, + NewOwner: BuyerName, + Price: 95000, + PurchaseDate: time.Now(), + })) + + queryResponse := paperChaincode.Query("get", IssuerName, "0001") + paper := expectcc.PayloadIs(queryResponse, &CommercialPaper{}).(CommercialPaper) + Expect(paper.Owner).To(Equal(BuyerName)) + Expect(paper.State).To(Equal(CommercialPaperTrading)) + }) + + It("Allow buyer to redeem commercial paper", func() { + //invoke chaincode method from authority actor + expectcc.ResponseOk(paperChaincode.Invoke(`redeem`, &RedeemCommercialPaper{ + Issuer: IssuerName, + PaperNumber: "0001", + RedeemingOwner: BuyerName, + RedeemDate: time.Now(), + })) + + queryResponse := paperChaincode.Query("get", IssuerName, "0001") + paper := expectcc.PayloadIs(queryResponse, &CommercialPaper{}).(CommercialPaper) + Expect(paper.Owner).To(Equal(IssuerName)) + Expect(paper.State).To(Equal(CommercialPaperRedeemed)) + }) + }) +}) diff --git a/examples/cpaper/schema/Makefile b/examples/cpaper/schema/Makefile deleted file mode 100644 index 6e4bb0c2..00000000 --- a/examples/cpaper/schema/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -.: generate - -generate: - @echo "schema" - @protoc -I=./ --go_out=./ ./*.proto \ No newline at end of file diff --git a/examples/cpaper/schema/payload.pb.go b/examples/cpaper/schema/payload.pb.go deleted file mode 100644 index 7c331da8..00000000 --- a/examples/cpaper/schema/payload.pb.go +++ /dev/null @@ -1,216 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: payload.proto - -/* -Package schema is a generated protocol buffer package. - -It is generated from these files: - payload.proto - state.proto - -It has these top-level messages: - IssueCommercialPaper - BuyCommercialPaper - RedeemCommercialPaper - CommercialPaper - CommercialPaperId - CommercialPaperList -*/ -package schema - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import google_protobuf "github.com/golang/protobuf/ptypes/timestamp" - -// 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 - -// IssueCommercialPaper event -type IssueCommercialPaper struct { - Issuer string `protobuf:"bytes,1,opt,name=issuer" json:"issuer,omitempty"` - PaperNumber string `protobuf:"bytes,2,opt,name=paper_number,json=paperNumber" json:"paper_number,omitempty"` - IssueDate *google_protobuf.Timestamp `protobuf:"bytes,3,opt,name=issue_date,json=issueDate" json:"issue_date,omitempty"` - MaturityDate *google_protobuf.Timestamp `protobuf:"bytes,4,opt,name=maturity_date,json=maturityDate" json:"maturity_date,omitempty"` - FaceValue int32 `protobuf:"varint,5,opt,name=face_value,json=faceValue" json:"face_value,omitempty"` -} - -func (m *IssueCommercialPaper) Reset() { *m = IssueCommercialPaper{} } -func (m *IssueCommercialPaper) String() string { return proto.CompactTextString(m) } -func (*IssueCommercialPaper) ProtoMessage() {} -func (*IssueCommercialPaper) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -func (m *IssueCommercialPaper) GetIssuer() string { - if m != nil { - return m.Issuer - } - return "" -} - -func (m *IssueCommercialPaper) GetPaperNumber() string { - if m != nil { - return m.PaperNumber - } - return "" -} - -func (m *IssueCommercialPaper) GetIssueDate() *google_protobuf.Timestamp { - if m != nil { - return m.IssueDate - } - return nil -} - -func (m *IssueCommercialPaper) GetMaturityDate() *google_protobuf.Timestamp { - if m != nil { - return m.MaturityDate - } - return nil -} - -func (m *IssueCommercialPaper) GetFaceValue() int32 { - if m != nil { - return m.FaceValue - } - return 0 -} - -// BuyCommercialPaper event -type BuyCommercialPaper struct { - Issuer string `protobuf:"bytes,1,opt,name=issuer" json:"issuer,omitempty"` - PaperNumber string `protobuf:"bytes,2,opt,name=paper_number,json=paperNumber" json:"paper_number,omitempty"` - CurrentOwner string `protobuf:"bytes,3,opt,name=current_owner,json=currentOwner" json:"current_owner,omitempty"` - NewOwner string `protobuf:"bytes,4,opt,name=new_owner,json=newOwner" json:"new_owner,omitempty"` - Price int32 `protobuf:"varint,5,opt,name=price" json:"price,omitempty"` - PurchaseDate *google_protobuf.Timestamp `protobuf:"bytes,6,opt,name=purchase_date,json=purchaseDate" json:"purchase_date,omitempty"` -} - -func (m *BuyCommercialPaper) Reset() { *m = BuyCommercialPaper{} } -func (m *BuyCommercialPaper) String() string { return proto.CompactTextString(m) } -func (*BuyCommercialPaper) ProtoMessage() {} -func (*BuyCommercialPaper) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -func (m *BuyCommercialPaper) GetIssuer() string { - if m != nil { - return m.Issuer - } - return "" -} - -func (m *BuyCommercialPaper) GetPaperNumber() string { - if m != nil { - return m.PaperNumber - } - return "" -} - -func (m *BuyCommercialPaper) GetCurrentOwner() string { - if m != nil { - return m.CurrentOwner - } - return "" -} - -func (m *BuyCommercialPaper) GetNewOwner() string { - if m != nil { - return m.NewOwner - } - return "" -} - -func (m *BuyCommercialPaper) GetPrice() int32 { - if m != nil { - return m.Price - } - return 0 -} - -func (m *BuyCommercialPaper) GetPurchaseDate() *google_protobuf.Timestamp { - if m != nil { - return m.PurchaseDate - } - return nil -} - -// RedeemCommercialPaper event -type RedeemCommercialPaper struct { - Issuer string `protobuf:"bytes,1,opt,name=issuer" json:"issuer,omitempty"` - PaperNumber string `protobuf:"bytes,2,opt,name=paper_number,json=paperNumber" json:"paper_number,omitempty"` - RedeemingOwner string `protobuf:"bytes,3,opt,name=redeeming_owner,json=redeemingOwner" json:"redeeming_owner,omitempty"` - RedeemDate *google_protobuf.Timestamp `protobuf:"bytes,4,opt,name=redeem_date,json=redeemDate" json:"redeem_date,omitempty"` -} - -func (m *RedeemCommercialPaper) Reset() { *m = RedeemCommercialPaper{} } -func (m *RedeemCommercialPaper) String() string { return proto.CompactTextString(m) } -func (*RedeemCommercialPaper) ProtoMessage() {} -func (*RedeemCommercialPaper) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } - -func (m *RedeemCommercialPaper) GetIssuer() string { - if m != nil { - return m.Issuer - } - return "" -} - -func (m *RedeemCommercialPaper) GetPaperNumber() string { - if m != nil { - return m.PaperNumber - } - return "" -} - -func (m *RedeemCommercialPaper) GetRedeemingOwner() string { - if m != nil { - return m.RedeemingOwner - } - return "" -} - -func (m *RedeemCommercialPaper) GetRedeemDate() *google_protobuf.Timestamp { - if m != nil { - return m.RedeemDate - } - return nil -} - -func init() { - proto.RegisterType((*IssueCommercialPaper)(nil), "schema.IssueCommercialPaper") - proto.RegisterType((*BuyCommercialPaper)(nil), "schema.BuyCommercialPaper") - proto.RegisterType((*RedeemCommercialPaper)(nil), "schema.RedeemCommercialPaper") -} - -func init() { proto.RegisterFile("payload.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 339 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x91, 0xc1, 0x4a, 0xf3, 0x40, - 0x14, 0x85, 0x99, 0xff, 0x6f, 0x83, 0xb9, 0x6d, 0x15, 0x86, 0x2a, 0xa1, 0x22, 0xd6, 0xba, 0xb0, - 0xab, 0x14, 0x74, 0x25, 0x2e, 0x04, 0x75, 0xe3, 0x46, 0x25, 0x88, 0xdb, 0x30, 0x4d, 0x6f, 0xdb, - 0x40, 0x26, 0x33, 0x4c, 0x66, 0x2c, 0x79, 0x33, 0x1f, 0xc9, 0x85, 0x0f, 0x21, 0x33, 0x93, 0x08, - 0xae, 0xea, 0xa2, 0xcb, 0xf9, 0xee, 0xb9, 0x97, 0x73, 0xce, 0xc0, 0x40, 0xb2, 0xba, 0x10, 0x6c, - 0x11, 0x4b, 0x25, 0xb4, 0xa0, 0x41, 0x95, 0xad, 0x91, 0xb3, 0xd1, 0xe9, 0x4a, 0x88, 0x55, 0x81, - 0x33, 0x47, 0xe7, 0x66, 0x39, 0xd3, 0x39, 0xc7, 0x4a, 0x33, 0x2e, 0xbd, 0x70, 0xf2, 0x45, 0x60, - 0xf8, 0x58, 0x55, 0x06, 0xef, 0x05, 0xe7, 0xa8, 0xb2, 0x9c, 0x15, 0x2f, 0x4c, 0xa2, 0xa2, 0x47, - 0x10, 0xe4, 0x96, 0xab, 0x88, 0x8c, 0xc9, 0x34, 0x4c, 0x9a, 0x17, 0x3d, 0x83, 0xbe, 0xb4, 0x82, - 0xb4, 0x34, 0x7c, 0x8e, 0x2a, 0xfa, 0xe7, 0xa6, 0x3d, 0xc7, 0x9e, 0x1c, 0xa2, 0xd7, 0x00, 0x4e, - 0x9c, 0x2e, 0x98, 0xc6, 0xe8, 0xff, 0x98, 0x4c, 0x7b, 0x97, 0xa3, 0xd8, 0x3b, 0x89, 0x5b, 0x27, - 0xf1, 0x6b, 0xeb, 0x24, 0x09, 0x9d, 0xfa, 0x81, 0x69, 0xa4, 0xb7, 0x30, 0xe0, 0x4c, 0x1b, 0x95, - 0xeb, 0xda, 0x6f, 0x77, 0xb6, 0x6e, 0xf7, 0xdb, 0x05, 0x77, 0xe0, 0x04, 0x60, 0xc9, 0x32, 0x4c, - 0xdf, 0x59, 0x61, 0x30, 0xea, 0x8e, 0xc9, 0xb4, 0x9b, 0x84, 0x96, 0xbc, 0x59, 0x30, 0xf9, 0x24, - 0x40, 0xef, 0x4c, 0xbd, 0xc3, 0xb0, 0xe7, 0x30, 0xc8, 0x8c, 0x52, 0x58, 0xea, 0x54, 0x6c, 0x4a, - 0x54, 0x2e, 0x6f, 0x98, 0xf4, 0x1b, 0xf8, 0x6c, 0x19, 0x3d, 0x86, 0xb0, 0xc4, 0x4d, 0x23, 0xe8, - 0x38, 0xc1, 0x5e, 0x89, 0x1b, 0x3f, 0x1c, 0x42, 0x57, 0xaa, 0x3c, 0x6b, 0xdd, 0xfa, 0x87, 0x6d, - 0x42, 0x1a, 0x95, 0xad, 0x59, 0xd5, 0xf4, 0x18, 0x6c, 0x6f, 0xa2, 0x5d, 0xb0, 0x4d, 0x4c, 0x3e, - 0x08, 0x1c, 0x26, 0xb8, 0x40, 0xe4, 0x3b, 0x4c, 0x7b, 0x01, 0x07, 0xca, 0xdd, 0xcc, 0xcb, 0xd5, - 0xaf, 0xbc, 0xfb, 0x3f, 0xd8, 0x87, 0xba, 0x81, 0x9e, 0x27, 0x7f, 0xfd, 0x46, 0xf0, 0x72, 0x6b, - 0x7d, 0x1e, 0xb8, 0xf9, 0xd5, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x35, 0x16, 0x2a, 0xb1, 0xd5, - 0x02, 0x00, 0x00, -} diff --git a/examples/cpaper/schema/payload.proto b/examples/cpaper/schema/payload.proto deleted file mode 100644 index 146af214..00000000 --- a/examples/cpaper/schema/payload.proto +++ /dev/null @@ -1,31 +0,0 @@ -syntax = "proto3"; -package schema; - -import "google/protobuf/timestamp.proto"; - -// IssueCommercialPaper event -message IssueCommercialPaper { - string issuer = 1; - string paper_number = 2; - google.protobuf.Timestamp issue_date = 3; - google.protobuf.Timestamp maturity_date = 4; - int32 face_value = 5; -} - -// BuyCommercialPaper event -message BuyCommercialPaper { - string issuer = 1; - string paper_number = 2; - string current_owner = 3; - string new_owner = 4; - int32 price = 5; - google.protobuf.Timestamp purchase_date = 6; -} - -// RedeemCommercialPaper event -message RedeemCommercialPaper { - string issuer = 1; - string paper_number = 2; - string redeeming_owner = 3; - google.protobuf.Timestamp redeem_date = 4; -} diff --git a/examples/cpaper/schema/state.pb.go b/examples/cpaper/schema/state.pb.go deleted file mode 100644 index 4b67b16f..00000000 --- a/examples/cpaper/schema/state.pb.go +++ /dev/null @@ -1,177 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: state.proto - -package schema - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import google_protobuf "github.com/golang/protobuf/ptypes/timestamp" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -type CommercialPaper_State int32 - -const ( - CommercialPaper_ISSUED CommercialPaper_State = 0 - CommercialPaper_TRADING CommercialPaper_State = 1 - CommercialPaper_REDEEMED CommercialPaper_State = 2 -) - -var CommercialPaper_State_name = map[int32]string{ - 0: "ISSUED", - 1: "TRADING", - 2: "REDEEMED", -} -var CommercialPaper_State_value = map[string]int32{ - "ISSUED": 0, - "TRADING": 1, - "REDEEMED": 2, -} - -func (x CommercialPaper_State) String() string { - return proto.EnumName(CommercialPaper_State_name, int32(x)) -} -func (CommercialPaper_State) EnumDescriptor() ([]byte, []int) { return fileDescriptor1, []int{0, 0} } - -type CommercialPaper struct { - Issuer string `protobuf:"bytes,1,opt,name=issuer" json:"issuer,omitempty"` - PaperNumber string `protobuf:"bytes,2,opt,name=paper_number,json=paperNumber" json:"paper_number,omitempty"` - Owner string `protobuf:"bytes,3,opt,name=owner" json:"owner,omitempty"` - IssueDate *google_protobuf.Timestamp `protobuf:"bytes,4,opt,name=issue_date,json=issueDate" json:"issue_date,omitempty"` - MaturityDate *google_protobuf.Timestamp `protobuf:"bytes,5,opt,name=maturity_date,json=maturityDate" json:"maturity_date,omitempty"` - FaceValue int32 `protobuf:"varint,6,opt,name=face_value,json=faceValue" json:"face_value,omitempty"` - State CommercialPaper_State `protobuf:"varint,7,opt,name=state,enum=schema.CommercialPaper_State" json:"state,omitempty"` -} - -func (m *CommercialPaper) Reset() { *m = CommercialPaper{} } -func (m *CommercialPaper) String() string { return proto.CompactTextString(m) } -func (*CommercialPaper) ProtoMessage() {} -func (*CommercialPaper) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } - -func (m *CommercialPaper) GetIssuer() string { - if m != nil { - return m.Issuer - } - return "" -} - -func (m *CommercialPaper) GetPaperNumber() string { - if m != nil { - return m.PaperNumber - } - return "" -} - -func (m *CommercialPaper) GetOwner() string { - if m != nil { - return m.Owner - } - return "" -} - -func (m *CommercialPaper) GetIssueDate() *google_protobuf.Timestamp { - if m != nil { - return m.IssueDate - } - return nil -} - -func (m *CommercialPaper) GetMaturityDate() *google_protobuf.Timestamp { - if m != nil { - return m.MaturityDate - } - return nil -} - -func (m *CommercialPaper) GetFaceValue() int32 { - if m != nil { - return m.FaceValue - } - return 0 -} - -func (m *CommercialPaper) GetState() CommercialPaper_State { - if m != nil { - return m.State - } - return CommercialPaper_ISSUED -} - -// CommercialPaperId identifier part -type CommercialPaperId struct { - Issuer string `protobuf:"bytes,1,opt,name=issuer" json:"issuer,omitempty"` - PaperNumber string `protobuf:"bytes,2,opt,name=paper_number,json=paperNumber" json:"paper_number,omitempty"` -} - -func (m *CommercialPaperId) Reset() { *m = CommercialPaperId{} } -func (m *CommercialPaperId) String() string { return proto.CompactTextString(m) } -func (*CommercialPaperId) ProtoMessage() {} -func (*CommercialPaperId) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } - -func (m *CommercialPaperId) GetIssuer() string { - if m != nil { - return m.Issuer - } - return "" -} - -func (m *CommercialPaperId) GetPaperNumber() string { - if m != nil { - return m.PaperNumber - } - return "" -} - -type CommercialPaperList struct { - Items []*CommercialPaper `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"` -} - -func (m *CommercialPaperList) Reset() { *m = CommercialPaperList{} } -func (m *CommercialPaperList) String() string { return proto.CompactTextString(m) } -func (*CommercialPaperList) ProtoMessage() {} -func (*CommercialPaperList) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } - -func (m *CommercialPaperList) GetItems() []*CommercialPaper { - if m != nil { - return m.Items - } - return nil -} - -func init() { - proto.RegisterType((*CommercialPaper)(nil), "schema.CommercialPaper") - proto.RegisterType((*CommercialPaperId)(nil), "schema.CommercialPaperId") - proto.RegisterType((*CommercialPaperList)(nil), "schema.CommercialPaperList") - proto.RegisterEnum("schema.CommercialPaper_State", CommercialPaper_State_name, CommercialPaper_State_value) -} - -func init() { proto.RegisterFile("state.proto", fileDescriptor1) } - -var fileDescriptor1 = []byte{ - // 334 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x90, 0xc1, 0x4f, 0xc2, 0x30, - 0x18, 0xc5, 0x1d, 0xb8, 0x21, 0xdf, 0x50, 0xb1, 0x1a, 0x5d, 0x48, 0x88, 0x73, 0xa7, 0x5d, 0x2c, - 0x09, 0x9c, 0x3c, 0x19, 0xe3, 0x16, 0x43, 0xa2, 0xc4, 0x14, 0xf4, 0x4a, 0x0a, 0x7c, 0xe0, 0x12, - 0xca, 0x96, 0xb6, 0xd3, 0xf8, 0xef, 0xfa, 0x97, 0x98, 0xb5, 0x72, 0x21, 0x31, 0x1e, 0x3c, 0x7e, - 0xaf, 0xbf, 0xf7, 0xf2, 0xfa, 0xc0, 0x57, 0x9a, 0x6b, 0xa4, 0x85, 0xcc, 0x75, 0x4e, 0x3c, 0x35, - 0x7f, 0x43, 0xc1, 0x3b, 0x97, 0xab, 0x3c, 0x5f, 0xad, 0xb1, 0x67, 0xd4, 0x59, 0xb9, 0xec, 0xe9, - 0x4c, 0xa0, 0xd2, 0x5c, 0x14, 0x16, 0x8c, 0xbe, 0x6a, 0x70, 0x7c, 0x9f, 0x0b, 0x81, 0x72, 0x9e, - 0xf1, 0xf5, 0x33, 0x2f, 0x50, 0x92, 0x73, 0xf0, 0x32, 0xa5, 0x4a, 0x94, 0x81, 0x13, 0x3a, 0x71, - 0x93, 0xfd, 0x5c, 0xe4, 0x0a, 0x5a, 0x45, 0x05, 0x4c, 0x37, 0xa5, 0x98, 0xa1, 0x0c, 0x6a, 0xe6, - 0xd5, 0x37, 0xda, 0xc8, 0x48, 0xe4, 0x0c, 0xdc, 0xfc, 0x63, 0x83, 0x32, 0xa8, 0x9b, 0x37, 0x7b, - 0x90, 0x1b, 0x00, 0x13, 0x31, 0x5d, 0x70, 0x8d, 0xc1, 0x7e, 0xe8, 0xc4, 0x7e, 0xbf, 0x43, 0x6d, - 0x35, 0xba, 0xad, 0x46, 0x27, 0xdb, 0x6a, 0xac, 0x69, 0xe8, 0x84, 0x6b, 0x24, 0xb7, 0x70, 0x28, - 0xb8, 0x2e, 0x65, 0xa6, 0x3f, 0xad, 0xdb, 0xfd, 0xd3, 0xdd, 0xda, 0x1a, 0x4c, 0x40, 0x17, 0x60, - 0xc9, 0xe7, 0x38, 0x7d, 0xe7, 0xeb, 0x12, 0x03, 0x2f, 0x74, 0x62, 0x97, 0x35, 0x2b, 0xe5, 0xb5, - 0x12, 0xc8, 0x00, 0x5c, 0xb3, 0x5b, 0xd0, 0x08, 0x9d, 0xf8, 0xa8, 0xdf, 0xa5, 0x76, 0x38, 0xba, - 0xb3, 0x09, 0x1d, 0x57, 0x10, 0xb3, 0x6c, 0x44, 0xc1, 0x35, 0x37, 0x01, 0xf0, 0x86, 0xe3, 0xf1, - 0x4b, 0x9a, 0xb4, 0xf7, 0x88, 0x0f, 0x8d, 0x09, 0xbb, 0x4b, 0x86, 0xa3, 0x87, 0xb6, 0x43, 0x5a, - 0x70, 0xc0, 0xd2, 0x24, 0x4d, 0x9f, 0xd2, 0xa4, 0x5d, 0x8b, 0x46, 0x70, 0xb2, 0x93, 0x37, 0x5c, - 0xfc, 0x63, 0xe5, 0x28, 0x81, 0xd3, 0x9d, 0xbc, 0xc7, 0x4c, 0x69, 0x72, 0x0d, 0x6e, 0xa6, 0x51, - 0xa8, 0xc0, 0x09, 0xeb, 0xb1, 0xdf, 0xbf, 0xf8, 0xe5, 0x2f, 0xcc, 0x52, 0x33, 0xcf, 0x6c, 0x37, - 0xf8, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x2f, 0x7e, 0x6d, 0xee, 0x39, 0x02, 0x00, 0x00, -} diff --git a/examples/cpaper/schema/state.proto b/examples/cpaper/schema/state.proto deleted file mode 100644 index 834bf1d3..00000000 --- a/examples/cpaper/schema/state.proto +++ /dev/null @@ -1,35 +0,0 @@ -syntax = "proto3"; -package schema; - -import "google/protobuf/timestamp.proto"; - -// CommercialPaper state entry -message CommercialPaper { - - enum State { - ISSUED = 0; - TRADING = 1; - REDEEMED = 2; - } - - // issuer and paper number comprises primary key of commercial paper entry - string issuer = 1; - string paper_number = 2; - - string owner = 3; - google.protobuf.Timestamp issue_date = 4; - google.protobuf.Timestamp maturity_date = 5; - int32 face_value = 6; - State state = 7; -} - -// CommercialPaperId identifier part -message CommercialPaperId { - string issuer = 1; - string paper_number = 2; -} - -message CommercialPaperList { - repeated CommercialPaper items = 1; -} - diff --git a/examples/cpaper/testdata/testdata.go b/examples/cpaper/testdata/testdata.go deleted file mode 100644 index 12e544e4..00000000 --- a/examples/cpaper/testdata/testdata.go +++ /dev/null @@ -1,32 +0,0 @@ -package testdata - -import ( - "time" - - "github.com/s7techlab/cckit/testing" - - "github.com/golang/protobuf/ptypes" - "github.com/s7techlab/cckit/examples/cpaper/schema" -) - -var ( - // CPapers commercial paper fixtures - CPapers = []schema.IssueCommercialPaper{{ - Issuer: `some-issuer-1`, - PaperNumber: `00000001`, - IssueDate: ptypes.TimestampNow(), - MaturityDate: testing.MustProtoTimestamp(time.Now().AddDate(0, 1, 0)), - FaceValue: 11111, - }, { - Issuer: `some-issuer-2`, - PaperNumber: `00000002`, - IssueDate: ptypes.TimestampNow(), - MaturityDate: testing.MustProtoTimestamp(time.Now().AddDate(0, 2, 0)), - FaceValue: 22222, - }, { - Issuer: `some-issuer-3`, - PaperNumber: `00000003`, - IssueDate: ptypes.TimestampNow(), - MaturityDate: testing.MustProtoTimestamp(time.Now().AddDate(0, 3, 0)), - }} -) diff --git a/examples/cpaper_extended/README.md b/examples/cpaper_extended/README.md index 64b2ef72..e73e938d 100644 --- a/examples/cpaper_extended/README.md +++ b/examples/cpaper_extended/README.md @@ -1,8 +1,10 @@ -# Commercial paper extended example with protobuf chaincode state +# Commercial paper extended example -https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/scenario.html +This is an extended example of the official [Commercial paper scenario](https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/scenario.html) +### Features -At the heart of a blockchain network is a smart contract. In PaperNet, the code in the commercial paper smart -contract defines the valid states for commercial paper, and the transaction logic that transition -a paper from one state to another. \ No newline at end of file +* Protobuf transaction payload and event definitions +* Protobuf chaincode state schema +* Event emitting +* Unique key external reference usage diff --git a/examples/cpaper_extended/chaincode.go b/examples/cpaper_extended/chaincode.go index 4727ec67..e53347df 100644 --- a/examples/cpaper_extended/chaincode.go +++ b/examples/cpaper_extended/chaincode.go @@ -18,22 +18,24 @@ var ( StateMappings = m.StateMappings{}. // Create mapping for Commercial Paper entity Add(&schema.CommercialPaper{}, - m.PKeySchema(&schema.CommercialPaperId{}), //key namespace will be <`CommercialPaper`, Issuer, PaperNumber> - m.List(&schema.CommercialPaperList{}), // list container - m.UniqKey(`ExternalId`), // external is uniq + m.PKeySchema(&schema.CommercialPaperId{}), // Key namespace will be <"CommercialPaper", Issuer, PaperNumber> + m.List(&schema.CommercialPaperList{}), // Structure of result for List method + m.UniqKey("ExternalId"), // External Id is unique ) // EventMappings EventMappings = m.EventMappings{}. - // event name will be `IssueCommercialPaper`, payload - same as issue payload + // Event name will be "IssueCommercialPaper", payload - same as issue payload Add(&schema.IssueCommercialPaper{}). + // Event name will be "BuyCommercialPaper" Add(&schema.BuyCommercialPaper{}). + // Event name will be "RedeemCommercialPaper" Add(&schema.RedeemCommercialPaper{}) ) func NewCC() *router.Chaincode { - r := router.New(`commercial_paper`) + r := router.New("commercial_paper") // Mappings for chaincode state r.Use(m.MapStates(StateMappings)) @@ -41,35 +43,34 @@ func NewCC() *router.Chaincode { // Mappings for chaincode events r.Use(m.MapEvents(EventMappings)) - // store in chaincode state information about chaincode first instantiator + // Store on the ledger the information about chaincode instantiator r.Init(owner.InvokeSetFromCreator) - // method for debug chaincode state - debug.AddHandlers(r, `debug`, owner.Only) + // Method for debug chaincode state + debug.AddHandlers(r, "debug", owner.Only) r. // read methods - Query(`list`, queryCPapers). + Query("list", queryCPapers). // Get method has 2 params - commercial paper primary key components - Query(`get`, queryCPaper, defparam.Proto(&schema.CommercialPaperId{})). - Query(`getByExternalId`, queryCPaperGetByExternalId, param.String(`externalId`)). + Query("get", queryCPaper, defparam.Proto(&schema.CommercialPaperId{})). + Query("getByExternalId", queryCPaperGetByExternalId, param.String("externalId")). // txn methods - Invoke(`issue`, invokeCPaperIssue, defparam.Proto(&schema.IssueCommercialPaper{})). - Invoke(`buy`, invokeCPaperBuy, defparam.Proto(&schema.BuyCommercialPaper{})). - Invoke(`redeem`, invokeCPaperRedeem, defparam.Proto(&schema.RedeemCommercialPaper{})). - Invoke(`delete`, invokeCPaperDelete, defparam.Proto(&schema.CommercialPaperId{})) + Invoke("issue", invokeCPaperIssue, defparam.Proto(&schema.IssueCommercialPaper{})). + Invoke("buy", invokeCPaperBuy, defparam.Proto(&schema.BuyCommercialPaper{})). + Invoke("redeem", invokeCPaperRedeem, defparam.Proto(&schema.RedeemCommercialPaper{})). + Invoke("delete", invokeCPaperDelete, defparam.Proto(&schema.CommercialPaperId{})) return router.NewChaincode(r) } func queryCPapers(c router.Context) (interface{}, error) { - // commercial paper key is composite key <`CommercialPaper`>, {Issuer}, {PaperNumber} > - // where `CommercialPaper` - namespace of this type - // list method retrieves entries from chaincode state - // using GetStateByPartialCompositeKey method, then unmarshal received from state bytes via proto.Ummarshal method - // and creates slice of *schema.CommercialPaper + // List method retrieves all entries from the ledger using GetStateByPartialCompositeKey method and passing it the + // namespace of our contract type, in this example that's "CommercialPaper", then it unmarshals received bytes via + // proto.Ummarshal method and creates a []schema.CommercialPaperList as defined in the + // "StateMappings" variable at the top of the file return c.State().List(&schema.CommercialPaper{}) } @@ -82,34 +83,34 @@ func queryCPaper(c router.Context) (interface{}, error) { func queryCPaperGetByExternalId(c router.Context) (interface{}, error) { var ( - externalId = c.ParamString(`externalId`) + externalId = c.ParamString("externalId") ) - return c.State().(m.MappedState).GetByUniqKey(&schema.CommercialPaper{}, `ExternalId`, []string{externalId}) + return c.State().(m.MappedState).GetByUniqKey(&schema.CommercialPaper{}, "ExternalId", []string{externalId}) } func invokeCPaperIssue(c router.Context) (res interface{}, err error) { var ( - // input message - issue = c.Param().(*schema.IssueCommercialPaper) //default parameter + // Input message + issueData = c.Param().(*schema.IssueCommercialPaper) // Default parameter ) - // validate input message by rules, defined in schema - if err = issue.Validate(); err != nil { - return err, errors.Wrap(err, `payload validation`) + // Validate input message using the rules defined in schema + if err = issueData.Validate(); err != nil { + return err, errors.Wrap(err, "payload validation") } - // create state entry + // Create state entry cpaper := &schema.CommercialPaper{ - Issuer: issue.Issuer, - PaperNumber: issue.PaperNumber, - Owner: issue.Issuer, - IssueDate: issue.IssueDate, - MaturityDate: issue.MaturityDate, - FaceValue: issue.FaceValue, - State: schema.CommercialPaper_ISSUED, // initial state - ExternalId: issue.ExternalId, + Issuer: issueData.Issuer, + PaperNumber: issueData.PaperNumber, + Owner: issueData.Issuer, + IssueDate: issueData.IssueDate, + MaturityDate: issueData.MaturityDate, + FaceValue: issueData.FaceValue, + State: schema.CommercialPaper_ISSUED, // Initial state + ExternalId: issueData.ExternalId, } - if err = c.Event().Set(issue); err != nil { + if err = c.Event().Set(issueData); err != nil { return nil, err } @@ -117,42 +118,46 @@ func invokeCPaperIssue(c router.Context) (res interface{}, err error) { } func invokeCPaperBuy(c router.Context) (interface{}, error) { - var ( cpaper *schema.CommercialPaper - // but tx payload - buy = c.Param().(*schema.BuyCommercialPaper) + // Buy transaction payload + buyData = c.Param().(*schema.BuyCommercialPaper) - // current commercial paper state + // Get the current commercial paper state cp, err = c.State().Get( - &schema.CommercialPaperId{Issuer: buy.Issuer, PaperNumber: buy.PaperNumber}, + &schema.CommercialPaperId{Issuer: buyData.Issuer, PaperNumber: buyData.PaperNumber}, &schema.CommercialPaper{}) ) if err != nil { - return nil, errors.Wrap(err, `not found`) + return nil, errors.Wrap(err, "not found") } + cpaper = cp.(*schema.CommercialPaper) // Validate current owner - if cpaper.Owner != buy.CurrentOwner { - return nil, fmt.Errorf(`paper %s %s is not owned by %s`, cpaper.Issuer, cpaper.PaperNumber, buy.CurrentOwner) + if cpaper.Owner != buyData.CurrentOwner { + return nil, fmt.Errorf( + "paper %s %s is not owned by %s", + cpaper.Issuer, cpaper.PaperNumber, buyData.CurrentOwner) } - // First buy moves state from ISSUED to TRADING + // First buyData moves state from ISSUED to TRADING if cpaper.State == schema.CommercialPaper_ISSUED { cpaper.State = schema.CommercialPaper_TRADING } // Check paper is not already REDEEMED if cpaper.State == schema.CommercialPaper_TRADING { - cpaper.Owner = buy.NewOwner + cpaper.Owner = buyData.NewOwner } else { - return nil, fmt.Errorf(`paper %s %s is not trading.current state = %s`, cpaper.Issuer, cpaper.PaperNumber, cpaper.State) + return nil, fmt.Errorf( + "paper %s %s is not trading.current state = %s", + cpaper.Issuer, cpaper.PaperNumber, cpaper.State) } - if err = c.Event().Set(buy); err != nil { + if err = c.Event().Set(buyData); err != nil { return nil, err } @@ -160,8 +165,47 @@ func invokeCPaperBuy(c router.Context) (interface{}, error) { } func invokeCPaperRedeem(c router.Context) (interface{}, error) { + var ( + commercialPaper *schema.CommercialPaper + + // Buy transaction payload + redeemData = c.Param().(*schema.RedeemCommercialPaper) + + // Get the current commercial paper state + cp, err = c.State().Get(&schema.CommercialPaper{ + Issuer: redeemData.Issuer, + PaperNumber: redeemData.PaperNumber, + }, &schema.CommercialPaper{}) + ) + + if err != nil { + return nil, errors.Wrap(err, "paper not found") + } + + commercialPaper = cp.(*schema.CommercialPaper) + + // Check paper is not REDEEMED + if commercialPaper.State == schema.CommercialPaper_REDEEMED { + return nil, fmt.Errorf( + "paper %s %s is already redeemed", + commercialPaper.Issuer, commercialPaper.PaperNumber) + } + + // Verify that the redeemer owns the commercial paper before redeeming it + if commercialPaper.Owner == redeemData.RedeemingOwner { + commercialPaper.Owner = redeemData.Issuer + commercialPaper.State = schema.CommercialPaper_REDEEMED + } else { + return nil, fmt.Errorf( + "redeeming owner does not own paper %s %s", + commercialPaper.Issuer, commercialPaper.PaperNumber) + } + + if err = c.Event().Set(redeemData); err != nil { + return nil, err + } - return nil, nil + return commercialPaper, c.State().Put(commercialPaper) } func invokeCPaperDelete(c router.Context) (interface{}, error) { diff --git a/examples/cpaper_extended/chaincode_test.go b/examples/cpaper_extended/chaincode_test.go index aa4b272d..a388a9aa 100644 --- a/examples/cpaper_extended/chaincode_test.go +++ b/examples/cpaper_extended/chaincode_test.go @@ -1 +1,174 @@ -package cpaper_extended_test +package cpaper_extended + +import ( + "github.com/golang/protobuf/ptypes" + "github.com/hyperledger/fabric/protos/peer" + "github.com/s7techlab/cckit/examples/cpaper_extended/schema" + "github.com/s7techlab/cckit/examples/cpaper_extended/testdata" + testcc "github.com/s7techlab/cckit/testing" + expectcc "github.com/s7techlab/cckit/testing/expect" + "path" + "testing" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +const ( + MspName = "msp" + + IssuerName = "SomeIssuer" + BuyerName = "SomeBuyer" +) + +func TestCommercialPaper(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Commercial Paper Suite") +} + +var _ = Describe(`CommercialPaper`, func() { + paperChaincode := testcc.NewMockStub(`commercial_paper`, NewCC()) + + BeforeSuite(func() { + // Init chaincode with admin identity + expectcc.ResponseOk( + paperChaincode. + From(testdata.GetTestIdentity(MspName, path.Join("testdata", "admin", "admin.pem"))). + Init()) + }) + + Describe("Commercial Paper lifecycle", func() { + It("Allow issuer to issue new commercial paper", func() { + issueTransactionData := &schema.IssueCommercialPaper{ + Issuer: IssuerName, + PaperNumber: "0001", + IssueDate: ptypes.TimestampNow(), + MaturityDate: testcc.MustProtoTimestamp(time.Now().AddDate(0, 2, 0)), + FaceValue: 100000, + ExternalId: "EXT0001", + } + + expectcc.ResponseOk(paperChaincode.Invoke(`issue`, issueTransactionData)) + + // Validate event has been emitted with the transaction data + Expect(<-paperChaincode.ChaincodeEventsChannel).To(BeEquivalentTo(&peer.ChaincodeEvent{ + EventName: `IssueCommercialPaper`, + Payload: testcc.MustProtoMarshal(issueTransactionData), + })) + + // Clear events channel after a test case that emits an event + paperChaincode.ClearEvents() + }) + + It("Allow issuer to get commercial paper by composite primary key", func() { + queryResponse := paperChaincode.Query("get", &schema.CommercialPaperId{ + Issuer: IssuerName, + PaperNumber: "0001", + }) + + paper := expectcc.PayloadIs(queryResponse, &schema.CommercialPaper{}).(*schema.CommercialPaper) + + Expect(paper.Issuer).To(Equal(IssuerName)) + Expect(paper.Owner).To(Equal(IssuerName)) + Expect(paper.State).To(Equal(schema.CommercialPaper_ISSUED)) + Expect(paper.PaperNumber).To(Equal("0001")) + Expect(paper.FaceValue).To(BeNumerically("==", 100000)) + }) + + It("Allow issuer to get commercial paper by unique key", func() { + queryResponse := paperChaincode.Query("getByExternalId", "EXT0001") + + paper := expectcc.PayloadIs(queryResponse, &schema.CommercialPaper{}).(*schema.CommercialPaper) + + Expect(paper.Issuer).To(Equal(IssuerName)) + Expect(paper.Owner).To(Equal(IssuerName)) + Expect(paper.State).To(Equal(schema.CommercialPaper_ISSUED)) + Expect(paper.PaperNumber).To(Equal("0001")) + Expect(paper.FaceValue).To(BeNumerically("==", 100000)) + }) + + It("Allow issuer to get a list of commercial papers", func() { + queryResponse := paperChaincode.Query("list") + + papers := expectcc.PayloadIs(queryResponse, &schema.CommercialPaperList{}).(*schema.CommercialPaperList) + + Expect(len(papers.Items)).To(BeNumerically("==", 1)) + Expect(papers.Items[0].Issuer).To(Equal(IssuerName)) + Expect(papers.Items[0].Owner).To(Equal(IssuerName)) + Expect(papers.Items[0].State).To(Equal(schema.CommercialPaper_ISSUED)) + Expect(papers.Items[0].PaperNumber).To(Equal("0001")) + Expect(papers.Items[0].FaceValue).To(BeNumerically("==", 100000)) + }) + + It("Allow buyer to buy commercial paper", func() { + buyTransactionData := &schema.BuyCommercialPaper{ + Issuer: IssuerName, + PaperNumber: "0001", + CurrentOwner: IssuerName, + NewOwner: BuyerName, + Price: 95000, + PurchaseDate: ptypes.TimestampNow(), + } + + expectcc.ResponseOk(paperChaincode.Invoke(`buy`, buyTransactionData)) + + queryResponse := paperChaincode.Query("get", &schema.CommercialPaperId{ + Issuer: IssuerName, + PaperNumber: "0001", + }) + + paper := expectcc.PayloadIs(queryResponse, &schema.CommercialPaper{}).(*schema.CommercialPaper) + + Expect(paper.Owner).To(Equal(BuyerName)) + Expect(paper.State).To(Equal(schema.CommercialPaper_TRADING)) + + Expect(<-paperChaincode.ChaincodeEventsChannel).To(BeEquivalentTo(&peer.ChaincodeEvent{ + EventName: `BuyCommercialPaper`, + Payload: testcc.MustProtoMarshal(buyTransactionData), + })) + + paperChaincode.ClearEvents() + }) + + It("Allow buyer to redeem commercial paper", func() { + redeemTransactionData := &schema.RedeemCommercialPaper{ + Issuer: IssuerName, + PaperNumber: "0001", + RedeemingOwner: BuyerName, + RedeemDate: ptypes.TimestampNow(), + } + + expectcc.ResponseOk(paperChaincode.Invoke(`redeem`, redeemTransactionData)) + + queryResponse := paperChaincode.Query("get", &schema.CommercialPaperId{ + Issuer: IssuerName, + PaperNumber: "0001", + }) + + paper := expectcc.PayloadIs(queryResponse, &schema.CommercialPaper{}).(*schema.CommercialPaper) + Expect(paper.Owner).To(Equal(IssuerName)) + Expect(paper.State).To(Equal(schema.CommercialPaper_REDEEMED)) + + Expect(<-paperChaincode.ChaincodeEventsChannel).To(BeEquivalentTo(&peer.ChaincodeEvent{ + EventName: `RedeemCommercialPaper`, + Payload: testcc.MustProtoMarshal(redeemTransactionData), + })) + + paperChaincode.ClearEvents() + }) + + It("Allow issuer to redeem delete commercial paper", func() { + expectcc.ResponseOk(paperChaincode.Invoke(`delete`, &schema.CommercialPaperId{ + Issuer: IssuerName, + PaperNumber: "0001", + })) + + // Validate there are 0 Commercial Papers in the world state + queryResponse := paperChaincode.Query("list") + papers := expectcc.PayloadIs(queryResponse, &schema.CommercialPaperList{}).(*schema.CommercialPaperList) + + Expect(len(papers.Items)).To(BeNumerically("==", 0)) + }) + }) +}) diff --git a/examples/cpaper_extended/schema/payload.validator.pb.go b/examples/cpaper_extended/schema/payload.validator.pb.go index ae3d26e4..f656c585 100644 --- a/examples/cpaper_extended/schema/payload.validator.pb.go +++ b/examples/cpaper_extended/schema/payload.validator.pb.go @@ -1,29 +1,16 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: payload.proto -/* -Package schema is a generated protocol buffer package. - -It is generated from these files: - payload.proto - state.proto - -It has these top-level messages: - IssueCommercialPaper - BuyCommercialPaper - RedeemCommercialPaper - CommercialPaper - CommercialPaperId - CommercialPaperList -*/ package schema -import fmt "fmt" -import go_proto_validators "github.com/mwitkow/go-proto-validators" -import proto "github.com/golang/protobuf/proto" -import math "math" -import _ "github.com/golang/protobuf/ptypes/timestamp" -import _ "github.com/mwitkow/go-proto-validators" +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + _ "github.com/golang/protobuf/ptypes/timestamp" + _ "github.com/mwitkow/go-proto-validators" + github_com_mwitkow_go_proto_validators "github.com/mwitkow/go-proto-validators" + math "math" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -32,77 +19,77 @@ var _ = math.Inf func (this *IssueCommercialPaper) Validate() error { if this.Issuer == "" { - return go_proto_validators.FieldError("Issuer", fmt.Errorf(`value '%v' must not be an empty string`, this.Issuer)) + return github_com_mwitkow_go_proto_validators.FieldError("Issuer", fmt.Errorf(`value '%v' must not be an empty string`, this.Issuer)) } if this.PaperNumber == "" { - return go_proto_validators.FieldError("PaperNumber", fmt.Errorf(`value '%v' must not be an empty string`, this.PaperNumber)) + return github_com_mwitkow_go_proto_validators.FieldError("PaperNumber", fmt.Errorf(`value '%v' must not be an empty string`, this.PaperNumber)) } if nil == this.IssueDate { - return go_proto_validators.FieldError("IssueDate", fmt.Errorf("message must exist")) + return github_com_mwitkow_go_proto_validators.FieldError("IssueDate", fmt.Errorf("message must exist")) } if this.IssueDate != nil { - if err := go_proto_validators.CallValidatorIfExists(this.IssueDate); err != nil { - return go_proto_validators.FieldError("IssueDate", err) + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.IssueDate); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("IssueDate", err) } } if nil == this.MaturityDate { - return go_proto_validators.FieldError("MaturityDate", fmt.Errorf("message must exist")) + return github_com_mwitkow_go_proto_validators.FieldError("MaturityDate", fmt.Errorf("message must exist")) } if this.MaturityDate != nil { - if err := go_proto_validators.CallValidatorIfExists(this.MaturityDate); err != nil { - return go_proto_validators.FieldError("MaturityDate", err) + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.MaturityDate); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("MaturityDate", err) } } if !(this.FaceValue > 0) { - return go_proto_validators.FieldError("FaceValue", fmt.Errorf(`value '%v' must be greater than '0'`, this.FaceValue)) + return github_com_mwitkow_go_proto_validators.FieldError("FaceValue", fmt.Errorf(`value '%v' must be greater than '0'`, this.FaceValue)) } if this.ExternalId == "" { - return go_proto_validators.FieldError("ExternalId", fmt.Errorf(`value '%v' must not be an empty string`, this.ExternalId)) + return github_com_mwitkow_go_proto_validators.FieldError("ExternalId", fmt.Errorf(`value '%v' must not be an empty string`, this.ExternalId)) } return nil } func (this *BuyCommercialPaper) Validate() error { if this.Issuer == "" { - return go_proto_validators.FieldError("Issuer", fmt.Errorf(`value '%v' must not be an empty string`, this.Issuer)) + return github_com_mwitkow_go_proto_validators.FieldError("Issuer", fmt.Errorf(`value '%v' must not be an empty string`, this.Issuer)) } if this.PaperNumber == "" { - return go_proto_validators.FieldError("PaperNumber", fmt.Errorf(`value '%v' must not be an empty string`, this.PaperNumber)) + return github_com_mwitkow_go_proto_validators.FieldError("PaperNumber", fmt.Errorf(`value '%v' must not be an empty string`, this.PaperNumber)) } if this.CurrentOwner == "" { - return go_proto_validators.FieldError("CurrentOwner", fmt.Errorf(`value '%v' must not be an empty string`, this.CurrentOwner)) + return github_com_mwitkow_go_proto_validators.FieldError("CurrentOwner", fmt.Errorf(`value '%v' must not be an empty string`, this.CurrentOwner)) } if this.NewOwner == "" { - return go_proto_validators.FieldError("NewOwner", fmt.Errorf(`value '%v' must not be an empty string`, this.NewOwner)) + return github_com_mwitkow_go_proto_validators.FieldError("NewOwner", fmt.Errorf(`value '%v' must not be an empty string`, this.NewOwner)) } if !(this.Price > 0) { - return go_proto_validators.FieldError("Price", fmt.Errorf(`value '%v' must be greater than '0'`, this.Price)) + return github_com_mwitkow_go_proto_validators.FieldError("Price", fmt.Errorf(`value '%v' must be greater than '0'`, this.Price)) } if nil == this.PurchaseDate { - return go_proto_validators.FieldError("PurchaseDate", fmt.Errorf("message must exist")) + return github_com_mwitkow_go_proto_validators.FieldError("PurchaseDate", fmt.Errorf("message must exist")) } if this.PurchaseDate != nil { - if err := go_proto_validators.CallValidatorIfExists(this.PurchaseDate); err != nil { - return go_proto_validators.FieldError("PurchaseDate", err) + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.PurchaseDate); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("PurchaseDate", err) } } return nil } func (this *RedeemCommercialPaper) Validate() error { if this.Issuer == "" { - return go_proto_validators.FieldError("Issuer", fmt.Errorf(`value '%v' must not be an empty string`, this.Issuer)) + return github_com_mwitkow_go_proto_validators.FieldError("Issuer", fmt.Errorf(`value '%v' must not be an empty string`, this.Issuer)) } if this.PaperNumber == "" { - return go_proto_validators.FieldError("PaperNumber", fmt.Errorf(`value '%v' must not be an empty string`, this.PaperNumber)) + return github_com_mwitkow_go_proto_validators.FieldError("PaperNumber", fmt.Errorf(`value '%v' must not be an empty string`, this.PaperNumber)) } if this.RedeemingOwner == "" { - return go_proto_validators.FieldError("RedeemingOwner", fmt.Errorf(`value '%v' must not be an empty string`, this.RedeemingOwner)) + return github_com_mwitkow_go_proto_validators.FieldError("RedeemingOwner", fmt.Errorf(`value '%v' must not be an empty string`, this.RedeemingOwner)) } if nil == this.RedeemDate { - return go_proto_validators.FieldError("RedeemDate", fmt.Errorf("message must exist")) + return github_com_mwitkow_go_proto_validators.FieldError("RedeemDate", fmt.Errorf("message must exist")) } if this.RedeemDate != nil { - if err := go_proto_validators.CallValidatorIfExists(this.RedeemDate); err != nil { - return go_proto_validators.FieldError("RedeemDate", err) + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.RedeemDate); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("RedeemDate", err) } } return nil diff --git a/examples/cpaper_extended/schema/state.pb.go b/examples/cpaper_extended/schema/state.pb.go index 712ab443..3970be41 100644 --- a/examples/cpaper_extended/schema/state.pb.go +++ b/examples/cpaper_extended/schema/state.pb.go @@ -37,9 +37,9 @@ func (x CommercialPaper_State) String() string { } func (CommercialPaper_State) EnumDescriptor() ([]byte, []int) { return fileDescriptor1, []int{0, 0} } -// Commercialpaper state entry +// Commercial Paper state entry type CommercialPaper struct { - // issuer and paper number comprises primary key of commercial paper entry + // Issuer and Paper number comprises composite primary key of Commercial paper entry Issuer string `protobuf:"bytes,1,opt,name=issuer" json:"issuer,omitempty"` PaperNumber string `protobuf:"bytes,2,opt,name=paper_number,json=paperNumber" json:"paper_number,omitempty"` Owner string `protobuf:"bytes,3,opt,name=owner" json:"owner,omitempty"` @@ -47,7 +47,7 @@ type CommercialPaper struct { MaturityDate *google_protobuf.Timestamp `protobuf:"bytes,5,opt,name=maturity_date,json=maturityDate" json:"maturity_date,omitempty"` FaceValue int32 `protobuf:"varint,6,opt,name=face_value,json=faceValue" json:"face_value,omitempty"` State CommercialPaper_State `protobuf:"varint,7,opt,name=state,enum=cckit.examples.cpaper_extended.schema.CommercialPaper_State" json:"state,omitempty"` - // additional uniq field for entry + // Additional unique field for entry ExternalId string `protobuf:"bytes,8,opt,name=external_id,json=externalId" json:"external_id,omitempty"` } @@ -137,6 +137,7 @@ func (m *CommercialPaperId) GetPaperNumber() string { return "" } +// Container for returning multiple entities type CommercialPaperList struct { Items []*CommercialPaper `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"` } diff --git a/examples/cpaper_extended/schema/state.proto b/examples/cpaper_extended/schema/state.proto index 23dabbc4..3db36c53 100644 --- a/examples/cpaper_extended/schema/state.proto +++ b/examples/cpaper_extended/schema/state.proto @@ -5,7 +5,7 @@ option go_package = "schema"; import "google/protobuf/timestamp.proto"; -// Commercialpaper state entry +// Commercial Paper state entry message CommercialPaper { enum State { @@ -14,7 +14,7 @@ message CommercialPaper { REDEEMED = 2; } - // issuer and paper number comprises primary key of commercial paper entry + // Issuer and Paper number comprises composite primary key of Commercial paper entry string issuer = 1; string paper_number = 2; @@ -24,7 +24,7 @@ message CommercialPaper { int32 face_value = 6; State state = 7; - // additional uniq field for entry + // Additional unique field for entry string external_id = 8; } @@ -34,9 +34,7 @@ message CommercialPaperId { string paper_number = 2; } - - +// Container for returning multiple entities message CommercialPaperList { repeated CommercialPaper items = 1; } - diff --git a/examples/cpaper_extended/schema/state.validator.pb.go b/examples/cpaper_extended/schema/state.validator.pb.go index f3e96ee8..b008c8cb 100644 --- a/examples/cpaper_extended/schema/state.validator.pb.go +++ b/examples/cpaper_extended/schema/state.validator.pb.go @@ -3,11 +3,13 @@ package schema -import go_proto_validators "github.com/mwitkow/go-proto-validators" -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import _ "github.com/golang/protobuf/ptypes/timestamp" +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + _ "github.com/golang/protobuf/ptypes/timestamp" + github_com_mwitkow_go_proto_validators "github.com/mwitkow/go-proto-validators" + math "math" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -16,13 +18,13 @@ var _ = math.Inf func (this *CommercialPaper) Validate() error { if this.IssueDate != nil { - if err := go_proto_validators.CallValidatorIfExists(this.IssueDate); err != nil { - return go_proto_validators.FieldError("IssueDate", err) + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.IssueDate); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("IssueDate", err) } } if this.MaturityDate != nil { - if err := go_proto_validators.CallValidatorIfExists(this.MaturityDate); err != nil { - return go_proto_validators.FieldError("MaturityDate", err) + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.MaturityDate); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("MaturityDate", err) } } return nil @@ -33,8 +35,8 @@ func (this *CommercialPaperId) Validate() error { func (this *CommercialPaperList) Validate() error { for _, item := range this.Items { if item != nil { - if err := go_proto_validators.CallValidatorIfExists(item); err != nil { - return go_proto_validators.FieldError("Items", err) + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("Items", err) } } } diff --git a/examples/cpaper_extended/testdata/admin/admin.key.pem b/examples/cpaper_extended/testdata/admin/admin.key.pem new file mode 100644 index 00000000..b4a78d32 --- /dev/null +++ b/examples/cpaper_extended/testdata/admin/admin.key.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBSoxUZoyY3jk1GD430 +8tIWWLiEw8dGL9SnfkG7AGQNHsYLz8hbamYtN9TPVg7JbemhZANiAASAPNEhxmCz +F7w+8rmE+iKHiTp+qinNnby69unp3eCpRD2XaI5zfPDiVZbPFm3uFsHskEGNwJyh +G84Vc74/Nw5jrIDU6p83i1yXCV2JafT5oCBsSLNw1vR3ddXW4vK7fJ8= +-----END PRIVATE KEY----- diff --git a/examples/cpaper_extended/testdata/admin/admin.pem b/examples/cpaper_extended/testdata/admin/admin.pem new file mode 100644 index 00000000..6e225d8e --- /dev/null +++ b/examples/cpaper_extended/testdata/admin/admin.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICTDCCAdECCQDXg5wOXASntDAKBggqhkjOPQQDAjCBjjELMAkGA1UEBhMCUlUx +DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRIwEAYDVQQKDAlTN1Rl +Y2hsYWIxEjAQBgNVBAsMCVM3VGVjaGxhYjESMBAGA1UEAwwJUzdUZWNobGFiMSEw +HwYJKoZIhvcNAQkBFhJpbmZvQHRlY2hsYWIuczcucnUwHhcNMTgxMTEzMTMxMTI3 +WhcNMjAxMTEyMTMxMTI3WjCBjjELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2Nv +dzEPMA0GA1UEBwwGTW9zY293MRIwEAYDVQQKDAlTN1RlY2hsYWIxEjAQBgNVBAsM +CVM3VGVjaGxhYjESMBAGA1UEAwwJUzdUZWNobGFiMSEwHwYJKoZIhvcNAQkBFhJp +bmZvQHRlY2hsYWIuczcucnUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASAPNEhxmCz +F7w+8rmE+iKHiTp+qinNnby69unp3eCpRD2XaI5zfPDiVZbPFm3uFsHskEGNwJyh +G84Vc74/Nw5jrIDU6p83i1yXCV2JafT5oCBsSLNw1vR3ddXW4vK7fJ8wCgYIKoZI +zj0EAwIDaQAwZgIxAMP56SfE7D8sjv5H4rU5CnXeJLoCmcDo20OQcMBbIoYNHiet +ReJZlqytK5WoPm8wHQIxANdPnajvejR+ZE7MMe+pd18uwGZ8hh9Hp6C9ugoipv0q +Oo4vB+J8+jEuRjSsXfMzPQ== +-----END CERTIFICATE----- diff --git a/examples/cpaper_extended/testdata/testdata.go b/examples/cpaper_extended/testdata/testdata.go index ddc42f61..30c7715a 100644 --- a/examples/cpaper_extended/testdata/testdata.go +++ b/examples/cpaper_extended/testdata/testdata.go @@ -1,33 +1,15 @@ package testdata import ( - "time" - "github.com/s7techlab/cckit/testing" - - "github.com/golang/protobuf/ptypes" - "github.com/s7techlab/cckit/examples/cpaper_extended/schema" + "io/ioutil" ) -var ( - // CPapers commercial paper fixtures - CPapers = []schema.IssueCommercialPaper{{ - Issuer: `some-issuer-1`, - PaperNumber: `00000001`, - IssueDate: ptypes.TimestampNow(), - MaturityDate: testing.MustProtoTimestamp(time.Now().AddDate(0, 1, 0)), - FaceValue: 11111, - ExternalId: `some-ext-id-1`, - }, { - Issuer: `some-issuer-2`, - PaperNumber: `00000002`, - IssueDate: ptypes.TimestampNow(), - MaturityDate: testing.MustProtoTimestamp(time.Now().AddDate(0, 2, 0)), - FaceValue: 22222, - }, { - Issuer: `some-issuer-3`, - PaperNumber: `00000003`, - IssueDate: ptypes.TimestampNow(), - MaturityDate: testing.MustProtoTimestamp(time.Now().AddDate(0, 3, 0)), - }} -) +func GetTestIdentity(msp, file string) *testing.Identity { + identity, err := testing.IdentityFromFile(msp, file, ioutil.ReadFile) + if err != nil { + panic(err) + } + + return identity +} diff --git a/state/mapping/mapping_test.go b/state/mapping/mapping_test.go index b9972e40..12cb475c 100644 --- a/state/mapping/mapping_test.go +++ b/state/mapping/mapping_test.go @@ -1,20 +1,14 @@ package mapping_test import ( + "github.com/s7techlab/cckit/state/mapping" "testing" "github.com/golang/protobuf/ptypes" "github.com/hyperledger/fabric/protos/peer" - "github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto" examplecert "github.com/s7techlab/cckit/examples/cert" - "github.com/s7techlab/cckit/examples/cpaper" - cpaper_schema "github.com/s7techlab/cckit/examples/cpaper/schema" - cpaper_testdata "github.com/s7techlab/cckit/examples/cpaper/testdata" - "github.com/s7techlab/cckit/examples/cpaper_extended" - cpaper_extended_schema "github.com/s7techlab/cckit/examples/cpaper_extended/schema" - cpaper_extended_testdata "github.com/s7techlab/cckit/examples/cpaper_extended/testdata" + "github.com/s7techlab/cckit/state" - "github.com/s7techlab/cckit/state/mapping" "github.com/s7techlab/cckit/state/mapping/testdata" "github.com/s7techlab/cckit/state/mapping/testdata/schema" state_schema "github.com/s7techlab/cckit/state/schema" @@ -31,9 +25,9 @@ func TestState(t *testing.T) { } var ( - actors testcc.Identities - cPaperCC, cPaperExtendedCC, complexIDCC, sliceIDCC *testcc.MockStub - err error + actors testcc.Identities + protoCC, complexIDCC, sliceIDCC *testcc.MockStub + err error ) var _ = Describe(`Mapping`, func() { @@ -44,12 +38,8 @@ var _ = Describe(`Mapping`, func() { Expect(err).To(BeNil()) - //Create commercial papers chaincode mock - protobuf based schema - cPaperCC = testcc.NewMockStub(`cpapers`, cpaper.NewCC()) - cPaperCC.From(actors[`owner`]).Init() - - cPaperExtendedCC = testcc.NewMockStub(`cpapers_extended`, cpaper_extended.NewCC()) - cPaperExtendedCC.From(actors[`owner`]).Init() + protoCC = testcc.NewMockStub(`cpapers`, testdata.NewProtoCC()) + protoCC.From(actors[`owner`]).Init() complexIDCC = testcc.NewMockStub(`complexid`, testdata.NewComplexIdCC()) complexIDCC.From(actors[`owner`]).Init() @@ -58,150 +48,132 @@ var _ = Describe(`Mapping`, func() { sliceIDCC.From(actors[`owner`]).Init() }) - Describe(`Commercial paper, protobuf based schema`, func() { - - var cpaper1 = &cpaper_testdata.CPapers[0] - var cpaper2 = &cpaper_testdata.CPapers[1] - var cpaper3 = &cpaper_testdata.CPapers[2] + Describe(`Commercial paper extended, protobuf based schema with additional keys`, func() { + issueMock1 := testdata.ProtoIssueMocks[0] + issueMock2 := testdata.ProtoIssueMocks[1] + issueMock3 := testdata.ProtoIssueMocks[2] + issueMockExistingExternal := testdata.ProtoIssueMockExistingExternal + issueMockExistingPrimary := testdata.ProtoIssueMockExistingPrimary It("Allow to get mapping data by namespace", func() { - mapping, err := cpaper.StateMappings.GetByNamespace(state.Key{`CommercialPaper`}) + mapping, err := testdata.ProtoStateMapping.GetByNamespace(state.Key{`ProtoEntity`}) Expect(err).NotTo(HaveOccurred()) - Expect(mapping.Schema()).To(BeEquivalentTo(&cpaper_schema.CommercialPaper{})) + Expect(mapping.Schema()).To(BeEquivalentTo(&schema.ProtoEntity{})) }) It("Allow to add data to chaincode state", func(done Done) { - - events := cPaperCC.EventSubscription() - expectcc.ResponseOk(cPaperCC.Invoke(`issue`, cpaper1)) + events := protoCC.EventSubscription() + expectcc.ResponseOk(protoCC.Invoke(`issue`, &issueMock1)) Expect(<-events).To(BeEquivalentTo(&peer.ChaincodeEvent{ - EventName: `IssueCommercialPaper`, - Payload: testcc.MustProtoMarshal(cpaper1), + EventName: `IssueProtoEntity`, + Payload: testcc.MustProtoMarshal(&issueMock1), })) - expectcc.ResponseOk(cPaperCC.Invoke(`issue`, cpaper2)) - expectcc.ResponseOk(cPaperCC.Invoke(`issue`, cpaper3)) + expectcc.ResponseOk(protoCC.Invoke(`issue`, &issueMock2)) + expectcc.ResponseOk(protoCC.Invoke(`issue`, &issueMock3)) close(done) }, 0.2) - It("Disallow to insert entries with same keys", func() { - expectcc.ResponseError(cPaperCC.Invoke(`issue`, cpaper1)) + It("Disallow to insert entries with same uniq AND primary keys", func() { + expectcc.ResponseError(protoCC.Invoke(`issue`, &issueMock1)) }) - It("Allow to get entry list", func() { - cpapers := expectcc.PayloadIs(cPaperCC.Query(`list`), - &cpaper_schema.CommercialPaperList{}).(*cpaper_schema.CommercialPaperList) - Expect(len(cpapers.Items)).To(Equal(3)) - Expect(cpapers.Items[0].Issuer).To(Equal(cpaper1.Issuer)) - Expect(cpapers.Items[0].PaperNumber).To(Equal(cpaper1.PaperNumber)) + It("Disallow to add data to chaincode state with same uniq key fields", func() { + // errored on checking uniq key + expectcc.ResponseError( + protoCC.Invoke(`issue`, &issueMockExistingExternal), + mapping.ErrMappingUniqKeyExists) }) - It("Allow to get entry raw protobuf", func() { - cpaperProtoFromCC := cPaperCC.Query(`get`, - &cpaper_schema.CommercialPaperId{Issuer: cpaper1.Issuer, PaperNumber: cpaper1.PaperNumber}).Payload - - stateCpaper := &cpaper_schema.CommercialPaper{ - Issuer: cpaper1.Issuer, - PaperNumber: cpaper1.PaperNumber, - Owner: cpaper1.Issuer, - IssueDate: cpaper1.IssueDate, - MaturityDate: cpaper1.MaturityDate, - FaceValue: cpaper1.FaceValue, - State: cpaper_schema.CommercialPaper_ISSUED, // initial state - } - Expect(cpaperProtoFromCC).To(Equal(testcc.MustProtoMarshal(stateCpaper))) + It("Disallow adding data to chaincode state with same primary key fields", func() { + // errored obn checkong primary key + expectcc.ResponseError( + protoCC.Invoke(`issue`, &issueMockExistingPrimary), + state.ErrKeyAlreadyExists) }) - It("Allow update data in chaincode state", func() { + It("Allow to get entry list", func() { + entities := expectcc.PayloadIs(protoCC.Query(`list`), + &schema.ProtoEntityList{}).(*schema.ProtoEntityList) + Expect(len(entities.Items)).To(Equal(3)) + Expect(entities.Items[0].Name).To(Equal(issueMock1.Name)) + Expect(entities.Items[0].Value).To(BeNumerically("==", 0)) + Expect(entities.Items[0].ExternalId).To(Equal(issueMock1.ExternalId)) + }) - expectcc.ResponseOk(cPaperCC.Invoke(`buy`, &cpaper_schema.BuyCommercialPaper{ - Issuer: cpaper1.Issuer, - PaperNumber: cpaper1.PaperNumber, - CurrentOwner: cpaper1.Issuer, - NewOwner: `some-new-owner`, - Price: cpaper1.FaceValue - 10, - PurchaseDate: ptypes.TimestampNow(), - })) + It("Allow finding data by uniq key", func() { + + cpaperFromCCByExtID := expectcc.PayloadIs( + protoCC.Query(`getByExternalId`, issueMock1.ExternalId), + &schema.ProtoEntity{}).(*schema.ProtoEntity) cpaperFromCC := expectcc.PayloadIs( - cPaperCC.Query(`get`, &cpaper_schema.CommercialPaperId{Issuer: cpaper1.Issuer, PaperNumber: cpaper1.PaperNumber}), - &cpaper_schema.CommercialPaper{}).(*cpaper_schema.CommercialPaper) + protoCC.Query(`get`, &schema.ProtoEntityId{ + IdFirstPart: issueMock1.IdFirstPart, + IdSecondPart: issueMock1.IdSecondPart}, + ), + &schema.ProtoEntity{}).(*schema.ProtoEntity) - // state is updated - Expect(cpaperFromCC.State).To(Equal(cpaper_schema.CommercialPaper_TRADING)) - Expect(cpaperFromCC.Owner).To(Equal(`some-new-owner`)) + Expect(cpaperFromCCByExtID).To(BeEquivalentTo(cpaperFromCC)) }) - It("Allow to delete entry", func() { - toDelete := &cpaper_schema.CommercialPaperId{Issuer: cpaper1.Issuer, PaperNumber: cpaper1.PaperNumber} - - expectcc.ResponseOk(cPaperCC.Invoke(`delete`, toDelete)) - cpapers := expectcc.PayloadIs(cPaperCC.Invoke(`list`), &state_schema.List{}).(*state_schema.List) - - Expect(len(cpapers.Items)).To(Equal(2)) - expectcc.ResponseError(cPaperCC.Invoke(`get`, toDelete), state.ErrKeyNotFound) + It("Disallow finding data by non existent uniq key", func() { + expectcc.ResponseError( + protoCC.Query(`getByExternalId`, `some-non-existent-id`), state.ErrKeyNotFound) }) - }) - - Describe(`Commercial paper extended, protobuf based schema with additional keys`, func() { - var cpaper1 = &cpaper_extended_testdata.CPapers[0] - - It("Allow to add data to chaincode state", func(done Done) { - events := cPaperExtendedCC.EventSubscription() - expectcc.ResponseOk(cPaperExtendedCC.Invoke(`issue`, cpaper1)) - - Expect(<-events).To(BeEquivalentTo(&peer.ChaincodeEvent{ - EventName: `IssueCommercialPaper`, - Payload: testcc.MustProtoMarshal(cpaper1), - })) - - close(done) - }, 0.2) - - It("Disallow to add data to chaincode state with same primary AND uniq key fields", func() { - expectcc.ResponseError(cPaperExtendedCC.Invoke(`issue`, cpaper1), mapping.ErrMappingUniqKeyExists) + It("Allow to get entry raw protobuf", func() { + cpaperProtoFromCC := protoCC.Query(`get`, + &schema.ProtoEntityId{ + IdFirstPart: issueMock1.IdFirstPart, + IdSecondPart: issueMock1.IdSecondPart}, + ).Payload + + stateProtoEntity := &schema.ProtoEntity{ + IdFirstPart: issueMock1.IdFirstPart, + IdSecondPart: issueMock1.IdSecondPart, + Name: issueMock1.Name, + Value: 0, + ExternalId: issueMock1.ExternalId, + } + Expect(cpaperProtoFromCC).To(Equal(testcc.MustProtoMarshal(stateProtoEntity))) }) - It("Disallow to add data to chaincode state with same uniq key fields", func() { - // change PK - cpChanged1 := proto.Clone(cpaper1).(*cpaper_extended_schema.IssueCommercialPaper) - cpChanged1.PaperNumber = `some-new-number` - - // errored on checking uniq key - expectcc.ResponseError(cPaperExtendedCC.Invoke(`issue`, cpChanged1), mapping.ErrMappingUniqKeyExists) - }) + It("Allow update data in chaincode state", func() { + expectcc.ResponseOk(protoCC.Invoke(`increment`, &schema.IncrementProtoEntity{ + IdFirstPart: issueMock1.IdFirstPart, + IdSecondPart: issueMock1.IdSecondPart, + Name: issueMock1.Name, + })) - It("Disallow to add data to chaincode state with same primary key fields", func() { - // change Uniq Key - cpChanged2 := proto.Clone(cpaper1).(*cpaper_extended_schema.IssueCommercialPaper) - cpChanged2.ExternalId = `some-new-external-id` + entityFromCC := expectcc.PayloadIs( + protoCC.Query(`get`, &schema.ProtoEntityId{ + IdFirstPart: issueMock1.IdFirstPart, + IdSecondPart: issueMock1.IdSecondPart, + }), + &schema.ProtoEntity{}).(*schema.ProtoEntity) - // errored obn checkong primary key - expectcc.ResponseError(cPaperExtendedCC.Invoke(`issue`, cpChanged2), state.ErrKeyAlreadyExists) + // state is updated + Expect(entityFromCC.Value).To(BeNumerically("==", 1)) }) - It("Allow to find data by uniq key", func() { - - cpaperFromCCByExtID := expectcc.PayloadIs( - cPaperExtendedCC.Query(`getByExternalId`, cpaper1.ExternalId), - &cpaper_extended_schema.CommercialPaper{}).(*cpaper_extended_schema.CommercialPaper) - - cpaperFromCC := expectcc.PayloadIs( - cPaperExtendedCC.Query(`get`, - &cpaper_extended_schema.CommercialPaperId{Issuer: cpaper1.Issuer, PaperNumber: cpaper1.PaperNumber}), - &cpaper_extended_schema.CommercialPaper{}).(*cpaper_extended_schema.CommercialPaper) + It("Allow to delete entry", func() { + toDelete := &schema.ProtoEntityId{ + IdFirstPart: issueMock1.IdFirstPart, + IdSecondPart: issueMock1.IdSecondPart, + } - Expect(cpaperFromCCByExtID).To(BeEquivalentTo(cpaperFromCC)) - }) + expectcc.ResponseOk(protoCC.Invoke(`delete`, toDelete)) + cpapers := expectcc.PayloadIs( + protoCC.Invoke(`list`), + &schema.ProtoEntityList{}, + ).(*schema.ProtoEntityList) - It("Disallow to find data by non existent uniq key", func() { - expectcc.ResponseError( - cPaperExtendedCC.Query(`getByExternalId`, `some-non-existent-id`), state.ErrKeyNotFound) + Expect(len(cpapers.Items)).To(Equal(2)) + expectcc.ResponseError(protoCC.Invoke(`get`, toDelete), state.ErrKeyNotFound) }) - }) Describe(`Entity with complex id`, func() { diff --git a/state/mapping/testdata/cc_proto_entity.go b/state/mapping/testdata/cc_proto_entity.go new file mode 100644 index 00000000..bda0ec0d --- /dev/null +++ b/state/mapping/testdata/cc_proto_entity.go @@ -0,0 +1,93 @@ +package testdata + +import ( + "github.com/s7techlab/cckit/extensions/debug" + "github.com/s7techlab/cckit/extensions/owner" + "github.com/s7techlab/cckit/router" + "github.com/s7techlab/cckit/router/param" + "github.com/s7techlab/cckit/router/param/defparam" + "github.com/s7techlab/cckit/state/mapping" + "github.com/s7techlab/cckit/state/mapping/testdata/schema" +) + +var ( + ProtoStateMapping = mapping.StateMappings{}. + Add(&schema.ProtoEntity{}, + mapping.PKeySchema(&schema.ProtoEntityId{}), + mapping.List(&schema.ProtoEntityList{}), + mapping.UniqKey("ExternalId"), + ) + + ProtoEventMapping = mapping.EventMappings{}. + Add(&schema.IssueProtoEntity{}). + Add(&schema.IncrementProtoEntity{}) +) + +func NewProtoCC() *router.Chaincode { + r := router.New("proto_test") + r.Use(mapping.MapStates(ProtoStateMapping)) + r.Use(mapping.MapEvents(ProtoEventMapping)) + r.Init(owner.InvokeSetFromCreator) + debug.AddHandlers(r, "debug", owner.Only) + + r. + Query("list", queryList). + Query("get", queryById, defparam.Proto(&schema.ProtoEntityId{})). + Query("getByExternalId", queryByExternalId, param.String("externalId")). + Invoke("issue", invokeIssue, defparam.Proto(&schema.IssueProtoEntity{})). + Invoke("increment", invokeIncrement, defparam.Proto(&schema.IncrementProtoEntity{})). + Invoke("delete", invokeDelte, defparam.Proto(&schema.ProtoEntityId{})) + + return router.NewChaincode(r) +} + +func queryById(c router.Context) (interface{}, error) { + return c.State().Get(c.Param().(*schema.ProtoEntityId)) +} + +func queryByExternalId(c router.Context) (interface{}, error) { + externalId := c.ParamString("externalId") + return c.State().(mapping.MappedState).GetByUniqKey(&schema.ProtoEntity{}, "ExternalId", []string{externalId}) +} + +func queryList(c router.Context) (interface{}, error) { + return c.State().List(&schema.ProtoEntity{}) +} + +func invokeIssue(c router.Context) (interface{}, error) { + issueData := c.Param().(*schema.IssueProtoEntity) + entity := &schema.ProtoEntity{ + IdFirstPart: issueData.IdFirstPart, + IdSecondPart: issueData.IdSecondPart, + Name: issueData.Name, + Value: 0, + ExternalId: issueData.ExternalId, + } + + if err := c.Event().Set(issueData); err != nil { + return nil, err + } + + return entity, c.State().Insert(entity) +} + +func invokeIncrement(c router.Context) (interface{}, error) { + incrementData := c.Param().(*schema.IncrementProtoEntity) + entity, _ := c.State().Get( + &schema.ProtoEntityId{IdFirstPart: incrementData.IdFirstPart, IdSecondPart: incrementData.IdSecondPart}, + &schema.ProtoEntity{}) + + protoEntity := entity.(*schema.ProtoEntity) + + protoEntity.Value = protoEntity.Value + 1 + + if err := c.Event().Set(incrementData); err != nil { + return nil, err + } + + return protoEntity, c.State().Put(protoEntity) +} + +func invokeDelte(c router.Context) (interface{}, error) { + return nil, c.State().Delete(c.Param().(*schema.ProtoEntityId)) +} diff --git a/state/mapping/testdata/schema/complex_id.pb.go b/state/mapping/testdata/schema/complex_id.pb.go index 10e2a8c9..7cacb103 100644 --- a/state/mapping/testdata/schema/complex_id.pb.go +++ b/state/mapping/testdata/schema/complex_id.pb.go @@ -6,11 +6,17 @@ Package schema is a generated protocol buffer package. It is generated from these files: complex_id.proto + proto_schema.proto slice_id.proto It has these top-level messages: EntityWithComplexId EntityComplexId + ProtoEntity + ProtoEntityId + ProtoEntityList + IssueProtoEntity + IncrementProtoEntity EntityWithSliceId */ package schema diff --git a/state/mapping/testdata/schema/proto_schema.pb.go b/state/mapping/testdata/schema/proto_schema.pb.go new file mode 100644 index 00000000..1cc13057 --- /dev/null +++ b/state/mapping/testdata/schema/proto_schema.pb.go @@ -0,0 +1,208 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: proto_schema.proto + +package schema + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// ProtoEntity +type ProtoEntity struct { + IdFirstPart string `protobuf:"bytes,1,opt,name=id_first_part,json=idFirstPart" json:"id_first_part,omitempty"` + IdSecondPart string `protobuf:"bytes,2,opt,name=id_second_part,json=idSecondPart" json:"id_second_part,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` + Value int32 `protobuf:"varint,4,opt,name=value" json:"value,omitempty"` + ExternalId string `protobuf:"bytes,5,opt,name=external_id,json=externalId" json:"external_id,omitempty"` +} + +func (m *ProtoEntity) Reset() { *m = ProtoEntity{} } +func (m *ProtoEntity) String() string { return proto.CompactTextString(m) } +func (*ProtoEntity) ProtoMessage() {} +func (*ProtoEntity) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } + +func (m *ProtoEntity) GetIdFirstPart() string { + if m != nil { + return m.IdFirstPart + } + return "" +} + +func (m *ProtoEntity) GetIdSecondPart() string { + if m != nil { + return m.IdSecondPart + } + return "" +} + +func (m *ProtoEntity) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *ProtoEntity) GetValue() int32 { + if m != nil { + return m.Value + } + return 0 +} + +func (m *ProtoEntity) GetExternalId() string { + if m != nil { + return m.ExternalId + } + return "" +} + +// ProtoEntityId +type ProtoEntityId struct { + IdFirstPart string `protobuf:"bytes,1,opt,name=id_first_part,json=idFirstPart" json:"id_first_part,omitempty"` + IdSecondPart string `protobuf:"bytes,2,opt,name=id_second_part,json=idSecondPart" json:"id_second_part,omitempty"` +} + +func (m *ProtoEntityId) Reset() { *m = ProtoEntityId{} } +func (m *ProtoEntityId) String() string { return proto.CompactTextString(m) } +func (*ProtoEntityId) ProtoMessage() {} +func (*ProtoEntityId) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } + +func (m *ProtoEntityId) GetIdFirstPart() string { + if m != nil { + return m.IdFirstPart + } + return "" +} + +func (m *ProtoEntityId) GetIdSecondPart() string { + if m != nil { + return m.IdSecondPart + } + return "" +} + +// ProtoEntityList +type ProtoEntityList struct { + Items []*ProtoEntity `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"` +} + +func (m *ProtoEntityList) Reset() { *m = ProtoEntityList{} } +func (m *ProtoEntityList) String() string { return proto.CompactTextString(m) } +func (*ProtoEntityList) ProtoMessage() {} +func (*ProtoEntityList) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } + +func (m *ProtoEntityList) GetItems() []*ProtoEntity { + if m != nil { + return m.Items + } + return nil +} + +// IssueProtoEntity +type IssueProtoEntity struct { + IdFirstPart string `protobuf:"bytes,1,opt,name=id_first_part,json=idFirstPart" json:"id_first_part,omitempty"` + IdSecondPart string `protobuf:"bytes,2,opt,name=id_second_part,json=idSecondPart" json:"id_second_part,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` + ExternalId string `protobuf:"bytes,5,opt,name=external_id,json=externalId" json:"external_id,omitempty"` +} + +func (m *IssueProtoEntity) Reset() { *m = IssueProtoEntity{} } +func (m *IssueProtoEntity) String() string { return proto.CompactTextString(m) } +func (*IssueProtoEntity) ProtoMessage() {} +func (*IssueProtoEntity) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{3} } + +func (m *IssueProtoEntity) GetIdFirstPart() string { + if m != nil { + return m.IdFirstPart + } + return "" +} + +func (m *IssueProtoEntity) GetIdSecondPart() string { + if m != nil { + return m.IdSecondPart + } + return "" +} + +func (m *IssueProtoEntity) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *IssueProtoEntity) GetExternalId() string { + if m != nil { + return m.ExternalId + } + return "" +} + +// IncrementProtoEntity +type IncrementProtoEntity struct { + IdFirstPart string `protobuf:"bytes,1,opt,name=id_first_part,json=idFirstPart" json:"id_first_part,omitempty"` + IdSecondPart string `protobuf:"bytes,2,opt,name=id_second_part,json=idSecondPart" json:"id_second_part,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` +} + +func (m *IncrementProtoEntity) Reset() { *m = IncrementProtoEntity{} } +func (m *IncrementProtoEntity) String() string { return proto.CompactTextString(m) } +func (*IncrementProtoEntity) ProtoMessage() {} +func (*IncrementProtoEntity) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{4} } + +func (m *IncrementProtoEntity) GetIdFirstPart() string { + if m != nil { + return m.IdFirstPart + } + return "" +} + +func (m *IncrementProtoEntity) GetIdSecondPart() string { + if m != nil { + return m.IdSecondPart + } + return "" +} + +func (m *IncrementProtoEntity) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func init() { + proto.RegisterType((*ProtoEntity)(nil), "schema.ProtoEntity") + proto.RegisterType((*ProtoEntityId)(nil), "schema.ProtoEntityId") + proto.RegisterType((*ProtoEntityList)(nil), "schema.ProtoEntityList") + proto.RegisterType((*IssueProtoEntity)(nil), "schema.IssueProtoEntity") + proto.RegisterType((*IncrementProtoEntity)(nil), "schema.IncrementProtoEntity") +} + +func init() { proto.RegisterFile("proto_schema.proto", fileDescriptor1) } + +var fileDescriptor1 = []byte{ + // 251 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x92, 0x31, 0x4b, 0x04, 0x31, + 0x10, 0x85, 0x89, 0x77, 0x7b, 0xe0, 0xac, 0xa7, 0x12, 0xaf, 0x48, 0xe7, 0x12, 0x2c, 0xd6, 0xe6, + 0x0a, 0x6d, 0x6d, 0x15, 0x16, 0x2c, 0x8e, 0xb5, 0xb2, 0x0a, 0x71, 0x33, 0xe2, 0xc0, 0x6d, 0xf6, + 0x48, 0xe6, 0x44, 0x7f, 0x86, 0x7f, 0xc1, 0x5f, 0x2a, 0x97, 0x28, 0x6c, 0x67, 0x73, 0x5c, 0x97, + 0xf7, 0xf2, 0xcd, 0xf0, 0x78, 0x0c, 0xc8, 0x4d, 0x18, 0x78, 0x30, 0xb1, 0x7b, 0xc3, 0xde, 0x2e, + 0x93, 0x90, 0xb3, 0xac, 0xf4, 0xb7, 0x80, 0x72, 0xb5, 0x73, 0xee, 0x3d, 0x13, 0x7f, 0x4a, 0x0d, + 0x73, 0x72, 0xe6, 0x95, 0x42, 0x64, 0xb3, 0xb1, 0x81, 0x95, 0xa8, 0x44, 0x7d, 0xdc, 0x96, 0xe4, + 0x1e, 0x76, 0xde, 0xca, 0x06, 0x96, 0x57, 0x70, 0x4a, 0xce, 0x44, 0xec, 0x06, 0xef, 0x32, 0x74, + 0x94, 0xa0, 0x13, 0x72, 0x4f, 0xc9, 0x4c, 0x94, 0x84, 0xa9, 0xb7, 0x3d, 0xaa, 0x49, 0xfa, 0x4b, + 0x6f, 0xb9, 0x80, 0xe2, 0xdd, 0xae, 0xb7, 0xa8, 0xa6, 0x95, 0xa8, 0x8b, 0x36, 0x0b, 0x79, 0x09, + 0x25, 0x7e, 0x30, 0x06, 0x6f, 0xd7, 0x86, 0x9c, 0x2a, 0xd2, 0x00, 0xfc, 0x59, 0x8d, 0xd3, 0xcf, + 0x30, 0x1f, 0x65, 0x6c, 0xdc, 0xfe, 0x52, 0xea, 0x3b, 0x38, 0x1b, 0xad, 0x7e, 0xa4, 0xc8, 0xf2, + 0x1a, 0x0a, 0x62, 0xec, 0xa3, 0x12, 0xd5, 0xa4, 0x2e, 0x6f, 0x2e, 0x96, 0xbf, 0xc5, 0x8d, 0xb8, + 0x36, 0x13, 0xfa, 0x4b, 0xc0, 0x79, 0x13, 0xe3, 0x16, 0x0f, 0x57, 0xe1, 0xbf, 0x65, 0x31, 0x2c, + 0x1a, 0xdf, 0x05, 0xec, 0xd1, 0xf3, 0xc1, 0x62, 0xbd, 0xcc, 0xd2, 0x59, 0xdd, 0xfe, 0x04, 0x00, + 0x00, 0xff, 0xff, 0x0a, 0xda, 0xc5, 0x5b, 0x6c, 0x02, 0x00, 0x00, +} diff --git a/state/mapping/testdata/schema/proto_schema.proto b/state/mapping/testdata/schema/proto_schema.proto new file mode 100644 index 00000000..8e39cd7c --- /dev/null +++ b/state/mapping/testdata/schema/proto_schema.proto @@ -0,0 +1,37 @@ +syntax = "proto3"; +package schema; + +// ProtoEntity +message ProtoEntity { + string id_first_part = 1; + string id_second_part = 2; + string name = 3; + int32 value = 4; + string external_id = 5; +} + +// ProtoEntityId +message ProtoEntityId { + string id_first_part = 1; + string id_second_part = 2; +} + +// ProtoEntityList +message ProtoEntityList { + repeated ProtoEntity items = 1; +} + +// IssueProtoEntity +message IssueProtoEntity { + string id_first_part = 1; + string id_second_part = 2; + string name = 3; + string external_id = 5; +} + +// IncrementProtoEntity +message IncrementProtoEntity { + string id_first_part = 1; + string id_second_part = 2; + string name = 3; +} diff --git a/state/mapping/testdata/schema/slice_id.pb.go b/state/mapping/testdata/schema/slice_id.pb.go index 3ffb6064..df2443ff 100644 --- a/state/mapping/testdata/schema/slice_id.pb.go +++ b/state/mapping/testdata/schema/slice_id.pb.go @@ -21,7 +21,7 @@ type EntityWithSliceId struct { func (m *EntityWithSliceId) Reset() { *m = EntityWithSliceId{} } func (m *EntityWithSliceId) String() string { return proto.CompactTextString(m) } func (*EntityWithSliceId) ProtoMessage() {} -func (*EntityWithSliceId) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } +func (*EntityWithSliceId) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} } func (m *EntityWithSliceId) GetId() []string { if m != nil { @@ -41,9 +41,9 @@ func init() { proto.RegisterType((*EntityWithSliceId)(nil), "schema.EntityWithSliceId") } -func init() { proto.RegisterFile("slice_id.proto", fileDescriptor1) } +func init() { proto.RegisterFile("slice_id.proto", fileDescriptor2) } -var fileDescriptor1 = []byte{ +var fileDescriptor2 = []byte{ // 153 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2b, 0xce, 0xc9, 0x4c, 0x4e, 0x8d, 0xcf, 0x4c, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2b, 0x4e, 0xce, 0x48, diff --git a/state/mapping/testdata/testdata.go b/state/mapping/testdata/testdata.go new file mode 100644 index 00000000..8afc8cec --- /dev/null +++ b/state/mapping/testdata/testdata.go @@ -0,0 +1,36 @@ +package testdata + +import "github.com/s7techlab/cckit/state/mapping/testdata/schema" + +var ( + ProtoIssueMocks = []schema.IssueProtoEntity{{ + IdFirstPart: "A", + IdSecondPart: "1", + Name: "Lorem", + ExternalId: "EXT1", + }, { + IdFirstPart: "B", + IdSecondPart: "1", + Name: "Ipsum", + ExternalId: "EXT2", + }, { + IdFirstPart: "B", + IdSecondPart: "2", + Name: "Dolor", + ExternalId: "EXT3", + }} + + ProtoIssueMockExistingExternal = schema.IssueProtoEntity{ + IdFirstPart: "Z", + IdSecondPart: "1", + Name: "Lorem", + ExternalId: "EXT1", + } + + ProtoIssueMockExistingPrimary = schema.IssueProtoEntity{ + IdFirstPart: "A", + IdSecondPart: "1", + Name: "Lorem", + ExternalId: "EXT100", + } +) diff --git a/testing/identity.go b/testing/identity.go index 01270cab..865bf601 100644 --- a/testing/identity.go +++ b/testing/identity.go @@ -39,7 +39,7 @@ func IdentityFromPem(mspID string, certPEM []byte) (*Identity, error) { return NewIdentity(mspID, certIdentity.Cert), nil } -// ActorsFromPem returns CertIdentity (MSP ID and X.509 cert) converted PEM content +// IdentitiesFromPem returns CertIdentity (MSP ID and X.509 cert) converted PEM content func IdentitiesFromPem(mspID string, certPEMs map[string][]byte) (ids Identities, err error) { identities := make(Identities) for role, certPEM := range certPEMs { @@ -50,7 +50,7 @@ func IdentitiesFromPem(mspID string, certPEMs map[string][]byte) (ids Identities return identities, nil } -// ActorsFromPemFile returns map of CertIdentity, loaded from PEM files +// IdentitiesFromFiles returns map of CertIdentity, loaded from PEM files func IdentitiesFromFiles(mspID string, files map[string]string, getContent identity.GetContent) (Identities, error) { contents := make(map[string][]byte) for key, filename := range files { @@ -63,6 +63,16 @@ func IdentitiesFromFiles(mspID string, files map[string]string, getContent ident return IdentitiesFromPem(mspID, contents) } +// IdentityFromFile returns Identity struct containing mspId and certificate +func IdentityFromFile(mspID string, file string, getContent identity.GetContent) (*Identity, error) { + content, err := getContent(file) + if err != nil { + return nil, err + } + + return IdentityFromPem(mspID, content) +} + // MustIdentitiesFromFiles func MustIdentitiesFromFiles(mspID string, files map[string]string, getContent identity.GetContent) Identities { ids, err := IdentitiesFromFiles(mspID, files, getContent)