Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
BEGIN;
ALTER TABLE ffi DROP COLUMN topics;
ALTER TABLE contractapis DROP COLUMN topics;
COMMIT;
4 changes: 4 additions & 0 deletions db/migrations/postgres/000118_add_definition_topics.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
BEGIN;
ALTER TABLE ffi ADD COLUMN topics VARCHAR(1024);
ALTER TABLE contractapis ADD COLUMN topics VARCHAR(1024);
COMMIT;
2 changes: 2 additions & 0 deletions db/migrations/sqlite/000118_add_definition_topics.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE ffi DROP COLUMN topics;
ALTER TABLE contractapis DROP COLUMN topics;
2 changes: 2 additions & 0 deletions db/migrations/sqlite/000118_add_definition_topics.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE ffi ADD COLUMN topics VARCHAR(1024);
ALTER TABLE contractapis ADD COLUMN topics VARCHAR(1024);
1 change: 1 addition & 0 deletions doc-site/docs/reference/types/contractapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ title: ContractAPI
| `message` | The UUID of the broadcast message that was used to publish this API to the network | [`UUID`](simpletypes.md#uuid) |
| `urls` | The URLs to use to access the API | [`ContractURLs`](#contracturls) |
| `published` | Indicates if the API is published to other members of the multiparty network | `bool` |
| `topics` | An optional list of custom topics used for ordering of the definition broadcast message, instead of the default system topic. Each topic must be a non-empty string. Only used when the definition is published to the multiparty network | `string[]` |

## FFIReference

Expand Down
1 change: 1 addition & 0 deletions doc-site/docs/reference/types/ffi.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ title: FFI
| `events` | An array of smart contract event definitions | [`FFIEvent[]`](#ffievent) |
| `errors` | An array of smart contract error definitions | [`FFIError[]`](#ffierror) |
| `published` | Indicates if the FFI is published to other members of the multiparty network | `bool` |
| `topics` | An optional list of custom topics used for ordering of the definition broadcast message, instead of the default system topic. Each topic must be a non-empty string. Only used when the definition is published to the multiparty network | `string[]` |

## FFIMethod

Expand Down
552 changes: 552 additions & 0 deletions doc-site/docs/swagger/swagger.yaml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,5 @@ require (
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace github.com/hyperledger-firefly/common => ../firefly-common
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hyperledger-firefly/common v1.6.3 h1:z9Jm6ttwy7AJvrHw0FbjtPT5wLG8n3K8Rrf3MUkifdY=
github.com/hyperledger-firefly/common v1.6.3/go.mod h1:UiHXY2QdM8UUYHDpFpOAt2hwrVL559G8wZ3b68kAEx8=
github.com/hyperledger-firefly/signer v1.2.1 h1:YmnCfiOPhrP/6WIGt5KwV3wiDEI61k7h282MpagSNnI=
github.com/hyperledger-firefly/signer v1.2.1/go.mod h1:qLBLnXZZHk83x68WLvDjx8q80+6lQzx57FPeRyI6jmo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
Expand Down
2 changes: 1 addition & 1 deletion internal/apiserver/route_post_contract_api_publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var postContractAPIPublish = &ffapi.Route{
waitConfirm := strings.EqualFold(r.QP["confirm"], "true")
r.SuccessStatus = syncRetcode(waitConfirm)
input := r.Input.(*core.DefinitionPublish)
return cr.or.DefinitionSender().PublishContractAPI(cr.ctx, cr.apiBaseURL, r.PP["apiName"], input.NetworkName, waitConfirm)
return cr.or.DefinitionSender().PublishContractAPI(cr.ctx, cr.apiBaseURL, r.PP["apiName"], input.NetworkName, waitConfirm, input.Topics)
},
},
}
22 changes: 21 additions & 1 deletion internal/apiserver/route_post_contract_api_publish_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"net/http/httptest"
"testing"

"github.com/hyperledger-firefly/common/pkg/fftypes"
"github.com/hyperledger-firefly/firefly/mocks/definitionsmocks"
"github.com/hyperledger-firefly/firefly/pkg/core"
"github.com/stretchr/testify/assert"
Expand All @@ -41,7 +42,26 @@ func TestPostContractAPIPublish(t *testing.T) {
res := httptest.NewRecorder()
api := &core.ContractAPI{}

mds.On("PublishContractAPI", mock.Anything, "http://127.0.0.1:5000/api/v1/namespaces/ns1", "banana", "banana-net", false).Return(api, nil)
mds.On("PublishContractAPI", mock.Anything, "http://127.0.0.1:5000/api/v1/namespaces/ns1", "banana", "banana-net", false, mock.Anything).Return(api, nil)
r.ServeHTTP(res, req)

assert.Equal(t, 202, res.Result().StatusCode)
}

func TestPostContractAPIPublishWithTopics(t *testing.T) {
o, r := newTestAPIServer()
o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
mds := &definitionsmocks.Sender{}
o.On("DefinitionSender").Return(mds)
input := core.DefinitionPublish{NetworkName: "banana-net", Topics: fftypes.FFStringArray{"my-topic"}}
var buf bytes.Buffer
json.NewEncoder(&buf).Encode(&input)
req := httptest.NewRequest("POST", "/api/v1/namespaces/ns1/apis/banana/publish", &buf)
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()
api := &core.ContractAPI{}

mds.On("PublishContractAPI", mock.Anything, "http://127.0.0.1:5000/api/v1/namespaces/ns1", "banana", "banana-net", false, []string{"my-topic"}).Return(api, nil)
r.ServeHTTP(res, req)

assert.Equal(t, 202, res.Result().StatusCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ var postContractInterfacePublish = &ffapi.Route{
waitConfirm := strings.EqualFold(r.QP["confirm"], "true")
r.SuccessStatus = syncRetcode(waitConfirm)
input := r.Input.(*core.DefinitionPublish)
return cr.or.DefinitionSender().PublishFFI(cr.ctx, r.PP["name"], r.PP["version"], input.NetworkName, waitConfirm)
return cr.or.DefinitionSender().PublishFFI(cr.ctx, r.PP["name"], r.PP["version"], input.NetworkName, waitConfirm, input.Topics)
},
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,26 @@ func TestPostContractInterfacePublish(t *testing.T) {
res := httptest.NewRecorder()
ffi := &fftypes.FFI{}

mds.On("PublishFFI", mock.Anything, "ffi1", "1.0", "", false).Return(ffi, nil)
mds.On("PublishFFI", mock.Anything, "ffi1", "1.0", "", false, mock.Anything).Return(ffi, nil)
r.ServeHTTP(res, req)

assert.Equal(t, 202, res.Result().StatusCode)
}

func TestPostContractInterfacePublishWithTopics(t *testing.T) {
o, r := newTestAPIServer()
o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
mds := &definitionsmocks.Sender{}
o.On("DefinitionSender").Return(mds)
input := core.DefinitionPublish{Topics: fftypes.FFStringArray{"my-topic"}}
var buf bytes.Buffer
json.NewEncoder(&buf).Encode(&input)
req := httptest.NewRequest("POST", "/api/v1/namespaces/ns1/contracts/interfaces/ffi1/1.0/publish", &buf)
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()
ffi := &fftypes.FFI{}

mds.On("PublishFFI", mock.Anything, "ffi1", "1.0", "", false, []string{"my-topic"}).Return(ffi, nil)
r.ServeHTTP(res, req)

assert.Equal(t, 202, res.Result().StatusCode)
Expand Down
2 changes: 1 addition & 1 deletion internal/apiserver/route_post_new_contract_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ var postNewContractAPI = &ffapi.Route{
api := r.Input.(*core.ContractAPI)
api.ID = nil
api.Published = strings.EqualFold(r.QP["publish"], "true")
err = cr.or.DefinitionSender().DefineContractAPI(cr.ctx, cr.apiBaseURL, api, waitConfirm)
err = cr.or.DefinitionSender().DefineContractAPI(cr.ctx, cr.apiBaseURL, api, waitConfirm, api.Topics)
return api, err
},
},
Expand Down
24 changes: 22 additions & 2 deletions internal/apiserver/route_post_new_contract_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"net/http/httptest"
"testing"

"github.com/hyperledger-firefly/common/pkg/fftypes"
"github.com/hyperledger-firefly/firefly/mocks/contractmocks"
"github.com/hyperledger-firefly/firefly/mocks/definitionsmocks"
"github.com/hyperledger-firefly/firefly/pkg/core"
Expand All @@ -42,7 +43,7 @@ func TestPostNewContractAPI(t *testing.T) {
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()

mds.On("DefineContractAPI", mock.Anything, mock.Anything, mock.AnythingOfType("*core.ContractAPI"), false).Return(nil)
mds.On("DefineContractAPI", mock.Anything, mock.Anything, mock.AnythingOfType("*core.ContractAPI"), false, mock.Anything).Return(nil)
r.ServeHTTP(res, req)

assert.Equal(t, 202, res.Result().StatusCode)
Expand All @@ -61,8 +62,27 @@ func TestPostNewContractAPISync(t *testing.T) {
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()

mds.On("DefineContractAPI", mock.Anything, mock.Anything, mock.AnythingOfType("*core.ContractAPI"), true).Return(nil)
mds.On("DefineContractAPI", mock.Anything, mock.Anything, mock.AnythingOfType("*core.ContractAPI"), true, mock.Anything).Return(nil)
r.ServeHTTP(res, req)

assert.Equal(t, 200, res.Result().StatusCode)
}

func TestPostNewContractAPIWithTopics(t *testing.T) {
o, r := newTestAPIServer()
o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
mds := &definitionsmocks.Sender{}
o.On("Contracts").Return(&contractmocks.Manager{})
o.On("DefinitionSender").Return(mds)
input := core.ContractAPI{Topics: fftypes.FFStringArray{"my-topic"}}
var buf bytes.Buffer
json.NewEncoder(&buf).Encode(&input)
req := httptest.NewRequest("POST", "/api/v1/namespaces/ns1/apis", &buf)
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()

mds.On("DefineContractAPI", mock.Anything, mock.Anything, mock.AnythingOfType("*core.ContractAPI"), false, []string{"my-topic"}).Return(nil)
r.ServeHTTP(res, req)

assert.Equal(t, 202, res.Result().StatusCode)
}
2 changes: 1 addition & 1 deletion internal/apiserver/route_post_new_contract_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var postNewContractInterface = &ffapi.Route{
r.SuccessStatus = syncRetcode(waitConfirm)
ffi := r.Input.(*fftypes.FFI)
ffi.Published = strings.EqualFold(r.QP["publish"], "true")
err = cr.or.DefinitionSender().DefineFFI(cr.ctx, ffi, waitConfirm)
err = cr.or.DefinitionSender().DefineFFI(cr.ctx, ffi, waitConfirm, ffi.Topics)
return ffi, err
},
},
Expand Down
24 changes: 22 additions & 2 deletions internal/apiserver/route_post_new_contract_interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"net/http/httptest"
"testing"

"github.com/hyperledger-firefly/common/pkg/fftypes"
"github.com/hyperledger-firefly/firefly/mocks/contractmocks"
"github.com/hyperledger-firefly/firefly/mocks/definitionsmocks"
"github.com/hyperledger-firefly/firefly/pkg/core"
Expand All @@ -42,7 +43,7 @@ func TestPostNewContractInterface(t *testing.T) {
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()

mds.On("DefineFFI", mock.Anything, mock.AnythingOfType("*fftypes.FFI"), false).Return(nil)
mds.On("DefineFFI", mock.Anything, mock.AnythingOfType("*fftypes.FFI"), false, mock.Anything).Return(nil)
r.ServeHTTP(res, req)

assert.Equal(t, 202, res.Result().StatusCode)
Expand All @@ -61,8 +62,27 @@ func TestPostNewContractInterfaceSync(t *testing.T) {
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()

mds.On("DefineFFI", mock.Anything, mock.AnythingOfType("*fftypes.FFI"), true).Return(nil)
mds.On("DefineFFI", mock.Anything, mock.AnythingOfType("*fftypes.FFI"), true, mock.Anything).Return(nil)
r.ServeHTTP(res, req)

assert.Equal(t, 200, res.Result().StatusCode)
}

func TestPostNewContractInterfaceWithTopics(t *testing.T) {
o, r := newTestAPIServer()
o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
mds := &definitionsmocks.Sender{}
o.On("Contracts").Return(&contractmocks.Manager{})
o.On("DefinitionSender").Return(mds)
input := fftypes.FFI{Topics: fftypes.FFStringArray{"my-topic"}}
var buf bytes.Buffer
json.NewEncoder(&buf).Encode(&input)
req := httptest.NewRequest("POST", "/api/v1/namespaces/ns1/contracts/interfaces", &buf)
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()

mds.On("DefineFFI", mock.Anything, mock.AnythingOfType("*fftypes.FFI"), false, []string{"my-topic"}).Return(nil)
r.ServeHTTP(res, req)

assert.Equal(t, 202, res.Result().StatusCode)
}
2 changes: 1 addition & 1 deletion internal/apiserver/route_put_contract_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var putContractAPI = &ffapi.Route{
api := r.Input.(*core.ContractAPI)
api.ID, err = fftypes.ParseUUID(cr.ctx, r.PP["id"])
if err == nil {
err = cr.or.DefinitionSender().DefineContractAPI(cr.ctx, cr.apiBaseURL, api, waitConfirm)
err = cr.or.DefinitionSender().DefineContractAPI(cr.ctx, cr.apiBaseURL, api, waitConfirm, api.Topics)
}
return api, err
},
Expand Down
24 changes: 22 additions & 2 deletions internal/apiserver/route_put_contract_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"net/http/httptest"
"testing"

"github.com/hyperledger-firefly/common/pkg/fftypes"
"github.com/hyperledger-firefly/firefly/mocks/contractmocks"
"github.com/hyperledger-firefly/firefly/mocks/definitionsmocks"
"github.com/hyperledger-firefly/firefly/pkg/core"
Expand All @@ -42,7 +43,7 @@ func TestPutContractAPI(t *testing.T) {
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()

mds.On("DefineContractAPI", mock.Anything, mock.Anything, mock.AnythingOfType("*core.ContractAPI"), false).Return(nil)
mds.On("DefineContractAPI", mock.Anything, mock.Anything, mock.AnythingOfType("*core.ContractAPI"), false, mock.Anything).Return(nil)
r.ServeHTTP(res, req)

assert.Equal(t, 202, res.Result().StatusCode)
Expand All @@ -61,8 +62,27 @@ func TestPutContractAPISync(t *testing.T) {
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()

mds.On("DefineContractAPI", mock.Anything, mock.Anything, mock.AnythingOfType("*core.ContractAPI"), true).Return(nil)
mds.On("DefineContractAPI", mock.Anything, mock.Anything, mock.AnythingOfType("*core.ContractAPI"), true, mock.Anything).Return(nil)
r.ServeHTTP(res, req)

assert.Equal(t, 200, res.Result().StatusCode)
}

func TestPutContractAPIWithTopics(t *testing.T) {
o, r := newTestAPIServer()
o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
mds := &definitionsmocks.Sender{}
o.On("DefinitionSender").Return(mds)
o.On("Contracts").Return(&contractmocks.Manager{})
input := core.ContractAPI{Topics: fftypes.FFStringArray{"my-topic"}}
var buf bytes.Buffer
json.NewEncoder(&buf).Encode(&input)
req := httptest.NewRequest("PUT", "/api/v1/namespaces/ns1/apis/99EEE458-037C-4C78-B66B-31E52F93D2E9", &buf)
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := httptest.NewRecorder()

mds.On("DefineContractAPI", mock.Anything, mock.Anything, mock.AnythingOfType("*core.ContractAPI"), false, []string{"my-topic"}).Return(nil)
r.ServeHTTP(res, req)

assert.Equal(t, 202, res.Result().StatusCode)
}
1 change: 1 addition & 0 deletions internal/coremsgs/en_error_messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,4 +323,5 @@ var (
MsgNodeMissingProfile = ffe("FF10482", "Node provided for check does not have a profile", 500)
MsgInvalidCardanoAddress = ffe("FF10483", "Supplied cardano address is invalid", 400)
MsgCardanoconnectRESTErr = ffe("FF10484", "Error from cardano connector: %s")
MsgEmptyCustomTopic = ffe("FF10485", "Custom topic at index %d is empty. Each custom topic for the definition broadcast message must be a non-empty string", 400)
)
3 changes: 3 additions & 0 deletions internal/coremsgs/en_struct_descriptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ var (
ContractAPIMessage = ffm("ContractAPI.message", "The UUID of the broadcast message that was used to publish this API to the network")
ContractAPIURLs = ffm("ContractAPI.urls", "The URLs to use to access the API")
ContractAPIPublished = ffm("ContractAPI.published", "Indicates if the API is published to other members of the multiparty network")
ContractAPITopics = ffm("ContractAPI.topics", "An optional list of custom topics used for ordering of the definition broadcast message, instead of the default system topic. Each topic must be a non-empty string. Only used when the definition is published to the multiparty network")

// ContractURLs field descriptions
ContractURLsAPI = ffm("ContractURLs.api", "The URL to use to invoke the API")
Expand All @@ -255,6 +256,7 @@ var (
FFIEvents = ffm("FFI.events", "An array of smart contract event definitions")
FFIErrors = ffm("FFI.errors", "An array of smart contract error definitions")
FFIPublished = ffm("FFI.published", "Indicates if the FFI is published to other members of the multiparty network")
FFITopics = ffm("FFI.topics", "An optional list of custom topics used for ordering of the definition broadcast message, instead of the default system topic. Each topic must be a non-empty string. Only used when the definition is published to the multiparty network")

// FFIMethod field descriptions
FFIMethodID = ffm("FFIMethod.id", "The UUID of the FFI method definition")
Expand Down Expand Up @@ -739,4 +741,5 @@ var (

// DefinitionPublish field descriptions
DefinitionPublishNetworkName = ffm("DefinitionPublish.networkName", "An optional name to be used for publishing this definition to the multiparty network, which may differ from the local name")
DefinitionPublishTopics = ffm("DefinitionPublish.topics", "An optional list of custom topics to use for ordering of the definition broadcast message, instead of the default system topic. Each topic must be a non-empty string. Only used when the definition is published to the multiparty network")
)
4 changes: 4 additions & 0 deletions internal/database/sqlcommon/contractapis_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ var (
"namespace",
"message_id",
"published",
"topics",
}
contractAPIsFilterFieldMap = map[string]string{
"interface": "interface_id",
Expand Down Expand Up @@ -68,6 +69,7 @@ func (s *SQLCommon) attemptContractAPIUpdate(ctx context.Context, tx *dbsql.TXWr
Set("network_name", networkName).
Set("message_id", api.Message).
Set("published", api.Published).
Set("topics", api.Topics).
Where(sq.Eq{"id": api.ID}),
func() {
s.callbacks.UUIDCollectionNSEvent(database.CollectionContractAPIs, core.ChangeEventTypeUpdated, api.Namespace, api.ID)
Expand All @@ -93,6 +95,7 @@ func (s *SQLCommon) setContractAPIInsertValues(query sq.InsertBuilder, api *core
api.Namespace,
api.Message,
api.Published,
api.Topics,
)
}

Expand Down Expand Up @@ -202,6 +205,7 @@ func (s *SQLCommon) contractAPIResult(ctx context.Context, row *sql.Rows) (*core
&api.Namespace,
&api.Message,
&api.Published,
&api.Topics,
)
if networkName != nil {
api.NetworkName = *networkName
Expand Down
Loading