From e185742746497cdb462eb63b17d43edb8809673f Mon Sep 17 00:00:00 2001 From: Nicko Guyer Date: Wed, 16 Feb 2022 17:01:46 -0500 Subject: [PATCH 1/2] Add query support for Fabric Signed-off-by: Nicko Guyer --- internal/blockchain/fabric/fabric.go | 211 ++++++++++++------ internal/blockchain/fabric/fabric_test.go | 172 ++++++++++++-- .../assetcreator/chaincode/smartcontract.go | 5 + test/e2e/fabric_contract_test.go | 68 +++++- 4 files changed, 362 insertions(+), 94 deletions(-) diff --git a/internal/blockchain/fabric/fabric.go b/internal/blockchain/fabric/fabric.go index 554d97d3a5..bf6d7ec2ac 100644 --- a/internal/blockchain/fabric/fabric.go +++ b/internal/blockchain/fabric/fabric.go @@ -66,17 +66,13 @@ type eventStreamWebsocket struct { Topic string `json:"topic"` } -type fabBatchPinInput struct { - Namespace string `json:"namespace"` - UUIDs string `json:"uuids"` - BatchHash string `json:"batchHash"` - PayloadRef string `json:"payloadRef"` - Contexts []string `json:"contexts"` -} - type fabTxInputHeaders struct { + ID string `json:"id,omitempty"` Type string `json:"type"` PayloadSchema *PayloadSchema `json:"payloadSchema,omitempty"` + Signer string `json:"signer,omitempty"` + Channel string `json:"channel,omitempty"` + Chaincode string `json:"chaincode,omitempty"` } type PayloadSchema struct { @@ -89,39 +85,19 @@ type PrefixItem struct { Type string `json:"type"` } -func newTxInputHeaders() *fabTxInputHeaders { - return &fabTxInputHeaders{ - Type: "SendTransaction", - } -} - -type fabTxInput struct { +type fabTxNamedInput struct { Headers *fabTxInputHeaders `json:"headers"` Func string `json:"func"` - Args []string `json:"args"` + Args map[string]string `json:"args"` } -type fabTxNamedInput struct { +type fabQueryNamedOutput struct { Headers *fabTxInputHeaders `json:"headers"` - Func string `json:"func"` - Args map[string]string `json:"args"` + Result interface{} `json:"result"` } -func newTxInput(pinInput *fabBatchPinInput) *fabTxInput { - hashesJSON, _ := json.Marshal(pinInput.Contexts) - stringifiedHashes := string(hashesJSON) - input := &fabTxInput{ - Headers: newTxInputHeaders(), - Func: "PinBatch", - Args: []string{ - pinInput.Namespace, - pinInput.UUIDs, - pinInput.BatchHash, - pinInput.PayloadRef, - stringifiedHashes, - }, - } - return input +type ffiParamSchema struct { + Type string `json:"type,omitempty"` } type fabWSCommandPayload struct { @@ -141,8 +117,33 @@ type Location struct { } var batchPinEvent = "BatchPin" +var batchPinMethodName = "PinBatch" +var batchPinPrefixItems = []*PrefixItem{ + { + Name: "namespace", + Type: "string", + }, + { + Name: "uuids", + Type: "string", + }, + { + Name: "batchHash", + Type: "string", + }, + { + Name: "payloadRef", + Type: "string", + }, + { + Name: "contexts", + Type: "string", + }, +} + var fullIdentityPattern = regexp.MustCompile(".+::x509::(.+)::.+") -var cnPatteren = regexp.MustCompile("CN=([^,]+)") + +var cnPattern = regexp.MustCompile("CN=([^,]+)") func (f *Fabric) Name() string { return "fabric" @@ -495,15 +496,25 @@ func (f *Fabric) ResolveSigningKey(ctx context.Context, signingKeyInput string) return signingKeyInput, nil } -func (f *Fabric) invokeContractMethod(ctx context.Context, channel, chaincode, signingKey string, requestID string, input interface{}) (*resty.Response, error) { +func (f *Fabric) invokeContractMethod(ctx context.Context, channel, chaincode, methodName, signingKey, requestID string, prefixItems []*PrefixItem, input map[string]string) (*resty.Response, error) { + in := &fabTxNamedInput{ + Headers: &fabTxInputHeaders{ + ID: requestID, + PayloadSchema: &PayloadSchema{ + Type: "array", + PrefixItems: prefixItems, + }, + Channel: channel, + Chaincode: chaincode, + Signer: getUserName(signingKey), + }, + Func: methodName, + Args: input, + } + return f.client.R(). SetContext(ctx). - SetQueryParam(f.prefixShort+"-signer", getUserName(signingKey)). - SetQueryParam(f.prefixShort+"-channel", channel). - SetQueryParam(f.prefixShort+"-chaincode", chaincode). - SetQueryParam(f.prefixShort+"-sync", "false"). - SetQueryParam(f.prefixShort+"-id", requestID). - SetBody(input). + SetBody(in). Post("/transactions") } @@ -512,7 +523,7 @@ func getUserName(fullIDString string) string { if len(matches) == 0 { return fullIDString } - matches = cnPatteren.FindStringSubmatch(matches[1]) + matches = cnPattern.FindStringSubmatch(matches[1]) if len(matches) > 1 { return matches[1] } @@ -534,15 +545,17 @@ func (f *Fabric) SubmitBatchPin(ctx context.Context, operationID *fftypes.UUID, var uuids fftypes.Bytes32 copy(uuids[0:16], (*batch.TransactionID)[:]) copy(uuids[16:32], (*batch.BatchID)[:]) - pinInput := &fabBatchPinInput{ - Namespace: batch.Namespace, - UUIDs: hexFormatB32(&uuids), - BatchHash: hexFormatB32(batch.BatchHash), - PayloadRef: batch.BatchPayloadRef, - Contexts: hashes, - } - input := newTxInput(pinInput) - res, err := f.invokeContractMethod(ctx, f.defaultChannel, f.chaincode, signingKey, operationID.String(), input) + pinInput := map[string]interface{}{ + "namespace": batch.Namespace, + "uuids": hexFormatB32(&uuids), + "batchHash": hexFormatB32(batch.BatchHash), + "payloadRef": batch.BatchPayloadRef, + "contexts": hashes, + } + + input, _ := jsonEncodeInput(pinInput) + + res, err := f.invokeContractMethod(ctx, f.defaultChannel, f.chaincode, batchPinMethodName, signingKey, operationID.String(), batchPinPrefixItems, input) if err != nil || !res.IsSuccess() { return restclient.WrapRestErr(ctx, res, err, i18n.MsgFabconnectRESTErr) } @@ -555,52 +568,102 @@ func (f *Fabric) InvokeContract(ctx context.Context, operationID *fftypes.UUID, if err != nil { return i18n.WrapError(ctx, err, i18n.MsgJSONObjectParseFailed, "params") } - in := &fabTxNamedInput{ - Func: method.Name, - Headers: newTxInputHeaders(), - Args: args, - } - in.Headers.PayloadSchema = &PayloadSchema{ - Type: "array", - PrefixItems: make([]*PrefixItem, len(method.Params)), + + fabricOnChainLocation, err := parseContractLocation(ctx, location) + if err != nil { + return err } // Build the payload schema for the method parameters + prefixItems := make([]*PrefixItem, len(method.Params)) for i, param := range method.Params { - in.Headers.PayloadSchema.PrefixItems[i] = &PrefixItem{ + var paramSchema ffiParamSchema + if err := json.Unmarshal(param.Schema.Bytes(), ¶mSchema); err != nil { + return i18n.WrapError(ctx, err, i18n.MsgJSONObjectParseFailed, fmt.Sprintf("%s.schema", param.Name)) + } + + prefixItems[i] = &PrefixItem{ Name: param.Name, - Type: "string", + Type: paramSchema.Type, } } + res, err := f.invokeContractMethod(ctx, fabricOnChainLocation.Channel, fabricOnChainLocation.Chaincode, method.Name, signingKey, operationID.String(), prefixItems, args) + + if err != nil || !res.IsSuccess() { + return restclient.WrapRestErr(ctx, res, err, i18n.MsgFabconnectRESTErr) + } + return nil +} + +func (f *Fabric) QueryContract(ctx context.Context, location *fftypes.JSONAny, method *fftypes.FFIMethod, input map[string]interface{}) (interface{}, error) { + // All arguments must be JSON serialized + args, err := jsonEncodeInput(input) + if err != nil { + return nil, i18n.WrapError(ctx, err, i18n.MsgJSONObjectParseFailed, "params") + } + fabricOnChainLocation, err := parseContractLocation(ctx, location) if err != nil { - return err + return nil, err + } + + // Build the payload schema for the method parameters + prefixItems := make([]*PrefixItem, len(method.Params)) + for i, param := range method.Params { + prefixItems[i] = &PrefixItem{ + Name: param.Name, + Type: "string", + } + } + + in := &fabTxNamedInput{ + Headers: &fabTxInputHeaders{ + PayloadSchema: &PayloadSchema{ + Type: "array", + PrefixItems: prefixItems, + }, + Channel: fabricOnChainLocation.Channel, + Chaincode: fabricOnChainLocation.Chaincode, + Signer: f.signer, + }, + Func: method.Name, + Args: args, } - res, err := f.invokeContractMethod(ctx, fabricOnChainLocation.Channel, fabricOnChainLocation.Chaincode, signingKey, operationID.String(), in) + res, err := f.client.R(). + SetContext(ctx). + SetBody(in). + Post("/query") + if err != nil || !res.IsSuccess() { - return restclient.WrapRestErr(ctx, res, err, i18n.MsgFabconnectRESTErr) + return nil, restclient.WrapRestErr(ctx, res, err, i18n.MsgFabconnectRESTErr) } - return nil + output := &fabQueryNamedOutput{} + if err = json.Unmarshal(res.Body(), output); err != nil { + return nil, err + } + return output.Result, nil } func jsonEncodeInput(params map[string]interface{}) (output map[string]string, err error) { output = make(map[string]string, len(params)) for field, value := range params { - encodedValue, err := json.Marshal(value) - if err != nil { - return nil, err + switch v := value.(type) { + case string: + output[field] = v + default: + encodedValue, err := json.Marshal(v) + if err != nil { + return nil, err + } + output[field] = string(encodedValue) } - output[field] = string(encodedValue) + } return } -func (f *Fabric) QueryContract(ctx context.Context, location *fftypes.JSONAny, method *fftypes.FFIMethod, input map[string]interface{}) (interface{}, error) { - return nil, fmt.Errorf(("not yet supported")) -} - func (f *Fabric) ValidateContractLocation(ctx context.Context, location *fftypes.JSONAny) (err error) { _, err = parseContractLocation(ctx, location) return diff --git a/internal/blockchain/fabric/fabric_test.go b/internal/blockchain/fabric/fabric_test.go index 5252009bd9..e0cd9df216 100644 --- a/internal/blockchain/fabric/fabric_test.go +++ b/internal/blockchain/fabric/fabric_test.go @@ -85,6 +85,10 @@ func testFFIMethod() *fftypes.FFIMethod { Name: "y", Schema: fftypes.JSONAnyPtr(`{"type": "integer"}`), }, + { + Name: "description", + Schema: fftypes.JSONAnyPtr(`{"type": "string"}`), + }, }, Returns: []*fftypes.FFIParam{ { @@ -397,11 +401,10 @@ func TestSubmitBatchPinOK(t *testing.T) { func(req *http.Request) (*http.Response, error) { var body map[string]interface{} json.NewDecoder(req.Body).Decode(&body) - assert.Equal(t, signer, req.FormValue(defaultPrefixShort+"-signer")) - assert.Equal(t, "false", req.FormValue(defaultPrefixShort+"-sync")) - assert.Equal(t, "0x9ffc50ff6bfe4502adc793aea54cc059c5df767cfe444e038eb51c5523097db5", (body["args"].([]interface{}))[1]) - assert.Equal(t, hexFormatB32(batch.BatchHash), (body["args"].([]interface{}))[2]) - assert.Equal(t, "Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (body["args"].([]interface{}))[3]) + assert.Equal(t, signer, (body["headers"].(map[string]interface{}))["signer"]) + assert.Equal(t, "0x9ffc50ff6bfe4502adc793aea54cc059c5df767cfe444e038eb51c5523097db5", (body["args"].(map[string]interface{}))["uuids"]) + assert.Equal(t, hexFormatB32(batch.BatchHash), (body["args"].(map[string]interface{}))["batchHash"]) + assert.Equal(t, "Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (body["args"].(map[string]interface{}))["payloadRef"]) return httpmock.NewJsonResponderOrPanic(200, "")(req) }) @@ -433,11 +436,10 @@ func TestSubmitBatchEmptyPayloadRef(t *testing.T) { func(req *http.Request) (*http.Response, error) { var body map[string]interface{} json.NewDecoder(req.Body).Decode(&body) - assert.Equal(t, signer, req.FormValue("fly-signer")) - assert.Equal(t, "false", req.FormValue("fly-sync")) - assert.Equal(t, "0x9ffc50ff6bfe4502adc793aea54cc059c5df767cfe444e038eb51c5523097db5", (body["args"].([]interface{}))[1]) - assert.Equal(t, hexFormatB32(batch.BatchHash), (body["args"].([]interface{}))[2]) - assert.Equal(t, "", (body["args"].([]interface{}))[3]) + assert.Equal(t, signer, (body["headers"].(map[string]interface{}))["signer"]) + assert.Equal(t, "0x9ffc50ff6bfe4502adc793aea54cc059c5df767cfe444e038eb51c5523097db5", (body["args"].(map[string]interface{}))["uuids"]) + assert.Equal(t, hexFormatB32(batch.BatchHash), (body["args"].(map[string]interface{}))["batchHash"]) + assert.Equal(t, "", (body["args"].(map[string]interface{}))["payloadRef"]) return httpmock.NewJsonResponderOrPanic(200, "")(req) }) @@ -1329,8 +1331,9 @@ func TestInvokeContractOK(t *testing.T) { } method := testFFIMethod() params := map[string]interface{}{ - "x": float64(1), - "y": float64(2), + "x": float64(1), + "y": float64(2), + "description": "test", } locationBytes, err := json.Marshal(location) assert.NoError(t, err) @@ -1338,18 +1341,49 @@ func TestInvokeContractOK(t *testing.T) { func(req *http.Request) (*http.Response, error) { var body map[string]interface{} json.NewDecoder(req.Body).Decode(&body) - assert.Equal(t, signingKey, req.URL.Query().Get(defaultPrefixShort+"-signer")) - assert.Equal(t, "firefly", req.URL.Query().Get(defaultPrefixShort+"-channel")) - assert.Equal(t, "simplestorage", req.URL.Query().Get(defaultPrefixShort+"-chaincode")) - assert.Equal(t, "false", req.URL.Query().Get(defaultPrefixShort+"-sync")) + assert.Equal(t, signingKey, (body["headers"].(map[string]interface{}))["signer"]) + assert.Equal(t, "firefly", (body["headers"].(map[string]interface{}))["channel"]) + assert.Equal(t, "simplestorage", (body["headers"].(map[string]interface{}))["chaincode"]) assert.Equal(t, "1", body["args"].(map[string]interface{})["x"]) assert.Equal(t, "2", body["args"].(map[string]interface{})["y"]) + assert.Equal(t, "test", body["args"].(map[string]interface{})["description"]) return httpmock.NewJsonResponderOrPanic(200, "")(req) }) err = e.InvokeContract(context.Background(), nil, signingKey, fftypes.JSONAnyPtrBytes(locationBytes), method, params) assert.NoError(t, err) } +func TestInvokeContractBadSchema(t *testing.T) { + e, cancel := newTestFabric() + defer cancel() + httpmock.ActivateNonDefault(e.client.GetClient()) + defer httpmock.DeactivateAndReset() + signingKey := fftypes.NewRandB32().String() + location := &Location{ + Channel: "firefly", + Chaincode: "simplestorage", + } + method := &fftypes.FFIMethod{ + Name: "sum", + Params: []*fftypes.FFIParam{ + { + Name: "x", + Schema: fftypes.JSONAnyPtr(`{not json]`), + }, + }, + Returns: []*fftypes.FFIParam{}, + } + params := map[string]interface{}{ + "x": float64(1), + "y": float64(2), + "description": "test", + } + locationBytes, err := json.Marshal(location) + assert.NoError(t, err) + err = e.InvokeContract(context.Background(), nil, signingKey, fftypes.JSONAnyPtrBytes(locationBytes), method, params) + assert.Regexp(t, "FF10151", err) +} + func TestInvokeContractChaincodeNotSet(t *testing.T) { e, cancel := newTestFabric() defer cancel() @@ -1392,6 +1426,100 @@ func TestInvokeContractFabconnectError(t *testing.T) { } func TestQueryContractOK(t *testing.T) { + e, cancel := newTestFabric() + defer cancel() + httpmock.ActivateNonDefault(e.client.GetClient()) + defer httpmock.DeactivateAndReset() + signingKey := fftypes.NewRandB32().String() + e.signer = signingKey + location := &Location{ + Channel: "firefly", + Chaincode: "simplestorage", + } + method := testFFIMethod() + params := map[string]interface{}{ + "x": float64(1), + "y": float64(2), + } + locationBytes, err := json.Marshal(location) + assert.NoError(t, err) + httpmock.RegisterResponder("POST", `http://localhost:12345/query`, + func(req *http.Request) (*http.Response, error) { + var body map[string]interface{} + json.NewDecoder(req.Body).Decode(&body) + assert.Equal(t, signingKey, body["headers"].(map[string]interface{})["signer"]) + assert.Equal(t, "firefly", body["headers"].(map[string]interface{})["channel"]) + assert.Equal(t, "simplestorage", body["headers"].(map[string]interface{})["chaincode"]) + assert.Equal(t, "1", body["args"].(map[string]interface{})["x"]) + assert.Equal(t, "2", body["args"].(map[string]interface{})["y"]) + return httpmock.NewJsonResponderOrPanic(200, &fabQueryNamedOutput{})(req) + }) + _, err = e.QueryContract(context.Background(), fftypes.JSONAnyPtrBytes(locationBytes), method, params) + assert.NoError(t, err) +} + +func TestQueryContractInputNotJSON(t *testing.T) { + e, cancel := newTestFabric() + defer cancel() + httpmock.ActivateNonDefault(e.client.GetClient()) + defer httpmock.DeactivateAndReset() + signingKey := fftypes.NewRandB32().String() + e.signer = signingKey + location := &Location{ + Channel: "firefly", + Chaincode: "simplestorage", + } + method := testFFIMethod() + params := map[string]interface{}{ + "bad": map[interface{}]interface{}{true: false}, + } + locationBytes, err := json.Marshal(location) + assert.NoError(t, err) + _, err = e.QueryContract(context.Background(), fftypes.JSONAnyPtrBytes(locationBytes), method, params) + assert.Regexp(t, "FF10151", err) +} + +func TestQueryContractBadLocation(t *testing.T) { + e, cancel := newTestFabric() + defer cancel() + httpmock.ActivateNonDefault(e.client.GetClient()) + defer httpmock.DeactivateAndReset() + signingKey := fftypes.NewRandB32().String() + e.signer = signingKey + method := testFFIMethod() + params := map[string]interface{}{ + "x": float64(1), + "y": float64(2), + } + _, err := e.QueryContract(context.Background(), fftypes.JSONAnyPtr(`{"validLocation": false}`), method, params) + assert.Regexp(t, "FF10310", err) +} + +func TestQueryContractFabconnectError(t *testing.T) { + e, cancel := newTestFabric() + defer cancel() + httpmock.ActivateNonDefault(e.client.GetClient()) + defer httpmock.DeactivateAndReset() + location := &Location{ + Channel: "fabric", + Chaincode: "simplestorage", + } + method := testFFIMethod() + params := map[string]interface{}{ + "x": float64(1), + "y": float64(2), + } + locationBytes, err := json.Marshal(location) + assert.NoError(t, err) + httpmock.RegisterResponder("POST", `http://localhost:12345/query`, + func(req *http.Request) (*http.Response, error) { + return httpmock.NewJsonResponderOrPanic(400, &fabQueryNamedOutput{})(req) + }) + _, err = e.QueryContract(context.Background(), fftypes.JSONAnyPtrBytes(locationBytes), method, params) + assert.Regexp(t, "FF10284", err) +} + +func TestQueryContractUnmarshalResponseError(t *testing.T) { e, cancel := newTestFabric() defer cancel() httpmock.ActivateNonDefault(e.client.GetClient()) @@ -1407,8 +1535,18 @@ func TestQueryContractOK(t *testing.T) { } locationBytes, err := json.Marshal(location) assert.NoError(t, err) + httpmock.RegisterResponder("POST", `http://localhost:12345/query`, + func(req *http.Request) (*http.Response, error) { + var body map[string]interface{} + json.NewDecoder(req.Body).Decode(&body) + assert.Equal(t, "firefly", (body["headers"].(map[string]interface{}))["channel"]) + assert.Equal(t, "simplestorage", (body["headers"].(map[string]interface{}))["chaincode"]) + assert.Equal(t, "1", body["args"].(map[string]interface{})["x"]) + assert.Equal(t, "2", body["args"].(map[string]interface{})["y"]) + return httpmock.NewStringResponder(200, "[definitely not JSON}")(req) + }) _, err = e.QueryContract(context.Background(), fftypes.JSONAnyPtrBytes(locationBytes), method, params) - assert.EqualError(t, err, "not yet supported") + assert.Regexp(t, "invalid character", err) } func TestValidateContractLocation(t *testing.T) { diff --git a/test/data/assetcreator/chaincode/smartcontract.go b/test/data/assetcreator/chaincode/smartcontract.go index 680aa58810..a00ab76feb 100644 --- a/test/data/assetcreator/chaincode/smartcontract.go +++ b/test/data/assetcreator/chaincode/smartcontract.go @@ -24,3 +24,8 @@ func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, ctx.GetStub().SetEvent("AssetCreated", assetJSON) return ctx.GetStub().PutState(name, assetJSON) } + +func (s *SmartContract) GetAsset(ctx contractapi.TransactionContextInterface, name string) (string, error) { + b, err := ctx.GetStub().GetState(name) + return string(b), err +} diff --git a/test/e2e/fabric_contract_test.go b/test/e2e/fabric_contract_test.go index 768980d24f..86c193becd 100644 --- a/test/e2e/fabric_contract_test.go +++ b/test/e2e/fabric_contract_test.go @@ -17,6 +17,7 @@ package e2e import ( + "encoding/json" "fmt" "os" "os/exec" @@ -49,6 +50,37 @@ var assetCreatedEvent = &fftypes.FFIEvent{ }, } +func assetManagerCreateAsset() *fftypes.FFIMethod { + return &fftypes.FFIMethod{ + Name: "CreateAsset", + Params: fftypes.FFIParams{ + { + Name: "name", + Schema: fftypes.JSONAnyPtr(`{"type": "string"}`), + }, + }, + Returns: fftypes.FFIParams{}, + } +} + +func assetManagerGetAsset() *fftypes.FFIMethod { + return &fftypes.FFIMethod{ + Name: "GetAsset", + Params: fftypes.FFIParams{ + { + Name: "name", + Schema: fftypes.JSONAnyPtr(`{"type": "string"}`), + }, + }, + Returns: fftypes.FFIParams{ + { + Name: "name", + Schema: fftypes.JSONAnyPtr(`{"type": "string"}`), + }, + }, + } +} + func deployChaincode(t *testing.T, stackName string) string { id, err := nanoid.Generate("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", nanoid.DefaultSize) assert.NoError(t, err) @@ -121,8 +153,25 @@ func (suite *FabricContractTestSuite) TestE2EContractEvents() { assert.Equal(suite.T(), 1, len(subs)) assert.Equal(suite.T(), sub.ProtocolID, subs[0].ProtocolID) - asset := nanoid.New() - invokeFabContract(suite.T(), suite.fabClient, "firefly", suite.chaincodeName, "org_0", "CreateAsset", []string{asset}) + assetName := nanoid.New() + // invokeFabContract(suite.T(), suite.fabClient, "firefly", suite.chaincodeName, "org_0", "CreateAsset", []string{asset}) + + location := map[string]interface{}{ + "chaincode": suite.chaincodeName, + "channel": "firefly", + } + locationBytes, _ := json.Marshal(location) + invokeContractRequest := &fftypes.ContractCallRequest{ + Location: fftypes.JSONAnyPtrBytes(locationBytes), + Method: assetManagerCreateAsset(), + Input: map[string]interface{}{ + "name": assetName, + }, + } + + res, err := InvokeContractMethod(suite.testState.t, suite.testState.client1, invokeContractRequest) + suite.T().Log(res) + assert.NoError(suite.T(), err) <-received1 <-changes1 // also expect database change events @@ -130,7 +179,20 @@ func (suite *FabricContractTestSuite) TestE2EContractEvents() { events := GetContractEvents(suite.T(), suite.testState.client1, suite.testState.startTime, sub.ID) assert.Equal(suite.T(), 1, len(events)) assert.Equal(suite.T(), "AssetCreated", events[0].Name) - assert.Equal(suite.T(), asset, events[0].Output.GetString("name")) + assert.Equal(suite.T(), assetName, events[0].Output.GetString("name")) + + queryContractRequest := &fftypes.ContractCallRequest{ + Location: fftypes.JSONAnyPtrBytes(locationBytes), + Method: assetManagerGetAsset(), + Input: map[string]interface{}{ + "name": assetName, + }, + } + + res, err = QueryContractMethod(suite.testState.t, suite.testState.client1, queryContractRequest) + suite.T().Log(res) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), assetName, res.(map[string]interface{})["name"]) DeleteContractSubscription(suite.T(), suite.testState.client1, subs[0].ID) subs = GetContractSubscriptions(suite.T(), suite.testState.client1, suite.testState.startTime) From 69306443f9f4589ed2a324c019fd27081ccda730 Mon Sep 17 00:00:00 2001 From: Nicko Guyer Date: Fri, 18 Feb 2022 12:09:30 -0500 Subject: [PATCH 2/2] Clean up E2E test Signed-off-by: Nicko Guyer --- test/e2e/fabric_contract_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/e2e/fabric_contract_test.go b/test/e2e/fabric_contract_test.go index 86c193becd..facdfc4457 100644 --- a/test/e2e/fabric_contract_test.go +++ b/test/e2e/fabric_contract_test.go @@ -154,8 +154,6 @@ func (suite *FabricContractTestSuite) TestE2EContractEvents() { assert.Equal(suite.T(), sub.ProtocolID, subs[0].ProtocolID) assetName := nanoid.New() - // invokeFabContract(suite.T(), suite.fabClient, "firefly", suite.chaincodeName, "org_0", "CreateAsset", []string{asset}) - location := map[string]interface{}{ "chaincode": suite.chaincodeName, "channel": "firefly",