diff --git a/db/migrations/postgres/000112_add_ffi_networkname.down.sql b/db/migrations/postgres/000112_add_ffi_networkname.down.sql new file mode 100644 index 000000000..1f4f4248b --- /dev/null +++ b/db/migrations/postgres/000112_add_ffi_networkname.down.sql @@ -0,0 +1,5 @@ +BEGIN; +DROP INDEX ffi_networkname; +ALTER TABLE ffi DROP COLUMN published; +ALTER TABLE ffi DROP COLUMN network_name; +COMMIT; diff --git a/db/migrations/postgres/000112_add_ffi_networkname.up.sql b/db/migrations/postgres/000112_add_ffi_networkname.up.sql new file mode 100644 index 000000000..e4136a095 --- /dev/null +++ b/db/migrations/postgres/000112_add_ffi_networkname.up.sql @@ -0,0 +1,7 @@ +BEGIN; +ALTER TABLE ffi ADD COLUMN published BOOLEAN DEFAULT false; +UPDATE ffi SET published = true WHERE message_id IS NOT NULL; +ALTER TABLE ffi ADD COLUMN network_name VARCHAR(64); +UPDATE ffi SET network_name = name WHERE message_id IS NOT NULL; +CREATE UNIQUE INDEX ffi_networkname ON ffi(namespace,network_name,version); +COMMIT; diff --git a/db/migrations/sqlite/000112_add_ffi_networkname.down.sql b/db/migrations/sqlite/000112_add_ffi_networkname.down.sql new file mode 100644 index 000000000..c3e86401e --- /dev/null +++ b/db/migrations/sqlite/000112_add_ffi_networkname.down.sql @@ -0,0 +1,3 @@ +DROP INDEX ffi_networkname; +ALTER TABLE ffi DROP COLUMN published; +ALTER TABLE ffi DROP COLUMN network_name; diff --git a/db/migrations/sqlite/000112_add_ffi_networkname.up.sql b/db/migrations/sqlite/000112_add_ffi_networkname.up.sql new file mode 100644 index 000000000..292ab579d --- /dev/null +++ b/db/migrations/sqlite/000112_add_ffi_networkname.up.sql @@ -0,0 +1,5 @@ +ALTER TABLE ffi ADD COLUMN published BOOLEAN DEFAULT false; +UPDATE ffi SET published = true WHERE message_id IS NOT NULL; +ALTER TABLE ffi ADD COLUMN network_name VARCHAR(64); +UPDATE ffi SET network_name = name WHERE message_id IS NOT NULL; +CREATE UNIQUE INDEX ffi_networkname ON ffi(namespace,network_name,version); diff --git a/docs/reference/types/ffi.md b/docs/reference/types/ffi.md index 8358acc01..01159395c 100644 --- a/docs/reference/types/ffi.md +++ b/docs/reference/types/ffi.md @@ -122,13 +122,13 @@ nav_order: 9 | `message` | The UUID of the broadcast message that was used to publish this FFI to the network | [`UUID`](simpletypes#uuid) | | `namespace` | The namespace of the FFI | `string` | | `name` | The name of the FFI - usually matching the smart contract name | `string` | -| `networkName` | The shared interface name within the multiparty network | `string` | +| `networkName` | The published name of the FFI within the multiparty network | `string` | | `description` | A description of the smart contract this FFI represents | `string` | | `version` | A version for the FFI - use of semantic versioning such as 'v1.0.1' is encouraged | `string` | | `methods` | An array of smart contract method definitions | [`FFIMethod[]`](#ffimethod) | | `events` | An array of smart contract event definitions | [`FFIEvent[]`](#ffievent) | | `errors` | An array of smart contract error definitions | [`FFIError[]`](#ffierror) | -| `published` | True if the interface has been published to a multiparty network | `bool` | +| `published` | Indicates if the FFI is published to other members of the multiparty network | `bool` | ## FFIMethod diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 47707af57..62c7de78e 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -596,11 +596,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning @@ -2424,6 +2425,16 @@ paths: name: name schema: type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: networkname + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: published + schema: + type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query name: version @@ -2686,12 +2697,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty + description: The published name of the FFI within the multiparty network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning @@ -2714,6 +2725,12 @@ paths: schema: example: "true" type: string + - description: When true the definition will be published to all other members + of the multiparty network + in: query + name: publish + schema: + type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) in: header @@ -2863,7 +2880,8 @@ paths: name type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string version: description: A version for the FFI - use of semantic versioning @@ -3084,11 +3102,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning @@ -3101,6 +3120,32 @@ paths: tags: - Default Namespace /contracts/interfaces/{interfaceId}: + delete: + description: Delete a contract interface + operationId: deleteContractInterface + parameters: + - description: The ID of the contract interface + in: path + name: interfaceId + required: true + schema: + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + responses: + "204": + content: + application/json: {} + description: Success + default: + description: "" + tags: + - Default Namespace get: description: Gets a contract interface by its ID operationId: getContractInterface @@ -3339,11 +3384,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning @@ -3600,11 +3646,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning @@ -3616,13 +3663,29 @@ paths: description: "" tags: - Default Namespace - /contracts/interfaces/generate: + /contracts/interfaces/{name}/{version}/publish: post: - description: A convenience method to convert a blockchain specific smart contract - format into a FireFly Interface format. The specific blockchain plugin in - use must support this functionality. - operationId: postGenerateContractInterface + description: Publish a contract interface to all other members of the multiparty + network + operationId: postContractInterfacePublish parameters: + - description: The name of the contract interface + in: path + name: name + required: true + schema: + type: string + - description: The version of the contract interface + in: path + name: version + required: true + schema: + type: string + - description: When true the HTTP request blocks until the message is confirmed + in: query + name: confirm + schema: + type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) in: header @@ -3635,23 +3698,9 @@ paths: application/json: schema: properties: - description: - description: The description of the FFI to be generated. Defaults - to the description extracted by the blockchain specific converter - utility - type: string - input: - description: A blockchain connector specific payload. For example - in Ethereum this is a JSON structure containing an 'abi' array, - and optionally a 'devdocs' array. - name: - description: The name of the FFI to generate - type: string - namespace: - description: The namespace into which the FFI will be generated - type: string - version: - description: The version of the FFI to generate + networkName: + description: An optional name to be used for publishing this definition + to the multiparty network, which may differ from the local name type: string type: object responses: @@ -3868,11 +3917,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning @@ -3880,456 +3930,229 @@ paths: type: string type: object description: Success - default: - description: "" - tags: - - Default Namespace - /contracts/invoke: - post: - description: Invokes a method on a smart contract. Performs a blockchain transaction. - operationId: postContractInvoke - parameters: - - description: When true the HTTP request blocks until the message is confirmed - in: query - name: confirm - schema: - example: "true" - type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - requestBody: - content: - application/json: - schema: - properties: - errors: - description: An in-line FFI errors definition for the method to - invoke. Alternative to specifying FFI - items: - description: An in-line FFI errors definition for the method to - invoke. Alternative to specifying FFI - properties: - description: - description: A description of the smart contract error - type: string - name: - description: The name of the error - type: string - params: - description: An array of error parameter/argument definitions - items: + "202": + content: + application/json: + schema: + properties: + description: + description: A description of the smart contract this FFI represents + type: string + errors: + description: An array of smart contract error definitions + items: + description: An array of smart contract error definitions + properties: + description: + description: A description of the smart contract error + type: string + id: + description: The UUID of the FFI error definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this error is part of + format: uuid + type: string + name: + description: The name of the error + type: string + namespace: + description: The namespace of the FFI + type: string + params: description: An array of error parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to - the order in the blockchain smart contract - type: string - schema: - description: FireFly uses an extended subset of JSON - Schema to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail - type: object - type: array - type: object - type: array - idempotencyKey: - description: An optional identifier to allow idempotent submission - of requests. Stored on the transaction uniquely within a namespace - type: string - input: - additionalProperties: - description: A map of named inputs. The name and type of each - input must be compatible with the FFI description of the method, - so that FireFly knows how to serialize it to the blockchain - via the connector - description: A map of named inputs. The name and type of each input - must be compatible with the FFI description of the method, so - that FireFly knows how to serialize it to the blockchain via the - connector - type: object - interface: - description: The UUID of a method within a pre-configured FireFly - interface (FFI) definition for a smart contract. Required if the - 'method' is omitted. Also see Contract APIs as a way to configure - a dedicated API for your FFI, including all methods and an OpenAPI/Swagger - interface - format: uuid - type: string - key: - description: The blockchain signing key that will sign the invocation. - Defaults to the first signing key of the organization that operates - the node - type: string - location: - description: A blockchain specific contract identifier. For example - an Ethereum contract address, or a Fabric chaincode name and channel - message: - description: You can specify a message to correlate with the invocation, - which can be of type broadcast or private. Your specified method - must support on-chain/off-chain correlation by taking a data input - on the call - properties: - data: - description: For input allows you to specify data in-line in - the message, that will be turned into data attachments. For - output when fetchdata is used on API calls, includes the in-line - data payloads of all data attachments - items: - description: For input allows you to specify data in-line - in the message, that will be turned into data attachments. - For output when fetchdata is used on API calls, includes - the in-line data payloads of all data attachments - properties: - datatype: - description: The optional datatype to use for validation - of the in-line data + items: + description: An array of error parameter/argument definitions properties: name: - description: The name of the datatype - type: string - version: - description: The version of the datatype. Semantic - versioning is encouraged, such as v1.0.1 - type: string - type: object - id: - description: The UUID of the referenced data resource - format: uuid - type: string - validator: - description: The data validator type to use for in-line - data - type: string - value: - description: The in-line value for the data. Can be any - JSON type - object, array, string, number or boolean - type: object - type: array - group: - description: Allows you to specify details of the private group - of recipients in-line in the message. Alternative to using - the header.group to specify the hash of a group that has been - previously resolved - properties: - members: - description: An array of members of the group. If no identities - local to the sending node are included, then the organization - owner of the local node is added automatically - items: - description: An array of members of the group. If no identities - local to the sending node are included, then the organization - owner of the local node is added automatically - properties: - identity: - description: The DID of the group member. On input - can be a UUID or org name, and will be resolved - to a DID - type: string - node: - description: The UUID of the node that will receive - a copy of the off-chain message for the identity. - The first applicable node for the identity will - be picked automatically on input if not specified + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail type: object type: array - name: - description: Optional name for the group. Allows you to - have multiple separate groups with the same list of participants + pathname: + description: The unique name allocated to this error within + the FFI for use on URL paths + type: string + signature: + description: The stringified signature of the error, as + computed by the blockchain plugin type: string type: object - header: - description: The message header contains all fields that are - used to build the message hash + type: array + events: + description: An array of smart contract event definitions + items: + description: An array of smart contract event definitions properties: - author: - description: The DID of identity of the submitter + description: + description: A description of the smart contract event type: string - cid: - description: The correlation ID of the message. Set this - when a message is a response to another message + details: + additionalProperties: + description: Additional blockchain specific fields about + this event from the original smart contract. Used by + the blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about + this event from the original smart contract. Used by the + blockchain plugin and for documentation generation. + type: object + id: + description: The UUID of the FFI event definition format: uuid type: string - group: - description: Private messages only - the identifier hash - of the privacy group. Derived from the name and member - list of the group - format: byte + interface: + description: The UUID of the FFI smart contract definition + that this event is part of + format: uuid type: string - key: - description: The on-chain signing key used to sign the transaction + name: + description: The name of the event type: string - tag: - description: The message tag indicates the purpose of the - message to the applications that process it + namespace: + description: The namespace of the FFI type: string - topics: - description: A message topic associates this message with - an ordered stream of data. A custom topic should be assigned - - using the default topic is discouraged + params: + description: An array of event parameter/argument definitions items: - description: A message topic associates this message with - an ordered stream of data. A custom topic should be - assigned - using the default topic is discouraged - type: string + description: An array of event parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object type: array - txtype: - description: The type of transaction used to order/deliver - this message - enum: - - none - - unpinned - - batch_pin - - network_action - - token_pool - - token_transfer - - contract_deploy - - contract_invoke - - contract_invoke_pin - - token_approval - - data_publish + pathname: + description: The unique name allocated to this event within + the FFI for use on URL paths. Supports contracts that + have multiple event overrides with the same name type: string - type: - description: The type of the message - enum: - - definition - - broadcast - - private - - groupinit - - transfer_broadcast - - transfer_private - - approval_broadcast - - approval_private + signature: + description: The stringified signature of the event, as + computed by the blockchain plugin type: string type: object - idempotencyKey: - description: An optional unique identifier for a message. Cannot - be duplicated within a namespace, thus allowing idempotent - submission of messages to the API. Local only - not transferred - when the message is sent to other members of the network - type: string - type: object - method: - description: An in-line FFI method definition for the method to - invoke. Required when FFI is not specified - properties: - description: - description: A description of the smart contract method - type: string - details: - additionalProperties: - description: Additional blockchain specific fields about this - method from the original smart contract. Used by the blockchain - plugin and for documentation generation. - description: Additional blockchain specific fields about this - method from the original smart contract. Used by the blockchain - plugin and for documentation generation. - type: object - name: - description: The name of the method - type: string - params: - description: An array of method parameter/argument definitions - items: - description: An array of method parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to the - order in the blockchain smart contract - type: string - schema: - description: FireFly uses an extended subset of JSON Schema - to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail - type: object - type: array - returns: - description: An array of method return definitions - items: - description: An array of method return definitions - properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to the - order in the blockchain smart contract - type: string - schema: - description: FireFly uses an extended subset of JSON Schema - to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail - type: object - type: array - type: object - methodPath: - description: The pathname of the method on the specified FFI - type: string - options: - additionalProperties: - description: A map of named inputs that will be passed through - to the blockchain connector - description: A map of named inputs that will be passed through to - the blockchain connector - type: object - type: object - responses: - "200": - content: - application/json: - schema: - properties: - created: - description: The time the operation was created - format: date-time - type: string - error: - description: Any error reported back from the plugin for this - operation - type: string + type: array id: - description: The UUID of the operation + description: The UUID of the FireFly interface (FFI) smart contract + definition format: uuid type: string - input: - additionalProperties: - description: The input to this operation - description: The input to this operation - type: object - namespace: - description: The namespace of the operation + message: + description: The UUID of the broadcast message that was used to + publish this FFI to the network + format: uuid type: string - output: - additionalProperties: - description: Any output reported back from the plugin for this - operation - description: Any output reported back from the plugin for this - operation - type: object - plugin: - description: The plugin responsible for performing the operation - type: string - retry: - description: If this operation was initiated as a retry to a previous - operation, this field points to the UUID of the operation being - retried - format: uuid - type: string - status: - description: The current status of the operation - type: string - tx: - description: The UUID of the FireFly transaction the operation - is part of - format: uuid - type: string - type: - description: The type of the operation - enum: - - blockchain_pin_batch - - blockchain_network_action - - blockchain_deploy - - blockchain_invoke - - sharedstorage_upload_batch - - sharedstorage_upload_blob - - sharedstorage_upload_value - - sharedstorage_download_batch - - sharedstorage_download_blob - - dataexchange_send_batch - - dataexchange_send_blob - - token_create_pool - - token_activate_pool - - token_transfer - - token_approval - type: string - updated: - description: The last update time of the operation - format: date-time - type: string - type: object - description: Success - "202": - content: - application/json: - schema: - properties: - created: - description: The time the operation was created - format: date-time - type: string - error: - description: Any error reported back from the plugin for this - operation - type: string - id: - description: The UUID of the operation - format: uuid + methods: + description: An array of smart contract method definitions + items: + description: An array of smart contract method definitions + properties: + description: + description: A description of the smart contract method + type: string + details: + additionalProperties: + description: Additional blockchain specific fields about + this method from the original smart contract. Used by + the blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about + this method from the original smart contract. Used by + the blockchain plugin and for documentation generation. + type: object + id: + description: The UUID of the FFI method definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this method is part of + format: uuid + type: string + name: + description: The name of the method + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of method parameter/argument definitions + items: + description: An array of method parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + pathname: + description: The unique name allocated to this method within + the FFI for use on URL paths. Supports contracts that + have multiple method overrides with the same name + type: string + returns: + description: An array of method return definitions + items: + description: An array of method return definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + type: object + type: array + name: + description: The name of the FFI - usually matching the smart + contract name type: string - input: - additionalProperties: - description: The input to this operation - description: The input to this operation - type: object namespace: - description: The namespace of the operation - type: string - output: - additionalProperties: - description: Any output reported back from the plugin for this - operation - description: Any output reported back from the plugin for this - operation - type: object - plugin: - description: The plugin responsible for performing the operation - type: string - retry: - description: If this operation was initiated as a retry to a previous - operation, this field points to the UUID of the operation being - retried - format: uuid - type: string - status: - description: The current status of the operation - type: string - tx: - description: The UUID of the FireFly transaction the operation - is part of - format: uuid + description: The namespace of the FFI type: string - type: - description: The type of the operation - enum: - - blockchain_pin_batch - - blockchain_network_action - - blockchain_deploy - - blockchain_invoke - - sharedstorage_upload_batch - - sharedstorage_upload_blob - - sharedstorage_upload_value - - sharedstorage_download_batch - - sharedstorage_download_blob - - dataexchange_send_batch - - dataexchange_send_blob - - token_create_pool - - token_activate_pool - - token_transfer - - token_approval + networkName: + description: The published name of the FFI within the multiparty + network type: string - updated: - description: The last update time of the operation - format: date-time + published: + description: Indicates if the FFI is published to other members + of the multiparty network + type: boolean + version: + description: A version for the FFI - use of semantic versioning + such as 'v1.0.1' is encouraged type: string type: object description: Success @@ -4337,10 +4160,12 @@ paths: description: "" tags: - Default Namespace - /contracts/listeners: - get: - description: Gets a list of contract listeners - operationId: getContractListeners + /contracts/interfaces/generate: + post: + description: A convenience method to convert a blockchain specific smart contract + format into a FireFly Interface format. The specific blockchain plugin in + use must support this functionality. + operationId: postGenerateContractInterface parameters: - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) @@ -4349,109 +4174,94 @@ paths: schema: default: 2m0s type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: backendid - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: created - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: id - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: interface - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: location - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: name - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: signature - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: state - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: topic - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: updated - schema: - type: string - - description: Sort field. For multi-field sort use comma separated values (or - multiple query values) with '-' prefix for descending - in: query - name: sort - schema: - type: string - - description: Ascending sort order (overrides all fields in a multi-field sort) - in: query - name: ascending - schema: - type: string - - description: Descending sort order (overrides all fields in a multi-field - sort) - in: query - name: descending - schema: - type: string - - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk - operations' - in: query - name: skip - schema: - type: string - - description: 'The maximum number of records to return (max: 1,000)' - in: query - name: limit - schema: - example: "25" - type: string - - description: Return a total count as well as items (adds extra database processing) - in: query - name: count - schema: - type: string + requestBody: + content: + application/json: + schema: + properties: + description: + description: The description of the FFI to be generated. Defaults + to the description extracted by the blockchain specific converter + utility + type: string + input: + description: A blockchain connector specific payload. For example + in Ethereum this is a JSON structure containing an 'abi' array, + and optionally a 'devdocs' array. + name: + description: The name of the FFI to generate + type: string + namespace: + description: The namespace into which the FFI will be generated + type: string + version: + description: The version of the FFI to generate + type: string + type: object responses: "200": content: application/json: schema: - items: - properties: - backendId: - description: An ID assigned by the blockchain connector to this - listener - type: string - created: - description: The creation time of the listener - format: date-time - type: string - event: - description: The definition of the event, either provided in-line - when creating the listener, or extracted from the referenced - FFI + properties: + description: + description: A description of the smart contract this FFI represents + type: string + errors: + description: An array of smart contract error definitions + items: + description: An array of smart contract error definitions + properties: + description: + description: A description of the smart contract error + type: string + id: + description: The UUID of the FFI error definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this error is part of + format: uuid + type: string + name: + description: The name of the error + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of error parameter/argument definitions + items: + description: An array of error parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + pathname: + description: The unique name allocated to this error within + the FFI for use on URL paths + type: string + signature: + description: The stringified signature of the error, as + computed by the blockchain plugin + type: string + type: object + type: array + events: + description: An array of smart contract event definitions + items: + description: An array of smart contract event definitions properties: description: description: A description of the smart contract event @@ -4465,9 +4275,21 @@ paths: this event from the original smart contract. Used by the blockchain plugin and for documentation generation. type: object + id: + description: The UUID of the FFI event definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this event is part of + format: uuid + type: string name: description: The name of the event type: string + namespace: + description: The namespace of the FFI + type: string params: description: An array of event parameter/argument definitions items: @@ -4486,70 +4308,138 @@ paths: ABI. See the documentation for more detail type: object type: array + pathname: + description: The unique name allocated to this event within + the FFI for use on URL paths. Supports contracts that + have multiple event overrides with the same name + type: string + signature: + description: The stringified signature of the event, as + computed by the blockchain plugin + type: string type: object - id: - description: The UUID of the smart contract listener - format: uuid - type: string - interface: - description: A reference to an existing FFI, containing pre-registered - type information for the event + type: array + id: + description: The UUID of the FireFly interface (FFI) smart contract + definition + format: uuid + type: string + message: + description: The UUID of the broadcast message that was used to + publish this FFI to the network + format: uuid + type: string + methods: + description: An array of smart contract method definitions + items: + description: An array of smart contract method definitions properties: + description: + description: A description of the smart contract method + type: string + details: + additionalProperties: + description: Additional blockchain specific fields about + this method from the original smart contract. Used by + the blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about + this method from the original smart contract. Used by + the blockchain plugin and for documentation generation. + type: object id: - description: The UUID of the FireFly interface + description: The UUID of the FFI method definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this method is part of format: uuid type: string name: - description: The name of the FireFly interface + description: The name of the method type: string - version: - description: The version of the FireFly interface + namespace: + description: The namespace of the FFI type: string - type: object - location: - description: A blockchain specific contract identifier. For - example an Ethereum contract address, or a Fabric chaincode - name and channel - name: - description: A descriptive name for the listener - type: string - namespace: - description: The namespace of the listener, which defines the - namespace of all blockchain events detected by this listener - type: string - options: - description: Options that control how the listener subscribes - to events from the underlying blockchain - properties: - firstEvent: - description: A blockchain specific string, such as a block - number, to start listening from. The special strings 'oldest' - and 'newest' are supported by all blockchain connectors. - Default is 'newest' + params: + description: An array of method parameter/argument definitions + items: + description: An array of method parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + pathname: + description: The unique name allocated to this method within + the FFI for use on URL paths. Supports contracts that + have multiple method overrides with the same name type: string - type: object - signature: - description: The stringified signature of the event, as computed - by the blockchain plugin - type: string - topic: - description: A topic to set on the FireFly event that is emitted - each time a blockchain event is detected from the blockchain. - Setting this topic on a number of listeners allows applications - to easily subscribe to all events they need - type: string - type: object - type: array - description: Success + returns: + description: An array of method return definitions + items: + description: An array of method return definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + type: object + type: array + name: + description: The name of the FFI - usually matching the smart + contract name + type: string + namespace: + description: The namespace of the FFI + type: string + networkName: + description: The published name of the FFI within the multiparty + network + type: string + published: + description: Indicates if the FFI is published to other members + of the multiparty network + type: boolean + version: + description: A version for the FFI - use of semantic versioning + such as 'v1.0.1' is encouraged + type: string + type: object + description: Success default: description: "" tags: - Default Namespace + /contracts/invoke: post: - description: Creates a new blockchain listener for events emitted by custom - smart contracts - operationId: postNewContractListener + description: Invokes a method on a smart contract. Performs a blockchain transaction. + operationId: postContractInvoke parameters: + - description: When true the HTTP request blocks until the message is confirmed + in: query + name: confirm + schema: + example: "true" + type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) in: header @@ -4562,393 +4452,23 @@ paths: application/json: schema: properties: - event: - description: The definition of the event, either provided in-line - when creating the listener, or extracted from the referenced FFI - properties: - description: - description: A description of the smart contract event - type: string - details: - additionalProperties: - description: Additional blockchain specific fields about this - event from the original smart contract. Used by the blockchain - plugin and for documentation generation. - description: Additional blockchain specific fields about this - event from the original smart contract. Used by the blockchain - plugin and for documentation generation. - type: object - name: - description: The name of the event - type: string - params: - description: An array of event parameter/argument definitions - items: - description: An array of event parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to the - order in the blockchain smart contract - type: string - schema: - description: FireFly uses an extended subset of JSON Schema - to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail - type: object - type: array - type: object - eventPath: - description: When creating a listener from an existing FFI, this - is the pathname of the event on that FFI to be detected by this - listener - type: string - interface: - description: A reference to an existing FFI, containing pre-registered - type information for the event - properties: - id: - description: The UUID of the FireFly interface - format: uuid - type: string - name: - description: The name of the FireFly interface - type: string - version: - description: The version of the FireFly interface - type: string - type: object - location: - description: A blockchain specific contract identifier. For example - an Ethereum contract address, or a Fabric chaincode name and channel - name: - description: A descriptive name for the listener - type: string - options: - description: Options that control how the listener subscribes to - events from the underlying blockchain - properties: - firstEvent: - description: A blockchain specific string, such as a block number, - to start listening from. The special strings 'oldest' and - 'newest' are supported by all blockchain connectors. Default - is 'newest' - type: string - type: object - topic: - description: A topic to set on the FireFly event that is emitted - each time a blockchain event is detected from the blockchain. - Setting this topic on a number of listeners allows applications - to easily subscribe to all events they need - type: string - type: object - responses: - "200": - content: - application/json: - schema: - properties: - backendId: - description: An ID assigned by the blockchain connector to this - listener - type: string - created: - description: The creation time of the listener - format: date-time - type: string - event: - description: The definition of the event, either provided in-line - when creating the listener, or extracted from the referenced - FFI + errors: + description: An in-line FFI errors definition for the method to + invoke. Alternative to specifying FFI + items: + description: An in-line FFI errors definition for the method to + invoke. Alternative to specifying FFI properties: description: - description: A description of the smart contract event + description: A description of the smart contract error type: string - details: - additionalProperties: - description: Additional blockchain specific fields about - this event from the original smart contract. Used by the - blockchain plugin and for documentation generation. - description: Additional blockchain specific fields about this - event from the original smart contract. Used by the blockchain - plugin and for documentation generation. - type: object name: - description: The name of the event + description: The name of the error type: string params: - description: An array of event parameter/argument definitions + description: An array of error parameter/argument definitions items: - description: An array of event parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to - the order in the blockchain smart contract - type: string - schema: - description: FireFly uses an extended subset of JSON - Schema to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail - type: object - type: array - type: object - id: - description: The UUID of the smart contract listener - format: uuid - type: string - interface: - description: A reference to an existing FFI, containing pre-registered - type information for the event - properties: - id: - description: The UUID of the FireFly interface - format: uuid - type: string - name: - description: The name of the FireFly interface - type: string - version: - description: The version of the FireFly interface - type: string - type: object - location: - description: A blockchain specific contract identifier. For example - an Ethereum contract address, or a Fabric chaincode name and - channel - name: - description: A descriptive name for the listener - type: string - namespace: - description: The namespace of the listener, which defines the - namespace of all blockchain events detected by this listener - type: string - options: - description: Options that control how the listener subscribes - to events from the underlying blockchain - properties: - firstEvent: - description: A blockchain specific string, such as a block - number, to start listening from. The special strings 'oldest' - and 'newest' are supported by all blockchain connectors. - Default is 'newest' - type: string - type: object - signature: - description: The stringified signature of the event, as computed - by the blockchain plugin - type: string - topic: - description: A topic to set on the FireFly event that is emitted - each time a blockchain event is detected from the blockchain. - Setting this topic on a number of listeners allows applications - to easily subscribe to all events they need - type: string - type: object - description: Success - default: - description: "" - tags: - - Default Namespace - /contracts/listeners/{nameOrId}: - delete: - description: Deletes a contract listener referenced by its name or its ID - operationId: deleteContractListener - parameters: - - description: The contract listener name or ID - in: path - name: nameOrId - required: true - schema: - type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - responses: - "204": - content: - application/json: {} - description: Success - default: - description: "" - tags: - - Default Namespace - get: - description: Gets a contract listener by its name or ID - operationId: getContractListenerByNameOrID - parameters: - - description: The contract listener name or ID - in: path - name: nameOrId - required: true - schema: - type: string - - description: When set, the API will return additional status information if - available - in: query - name: fetchstatus - schema: - example: "true" - type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - responses: - "200": - content: - application/json: - schema: - properties: - backendId: - description: An ID assigned by the blockchain connector to this - listener - type: string - created: - description: The creation time of the listener - format: date-time - type: string - event: - description: The definition of the event, either provided in-line - when creating the listener, or extracted from the referenced - FFI - properties: - description: - description: A description of the smart contract event - type: string - details: - additionalProperties: - description: Additional blockchain specific fields about - this event from the original smart contract. Used by the - blockchain plugin and for documentation generation. - description: Additional blockchain specific fields about this - event from the original smart contract. Used by the blockchain - plugin and for documentation generation. - type: object - name: - description: The name of the event - type: string - params: - description: An array of event parameter/argument definitions - items: - description: An array of event parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to - the order in the blockchain smart contract - type: string - schema: - description: FireFly uses an extended subset of JSON - Schema to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail - type: object - type: array - type: object - id: - description: The UUID of the smart contract listener - format: uuid - type: string - interface: - description: A reference to an existing FFI, containing pre-registered - type information for the event - properties: - id: - description: The UUID of the FireFly interface - format: uuid - type: string - name: - description: The name of the FireFly interface - type: string - version: - description: The version of the FireFly interface - type: string - type: object - location: - description: A blockchain specific contract identifier. For example - an Ethereum contract address, or a Fabric chaincode name and - channel - name: - description: A descriptive name for the listener - type: string - namespace: - description: The namespace of the listener, which defines the - namespace of all blockchain events detected by this listener - type: string - options: - description: Options that control how the listener subscribes - to events from the underlying blockchain - properties: - firstEvent: - description: A blockchain specific string, such as a block - number, to start listening from. The special strings 'oldest' - and 'newest' are supported by all blockchain connectors. - Default is 'newest' - type: string - type: object - signature: - description: The stringified signature of the event, as computed - by the blockchain plugin - type: string - topic: - description: A topic to set on the FireFly event that is emitted - each time a blockchain event is detected from the blockchain. - Setting this topic on a number of listeners allows applications - to easily subscribe to all events they need - type: string - type: object - description: Success - default: - description: "" - tags: - - Default Namespace - /contracts/query: - post: - description: Queries a method on a smart contract. Performs a read-only query. - operationId: postContractQuery - parameters: - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - requestBody: - content: - application/json: - schema: - properties: - errors: - description: An in-line FFI errors definition for the method to - invoke. Alternative to specifying FFI - items: - description: An in-line FFI errors definition for the method to - invoke. Alternative to specifying FFI - properties: - description: - description: A description of the smart contract error - type: string - name: - description: The name of the error - type: string - params: - description: An array of error parameter/argument definitions - items: - description: An array of error parameter/argument definitions + description: An array of error parameter/argument definitions properties: name: description: The name of the parameter. Note that parameters @@ -4996,48 +4516,194 @@ paths: location: description: A blockchain specific contract identifier. For example an Ethereum contract address, or a Fabric chaincode name and channel - method: - description: An in-line FFI method definition for the method to - invoke. Required when FFI is not specified + message: + description: You can specify a message to correlate with the invocation, + which can be of type broadcast or private. Your specified method + must support on-chain/off-chain correlation by taking a data input + on the call properties: - description: - description: A description of the smart contract method - type: string - details: - additionalProperties: - description: Additional blockchain specific fields about this - method from the original smart contract. Used by the blockchain - plugin and for documentation generation. - description: Additional blockchain specific fields about this - method from the original smart contract. Used by the blockchain - plugin and for documentation generation. - type: object - name: - description: The name of the method - type: string - params: - description: An array of method parameter/argument definitions + data: + description: For input allows you to specify data in-line in + the message, that will be turned into data attachments. For + output when fetchdata is used on API calls, includes the in-line + data payloads of all data attachments items: - description: An array of method parameter/argument definitions + description: For input allows you to specify data in-line + in the message, that will be turned into data attachments. + For output when fetchdata is used on API calls, includes + the in-line data payloads of all data attachments properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to the - order in the blockchain smart contract + datatype: + description: The optional datatype to use for validation + of the in-line data + properties: + name: + description: The name of the datatype + type: string + version: + description: The version of the datatype. Semantic + versioning is encouraged, such as v1.0.1 + type: string + type: object + id: + description: The UUID of the referenced data resource + format: uuid type: string - schema: - description: FireFly uses an extended subset of JSON Schema - to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail + validator: + description: The data validator type to use for in-line + data + type: string + value: + description: The in-line value for the data. Can be any + JSON type - object, array, string, number or boolean type: object type: array - returns: - description: An array of method return definitions - items: - description: An array of method return definitions - properties: + group: + description: Allows you to specify details of the private group + of recipients in-line in the message. Alternative to using + the header.group to specify the hash of a group that has been + previously resolved + properties: + members: + description: An array of members of the group. If no identities + local to the sending node are included, then the organization + owner of the local node is added automatically + items: + description: An array of members of the group. If no identities + local to the sending node are included, then the organization + owner of the local node is added automatically + properties: + identity: + description: The DID of the group member. On input + can be a UUID or org name, and will be resolved + to a DID + type: string + node: + description: The UUID of the node that will receive + a copy of the off-chain message for the identity. + The first applicable node for the identity will + be picked automatically on input if not specified + type: string + type: object + type: array + name: + description: Optional name for the group. Allows you to + have multiple separate groups with the same list of participants + type: string + type: object + header: + description: The message header contains all fields that are + used to build the message hash + properties: + author: + description: The DID of identity of the submitter + type: string + cid: + description: The correlation ID of the message. Set this + when a message is a response to another message + format: uuid + type: string + group: + description: Private messages only - the identifier hash + of the privacy group. Derived from the name and member + list of the group + format: byte + type: string + key: + description: The on-chain signing key used to sign the transaction + type: string + tag: + description: The message tag indicates the purpose of the + message to the applications that process it + type: string + topics: + description: A message topic associates this message with + an ordered stream of data. A custom topic should be assigned + - using the default topic is discouraged + items: + description: A message topic associates this message with + an ordered stream of data. A custom topic should be + assigned - using the default topic is discouraged + type: string + type: array + txtype: + description: The type of transaction used to order/deliver + this message + enum: + - none + - unpinned + - batch_pin + - network_action + - token_pool + - token_transfer + - contract_deploy + - contract_invoke + - contract_invoke_pin + - token_approval + - data_publish + type: string + type: + description: The type of the message + enum: + - definition + - broadcast + - private + - groupinit + - transfer_broadcast + - transfer_private + - approval_broadcast + - approval_private + type: string + type: object + idempotencyKey: + description: An optional unique identifier for a message. Cannot + be duplicated within a namespace, thus allowing idempotent + submission of messages to the API. Local only - not transferred + when the message is sent to other members of the network + type: string + type: object + method: + description: An in-line FFI method definition for the method to + invoke. Required when FFI is not specified + properties: + description: + description: A description of the smart contract method + type: string + details: + additionalProperties: + description: Additional blockchain specific fields about this + method from the original smart contract. Used by the blockchain + plugin and for documentation generation. + description: Additional blockchain specific fields about this + method from the original smart contract. Used by the blockchain + plugin and for documentation generation. + type: object + name: + description: The name of the method + type: string + params: + description: An array of method parameter/argument definitions + items: + description: An array of method parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to the + order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON Schema + to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array + returns: + description: An array of method return definitions + items: + description: An array of method return definitions + properties: name: description: The name of the parameter. Note that parameters must be ordered correctly on the FFI, according to the @@ -5068,50 +4734,171 @@ paths: content: application/json: schema: - additionalProperties: {} + properties: + created: + description: The time the operation was created + format: date-time + type: string + error: + description: Any error reported back from the plugin for this + operation + type: string + id: + description: The UUID of the operation + format: uuid + type: string + input: + additionalProperties: + description: The input to this operation + description: The input to this operation + type: object + namespace: + description: The namespace of the operation + type: string + output: + additionalProperties: + description: Any output reported back from the plugin for this + operation + description: Any output reported back from the plugin for this + operation + type: object + plugin: + description: The plugin responsible for performing the operation + type: string + retry: + description: If this operation was initiated as a retry to a previous + operation, this field points to the UUID of the operation being + retried + format: uuid + type: string + status: + description: The current status of the operation + type: string + tx: + description: The UUID of the FireFly transaction the operation + is part of + format: uuid + type: string + type: + description: The type of the operation + enum: + - blockchain_pin_batch + - blockchain_network_action + - blockchain_deploy + - blockchain_invoke + - sharedstorage_upload_batch + - sharedstorage_upload_blob + - sharedstorage_upload_value + - sharedstorage_download_batch + - sharedstorage_download_blob + - dataexchange_send_batch + - dataexchange_send_blob + - token_create_pool + - token_activate_pool + - token_transfer + - token_approval + type: string + updated: + description: The last update time of the operation + format: date-time + type: string type: object description: Success - default: - description: "" - tags: - - Default Namespace - /data: - get: - description: Gets a list of data items - operationId: getData - parameters: - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: blob.hash - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: blob.name - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: blob.path - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: blob.public - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: blob.size - schema: - type: string + "202": + content: + application/json: + schema: + properties: + created: + description: The time the operation was created + format: date-time + type: string + error: + description: Any error reported back from the plugin for this + operation + type: string + id: + description: The UUID of the operation + format: uuid + type: string + input: + additionalProperties: + description: The input to this operation + description: The input to this operation + type: object + namespace: + description: The namespace of the operation + type: string + output: + additionalProperties: + description: Any output reported back from the plugin for this + operation + description: Any output reported back from the plugin for this + operation + type: object + plugin: + description: The plugin responsible for performing the operation + type: string + retry: + description: If this operation was initiated as a retry to a previous + operation, this field points to the UUID of the operation being + retried + format: uuid + type: string + status: + description: The current status of the operation + type: string + tx: + description: The UUID of the FireFly transaction the operation + is part of + format: uuid + type: string + type: + description: The type of the operation + enum: + - blockchain_pin_batch + - blockchain_network_action + - blockchain_deploy + - blockchain_invoke + - sharedstorage_upload_batch + - sharedstorage_upload_blob + - sharedstorage_upload_value + - sharedstorage_download_batch + - sharedstorage_download_blob + - dataexchange_send_batch + - dataexchange_send_blob + - token_create_pool + - token_activate_pool + - token_transfer + - token_approval + type: string + updated: + description: The last update time of the operation + format: date-time + type: string + type: object + description: Success + default: + description: "" + tags: + - Default Namespace + /contracts/listeners: + get: + description: Gets a list of contract listeners + operationId: getContractListeners + parameters: + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: backendid + schema: + type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query name: created @@ -5119,37 +4906,42 @@ paths: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: datatype.name + name: id schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: datatype.version + name: interface schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: hash + name: location schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: id + name: name schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: public + name: signature schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: validator + name: state schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: value + name: topic + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: updated schema: type: string - description: Sort field. For multi-field sort use comma separated values (or @@ -5193,73 +4985,104 @@ paths: schema: items: properties: - blob: - description: An optional hash reference to a binary blob attachment + backendId: + description: An ID assigned by the blockchain connector to this + listener + type: string + created: + description: The creation time of the listener + format: date-time + type: string + event: + description: The definition of the event, either provided in-line + when creating the listener, or extracted from the referenced + FFI properties: - hash: - description: The hash of the binary blob data - format: byte + description: + description: A description of the smart contract event type: string + details: + additionalProperties: + description: Additional blockchain specific fields about + this event from the original smart contract. Used by + the blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about + this event from the original smart contract. Used by the + blockchain plugin and for documentation generation. + type: object name: - description: The name field from the metadata attached to - the blob, commonly used as a path/filename, and indexed - for search - type: string - path: - description: If a name is specified, this field stores the - '/' prefixed and separated path extracted from the full - name - type: string - public: - description: If the blob data has been published to shared - storage, this field is the id of the data in the shared - storage plugin (IPFS hash etc.) + description: The name of the event type: string - size: - description: The size of the binary data - format: int64 - type: integer + params: + description: An array of event parameter/argument definitions + items: + description: An array of event parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array type: object - created: - description: The creation time of the data resource - format: date-time + id: + description: The UUID of the smart contract listener + format: uuid type: string - datatype: - description: The optional datatype to use of validation of this - data + interface: + description: A reference to an existing FFI, containing pre-registered + type information for the event properties: + id: + description: The UUID of the FireFly interface + format: uuid + type: string name: - description: The name of the datatype + description: The name of the FireFly interface type: string version: - description: The version of the datatype. Semantic versioning - is encouraged, such as v1.0.1 + description: The version of the FireFly interface type: string type: object - hash: - description: The hash of the data resource. Derived from the - value and the hash of any binary blob attachment - format: byte - type: string - id: - description: The UUID of the data resource - format: uuid + location: + description: A blockchain specific contract identifier. For + example an Ethereum contract address, or a Fabric chaincode + name and channel + name: + description: A descriptive name for the listener type: string namespace: - description: The namespace of the data resource + description: The namespace of the listener, which defines the + namespace of all blockchain events detected by this listener type: string - public: - description: If the JSON value has been published to shared - storage, this field is the id of the data in the shared storage - plugin (IPFS hash etc.) + options: + description: Options that control how the listener subscribes + to events from the underlying blockchain + properties: + firstEvent: + description: A blockchain specific string, such as a block + number, to start listening from. The special strings 'oldest' + and 'newest' are supported by all blockchain connectors. + Default is 'newest' + type: string + type: object + signature: + description: The stringified signature of the event, as computed + by the blockchain plugin type: string - validator: - description: The data validator type + topic: + description: A topic to set on the FireFly event that is emitted + each time a blockchain event is detected from the blockchain. + Setting this topic on a number of listeners allows applications + to easily subscribe to all events they need type: string - value: - description: The value for the data, stored in the FireFly core - database. Can be any JSON type - object, array, string, number - or boolean. Can be combined with a binary blob attachment type: object type: array description: Success @@ -5268,8 +5091,9 @@ paths: tags: - Default Namespace post: - description: Creates a new data item in this FireFly node - operationId: postData + description: Creates a new blockchain listener for events emitted by custom + smart contracts + operationId: postNewContractListener parameters: - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) @@ -5283,138 +5107,206 @@ paths: application/json: schema: properties: - datatype: - description: The optional datatype to use for validation of the - in-line data + event: + description: The definition of the event, either provided in-line + when creating the listener, or extracted from the referenced FFI properties: + description: + description: A description of the smart contract event + type: string + details: + additionalProperties: + description: Additional blockchain specific fields about this + event from the original smart contract. Used by the blockchain + plugin and for documentation generation. + description: Additional blockchain specific fields about this + event from the original smart contract. Used by the blockchain + plugin and for documentation generation. + type: object name: - description: The name of the datatype + description: The name of the event + type: string + params: + description: An array of event parameter/argument definitions + items: + description: An array of event parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to the + order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON Schema + to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array + type: object + eventPath: + description: When creating a listener from an existing FFI, this + is the pathname of the event on that FFI to be detected by this + listener + type: string + interface: + description: A reference to an existing FFI, containing pre-registered + type information for the event + properties: + id: + description: The UUID of the FireFly interface + format: uuid + type: string + name: + description: The name of the FireFly interface type: string version: - description: The version of the datatype. Semantic versioning - is encouraged, such as v1.0.1 + description: The version of the FireFly interface type: string type: object - id: - description: The UUID of the referenced data resource - format: uuid - type: string - validator: - description: The data validator type to use for in-line data - type: string - value: - description: The in-line value for the data. Can be any JSON type - - object, array, string, number or boolean - type: object - multipart/form-data: - schema: - properties: - autometa: - description: Success - type: string - datatype.name: - description: Success - type: string - datatype.version: - description: Success - type: string - filename.ext: - format: binary - type: string - metadata: - description: Success + location: + description: A blockchain specific contract identifier. For example + an Ethereum contract address, or a Fabric chaincode name and channel + name: + description: A descriptive name for the listener type: string - validator: - description: Success + options: + description: Options that control how the listener subscribes to + events from the underlying blockchain + properties: + firstEvent: + description: A blockchain specific string, such as a block number, + to start listening from. The special strings 'oldest' and + 'newest' are supported by all blockchain connectors. Default + is 'newest' + type: string + type: object + topic: + description: A topic to set on the FireFly event that is emitted + each time a blockchain event is detected from the blockchain. + Setting this topic on a number of listeners allows applications + to easily subscribe to all events they need type: string type: object responses: - "201": + "200": content: application/json: schema: properties: - blob: - description: An optional hash reference to a binary blob attachment + backendId: + description: An ID assigned by the blockchain connector to this + listener + type: string + created: + description: The creation time of the listener + format: date-time + type: string + event: + description: The definition of the event, either provided in-line + when creating the listener, or extracted from the referenced + FFI properties: - hash: - description: The hash of the binary blob data - format: byte + description: + description: A description of the smart contract event type: string + details: + additionalProperties: + description: Additional blockchain specific fields about + this event from the original smart contract. Used by the + blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about this + event from the original smart contract. Used by the blockchain + plugin and for documentation generation. + type: object name: - description: The name field from the metadata attached to - the blob, commonly used as a path/filename, and indexed - for search - type: string - path: - description: If a name is specified, this field stores the - '/' prefixed and separated path extracted from the full - name - type: string - public: - description: If the blob data has been published to shared - storage, this field is the id of the data in the shared - storage plugin (IPFS hash etc.) + description: The name of the event type: string - size: - description: The size of the binary data - format: int64 - type: integer + params: + description: An array of event parameter/argument definitions + items: + description: An array of event parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to + the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array type: object - created: - description: The creation time of the data resource - format: date-time + id: + description: The UUID of the smart contract listener + format: uuid type: string - datatype: - description: The optional datatype to use of validation of this - data + interface: + description: A reference to an existing FFI, containing pre-registered + type information for the event properties: + id: + description: The UUID of the FireFly interface + format: uuid + type: string name: - description: The name of the datatype + description: The name of the FireFly interface type: string version: - description: The version of the datatype. Semantic versioning - is encouraged, such as v1.0.1 + description: The version of the FireFly interface type: string type: object - hash: - description: The hash of the data resource. Derived from the value - and the hash of any binary blob attachment - format: byte - type: string - id: - description: The UUID of the data resource - format: uuid + location: + description: A blockchain specific contract identifier. For example + an Ethereum contract address, or a Fabric chaincode name and + channel + name: + description: A descriptive name for the listener type: string namespace: - description: The namespace of the data resource + description: The namespace of the listener, which defines the + namespace of all blockchain events detected by this listener type: string - public: - description: If the JSON value has been published to shared storage, - this field is the id of the data in the shared storage plugin - (IPFS hash etc.) + options: + description: Options that control how the listener subscribes + to events from the underlying blockchain + properties: + firstEvent: + description: A blockchain specific string, such as a block + number, to start listening from. The special strings 'oldest' + and 'newest' are supported by all blockchain connectors. + Default is 'newest' + type: string + type: object + signature: + description: The stringified signature of the event, as computed + by the blockchain plugin type: string - validator: - description: The data validator type + topic: + description: A topic to set on the FireFly event that is emitted + each time a blockchain event is detected from the blockchain. + Setting this topic on a number of listeners allows applications + to easily subscribe to all events they need type: string - value: - description: The value for the data, stored in the FireFly core - database. Can be any JSON type - object, array, string, number - or boolean. Can be combined with a binary blob attachment type: object description: Success default: description: "" tags: - Default Namespace - /data/{dataid}: + /contracts/listeners/{nameOrId}: delete: - description: Deletes a data item by its ID, including metadata about this item - operationId: deleteData + description: Deletes a contract listener referenced by its name or its ID + operationId: deleteContractListener parameters: - - description: The data item ID + - description: The contract listener name or ID in: path - name: dataid + name: nameOrId required: true schema: type: string @@ -5435,17 +5327,24 @@ paths: tags: - Default Namespace get: - description: Gets a data item by its ID, including metadata about this item - operationId: getDataByID + description: Gets a contract listener by its name or ID + operationId: getContractListenerByNameOrID parameters: - - description: The data item ID + - description: The contract listener name or ID in: path - name: dataid + name: nameOrId required: true schema: type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) + - description: When set, the API will return additional status information if + available + in: query + name: fetchstatus + schema: + example: "true" + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) in: header name: Request-Timeout schema: @@ -5457,90 +5356,115 @@ paths: application/json: schema: properties: - blob: - description: An optional hash reference to a binary blob attachment + backendId: + description: An ID assigned by the blockchain connector to this + listener + type: string + created: + description: The creation time of the listener + format: date-time + type: string + event: + description: The definition of the event, either provided in-line + when creating the listener, or extracted from the referenced + FFI properties: - hash: - description: The hash of the binary blob data - format: byte + description: + description: A description of the smart contract event type: string + details: + additionalProperties: + description: Additional blockchain specific fields about + this event from the original smart contract. Used by the + blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about this + event from the original smart contract. Used by the blockchain + plugin and for documentation generation. + type: object name: - description: The name field from the metadata attached to - the blob, commonly used as a path/filename, and indexed - for search - type: string - path: - description: If a name is specified, this field stores the - '/' prefixed and separated path extracted from the full - name - type: string - public: - description: If the blob data has been published to shared - storage, this field is the id of the data in the shared - storage plugin (IPFS hash etc.) + description: The name of the event type: string - size: - description: The size of the binary data - format: int64 - type: integer + params: + description: An array of event parameter/argument definitions + items: + description: An array of event parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to + the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array type: object - created: - description: The creation time of the data resource - format: date-time + id: + description: The UUID of the smart contract listener + format: uuid type: string - datatype: - description: The optional datatype to use of validation of this - data + interface: + description: A reference to an existing FFI, containing pre-registered + type information for the event properties: + id: + description: The UUID of the FireFly interface + format: uuid + type: string name: - description: The name of the datatype + description: The name of the FireFly interface type: string version: - description: The version of the datatype. Semantic versioning - is encouraged, such as v1.0.1 + description: The version of the FireFly interface type: string type: object - hash: - description: The hash of the data resource. Derived from the value - and the hash of any binary blob attachment - format: byte - type: string - id: - description: The UUID of the data resource - format: uuid + location: + description: A blockchain specific contract identifier. For example + an Ethereum contract address, or a Fabric chaincode name and + channel + name: + description: A descriptive name for the listener type: string namespace: - description: The namespace of the data resource + description: The namespace of the listener, which defines the + namespace of all blockchain events detected by this listener type: string - public: - description: If the JSON value has been published to shared storage, - this field is the id of the data in the shared storage plugin - (IPFS hash etc.) + options: + description: Options that control how the listener subscribes + to events from the underlying blockchain + properties: + firstEvent: + description: A blockchain specific string, such as a block + number, to start listening from. The special strings 'oldest' + and 'newest' are supported by all blockchain connectors. + Default is 'newest' + type: string + type: object + signature: + description: The stringified signature of the event, as computed + by the blockchain plugin type: string - validator: - description: The data validator type + topic: + description: A topic to set on the FireFly event that is emitted + each time a blockchain event is detected from the blockchain. + Setting this topic on a number of listeners allows applications + to easily subscribe to all events they need type: string - value: - description: The value for the data, stored in the FireFly core - database. Can be any JSON type - object, array, string, number - or boolean. Can be combined with a binary blob attachment type: object description: Success default: description: "" tags: - Default Namespace - /data/{dataid}/blob: - get: - description: Downloads the original file that was previously uploaded or received - operationId: getDataBlob + /contracts/query: + post: + description: Queries a method on a smart contract. Performs a read-only query. + operationId: postContractQuery parameters: - - description: The data item ID - in: path - name: dataid - required: true - schema: - type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) in: header @@ -5548,109 +5472,229 @@ paths: schema: default: 2m0s type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: author - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: batch - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: cid - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: confirmed - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: created - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: datahash - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: group - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: hash - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: id - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: idempotencykey - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: key - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: pins - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: sequence - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: state - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: tag - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: topics - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txid - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txparent.id - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txparent.type - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txtype - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: type + requestBody: + content: + application/json: + schema: + properties: + errors: + description: An in-line FFI errors definition for the method to + invoke. Alternative to specifying FFI + items: + description: An in-line FFI errors definition for the method to + invoke. Alternative to specifying FFI + properties: + description: + description: A description of the smart contract error + type: string + name: + description: The name of the error + type: string + params: + description: An array of error parameter/argument definitions + items: + description: An array of error parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to + the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array + type: object + type: array + idempotencyKey: + description: An optional identifier to allow idempotent submission + of requests. Stored on the transaction uniquely within a namespace + type: string + input: + additionalProperties: + description: A map of named inputs. The name and type of each + input must be compatible with the FFI description of the method, + so that FireFly knows how to serialize it to the blockchain + via the connector + description: A map of named inputs. The name and type of each input + must be compatible with the FFI description of the method, so + that FireFly knows how to serialize it to the blockchain via the + connector + type: object + interface: + description: The UUID of a method within a pre-configured FireFly + interface (FFI) definition for a smart contract. Required if the + 'method' is omitted. Also see Contract APIs as a way to configure + a dedicated API for your FFI, including all methods and an OpenAPI/Swagger + interface + format: uuid + type: string + key: + description: The blockchain signing key that will sign the invocation. + Defaults to the first signing key of the organization that operates + the node + type: string + location: + description: A blockchain specific contract identifier. For example + an Ethereum contract address, or a Fabric chaincode name and channel + method: + description: An in-line FFI method definition for the method to + invoke. Required when FFI is not specified + properties: + description: + description: A description of the smart contract method + type: string + details: + additionalProperties: + description: Additional blockchain specific fields about this + method from the original smart contract. Used by the blockchain + plugin and for documentation generation. + description: Additional blockchain specific fields about this + method from the original smart contract. Used by the blockchain + plugin and for documentation generation. + type: object + name: + description: The name of the method + type: string + params: + description: An array of method parameter/argument definitions + items: + description: An array of method parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to the + order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON Schema + to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array + returns: + description: An array of method return definitions + items: + description: An array of method return definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to the + order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON Schema + to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array + type: object + methodPath: + description: The pathname of the method on the specified FFI + type: string + options: + additionalProperties: + description: A map of named inputs that will be passed through + to the blockchain connector + description: A map of named inputs that will be passed through to + the blockchain connector + type: object + type: object + responses: + "200": + content: + application/json: + schema: + additionalProperties: {} + type: object + description: Success + default: + description: "" + tags: + - Default Namespace + /data: + get: + description: Gets a list of data items + operationId: getData + parameters: + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: blob.hash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: blob.name + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: blob.path + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: blob.public + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: blob.size + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: created + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: datatype.name + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: datatype.version + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: hash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: id + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: public + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: validator + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: value schema: type: string - description: Sort field. For multi-field sort use comma separated values (or @@ -5692,44 +5736,145 @@ paths: content: application/json: schema: - format: byte - type: string - description: Success - default: - description: "" - tags: - - Default Namespace - /data/{dataid}/blob/publish: - post: - description: Publishes the binary blob attachment stored in your local data - exchange, to shared storage - operationId: postDataBlobPublish - parameters: - - description: The blob ID - in: path - name: dataid - required: true - schema: - type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - requestBody: - content: - application/json: - schema: - properties: - idempotencyKey: - description: An optional identifier to allow idempotent submission - of requests. Stored on the transaction uniquely within a namespace + items: + properties: + blob: + description: An optional hash reference to a binary blob attachment + properties: + hash: + description: The hash of the binary blob data + format: byte + type: string + name: + description: The name field from the metadata attached to + the blob, commonly used as a path/filename, and indexed + for search + type: string + path: + description: If a name is specified, this field stores the + '/' prefixed and separated path extracted from the full + name + type: string + public: + description: If the blob data has been published to shared + storage, this field is the id of the data in the shared + storage plugin (IPFS hash etc.) + type: string + size: + description: The size of the binary data + format: int64 + type: integer + type: object + created: + description: The creation time of the data resource + format: date-time + type: string + datatype: + description: The optional datatype to use of validation of this + data + properties: + name: + description: The name of the datatype + type: string + version: + description: The version of the datatype. Semantic versioning + is encouraged, such as v1.0.1 + type: string + type: object + hash: + description: The hash of the data resource. Derived from the + value and the hash of any binary blob attachment + format: byte + type: string + id: + description: The UUID of the data resource + format: uuid + type: string + namespace: + description: The namespace of the data resource + type: string + public: + description: If the JSON value has been published to shared + storage, this field is the id of the data in the shared storage + plugin (IPFS hash etc.) + type: string + validator: + description: The data validator type + type: string + value: + description: The value for the data, stored in the FireFly core + database. Can be any JSON type - object, array, string, number + or boolean. Can be combined with a binary blob attachment + type: object + type: array + description: Success + default: + description: "" + tags: + - Default Namespace + post: + description: Creates a new data item in this FireFly node + operationId: postData + parameters: + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + requestBody: + content: + application/json: + schema: + properties: + datatype: + description: The optional datatype to use for validation of the + in-line data + properties: + name: + description: The name of the datatype + type: string + version: + description: The version of the datatype. Semantic versioning + is encouraged, such as v1.0.1 + type: string + type: object + id: + description: The UUID of the referenced data resource + format: uuid + type: string + validator: + description: The data validator type to use for in-line data + type: string + value: + description: The in-line value for the data. Can be any JSON type + - object, array, string, number or boolean + type: object + multipart/form-data: + schema: + properties: + autometa: + description: Success + type: string + datatype.name: + description: Success + type: string + datatype.version: + description: Success + type: string + filename.ext: + format: binary + type: string + metadata: + description: Success + type: string + validator: + description: Success type: string type: object responses: - "200": + "201": content: application/json: schema: @@ -5807,10 +5952,10 @@ paths: description: "" tags: - Default Namespace - /data/{dataid}/messages: - get: - description: Gets a list of the messages associated with a data item - operationId: getDataMsgs + /data/{dataid}: + delete: + description: Deletes a data item by its ID, including metadata about this item + operationId: deleteData parameters: - description: The data item ID in: path @@ -5825,144 +5970,31 @@ paths: schema: default: 2m0s type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: author - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: batch - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: cid - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: confirmed - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: created - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: datahash - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: group - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: hash - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: id - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: idempotencykey - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: key - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: pins - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: sequence - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: state - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: tag - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: topics - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txid + responses: + "204": + content: + application/json: {} + description: Success + default: + description: "" + tags: + - Default Namespace + get: + description: Gets a data item by its ID, including metadata about this item + operationId: getDataByID + parameters: + - description: The data item ID + in: path + name: dataid + required: true schema: type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txparent.id - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txparent.type - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txtype - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: type - schema: - type: string - - description: Sort field. For multi-field sort use comma separated values (or - multiple query values) with '-' prefix for descending - in: query - name: sort - schema: - type: string - - description: Ascending sort order (overrides all fields in a multi-field sort) - in: query - name: ascending - schema: - type: string - - description: Descending sort order (overrides all fields in a multi-field - sort) - in: query - name: descending - schema: - type: string - - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk - operations' - in: query - name: skip - schema: - type: string - - description: 'The maximum number of records to return (max: 1,000)' - in: query - name: limit - schema: - example: "25" - type: string - - description: Return a total count as well as items (adds extra database processing) - in: query - name: count + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout schema: + default: 2m0s type: string responses: "200": @@ -5970,173 +6002,85 @@ paths: application/json: schema: properties: - batch: - description: The UUID of the batch in which the message was pinned/transferred - format: uuid - type: string - confirmed: - description: The timestamp of when the message was confirmed/rejected - format: date-time - type: string - data: - description: The list of data elements attached to the message - items: - description: The list of data elements attached to the message - properties: - hash: - description: The hash of the referenced data - format: byte - type: string - id: - description: The UUID of the referenced data resource - format: uuid - type: string - type: object - type: array - hash: - description: The hash of the message. Derived from the header, - which includes the data hash - format: byte - type: string - header: - description: The message header contains all fields that are used - to build the message hash + blob: + description: An optional hash reference to a binary blob attachment properties: - author: - description: The DID of identity of the submitter - type: string - cid: - description: The correlation ID of the message. Set this when - a message is a response to another message - format: uuid - type: string - created: - description: The creation time of the message - format: date-time - type: string - datahash: - description: A single hash representing all data in the message. - Derived from the array of data ids+hashes attached to this - message - format: byte - type: string - group: - description: Private messages only - the identifier hash of - the privacy group. Derived from the name and member list - of the group + hash: + description: The hash of the binary blob data format: byte type: string - id: - description: The UUID of the message. Unique to each message - format: uuid - type: string - key: - description: The on-chain signing key used to sign the transaction + name: + description: The name field from the metadata attached to + the blob, commonly used as a path/filename, and indexed + for search type: string - namespace: - description: The namespace of the message within the multiparty - network + path: + description: If a name is specified, this field stores the + '/' prefixed and separated path extracted from the full + name type: string - tag: - description: The message tag indicates the purpose of the - message to the applications that process it + public: + description: If the blob data has been published to shared + storage, this field is the id of the data in the shared + storage plugin (IPFS hash etc.) type: string - topics: - description: A message topic associates this message with - an ordered stream of data. A custom topic should be assigned - - using the default topic is discouraged - items: - description: A message topic associates this message with - an ordered stream of data. A custom topic should be assigned - - using the default topic is discouraged - type: string - type: array - txparent: - description: The parent transaction that originally triggered - this message - properties: - id: - description: The UUID of the FireFly transaction - format: uuid - type: string - type: - description: The type of the FireFly transaction - type: string - type: object - txtype: - description: The type of transaction used to order/deliver - this message - enum: - - none - - unpinned - - batch_pin - - network_action - - token_pool - - token_transfer - - contract_deploy - - contract_invoke - - contract_invoke_pin - - token_approval - - data_publish + size: + description: The size of the binary data + format: int64 + type: integer + type: object + created: + description: The creation time of the data resource + format: date-time + type: string + datatype: + description: The optional datatype to use of validation of this + data + properties: + name: + description: The name of the datatype type: string - type: - description: The type of the message - enum: - - definition - - broadcast - - private - - groupinit - - transfer_broadcast - - transfer_private - - approval_broadcast - - approval_private + version: + description: The version of the datatype. Semantic versioning + is encouraged, such as v1.0.1 type: string type: object - idempotencyKey: - description: An optional unique identifier for a message. Cannot - be duplicated within a namespace, thus allowing idempotent submission - of messages to the API. Local only - not transferred when the - message is sent to other members of the network + hash: + description: The hash of the data resource. Derived from the value + and the hash of any binary blob attachment + format: byte type: string - localNamespace: - description: The local namespace of the message + id: + description: The UUID of the data resource + format: uuid type: string - pins: - description: For private messages, a unique pin hash:nonce is - assigned for each topic - items: - description: For private messages, a unique pin hash:nonce is - assigned for each topic - type: string - type: array - state: - description: The current state of the message - enum: - - staged - - ready - - sent - - pending - - confirmed - - rejected + namespace: + description: The namespace of the data resource type: string - txid: - description: The ID of the transaction used to order/deliver this - message - format: uuid + public: + description: If the JSON value has been published to shared storage, + this field is the id of the data in the shared storage plugin + (IPFS hash etc.) type: string + validator: + description: The data validator type + type: string + value: + description: The value for the data, stored in the FireFly core + database. Can be any JSON type - object, array, string, number + or boolean. Can be combined with a binary blob attachment type: object description: Success default: description: "" tags: - Default Namespace - /data/{dataid}/value: + /data/{dataid}/blob: get: - description: Downloads the JSON value of the data resource, without the associated - metadata - operationId: getDataValue + description: Downloads the original file that was previously uploaded or received + operationId: getDataBlob parameters: - - description: The blob ID + - description: The data item ID in: path name: dataid required: true @@ -6300,11 +6244,11 @@ paths: description: "" tags: - Default Namespace - /data/{dataid}/value/publish: + /data/{dataid}/blob/publish: post: - description: Publishes the JSON value from the specified data resource, to shared - storage - operationId: postDataValuePublish + description: Publishes the binary blob attachment stored in your local data + exchange, to shared storage + operationId: postDataBlobPublish parameters: - description: The blob ID in: path @@ -6408,15 +6352,14 @@ paths: description: "" tags: - Default Namespace - /datasubpaths/{parent}: + /data/{dataid}/messages: get: - description: Gets a list of path names of named blob data, underneath a given - parent path ('/' path prefixes are automatically pre-prepended) - operationId: getDataSubPaths + description: Gets a list of the messages associated with a data item + operationId: getDataMsgs parameters: - - description: The parent path to query + - description: The data item ID in: path - name: parent + name: dataid required: true schema: type: string @@ -6427,36 +6370,46 @@ paths: schema: default: 2m0s type: string - responses: - "200": - content: - application/json: - schema: - items: - type: string - type: array - description: Success - default: - description: "" - tags: - - Default Namespace - /datatypes: - get: - description: Gets a list of datatypes that have been published - operationId: getDatatypes - parameters: - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: author + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: batch + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: cid + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: confirmed schema: - default: 2m0s type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query name: created schema: type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: datahash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: group + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: hash + schema: + type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query name: id @@ -6464,22 +6417,62 @@ paths: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: message + name: idempotencykey schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: name + name: key schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: validator + name: pins schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: version + name: sequence + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: state + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: tag + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: topics + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txid + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txparent.id + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txparent.type + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txtype + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: type schema: type: string - description: Sort field. For multi-field sort use comma separated values (or @@ -6516,199 +6509,165 @@ paths: name: count schema: type: string - responses: - "200": - content: - application/json: - schema: - items: - properties: - created: - description: The time the datatype was created - format: date-time - type: string - hash: - description: The hash of the value, such as the JSON schema. - Allows all parties to be confident they have the exact same - rules for verifying data created against a datatype - format: byte - type: string - id: - description: The UUID of the datatype - format: uuid - type: string - message: - description: The UUID of the broadcast message that was used - to publish this datatype to the network - format: uuid - type: string - name: - description: The name of the datatype - type: string - namespace: - description: The namespace of the datatype. Data resources can - only be created referencing datatypes in the same namespace - type: string - validator: - description: The validator that should be used to verify this - datatype - enum: - - json - - none - - definition - type: string - value: - description: The definition of the datatype, in the syntax supported - by the validator (such as a JSON Schema definition) - version: - description: The version of the datatype. Multiple versions - can exist with the same name. Use of semantic versioning is - encourages, such as v1.0.1 - type: string - type: object - type: array - description: Success - default: - description: "" - tags: - - Default Namespace - post: - description: Creates and broadcasts a new datatype - operationId: postNewDatatype - parameters: - - description: When true the HTTP request blocks until the message is confirmed - in: query - name: confirm - schema: - example: "true" - type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - requestBody: - content: - application/json: - schema: - properties: - name: - description: The name of the datatype - type: string - validator: - description: The validator that should be used to verify this datatype - enum: - - json - - none - - definition - type: string - value: - description: The definition of the datatype, in the syntax supported - by the validator (such as a JSON Schema definition) - version: - description: The version of the datatype. Multiple versions can - exist with the same name. Use of semantic versioning is encourages, - such as v1.0.1 - type: string - type: object responses: "200": content: application/json: schema: properties: - created: - description: The time the datatype was created + batch: + description: The UUID of the batch in which the message was pinned/transferred + format: uuid + type: string + confirmed: + description: The timestamp of when the message was confirmed/rejected format: date-time type: string + data: + description: The list of data elements attached to the message + items: + description: The list of data elements attached to the message + properties: + hash: + description: The hash of the referenced data + format: byte + type: string + id: + description: The UUID of the referenced data resource + format: uuid + type: string + type: object + type: array hash: - description: The hash of the value, such as the JSON schema. Allows - all parties to be confident they have the exact same rules for - verifying data created against a datatype + description: The hash of the message. Derived from the header, + which includes the data hash format: byte type: string - id: - description: The UUID of the datatype - format: uuid - type: string - message: - description: The UUID of the broadcast message that was used to - publish this datatype to the network - format: uuid - type: string - name: - description: The name of the datatype - type: string - namespace: - description: The namespace of the datatype. Data resources can - only be created referencing datatypes in the same namespace - type: string - validator: - description: The validator that should be used to verify this - datatype - enum: - - json - - none - - definition - type: string - value: - description: The definition of the datatype, in the syntax supported - by the validator (such as a JSON Schema definition) - version: - description: The version of the datatype. Multiple versions can - exist with the same name. Use of semantic versioning is encourages, - such as v1.0.1 - type: string - type: object - description: Success - "202": - content: - application/json: - schema: - properties: - created: - description: The time the datatype was created - format: date-time - type: string - hash: - description: The hash of the value, such as the JSON schema. Allows - all parties to be confident they have the exact same rules for - verifying data created against a datatype - format: byte - type: string - id: - description: The UUID of the datatype - format: uuid - type: string - message: - description: The UUID of the broadcast message that was used to - publish this datatype to the network - format: uuid - type: string - name: - description: The name of the datatype + header: + description: The message header contains all fields that are used + to build the message hash + properties: + author: + description: The DID of identity of the submitter + type: string + cid: + description: The correlation ID of the message. Set this when + a message is a response to another message + format: uuid + type: string + created: + description: The creation time of the message + format: date-time + type: string + datahash: + description: A single hash representing all data in the message. + Derived from the array of data ids+hashes attached to this + message + format: byte + type: string + group: + description: Private messages only - the identifier hash of + the privacy group. Derived from the name and member list + of the group + format: byte + type: string + id: + description: The UUID of the message. Unique to each message + format: uuid + type: string + key: + description: The on-chain signing key used to sign the transaction + type: string + namespace: + description: The namespace of the message within the multiparty + network + type: string + tag: + description: The message tag indicates the purpose of the + message to the applications that process it + type: string + topics: + description: A message topic associates this message with + an ordered stream of data. A custom topic should be assigned + - using the default topic is discouraged + items: + description: A message topic associates this message with + an ordered stream of data. A custom topic should be assigned + - using the default topic is discouraged + type: string + type: array + txparent: + description: The parent transaction that originally triggered + this message + properties: + id: + description: The UUID of the FireFly transaction + format: uuid + type: string + type: + description: The type of the FireFly transaction + type: string + type: object + txtype: + description: The type of transaction used to order/deliver + this message + enum: + - none + - unpinned + - batch_pin + - network_action + - token_pool + - token_transfer + - contract_deploy + - contract_invoke + - contract_invoke_pin + - token_approval + - data_publish + type: string + type: + description: The type of the message + enum: + - definition + - broadcast + - private + - groupinit + - transfer_broadcast + - transfer_private + - approval_broadcast + - approval_private + type: string + type: object + idempotencyKey: + description: An optional unique identifier for a message. Cannot + be duplicated within a namespace, thus allowing idempotent submission + of messages to the API. Local only - not transferred when the + message is sent to other members of the network type: string - namespace: - description: The namespace of the datatype. Data resources can - only be created referencing datatypes in the same namespace + localNamespace: + description: The local namespace of the message type: string - validator: - description: The validator that should be used to verify this - datatype + pins: + description: For private messages, a unique pin hash:nonce is + assigned for each topic + items: + description: For private messages, a unique pin hash:nonce is + assigned for each topic + type: string + type: array + state: + description: The current state of the message enum: - - json - - none - - definition + - staged + - ready + - sent + - pending + - confirmed + - rejected type: string - value: - description: The definition of the datatype, in the syntax supported - by the validator (such as a JSON Schema definition) - version: - description: The version of the datatype. Multiple versions can - exist with the same name. Use of semantic versioning is encourages, - such as v1.0.1 + txid: + description: The ID of the transaction used to order/deliver this + message + format: uuid type: string type: object description: Success @@ -6716,20 +6675,15 @@ paths: description: "" tags: - Default Namespace - /datatypes/{name}/{version}: + /data/{dataid}/value: get: - description: Gets a datatype by its name and version - operationId: getDatatypeByName + description: Downloads the JSON value of the data resource, without the associated + metadata + operationId: getDataValue parameters: - - description: The name of the datatype - in: path - name: name - required: true - schema: - type: string - - description: The version of the datatype + - description: The blob ID in: path - name: version + name: dataid required: true schema: type: string @@ -6740,89 +6694,24 @@ paths: schema: default: 2m0s type: string - responses: - "200": - content: - application/json: - schema: - properties: - created: - description: The time the datatype was created - format: date-time - type: string - hash: - description: The hash of the value, such as the JSON schema. Allows - all parties to be confident they have the exact same rules for - verifying data created against a datatype - format: byte - type: string - id: - description: The UUID of the datatype - format: uuid - type: string - message: - description: The UUID of the broadcast message that was used to - publish this datatype to the network - format: uuid - type: string - name: - description: The name of the datatype - type: string - namespace: - description: The namespace of the datatype. Data resources can - only be created referencing datatypes in the same namespace - type: string - validator: - description: The validator that should be used to verify this - datatype - enum: - - json - - none - - definition - type: string - value: - description: The definition of the datatype, in the syntax supported - by the validator (such as a JSON Schema definition) - version: - description: The version of the datatype. Multiple versions can - exist with the same name. Use of semantic versioning is encourages, - such as v1.0.1 - type: string - type: object - description: Success - default: - description: "" - tags: - - Default Namespace - /events: - get: - description: Gets a list of events - operationId: getEvents - parameters: - - description: When set, the API will return the record that this item references - in its 'reference' field + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: fetchreferences + name: author schema: - example: "true" type: string - - description: When set, the API will return the record that this item references - in its 'reference' field + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: fetchreference + name: batch schema: - example: "true" type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: cid schema: - default: 2m0s type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: correlator + name: confirmed schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' @@ -6830,6 +6719,21 @@ paths: name: created schema: type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: datahash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: group + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: hash + schema: + type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query name: id @@ -6837,7 +6741,17 @@ paths: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: reference + name: idempotencykey + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: key + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: pins schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' @@ -6847,12 +6761,37 @@ paths: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: topic + name: state schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: tx + name: tag + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: topics + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txid + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txparent.id + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txparent.type + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txtype schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' @@ -6899,107 +6838,25 @@ paths: content: application/json: schema: - items: - properties: - correlator: - description: For message events, this is the 'header.cid' field - from the referenced message. For certain other event types, - a secondary object is referenced such as a token pool - format: uuid - type: string - created: - description: The time the event was emitted. Not guaranteed - to be unique, or to increase between events in the same order - as the final sequence events are delivered to your application. - As such, the 'sequence' field should be used instead of the - 'created' field for querying events in the exact order they - are delivered to applications - format: date-time - type: string - id: - description: The UUID assigned to this event by your local FireFly - node - format: uuid - type: string - namespace: - description: The namespace of the event. Your application must - subscribe to events within a namespace - type: string - reference: - description: The UUID of an resource that is the subject of - this event. The event type determines what type of resource - is referenced, and whether this field might be unset - format: uuid - type: string - sequence: - description: A sequence indicating the order in which events - are delivered to your application. Assure to be unique per - event in your local FireFly database (unlike the created timestamp) - format: int64 - type: integer - topic: - description: A stream of information this event relates to. - For message confirmation events, a separate event is emitted - for each topic in the message. For blockchain events, the - listener specifies the topic. Rules exist for how the topic - is set for other event types - type: string - tx: - description: The UUID of a transaction that is event is part - of. Not all events are part of a transaction - format: uuid - type: string - type: - description: All interesting activity in FireFly is emitted - as a FireFly event, of a given type. The 'type' combined with - the 'reference' can be used to determine how to process the - event within your application - enum: - - transaction_submitted - - message_confirmed - - message_rejected - - datatype_confirmed - - identity_confirmed - - identity_updated - - token_pool_confirmed - - token_pool_op_failed - - token_transfer_confirmed - - token_transfer_op_failed - - token_approval_confirmed - - token_approval_op_failed - - contract_interface_confirmed - - contract_api_confirmed - - blockchain_event_received - - blockchain_invoke_op_succeeded - - blockchain_invoke_op_failed - - blockchain_contract_deploy_op_succeeded - - blockchain_contract_deploy_op_failed - type: string - type: object - type: array + format: byte + type: string description: Success default: description: "" tags: - Default Namespace - /events/{eid}: - get: - description: Gets an event by its ID - operationId: getEventByID + /data/{dataid}/value/publish: + post: + description: Publishes the JSON value from the specified data resource, to shared + storage + operationId: postDataValuePublish parameters: - - description: The event ID + - description: The blob ID in: path - name: eid + name: dataid required: true schema: type: string - - description: When set, the API will return the record that this item references - in its 'reference' field - in: query - name: fetchreference - schema: - example: "true" - type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) in: header @@ -7007,96 +6864,131 @@ paths: schema: default: 2m0s type: string + requestBody: + content: + application/json: + schema: + properties: + idempotencyKey: + description: An optional identifier to allow idempotent submission + of requests. Stored on the transaction uniquely within a namespace + type: string + type: object responses: "200": content: application/json: schema: properties: - correlator: - description: For message events, this is the 'header.cid' field - from the referenced message. For certain other event types, - a secondary object is referenced such as a token pool - format: uuid - type: string + blob: + description: An optional hash reference to a binary blob attachment + properties: + hash: + description: The hash of the binary blob data + format: byte + type: string + name: + description: The name field from the metadata attached to + the blob, commonly used as a path/filename, and indexed + for search + type: string + path: + description: If a name is specified, this field stores the + '/' prefixed and separated path extracted from the full + name + type: string + public: + description: If the blob data has been published to shared + storage, this field is the id of the data in the shared + storage plugin (IPFS hash etc.) + type: string + size: + description: The size of the binary data + format: int64 + type: integer + type: object created: - description: The time the event was emitted. Not guaranteed to - be unique, or to increase between events in the same order as - the final sequence events are delivered to your application. - As such, the 'sequence' field should be used instead of the - 'created' field for querying events in the exact order they - are delivered to applications + description: The creation time of the data resource format: date-time type: string + datatype: + description: The optional datatype to use of validation of this + data + properties: + name: + description: The name of the datatype + type: string + version: + description: The version of the datatype. Semantic versioning + is encouraged, such as v1.0.1 + type: string + type: object + hash: + description: The hash of the data resource. Derived from the value + and the hash of any binary blob attachment + format: byte + type: string id: - description: The UUID assigned to this event by your local FireFly - node + description: The UUID of the data resource format: uuid type: string namespace: - description: The namespace of the event. Your application must - subscribe to events within a namespace + description: The namespace of the data resource type: string - reference: - description: The UUID of an resource that is the subject of this - event. The event type determines what type of resource is referenced, - and whether this field might be unset - format: uuid - type: string - sequence: - description: A sequence indicating the order in which events are - delivered to your application. Assure to be unique per event - in your local FireFly database (unlike the created timestamp) - format: int64 - type: integer - topic: - description: A stream of information this event relates to. For - message confirmation events, a separate event is emitted for - each topic in the message. For blockchain events, the listener - specifies the topic. Rules exist for how the topic is set for - other event types - type: string - tx: - description: The UUID of a transaction that is event is part of. - Not all events are part of a transaction - format: uuid + public: + description: If the JSON value has been published to shared storage, + this field is the id of the data in the shared storage plugin + (IPFS hash etc.) type: string - type: - description: All interesting activity in FireFly is emitted as - a FireFly event, of a given type. The 'type' combined with the - 'reference' can be used to determine how to process the event - within your application - enum: - - transaction_submitted - - message_confirmed - - message_rejected - - datatype_confirmed - - identity_confirmed - - identity_updated - - token_pool_confirmed - - token_pool_op_failed - - token_transfer_confirmed - - token_transfer_op_failed - - token_approval_confirmed - - token_approval_op_failed - - contract_interface_confirmed - - contract_api_confirmed - - blockchain_event_received - - blockchain_invoke_op_succeeded - - blockchain_invoke_op_failed - - blockchain_contract_deploy_op_succeeded - - blockchain_contract_deploy_op_failed + validator: + description: The data validator type type: string + value: + description: The value for the data, stored in the FireFly core + database. Can be any JSON type - object, array, string, number + or boolean. Can be combined with a binary blob attachment type: object description: Success default: description: "" tags: - Default Namespace - /groups: + /datasubpaths/{parent}: get: - description: Gets a list of groups - operationId: getGroups + description: Gets a list of path names of named blob data, underneath a given + parent path ('/' path prefixes are automatically pre-prepended) + operationId: getDataSubPaths + parameters: + - description: The parent path to query + in: path + name: parent + required: true + schema: + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + responses: + "200": + content: + application/json: + schema: + items: + type: string + type: array + description: Success + default: + description: "" + tags: + - Default Namespace + /datatypes: + get: + description: Gets a list of datatypes that have been published + operationId: getDatatypes parameters: - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) @@ -7112,22 +7004,27 @@ paths: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: description + name: id schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: hash + name: message schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: ledger + name: name schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: message + name: validator + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: version schema: type: string - description: Sort field. For multi-field sort use comma separated values (or @@ -7172,45 +7069,46 @@ paths: items: properties: created: - description: The time when the group was first used to send - a message in the network + description: The time the datatype was created format: date-time type: string hash: - description: The identifier hash of this group. Derived from - the name and group members + description: The hash of the value, such as the JSON schema. + Allows all parties to be confident they have the exact same + rules for verifying data created against a datatype format: byte type: string - localNamespace: - description: The local namespace of the group + id: + description: The UUID of the datatype + format: uuid type: string - members: - description: The list of members in this privacy group - items: - description: The list of members in this privacy group - properties: - identity: - description: The DID of the group member - type: string - node: - description: The UUID of the node that receives a copy - of the off-chain message for the identity - format: uuid - type: string - type: object - type: array message: - description: The message used to broadcast this group privately - to the members + description: The UUID of the broadcast message that was used + to publish this datatype to the network format: uuid type: string name: - description: The optional name of the group, allowing multiple - unique groups to exist with the same list of recipients + description: The name of the datatype type: string namespace: - description: The namespace of the group within the multiparty - network + description: The namespace of the datatype. Data resources can + only be created referencing datatypes in the same namespace + type: string + validator: + description: The validator that should be used to verify this + datatype + enum: + - json + - none + - definition + type: string + value: + description: The definition of the datatype, in the syntax supported + by the validator (such as a JSON Schema definition) + version: + description: The version of the datatype. Multiple versions + can exist with the same name. Use of semantic versioning is + encourages, such as v1.0.1 type: string type: object type: array @@ -7219,16 +7117,15 @@ paths: description: "" tags: - Default Namespace - /groups/{hash}: - get: - description: Gets a group by its ID (hash) - operationId: getGroupByHash + post: + description: Creates and broadcasts a new datatype + operationId: postNewDatatype parameters: - - description: The hash of the group - in: path - name: hash - required: true + - description: When true the HTTP request blocks until the message is confirmed + in: query + name: confirm schema: + example: "true" type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) @@ -7237,6 +7134,30 @@ paths: schema: default: 2m0s type: string + requestBody: + content: + application/json: + schema: + properties: + name: + description: The name of the datatype + type: string + validator: + description: The validator that should be used to verify this datatype + enum: + - json + - none + - definition + type: string + value: + description: The definition of the datatype, in the syntax supported + by the validator (such as a JSON Schema definition) + version: + description: The version of the datatype. Multiple versions can + exist with the same name. Use of semantic versioning is encourages, + such as v1.0.1 + type: string + type: object responses: "200": content: @@ -7244,63 +7165,118 @@ paths: schema: properties: created: - description: The time when the group was first used to send a - message in the network + description: The time the datatype was created format: date-time type: string hash: - description: The identifier hash of this group. Derived from the - name and group members + description: The hash of the value, such as the JSON schema. Allows + all parties to be confident they have the exact same rules for + verifying data created against a datatype format: byte type: string - localNamespace: - description: The local namespace of the group + id: + description: The UUID of the datatype + format: uuid type: string - members: - description: The list of members in this privacy group - items: - description: The list of members in this privacy group - properties: - identity: - description: The DID of the group member - type: string - node: - description: The UUID of the node that receives a copy of - the off-chain message for the identity - format: uuid - type: string - type: object - type: array message: - description: The message used to broadcast this group privately - to the members + description: The UUID of the broadcast message that was used to + publish this datatype to the network format: uuid type: string name: - description: The optional name of the group, allowing multiple - unique groups to exist with the same list of recipients + description: The name of the datatype type: string namespace: - description: The namespace of the group within the multiparty - network + description: The namespace of the datatype. Data resources can + only be created referencing datatypes in the same namespace type: string - type: object - description: Success - default: - description: "" - tags: - - Default Namespace - /identities: - get: - description: Gets a list of all identities that have been registered in the - namespace - operationId: getIdentities - parameters: - - description: When set, the API will return the verifier for this identity - in: query - name: fetchverifiers + validator: + description: The validator that should be used to verify this + datatype + enum: + - json + - none + - definition + type: string + value: + description: The definition of the datatype, in the syntax supported + by the validator (such as a JSON Schema definition) + version: + description: The version of the datatype. Multiple versions can + exist with the same name. Use of semantic versioning is encourages, + such as v1.0.1 + type: string + type: object + description: Success + "202": + content: + application/json: + schema: + properties: + created: + description: The time the datatype was created + format: date-time + type: string + hash: + description: The hash of the value, such as the JSON schema. Allows + all parties to be confident they have the exact same rules for + verifying data created against a datatype + format: byte + type: string + id: + description: The UUID of the datatype + format: uuid + type: string + message: + description: The UUID of the broadcast message that was used to + publish this datatype to the network + format: uuid + type: string + name: + description: The name of the datatype + type: string + namespace: + description: The namespace of the datatype. Data resources can + only be created referencing datatypes in the same namespace + type: string + validator: + description: The validator that should be used to verify this + datatype + enum: + - json + - none + - definition + type: string + value: + description: The definition of the datatype, in the syntax supported + by the validator (such as a JSON Schema definition) + version: + description: The version of the datatype. Multiple versions can + exist with the same name. Use of semantic versioning is encourages, + such as v1.0.1 + type: string + type: object + description: Success + default: + description: "" + tags: + - Default Namespace + /datatypes/{name}/{version}: + get: + description: Gets a datatype by its name and version + operationId: getDatatypeByName + parameters: + - description: The name of the datatype + in: path + name: name + required: true + schema: + type: string + - description: The version of the datatype + in: path + name: version + required: true schema: - example: "true" type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) @@ -7309,54 +7285,119 @@ paths: schema: default: 2m0s type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + responses: + "200": + content: + application/json: + schema: + properties: + created: + description: The time the datatype was created + format: date-time + type: string + hash: + description: The hash of the value, such as the JSON schema. Allows + all parties to be confident they have the exact same rules for + verifying data created against a datatype + format: byte + type: string + id: + description: The UUID of the datatype + format: uuid + type: string + message: + description: The UUID of the broadcast message that was used to + publish this datatype to the network + format: uuid + type: string + name: + description: The name of the datatype + type: string + namespace: + description: The namespace of the datatype. Data resources can + only be created referencing datatypes in the same namespace + type: string + validator: + description: The validator that should be used to verify this + datatype + enum: + - json + - none + - definition + type: string + value: + description: The definition of the datatype, in the syntax supported + by the validator (such as a JSON Schema definition) + version: + description: The version of the datatype. Multiple versions can + exist with the same name. Use of semantic versioning is encourages, + such as v1.0.1 + type: string + type: object + description: Success + default: + description: "" + tags: + - Default Namespace + /events: + get: + description: Gets a list of events + operationId: getEvents + parameters: + - description: When set, the API will return the record that this item references + in its 'reference' field in: query - name: created + name: fetchreferences schema: + example: "true" type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + - description: When set, the API will return the record that this item references + in its 'reference' field in: query - name: description + name: fetchreference schema: + example: "true" type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: did + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout schema: + default: 2m0s type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: id + name: correlator schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: messages.claim + name: created schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: messages.update + name: id schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: messages.verification + name: reference schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: name + name: sequence schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: parent + name: topic schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: profile + name: tx schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' @@ -7364,11 +7405,6 @@ paths: name: type schema: type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: updated - schema: - type: string - description: Sort field. For multi-field sort use comma separated values (or multiple query values) with '-' prefix for descending in: query @@ -7410,95 +7446,80 @@ paths: schema: items: properties: + correlator: + description: For message events, this is the 'header.cid' field + from the referenced message. For certain other event types, + a secondary object is referenced such as a token pool + format: uuid + type: string created: - description: The creation time of the identity + description: The time the event was emitted. Not guaranteed + to be unique, or to increase between events in the same order + as the final sequence events are delivered to your application. + As such, the 'sequence' field should be used instead of the + 'created' field for querying events in the exact order they + are delivered to applications format: date-time type: string - description: - description: A description of the identity. Part of the updatable - profile information of an identity - type: string - did: - description: The DID of the identity. Unique across namespaces - within a FireFly network - type: string id: - description: The UUID of the identity + description: The UUID assigned to this event by your local FireFly + node format: uuid type: string - messages: - description: References to the broadcast messages that established - this identity and proved ownership of the associated verifiers - (keys) - properties: - claim: - description: The UUID of claim message - format: uuid - type: string - update: - description: The UUID of the most recently applied update - message. Unset if no updates have been confirmed - format: uuid - type: string - verification: - description: The UUID of claim message. Unset for root organization - identities - format: uuid - type: string - type: object - name: - description: The name of the identity. The name must be unique - within the type and namespace - type: string namespace: - description: The namespace of the identity. Organization and - node identities are always defined in the ff_system namespace + description: The namespace of the event. Your application must + subscribe to events within a namespace type: string - parent: - description: The UUID of the parent identity. Unset for root - organization identities + reference: + description: The UUID of an resource that is the subject of + this event. The event type determines what type of resource + is referenced, and whether this field might be unset format: uuid type: string - profile: - additionalProperties: - description: A set of metadata for the identity. Part of the - updatable profile information of an identity - description: A set of metadata for the identity. Part of the - updatable profile information of an identity - type: object - type: - description: The type of the identity - enum: - - org - - node - - custom + sequence: + description: A sequence indicating the order in which events + are delivered to your application. Assure to be unique per + event in your local FireFly database (unlike the created timestamp) + format: int64 + type: integer + topic: + description: A stream of information this event relates to. + For message confirmation events, a separate event is emitted + for each topic in the message. For blockchain events, the + listener specifies the topic. Rules exist for how the topic + is set for other event types type: string - updated: - description: The last update time of the identity profile - format: date-time + tx: + description: The UUID of a transaction that is event is part + of. Not all events are part of a transaction + format: uuid + type: string + type: + description: All interesting activity in FireFly is emitted + as a FireFly event, of a given type. The 'type' combined with + the 'reference' can be used to determine how to process the + event within your application + enum: + - transaction_submitted + - message_confirmed + - message_rejected + - datatype_confirmed + - identity_confirmed + - identity_updated + - token_pool_confirmed + - token_pool_op_failed + - token_transfer_confirmed + - token_transfer_op_failed + - token_approval_confirmed + - token_approval_op_failed + - contract_interface_confirmed + - contract_api_confirmed + - blockchain_event_received + - blockchain_invoke_op_succeeded + - blockchain_invoke_op_failed + - blockchain_contract_deploy_op_succeeded + - blockchain_contract_deploy_op_failed type: string - verifiers: - description: The verifiers, such as blockchain signing keys, - that have been bound to this identity and can be used to prove - data orignates from that identity - items: - description: The verifiers, such as blockchain signing keys, - that have been bound to this identity and can be used to - prove data orignates from that identity - properties: - type: - description: The type of the verifier - enum: - - ethereum_address - - fabric_msp_id - - dx_peer_id - type: string - value: - description: The verifier string, such as an Ethereum - address, or Fabric MSP identifier - type: string - type: object - type: array type: object type: array description: Success @@ -7506,14 +7527,23 @@ paths: description: "" tags: - Default Namespace - post: - description: Registers a new identity in the network - operationId: postNewIdentity + /events/{eid}: + get: + description: Gets an event by its ID + operationId: getEventByID parameters: - - description: When true the HTTP request blocks until the message is confirmed + - description: The event ID + in: path + name: eid + required: true + schema: + type: string + - description: When set, the API will return the record that this item references + in its 'reference' field in: query - name: confirm + name: fetchreference schema: + example: "true" type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) @@ -7522,188 +7552,85 @@ paths: schema: default: 2m0s type: string - requestBody: - content: - application/json: - schema: - properties: - description: - description: A description of the identity. Part of the updatable - profile information of an identity - type: string - key: - description: The blockchain signing key to use to make the claim - to the identity. Must be available to the local node to sign the - identity claim. Will become a verifier on the established identity - type: string - name: - description: The name of the identity. The name must be unique within - the type and namespace - type: string - parent: - description: On input the parent can be specified directly as the - UUID of and existing identity, or as a DID to resolve to that - identity, or an organization name. The parent must already have - been registered, and its blockchain signing key must be available - to the local node to sign the verification - type: string - profile: - additionalProperties: - description: A set of metadata for the identity. Part of the updatable - profile information of an identity - description: A set of metadata for the identity. Part of the updatable - profile information of an identity - type: object - type: - description: The type of the identity - type: string - type: object responses: "200": content: application/json: schema: properties: + correlator: + description: For message events, this is the 'header.cid' field + from the referenced message. For certain other event types, + a secondary object is referenced such as a token pool + format: uuid + type: string created: - description: The creation time of the identity + description: The time the event was emitted. Not guaranteed to + be unique, or to increase between events in the same order as + the final sequence events are delivered to your application. + As such, the 'sequence' field should be used instead of the + 'created' field for querying events in the exact order they + are delivered to applications format: date-time type: string - description: - description: A description of the identity. Part of the updatable - profile information of an identity - type: string - did: - description: The DID of the identity. Unique across namespaces - within a FireFly network - type: string id: - description: The UUID of the identity + description: The UUID assigned to this event by your local FireFly + node format: uuid type: string - messages: - description: References to the broadcast messages that established - this identity and proved ownership of the associated verifiers - (keys) - properties: - claim: - description: The UUID of claim message - format: uuid - type: string - update: - description: The UUID of the most recently applied update - message. Unset if no updates have been confirmed - format: uuid - type: string - verification: - description: The UUID of claim message. Unset for root organization - identities - format: uuid - type: string - type: object - name: - description: The name of the identity. The name must be unique - within the type and namespace - type: string namespace: - description: The namespace of the identity. Organization and node - identities are always defined in the ff_system namespace + description: The namespace of the event. Your application must + subscribe to events within a namespace type: string - parent: - description: The UUID of the parent identity. Unset for root organization - identities + reference: + description: The UUID of an resource that is the subject of this + event. The event type determines what type of resource is referenced, + and whether this field might be unset + format: uuid + type: string + sequence: + description: A sequence indicating the order in which events are + delivered to your application. Assure to be unique per event + in your local FireFly database (unlike the created timestamp) + format: int64 + type: integer + topic: + description: A stream of information this event relates to. For + message confirmation events, a separate event is emitted for + each topic in the message. For blockchain events, the listener + specifies the topic. Rules exist for how the topic is set for + other event types + type: string + tx: + description: The UUID of a transaction that is event is part of. + Not all events are part of a transaction format: uuid type: string - profile: - additionalProperties: - description: A set of metadata for the identity. Part of the - updatable profile information of an identity - description: A set of metadata for the identity. Part of the updatable - profile information of an identity - type: object type: - description: The type of the identity + description: All interesting activity in FireFly is emitted as + a FireFly event, of a given type. The 'type' combined with the + 'reference' can be used to determine how to process the event + within your application enum: - - org - - node - - custom - type: string - updated: - description: The last update time of the identity profile - format: date-time - type: string - type: object - description: Success - "202": - content: - application/json: - schema: - properties: - created: - description: The creation time of the identity - format: date-time - type: string - description: - description: A description of the identity. Part of the updatable - profile information of an identity - type: string - did: - description: The DID of the identity. Unique across namespaces - within a FireFly network - type: string - id: - description: The UUID of the identity - format: uuid - type: string - messages: - description: References to the broadcast messages that established - this identity and proved ownership of the associated verifiers - (keys) - properties: - claim: - description: The UUID of claim message - format: uuid - type: string - update: - description: The UUID of the most recently applied update - message. Unset if no updates have been confirmed - format: uuid - type: string - verification: - description: The UUID of claim message. Unset for root organization - identities - format: uuid - type: string - type: object - name: - description: The name of the identity. The name must be unique - within the type and namespace - type: string - namespace: - description: The namespace of the identity. Organization and node - identities are always defined in the ff_system namespace - type: string - parent: - description: The UUID of the parent identity. Unset for root organization - identities - format: uuid - type: string - profile: - additionalProperties: - description: A set of metadata for the identity. Part of the - updatable profile information of an identity - description: A set of metadata for the identity. Part of the updatable - profile information of an identity - type: object - type: - description: The type of the identity - enum: - - org - - node - - custom - type: string - updated: - description: The last update time of the identity profile - format: date-time + - transaction_submitted + - message_confirmed + - message_rejected + - datatype_confirmed + - identity_confirmed + - identity_updated + - token_pool_confirmed + - token_pool_op_failed + - token_transfer_confirmed + - token_transfer_op_failed + - token_approval_confirmed + - token_approval_op_failed + - contract_interface_confirmed + - contract_api_confirmed + - blockchain_event_received + - blockchain_invoke_op_succeeded + - blockchain_invoke_op_failed + - blockchain_contract_deploy_op_succeeded + - blockchain_contract_deploy_op_failed type: string type: object description: Success @@ -7711,22 +7638,142 @@ paths: description: "" tags: - Default Namespace - /identities/{did}: + /groups: get: - description: Gets an identity by its DID - operationId: getIdentityByDID + description: Gets a list of groups + operationId: getGroups parameters: - - description: The identity DID - in: path - name: did - required: true + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout schema: + default: 2m0s type: string - - description: When set, the API will return the verifier for this identity + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: fetchverifiers + name: created + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: description + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: hash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: ledger + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: message + schema: + type: string + - description: Sort field. For multi-field sort use comma separated values (or + multiple query values) with '-' prefix for descending + in: query + name: sort + schema: + type: string + - description: Ascending sort order (overrides all fields in a multi-field sort) + in: query + name: ascending + schema: + type: string + - description: Descending sort order (overrides all fields in a multi-field + sort) + in: query + name: descending + schema: + type: string + - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk + operations' + in: query + name: skip + schema: + type: string + - description: 'The maximum number of records to return (max: 1,000)' + in: query + name: limit + schema: + example: "25" + type: string + - description: Return a total count as well as items (adds extra database processing) + in: query + name: count + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + properties: + created: + description: The time when the group was first used to send + a message in the network + format: date-time + type: string + hash: + description: The identifier hash of this group. Derived from + the name and group members + format: byte + type: string + localNamespace: + description: The local namespace of the group + type: string + members: + description: The list of members in this privacy group + items: + description: The list of members in this privacy group + properties: + identity: + description: The DID of the group member + type: string + node: + description: The UUID of the node that receives a copy + of the off-chain message for the identity + format: uuid + type: string + type: object + type: array + message: + description: The message used to broadcast this group privately + to the members + format: uuid + type: string + name: + description: The optional name of the group, allowing multiple + unique groups to exist with the same list of recipients + type: string + namespace: + description: The namespace of the group within the multiparty + network + type: string + type: object + type: array + description: Success + default: + description: "" + tags: + - Default Namespace + /groups/{hash}: + get: + description: Gets a group by its ID (hash) + operationId: getGroupByHash + parameters: + - description: The hash of the group + in: path + name: hash + required: true schema: - example: "true" type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) @@ -7742,112 +7789,58 @@ paths: schema: properties: created: - description: The creation time of the identity + description: The time when the group was first used to send a + message in the network format: date-time type: string - description: - description: A description of the identity. Part of the updatable - profile information of an identity + hash: + description: The identifier hash of this group. Derived from the + name and group members + format: byte type: string - did: - description: The DID of the identity. Unique across namespaces - within a FireFly network + localNamespace: + description: The local namespace of the group type: string - id: - description: The UUID of the identity + members: + description: The list of members in this privacy group + items: + description: The list of members in this privacy group + properties: + identity: + description: The DID of the group member + type: string + node: + description: The UUID of the node that receives a copy of + the off-chain message for the identity + format: uuid + type: string + type: object + type: array + message: + description: The message used to broadcast this group privately + to the members format: uuid type: string - messages: - description: References to the broadcast messages that established - this identity and proved ownership of the associated verifiers - (keys) - properties: - claim: - description: The UUID of claim message - format: uuid - type: string - update: - description: The UUID of the most recently applied update - message. Unset if no updates have been confirmed - format: uuid - type: string - verification: - description: The UUID of claim message. Unset for root organization - identities - format: uuid - type: string - type: object name: - description: The name of the identity. The name must be unique - within the type and namespace + description: The optional name of the group, allowing multiple + unique groups to exist with the same list of recipients type: string namespace: - description: The namespace of the identity. Organization and node - identities are always defined in the ff_system namespace - type: string - parent: - description: The UUID of the parent identity. Unset for root organization - identities - format: uuid - type: string - profile: - additionalProperties: - description: A set of metadata for the identity. Part of the - updatable profile information of an identity - description: A set of metadata for the identity. Part of the updatable - profile information of an identity - type: object - type: - description: The type of the identity - enum: - - org - - node - - custom - type: string - updated: - description: The last update time of the identity profile - format: date-time + description: The namespace of the group within the multiparty + network type: string - verifiers: - description: The verifiers, such as blockchain signing keys, that - have been bound to this identity and can be used to prove data - orignates from that identity - items: - description: The verifiers, such as blockchain signing keys, - that have been bound to this identity and can be used to prove - data orignates from that identity - properties: - type: - description: The type of the verifier - enum: - - ethereum_address - - fabric_msp_id - - dx_peer_id - type: string - value: - description: The verifier string, such as an Ethereum address, - or Fabric MSP identifier - type: string - type: object - type: array type: object description: Success default: description: "" tags: - Default Namespace - /identities/{iid}: + /identities: get: - description: Gets an identity by its ID - operationId: getIdentityByID + description: Gets a list of all identities that have been registered in the + namespace + operationId: getIdentities parameters: - - description: The identity ID, which is a UUID generated by FireFly - in: path - name: iid - required: true - schema: - example: id - type: string - description: When set, the API will return the verifier for this identity in: query name: fetchverifiers @@ -7861,386 +7854,54 @@ paths: schema: default: 2m0s type: string - responses: - "200": - content: - application/json: - schema: - properties: - created: - description: The creation time of the identity - format: date-time - type: string - description: - description: A description of the identity. Part of the updatable - profile information of an identity - type: string - did: - description: The DID of the identity. Unique across namespaces - within a FireFly network - type: string - id: - description: The UUID of the identity - format: uuid - type: string - messages: - description: References to the broadcast messages that established - this identity and proved ownership of the associated verifiers - (keys) - properties: - claim: - description: The UUID of claim message - format: uuid - type: string - update: - description: The UUID of the most recently applied update - message. Unset if no updates have been confirmed - format: uuid - type: string - verification: - description: The UUID of claim message. Unset for root organization - identities - format: uuid - type: string - type: object - name: - description: The name of the identity. The name must be unique - within the type and namespace - type: string - namespace: - description: The namespace of the identity. Organization and node - identities are always defined in the ff_system namespace - type: string - parent: - description: The UUID of the parent identity. Unset for root organization - identities - format: uuid - type: string - profile: - additionalProperties: - description: A set of metadata for the identity. Part of the - updatable profile information of an identity - description: A set of metadata for the identity. Part of the updatable - profile information of an identity - type: object - type: - description: The type of the identity - enum: - - org - - node - - custom - type: string - updated: - description: The last update time of the identity profile - format: date-time - type: string - type: object - description: Success - default: - description: "" - tags: - - Default Namespace - patch: - description: Updates an identity - operationId: patchUpdateIdentity - parameters: - - description: The identity ID, which is a UUID generated by FireFly - in: path - name: iid - required: true + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: created schema: type: string - - description: When true the HTTP request blocks until the message is confirmed + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: confirm + name: description schema: type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: did schema: - default: 2m0s type: string - requestBody: - content: - application/json: - schema: - properties: - description: - description: A description of the identity. Part of the updatable - profile information of an identity - type: string - profile: - additionalProperties: - description: A set of metadata for the identity. Part of the updatable - profile information of an identity - description: A set of metadata for the identity. Part of the updatable - profile information of an identity - type: object - type: object - responses: - "200": - content: - application/json: - schema: - properties: - created: - description: The creation time of the identity - format: date-time - type: string - description: - description: A description of the identity. Part of the updatable - profile information of an identity - type: string - did: - description: The DID of the identity. Unique across namespaces - within a FireFly network - type: string - id: - description: The UUID of the identity - format: uuid - type: string - messages: - description: References to the broadcast messages that established - this identity and proved ownership of the associated verifiers - (keys) - properties: - claim: - description: The UUID of claim message - format: uuid - type: string - update: - description: The UUID of the most recently applied update - message. Unset if no updates have been confirmed - format: uuid - type: string - verification: - description: The UUID of claim message. Unset for root organization - identities - format: uuid - type: string - type: object - name: - description: The name of the identity. The name must be unique - within the type and namespace - type: string - namespace: - description: The namespace of the identity. Organization and node - identities are always defined in the ff_system namespace - type: string - parent: - description: The UUID of the parent identity. Unset for root organization - identities - format: uuid - type: string - profile: - additionalProperties: - description: A set of metadata for the identity. Part of the - updatable profile information of an identity - description: A set of metadata for the identity. Part of the updatable - profile information of an identity - type: object - type: - description: The type of the identity - enum: - - org - - node - - custom - type: string - updated: - description: The last update time of the identity profile - format: date-time - type: string - type: object - description: Success - "202": - content: - application/json: - schema: - properties: - created: - description: The creation time of the identity - format: date-time - type: string - description: - description: A description of the identity. Part of the updatable - profile information of an identity - type: string - did: - description: The DID of the identity. Unique across namespaces - within a FireFly network - type: string - id: - description: The UUID of the identity - format: uuid - type: string - messages: - description: References to the broadcast messages that established - this identity and proved ownership of the associated verifiers - (keys) - properties: - claim: - description: The UUID of claim message - format: uuid - type: string - update: - description: The UUID of the most recently applied update - message. Unset if no updates have been confirmed - format: uuid - type: string - verification: - description: The UUID of claim message. Unset for root organization - identities - format: uuid - type: string - type: object - name: - description: The name of the identity. The name must be unique - within the type and namespace - type: string - namespace: - description: The namespace of the identity. Organization and node - identities are always defined in the ff_system namespace - type: string - parent: - description: The UUID of the parent identity. Unset for root organization - identities - format: uuid - type: string - profile: - additionalProperties: - description: A set of metadata for the identity. Part of the - updatable profile information of an identity - description: A set of metadata for the identity. Part of the updatable - profile information of an identity - type: object - type: - description: The type of the identity - enum: - - org - - node - - custom - type: string - updated: - description: The last update time of the identity profile - format: date-time - type: string - type: object - description: Success - default: - description: "" - tags: - - Default Namespace - /identities/{iid}/did: - get: - description: Gets the DID for an identity based on its ID - operationId: getIdentityDID - parameters: - - description: The identity ID, which is a UUID generated by FireFly - in: path - name: iid - required: true + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: id schema: - example: id type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: messages.claim schema: - default: 2m0s type: string - responses: - "200": - content: - application/json: - schema: - properties: - '@context': - description: See https://www.w3.org/TR/did-core/#json-ld - items: - description: See https://www.w3.org/TR/did-core/#json-ld - type: string - type: array - authentication: - description: See https://www.w3.org/TR/did-core/#did-document-properties - items: - description: See https://www.w3.org/TR/did-core/#did-document-properties - type: string - type: array - id: - description: See https://www.w3.org/TR/did-core/#did-document-properties - type: string - verificationMethod: - description: See https://www.w3.org/TR/did-core/#did-document-properties - items: - description: See https://www.w3.org/TR/did-core/#did-document-properties - properties: - blockchainAcountId: - description: For blockchains like Ethereum that represent - signing identities directly by their public key summarized - in an account string - type: string - controller: - description: See https://www.w3.org/TR/did-core/#service-properties - type: string - dataExchangePeerID: - description: A string provided by your Data Exchange plugin, - that it uses a technology specific mechanism to validate - against when messages arrive from this identity - type: string - id: - description: See https://www.w3.org/TR/did-core/#service-properties - type: string - mspIdentityString: - description: For Hyperledger Fabric where the signing identity - is represented by an MSP identifier (containing X509 certificate - DN strings) that were validated by your local MSP - type: string - type: - description: See https://www.w3.org/TR/did-core/#service-properties - type: string - type: object - type: array - type: object - description: Success - default: - description: "" - tags: - - Default Namespace - /identities/{iid}/verifiers: - get: - description: Gets the verifiers for an identity - operationId: getIdentityVerifiers - parameters: - - description: The identity ID, which is a UUID generated by FireFly - in: path - name: iid - required: true + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: messages.update schema: - example: id type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: messages.verification schema: - default: 2m0s type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: created + name: name schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: hash + name: parent schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: identity + name: profile schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' @@ -8250,7 +7911,7 @@ paths: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: value + name: updated schema: type: string - description: Sort field. For multi-field sort use comma separated values (or @@ -8295,34 +7956,94 @@ paths: items: properties: created: - description: The time this verifier was created on this node + description: The creation time of the identity format: date-time type: string - hash: - description: Hash used as a globally consistent identifier for - this namespace + type + value combination on every node in - the network - format: byte + description: + description: A description of the identity. Part of the updatable + profile information of an identity type: string - identity: - description: The UUID of the parent identity that has claimed - this verifier + did: + description: The DID of the identity. Unique across namespaces + within a FireFly network + type: string + id: + description: The UUID of the identity format: uuid type: string + messages: + description: References to the broadcast messages that established + this identity and proved ownership of the associated verifiers + (keys) + properties: + claim: + description: The UUID of claim message + format: uuid + type: string + update: + description: The UUID of the most recently applied update + message. Unset if no updates have been confirmed + format: uuid + type: string + verification: + description: The UUID of claim message. Unset for root organization + identities + format: uuid + type: string + type: object + name: + description: The name of the identity. The name must be unique + within the type and namespace + type: string namespace: - description: The namespace of the verifier + description: The namespace of the identity. Organization and + node identities are always defined in the ff_system namespace + type: string + parent: + description: The UUID of the parent identity. Unset for root + organization identities + format: uuid type: string + profile: + additionalProperties: + description: A set of metadata for the identity. Part of the + updatable profile information of an identity + description: A set of metadata for the identity. Part of the + updatable profile information of an identity + type: object type: - description: The type of the verifier + description: The type of the identity enum: - - ethereum_address - - fabric_msp_id - - dx_peer_id + - org + - node + - custom type: string - value: - description: The verifier string, such as an Ethereum address, - or Fabric MSP identifier + updated: + description: The last update time of the identity profile + format: date-time type: string + verifiers: + description: The verifiers, such as blockchain signing keys, + that have been bound to this identity and can be used to prove + data orignates from that identity + items: + description: The verifiers, such as blockchain signing keys, + that have been bound to this identity and can be used to + prove data orignates from that identity + properties: + type: + description: The type of the verifier + enum: + - ethereum_address + - fabric_msp_id + - dx_peer_id + type: string + value: + description: The verifier string, such as an Ethereum + address, or Fabric MSP identifier + type: string + type: object + type: array type: object type: array description: Success @@ -8330,14 +8051,13 @@ paths: description: "" tags: - Default Namespace - /messages: - get: - description: Gets a list of messages - operationId: getMsgs + post: + description: Registers a new identity in the network + operationId: postNewIdentity parameters: - - description: Fetch the data and include it in the messages returned + - description: When true the HTTP request blocks until the message is confirmed in: query - name: fetchdata + name: confirm schema: type: string - description: Server-side request timeout (milliseconds, or set a custom suffix @@ -8347,329 +8067,704 @@ paths: schema: default: 2m0s type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: author - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: batch + requestBody: + content: + application/json: + schema: + properties: + description: + description: A description of the identity. Part of the updatable + profile information of an identity + type: string + key: + description: The blockchain signing key to use to make the claim + to the identity. Must be available to the local node to sign the + identity claim. Will become a verifier on the established identity + type: string + name: + description: The name of the identity. The name must be unique within + the type and namespace + type: string + parent: + description: On input the parent can be specified directly as the + UUID of and existing identity, or as a DID to resolve to that + identity, or an organization name. The parent must already have + been registered, and its blockchain signing key must be available + to the local node to sign the verification + type: string + profile: + additionalProperties: + description: A set of metadata for the identity. Part of the updatable + profile information of an identity + description: A set of metadata for the identity. Part of the updatable + profile information of an identity + type: object + type: + description: The type of the identity + type: string + type: object + responses: + "200": + content: + application/json: + schema: + properties: + created: + description: The creation time of the identity + format: date-time + type: string + description: + description: A description of the identity. Part of the updatable + profile information of an identity + type: string + did: + description: The DID of the identity. Unique across namespaces + within a FireFly network + type: string + id: + description: The UUID of the identity + format: uuid + type: string + messages: + description: References to the broadcast messages that established + this identity and proved ownership of the associated verifiers + (keys) + properties: + claim: + description: The UUID of claim message + format: uuid + type: string + update: + description: The UUID of the most recently applied update + message. Unset if no updates have been confirmed + format: uuid + type: string + verification: + description: The UUID of claim message. Unset for root organization + identities + format: uuid + type: string + type: object + name: + description: The name of the identity. The name must be unique + within the type and namespace + type: string + namespace: + description: The namespace of the identity. Organization and node + identities are always defined in the ff_system namespace + type: string + parent: + description: The UUID of the parent identity. Unset for root organization + identities + format: uuid + type: string + profile: + additionalProperties: + description: A set of metadata for the identity. Part of the + updatable profile information of an identity + description: A set of metadata for the identity. Part of the updatable + profile information of an identity + type: object + type: + description: The type of the identity + enum: + - org + - node + - custom + type: string + updated: + description: The last update time of the identity profile + format: date-time + type: string + type: object + description: Success + "202": + content: + application/json: + schema: + properties: + created: + description: The creation time of the identity + format: date-time + type: string + description: + description: A description of the identity. Part of the updatable + profile information of an identity + type: string + did: + description: The DID of the identity. Unique across namespaces + within a FireFly network + type: string + id: + description: The UUID of the identity + format: uuid + type: string + messages: + description: References to the broadcast messages that established + this identity and proved ownership of the associated verifiers + (keys) + properties: + claim: + description: The UUID of claim message + format: uuid + type: string + update: + description: The UUID of the most recently applied update + message. Unset if no updates have been confirmed + format: uuid + type: string + verification: + description: The UUID of claim message. Unset for root organization + identities + format: uuid + type: string + type: object + name: + description: The name of the identity. The name must be unique + within the type and namespace + type: string + namespace: + description: The namespace of the identity. Organization and node + identities are always defined in the ff_system namespace + type: string + parent: + description: The UUID of the parent identity. Unset for root organization + identities + format: uuid + type: string + profile: + additionalProperties: + description: A set of metadata for the identity. Part of the + updatable profile information of an identity + description: A set of metadata for the identity. Part of the updatable + profile information of an identity + type: object + type: + description: The type of the identity + enum: + - org + - node + - custom + type: string + updated: + description: The last update time of the identity profile + format: date-time + type: string + type: object + description: Success + default: + description: "" + tags: + - Default Namespace + /identities/{did}: + get: + description: Gets an identity by its DID + operationId: getIdentityByDID + parameters: + - description: The identity DID + in: path + name: did + required: true schema: type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + - description: When set, the API will return the verifier for this identity in: query - name: cid + name: fetchverifiers schema: + example: "true" type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: confirmed + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout schema: + default: 2m0s type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: created - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: datahash - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: group - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: hash - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: id - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: idempotencykey + responses: + "200": + content: + application/json: + schema: + properties: + created: + description: The creation time of the identity + format: date-time + type: string + description: + description: A description of the identity. Part of the updatable + profile information of an identity + type: string + did: + description: The DID of the identity. Unique across namespaces + within a FireFly network + type: string + id: + description: The UUID of the identity + format: uuid + type: string + messages: + description: References to the broadcast messages that established + this identity and proved ownership of the associated verifiers + (keys) + properties: + claim: + description: The UUID of claim message + format: uuid + type: string + update: + description: The UUID of the most recently applied update + message. Unset if no updates have been confirmed + format: uuid + type: string + verification: + description: The UUID of claim message. Unset for root organization + identities + format: uuid + type: string + type: object + name: + description: The name of the identity. The name must be unique + within the type and namespace + type: string + namespace: + description: The namespace of the identity. Organization and node + identities are always defined in the ff_system namespace + type: string + parent: + description: The UUID of the parent identity. Unset for root organization + identities + format: uuid + type: string + profile: + additionalProperties: + description: A set of metadata for the identity. Part of the + updatable profile information of an identity + description: A set of metadata for the identity. Part of the updatable + profile information of an identity + type: object + type: + description: The type of the identity + enum: + - org + - node + - custom + type: string + updated: + description: The last update time of the identity profile + format: date-time + type: string + verifiers: + description: The verifiers, such as blockchain signing keys, that + have been bound to this identity and can be used to prove data + orignates from that identity + items: + description: The verifiers, such as blockchain signing keys, + that have been bound to this identity and can be used to prove + data orignates from that identity + properties: + type: + description: The type of the verifier + enum: + - ethereum_address + - fabric_msp_id + - dx_peer_id + type: string + value: + description: The verifier string, such as an Ethereum address, + or Fabric MSP identifier + type: string + type: object + type: array + type: object + description: Success + default: + description: "" + tags: + - Default Namespace + /identities/{iid}: + get: + description: Gets an identity by its ID + operationId: getIdentityByID + parameters: + - description: The identity ID, which is a UUID generated by FireFly + in: path + name: iid + required: true schema: + example: id type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + - description: When set, the API will return the verifier for this identity in: query - name: key + name: fetchverifiers schema: + example: "true" type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: pins + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout schema: + default: 2m0s type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: sequence + responses: + "200": + content: + application/json: + schema: + properties: + created: + description: The creation time of the identity + format: date-time + type: string + description: + description: A description of the identity. Part of the updatable + profile information of an identity + type: string + did: + description: The DID of the identity. Unique across namespaces + within a FireFly network + type: string + id: + description: The UUID of the identity + format: uuid + type: string + messages: + description: References to the broadcast messages that established + this identity and proved ownership of the associated verifiers + (keys) + properties: + claim: + description: The UUID of claim message + format: uuid + type: string + update: + description: The UUID of the most recently applied update + message. Unset if no updates have been confirmed + format: uuid + type: string + verification: + description: The UUID of claim message. Unset for root organization + identities + format: uuid + type: string + type: object + name: + description: The name of the identity. The name must be unique + within the type and namespace + type: string + namespace: + description: The namespace of the identity. Organization and node + identities are always defined in the ff_system namespace + type: string + parent: + description: The UUID of the parent identity. Unset for root organization + identities + format: uuid + type: string + profile: + additionalProperties: + description: A set of metadata for the identity. Part of the + updatable profile information of an identity + description: A set of metadata for the identity. Part of the updatable + profile information of an identity + type: object + type: + description: The type of the identity + enum: + - org + - node + - custom + type: string + updated: + description: The last update time of the identity profile + format: date-time + type: string + type: object + description: Success + default: + description: "" + tags: + - Default Namespace + patch: + description: Updates an identity + operationId: patchUpdateIdentity + parameters: + - description: The identity ID, which is a UUID generated by FireFly + in: path + name: iid + required: true schema: type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + - description: When true the HTTP request blocks until the message is confirmed in: query - name: state + name: confirm schema: type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: tag + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout schema: + default: 2m0s type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: topics - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txid - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txparent.id - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txparent.type - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: txtype - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: type - schema: - type: string - - description: Sort field. For multi-field sort use comma separated values (or - multiple query values) with '-' prefix for descending - in: query - name: sort - schema: - type: string - - description: Ascending sort order (overrides all fields in a multi-field sort) - in: query - name: ascending - schema: - type: string - - description: Descending sort order (overrides all fields in a multi-field - sort) - in: query - name: descending - schema: - type: string - - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk - operations' - in: query - name: skip - schema: - type: string - - description: 'The maximum number of records to return (max: 1,000)' - in: query - name: limit + requestBody: + content: + application/json: + schema: + properties: + description: + description: A description of the identity. Part of the updatable + profile information of an identity + type: string + profile: + additionalProperties: + description: A set of metadata for the identity. Part of the updatable + profile information of an identity + description: A set of metadata for the identity. Part of the updatable + profile information of an identity + type: object + type: object + responses: + "200": + content: + application/json: + schema: + properties: + created: + description: The creation time of the identity + format: date-time + type: string + description: + description: A description of the identity. Part of the updatable + profile information of an identity + type: string + did: + description: The DID of the identity. Unique across namespaces + within a FireFly network + type: string + id: + description: The UUID of the identity + format: uuid + type: string + messages: + description: References to the broadcast messages that established + this identity and proved ownership of the associated verifiers + (keys) + properties: + claim: + description: The UUID of claim message + format: uuid + type: string + update: + description: The UUID of the most recently applied update + message. Unset if no updates have been confirmed + format: uuid + type: string + verification: + description: The UUID of claim message. Unset for root organization + identities + format: uuid + type: string + type: object + name: + description: The name of the identity. The name must be unique + within the type and namespace + type: string + namespace: + description: The namespace of the identity. Organization and node + identities are always defined in the ff_system namespace + type: string + parent: + description: The UUID of the parent identity. Unset for root organization + identities + format: uuid + type: string + profile: + additionalProperties: + description: A set of metadata for the identity. Part of the + updatable profile information of an identity + description: A set of metadata for the identity. Part of the updatable + profile information of an identity + type: object + type: + description: The type of the identity + enum: + - org + - node + - custom + type: string + updated: + description: The last update time of the identity profile + format: date-time + type: string + type: object + description: Success + "202": + content: + application/json: + schema: + properties: + created: + description: The creation time of the identity + format: date-time + type: string + description: + description: A description of the identity. Part of the updatable + profile information of an identity + type: string + did: + description: The DID of the identity. Unique across namespaces + within a FireFly network + type: string + id: + description: The UUID of the identity + format: uuid + type: string + messages: + description: References to the broadcast messages that established + this identity and proved ownership of the associated verifiers + (keys) + properties: + claim: + description: The UUID of claim message + format: uuid + type: string + update: + description: The UUID of the most recently applied update + message. Unset if no updates have been confirmed + format: uuid + type: string + verification: + description: The UUID of claim message. Unset for root organization + identities + format: uuid + type: string + type: object + name: + description: The name of the identity. The name must be unique + within the type and namespace + type: string + namespace: + description: The namespace of the identity. Organization and node + identities are always defined in the ff_system namespace + type: string + parent: + description: The UUID of the parent identity. Unset for root organization + identities + format: uuid + type: string + profile: + additionalProperties: + description: A set of metadata for the identity. Part of the + updatable profile information of an identity + description: A set of metadata for the identity. Part of the updatable + profile information of an identity + type: object + type: + description: The type of the identity + enum: + - org + - node + - custom + type: string + updated: + description: The last update time of the identity profile + format: date-time + type: string + type: object + description: Success + default: + description: "" + tags: + - Default Namespace + /identities/{iid}/did: + get: + description: Gets the DID for an identity based on its ID + operationId: getIdentityDID + parameters: + - description: The identity ID, which is a UUID generated by FireFly + in: path + name: iid + required: true schema: - example: "25" + example: id type: string - - description: Return a total count as well as items (adds extra database processing) - in: query - name: count + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout schema: + default: 2m0s type: string responses: "200": content: application/json: schema: - items: - properties: - batch: - description: The UUID of the batch in which the message was - pinned/transferred - format: uuid + properties: + '@context': + description: See https://www.w3.org/TR/did-core/#json-ld + items: + description: See https://www.w3.org/TR/did-core/#json-ld type: string - confirmed: - description: The timestamp of when the message was confirmed/rejected - format: date-time - type: string - data: - description: The list of data elements attached to the message - items: - description: The list of data elements attached to the message - properties: - hash: - description: The hash of the referenced data - format: byte - type: string - id: - description: The UUID of the referenced data resource - format: uuid - type: string - type: object - type: array - hash: - description: The hash of the message. Derived from the header, - which includes the data hash - format: byte + type: array + authentication: + description: See https://www.w3.org/TR/did-core/#did-document-properties + items: + description: See https://www.w3.org/TR/did-core/#did-document-properties type: string - header: - description: The message header contains all fields that are - used to build the message hash + type: array + id: + description: See https://www.w3.org/TR/did-core/#did-document-properties + type: string + verificationMethod: + description: See https://www.w3.org/TR/did-core/#did-document-properties + items: + description: See https://www.w3.org/TR/did-core/#did-document-properties properties: - author: - description: The DID of identity of the submitter - type: string - cid: - description: The correlation ID of the message. Set this - when a message is a response to another message - format: uuid - type: string - created: - description: The creation time of the message - format: date-time + blockchainAcountId: + description: For blockchains like Ethereum that represent + signing identities directly by their public key summarized + in an account string type: string - datahash: - description: A single hash representing all data in the - message. Derived from the array of data ids+hashes attached - to this message - format: byte + controller: + description: See https://www.w3.org/TR/did-core/#service-properties type: string - group: - description: Private messages only - the identifier hash - of the privacy group. Derived from the name and member - list of the group - format: byte + dataExchangePeerID: + description: A string provided by your Data Exchange plugin, + that it uses a technology specific mechanism to validate + against when messages arrive from this identity type: string id: - description: The UUID of the message. Unique to each message - format: uuid - type: string - key: - description: The on-chain signing key used to sign the transaction - type: string - namespace: - description: The namespace of the message within the multiparty - network - type: string - tag: - description: The message tag indicates the purpose of the - message to the applications that process it + description: See https://www.w3.org/TR/did-core/#service-properties type: string - topics: - description: A message topic associates this message with - an ordered stream of data. A custom topic should be assigned - - using the default topic is discouraged - items: - description: A message topic associates this message with - an ordered stream of data. A custom topic should be - assigned - using the default topic is discouraged - type: string - type: array - txparent: - description: The parent transaction that originally triggered - this message - properties: - id: - description: The UUID of the FireFly transaction - format: uuid - type: string - type: - description: The type of the FireFly transaction - type: string - type: object - txtype: - description: The type of transaction used to order/deliver - this message - enum: - - none - - unpinned - - batch_pin - - network_action - - token_pool - - token_transfer - - contract_deploy - - contract_invoke - - contract_invoke_pin - - token_approval - - data_publish + mspIdentityString: + description: For Hyperledger Fabric where the signing identity + is represented by an MSP identifier (containing X509 certificate + DN strings) that were validated by your local MSP type: string type: - description: The type of the message - enum: - - definition - - broadcast - - private - - groupinit - - transfer_broadcast - - transfer_private - - approval_broadcast - - approval_private + description: See https://www.w3.org/TR/did-core/#service-properties type: string type: object - idempotencyKey: - description: An optional unique identifier for a message. Cannot - be duplicated within a namespace, thus allowing idempotent - submission of messages to the API. Local only - not transferred - when the message is sent to other members of the network - type: string - localNamespace: - description: The local namespace of the message - type: string - pins: - description: For private messages, a unique pin hash:nonce is - assigned for each topic - items: - description: For private messages, a unique pin hash:nonce - is assigned for each topic - type: string - type: array - state: - description: The current state of the message - enum: - - staged - - ready - - sent - - pending - - confirmed - - rejected - type: string - txid: - description: The ID of the transaction used to order/deliver - this message - format: uuid - type: string - type: object - type: array + type: array + type: object description: Success default: description: "" tags: - Default Namespace - /messages/{msgid}: + /identities/{iid}/verifiers: get: - description: Gets a message by its ID - operationId: getMsgByID + description: Gets the verifiers for an identity + operationId: getIdentityVerifiers parameters: - - description: The message ID + - description: The identity ID, which is a UUID generated by FireFly in: path - name: msgid + name: iid required: true schema: - type: string - - description: Fetch the data and include it in the messages returned - in: query - name: fetchdata - schema: + example: id type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) @@ -8678,23 +8773,473 @@ paths: schema: default: 2m0s type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: created + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: hash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: identity + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: type + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: value + schema: + type: string + - description: Sort field. For multi-field sort use comma separated values (or + multiple query values) with '-' prefix for descending + in: query + name: sort + schema: + type: string + - description: Ascending sort order (overrides all fields in a multi-field sort) + in: query + name: ascending + schema: + type: string + - description: Descending sort order (overrides all fields in a multi-field + sort) + in: query + name: descending + schema: + type: string + - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk + operations' + in: query + name: skip + schema: + type: string + - description: 'The maximum number of records to return (max: 1,000)' + in: query + name: limit + schema: + example: "25" + type: string + - description: Return a total count as well as items (adds extra database processing) + in: query + name: count + schema: + type: string responses: "200": content: application/json: schema: - properties: - batch: - description: The UUID of the batch in which the message was pinned/transferred - format: uuid - type: string - confirmed: - description: The timestamp of when the message was confirmed/rejected - format: date-time - type: string - data: - description: For input allows you to specify data in-line in the - message, that will be turned into data attachments. For output + items: + properties: + created: + description: The time this verifier was created on this node + format: date-time + type: string + hash: + description: Hash used as a globally consistent identifier for + this namespace + type + value combination on every node in + the network + format: byte + type: string + identity: + description: The UUID of the parent identity that has claimed + this verifier + format: uuid + type: string + namespace: + description: The namespace of the verifier + type: string + type: + description: The type of the verifier + enum: + - ethereum_address + - fabric_msp_id + - dx_peer_id + type: string + value: + description: The verifier string, such as an Ethereum address, + or Fabric MSP identifier + type: string + type: object + type: array + description: Success + default: + description: "" + tags: + - Default Namespace + /messages: + get: + description: Gets a list of messages + operationId: getMsgs + parameters: + - description: Fetch the data and include it in the messages returned + in: query + name: fetchdata + schema: + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: author + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: batch + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: cid + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: confirmed + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: created + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: datahash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: group + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: hash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: id + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: idempotencykey + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: key + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: pins + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: sequence + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: state + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: tag + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: topics + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txid + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txparent.id + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txparent.type + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: txtype + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: type + schema: + type: string + - description: Sort field. For multi-field sort use comma separated values (or + multiple query values) with '-' prefix for descending + in: query + name: sort + schema: + type: string + - description: Ascending sort order (overrides all fields in a multi-field sort) + in: query + name: ascending + schema: + type: string + - description: Descending sort order (overrides all fields in a multi-field + sort) + in: query + name: descending + schema: + type: string + - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk + operations' + in: query + name: skip + schema: + type: string + - description: 'The maximum number of records to return (max: 1,000)' + in: query + name: limit + schema: + example: "25" + type: string + - description: Return a total count as well as items (adds extra database processing) + in: query + name: count + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + properties: + batch: + description: The UUID of the batch in which the message was + pinned/transferred + format: uuid + type: string + confirmed: + description: The timestamp of when the message was confirmed/rejected + format: date-time + type: string + data: + description: The list of data elements attached to the message + items: + description: The list of data elements attached to the message + properties: + hash: + description: The hash of the referenced data + format: byte + type: string + id: + description: The UUID of the referenced data resource + format: uuid + type: string + type: object + type: array + hash: + description: The hash of the message. Derived from the header, + which includes the data hash + format: byte + type: string + header: + description: The message header contains all fields that are + used to build the message hash + properties: + author: + description: The DID of identity of the submitter + type: string + cid: + description: The correlation ID of the message. Set this + when a message is a response to another message + format: uuid + type: string + created: + description: The creation time of the message + format: date-time + type: string + datahash: + description: A single hash representing all data in the + message. Derived from the array of data ids+hashes attached + to this message + format: byte + type: string + group: + description: Private messages only - the identifier hash + of the privacy group. Derived from the name and member + list of the group + format: byte + type: string + id: + description: The UUID of the message. Unique to each message + format: uuid + type: string + key: + description: The on-chain signing key used to sign the transaction + type: string + namespace: + description: The namespace of the message within the multiparty + network + type: string + tag: + description: The message tag indicates the purpose of the + message to the applications that process it + type: string + topics: + description: A message topic associates this message with + an ordered stream of data. A custom topic should be assigned + - using the default topic is discouraged + items: + description: A message topic associates this message with + an ordered stream of data. A custom topic should be + assigned - using the default topic is discouraged + type: string + type: array + txparent: + description: The parent transaction that originally triggered + this message + properties: + id: + description: The UUID of the FireFly transaction + format: uuid + type: string + type: + description: The type of the FireFly transaction + type: string + type: object + txtype: + description: The type of transaction used to order/deliver + this message + enum: + - none + - unpinned + - batch_pin + - network_action + - token_pool + - token_transfer + - contract_deploy + - contract_invoke + - contract_invoke_pin + - token_approval + - data_publish + type: string + type: + description: The type of the message + enum: + - definition + - broadcast + - private + - groupinit + - transfer_broadcast + - transfer_private + - approval_broadcast + - approval_private + type: string + type: object + idempotencyKey: + description: An optional unique identifier for a message. Cannot + be duplicated within a namespace, thus allowing idempotent + submission of messages to the API. Local only - not transferred + when the message is sent to other members of the network + type: string + localNamespace: + description: The local namespace of the message + type: string + pins: + description: For private messages, a unique pin hash:nonce is + assigned for each topic + items: + description: For private messages, a unique pin hash:nonce + is assigned for each topic + type: string + type: array + state: + description: The current state of the message + enum: + - staged + - ready + - sent + - pending + - confirmed + - rejected + type: string + txid: + description: The ID of the transaction used to order/deliver + this message + format: uuid + type: string + type: object + type: array + description: Success + default: + description: "" + tags: + - Default Namespace + /messages/{msgid}: + get: + description: Gets a message by its ID + operationId: getMsgByID + parameters: + - description: The message ID + in: path + name: msgid + required: true + schema: + type: string + - description: Fetch the data and include it in the messages returned + in: query + name: fetchdata + schema: + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + responses: + "200": + content: + application/json: + schema: + properties: + batch: + description: The UUID of the batch in which the message was pinned/transferred + format: uuid + type: string + confirmed: + description: The timestamp of when the message was confirmed/rejected + format: date-time + type: string + data: + description: For input allows you to specify data in-line in the + message, that will be turned into data attachments. For output when fetchdata is used on API calls, includes the in-line data payloads of all data attachments items: @@ -11333,11 +11878,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning @@ -12807,37 +13353,297 @@ paths: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: created + name: created + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: group + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: hash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: id + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: key + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: node + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: payloadref + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: tx.id + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: tx.type + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: type + schema: + type: string + - description: Sort field. For multi-field sort use comma separated values (or + multiple query values) with '-' prefix for descending + in: query + name: sort + schema: + type: string + - description: Ascending sort order (overrides all fields in a multi-field sort) + in: query + name: ascending + schema: + type: string + - description: Descending sort order (overrides all fields in a multi-field + sort) + in: query + name: descending + schema: + type: string + - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk + operations' + in: query + name: skip + schema: + type: string + - description: 'The maximum number of records to return (max: 1,000)' + in: query + name: limit + schema: + example: "25" + type: string + - description: Return a total count as well as items (adds extra database processing) + in: query + name: count + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + properties: + author: + description: The DID of identity of the submitter + type: string + confirmed: + description: The time when the batch was confirmed + format: date-time + type: string + created: + description: The time the batch was sealed + format: date-time + type: string + group: + description: The privacy group the batch is sent to, for private + batches + format: byte + type: string + hash: + description: The hash of the manifest of the batch + format: byte + type: string + id: + description: The UUID of the batch + format: uuid + type: string + key: + description: The on-chain signing key used to sign the transaction + type: string + manifest: + description: The manifest of the batch + namespace: + description: The namespace of the batch + type: string + node: + description: The UUID of the node that generated the batch + format: uuid + type: string + tx: + description: The FireFly transaction associated with this batch + properties: + id: + description: The UUID of the FireFly transaction + format: uuid + type: string + type: + description: The type of the FireFly transaction + type: string + type: object + type: + description: The type of the batch + enum: + - broadcast + - private + type: string + type: object + type: array + description: Success + default: + description: "" + tags: + - Non-Default Namespace + /namespaces/{ns}/batches/{batchid}: + get: + description: Gets a message batch + operationId: getBatchByIDNamespace + parameters: + - description: The batch ID + in: path + name: batchid + required: true + schema: + type: string + - description: The namespace which scopes this request + in: path + name: ns + required: true + schema: + example: default + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + responses: + "200": + content: + application/json: + schema: + properties: + author: + description: The DID of identity of the submitter + type: string + confirmed: + description: The time when the batch was confirmed + format: date-time + type: string + created: + description: The time the batch was sealed + format: date-time + type: string + group: + description: The privacy group the batch is sent to, for private + batches + format: byte + type: string + hash: + description: The hash of the manifest of the batch + format: byte + type: string + id: + description: The UUID of the batch + format: uuid + type: string + key: + description: The on-chain signing key used to sign the transaction + type: string + manifest: + description: The manifest of the batch + namespace: + description: The namespace of the batch + type: string + node: + description: The UUID of the node that generated the batch + format: uuid + type: string + tx: + description: The FireFly transaction associated with this batch + properties: + id: + description: The UUID of the FireFly transaction + format: uuid + type: string + type: + description: The type of the FireFly transaction + type: string + type: object + type: + description: The type of the batch + enum: + - broadcast + - private + type: string + type: object + description: Success + default: + description: "" + tags: + - Non-Default Namespace + /namespaces/{ns}/blockchainevents: + get: + description: Gets a list of blockchain events + operationId: getBlockchainEventsNamespace + parameters: + - description: The namespace which scopes this request + in: path + name: ns + required: true + schema: + example: default + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: id schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: group + name: listener schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: hash + name: name schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: id + name: protocolid schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: key + name: source schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: node + name: timestamp schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: payloadref + name: tx.blockchainid schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' @@ -12850,11 +13656,6 @@ paths: name: tx.type schema: type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: type - schema: - type: string - description: Sort field. For multi-field sort use comma separated values (or multiple query values) with '-' prefix for descending in: query @@ -12896,59 +13697,251 @@ paths: schema: items: properties: - author: - description: The DID of identity of the submitter - type: string - confirmed: - description: The time when the batch was confirmed - format: date-time + id: + description: The UUID assigned to the event by FireFly + format: uuid type: string - created: - description: The time the batch was sealed - format: date-time + info: + additionalProperties: + description: Detailed blockchain specific information about + the event, as generated by the blockchain connector + description: Detailed blockchain specific information about + the event, as generated by the blockchain connector + type: object + listener: + description: The UUID of the listener that detected this event, + or nil for built-in events in the system namespace + format: uuid type: string - group: - description: The privacy group the batch is sent to, for private - batches - format: byte + name: + description: The name of the event in the blockchain smart contract type: string - hash: - description: The hash of the manifest of the batch - format: byte + namespace: + description: The namespace of the listener that detected this + blockchain event type: string - id: - description: The UUID of the batch - format: uuid + output: + additionalProperties: + description: The data output by the event, parsed to JSON + according to the interface of the smart contract + description: The data output by the event, parsed to JSON according + to the interface of the smart contract + type: object + protocolId: + description: An alphanumerically sortable string that represents + this event uniquely on the blockchain (convention for plugins + is zero-padded values BLOCKNUMBER/TXN_INDEX/EVENT_INDEX) type: string - key: - description: The on-chain signing key used to sign the transaction + source: + description: The blockchain plugin or token service that detected + the event type: string - manifest: - description: The manifest of the batch - namespace: - description: The namespace of the batch + timestamp: + description: The time allocated to this event by the blockchain. + This is the block timestamp for most blockchain connectors + format: date-time type: string - node: - description: The UUID of the node that generated the batch - format: uuid + tx: + description: If this blockchain event is coorelated to FireFly + transaction such as a FireFly submitted token transfer, this + field is set to the UUID of the FireFly transaction + properties: + blockchainId: + description: The blockchain transaction ID, in the format + specific to the blockchain involved in the transaction. + Not all FireFly transactions include a blockchain + type: string + id: + description: The UUID of the FireFly transaction + format: uuid + type: string + type: + description: The type of the FireFly transaction + type: string + type: object + type: object + type: array + description: Success + default: + description: "" + tags: + - Non-Default Namespace + /namespaces/{ns}/blockchainevents/{id}: + get: + description: Gets a blockchain event + operationId: getBlockchainEventByIDNamespace + parameters: + - description: The blockchain event ID + in: path + name: id + required: true + schema: + type: string + - description: The namespace which scopes this request + in: path + name: ns + required: true + schema: + example: default + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + responses: + "200": + content: + application/json: + schema: + properties: + id: + description: The UUID assigned to the event by FireFly + format: uuid + type: string + info: + additionalProperties: + description: Detailed blockchain specific information about + the event, as generated by the blockchain connector + description: Detailed blockchain specific information about the + event, as generated by the blockchain connector + type: object + listener: + description: The UUID of the listener that detected this event, + or nil for built-in events in the system namespace + format: uuid + type: string + name: + description: The name of the event in the blockchain smart contract + type: string + namespace: + description: The namespace of the listener that detected this + blockchain event + type: string + output: + additionalProperties: + description: The data output by the event, parsed to JSON according + to the interface of the smart contract + description: The data output by the event, parsed to JSON according + to the interface of the smart contract + type: object + protocolId: + description: An alphanumerically sortable string that represents + this event uniquely on the blockchain (convention for plugins + is zero-padded values BLOCKNUMBER/TXN_INDEX/EVENT_INDEX) + type: string + source: + description: The blockchain plugin or token service that detected + the event + type: string + timestamp: + description: The time allocated to this event by the blockchain. + This is the block timestamp for most blockchain connectors + format: date-time + type: string + tx: + description: If this blockchain event is coorelated to FireFly + transaction such as a FireFly submitted token transfer, this + field is set to the UUID of the FireFly transaction + properties: + blockchainId: + description: The blockchain transaction ID, in the format + specific to the blockchain involved in the transaction. + Not all FireFly transactions include a blockchain + type: string + id: + description: The UUID of the FireFly transaction + format: uuid + type: string + type: + description: The type of the FireFly transaction + type: string + type: object + type: object + description: Success + default: + description: "" + tags: + - Non-Default Namespace + /namespaces/{ns}/charts/histogram/{collection}: + get: + description: Gets a JSON object containing statistics data that can be used + to build a graphical representation of recent activity in a given database + collection + operationId: getChartHistogramNamespace + parameters: + - description: The collection ID + in: path + name: collection + required: true + schema: + type: string + - description: The namespace which scopes this request + in: path + name: ns + required: true + schema: + example: default + type: string + - description: Start time of the data to be fetched + in: query + name: startTime + schema: + type: string + - description: End time of the data to be fetched + in: query + name: endTime + schema: + type: string + - description: Number of buckets between start time and end time + in: query + name: buckets + schema: + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + responses: + "200": + content: + application/json: + schema: + items: + properties: + count: + description: Total count of entries in this time bucket within + the histogram type: string - tx: - description: The FireFly transaction associated with this batch - properties: - id: - description: The UUID of the FireFly transaction - format: uuid - type: string - type: - description: The type of the FireFly transaction - type: string - type: object - type: - description: The type of the batch - enum: - - broadcast - - private + isCapped: + description: Indicates whether there are more results in this + bucket that are not being displayed + type: boolean + timestamp: + description: Starting timestamp for the bucket + format: date-time type: string + types: + description: Array of separate counts for individual types of + record within the bucket + items: + description: Array of separate counts for individual types + of record within the bucket + properties: + count: + description: Count of entries of a given type within a + bucket + type: string + type: + description: Name of the type + type: string + type: object + type: array type: object type: array description: Success @@ -12956,17 +13949,11 @@ paths: description: "" tags: - Non-Default Namespace - /namespaces/{ns}/batches/{batchid}: - get: - description: Gets a message batch - operationId: getBatchByIDNamespace + /namespaces/{ns}/contracts/deploy: + post: + description: Deploy a new smart contract + operationId: postContractDeployNamespace parameters: - - description: The batch ID - in: path - name: batchid - required: true - schema: - type: string - description: The namespace which scopes this request in: path name: ns @@ -12974,6 +13961,12 @@ paths: schema: example: default type: string + - description: When true the HTTP request blocks until the message is confirmed + in: query + name: confirm + schema: + example: "true" + type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) in: header @@ -12981,64 +13974,186 @@ paths: schema: default: 2m0s type: string + requestBody: + content: + application/json: + schema: + properties: + contract: + description: The smart contract to deploy. This should be pre-compiled + if required by the blockchain connector + definition: + description: The definition of the smart contract + idempotencyKey: + description: An optional identifier to allow idempotent submission + of requests. Stored on the transaction uniquely within a namespace + type: string + input: + description: An optional array of inputs passed to the smart contract's + constructor, if applicable + items: + description: An optional array of inputs passed to the smart contract's + constructor, if applicable + type: array + key: + description: The blockchain signing key that will be used to deploy + the contract. Defaults to the first signing key of the organization + that operates the node + type: string + options: + additionalProperties: + description: A map of named inputs that will be passed through + to the blockchain connector + description: A map of named inputs that will be passed through to + the blockchain connector + type: object + type: object responses: "200": content: application/json: schema: properties: - author: - description: The DID of identity of the submitter + created: + description: The time the operation was created + format: date-time type: string - confirmed: - description: The time when the batch was confirmed + error: + description: Any error reported back from the plugin for this + operation + type: string + id: + description: The UUID of the operation + format: uuid + type: string + input: + additionalProperties: + description: The input to this operation + description: The input to this operation + type: object + namespace: + description: The namespace of the operation + type: string + output: + additionalProperties: + description: Any output reported back from the plugin for this + operation + description: Any output reported back from the plugin for this + operation + type: object + plugin: + description: The plugin responsible for performing the operation + type: string + retry: + description: If this operation was initiated as a retry to a previous + operation, this field points to the UUID of the operation being + retried + format: uuid + type: string + status: + description: The current status of the operation + type: string + tx: + description: The UUID of the FireFly transaction the operation + is part of + format: uuid + type: string + type: + description: The type of the operation + enum: + - blockchain_pin_batch + - blockchain_network_action + - blockchain_deploy + - blockchain_invoke + - sharedstorage_upload_batch + - sharedstorage_upload_blob + - sharedstorage_upload_value + - sharedstorage_download_batch + - sharedstorage_download_blob + - dataexchange_send_batch + - dataexchange_send_blob + - token_create_pool + - token_activate_pool + - token_transfer + - token_approval + type: string + updated: + description: The last update time of the operation format: date-time type: string + type: object + description: Success + "202": + content: + application/json: + schema: + properties: created: - description: The time the batch was sealed + description: The time the operation was created format: date-time type: string - group: - description: The privacy group the batch is sent to, for private - batches - format: byte - type: string - hash: - description: The hash of the manifest of the batch - format: byte + error: + description: Any error reported back from the plugin for this + operation type: string id: - description: The UUID of the batch + description: The UUID of the operation format: uuid type: string - key: - description: The on-chain signing key used to sign the transaction - type: string - manifest: - description: The manifest of the batch + input: + additionalProperties: + description: The input to this operation + description: The input to this operation + type: object namespace: - description: The namespace of the batch + description: The namespace of the operation type: string - node: - description: The UUID of the node that generated the batch + output: + additionalProperties: + description: Any output reported back from the plugin for this + operation + description: Any output reported back from the plugin for this + operation + type: object + plugin: + description: The plugin responsible for performing the operation + type: string + retry: + description: If this operation was initiated as a retry to a previous + operation, this field points to the UUID of the operation being + retried format: uuid type: string + status: + description: The current status of the operation + type: string tx: - description: The FireFly transaction associated with this batch - properties: - id: - description: The UUID of the FireFly transaction - format: uuid - type: string - type: - description: The type of the FireFly transaction - type: string - type: object + description: The UUID of the FireFly transaction the operation + is part of + format: uuid + type: string type: - description: The type of the batch + description: The type of the operation enum: - - broadcast - - private + - blockchain_pin_batch + - blockchain_network_action + - blockchain_deploy + - blockchain_invoke + - sharedstorage_upload_batch + - sharedstorage_upload_blob + - sharedstorage_upload_value + - sharedstorage_download_batch + - sharedstorage_download_blob + - dataexchange_send_batch + - dataexchange_send_blob + - token_create_pool + - token_activate_pool + - token_transfer + - token_approval + type: string + updated: + description: The last update time of the operation + format: date-time type: string type: object description: Success @@ -13046,10 +14161,10 @@ paths: description: "" tags: - Non-Default Namespace - /namespaces/{ns}/blockchainevents: + /namespaces/{ns}/contracts/interfaces: get: - description: Gets a list of blockchain events - operationId: getBlockchainEventsNamespace + description: Gets a list of contract interfaces that have been published + operationId: getContractInterfacesNamespace parameters: - description: The namespace which scopes this request in: path @@ -13070,11 +14185,6 @@ paths: name: id schema: type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: listener - schema: - type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query name: name @@ -13082,32 +14192,17 @@ paths: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: protocolid - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: source - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: timestamp - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: tx.blockchainid + name: networkname schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: tx.id + name: published schema: type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query - name: tx.type + name: version schema: type: string - description: Sort field. For multi-field sort use comma separated values (or @@ -13116,250 +14211,33 @@ paths: name: sort schema: type: string - - description: Ascending sort order (overrides all fields in a multi-field sort) - in: query - name: ascending - schema: - type: string - - description: Descending sort order (overrides all fields in a multi-field - sort) - in: query - name: descending - schema: - type: string - - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk - operations' - in: query - name: skip - schema: - type: string - - description: 'The maximum number of records to return (max: 1,000)' - in: query - name: limit - schema: - example: "25" - type: string - - description: Return a total count as well as items (adds extra database processing) - in: query - name: count - schema: - type: string - responses: - "200": - content: - application/json: - schema: - items: - properties: - id: - description: The UUID assigned to the event by FireFly - format: uuid - type: string - info: - additionalProperties: - description: Detailed blockchain specific information about - the event, as generated by the blockchain connector - description: Detailed blockchain specific information about - the event, as generated by the blockchain connector - type: object - listener: - description: The UUID of the listener that detected this event, - or nil for built-in events in the system namespace - format: uuid - type: string - name: - description: The name of the event in the blockchain smart contract - type: string - namespace: - description: The namespace of the listener that detected this - blockchain event - type: string - output: - additionalProperties: - description: The data output by the event, parsed to JSON - according to the interface of the smart contract - description: The data output by the event, parsed to JSON according - to the interface of the smart contract - type: object - protocolId: - description: An alphanumerically sortable string that represents - this event uniquely on the blockchain (convention for plugins - is zero-padded values BLOCKNUMBER/TXN_INDEX/EVENT_INDEX) - type: string - source: - description: The blockchain plugin or token service that detected - the event - type: string - timestamp: - description: The time allocated to this event by the blockchain. - This is the block timestamp for most blockchain connectors - format: date-time - type: string - tx: - description: If this blockchain event is coorelated to FireFly - transaction such as a FireFly submitted token transfer, this - field is set to the UUID of the FireFly transaction - properties: - blockchainId: - description: The blockchain transaction ID, in the format - specific to the blockchain involved in the transaction. - Not all FireFly transactions include a blockchain - type: string - id: - description: The UUID of the FireFly transaction - format: uuid - type: string - type: - description: The type of the FireFly transaction - type: string - type: object - type: object - type: array - description: Success - default: - description: "" - tags: - - Non-Default Namespace - /namespaces/{ns}/blockchainevents/{id}: - get: - description: Gets a blockchain event - operationId: getBlockchainEventByIDNamespace - parameters: - - description: The blockchain event ID - in: path - name: id - required: true - schema: - type: string - - description: The namespace which scopes this request - in: path - name: ns - required: true - schema: - example: default - type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - responses: - "200": - content: - application/json: - schema: - properties: - id: - description: The UUID assigned to the event by FireFly - format: uuid - type: string - info: - additionalProperties: - description: Detailed blockchain specific information about - the event, as generated by the blockchain connector - description: Detailed blockchain specific information about the - event, as generated by the blockchain connector - type: object - listener: - description: The UUID of the listener that detected this event, - or nil for built-in events in the system namespace - format: uuid - type: string - name: - description: The name of the event in the blockchain smart contract - type: string - namespace: - description: The namespace of the listener that detected this - blockchain event - type: string - output: - additionalProperties: - description: The data output by the event, parsed to JSON according - to the interface of the smart contract - description: The data output by the event, parsed to JSON according - to the interface of the smart contract - type: object - protocolId: - description: An alphanumerically sortable string that represents - this event uniquely on the blockchain (convention for plugins - is zero-padded values BLOCKNUMBER/TXN_INDEX/EVENT_INDEX) - type: string - source: - description: The blockchain plugin or token service that detected - the event - type: string - timestamp: - description: The time allocated to this event by the blockchain. - This is the block timestamp for most blockchain connectors - format: date-time - type: string - tx: - description: If this blockchain event is coorelated to FireFly - transaction such as a FireFly submitted token transfer, this - field is set to the UUID of the FireFly transaction - properties: - blockchainId: - description: The blockchain transaction ID, in the format - specific to the blockchain involved in the transaction. - Not all FireFly transactions include a blockchain - type: string - id: - description: The UUID of the FireFly transaction - format: uuid - type: string - type: - description: The type of the FireFly transaction - type: string - type: object - type: object - description: Success - default: - description: "" - tags: - - Non-Default Namespace - /namespaces/{ns}/charts/histogram/{collection}: - get: - description: Gets a JSON object containing statistics data that can be used - to build a graphical representation of recent activity in a given database - collection - operationId: getChartHistogramNamespace - parameters: - - description: The collection ID - in: path - name: collection - required: true - schema: - type: string - - description: The namespace which scopes this request - in: path - name: ns - required: true + - description: Ascending sort order (overrides all fields in a multi-field sort) + in: query + name: ascending schema: - example: default type: string - - description: Start time of the data to be fetched + - description: Descending sort order (overrides all fields in a multi-field + sort) in: query - name: startTime + name: descending schema: type: string - - description: End time of the data to be fetched + - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk + operations' in: query - name: endTime + name: skip schema: type: string - - description: Number of buckets between start time and end time + - description: 'The maximum number of records to return (max: 1,000)' in: query - name: buckets + name: limit schema: + example: "25" type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout + - description: Return a total count as well as items (adds extra database processing) + in: query + name: count schema: - default: 2m0s type: string responses: "200": @@ -13368,34 +14246,233 @@ paths: schema: items: properties: - count: - description: Total count of entries in this time bucket within - the histogram + description: + description: A description of the smart contract this FFI represents type: string - isCapped: - description: Indicates whether there are more results in this - bucket that are not being displayed - type: boolean - timestamp: - description: Starting timestamp for the bucket - format: date-time + errors: + description: An array of smart contract error definitions + items: + description: An array of smart contract error definitions + properties: + description: + description: A description of the smart contract error + type: string + id: + description: The UUID of the FFI error definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this error is part of + format: uuid + type: string + name: + description: The name of the error + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of error parameter/argument definitions + items: + description: An array of error parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart + contract + type: string + schema: + description: FireFly uses an extended subset of + JSON Schema to describe parameters, similar to + OpenAPI/Swagger. Converters are available for + native blockchain interface definitions / type + systems - such as an Ethereum ABI. See the documentation + for more detail + type: object + type: array + pathname: + description: The unique name allocated to this error within + the FFI for use on URL paths + type: string + signature: + description: The stringified signature of the error, as + computed by the blockchain plugin + type: string + type: object + type: array + events: + description: An array of smart contract event definitions + items: + description: An array of smart contract event definitions + properties: + description: + description: A description of the smart contract event + type: string + details: + additionalProperties: + description: Additional blockchain specific fields about + this event from the original smart contract. Used + by the blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about + this event from the original smart contract. Used by + the blockchain plugin and for documentation generation. + type: object + id: + description: The UUID of the FFI event definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this event is part of + format: uuid + type: string + name: + description: The name of the event + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of event parameter/argument definitions + items: + description: An array of event parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart + contract + type: string + schema: + description: FireFly uses an extended subset of + JSON Schema to describe parameters, similar to + OpenAPI/Swagger. Converters are available for + native blockchain interface definitions / type + systems - such as an Ethereum ABI. See the documentation + for more detail + type: object + type: array + pathname: + description: The unique name allocated to this event within + the FFI for use on URL paths. Supports contracts that + have multiple event overrides with the same name + type: string + signature: + description: The stringified signature of the event, as + computed by the blockchain plugin + type: string + type: object + type: array + id: + description: The UUID of the FireFly interface (FFI) smart contract + definition + format: uuid type: string - types: - description: Array of separate counts for individual types of - record within the bucket + message: + description: The UUID of the broadcast message that was used + to publish this FFI to the network + format: uuid + type: string + methods: + description: An array of smart contract method definitions items: - description: Array of separate counts for individual types - of record within the bucket + description: An array of smart contract method definitions properties: - count: - description: Count of entries of a given type within a - bucket + description: + description: A description of the smart contract method type: string - type: - description: Name of the type + details: + additionalProperties: + description: Additional blockchain specific fields about + this method from the original smart contract. Used + by the blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about + this method from the original smart contract. Used by + the blockchain plugin and for documentation generation. + type: object + id: + description: The UUID of the FFI method definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this method is part of + format: uuid + type: string + name: + description: The name of the method + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of method parameter/argument definitions + items: + description: An array of method parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart + contract + type: string + schema: + description: FireFly uses an extended subset of + JSON Schema to describe parameters, similar to + OpenAPI/Swagger. Converters are available for + native blockchain interface definitions / type + systems - such as an Ethereum ABI. See the documentation + for more detail + type: object + type: array + pathname: + description: The unique name allocated to this method + within the FFI for use on URL paths. Supports contracts + that have multiple method overrides with the same name type: string + returns: + description: An array of method return definitions + items: + description: An array of method return definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart + contract + type: string + schema: + description: FireFly uses an extended subset of + JSON Schema to describe parameters, similar to + OpenAPI/Swagger. Converters are available for + native blockchain interface definitions / type + systems - such as an Ethereum ABI. See the documentation + for more detail + type: object + type: array type: object type: array + name: + description: The name of the FFI - usually matching the smart + contract name + type: string + namespace: + description: The namespace of the FFI + type: string + networkName: + description: The published name of the FFI within the multiparty + network + type: string + published: + description: Indicates if the FFI is published to other members + of the multiparty network + type: boolean + version: + description: A version for the FFI - use of semantic versioning + such as 'v1.0.1' is encouraged + type: string type: object type: array description: Success @@ -13403,10 +14480,9 @@ paths: description: "" tags: - Non-Default Namespace - /namespaces/{ns}/contracts/deploy: post: - description: Deploy a new smart contract - operationId: postContractDeployNamespace + description: Creates and broadcasts a new custom smart contract interface + operationId: postNewContractInterfaceNamespace parameters: - description: The namespace which scopes this request in: path @@ -13421,6 +14497,12 @@ paths: schema: example: "true" type: string + - description: When true the definition will be published to all other members + of the multiparty network + in: query + name: publish + schema: + type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) in: header @@ -13433,181 +14515,375 @@ paths: application/json: schema: properties: - contract: - description: The smart contract to deploy. This should be pre-compiled - if required by the blockchain connector - definition: - description: The definition of the smart contract - idempotencyKey: - description: An optional identifier to allow idempotent submission - of requests. Stored on the transaction uniquely within a namespace + description: + description: A description of the smart contract this FFI represents type: string - input: - description: An optional array of inputs passed to the smart contract's - constructor, if applicable + errors: + description: An array of smart contract error definitions items: - description: An optional array of inputs passed to the smart contract's - constructor, if applicable + description: An array of smart contract error definitions + properties: + description: + description: A description of the smart contract error + type: string + name: + description: The name of the error + type: string + params: + description: An array of error parameter/argument definitions + items: + description: An array of error parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to + the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array + type: object type: array - key: - description: The blockchain signing key that will be used to deploy - the contract. Defaults to the first signing key of the organization - that operates the node + events: + description: An array of smart contract event definitions + items: + description: An array of smart contract event definitions + properties: + description: + description: A description of the smart contract event + type: string + details: + additionalProperties: + description: Additional blockchain specific fields about + this event from the original smart contract. Used by the + blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about this + event from the original smart contract. Used by the blockchain + plugin and for documentation generation. + type: object + name: + description: The name of the event + type: string + params: + description: An array of event parameter/argument definitions + items: + description: An array of event parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to + the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array + type: object + type: array + methods: + description: An array of smart contract method definitions + items: + description: An array of smart contract method definitions + properties: + description: + description: A description of the smart contract method + type: string + details: + additionalProperties: + description: Additional blockchain specific fields about + this method from the original smart contract. Used by + the blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about this + method from the original smart contract. Used by the blockchain + plugin and for documentation generation. + type: object + name: + description: The name of the method + type: string + params: + description: An array of method parameter/argument definitions + items: + description: An array of method parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to + the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array + returns: + description: An array of method return definitions + items: + description: An array of method return definitions + properties: + name: + description: The name of the parameter. Note that parameters + must be ordered correctly on the FFI, according to + the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum ABI. + See the documentation for more detail + type: object + type: array + type: object + type: array + name: + description: The name of the FFI - usually matching the smart contract + name + type: string + networkName: + description: The published name of the FFI within the multiparty + network + type: string + version: + description: A version for the FFI - use of semantic versioning + such as 'v1.0.1' is encouraged type: string - options: - additionalProperties: - description: A map of named inputs that will be passed through - to the blockchain connector - description: A map of named inputs that will be passed through to - the blockchain connector - type: object type: object responses: - "200": - content: - application/json: - schema: - properties: - created: - description: The time the operation was created - format: date-time - type: string - error: - description: Any error reported back from the plugin for this - operation - type: string - id: - description: The UUID of the operation - format: uuid - type: string - input: - additionalProperties: - description: The input to this operation - description: The input to this operation - type: object - namespace: - description: The namespace of the operation - type: string - output: - additionalProperties: - description: Any output reported back from the plugin for this - operation - description: Any output reported back from the plugin for this - operation - type: object - plugin: - description: The plugin responsible for performing the operation - type: string - retry: - description: If this operation was initiated as a retry to a previous - operation, this field points to the UUID of the operation being - retried - format: uuid - type: string - status: - description: The current status of the operation - type: string - tx: - description: The UUID of the FireFly transaction the operation - is part of - format: uuid - type: string - type: - description: The type of the operation - enum: - - blockchain_pin_batch - - blockchain_network_action - - blockchain_deploy - - blockchain_invoke - - sharedstorage_upload_batch - - sharedstorage_upload_blob - - sharedstorage_upload_value - - sharedstorage_download_batch - - sharedstorage_download_blob - - dataexchange_send_batch - - dataexchange_send_blob - - token_create_pool - - token_activate_pool - - token_transfer - - token_approval - type: string - updated: - description: The last update time of the operation - format: date-time - type: string - type: object - description: Success - "202": + "200": content: application/json: schema: properties: - created: - description: The time the operation was created - format: date-time - type: string - error: - description: Any error reported back from the plugin for this - operation + description: + description: A description of the smart contract this FFI represents type: string + errors: + description: An array of smart contract error definitions + items: + description: An array of smart contract error definitions + properties: + description: + description: A description of the smart contract error + type: string + id: + description: The UUID of the FFI error definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this error is part of + format: uuid + type: string + name: + description: The name of the error + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of error parameter/argument definitions + items: + description: An array of error parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + pathname: + description: The unique name allocated to this error within + the FFI for use on URL paths + type: string + signature: + description: The stringified signature of the error, as + computed by the blockchain plugin + type: string + type: object + type: array + events: + description: An array of smart contract event definitions + items: + description: An array of smart contract event definitions + properties: + description: + description: A description of the smart contract event + type: string + details: + additionalProperties: + description: Additional blockchain specific fields about + this event from the original smart contract. Used by + the blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about + this event from the original smart contract. Used by the + blockchain plugin and for documentation generation. + type: object + id: + description: The UUID of the FFI event definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this event is part of + format: uuid + type: string + name: + description: The name of the event + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of event parameter/argument definitions + items: + description: An array of event parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + pathname: + description: The unique name allocated to this event within + the FFI for use on URL paths. Supports contracts that + have multiple event overrides with the same name + type: string + signature: + description: The stringified signature of the event, as + computed by the blockchain plugin + type: string + type: object + type: array id: - description: The UUID of the operation + description: The UUID of the FireFly interface (FFI) smart contract + definition format: uuid type: string - input: - additionalProperties: - description: The input to this operation - description: The input to this operation - type: object - namespace: - description: The namespace of the operation - type: string - output: - additionalProperties: - description: Any output reported back from the plugin for this - operation - description: Any output reported back from the plugin for this - operation - type: object - plugin: - description: The plugin responsible for performing the operation - type: string - retry: - description: If this operation was initiated as a retry to a previous - operation, this field points to the UUID of the operation being - retried + message: + description: The UUID of the broadcast message that was used to + publish this FFI to the network format: uuid type: string - status: - description: The current status of the operation + methods: + description: An array of smart contract method definitions + items: + description: An array of smart contract method definitions + properties: + description: + description: A description of the smart contract method + type: string + details: + additionalProperties: + description: Additional blockchain specific fields about + this method from the original smart contract. Used by + the blockchain plugin and for documentation generation. + description: Additional blockchain specific fields about + this method from the original smart contract. Used by + the blockchain plugin and for documentation generation. + type: object + id: + description: The UUID of the FFI method definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this method is part of + format: uuid + type: string + name: + description: The name of the method + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of method parameter/argument definitions + items: + description: An array of method parameter/argument definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + pathname: + description: The unique name allocated to this method within + the FFI for use on URL paths. Supports contracts that + have multiple method overrides with the same name + type: string + returns: + description: An array of method return definitions + items: + description: An array of method return definitions + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + type: object + type: array + name: + description: The name of the FFI - usually matching the smart + contract name type: string - tx: - description: The UUID of the FireFly transaction the operation - is part of - format: uuid + namespace: + description: The namespace of the FFI type: string - type: - description: The type of the operation - enum: - - blockchain_pin_batch - - blockchain_network_action - - blockchain_deploy - - blockchain_invoke - - sharedstorage_upload_batch - - sharedstorage_upload_blob - - sharedstorage_upload_value - - sharedstorage_download_batch - - sharedstorage_download_blob - - dataexchange_send_batch - - dataexchange_send_blob - - token_create_pool - - token_activate_pool - - token_transfer - - token_approval + networkName: + description: The published name of the FFI within the multiparty + network type: string - updated: - description: The last update time of the operation - format: date-time + published: + description: Indicates if the FFI is published to other members + of the multiparty network + type: boolean + version: + description: A version for the FFI - use of semantic versioning + such as 'v1.0.1' is encouraged type: string type: object description: Success @@ -13615,11 +14891,17 @@ paths: description: "" tags: - Non-Default Namespace - /namespaces/{ns}/contracts/interfaces: - get: - description: Gets a list of contract interfaces that have been published - operationId: getContractInterfacesNamespace + /namespaces/{ns}/contracts/interfaces/{interfaceId}: + delete: + description: Delete a contract interface + operationId: deleteContractInterfaceNamespace parameters: + - description: The ID of the contract interface + in: path + name: interfaceId + required: true + schema: + type: string - description: The namespace which scopes this request in: path name: ns @@ -13634,300 +14916,294 @@ paths: schema: default: 2m0s type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: id - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: name - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: version - schema: - type: string - - description: Sort field. For multi-field sort use comma separated values (or - multiple query values) with '-' prefix for descending - in: query - name: sort - schema: - type: string - - description: Ascending sort order (overrides all fields in a multi-field sort) - in: query - name: ascending - schema: - type: string - - description: Descending sort order (overrides all fields in a multi-field - sort) - in: query - name: descending + responses: + "204": + content: + application/json: {} + description: Success + default: + description: "" + tags: + - Non-Default Namespace + get: + description: Gets a contract interface by its ID + operationId: getContractInterfaceNamespace + parameters: + - description: The ID of the contract interface + in: path + name: interfaceId + required: true schema: type: string - - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk - operations' - in: query - name: skip + - description: The namespace which scopes this request + in: path + name: ns + required: true schema: + example: default type: string - - description: 'The maximum number of records to return (max: 1,000)' + - description: When set, the API will return the full FireFly Interface document + including all methods, events, and parameters in: query - name: limit + name: fetchchildren schema: - example: "25" + example: "true" type: string - - description: Return a total count as well as items (adds extra database processing) - in: query - name: count + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout schema: + default: 2m0s type: string responses: "200": content: application/json: schema: - items: - properties: - description: - description: A description of the smart contract this FFI represents - type: string - errors: + properties: + description: + description: A description of the smart contract this FFI represents + type: string + errors: + description: An array of smart contract error definitions + items: description: An array of smart contract error definitions - items: - description: An array of smart contract error definitions - properties: - description: - description: A description of the smart contract error - type: string - id: - description: The UUID of the FFI error definition - format: uuid - type: string - interface: - description: The UUID of the FFI smart contract definition - that this error is part of - format: uuid - type: string - name: - description: The name of the error - type: string - namespace: - description: The namespace of the FFI - type: string - params: + properties: + description: + description: A description of the smart contract error + type: string + id: + description: The UUID of the FFI error definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this error is part of + format: uuid + type: string + name: + description: The name of the error + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of error parameter/argument definitions + items: description: An array of error parameter/argument definitions - items: - description: An array of error parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that - parameters must be ordered correctly on the FFI, - according to the order in the blockchain smart - contract - type: string - schema: - description: FireFly uses an extended subset of - JSON Schema to describe parameters, similar to - OpenAPI/Swagger. Converters are available for - native blockchain interface definitions / type - systems - such as an Ethereum ABI. See the documentation - for more detail - type: object - type: array - pathname: - description: The unique name allocated to this error within - the FFI for use on URL paths - type: string - signature: - description: The stringified signature of the error, as - computed by the blockchain plugin - type: string - type: object - type: array - events: + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + pathname: + description: The unique name allocated to this error within + the FFI for use on URL paths + type: string + signature: + description: The stringified signature of the error, as + computed by the blockchain plugin + type: string + type: object + type: array + events: + description: An array of smart contract event definitions + items: description: An array of smart contract event definitions - items: - description: An array of smart contract event definitions - properties: - description: - description: A description of the smart contract event - type: string - details: - additionalProperties: - description: Additional blockchain specific fields about - this event from the original smart contract. Used - by the blockchain plugin and for documentation generation. + properties: + description: + description: A description of the smart contract event + type: string + details: + additionalProperties: description: Additional blockchain specific fields about this event from the original smart contract. Used by the blockchain plugin and for documentation generation. - type: object - id: - description: The UUID of the FFI event definition - format: uuid - type: string - interface: - description: The UUID of the FFI smart contract definition - that this event is part of - format: uuid - type: string - name: - description: The name of the event - type: string - namespace: - description: The namespace of the FFI - type: string - params: + description: Additional blockchain specific fields about + this event from the original smart contract. Used by the + blockchain plugin and for documentation generation. + type: object + id: + description: The UUID of the FFI event definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this event is part of + format: uuid + type: string + name: + description: The name of the event + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of event parameter/argument definitions + items: description: An array of event parameter/argument definitions - items: - description: An array of event parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that - parameters must be ordered correctly on the FFI, - according to the order in the blockchain smart - contract - type: string - schema: - description: FireFly uses an extended subset of - JSON Schema to describe parameters, similar to - OpenAPI/Swagger. Converters are available for - native blockchain interface definitions / type - systems - such as an Ethereum ABI. See the documentation - for more detail - type: object - type: array - pathname: - description: The unique name allocated to this event within - the FFI for use on URL paths. Supports contracts that - have multiple event overrides with the same name - type: string - signature: - description: The stringified signature of the event, as - computed by the blockchain plugin - type: string - type: object - type: array - id: - description: The UUID of the FireFly interface (FFI) smart contract - definition - format: uuid - type: string - message: - description: The UUID of the broadcast message that was used - to publish this FFI to the network - format: uuid - type: string - methods: + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + pathname: + description: The unique name allocated to this event within + the FFI for use on URL paths. Supports contracts that + have multiple event overrides with the same name + type: string + signature: + description: The stringified signature of the event, as + computed by the blockchain plugin + type: string + type: object + type: array + id: + description: The UUID of the FireFly interface (FFI) smart contract + definition + format: uuid + type: string + message: + description: The UUID of the broadcast message that was used to + publish this FFI to the network + format: uuid + type: string + methods: + description: An array of smart contract method definitions + items: description: An array of smart contract method definitions - items: - description: An array of smart contract method definitions - properties: - description: - description: A description of the smart contract method - type: string - details: - additionalProperties: - description: Additional blockchain specific fields about - this method from the original smart contract. Used - by the blockchain plugin and for documentation generation. + properties: + description: + description: A description of the smart contract method + type: string + details: + additionalProperties: description: Additional blockchain specific fields about this method from the original smart contract. Used by the blockchain plugin and for documentation generation. - type: object - id: - description: The UUID of the FFI method definition - format: uuid - type: string - interface: - description: The UUID of the FFI smart contract definition - that this method is part of - format: uuid - type: string - name: - description: The name of the method - type: string - namespace: - description: The namespace of the FFI - type: string - params: + description: Additional blockchain specific fields about + this method from the original smart contract. Used by + the blockchain plugin and for documentation generation. + type: object + id: + description: The UUID of the FFI method definition + format: uuid + type: string + interface: + description: The UUID of the FFI smart contract definition + that this method is part of + format: uuid + type: string + name: + description: The name of the method + type: string + namespace: + description: The namespace of the FFI + type: string + params: + description: An array of method parameter/argument definitions + items: description: An array of method parameter/argument definitions - items: - description: An array of method parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that - parameters must be ordered correctly on the FFI, - according to the order in the blockchain smart - contract - type: string - schema: - description: FireFly uses an extended subset of - JSON Schema to describe parameters, similar to - OpenAPI/Swagger. Converters are available for - native blockchain interface definitions / type - systems - such as an Ethereum ABI. See the documentation - for more detail - type: object - type: array - pathname: - description: The unique name allocated to this method - within the FFI for use on URL paths. Supports contracts - that have multiple method overrides with the same name - type: string - returns: + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + pathname: + description: The unique name allocated to this method within + the FFI for use on URL paths. Supports contracts that + have multiple method overrides with the same name + type: string + returns: + description: An array of method return definitions + items: description: An array of method return definitions - items: - description: An array of method return definitions - properties: - name: - description: The name of the parameter. Note that - parameters must be ordered correctly on the FFI, - according to the order in the blockchain smart - contract - type: string - schema: - description: FireFly uses an extended subset of - JSON Schema to describe parameters, similar to - OpenAPI/Swagger. Converters are available for - native blockchain interface definitions / type - systems - such as an Ethereum ABI. See the documentation - for more detail - type: object - type: array - type: object - type: array - name: - description: The name of the FFI - usually matching the smart - contract name - type: string - namespace: - description: The namespace of the FFI - type: string - networkName: - description: The shared interface name within the multiparty - network - type: string - published: - description: True if the interface has been published to a multiparty - network - type: boolean - version: - description: A version for the FFI - use of semantic versioning - such as 'v1.0.1' is encouraged - type: string - type: object - type: array + properties: + name: + description: The name of the parameter. Note that + parameters must be ordered correctly on the FFI, + according to the order in the blockchain smart contract + type: string + schema: + description: FireFly uses an extended subset of JSON + Schema to describe parameters, similar to OpenAPI/Swagger. + Converters are available for native blockchain interface + definitions / type systems - such as an Ethereum + ABI. See the documentation for more detail + type: object + type: array + type: object + type: array + name: + description: The name of the FFI - usually matching the smart + contract name + type: string + namespace: + description: The namespace of the FFI + type: string + networkName: + description: The published name of the FFI within the multiparty + network + type: string + published: + description: Indicates if the FFI is published to other members + of the multiparty network + type: boolean + version: + description: A version for the FFI - use of semantic versioning + such as 'v1.0.1' is encouraged + type: string + type: object description: Success default: description: "" tags: - Non-Default Namespace - post: - description: Creates and broadcasts a new custom smart contract interface - operationId: postNewContractInterfaceNamespace + /namespaces/{ns}/contracts/interfaces/{name}/{version}: + get: + description: Gets a contract interface by its name and version + operationId: getContractInterfaceByNameAndVersionNamespace parameters: + - description: The name of the contract interface + in: path + name: name + required: true + schema: + type: string + - description: The version of the contract interface + in: path + name: version + required: true + schema: + type: string - description: The namespace which scopes this request in: path name: ns @@ -13935,9 +15211,10 @@ paths: schema: example: default type: string - - description: When true the HTTP request blocks until the message is confirmed + - description: When set, the API will return the full FireFly Interface document + including all methods, events, and parameters in: query - name: confirm + name: fetchchildren schema: example: "true" type: string @@ -13948,155 +15225,6 @@ paths: schema: default: 2m0s type: string - requestBody: - content: - application/json: - schema: - properties: - description: - description: A description of the smart contract this FFI represents - type: string - errors: - description: An array of smart contract error definitions - items: - description: An array of smart contract error definitions - properties: - description: - description: A description of the smart contract error - type: string - name: - description: The name of the error - type: string - params: - description: An array of error parameter/argument definitions - items: - description: An array of error parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to - the order in the blockchain smart contract - type: string - schema: - description: FireFly uses an extended subset of JSON - Schema to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail - type: object - type: array - type: object - type: array - events: - description: An array of smart contract event definitions - items: - description: An array of smart contract event definitions - properties: - description: - description: A description of the smart contract event - type: string - details: - additionalProperties: - description: Additional blockchain specific fields about - this event from the original smart contract. Used by the - blockchain plugin and for documentation generation. - description: Additional blockchain specific fields about this - event from the original smart contract. Used by the blockchain - plugin and for documentation generation. - type: object - name: - description: The name of the event - type: string - params: - description: An array of event parameter/argument definitions - items: - description: An array of event parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to - the order in the blockchain smart contract - type: string - schema: - description: FireFly uses an extended subset of JSON - Schema to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail - type: object - type: array - type: object - type: array - methods: - description: An array of smart contract method definitions - items: - description: An array of smart contract method definitions - properties: - description: - description: A description of the smart contract method - type: string - details: - additionalProperties: - description: Additional blockchain specific fields about - this method from the original smart contract. Used by - the blockchain plugin and for documentation generation. - description: Additional blockchain specific fields about this - method from the original smart contract. Used by the blockchain - plugin and for documentation generation. - type: object - name: - description: The name of the method - type: string - params: - description: An array of method parameter/argument definitions - items: - description: An array of method parameter/argument definitions - properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to - the order in the blockchain smart contract - type: string - schema: - description: FireFly uses an extended subset of JSON - Schema to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail - type: object - type: array - returns: - description: An array of method return definitions - items: - description: An array of method return definitions - properties: - name: - description: The name of the parameter. Note that parameters - must be ordered correctly on the FFI, according to - the order in the blockchain smart contract - type: string - schema: - description: FireFly uses an extended subset of JSON - Schema to describe parameters, similar to OpenAPI/Swagger. - Converters are available for native blockchain interface - definitions / type systems - such as an Ethereum ABI. - See the documentation for more detail - type: object - type: array - type: object - type: array - name: - description: The name of the FFI - usually matching the smart contract - name - type: string - networkName: - description: The shared interface name within the multiparty network - type: string - version: - description: A version for the FFI - use of semantic versioning - such as 'v1.0.1' is encouraged - type: string - type: object responses: "200": content: @@ -14311,11 +15439,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning @@ -14327,14 +15456,21 @@ paths: description: "" tags: - Non-Default Namespace - /namespaces/{ns}/contracts/interfaces/{interfaceId}: - get: - description: Gets a contract interface by its ID - operationId: getContractInterfaceNamespace + /namespaces/{ns}/contracts/interfaces/{name}/{version}/publish: + post: + description: Publish a contract interface to all other members of the multiparty + network + operationId: postContractInterfacePublishNamespace parameters: - - description: The ID of the contract interface + - description: The name of the contract interface in: path - name: interfaceId + name: name + required: true + schema: + type: string + - description: The version of the contract interface + in: path + name: version required: true schema: type: string @@ -14345,12 +15481,10 @@ paths: schema: example: default type: string - - description: When set, the API will return the full FireFly Interface document - including all methods, events, and parameters + - description: When true the HTTP request blocks until the message is confirmed in: query - name: fetchchildren + name: confirm schema: - example: "true" type: string - description: Server-side request timeout (milliseconds, or set a custom suffix like 10s) @@ -14359,6 +15493,16 @@ paths: schema: default: 2m0s type: string + requestBody: + content: + application/json: + schema: + properties: + networkName: + description: An optional name to be used for publishing this definition + to the multiparty network, which may differ from the local name + type: string + type: object responses: "200": content: @@ -14573,11 +15717,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning @@ -14585,50 +15730,7 @@ paths: type: string type: object description: Success - default: - description: "" - tags: - - Non-Default Namespace - /namespaces/{ns}/contracts/interfaces/{name}/{version}: - get: - description: Gets a contract interface by its name and version - operationId: getContractInterfaceByNameAndVersionNamespace - parameters: - - description: The name of the contract interface - in: path - name: name - required: true - schema: - type: string - - description: The version of the contract interface - in: path - name: version - required: true - schema: - type: string - - description: The namespace which scopes this request - in: path - name: ns - required: true - schema: - example: default - type: string - - description: When set, the API will return the full FireFly Interface document - including all methods, events, and parameters - in: query - name: fetchchildren - schema: - example: "true" - type: string - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - responses: - "200": + "202": content: application/json: schema: @@ -14841,11 +15943,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning @@ -15116,11 +16219,12 @@ paths: description: The namespace of the FFI type: string networkName: - description: The shared interface name within the multiparty network + description: The published name of the FFI within the multiparty + network type: string published: - description: True if the interface has been published to a multiparty - network + description: Indicates if the FFI is published to other members + of the multiparty network type: boolean version: description: A version for the FFI - use of semantic versioning diff --git a/internal/apiserver/route_delete_contract_interface.go b/internal/apiserver/route_delete_contract_interface.go new file mode 100644 index 000000000..64631f426 --- /dev/null +++ b/internal/apiserver/route_delete_contract_interface.go @@ -0,0 +1,48 @@ +// Copyright © 2023 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http" + + "github.com/hyperledger/firefly-common/pkg/ffapi" + "github.com/hyperledger/firefly-common/pkg/fftypes" + "github.com/hyperledger/firefly/internal/coremsgs" +) + +var deleteContractInterface = &ffapi.Route{ + Name: "deleteContractInterface", + Path: "contracts/interfaces/{interfaceId}", + Method: http.MethodDelete, + PathParams: []*ffapi.PathParam{ + {Name: "interfaceId", Description: coremsgs.APIParamsContractInterfaceID}, + }, + QueryParams: nil, + Description: coremsgs.APIEndpointsDeleteContractInterface, + JSONInputValue: nil, + JSONOutputValue: nil, + JSONOutputCodes: []int{http.StatusNoContent}, // Sync operation, no output + Extensions: &coreExtensions{ + CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { + interfaceID, err := fftypes.ParseUUID(cr.ctx, r.PP["interfaceId"]) + if err != nil { + return nil, err + } + return nil, cr.or.Contracts().DeleteFFI(cr.ctx, interfaceID) + }, + }, +} diff --git a/internal/apiserver/route_delete_contract_interface_test.go b/internal/apiserver/route_delete_contract_interface_test.go new file mode 100644 index 000000000..a4daf087b --- /dev/null +++ b/internal/apiserver/route_delete_contract_interface_test.go @@ -0,0 +1,56 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "fmt" + "net/http/httptest" + "testing" + + "github.com/hyperledger/firefly-common/pkg/fftypes" + "github.com/hyperledger/firefly/mocks/contractmocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestDeleteContractInterface(t *testing.T) { + o, r := newTestAPIServer() + o.On("Authorize", mock.Anything, mock.Anything).Return(nil) + mcm := &contractmocks.Manager{} + o.On("Contracts").Return(mcm) + u := fftypes.NewUUID() + req := httptest.NewRequest("DELETE", fmt.Sprintf("/api/v1/namespaces/ns1/contracts/interfaces/%s", u), nil) + req.Header.Set("Content-Type", "application/json; charset=utf-8") + res := httptest.NewRecorder() + + mcm.On("DeleteFFI", mock.Anything, u).Return(nil) + r.ServeHTTP(res, req) + + assert.Equal(t, 204, res.Result().StatusCode) +} + +func TestDeleteContractInterfaceBadID(t *testing.T) { + o, r := newTestAPIServer() + o.On("Authorize", mock.Anything, mock.Anything).Return(nil) + req := httptest.NewRequest("DELETE", fmt.Sprintf("/api/v1/namespaces/ns1/contracts/interfaces/bad"), nil) + req.Header.Set("Content-Type", "application/json; charset=utf-8") + res := httptest.NewRecorder() + + r.ServeHTTP(res, req) + + assert.Equal(t, 400, res.Result().StatusCode) +} diff --git a/internal/apiserver/route_get_contract_interface_name_version.go b/internal/apiserver/route_get_contract_interface_name_version.go index 4c2d5d90f..c995da4ca 100644 --- a/internal/apiserver/route_get_contract_interface_name_version.go +++ b/internal/apiserver/route_get_contract_interface_name_version.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/internal/apiserver/route_post_contract_interface_publish.go b/internal/apiserver/route_post_contract_interface_publish.go new file mode 100644 index 000000000..1f161f883 --- /dev/null +++ b/internal/apiserver/route_post_contract_interface_publish.go @@ -0,0 +1,52 @@ +// Copyright © 2023 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http" + "strings" + + "github.com/hyperledger/firefly-common/pkg/ffapi" + "github.com/hyperledger/firefly-common/pkg/fftypes" + "github.com/hyperledger/firefly/internal/coremsgs" + "github.com/hyperledger/firefly/pkg/core" +) + +var postContractInterfacePublish = &ffapi.Route{ + Name: "postContractInterfacePublish", + Path: "contracts/interfaces/{name}/{version}/publish", + Method: http.MethodPost, + PathParams: []*ffapi.PathParam{ + {Name: "name", Description: coremsgs.APIParamsContractInterfaceName}, + {Name: "version", Description: coremsgs.APIParamsContractInterfaceVersion}, + }, + QueryParams: []*ffapi.QueryParam{ + {Name: "confirm", Description: coremsgs.APIConfirmQueryParam, IsBool: true}, + }, + Description: coremsgs.APIEndpointsPostContractInterfacePublish, + JSONInputValue: func() interface{} { return &core.DefinitionPublish{} }, + JSONOutputValue: func() interface{} { return &fftypes.FFI{} }, + JSONOutputCodes: []int{http.StatusAccepted, http.StatusOK}, + Extensions: &coreExtensions{ + CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { + 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) + }, + }, +} diff --git a/internal/apiserver/route_post_contract_interface_publish_test.go b/internal/apiserver/route_post_contract_interface_publish_test.go new file mode 100644 index 000000000..16f9279c8 --- /dev/null +++ b/internal/apiserver/route_post_contract_interface_publish_test.go @@ -0,0 +1,49 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "bytes" + "encoding/json" + "net/http/httptest" + "testing" + + "github.com/hyperledger/firefly-common/pkg/fftypes" + "github.com/hyperledger/firefly/mocks/definitionsmocks" + "github.com/hyperledger/firefly/pkg/core" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestPostContractInterfacePublish(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.TokenPool{} + 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).Return(ffi, nil) + r.ServeHTTP(res, req) + + assert.Equal(t, 202, res.Result().StatusCode) +} diff --git a/internal/apiserver/route_post_new_contract_interface.go b/internal/apiserver/route_post_new_contract_interface.go index 1b408739a..5a02ad847 100644 --- a/internal/apiserver/route_post_new_contract_interface.go +++ b/internal/apiserver/route_post_new_contract_interface.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -33,6 +33,7 @@ var postNewContractInterface = &ffapi.Route{ PathParams: nil, QueryParams: []*ffapi.QueryParam{ {Name: "confirm", Description: coremsgs.APIConfirmQueryParam, IsBool: true, Example: "true"}, + {Name: "publish", Description: coremsgs.APIPublishQueryParam, IsBool: true}, }, Description: coremsgs.APIEndpointsPostNewContractInterface, JSONInputValue: func() interface{} { return &fftypes.FFI{} }, @@ -46,6 +47,7 @@ var postNewContractInterface = &ffapi.Route{ waitConfirm := strings.EqualFold(r.QP["confirm"], "true") 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) return ffi, err }, diff --git a/internal/apiserver/route_post_token_pool_publish_test.go b/internal/apiserver/route_post_token_pool_publish_test.go index 78db486aa..fc9aad0b8 100644 --- a/internal/apiserver/route_post_token_pool_publish_test.go +++ b/internal/apiserver/route_post_token_pool_publish_test.go @@ -22,7 +22,6 @@ import ( "net/http/httptest" "testing" - "github.com/hyperledger/firefly/mocks/assetmocks" "github.com/hyperledger/firefly/mocks/definitionsmocks" "github.com/hyperledger/firefly/pkg/core" "github.com/stretchr/testify/assert" @@ -32,9 +31,7 @@ import ( func TestPostTokenPoolPublish(t *testing.T) { o, r := newTestAPIServer() o.On("Authorize", mock.Anything, mock.Anything).Return(nil) - mam := &assetmocks.Manager{} mds := &definitionsmocks.Sender{} - o.On("Assets").Return(mam) o.On("DefinitionSender").Return(mds) input := core.TokenPool{} var buf bytes.Buffer @@ -44,7 +41,6 @@ func TestPostTokenPoolPublish(t *testing.T) { res := httptest.NewRecorder() pool := &core.TokenPool{} - mam.On("GetTokenPoolByNameOrID", mock.Anything, "pool1").Return(pool, nil) mds.On("PublishTokenPool", mock.Anything, "pool1", "", false).Return(pool, nil) r.ServeHTTP(res, req) diff --git a/internal/apiserver/routes.go b/internal/apiserver/routes.go index d55ee5e59..1b6cf38e0 100644 --- a/internal/apiserver/routes.go +++ b/internal/apiserver/routes.go @@ -52,6 +52,7 @@ var routes = append( getWebSockets, }), namespacedRoutes([]*ffapi.Route{ + deleteContractInterface, deleteContractListener, deleteData, deleteSubscription, @@ -128,6 +129,7 @@ var routes = append( postContractAPIQuery, postContractAPIListeners, postContractInterfaceGenerate, + postContractInterfacePublish, postContractDeploy, postContractInvoke, postContractQuery, diff --git a/internal/contracts/manager.go b/internal/contracts/manager.go index 08ae7c125..e15ee49dd 100644 --- a/internal/contracts/manager.go +++ b/internal/contracts/manager.go @@ -53,6 +53,7 @@ type Manager interface { GetFFIs(ctx context.Context, filter ffapi.AndFilter) ([]*fftypes.FFI, *ffapi.FilterResult, error) ResolveFFI(ctx context.Context, ffi *fftypes.FFI) error ResolveFFIReference(ctx context.Context, ref *fftypes.FFIReference) error + DeleteFFI(ctx context.Context, id *fftypes.UUID) error DeployContract(ctx context.Context, req *core.ContractDeployRequest, waitConfirm bool) (interface{}, error) InvokeContract(ctx context.Context, req *core.ContractCallRequest, waitConfirm bool) (interface{}, error) @@ -141,7 +142,13 @@ func (cm *contractManager) newFFISchemaCompiler() *jsonschema.Compiler { } func (cm *contractManager) GetFFI(ctx context.Context, name, version string) (*fftypes.FFI, error) { - return cm.database.GetFFI(ctx, cm.namespace, name, version) + ffi, err := cm.database.GetFFI(ctx, cm.namespace, name, version) + if err != nil { + return nil, err + } else if ffi == nil { + return nil, i18n.NewError(ctx, coremsgs.Msg404NotFound) + } + return ffi, nil } func (cm *contractManager) GetFFIWithChildren(ctx context.Context, name, version string) (*fftypes.FFI, error) { @@ -566,11 +573,6 @@ func (cm *contractManager) ResolveFFI(ctx context.Context, ffi *fftypes.FFI) err return err } - existing, err := cm.database.GetFFI(ctx, cm.namespace, ffi.Name, ffi.Version) - if existing != nil && err == nil { - return i18n.NewError(ctx, coremsgs.MsgContractInterfaceExists, ffi.Namespace, ffi.Name, ffi.Version) - } - methodPathNames := map[string]bool{} for _, method := range ffi.Methods { method.Interface = ffi.ID @@ -948,3 +950,19 @@ func (cm *contractManager) buildInvokeMessage(ctx context.Context, in *core.Mess return nil, i18n.NewError(ctx, coremsgs.MsgInvalidMessageType, allowedTypes) } } + +func (cm *contractManager) DeleteFFI(ctx context.Context, id *fftypes.UUID) error { + return cm.database.RunAsGroup(ctx, func(ctx context.Context) error { + ffi, err := cm.GetFFIByID(ctx, id) + if err != nil { + return err + } + if ffi == nil { + return i18n.NewError(ctx, coremsgs.Msg404NotFound) + } + if ffi.Published { + return i18n.NewError(ctx, coremsgs.MsgCannotDeletePublished) + } + return cm.database.DeleteFFI(ctx, cm.namespace, id) + }) +} diff --git a/internal/contracts/manager_test.go b/internal/contracts/manager_test.go index eb20ba4cf..059e8ea8d 100644 --- a/internal/contracts/manager_test.go +++ b/internal/contracts/manager_test.go @@ -172,9 +172,6 @@ func TestResolveFFI(t *testing.T) { func TestBroadcastFFIInvalid(t *testing.T) { cm := newTestContractManager() - mdb := cm.database.(*databasemocks.Plugin) - - mdb.On("GetFFI", mock.Anything, "ns1", "test", "1.0.0").Return(nil, nil) ffi := &fftypes.FFI{ Namespace: "ns1", @@ -196,37 +193,6 @@ func TestBroadcastFFIInvalid(t *testing.T) { err := cm.ResolveFFI(context.Background(), ffi) assert.Regexp(t, "does not validate", err) - - mdb.AssertExpectations(t) -} - -func TestResolveFFIExists(t *testing.T) { - cm := newTestContractManager() - mdb := cm.database.(*databasemocks.Plugin) - - mdb.On("GetFFI", mock.Anything, "ns1", "test", "1.0.0").Return(&fftypes.FFI{}, nil) - - ffi := &fftypes.FFI{ - Namespace: "ns1", - Name: "test", - Version: "1.0.0", - ID: fftypes.NewUUID(), - Methods: []*fftypes.FFIMethod{ - { - Name: "sum", - }, - }, - Events: []*fftypes.FFIEvent{ - { - FFIEventDefinition: fftypes.FFIEventDefinition{ - Name: "changed", - }, - }, - }, - } - - err := cm.ResolveFFI(context.Background(), ffi) - assert.Regexp(t, "FF10302", err) } func TestValidateInvokeContractRequest(t *testing.T) { @@ -1431,6 +1397,22 @@ func TestGetFFI(t *testing.T) { assert.NoError(t, err) } +func TestGetFFINotFound(t *testing.T) { + cm := newTestContractManager() + mdb := cm.database.(*databasemocks.Plugin) + mdb.On("GetFFI", mock.Anything, "ns1", "ffi", "v1.0.0").Return(nil, nil) + _, err := cm.GetFFI(context.Background(), "ffi", "v1.0.0") + assert.Regexp(t, "FF10109", err) +} + +func TestGetFFIFail(t *testing.T) { + cm := newTestContractManager() + mdb := cm.database.(*databasemocks.Plugin) + mdb.On("GetFFI", mock.Anything, "ns1", "ffi", "v1.0.0").Return(nil, fmt.Errorf("pop")) + _, err := cm.GetFFI(context.Background(), "ffi", "v1.0.0") + assert.EqualError(t, err, "pop") +} + func TestGetFFIWithChildren(t *testing.T) { cm := newTestContractManager() mdb := cm.database.(*databasemocks.Plugin) @@ -3383,3 +3365,60 @@ func TestBuildInvokeMessageInvalidType(t *testing.T) { }) assert.Regexp(t, "FF10287", err) } + +func TestDeleteFFI(t *testing.T) { + cm := newTestContractManager() + + id := fftypes.NewUUID() + + mdi := cm.database.(*databasemocks.Plugin) + mdi.On("GetFFIByID", context.Background(), "ns1", id).Return(&fftypes.FFI{}, nil) + mdi.On("DeleteFFI", context.Background(), "ns1", id).Return(nil) + + err := cm.DeleteFFI(context.Background(), id) + assert.NoError(t, err) + + mdi.AssertExpectations(t) +} + +func TestDeleteFFINotFound(t *testing.T) { + cm := newTestContractManager() + + id := fftypes.NewUUID() + + mdi := cm.database.(*databasemocks.Plugin) + mdi.On("GetFFIByID", context.Background(), "ns1", id).Return(nil, nil) + + err := cm.DeleteFFI(context.Background(), id) + assert.Regexp(t, "FF10109", err) + + mdi.AssertExpectations(t) +} + +func TestDeleteFFIFail(t *testing.T) { + cm := newTestContractManager() + + id := fftypes.NewUUID() + + mdi := cm.database.(*databasemocks.Plugin) + mdi.On("GetFFIByID", context.Background(), "ns1", id).Return(nil, fmt.Errorf("pop")) + + err := cm.DeleteFFI(context.Background(), id) + assert.EqualError(t, err, "pop") + + mdi.AssertExpectations(t) +} + +func TestDeleteFFIPublished(t *testing.T) { + cm := newTestContractManager() + + id := fftypes.NewUUID() + + mdi := cm.database.(*databasemocks.Plugin) + mdi.On("GetFFIByID", context.Background(), "ns1", id).Return(&fftypes.FFI{Published: true}, nil) + + err := cm.DeleteFFI(context.Background(), id) + assert.Regexp(t, "FF10449", err) + + mdi.AssertExpectations(t) +} diff --git a/internal/coremsgs/en_api_translations.go b/internal/coremsgs/en_api_translations.go index 9bbc2f54e..45a517a66 100644 --- a/internal/coremsgs/en_api_translations.go +++ b/internal/coremsgs/en_api_translations.go @@ -76,8 +76,10 @@ var ( APIEndpointsAdminGetListenerByID = ffm("api.endpoints.adminGetListenerByID", "Gets a contract listener by ID") APIEndpointsAdminGetListeners = ffm("api.endpoints.adminGetListeners", "Lists contract listeners") + APIEndpointsDeleteContractInterface = ffm("api.endpoints.deleteContractInterface", "Delete a contract interface") APIEndpointsDeleteContractListener = ffm("api.endpoints.deleteContractListener", "Deletes a contract listener referenced by its name or its ID") APIEndpointsDeleteSubscription = ffm("api.endpoints.deleteSubscription", "Deletes a subscription") + APIEndpointsDeleteTokenPool = ffm("api.endpoints.deleteTokenPool", "Delete a token pool") APIEndpointsGetBatchBbyID = ffm("api.endpoints.getBatchByID", "Gets a message batch") APIEndpointsGetBatches = ffm("api.endpoints.getBatches", "Gets a list of message batches") APIEndpointsGetBlockchainEventByID = ffm("api.endpoints.getBlockchainEventByID", "Gets a blockchain event") @@ -154,6 +156,7 @@ var ( APIEndpointsPostContractInterfaceGenerate = ffm("api.endpoints.postContractInterfaceGenerate", "A convenience method to convert a blockchain specific smart contract format into a FireFly Interface format. The specific blockchain plugin in use must support this functionality.") APIEndpointsPostContractInterfaceInvoke = ffm("api.endpoints.postContractInterfaceInvoke", "Invokes a method on a smart contract that matches a given contract interface. Performs a blockchain transaction.") APIEndpointsPostContractInterfaceQuery = ffm("api.endpoints.postContractInterfaceQuery", "Queries a method on a smart contract that matches a given contract interface. Performs a read-only query.") + APIEndpointsPostContractInterfacePublish = ffm("api.endpoints.postContractInterfacePublish", "Publish a contract interface to all other members of the multiparty network") APIEndpointsPostContractInvoke = ffm("api.endpoints.postContractInvoke", "Invokes a method on a smart contract. Performs a blockchain transaction.") APIEndpointsPostContractQuery = ffm("api.endpoints.postContractQuery", "Queries a method on a smart contract. Performs a read-only query.") APIEndpointsPostData = ffm("api.endpoints.postData", "Creates a new data item in this FireFly node") @@ -179,7 +182,6 @@ var ( APIEndpointsPostTokenMint = ffm("api.endpoints.postTokenMint", "Mints some tokens") APIEndpointsPostTokenPool = ffm("api.endpoints.postTokenPool", "Creates a new token pool") APIEndpointsPostTokenPoolPublish = ffm("api.endpoints.postTokenPoolPublish", "Publish a token pool to all other members of the multiparty network") - APIEndpointsDeleteTokenPool = ffm("api.endpoints.deleteTokenPool", "Delete a token pool") APIEndpointsPostTokenTransfer = ffm("api.endpoints.postTokenTransfer", "Transfers some tokens") APIEndpointsPutContractAPI = ffm("api.endpoints.putContractAPI", "Updates an existing contract API") APIEndpointsPutSubscription = ffm("api.endpoints.putSubscription", "Update an existing subscription") diff --git a/internal/coremsgs/en_error_messages.go b/internal/coremsgs/en_error_messages.go index 0af9e1a69..eb74d252b 100644 --- a/internal/coremsgs/en_error_messages.go +++ b/internal/coremsgs/en_error_messages.go @@ -287,4 +287,5 @@ var ( MsgNetworkNameExists = ffe("FF10448", "Network name already exists", 409) MsgCannotDeletePublished = ffe("FF10449", "Cannot delete an item that has been published", 409) MsgAlreadyPublished = ffe("FF10450", "Item has already been published", 409) + MsgContractInterfaceNotPublished = ffe("FF10451", "Contract interface '%s' has not been published", 409) ) diff --git a/internal/coremsgs/en_struct_descriptions.go b/internal/coremsgs/en_struct_descriptions.go index 5b166241b..05de5a032 100644 --- a/internal/coremsgs/en_struct_descriptions.go +++ b/internal/coremsgs/en_struct_descriptions.go @@ -244,13 +244,13 @@ var ( FFIMessage = ffm("FFI.message", "The UUID of the broadcast message that was used to publish this FFI to the network") FFINamespace = ffm("FFI.namespace", "The namespace of the FFI") FFIName = ffm("FFI.name", "The name of the FFI - usually matching the smart contract name") + FFINetworkName = ffm("FFI.networkName", "The published name of the FFI within the multiparty network") FFIDescription = ffm("FFI.description", "A description of the smart contract this FFI represents") FFIVersion = ffm("FFI.version", "A version for the FFI - use of semantic versioning such as 'v1.0.1' is encouraged") FFIMethods = ffm("FFI.methods", "An array of smart contract method definitions") FFIEvents = ffm("FFI.events", "An array of smart contract event definitions") FFIErrors = ffm("FFI.errors", "An array of smart contract error definitions") - FFINetworkName = ffm("FFI.networkName", "The shared interface name within the multiparty network") - FFIPublished = ffm("FFI.published", "True if the interface has been published to a multiparty network") + FFIPublished = ffm("FFI.published", "Indicates if the FFI is published to other members of the multiparty network") // FFIMethod field descriptions FFIMethodID = ffm("FFIMethod.id", "The UUID of the FFI method definition") diff --git a/internal/database/sqlcommon/ffi_sql.go b/internal/database/sqlcommon/ffi_sql.go index 0d1f4ff2b..d50688d05 100644 --- a/internal/database/sqlcommon/ffi_sql.go +++ b/internal/database/sqlcommon/ffi_sql.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -21,6 +21,7 @@ import ( "database/sql" sq "github.com/Masterminds/squirrel" + "github.com/hyperledger/firefly-common/pkg/dbsql" "github.com/hyperledger/firefly-common/pkg/ffapi" "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly-common/pkg/i18n" @@ -35,67 +36,142 @@ var ( "id", "namespace", "name", + "network_name", "version", "description", "message_id", + "published", } ffiFilterFieldMap = map[string]string{ - "message": "message_id", + "message": "message_id", + "networkname": "network_name", } ) const ffiTable = "ffi" -func (s *SQLCommon) UpsertFFI(ctx context.Context, ffi *fftypes.FFI) (err error) { +func (s *SQLCommon) attemptFFIUpdate(ctx context.Context, tx *dbsql.TXWrapper, ffi *fftypes.FFI) (int64, error) { + var networkName *string + if ffi.NetworkName != "" { + networkName = &ffi.NetworkName + } + return s.UpdateTx(ctx, ffiTable, tx, + sq.Update(ffiTable). + Set("name", ffi.Name). + Set("network_name", networkName). + Set("version", ffi.Version). + Set("description", ffi.Description). + Set("message_id", ffi.Message). + Set("published", ffi.Published). + Where(sq.Eq{"id": ffi.ID}), + func() { + s.callbacks.UUIDCollectionNSEvent(database.CollectionFFIs, core.ChangeEventTypeUpdated, ffi.Namespace, ffi.ID) + }, + ) +} + +func (s *SQLCommon) setFFIInsertValues(query sq.InsertBuilder, ffi *fftypes.FFI) sq.InsertBuilder { + var networkName *string + if ffi.NetworkName != "" { + networkName = &ffi.NetworkName + } + return query.Values( + ffi.ID, + ffi.Namespace, + ffi.Name, + networkName, + ffi.Version, + ffi.Description, + ffi.Message, + ffi.Published, + ) +} + +func (s *SQLCommon) attemptFFIInsert(ctx context.Context, tx *dbsql.TXWrapper, ffi *fftypes.FFI, requestConflictEmptyResult bool) error { + _, err := s.InsertTxExt(ctx, ffiTable, tx, + s.setFFIInsertValues(sq.Insert(ffiTable).Columns(ffiColumns...), ffi), + func() { + s.callbacks.UUIDCollectionNSEvent(database.CollectionFFIs, core.ChangeEventTypeCreated, ffi.Namespace, ffi.ID) + }, requestConflictEmptyResult) + return err +} + +func (s *SQLCommon) ffiExists(ctx context.Context, tx *dbsql.TXWrapper, ffi *fftypes.FFI) (bool, error) { + rows, _, err := s.QueryTx(ctx, tokenpoolTable, tx, + sq.Select("id").From(ffiTable).Where(sq.And{ + sq.Eq{ + "namespace": ffi.Namespace, + "version": ffi.Version, + }, + sq.Or{ + sq.Eq{"name": ffi.Name}, + sq.Eq{"network_name": ffi.NetworkName}, + }, + }), + ) + if err != nil { + return false, err + } + defer rows.Close() + return rows.Next(), nil +} + +func (s *SQLCommon) InsertOrGetFFI(ctx context.Context, ffi *fftypes.FFI) (existing *fftypes.FFI, err error) { ctx, tx, autoCommit, err := s.BeginOrUseTx(ctx) if err != nil { - return err + return nil, err } defer s.RollbackTx(ctx, tx, autoCommit) - rows, _, err := s.QueryTx(ctx, ffiTable, tx, - sq.Select("id"). - From(ffiTable). - Where(sq.Eq{ - "namespace": ffi.Namespace, - "id": ffi.ID, - }), - ) + insertErr := s.attemptFFIInsert(ctx, tx, ffi, true /* we want a failure here we can progress past */) + if insertErr == nil { + return nil, s.CommitTx(ctx, tx, autoCommit) + } + + // Do a select within the transaction to determine if the pool already exists + existing, queryErr := s.getFFIPred(ctx, ffi.Namespace+":"+ffi.Name, sq.And{ + sq.Eq{"namespace": ffi.Namespace}, + sq.Or{ + sq.Eq{"id": ffi.ID}, + sq.Eq{"name": ffi.Name}, + sq.Eq{"network_name": ffi.NetworkName}, + }, + }) + if queryErr != nil || existing != nil { + return existing, queryErr + } + + // Error was apparently not an index conflict - must have been something else + return nil, insertErr +} + +func (s *SQLCommon) UpsertFFI(ctx context.Context, ffi *fftypes.FFI, optimization database.UpsertOptimization) error { + ctx, tx, autoCommit, err := s.BeginOrUseTx(ctx) if err != nil { return err } - existing := rows.Next() - rows.Close() - - if existing { - if _, err = s.UpdateTx(ctx, ffiTable, tx, - sq.Update(ffiTable). - Set("name", ffi.Name). - Set("version", ffi.Version). - Set("description", ffi.Description). - Set("message_id", ffi.Message), - func() { - s.callbacks.UUIDCollectionNSEvent(database.CollectionFFIs, core.ChangeEventTypeUpdated, ffi.Namespace, ffi.ID) - }, - ); err != nil { + defer s.RollbackTx(ctx, tx, autoCommit) + + optimized := false + if optimization == database.UpsertOptimizationNew { + opErr := s.attemptFFIInsert(ctx, tx, ffi, true /* we want a failure here we can progress past */) + optimized = opErr == nil + } else if optimization == database.UpsertOptimizationExisting { + rowsAffected, opErr := s.attemptFFIUpdate(ctx, tx, ffi) + optimized = opErr == nil && rowsAffected == 1 + } + + if !optimized { + // Do a select within the transaction to determine if the FFI already exists + exists, err := s.ffiExists(ctx, tx, ffi) + if err != nil { return err + } else if exists { + if _, err := s.attemptFFIUpdate(ctx, tx, ffi); err != nil { + return err + } } - } else { - if _, err = s.InsertTx(ctx, ffiTable, tx, - sq.Insert(ffiTable). - Columns(ffiColumns...). - Values( - ffi.ID, - ffi.Namespace, - ffi.Name, - ffi.Version, - ffi.Description, - ffi.Message, - ), - func() { - s.callbacks.UUIDCollectionNSEvent(database.CollectionFFIs, core.ChangeEventTypeCreated, ffi.Namespace, ffi.ID) - }, - ); err != nil { + if err := s.attemptFFIInsert(ctx, tx, ffi, false); err != nil { return err } } @@ -105,14 +181,20 @@ func (s *SQLCommon) UpsertFFI(ctx context.Context, ffi *fftypes.FFI) (err error) func (s *SQLCommon) ffiResult(ctx context.Context, row *sql.Rows) (*fftypes.FFI, error) { ffi := fftypes.FFI{} + var networkName *string err := row.Scan( &ffi.ID, &ffi.Namespace, &ffi.Name, + &networkName, &ffi.Version, &ffi.Description, &ffi.Message, + &ffi.Published, ) + if networkName != nil { + ffi.NetworkName = *networkName + } if err != nil { return nil, i18n.WrapError(ctx, err, coremsgs.MsgDBReadErr, ffiTable) } @@ -175,5 +257,36 @@ func (s *SQLCommon) GetFFIByID(ctx context.Context, namespace string, id *fftype } func (s *SQLCommon) GetFFI(ctx context.Context, namespace, name, version string) (*fftypes.FFI, error) { - return s.getFFIPred(ctx, namespace+":"+name+":"+version, sq.Eq{"namespace": namespace, "name": name, "version": version}) + return s.getFFIPred(ctx, namespace+":"+name+":"+version, sq.Eq{ + "namespace": namespace, + "name": name, + "version": version, + }) +} + +func (s *SQLCommon) GetFFIByNetworkName(ctx context.Context, namespace, networkName, version string) (*fftypes.FFI, error) { + return s.getFFIPred(ctx, namespace+":"+networkName+":"+version, sq.Eq{ + "namespace": namespace, + "network_name": networkName, + "version": version, + }) +} + +func (s *SQLCommon) DeleteFFI(ctx context.Context, namespace string, id *fftypes.UUID) error { + ctx, tx, autoCommit, err := s.BeginOrUseTx(ctx) + if err != nil { + return err + } + defer s.RollbackTx(ctx, tx, autoCommit) + + err = s.DeleteTx(ctx, ffiTable, tx, sq.Delete(ffiTable).Where(sq.Eq{ + "id": id, "namespace": namespace, + }), func() { + s.callbacks.UUIDCollectionNSEvent(database.CollectionFFIs, core.ChangeEventTypeDeleted, namespace, id) + }) + if err != nil { + return err + } + + return s.CommitTx(ctx, tx, autoCommit) } diff --git a/internal/database/sqlcommon/ffi_sql_test.go b/internal/database/sqlcommon/ffi_sql_test.go index e623d8435..a620f4749 100644 --- a/internal/database/sqlcommon/ffi_sql_test.go +++ b/internal/database/sqlcommon/ffi_sql_test.go @@ -43,6 +43,7 @@ func TestFFIE2EWithDB(t *testing.T) { ID: id, Namespace: "ns1", Name: "math", + NetworkName: "math", Version: "v1.0.0", Description: "Does things and stuff", Message: fftypes.NewUUID(), @@ -71,8 +72,9 @@ func TestFFIE2EWithDB(t *testing.T) { s.callbacks.On("UUIDCollectionNSEvent", database.CollectionFFIs, core.ChangeEventTypeCreated, "ns1", ffi.ID).Return() s.callbacks.On("UUIDCollectionNSEvent", database.CollectionFFIs, core.ChangeEventTypeUpdated, "ns1", ffi.ID).Return() + s.callbacks.On("UUIDCollectionNSEvent", database.CollectionFFIs, core.ChangeEventTypeDeleted, "ns1", ffi.ID).Return() - err := s.UpsertFFI(ctx, ffi) + _, err := s.InsertOrGetFFI(ctx, ffi) assert.NoError(t, err) // Check we get the correct fields back @@ -86,8 +88,7 @@ func TestFFIE2EWithDB(t *testing.T) { assert.Equal(t, ffi.Message, dataRead.Message) ffi.Version = "v1.1.0" - - err = s.UpsertFFI(ctx, ffi) + err = s.UpsertFFI(ctx, ffi, database.UpsertOptimizationExisting) assert.NoError(t, err) // Check we get the correct fields back @@ -99,12 +100,43 @@ func TestFFIE2EWithDB(t *testing.T) { assert.Equal(t, ffi.Name, dataRead.Name) assert.Equal(t, ffi.Version, dataRead.Version) assert.Equal(t, ffi.Message, dataRead.Message) + + dataRead, err = s.GetFFIByNetworkName(ctx, "ns1", "math", "v1.1.0") + assert.NoError(t, err) + assert.NotNil(t, dataRead) + assert.Equal(t, ffi.ID, dataRead.ID) + assert.Equal(t, ffi.Namespace, dataRead.Namespace) + assert.Equal(t, ffi.Name, dataRead.Name) + assert.Equal(t, ffi.Version, dataRead.Version) + assert.Equal(t, ffi.Message, dataRead.Message) + + // Cannot insert again with same name or network name + existing, err := s.InsertOrGetFFI(ctx, &fftypes.FFI{ + ID: fftypes.NewUUID(), + Name: "math", + Version: "v1.1.0", + Namespace: "ns1", + }) + assert.NoError(t, err) + assert.Equal(t, ffi.ID, existing.ID) + existing, err = s.InsertOrGetFFI(ctx, &fftypes.FFI{ + ID: fftypes.NewUUID(), + NetworkName: "math", + Version: "v1.1.0", + Namespace: "ns1", + }) + assert.NoError(t, err) + assert.Equal(t, ffi.ID, existing.ID) + + // Delete the FFI + err = s.DeleteFFI(ctx, "ns1", ffi.ID) + assert.NoError(t, err) } func TestFFIDBFailBeginTransaction(t *testing.T) { s, mock := newMockProvider().init() mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) - err := s.UpsertFFI(context.Background(), &fftypes.FFI{}) + err := s.UpsertFFI(context.Background(), &fftypes.FFI{}, database.UpsertOptimizationNew) assert.Regexp(t, "FF00175", err) assert.NoError(t, mock.ExpectationsWereMet()) } @@ -113,20 +145,39 @@ func TestFFIDBFailSelect(t *testing.T) { s, mock := newMockProvider().init() mock.ExpectBegin() mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) - err := s.UpsertFFI(context.Background(), &fftypes.FFI{}) + err := s.UpsertFFI(context.Background(), &fftypes.FFI{}, database.UpsertOptimizationNew) assert.Regexp(t, "pop", err) assert.NoError(t, mock.ExpectationsWereMet()) } +func TestFFIDBFailUpsert(t *testing.T) { + s, mock := newMockProvider().init() + mock.ExpectBegin() + mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{})) + mock.ExpectExec("INSERT .*").WillReturnError(fmt.Errorf("pop")) + err := s.UpsertFFI(context.Background(), &fftypes.FFI{}, database.UpsertOptimizationNew) + assert.Regexp(t, "pop", err) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +func TestFFIDBInsertFailBegin(t *testing.T) { + s, mock := newMockProvider().init() + mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) + _, err := s.InsertOrGetFFI(context.Background(), &fftypes.FFI{}) + assert.Regexp(t, "FF00175", err) + assert.NoError(t, mock.ExpectationsWereMet()) +} + func TestFFIDBFailInsert(t *testing.T) { - rows := sqlmock.NewRows([]string{"id", "namespace", "name", "version"}) s, mock := newMockProvider().init() mock.ExpectBegin() - mock.ExpectQuery("SELECT .*").WillReturnRows(rows) + mock.ExpectExec("INSERT .*").WillReturnError(fmt.Errorf("pop")) + mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{})) + mock.ExpectRollback() ffi := &fftypes.FFI{ ID: fftypes.NewUUID(), } - err := s.UpsertFFI(context.Background(), ffi) + _, err := s.InsertOrGetFFI(context.Background(), ffi) assert.Regexp(t, "FF00177", err) assert.NoError(t, mock.ExpectationsWereMet()) } @@ -141,7 +192,7 @@ func TestFFIDBFailUpdate(t *testing.T) { ffi := &fftypes.FFI{ ID: fftypes.NewUUID(), } - err := s.UpsertFFI(context.Background(), ffi) + err := s.UpsertFFI(context.Background(), ffi, database.UpsertOptimizationNew) assert.Regexp(t, "pop", err) } @@ -176,7 +227,7 @@ func TestGetFFIs(t *testing.T) { fb := database.FFIQueryFactory.NewFilter(context.Background()) s, mock := newMockProvider().init() rows := sqlmock.NewRows(ffiColumns). - AddRow("7e2c001c-e270-4fd7-9e82-9dacee843dc2", "ns1", "math", "v1.0.0", "super mathy things", "acfe07a2-117f-46b7-8d47-e3beb7cc382f") + AddRow("7e2c001c-e270-4fd7-9e82-9dacee843dc2", "ns1", "math", "math", "v1.0.0", "super mathy things", "acfe07a2-117f-46b7-8d47-e3beb7cc382f", false) mock.ExpectQuery("SELECT .*").WillReturnRows(rows) _, _, err := s.GetFFIs(context.Background(), "ns1", fb.And()) assert.NoError(t, err) @@ -214,7 +265,7 @@ func TestGetFFIsQueryResultFail(t *testing.T) { func TestGetFFI(t *testing.T) { s, mock := newMockProvider().init() rows := sqlmock.NewRows(ffiColumns). - AddRow("7e2c001c-e270-4fd7-9e82-9dacee843dc2", "ns1", "math", "v1.0.0", "super mathy things", "acfe07a2-117f-46b7-8d47-e3beb7cc382f") + AddRow("7e2c001c-e270-4fd7-9e82-9dacee843dc2", "ns1", "math", "math", "v1.0.0", "super mathy things", "acfe07a2-117f-46b7-8d47-e3beb7cc382f", false) mock.ExpectQuery("SELECT .*").WillReturnRows(rows) ffi, err := s.GetFFI(context.Background(), "ns1", "math", "v1.0.0") assert.NoError(t, err) @@ -223,3 +274,21 @@ func TestGetFFI(t *testing.T) { assert.Equal(t, "v1.0.0", ffi.Version) assert.NoError(t, mock.ExpectationsWereMet()) } + +func TestDeleteFFIFailBegin(t *testing.T) { + s, mock := newMockProvider().init() + mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) + err := s.DeleteFFI(context.Background(), "ns1", fftypes.NewUUID()) + assert.Regexp(t, "FF00175", err) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +func TestDeleteFFIFailDelete(t *testing.T) { + s, mock := newMockProvider().init() + mock.ExpectBegin() + mock.ExpectExec("DELETE .*").WillReturnError(fmt.Errorf("pop")) + mock.ExpectRollback() + err := s.DeleteFFI(context.Background(), "ns1", fftypes.NewUUID()) + assert.Regexp(t, "FF00179", err) + assert.NoError(t, mock.ExpectationsWereMet()) +} diff --git a/internal/definitions/handler_contracts.go b/internal/definitions/handler_contracts.go index e06886cf7..86e5c274f 100644 --- a/internal/definitions/handler_contracts.go +++ b/internal/definitions/handler_contracts.go @@ -18,6 +18,7 @@ package definitions import ( "context" + "fmt" "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly-common/pkg/i18n" @@ -27,14 +28,38 @@ import ( "github.com/hyperledger/firefly/pkg/database" ) -func (dh *definitionHandler) persistFFI(ctx context.Context, ffi *fftypes.FFI) (retry bool, err error) { - if err = dh.contracts.ResolveFFI(ctx, ffi); err != nil { - return false, i18n.WrapError(ctx, err, coremsgs.MsgDefRejectedValidateFail, "contract interface", ffi.ID) - } +func (dh *definitionHandler) persistFFI(ctx context.Context, ffi *fftypes.FFI, isAuthor bool) (retry bool, err error) { + for i := 1; ; i++ { + if err = dh.contracts.ResolveFFI(ctx, ffi); err != nil { + return false, i18n.WrapError(ctx, err, coremsgs.MsgDefRejectedValidateFail, "contract interface", ffi.ID) + } - err = dh.database.UpsertFFI(ctx, ffi) - if err != nil { - return true, err + // Check if this conflicts with an existing FFI + existing, err := dh.database.InsertOrGetFFI(ctx, ffi) + if err != nil { + return true, err + } + + if existing == nil { + // No conflict - new FFI was inserted successfully + break + } + + if ffi.Published { + if existing.ID.Equals(ffi.ID) { + // ID conflict - check if this matches (or should overwrite) the existing record + return dh.reconcilePublishedFFI(ctx, existing, ffi, isAuthor) + } + + if existing.Name == ffi.Name && existing.Version == ffi.Version { + // Local name conflict - generate a unique name and try again + ffi.Name = fmt.Sprintf("%s-%d", ffi.NetworkName, i) + continue + } + } + + // Any other conflict - reject + return false, i18n.NewError(ctx, coremsgs.MsgDefRejectedConflict, "contract interface", ffi.ID, existing.ID) } for _, method := range ffi.Methods { @@ -56,6 +81,24 @@ func (dh *definitionHandler) persistFFI(ctx context.Context, ffi *fftypes.FFI) ( return false, nil } +func (dh *definitionHandler) reconcilePublishedFFI(ctx context.Context, existing, ffi *fftypes.FFI, isAuthor bool) (retry bool, err error) { + if existing.Message.Equals(ffi.Message) { + // Message already recorded + return false, nil + } + + if existing.Message == nil && isAuthor { + // FFI was previously unpublished - if it was now published by this node, upsert the new version + ffi.Name = existing.Name + if err := dh.database.UpsertFFI(ctx, ffi, database.UpsertOptimizationExisting); err != nil { + return true, err + } + return false, nil + } + + return false, i18n.NewError(ctx, coremsgs.MsgDefRejectedConflict, "contract interface", ffi.ID, existing.ID) +} + func (dh *definitionHandler) persistContractAPI(ctx context.Context, httpServerURL string, api *core.ContractAPI) (retry bool, err error) { if err := dh.contracts.ResolveContractAPI(ctx, httpServerURL, api); err != nil { return false, i18n.WrapError(ctx, err, coremsgs.MsgDefRejectedValidateFail, "contract API", api.ID) @@ -76,18 +119,24 @@ func (dh *definitionHandler) handleFFIBroadcast(ctx context.Context, state *core if valid := dh.getSystemBroadcastPayload(ctx, msg, data, &ffi); !valid { return HandlerResult{Action: core.ActionReject}, i18n.NewError(ctx, coremsgs.MsgDefRejectedBadPayload, "contract interface", msg.Header.ID) } + + org, err := dh.identity.GetMultipartyRootOrg(ctx) + if err != nil { + return HandlerResult{Action: core.ActionRetry}, err + } + isAuthor := org.DID == msg.Header.Author + ffi.Message = msg.Header.ID - return dh.handleFFIDefinition(ctx, state, &ffi, tx) + ffi.Name = ffi.NetworkName + ffi.Published = true + return dh.handleFFIDefinition(ctx, state, &ffi, tx, isAuthor) } -func (dh *definitionHandler) handleFFIDefinition(ctx context.Context, state *core.BatchState, ffi *fftypes.FFI, tx *fftypes.UUID) (HandlerResult, error) { +func (dh *definitionHandler) handleFFIDefinition(ctx context.Context, state *core.BatchState, ffi *fftypes.FFI, tx *fftypes.UUID, isAuthor bool) (HandlerResult, error) { l := log.L(ctx) - ffi.Namespace = dh.namespace.Name - if err := ffi.Validate(ctx); err != nil { - return HandlerResult{Action: core.ActionReject}, i18n.WrapError(ctx, err, coremsgs.MsgDefRejectedValidateFail, "contract interface", ffi.ID) - } - if retry, err := dh.persistFFI(ctx, ffi); err != nil { + ffi.Namespace = dh.namespace.Name + if retry, err := dh.persistFFI(ctx, ffi, isAuthor); err != nil { if retry { return HandlerResult{Action: core.ActionRetry}, err } diff --git a/internal/definitions/handler_contracts_test.go b/internal/definitions/handler_contracts_test.go index c5c1214df..86e879139 100644 --- a/internal/definitions/handler_contracts_test.go +++ b/internal/definitions/handler_contracts_test.go @@ -23,8 +23,6 @@ import ( "testing" "github.com/hyperledger/firefly-common/pkg/fftypes" - "github.com/hyperledger/firefly/mocks/contractmocks" - "github.com/hyperledger/firefly/mocks/databasemocks" "github.com/hyperledger/firefly/pkg/core" "github.com/hyperledger/firefly/pkg/database" "github.com/stretchr/testify/assert" @@ -33,10 +31,12 @@ import ( func testFFI() *fftypes.FFI { return &fftypes.FFI{ - ID: fftypes.NewUUID(), - Namespace: "ns1", - Name: "math", - Version: "v1.0.0", + ID: fftypes.NewUUID(), + Namespace: "ns1", + Name: "math", + NetworkName: "math", + Version: "v1.0.0", + Published: true, Methods: []*fftypes.FFIMethod{ { Name: "sum", @@ -103,6 +103,7 @@ func testContractAPI() *core.ContractAPI { func TestHandleFFIBroadcastOk(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) b, err := json.Marshal(testFFI()) assert.NoError(t, err) @@ -110,48 +111,152 @@ func TestHandleFFIBroadcastOk(t *testing.T) { Value: fftypes.JSONAnyPtrBytes(b), } - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("UpsertFFI", mock.Anything, mock.Anything).Return(nil) - mdi.On("UpsertFFIMethod", mock.Anything, mock.Anything).Return(nil) - mdi.On("UpsertFFIEvent", mock.Anything, mock.Anything).Return(nil) - mdi.On("UpsertFFIError", mock.Anything, mock.Anything).Return(nil) - mdi.On("InsertEvent", mock.Anything, mock.Anything).Return(nil) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.Anything).Return(nil, nil) + dh.mdi.On("UpsertFFIMethod", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("UpsertFFIEvent", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("UpsertFFIError", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("InsertEvent", mock.Anything, mock.Anything).Return(nil) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + dh.mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ + IdentityBase: core.IdentityBase{ + DID: "firefly:org1", + }, + }, nil) + + action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ + Header: core.MessageHeader{ + Tag: core.SystemTagDefineFFI, + }, + }, core.DataArray{data}, fftypes.NewUUID()) + assert.NoError(t, err) + assert.Equal(t, HandlerResult{Action: core.ActionConfirm}, action) + err = bs.RunFinalize(context.Background()) + assert.NoError(t, err) +} + +func TestHandleFFIBroadcastUpdate(t *testing.T) { + dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + + ffi := testFFI() + b, err := json.Marshal(ffi) + assert.NoError(t, err) + data := &core.Data{ + Value: fftypes.JSONAnyPtrBytes(b), + } + + existing := &fftypes.FFI{ + ID: ffi.ID, + Message: ffi.Message, + } + + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.Anything).Return(existing, nil) + dh.mdi.On("InsertEvent", mock.Anything, mock.Anything).Return(nil) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + dh.mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ + IdentityBase: core.IdentityBase{ + DID: "firefly:org1", + }, + }, nil) + + action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ + Header: core.MessageHeader{ + Tag: core.SystemTagDefineFFI, + }, + }, core.DataArray{data}, fftypes.NewUUID()) + assert.NoError(t, err) + assert.Equal(t, HandlerResult{Action: core.ActionConfirm}, action) + err = bs.RunFinalize(context.Background()) + assert.NoError(t, err) +} + +func TestHandleFFIBroadcastNameExists(t *testing.T) { + dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + + ffi := testFFI() + existing := &fftypes.FFI{ + Name: ffi.Name, + Version: ffi.Version, + } + + b, err := json.Marshal(ffi) + assert.NoError(t, err) + data := &core.Data{ + Value: fftypes.JSONAnyPtrBytes(b), + } + + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.MatchedBy(func(f *fftypes.FFI) bool { + return f.Name == "math" + })).Return(existing, nil) + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.MatchedBy(func(f *fftypes.FFI) bool { + return f.Name == "math-1" + })).Return(nil, nil) + dh.mdi.On("UpsertFFIMethod", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("UpsertFFIEvent", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("UpsertFFIError", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("InsertEvent", mock.Anything, mock.Anything).Return(nil) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + dh.mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ + IdentityBase: core.IdentityBase{ + DID: "firefly:org1", + }, + }, nil) action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ Tag: core.SystemTagDefineFFI, }, }, core.DataArray{data}, fftypes.NewUUID()) + assert.NoError(t, err) assert.Equal(t, HandlerResult{Action: core.ActionConfirm}, action) + err = bs.RunFinalize(context.Background()) assert.NoError(t, err) +} + +func TestHandleFFILocalNameExists(t *testing.T) { + dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + + ffi := testFFI() + ffi.Published = false + existing := &fftypes.FFI{ + Name: ffi.Name, + Version: ffi.Version, + } + + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.MatchedBy(func(f *fftypes.FFI) bool { + return f.Name == "math" + })).Return(existing, nil) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + + action, err := dh.handleFFIDefinition(context.Background(), &bs.BatchState, ffi, fftypes.NewUUID(), true) + assert.Regexp(t, "FF10407", err) + assert.Equal(t, HandlerResult{Action: core.ActionReject}, action) err = bs.RunFinalize(context.Background()) assert.NoError(t, err) - mdi.AssertExpectations(t) } func TestPersistFFIValidateFFIFail(t *testing.T) { dh, _ := newTestDefinitionHandler(t) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - retry, err := dh.persistFFI(context.Background(), testFFI()) + defer dh.cleanup(t) + + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + retry, err := dh.persistFFI(context.Background(), testFFI(), true) assert.Regexp(t, "FF10403", err) assert.False(t, retry) - mcm.AssertExpectations(t) } func TestHandleFFIBroadcastReject(t *testing.T) { dh, bs := newTestDefinitionHandler(t) - mdi := dh.database.(*databasemocks.Plugin) - mcm := dh.contracts.(*contractmocks.Manager) - mdi.On("InsertEvent", mock.Anything, mock.Anything).Return(nil) - mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + defer dh.cleanup(t) + action, err := dh.handleFFIBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ Tag: core.SystemTagDefineFFI, }, }, core.DataArray{}, fftypes.NewUUID()) + assert.Equal(t, HandlerResult{Action: core.ActionReject}, action) assert.Error(t, err) bs.assertNoFinalizers() @@ -159,95 +264,153 @@ func TestHandleFFIBroadcastReject(t *testing.T) { func TestPersistFFIUpsertFFIFail(t *testing.T) { dh, _ := newTestDefinitionHandler(t) - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("UpsertFFI", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) - retry, err := dh.persistFFI(context.Background(), testFFI()) + defer dh.cleanup(t) + + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("pop")) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + retry, err := dh.persistFFI(context.Background(), testFFI(), true) assert.Regexp(t, "pop", err) assert.True(t, retry) - mdi.AssertExpectations(t) - mcm.AssertExpectations(t) } func TestPersistFFIUpsertFFIMethodFail(t *testing.T) { dh, _ := newTestDefinitionHandler(t) - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("UpsertFFI", mock.Anything, mock.Anything).Return(nil) - mdi.On("UpsertFFIMethod", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) - retry, err := dh.persistFFI(context.Background(), testFFI()) + defer dh.cleanup(t) + + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.Anything).Return(nil, nil) + dh.mdi.On("UpsertFFIMethod", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + retry, err := dh.persistFFI(context.Background(), testFFI(), true) assert.Regexp(t, "pop", err) assert.True(t, retry) - mdi.AssertExpectations(t) - mcm.AssertExpectations(t) } func TestPersistFFIUpsertFFIEventFail(t *testing.T) { dh, _ := newTestDefinitionHandler(t) - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("UpsertFFI", mock.Anything, mock.Anything).Return(nil) - mdi.On("UpsertFFIMethod", mock.Anything, mock.Anything).Return(nil) - mdi.On("UpsertFFIEvent", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) - retry, err := dh.persistFFI(context.Background(), testFFI()) + defer dh.cleanup(t) + + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.Anything).Return(nil, nil) + dh.mdi.On("UpsertFFIMethod", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("UpsertFFIEvent", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + retry, err := dh.persistFFI(context.Background(), testFFI(), true) assert.Regexp(t, "pop", err) assert.True(t, retry) - mdi.AssertExpectations(t) - mcm.AssertExpectations(t) } func TestPersistFFIUpsertFFIErrorFail(t *testing.T) { dh, _ := newTestDefinitionHandler(t) - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("UpsertFFI", mock.Anything, mock.Anything).Return(nil) - mdi.On("UpsertFFIMethod", mock.Anything, mock.Anything).Return(nil) - mdi.On("UpsertFFIEvent", mock.Anything, mock.Anything).Return(nil) - mdi.On("UpsertFFIError", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) - retry, err := dh.persistFFI(context.Background(), testFFI()) + defer dh.cleanup(t) + + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.Anything).Return(nil, nil) + dh.mdi.On("UpsertFFIMethod", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("UpsertFFIEvent", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("UpsertFFIError", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + retry, err := dh.persistFFI(context.Background(), testFFI(), true) assert.Regexp(t, "pop", err) assert.True(t, retry) - mdi.AssertExpectations(t) - mcm.AssertExpectations(t) } -func TestHandleFFIBroadcastValidateFail(t *testing.T) { +func TestPersistFFILocalPublish(t *testing.T) { + dh, _ := newTestDefinitionHandler(t) + defer dh.cleanup(t) + + published := testFFI() + published.Message = fftypes.NewUUID() + existing := &fftypes.FFI{ + ID: published.ID, + } + + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.Anything).Return(existing, nil) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("UpsertFFI", mock.Anything, published, database.UpsertOptimizationExisting).Return(nil) + + retry, err := dh.persistFFI(context.Background(), published, true) + assert.NoError(t, err) + assert.False(t, retry) +} + +func TestPersistFFILocalPublishUpsertFail(t *testing.T) { + dh, _ := newTestDefinitionHandler(t) + defer dh.cleanup(t) + + published := testFFI() + published.Message = fftypes.NewUUID() + existing := &fftypes.FFI{ + ID: published.ID, + } + + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.Anything).Return(existing, nil) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("UpsertFFI", mock.Anything, published, database.UpsertOptimizationExisting).Return(fmt.Errorf("pop")) + + retry, err := dh.persistFFI(context.Background(), published, true) + assert.EqualError(t, err, "pop") + assert.True(t, retry) +} + +func TestPersistFFIWrongMessage(t *testing.T) { + dh, _ := newTestDefinitionHandler(t) + defer dh.cleanup(t) + + published := testFFI() + published.Message = fftypes.NewUUID() + existing := &fftypes.FFI{ + ID: published.ID, + Message: fftypes.NewUUID(), + } + + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.Anything).Return(existing, nil) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + + retry, err := dh.persistFFI(context.Background(), published, true) + assert.Regexp(t, "FF10407", err) + assert.False(t, retry) +} + +func TestHandleFFIBroadcastOrgFail(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + ffi := testFFI() - ffi.Name = "*%^!$%^&*" b, err := json.Marshal(ffi) assert.NoError(t, err) data := &core.Data{ Value: fftypes.JSONAnyPtrBytes(b), } - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("InsertEvent", mock.Anything, mock.Anything).Return(nil) + + dh.mim.On("GetMultipartyRootOrg", context.Background()).Return(nil, fmt.Errorf("pop")) + action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ Tag: core.SystemTagDefineFFI, }, }, core.DataArray{data}, fftypes.NewUUID()) - assert.Equal(t, HandlerResult{Action: core.ActionReject}, action) - assert.Error(t, err) + + assert.Equal(t, HandlerResult{Action: core.ActionRetry}, action) + assert.Regexp(t, "pop", err) bs.assertNoFinalizers() } func TestHandleFFIBroadcastPersistFail(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + ffi := testFFI() b, err := json.Marshal(ffi) assert.NoError(t, err) data := &core.Data{ Value: fftypes.JSONAnyPtrBytes(b), } - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("UpsertFFI", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("InsertOrGetFFI", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("pop")) + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(nil) + dh.mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ + IdentityBase: core.IdentityBase{ + DID: "firefly:org1", + }, + }, nil) + action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ Tag: core.SystemTagDefineFFI, @@ -256,35 +419,40 @@ func TestHandleFFIBroadcastPersistFail(t *testing.T) { assert.Equal(t, HandlerResult{Action: core.ActionRetry}, action) assert.Regexp(t, "pop", err) bs.assertNoFinalizers() - - mdi.AssertExpectations(t) - mcm.AssertExpectations(t) } func TestHandleFFIBroadcastResolveFail(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + ffi := testFFI() b, err := json.Marshal(ffi) assert.NoError(t, err) data := &core.Data{ Value: fftypes.JSONAnyPtrBytes(b), } - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + + dh.mcm.On("ResolveFFI", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + dh.mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ + IdentityBase: core.IdentityBase{ + DID: "firefly:org1", + }, + }, nil) + action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ Tag: core.SystemTagDefineFFI, }, }, core.DataArray{data}, fftypes.NewUUID()) + assert.Equal(t, HandlerResult{Action: core.ActionReject}, action) assert.Regexp(t, "pop", err) bs.assertNoFinalizers() - - mcm.AssertExpectations(t) } func TestHandleContractAPIBroadcastOk(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) b, err := json.Marshal(testFFI()) assert.NoError(t, err) @@ -292,11 +460,9 @@ func TestHandleContractAPIBroadcastOk(t *testing.T) { Value: fftypes.JSONAnyPtrBytes(b), } - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("UpsertContractAPI", mock.Anything, mock.Anything, mock.Anything).Return(nil) - mdi.On("InsertEvent", mock.Anything, mock.Anything).Return(nil) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveContractAPI", context.Background(), "", mock.Anything).Return(nil) + dh.mdi.On("UpsertContractAPI", mock.Anything, mock.Anything, mock.Anything).Return(nil) + dh.mdi.On("InsertEvent", mock.Anything, mock.Anything).Return(nil) + dh.mcm.On("ResolveContractAPI", context.Background(), "", mock.Anything).Return(nil) action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ @@ -307,13 +473,12 @@ func TestHandleContractAPIBroadcastOk(t *testing.T) { assert.NoError(t, err) err = bs.RunFinalize(context.Background()) assert.NoError(t, err) - - mdi.AssertExpectations(t) - mcm.AssertExpectations(t) } func TestHandleContractAPIBadPayload(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + data := &core.Data{ Value: fftypes.JSONAnyPtr("bad"), } @@ -329,6 +494,7 @@ func TestHandleContractAPIBadPayload(t *testing.T) { func TestHandleContractAPIIDMismatch(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) b, err := json.Marshal(testFFI()) assert.NoError(t, err) @@ -336,10 +502,8 @@ func TestHandleContractAPIIDMismatch(t *testing.T) { Value: fftypes.JSONAnyPtrBytes(b), } - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("UpsertContractAPI", mock.Anything, mock.Anything, mock.Anything).Return(database.IDMismatch) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveContractAPI", context.Background(), "", mock.Anything).Return(nil) + dh.mdi.On("UpsertContractAPI", mock.Anything, mock.Anything, mock.Anything).Return(database.IDMismatch) + dh.mcm.On("ResolveContractAPI", context.Background(), "", mock.Anything).Return(nil) action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ @@ -348,27 +512,23 @@ func TestHandleContractAPIIDMismatch(t *testing.T) { }, core.DataArray{data}, fftypes.NewUUID()) assert.Equal(t, HandlerResult{Action: core.ActionReject}, action) assert.Regexp(t, "FF10404", err) - - mdi.AssertExpectations(t) - mcm.AssertExpectations(t) } func TestPersistContractAPIUpsertFail(t *testing.T) { dh, _ := newTestDefinitionHandler(t) - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("UpsertContractAPI", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveContractAPI", context.Background(), "http://test", mock.Anything).Return(nil) + defer dh.cleanup(t) + + dh.mdi.On("UpsertContractAPI", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + dh.mcm.On("ResolveContractAPI", context.Background(), "http://test", mock.Anything).Return(nil) _, err := dh.persistContractAPI(context.Background(), "http://test", testContractAPI()) assert.Regexp(t, "pop", err) - - mdi.AssertExpectations(t) - mcm.AssertExpectations(t) } func TestHandleContractAPIBroadcastValidateFail(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + api := testContractAPI() api.Name = "*%^!$%^&*" b, err := json.Marshal(api) @@ -376,13 +536,13 @@ func TestHandleContractAPIBroadcastValidateFail(t *testing.T) { data := &core.Data{ Value: fftypes.JSONAnyPtrBytes(b), } - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("InsertEvent", mock.Anything, mock.Anything).Return(nil) + action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ Tag: core.SystemTagDefineContractAPI, }, }, core.DataArray{data}, fftypes.NewUUID()) + assert.Equal(t, HandlerResult{Action: core.ActionReject}, action) assert.Error(t, err) bs.assertNoFinalizers() @@ -390,16 +550,16 @@ func TestHandleContractAPIBroadcastValidateFail(t *testing.T) { func TestHandleContractAPIBroadcastPersistFail(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + ffi := testFFI() b, err := json.Marshal(ffi) assert.NoError(t, err) data := &core.Data{ Value: fftypes.JSONAnyPtrBytes(b), } - mdi := dh.database.(*databasemocks.Plugin) - mdi.On("UpsertContractAPI", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveContractAPI", context.Background(), "", mock.Anything).Return(nil) + dh.mdi.On("UpsertContractAPI", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + dh.mcm.On("ResolveContractAPI", context.Background(), "", mock.Anything).Return(nil) action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ @@ -410,21 +570,19 @@ func TestHandleContractAPIBroadcastPersistFail(t *testing.T) { assert.Regexp(t, "pop", err) bs.assertNoFinalizers() - - mdi.AssertExpectations(t) - mcm.AssertExpectations(t) } func TestHandleContractAPIBroadcastResolveFail(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + ffi := testFFI() b, err := json.Marshal(ffi) assert.NoError(t, err) data := &core.Data{ Value: fftypes.JSONAnyPtrBytes(b), } - mcm := dh.contracts.(*contractmocks.Manager) - mcm.On("ResolveContractAPI", context.Background(), "", mock.Anything).Return(fmt.Errorf("pop")) + dh.mcm.On("ResolveContractAPI", context.Background(), "", mock.Anything).Return(fmt.Errorf("pop")) action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ @@ -435,6 +593,4 @@ func TestHandleContractAPIBroadcastResolveFail(t *testing.T) { assert.Regexp(t, "pop", err) bs.assertNoFinalizers() - - mcm.AssertExpectations(t) } diff --git a/internal/definitions/handler_test.go b/internal/definitions/handler_test.go index 0a4164cc7..44559f039 100644 --- a/internal/definitions/handler_test.go +++ b/internal/definitions/handler_test.go @@ -33,7 +33,29 @@ import ( "github.com/stretchr/testify/assert" ) -func newTestDefinitionHandler(t *testing.T) (*definitionHandler, *testDefinitionBatchState) { +type testDefinitionHandler struct { + definitionHandler + + mdi *databasemocks.Plugin + mbi *blockchainmocks.Plugin + mdx *dataexchangemocks.Plugin + mim *identitymanagermocks.Manager + mdm *datamocks.Manager + mam *assetmocks.Manager + mcm *contractmocks.Manager +} + +func (tdh *testDefinitionHandler) cleanup(t *testing.T) { + tdh.mdi.AssertExpectations(t) + tdh.mbi.AssertExpectations(t) + tdh.mdx.AssertExpectations(t) + tdh.mim.AssertExpectations(t) + tdh.mdm.AssertExpectations(t) + tdh.mam.AssertExpectations(t) + tdh.mcm.AssertExpectations(t) +} + +func newTestDefinitionHandler(t *testing.T) (*testDefinitionHandler, *testDefinitionBatchState) { mdi := &databasemocks.Plugin{} mbi := &blockchainmocks.Plugin{} mdx := &dataexchangemocks.Plugin{} @@ -46,7 +68,16 @@ func newTestDefinitionHandler(t *testing.T) (*definitionHandler, *testDefinition mbi.On("VerifierType").Return(core.VerifierTypeEthAddress).Maybe() ns := &core.Namespace{Name: "ns1", NetworkName: "ns1"} dh, _ := newDefinitionHandler(context.Background(), ns, false, mdi, mbi, mdx, mdm, mim, mam, mcm, tokenNames) - return dh, newTestDefinitionBatchState(t) + return &testDefinitionHandler{ + definitionHandler: *dh, + mdi: mdi, + mbi: mbi, + mdx: mdx, + mim: mim, + mdm: mdm, + mam: mam, + mcm: mcm, + }, newTestDefinitionBatchState(t) } type testDefinitionBatchState struct { @@ -77,6 +108,8 @@ func TestInitFail(t *testing.T) { func TestHandleDefinitionBroadcastUnknown(t *testing.T) { dh, bs := newTestDefinitionHandler(t) + defer dh.cleanup(t) + action, err := dh.HandleDefinitionBroadcast(context.Background(), &bs.BatchState, &core.Message{ Header: core.MessageHeader{ Tag: "unknown", @@ -89,6 +122,8 @@ func TestHandleDefinitionBroadcastUnknown(t *testing.T) { func TestGetSystemBroadcastPayloadMissingData(t *testing.T) { dh, _ := newTestDefinitionHandler(t) + defer dh.cleanup(t) + valid := dh.getSystemBroadcastPayload(context.Background(), &core.Message{ Header: core.MessageHeader{ Tag: "unknown", @@ -99,6 +134,8 @@ func TestGetSystemBroadcastPayloadMissingData(t *testing.T) { func TestGetSystemBroadcastPayloadBadJSON(t *testing.T) { dh, _ := newTestDefinitionHandler(t) + defer dh.cleanup(t) + valid := dh.getSystemBroadcastPayload(context.Background(), &core.Message{ Header: core.MessageHeader{ Tag: "unknown", diff --git a/internal/definitions/sender.go b/internal/definitions/sender.go index 79f19e22a..5417b5146 100644 --- a/internal/definitions/sender.go +++ b/internal/definitions/sender.go @@ -44,6 +44,7 @@ type Sender interface { DefineTokenPool(ctx context.Context, pool *core.TokenPool, waitConfirm bool) error PublishTokenPool(ctx context.Context, poolNameOrID, networkName string, waitConfirm bool) (*core.TokenPool, error) DefineFFI(ctx context.Context, ffi *fftypes.FFI, waitConfirm bool) error + PublishFFI(ctx context.Context, name, version, networkName string, waitConfirm bool) (*fftypes.FFI, error) DefineContractAPI(ctx context.Context, httpServerURL string, api *core.ContractAPI, waitConfirm bool) error } diff --git a/internal/definitions/sender_contracts.go b/internal/definitions/sender_contracts.go index 4799e0855..e3de33409 100644 --- a/internal/definitions/sender_contracts.go +++ b/internal/definitions/sender_contracts.go @@ -18,8 +18,11 @@ package definitions import ( "context" + "errors" "github.com/hyperledger/firefly-common/pkg/fftypes" + "github.com/hyperledger/firefly-common/pkg/i18n" + "github.com/hyperledger/firefly/internal/coremsgs" "github.com/hyperledger/firefly/pkg/core" ) @@ -35,25 +38,87 @@ func (ds *definitionSender) DefineFFI(ctx context.Context, ffi *fftypes.FFI, wai errorDef.ID = fftypes.NewUUID() } - if ds.multiparty { - if err := ds.contracts.ResolveFFI(ctx, ffi); err != nil { - return err - } - - ffi.Namespace = "" - msg, err := ds.getSenderDefault(ctx, ffi, core.SystemTagDefineFFI).send(ctx, waitConfirm) - if msg != nil { - ffi.Message = msg.Header.ID + if ffi.Published { + if !ds.multiparty { + return i18n.NewError(ctx, coremsgs.MsgActionNotSupported) } - ffi.Namespace = ds.namespace + _, err := ds.getFFISender(ctx, ffi).send(ctx, waitConfirm) return err } + ffi.NetworkName = "" + return fakeBatch(ctx, func(ctx context.Context, state *core.BatchState) (HandlerResult, error) { - return ds.handler.handleFFIDefinition(ctx, state, ffi, nil) + hr, err := ds.handler.handleFFIDefinition(ctx, state, ffi, nil, true) + if err != nil { + if innerErr := errors.Unwrap(err); innerErr != nil { + return hr, innerErr + } + } + return hr, err }) } +func (ds *definitionSender) getFFISender(ctx context.Context, ffi *fftypes.FFI) *sendWrapper { + if err := ds.contracts.ResolveFFI(ctx, ffi); err != nil { + return wrapSendError(err) + } + + if ffi.NetworkName == "" { + ffi.NetworkName = ffi.Name + } + + existing, err := ds.database.GetFFIByNetworkName(ctx, ds.namespace, ffi.NetworkName, ffi.Version) + if err != nil { + return wrapSendError(err) + } else if existing != nil { + return wrapSendError(i18n.NewError(ctx, coremsgs.MsgNetworkNameExists)) + } + + // Prepare the FFI definition to be serialized for broadcast + localName := ffi.Name + ffi.Name = "" + ffi.Namespace = "" + ffi.Published = true + + sender := ds.getSenderDefault(ctx, ffi, core.SystemTagDefineFFI) + if sender.message != nil { + ffi.Message = sender.message.Header.ID + } + + ffi.Name = localName + ffi.Namespace = ds.namespace + return sender +} + +func (ds *definitionSender) PublishFFI(ctx context.Context, name, version, networkName string, waitConfirm bool) (ffi *fftypes.FFI, err error) { + if !ds.multiparty { + return nil, i18n.NewError(ctx, coremsgs.MsgActionNotSupported) + } + + var sender *sendWrapper + err = ds.database.RunAsGroup(ctx, func(ctx context.Context) error { + if ffi, err = ds.contracts.GetFFI(ctx, name, version); err != nil { + return err + } + if ffi.Published { + return i18n.NewError(ctx, coremsgs.MsgAlreadyPublished) + } + ffi.NetworkName = networkName + sender = ds.getFFISender(ctx, ffi) + if sender.err != nil { + return sender.err + } + return sender.sender.Prepare(ctx) + }) + if err != nil { + return nil, err + } + + _, err = sender.send(ctx, waitConfirm) + return ffi, err +} + func (ds *definitionSender) DefineContractAPI(ctx context.Context, httpServerURL string, api *core.ContractAPI, waitConfirm bool) error { if api.ID == nil { api.ID = fftypes.NewUUID() diff --git a/internal/definitions/sender_contracts_test.go b/internal/definitions/sender_contracts_test.go index 367f3837d..185cb5766 100644 --- a/internal/definitions/sender_contracts_test.go +++ b/internal/definitions/sender_contracts_test.go @@ -22,9 +22,6 @@ import ( "testing" "github.com/hyperledger/firefly-common/pkg/fftypes" - "github.com/hyperledger/firefly/mocks/broadcastmocks" - "github.com/hyperledger/firefly/mocks/contractmocks" - "github.com/hyperledger/firefly/mocks/identitymanagermocks" "github.com/hyperledger/firefly/mocks/syncasyncmocks" "github.com/hyperledger/firefly/pkg/core" "github.com/stretchr/testify/assert" @@ -32,193 +29,245 @@ import ( ) func TestDefineFFIResolveFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true ffi := &fftypes.FFI{ - Methods: []*fftypes.FFIMethod{{}}, - Events: []*fftypes.FFIEvent{{}}, - Errors: []*fftypes.FFIError{{}}, + Name: "ffi1", + Version: "1.0", + Methods: []*fftypes.FFIMethod{{}}, + Events: []*fftypes.FFIEvent{{}}, + Errors: []*fftypes.FFIError{{}}, + Published: true, } - mcm := ds.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", context.Background(), ffi).Return(fmt.Errorf("pop")) + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(fmt.Errorf("pop")) err := ds.DefineFFI(context.Background(), ffi, false) assert.EqualError(t, err, "pop") - - mcm.AssertExpectations(t) } func TestDefineFFIFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true - ffi := &fftypes.FFI{} - - mcm := ds.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + Published: true, + } - mim := ds.identity.(*identitymanagermocks.Manager) - mim.On("GetMultipartyRootOrg", context.Background()).Return(nil, fmt.Errorf("pop")) + ds.mdi.On("GetFFIByNetworkName", context.Background(), "ns1", "ffi1", "1.0").Return(nil, nil) + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + ds.mim.On("GetMultipartyRootOrg", context.Background()).Return(nil, fmt.Errorf("pop")) err := ds.DefineFFI(context.Background(), ffi, false) assert.EqualError(t, err, "pop") +} + +func TestDefineFFIExists(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = true - mcm.AssertExpectations(t) - mim.AssertExpectations(t) + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + Published: true, + } + + ds.mdi.On("GetFFIByNetworkName", context.Background(), "ns1", "ffi1", "1.0").Return(&fftypes.FFI{}, nil) + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + + err := ds.DefineFFI(context.Background(), ffi, false) + assert.Regexp(t, "FF10448", err) } -func TestDefineFFIOk(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() +func TestDefineFFIQueryFail(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true - ffi := &fftypes.FFI{} + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + Published: true, + } + + ds.mdi.On("GetFFIByNetworkName", context.Background(), "ns1", "ffi1", "1.0").Return(nil, fmt.Errorf("pop")) + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + + err := ds.DefineFFI(context.Background(), ffi, false) + assert.EqualError(t, err, "pop") +} + +func TestDefineFFIOk(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = true - mcm := ds.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + Published: true, + } - mim := ds.identity.(*identitymanagermocks.Manager) - mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ + ds.mdi.On("GetFFIByNetworkName", context.Background(), "ns1", "ffi1", "1.0").Return(nil, nil) + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + ds.mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ IdentityBase: core.IdentityBase{ DID: "firefly:org1", }, }, nil) - mim.On("ResolveInputSigningIdentity", context.Background(), mock.Anything).Return(nil) + ds.mim.On("ResolveInputSigningIdentity", context.Background(), mock.Anything).Return(nil) - mbm := ds.broadcast.(*broadcastmocks.Manager) mms := &syncasyncmocks.Sender{} - mbm.On("NewBroadcast", mock.Anything).Return(mms) + ds.mbm.On("NewBroadcast", mock.Anything).Return(mms) mms.On("Send", context.Background()).Return(nil) err := ds.DefineFFI(context.Background(), ffi, false) assert.NoError(t, err) - mcm.AssertExpectations(t) - mim.AssertExpectations(t) - mbm.AssertExpectations(t) mms.AssertExpectations(t) } func TestDefineFFIConfirm(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true - ffi := &fftypes.FFI{} - - mcm := ds.contracts.(*contractmocks.Manager) - mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + Published: true, + } - mim := ds.identity.(*identitymanagermocks.Manager) - mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ + ds.mdi.On("GetFFIByNetworkName", context.Background(), "ns1", "ffi1", "1.0").Return(nil, nil) + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + ds.mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ IdentityBase: core.IdentityBase{ DID: "firefly:org1", }, }, nil) - mim.On("ResolveInputSigningIdentity", context.Background(), mock.Anything).Return(nil) + ds.mim.On("ResolveInputSigningIdentity", context.Background(), mock.Anything).Return(nil) - mbm := ds.broadcast.(*broadcastmocks.Manager) mms := &syncasyncmocks.Sender{} - mbm.On("NewBroadcast", mock.Anything).Return(mms) + ds.mbm.On("NewBroadcast", mock.Anything).Return(mms) mms.On("SendAndWait", context.Background()).Return(nil) err := ds.DefineFFI(context.Background(), ffi, true) assert.NoError(t, err) - mcm.AssertExpectations(t) - mim.AssertExpectations(t) - mbm.AssertExpectations(t) mms.AssertExpectations(t) } +func TestDefineFFIPublishNonMultiparty(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = false + + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + Published: true, + } + + err := ds.DefineFFI(context.Background(), ffi, false) + assert.Regexp(t, "FF10414", err) +} + func TestDefineFFINonMultiparty(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + } + + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + ds.mdi.On("InsertOrGetFFI", context.Background(), ffi).Return(nil, nil) + ds.mdi.On("InsertEvent", context.Background(), mock.Anything).Return(nil) + + err := ds.DefineFFI(context.Background(), ffi, false) + assert.NoError(t, err) +} + +func TestDefineFFINonMultipartyFail(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) - ffi := &fftypes.FFI{} + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + } + + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(fmt.Errorf("pop")) err := ds.DefineFFI(context.Background(), ffi, false) assert.Regexp(t, "FF10403", err) } func TestDefineContractAPIResolveFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true url := "http://firefly" api := &core.ContractAPI{} - mcm := ds.contracts.(*contractmocks.Manager) - mcm.On("ResolveContractAPI", context.Background(), url, api).Return(fmt.Errorf("pop")) + ds.mcm.On("ResolveContractAPI", context.Background(), url, api).Return(fmt.Errorf("pop")) err := ds.DefineContractAPI(context.Background(), url, api, false) assert.EqualError(t, err, "pop") - - mcm.AssertExpectations(t) } func TestDefineContractAPIFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true url := "http://firefly" api := &core.ContractAPI{} - mcm := ds.contracts.(*contractmocks.Manager) - mcm.On("ResolveContractAPI", context.Background(), url, api).Return(nil) - - mim := ds.identity.(*identitymanagermocks.Manager) - mim.On("GetMultipartyRootOrg", context.Background()).Return(nil, fmt.Errorf("pop")) + ds.mcm.On("ResolveContractAPI", context.Background(), url, api).Return(nil) + ds.mim.On("GetMultipartyRootOrg", context.Background()).Return(nil, fmt.Errorf("pop")) err := ds.DefineContractAPI(context.Background(), url, api, false) assert.EqualError(t, err, "pop") - - mcm.AssertExpectations(t) - mim.AssertExpectations(t) } func TestDefineContractAPIOk(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true url := "http://firefly" api := &core.ContractAPI{} - mcm := ds.contracts.(*contractmocks.Manager) - mcm.On("ResolveContractAPI", context.Background(), url, api).Return(nil) - - mim := ds.identity.(*identitymanagermocks.Manager) - mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ + ds.mcm.On("ResolveContractAPI", context.Background(), url, api).Return(nil) + ds.mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ IdentityBase: core.IdentityBase{ DID: "firefly:org1", }, }, nil) - mim.On("ResolveInputSigningIdentity", context.Background(), mock.Anything).Return(nil) + ds.mim.On("ResolveInputSigningIdentity", context.Background(), mock.Anything).Return(nil) - mbm := ds.broadcast.(*broadcastmocks.Manager) mms := &syncasyncmocks.Sender{} - mbm.On("NewBroadcast", mock.Anything).Return(mms) + ds.mbm.On("NewBroadcast", mock.Anything).Return(mms) mms.On("Send", context.Background()).Return(nil) err := ds.DefineContractAPI(context.Background(), url, api, false) assert.NoError(t, err) - mcm.AssertExpectations(t) - mim.AssertExpectations(t) - mbm.AssertExpectations(t) mms.AssertExpectations(t) } func TestDefineContractAPINonMultiparty(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) url := "http://firefly" api := &core.ContractAPI{} @@ -226,3 +275,132 @@ func TestDefineContractAPINonMultiparty(t *testing.T) { err := ds.DefineContractAPI(context.Background(), url, api, false) assert.Regexp(t, "FF10403", err) } + +func TestPublishFFI(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = true + + mms := &syncasyncmocks.Sender{} + + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + Namespace: "ns1", + Published: false, + } + + ds.mdi.On("GetFFIByNetworkName", context.Background(), "ns1", "ffi1-shared", "1.0").Return(nil, nil) + ds.mcm.On("GetFFI", context.Background(), "ffi1", "1.0").Return(ffi, nil) + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + ds.mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ + IdentityBase: core.IdentityBase{ + DID: "firefly:org1", + }, + }, nil) + ds.mim.On("ResolveInputSigningIdentity", mock.Anything, mock.Anything).Return(nil) + ds.mbm.On("NewBroadcast", mock.Anything).Return(mms) + mms.On("Prepare", context.Background()).Return(nil) + mms.On("Send", context.Background()).Return(nil) + mockRunAsGroupPassthrough(ds.mdi) + + result, err := ds.PublishFFI(context.Background(), "ffi1", "1.0", "ffi1-shared", false) + assert.NoError(t, err) + assert.Equal(t, ffi, result) + assert.True(t, ffi.Published) + + mms.AssertExpectations(t) +} + +func TestPublishFFIAlreadyPublished(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = true + + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + Namespace: "ns1", + Published: true, + } + + ds.mcm.On("GetFFI", context.Background(), "ffi1", "1.0").Return(ffi, nil) + mockRunAsGroupPassthrough(ds.mdi) + + _, err := ds.PublishFFI(context.Background(), "ffi1", "1.0", "ffi1-shared", false) + assert.Regexp(t, "FF10450", err) +} + +func TestPublishFFIQueryFail(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = true + + ds.mcm.On("GetFFI", context.Background(), "ffi1", "1.0").Return(nil, fmt.Errorf("pop")) + mockRunAsGroupPassthrough(ds.mdi) + + _, err := ds.PublishFFI(context.Background(), "ffi1", "1.0", "ffi1-shared", false) + assert.EqualError(t, err, "pop") +} + +func TestPublishFFIResolveFail(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = true + + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + Namespace: "ns1", + Published: false, + } + + ds.mcm.On("GetFFI", context.Background(), "ffi1", "1.0").Return(ffi, nil) + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(fmt.Errorf("pop")) + mockRunAsGroupPassthrough(ds.mdi) + + _, err := ds.PublishFFI(context.Background(), "ffi1", "1.0", "ffi1-shared", false) + assert.EqualError(t, err, "pop") +} + +func TestPublishFFIPrepareFail(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = true + + mms := &syncasyncmocks.Sender{} + + ffi := &fftypes.FFI{ + Name: "ffi1", + Version: "1.0", + Namespace: "ns1", + Published: false, + } + + ds.mdi.On("GetFFIByNetworkName", context.Background(), "ns1", "ffi1-shared", "1.0").Return(nil, nil) + ds.mcm.On("GetFFI", context.Background(), "ffi1", "1.0").Return(ffi, nil) + ds.mcm.On("ResolveFFI", context.Background(), ffi).Return(nil) + ds.mim.On("GetMultipartyRootOrg", context.Background()).Return(&core.Identity{ + IdentityBase: core.IdentityBase{ + DID: "firefly:org1", + }, + }, nil) + ds.mim.On("ResolveInputSigningIdentity", mock.Anything, mock.Anything).Return(nil) + ds.mbm.On("NewBroadcast", mock.Anything).Return(mms) + mms.On("Prepare", context.Background()).Return(fmt.Errorf("pop")) + mockRunAsGroupPassthrough(ds.mdi) + + _, err := ds.PublishFFI(context.Background(), "ffi1", "1.0", "ffi1-shared", false) + assert.EqualError(t, err, "pop") + + mms.AssertExpectations(t) +} + +func TestPublishFFINonMultiparty(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = false + + _, err := ds.PublishFFI(context.Background(), "ffi1", "1.0", "ffi1-shared", false) + assert.Regexp(t, "FF10414", err) +} diff --git a/internal/definitions/sender_datatype_test.go b/internal/definitions/sender_datatype_test.go index 86cdc2237..4b19c988a 100644 --- a/internal/definitions/sender_datatype_test.go +++ b/internal/definitions/sender_datatype_test.go @@ -32,8 +32,8 @@ import ( ) func TestDefineDatatypeBadType(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true err := ds.DefineDatatype(context.Background(), &core.Datatype{ Validator: core.ValidatorType("wrong"), @@ -42,8 +42,8 @@ func TestDefineDatatypeBadType(t *testing.T) { } func TestBroadcastDatatypeBadValue(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mdm := ds.data.(*datamocks.Manager) mdm.On("CheckDatatype", mock.Anything, mock.Anything).Return(nil) @@ -67,14 +67,11 @@ func TestBroadcastDatatypeBadValue(t *testing.T) { } func TestDefineDatatypeInvalid(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true - mdm := ds.data.(*datamocks.Manager) - mim := ds.identity.(*identitymanagermocks.Manager) - mim.On("ResolveInputIdentity", mock.Anything, mock.Anything).Return(nil) - mdm.On("CheckDatatype", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + ds.mdm.On("CheckDatatype", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) err := ds.DefineDatatype(context.Background(), &core.Datatype{ Namespace: "ns1", @@ -83,13 +80,11 @@ func TestDefineDatatypeInvalid(t *testing.T) { Value: fftypes.JSONAnyPtr(`{"some": "data"}`), }, false) assert.EqualError(t, err, "pop") - - mdm.AssertExpectations(t) } func TestBroadcastOk(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mdm := ds.data.(*datamocks.Manager) mim := ds.identity.(*identitymanagermocks.Manager) @@ -121,8 +116,8 @@ func TestBroadcastOk(t *testing.T) { } func TestDefineDatatypeNonMultiparty(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = false err := ds.DefineDatatype(context.Background(), &core.Datatype{ diff --git a/internal/definitions/sender_identity_test.go b/internal/definitions/sender_identity_test.go index 80a97c646..3db7e4d95 100644 --- a/internal/definitions/sender_identity_test.go +++ b/internal/definitions/sender_identity_test.go @@ -30,8 +30,8 @@ import ( ) func TestClaimIdentity(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) mim := ds.identity.(*identitymanagermocks.Manager) mbm := ds.broadcast.(*broadcastmocks.Manager) @@ -56,8 +56,8 @@ func TestClaimIdentity(t *testing.T) { } func TestClaimIdentityFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) mim := ds.identity.(*identitymanagermocks.Manager) mbm := ds.broadcast.(*broadcastmocks.Manager) @@ -82,8 +82,8 @@ func TestClaimIdentityFail(t *testing.T) { } func TestClaimIdentityFailKey(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) mim := ds.identity.(*identitymanagermocks.Manager) @@ -102,8 +102,8 @@ func TestClaimIdentityFailKey(t *testing.T) { } func TestClaimIdentityChild(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) mim := ds.identity.(*identitymanagermocks.Manager) mbm := ds.broadcast.(*broadcastmocks.Manager) @@ -136,8 +136,8 @@ func TestClaimIdentityChild(t *testing.T) { } func TestClaimIdentityChildFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) mim := ds.identity.(*identitymanagermocks.Manager) mbm := ds.broadcast.(*broadcastmocks.Manager) @@ -170,8 +170,8 @@ func TestClaimIdentityChildFail(t *testing.T) { } func TestClaimIdentityNonMultiparty(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) dh := ds.handler mim := dh.identity.(*identitymanagermocks.Manager) @@ -190,8 +190,8 @@ func TestClaimIdentityNonMultiparty(t *testing.T) { } func TestUpdateIdentity(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) mim := ds.identity.(*identitymanagermocks.Manager) mbm := ds.broadcast.(*broadcastmocks.Manager) @@ -219,8 +219,8 @@ func TestUpdateIdentity(t *testing.T) { } func TestUpdateIdentityNonMultiparty(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = false diff --git a/internal/definitions/sender_test.go b/internal/definitions/sender_test.go index eb72345eb..873a5d119 100644 --- a/internal/definitions/sender_test.go +++ b/internal/definitions/sender_test.go @@ -35,7 +35,33 @@ import ( "github.com/stretchr/testify/mock" ) -func newTestDefinitionSender(t *testing.T) (*definitionSender, func()) { +type testDefinitionSender struct { + definitionSender + + cancel func() + mdi *databasemocks.Plugin + mbi *blockchainmocks.Plugin + mdx *dataexchangemocks.Plugin + mbm *broadcastmocks.Manager + mim *identitymanagermocks.Manager + mdm *datamocks.Manager + mam *assetmocks.Manager + mcm *contractmocks.Manager +} + +func (tds *testDefinitionSender) cleanup(t *testing.T) { + tds.cancel() + tds.mdi.AssertExpectations(t) + tds.mbi.AssertExpectations(t) + tds.mdx.AssertExpectations(t) + tds.mbm.AssertExpectations(t) + tds.mim.AssertExpectations(t) + tds.mdm.AssertExpectations(t) + tds.mam.AssertExpectations(t) + tds.mcm.AssertExpectations(t) +} + +func newTestDefinitionSender(t *testing.T) *testDefinitionSender { mdi := &databasemocks.Plugin{} mbi := &blockchainmocks.Plugin{} mdx := &dataexchangemocks.Plugin{} @@ -51,7 +77,19 @@ func newTestDefinitionSender(t *testing.T) (*definitionSender, func()) { ns := &core.Namespace{Name: "ns1", NetworkName: "ns1"} ds, _, err := NewDefinitionSender(ctx, ns, false, mdi, mbi, mdx, mbm, mim, mdm, mam, mcm, tokenBroadcastNames) assert.NoError(t, err) - return ds.(*definitionSender), cancel + + return &testDefinitionSender{ + definitionSender: *ds.(*definitionSender), + cancel: cancel, + mdi: mdi, + mbi: mbi, + mdx: mdx, + mbm: mbm, + mim: mim, + mdm: mdm, + mam: mam, + mcm: mcm, + } } func mockRunAsGroupPassthrough(mdi *databasemocks.Plugin) { @@ -68,14 +106,14 @@ func TestInitSenderFail(t *testing.T) { } func TestName(t *testing.T) { - bm, cancel := newTestDefinitionSender(t) - defer cancel() - assert.Equal(t, "DefinitionSender", bm.Name()) + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + assert.Equal(t, "DefinitionSender", ds.Name()) } func TestCreateDefinitionConfirm(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) mim := ds.identity.(*identitymanagermocks.Manager) mbm := ds.broadcast.(*broadcastmocks.Manager) @@ -100,8 +138,8 @@ func TestCreateDefinitionConfirm(t *testing.T) { } func TestCreateDatatypeDefinitionAsNodeConfirm(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) mim := ds.identity.(*identitymanagermocks.Manager) mbm := ds.broadcast.(*broadcastmocks.Manager) @@ -127,8 +165,8 @@ func TestCreateDatatypeDefinitionAsNodeConfirm(t *testing.T) { } func TestCreateDefinitionBadIdentity(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true diff --git a/internal/definitions/sender_tokenpool.go b/internal/definitions/sender_tokenpool.go index e1da374af..b68fcee46 100644 --- a/internal/definitions/sender_tokenpool.go +++ b/internal/definitions/sender_tokenpool.go @@ -71,12 +71,23 @@ func (ds *definitionSender) getTokenPoolSender(ctx context.Context, pool *core.T if err := pool.Validate(ctx); err != nil { return wrapSendError(err) } - existing, err := ds.database.GetTokenPoolByNetworkName(ctx, pool.Namespace, pool.NetworkName) + existing, err := ds.database.GetTokenPoolByNetworkName(ctx, ds.namespace, pool.NetworkName) if err != nil { return wrapSendError(err) } else if existing != nil { return wrapSendError(i18n.NewError(ctx, coremsgs.MsgNetworkNameExists)) } + if pool.Interface != nil && pool.Interface.ID != nil { + iface, err := ds.database.GetFFIByID(ctx, ds.namespace, pool.Interface.ID) + switch { + case err != nil: + return wrapSendError(err) + case iface == nil: + return wrapSendError(i18n.NewError(ctx, coremsgs.MsgContractInterfaceNotFound, pool.Interface.ID)) + case !iface.Published: + return wrapSendError(i18n.NewError(ctx, coremsgs.MsgContractInterfaceNotPublished, pool.Interface.ID)) + } + } // Prepare the pool definition to be serialized for broadcast localName := pool.Name diff --git a/internal/definitions/sender_tokenpool_test.go b/internal/definitions/sender_tokenpool_test.go index 5e7ea3269..d222fb791 100644 --- a/internal/definitions/sender_tokenpool_test.go +++ b/internal/definitions/sender_tokenpool_test.go @@ -34,8 +34,8 @@ import ( ) func TestBroadcastTokenPoolInvalid(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mdm := ds.data.(*datamocks.Manager) @@ -57,8 +57,8 @@ func TestBroadcastTokenPoolInvalid(t *testing.T) { } func TestBroadcastTokenPoolInvalidNonMultiparty(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = false mdm := ds.data.(*datamocks.Manager) @@ -80,12 +80,10 @@ func TestBroadcastTokenPoolInvalidNonMultiparty(t *testing.T) { } func TestBroadcastTokenPoolPublishNonMultiparty(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = false - mdm := ds.data.(*datamocks.Manager) - pool := &core.TokenPool{ ID: fftypes.NewUUID(), Namespace: "", @@ -98,13 +96,11 @@ func TestBroadcastTokenPoolPublishNonMultiparty(t *testing.T) { err := ds.DefineTokenPool(context.Background(), pool, false) assert.Regexp(t, "FF10414", err) - - mdm.AssertExpectations(t) } func TestBroadcastTokenPoolInvalidNameMultiparty(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mdm := ds.data.(*datamocks.Manager) @@ -127,8 +123,8 @@ func TestBroadcastTokenPoolInvalidNameMultiparty(t *testing.T) { } func TestDefineTokenPoolOk(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mdi := ds.database.(*databasemocks.Plugin) @@ -169,8 +165,8 @@ func TestDefineTokenPoolOk(t *testing.T) { } func TestDefineTokenPoolkONonMultiparty(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = false mdb := ds.database.(*databasemocks.Plugin) @@ -199,8 +195,8 @@ func TestDefineTokenPoolkONonMultiparty(t *testing.T) { } func TestDefineTokenPoolNonMultipartyTokenPoolFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) mdi := ds.database.(*databasemocks.Plugin) @@ -224,8 +220,8 @@ func TestDefineTokenPoolNonMultipartyTokenPoolFail(t *testing.T) { } func TestDefineTokenPoolBadName(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true pool := &core.TokenPool{ @@ -244,8 +240,8 @@ func TestDefineTokenPoolBadName(t *testing.T) { } func TestPublishTokenPool(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mdi := ds.database.(*databasemocks.Plugin) @@ -291,8 +287,8 @@ func TestPublishTokenPool(t *testing.T) { } func TestPublishTokenPoolNonMultiparty(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = false _, err := ds.PublishTokenPool(context.Background(), "pool1", "pool-shared", false) @@ -300,8 +296,8 @@ func TestPublishTokenPoolNonMultiparty(t *testing.T) { } func TestPublishTokenPoolAlreadyPublished(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mam := ds.assets.(*assetmocks.Manager) @@ -329,8 +325,8 @@ func TestPublishTokenPoolAlreadyPublished(t *testing.T) { } func TestPublishTokenPoolQueryFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mam := ds.assets.(*assetmocks.Manager) @@ -347,8 +343,8 @@ func TestPublishTokenPoolQueryFail(t *testing.T) { } func TestPublishTokenPoolNetworkNameError(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mam := ds.assets.(*assetmocks.Manager) @@ -377,8 +373,8 @@ func TestPublishTokenPoolNetworkNameError(t *testing.T) { } func TestPublishTokenPoolNetworkNameConflict(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mam := ds.assets.(*assetmocks.Manager) @@ -407,8 +403,8 @@ func TestPublishTokenPoolNetworkNameConflict(t *testing.T) { } func TestPublishTokenPoolResolveFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mam := ds.assets.(*assetmocks.Manager) @@ -440,8 +436,8 @@ func TestPublishTokenPoolResolveFail(t *testing.T) { } func TestPublishTokenPoolPrepareFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mdi := ds.database.(*databasemocks.Plugin) @@ -475,7 +471,6 @@ func TestPublishTokenPoolPrepareFail(t *testing.T) { _, err := ds.PublishTokenPool(context.Background(), "pool1", "pool-shared", false) assert.EqualError(t, err, "pop") - assert.True(t, pool.Published) mdi.AssertExpectations(t) mam.AssertExpectations(t) @@ -485,8 +480,8 @@ func TestPublishTokenPoolPrepareFail(t *testing.T) { } func TestPublishTokenPoolSendFail(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mdi := ds.database.(*databasemocks.Plugin) @@ -521,7 +516,6 @@ func TestPublishTokenPoolSendFail(t *testing.T) { _, err := ds.PublishTokenPool(context.Background(), "pool1", "pool-shared", false) assert.EqualError(t, err, "pop") - assert.True(t, pool.Published) mdi.AssertExpectations(t) mam.AssertExpectations(t) @@ -531,8 +525,8 @@ func TestPublishTokenPoolSendFail(t *testing.T) { } func TestPublishTokenPoolConfirm(t *testing.T) { - ds, cancel := newTestDefinitionSender(t) - defer cancel() + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) ds.multiparty = true mdi := ds.database.(*databasemocks.Plugin) @@ -575,3 +569,89 @@ func TestPublishTokenPoolConfirm(t *testing.T) { mbm.AssertExpectations(t) mms.AssertExpectations(t) } + +func TestPublishTokenPoolInterfaceFail(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = true + + pool := &core.TokenPool{ + ID: fftypes.NewUUID(), + Namespace: "ns1", + Name: "pool1", + Type: core.TokenTypeNonFungible, + Locator: "N1", + Symbol: "COIN", + Connector: "connector1", + Published: false, + Interface: &fftypes.FFIReference{ + ID: fftypes.NewUUID(), + }, + } + + ds.mam.On("GetTokenPoolByNameOrID", mock.Anything, "pool1").Return(pool, nil) + ds.mdi.On("GetTokenPoolByNetworkName", mock.Anything, "ns1", "pool-shared").Return(nil, nil) + mockRunAsGroupPassthrough(ds.mdi) + ds.mdi.On("GetFFIByID", context.Background(), "ns1", pool.Interface.ID).Return(nil, fmt.Errorf("pop")) + + _, err := ds.PublishTokenPool(context.Background(), "pool1", "pool-shared", false) + assert.EqualError(t, err, "pop") +} + +func TestPublishTokenPoolInterfaceNotFound(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = true + + pool := &core.TokenPool{ + ID: fftypes.NewUUID(), + Namespace: "ns1", + Name: "pool1", + Type: core.TokenTypeNonFungible, + Locator: "N1", + Symbol: "COIN", + Connector: "connector1", + Published: false, + Interface: &fftypes.FFIReference{ + ID: fftypes.NewUUID(), + }, + } + + ds.mam.On("GetTokenPoolByNameOrID", mock.Anything, "pool1").Return(pool, nil) + ds.mdi.On("GetTokenPoolByNetworkName", mock.Anything, "ns1", "pool-shared").Return(nil, nil) + mockRunAsGroupPassthrough(ds.mdi) + ds.mdi.On("GetFFIByID", context.Background(), "ns1", pool.Interface.ID).Return(nil, nil) + + _, err := ds.PublishTokenPool(context.Background(), "pool1", "pool-shared", false) + assert.Regexp(t, "FF10303", err) +} + +func TestPublishTokenPoolInterfaceNotPublished(t *testing.T) { + ds := newTestDefinitionSender(t) + defer ds.cleanup(t) + ds.multiparty = true + + pool := &core.TokenPool{ + ID: fftypes.NewUUID(), + Namespace: "ns1", + Name: "pool1", + Type: core.TokenTypeNonFungible, + Locator: "N1", + Symbol: "COIN", + Connector: "connector1", + Published: false, + Interface: &fftypes.FFIReference{ + ID: fftypes.NewUUID(), + }, + } + + ds.mam.On("GetTokenPoolByNameOrID", mock.Anything, "pool1").Return(pool, nil) + ds.mdi.On("GetTokenPoolByNetworkName", mock.Anything, "ns1", "pool-shared").Return(nil, nil) + mockRunAsGroupPassthrough(ds.mdi) + ds.mdi.On("GetFFIByID", context.Background(), "ns1", pool.Interface.ID).Return(&fftypes.FFI{ + Published: false, + }, nil) + + _, err := ds.PublishTokenPool(context.Background(), "pool1", "pool-shared", false) + assert.Regexp(t, "FF10451", err) +} diff --git a/mocks/contractmocks/manager.go b/mocks/contractmocks/manager.go index e04d59d9d..94846cb52 100644 --- a/mocks/contractmocks/manager.go +++ b/mocks/contractmocks/manager.go @@ -85,6 +85,20 @@ func (_m *Manager) DeleteContractListenerByNameOrID(ctx context.Context, nameOrI return r0 } +// DeleteFFI provides a mock function with given fields: ctx, id +func (_m *Manager) DeleteFFI(ctx context.Context, id *fftypes.UUID) error { + ret := _m.Called(ctx, id) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *fftypes.UUID) error); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // DeployContract provides a mock function with given fields: ctx, req, waitConfirm func (_m *Manager) DeployContract(ctx context.Context, req *core.ContractDeployRequest, waitConfirm bool) (interface{}, error) { ret := _m.Called(ctx, req, waitConfirm) diff --git a/mocks/databasemocks/plugin.go b/mocks/databasemocks/plugin.go index 0f81ca99d..61fa358c1 100644 --- a/mocks/databasemocks/plugin.go +++ b/mocks/databasemocks/plugin.go @@ -81,6 +81,20 @@ func (_m *Plugin) DeleteData(ctx context.Context, namespace string, id *fftypes. return r0 } +// DeleteFFI provides a mock function with given fields: ctx, namespace, id +func (_m *Plugin) DeleteFFI(ctx context.Context, namespace string, id *fftypes.UUID) error { + ret := _m.Called(ctx, namespace, id) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, *fftypes.UUID) error); ok { + r0 = rf(ctx, namespace, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // DeleteNonce provides a mock function with given fields: ctx, hash func (_m *Plugin) DeleteNonce(ctx context.Context, hash *fftypes.Bytes32) error { ret := _m.Called(ctx, hash) @@ -962,6 +976,32 @@ func (_m *Plugin) GetFFIByID(ctx context.Context, namespace string, id *fftypes. return r0, r1 } +// GetFFIByNetworkName provides a mock function with given fields: ctx, namespace, networkName, version +func (_m *Plugin) GetFFIByNetworkName(ctx context.Context, namespace string, networkName string, version string) (*fftypes.FFI, error) { + ret := _m.Called(ctx, namespace, networkName, version) + + var r0 *fftypes.FFI + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (*fftypes.FFI, error)); ok { + return rf(ctx, namespace, networkName, version) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *fftypes.FFI); ok { + r0 = rf(ctx, namespace, networkName, version) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*fftypes.FFI) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { + r1 = rf(ctx, namespace, networkName, version) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetFFIErrors provides a mock function with given fields: ctx, namespace, filter func (_m *Plugin) GetFFIErrors(ctx context.Context, namespace string, filter ffapi.Filter) ([]*fftypes.FFIError, *ffapi.FilterResult, error) { ret := _m.Called(ctx, namespace, filter) @@ -2619,6 +2659,32 @@ func (_m *Plugin) InsertOrGetBlockchainEvent(ctx context.Context, event *core.Bl return r0, r1 } +// InsertOrGetFFI provides a mock function with given fields: ctx, ffi +func (_m *Plugin) InsertOrGetFFI(ctx context.Context, ffi *fftypes.FFI) (*fftypes.FFI, error) { + ret := _m.Called(ctx, ffi) + + var r0 *fftypes.FFI + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *fftypes.FFI) (*fftypes.FFI, error)); ok { + return rf(ctx, ffi) + } + if rf, ok := ret.Get(0).(func(context.Context, *fftypes.FFI) *fftypes.FFI); ok { + r0 = rf(ctx, ffi) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*fftypes.FFI) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *fftypes.FFI) error); ok { + r1 = rf(ctx, ffi) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // InsertOrGetTokenPool provides a mock function with given fields: ctx, pool func (_m *Plugin) InsertOrGetTokenPool(ctx context.Context, pool *core.TokenPool) (*core.TokenPool, error) { ret := _m.Called(ctx, pool) @@ -2968,13 +3034,13 @@ func (_m *Plugin) UpsertDatatype(ctx context.Context, datadef *core.Datatype, al return r0 } -// UpsertFFI provides a mock function with given fields: ctx, cd -func (_m *Plugin) UpsertFFI(ctx context.Context, cd *fftypes.FFI) error { - ret := _m.Called(ctx, cd) +// UpsertFFI provides a mock function with given fields: ctx, ffi, optimization +func (_m *Plugin) UpsertFFI(ctx context.Context, ffi *fftypes.FFI, optimization database.UpsertOptimization) error { + ret := _m.Called(ctx, ffi, optimization) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *fftypes.FFI) error); ok { - r0 = rf(ctx, cd) + if rf, ok := ret.Get(0).(func(context.Context, *fftypes.FFI, database.UpsertOptimization) error); ok { + r0 = rf(ctx, ffi, optimization) } else { r0 = ret.Error(0) } diff --git a/mocks/definitionsmocks/sender.go b/mocks/definitionsmocks/sender.go index 2d6739715..a686f40f4 100644 --- a/mocks/definitionsmocks/sender.go +++ b/mocks/definitionsmocks/sender.go @@ -101,6 +101,32 @@ func (_m *Sender) Name() string { return r0 } +// PublishFFI provides a mock function with given fields: ctx, name, version, networkName, waitConfirm +func (_m *Sender) PublishFFI(ctx context.Context, name string, version string, networkName string, waitConfirm bool) (*fftypes.FFI, error) { + ret := _m.Called(ctx, name, version, networkName, waitConfirm) + + var r0 *fftypes.FFI + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool) (*fftypes.FFI, error)); ok { + return rf(ctx, name, version, networkName, waitConfirm) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool) *fftypes.FFI); ok { + r0 = rf(ctx, name, version, networkName, waitConfirm) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*fftypes.FFI) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, bool) error); ok { + r1 = rf(ctx, name, version, networkName, waitConfirm) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // PublishTokenPool provides a mock function with given fields: ctx, poolNameOrID, networkName, waitConfirm func (_m *Sender) PublishTokenPool(ctx context.Context, poolNameOrID string, networkName string, waitConfirm bool) (*core.TokenPool, error) { ret := _m.Called(ctx, poolNameOrID, networkName, waitConfirm) diff --git a/pkg/database/plugin.go b/pkg/database/plugin.go index cf9c7db28..b29780ff4 100644 --- a/pkg/database/plugin.go +++ b/pkg/database/plugin.go @@ -433,8 +433,12 @@ type iTokenApprovalCollection interface { } type iFFICollection interface { + // InsertOrGetFFI - Insert an FFI + // If an FFI with the same name has already been recorded, does not insert but returns the existing row + InsertOrGetFFI(ctx context.Context, ffi *fftypes.FFI) (*fftypes.FFI, error) + // UpsertFFI - Upsert an FFI - UpsertFFI(ctx context.Context, cd *fftypes.FFI) error + UpsertFFI(ctx context.Context, ffi *fftypes.FFI, optimization UpsertOptimization) error // GetFFIs - Get FFIs GetFFIs(ctx context.Context, namespace string, filter ffapi.Filter) ([]*fftypes.FFI, *ffapi.FilterResult, error) @@ -444,6 +448,12 @@ type iFFICollection interface { // GetFFI - Get an FFI by name and version GetFFI(ctx context.Context, namespace, name, version string) (*fftypes.FFI, error) + + // GetFFIByNetworkName - Get an FFI by network name and version + GetFFIByNetworkName(ctx context.Context, namespace, networkName, version string) (*fftypes.FFI, error) + + // DeleteFFI - Delete an FFI + DeleteFFI(ctx context.Context, namespace string, id *fftypes.UUID) error } type iFFIMethodCollection interface { @@ -979,9 +989,11 @@ var TokenApprovalQueryFactory = &ffapi.QueryFields{ // FFIQueryFactory filter fields for contract definitions var FFIQueryFactory = &ffapi.QueryFields{ - "id": &ffapi.UUIDField{}, - "name": &ffapi.StringField{}, - "version": &ffapi.StringField{}, + "id": &ffapi.UUIDField{}, + "name": &ffapi.StringField{}, + "networkname": &ffapi.StringField{}, + "version": &ffapi.StringField{}, + "published": &ffapi.BoolField{}, } // FFIMethodQueryFactory filter fields for contract methods diff --git a/test/e2e/client/restclient.go b/test/e2e/client/restclient.go index 2c3b359ba..d2c73dad4 100644 --- a/test/e2e/client/restclient.go +++ b/test/e2e/client/restclient.go @@ -608,7 +608,7 @@ func (client *FireFlyClient) DeleteTokenPool(t *testing.T, poolID *fftypes.UUID, path := client.namespaced(urlTokenPools + "/" + poolID.String()) resp, err := client.Client.R().Delete(path) require.NoError(t, err) - require.Equal(t, expectedStatus, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String()) + require.Equal(t, expectedStatus, resp.StatusCode(), "DELETE %s [%d]: %s", path, resp.StatusCode(), resp.String()) } func (client *FireFlyClient) MintTokens(t *testing.T, mint *core.TokenTransferInput, confirm bool, expectedStatus ...int) *core.TokenTransfer { @@ -860,19 +860,43 @@ func (client *FireFlyClient) GenerateFFIFromABI(t *testing.T, req *fftypes.FFIGe return &res } -func (client *FireFlyClient) CreateFFI(t *testing.T, ffi *fftypes.FFI) (*fftypes.FFI, error) { +func (client *FireFlyClient) CreateFFI(t *testing.T, ffi *fftypes.FFI, publish bool) (*fftypes.FFI, error) { var res fftypes.FFI path := client.namespaced(urlContractInterface) resp, err := client.Client.R(). SetBody(ffi). SetResult(&res). SetQueryParam("confirm", "true"). + SetQueryParam("publish", strconv.FormatBool(publish)). Post(path) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String()) return &res, err } +func (client *FireFlyClient) PublishFFI(t *testing.T, name, version, networkName string, confirm bool) { + path := client.namespaced(urlContractInterface + "/" + name + "/" + version + "/publish") + resp, err := client.Client.R(). + SetBody(&core.DefinitionPublish{ + NetworkName: networkName, + }). + SetQueryParam("confirm", strconv.FormatBool(confirm)). + Post(path) + require.NoError(t, err) + expected := 202 + if confirm { + expected = 200 + } + require.Equal(t, expected, resp.StatusCode(), "POST %s [%d]: %s", path, resp.StatusCode(), resp.String()) +} + +func (client *FireFlyClient) DeleteFFI(t *testing.T, id *fftypes.UUID, expectedStatus int) { + path := client.namespaced(urlContractInterface + "/" + id.String()) + resp, err := client.Client.R().Delete(path) + require.NoError(t, err) + require.Equal(t, expectedStatus, resp.StatusCode(), "DELETE %s [%d]: %s", path, resp.StatusCode(), resp.String()) +} + func (client *FireFlyClient) CreateContractAPI(t *testing.T, name string, ffiReference *fftypes.FFIReference, location *fftypes.JSONAny) (interface{}, error) { apiReqBody := &core.ContractAPI{ Name: name, diff --git a/test/e2e/gateway/ethereum_contracts.go b/test/e2e/gateway/ethereum_contracts.go index 4b050434d..c67dab682 100644 --- a/test/e2e/gateway/ethereum_contracts.go +++ b/test/e2e/gateway/ethereum_contracts.go @@ -124,7 +124,7 @@ func (suite *EthereumContractTestSuite) SetupSuite() { suite.ethIdentity = account["address"].(string) suite.contractAddress = deployContract(suite.T(), stack.Name, "simplestorage/simple_storage.json") - res, err := suite.testState.client1.CreateFFI(suite.T(), simpleStorageFFI()) + res, err := suite.testState.client1.CreateFFI(suite.T(), simpleStorageFFI(), false) suite.interfaceID = res.ID suite.T().Logf("interfaceID: %s", suite.interfaceID) assert.NoError(suite.T(), err) diff --git a/test/e2e/multiparty/common.go b/test/e2e/multiparty/common.go index 5d1e6ffd4..7c288d630 100644 --- a/test/e2e/multiparty/common.go +++ b/test/e2e/multiparty/common.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -181,7 +181,7 @@ func beforeE2ETest(t *testing.T) *testState { t.Logf("Org1: ID=%s DID=%s Key=%s", ts.org1.ID, ts.org1.DID, ts.org1key.Value) t.Logf("Org2: ID=%s DID=%s Key=%s", ts.org2.ID, ts.org2.DID, ts.org2key.Value) - eventNames := "message_confirmed|token_pool_confirmed|token_transfer_confirmed|blockchain_event_received|token_approval_confirmed|identity_confirmed|message_rejected" + eventNames := "message_confirmed|token_pool_confirmed|token_transfer_confirmed|blockchain_event_received|token_approval_confirmed|identity_confirmed|message_rejected|contract_interface_confirmed" queryString := fmt.Sprintf("namespace=%s&ephemeral&autoack&filter.events=%s&changeevents=.*", ts.namespace, eventNames) ts.ws1 = ts.client1.WebSocket(t, queryString, authHeader1) ts.ws2 = ts.client2.WebSocket(t, queryString, authHeader2) diff --git a/test/e2e/multiparty/ethereum_contract_message.go b/test/e2e/multiparty/ethereum_contract_message.go index d8c0e56ab..0b442a0dc 100644 --- a/test/e2e/multiparty/ethereum_contract_message.go +++ b/test/e2e/multiparty/ethereum_contract_message.go @@ -54,10 +54,10 @@ func (suite *EthereumContractWithMessageTestSuite) TestCustomContractWithMessage ffi := suite.testState.client1.GenerateFFIFromABI(suite.T(), &fftypes.FFIGenerationRequest{ Name: "CustomPin", - Version: contractVersion, + Version: contractVersion(), Input: fftypes.JSONAnyPtr(`{"abi":` + suite.contractJSON.GetObjectArray("abi").String() + `}`), }) - iface, err := suite.testState.client1.CreateFFI(suite.T(), ffi) + iface, err := suite.testState.client1.CreateFFI(suite.T(), ffi, true) assert.NoError(suite.T(), err) status, _, err := suite.testState.client1.GetStatus() diff --git a/test/e2e/multiparty/ethereum_contracts.go b/test/e2e/multiparty/ethereum_contracts.go index 253dadffd..c75d16c2f 100644 --- a/test/e2e/multiparty/ethereum_contracts.go +++ b/test/e2e/multiparty/ethereum_contracts.go @@ -35,7 +35,11 @@ import ( "github.com/stretchr/testify/suite" ) -var contractVersion, _ = nanoid.Generate("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", nanoid.DefaultSize) +func contractVersion() string { + versionAlphabet := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + version, _ := nanoid.Generate(versionAlphabet, nanoid.DefaultSize) + return version +} func simpleStorageFFIChanged() *fftypes.FFIEvent { return &fftypes.FFIEvent{ @@ -55,10 +59,10 @@ func simpleStorageFFIChanged() *fftypes.FFIEvent { } } -func simpleStorageFFI() *fftypes.FFI { +func simpleStorageFFI(version string) *fftypes.FFI { return &fftypes.FFI{ Name: "SimpleStorage", - Version: contractVersion, + Version: version, Methods: []*fftypes.FFIMethod{ simpleStorageFFISet(), simpleStorageFFIGet(), @@ -124,7 +128,7 @@ func (suite *EthereumContractTestSuite) SetupSuite() { suite.ethIdentity = suite.testState.org1key.Value suite.contractAddress = deployContract(suite.T(), stack.Name, "simplestorage/simple_storage.json") - res, err := suite.testState.client1.CreateFFI(suite.T(), simpleStorageFFI()) + res, err := suite.testState.client1.CreateFFI(suite.T(), simpleStorageFFI(contractVersion()), true) suite.interfaceID = res.ID suite.T().Logf("interfaceID: %s", suite.interfaceID) assert.NoError(suite.T(), err) @@ -323,3 +327,34 @@ func readContractJSON(t *testing.T, contract string) fftypes.JSONObject { assert.NoError(t, err) return jsonValue } + +func (suite *EthereumContractTestSuite) TestContractPublish() { + received1 := e2e.WsReader(suite.testState.ws1) + received2 := e2e.WsReader(suite.testState.ws2) + + ffi := simpleStorageFFI(contractVersion()) + networkName := ffi.Name + "-shared" + suite.T().Logf("Interface local name: %s", ffi.Name) + suite.T().Logf("Interface network name: %s", networkName) + suite.T().Logf("Interface version: %s", ffi.Version) + + result, err := suite.testState.client1.CreateFFI(suite.T(), ffi, false) + assert.NoError(suite.T(), err) + + e2e.WaitForEvent(suite.T(), received1, core.EventTypeContractInterfaceConfirmed, result.ID) + + // Delete and recreate + suite.testState.client1.DeleteFFI(suite.T(), result.ID, 204) + result, err = suite.testState.client1.CreateFFI(suite.T(), ffi, false) + assert.NoError(suite.T(), err) + + e2e.WaitForEvent(suite.T(), received1, core.EventTypeContractInterfaceConfirmed, result.ID) + + suite.testState.client1.PublishFFI(suite.T(), ffi.Name, ffi.Version, networkName, false) + + e2e.WaitForMessageConfirmed(suite.T(), received1, core.MessageTypeDefinition) + e2e.WaitForEvent(suite.T(), received2, core.EventTypeContractInterfaceConfirmed, result.ID) + + // Cannot delete published interfaces + suite.testState.client1.DeleteFFI(suite.T(), result.ID, 409) +} diff --git a/test/e2e/multiparty/ethereum_token_contract.go b/test/e2e/multiparty/ethereum_token_contract.go index 4255c427f..d67b0e605 100644 --- a/test/e2e/multiparty/ethereum_token_contract.go +++ b/test/e2e/multiparty/ethereum_token_contract.go @@ -410,13 +410,14 @@ func (suite *EthereumTokenContractTestSuite) TestTokensWithInterface() { suite.T().Logf("contract: %s", suite.contract) contractAddress := deployContract(suite.T(), suite.testState.stackName, suite.contract) contractJSON := readContractJSON(suite.T(), suite.contract) + version := contractVersion() ffi := suite.testState.client1.GenerateFFIFromABI(suite.T(), &fftypes.FFIGenerationRequest{ Name: "ERC20", - Version: contractVersion, + Version: version, Input: fftypes.JSONAnyPtr(`{"abi":` + contractJSON.GetObjectArray("abi").String() + `}`), }) - _, err := suite.testState.client1.CreateFFI(suite.T(), ffi) + _, err := suite.testState.client1.CreateFFI(suite.T(), ffi, true) assert.NoError(suite.T(), err) poolName := fmt.Sprintf("pool_%s", e2e.RandomName(suite.T())) @@ -428,7 +429,7 @@ func (suite *EthereumTokenContractTestSuite) TestTokensWithInterface() { }, Interface: &fftypes.FFIReference{ Name: "ERC20", - Version: contractVersion, + Version: version, }, } poolResp := suite.testState.client1.CreateTokenPool(suite.T(), pool, true, false) diff --git a/test/e2e/multiparty/tokens.go b/test/e2e/multiparty/tokens.go index 7be8c80a3..f05e80326 100644 --- a/test/e2e/multiparty/tokens.go +++ b/test/e2e/multiparty/tokens.go @@ -379,7 +379,7 @@ func (suite *TokensTestSuite) TestE2ENonFungibleTokensSync() { accountPools = suite.testState.client2.GetTokenAccountPools(suite.T(), suite.testState.org2key.Value) assert.Equal(suite.T(), *poolID, *accountPools[0].Pool) - // Cannot delete pools in multiparty mode + // Cannot delete published pools suite.testState.client1.DeleteTokenPool(suite.T(), poolID, 409) } @@ -424,4 +424,7 @@ func (suite *TokensTestSuite) TestE2ETokenPoolPublish() { assert.Equal(suite.T(), core.TokenTypeFungible, pools[0].Type) assert.NotEmpty(suite.T(), pools[0].Locator) assert.NotNil(suite.T(), pools[0].Message) + + // Cannot delete published pools + suite.testState.client1.DeleteTokenPool(suite.T(), poolID, 409) }