diff --git a/head/architecture/blockchain_connector_framework.html b/head/architecture/blockchain_connector_framework.html index 3bfaf987d..d8dc1480b 100644 --- a/head/architecture/blockchain_connector_framework.html +++ b/head/architecture/blockchain_connector_framework.html @@ -196,7 +196,7 @@ WSAck @@ -310,11 +310,6 @@

  • Transaction Handler
  • Event Streams
  • -
  • Blockchain error messages
      -
    1. Format of a firefly-evmconnect error message
    2. -
    3. Retrieving EVM blockchain transaction errors
    4. -
    -

  • @@ -603,121 +598,6 @@

    FireFly Connector Toolkit Event Streams

    -

    - - - Blockchain error messages - - -

    - - -

    The receipt for a FireFly blockchain operation contains an extraInfo section that records additional information about the transaction. For example:

    - -
    "receipt": {
    -  ...
    -  "extraInfo": [
    -    {
    -      {
    -        "contractAddress":"0x87ae94ab290932c4e6269648bb47c86978af4436",
    -        "cumulativeGasUsed":"33812",
    -        "from":"0x2b1c769ef5ad304a4889f2a07a6617cd935849ae",
    -        "to":"0x302259069aaa5b10dc6f29a9a3f72a8e52837cc3",
    -        "gasUsed":"33812",
    -        "status":"0",
    -        "errorMessage":"Not enough tokens", 
    -      }
    -    }
    -  ],
    -  ...
    -},
    -
    - -

    The errorMessage field can be be set by a blockchain connector to provide FireFly and the end-user with more information about the reason why a tranasction failed. The blockchain connector can choose what information to include in errorMessage field. It may be set to an error message relating to the blockchain connector itself or an error message passed back from the blockchain or smart contract that was invoked.

    -

    - - - Format of a firefly-evmconnect error message - - -

    - - -

    The following section describes the way that the firefly-evmconnect plugin uses the errorMessage field. This serves both as an explanation of how EVM-based transaction errors will be formatted, and as a guide that other blockchain connectors may decide to follow.

    - -

    The errorMessage field for a firefly-evmconnect transaction may contain one of the following:

    - -
      -
    1. An error message from the FireFly blockchain connector - -
    2. -
    3. A decoded error string from the blockchain transaction - -
    4. -
    5. An un-decoded byte string from the blockchain transaction - -
    6. -
    -

    - - - Retrieving EVM blockchain transaction errors - - -

    - - -

    The ability of a blockchain connector such as firefly-evmconnect to retrieve the reason for a transaction failure, is dependent on by the configuration of the blockchain it is connected to. For an EVM blockchain the reason why a transaction failed is recorded with the REVERT op code, with a REASON set to the reason for the failure. By default, most EVM clients do not store this reason in the transaction receipt. This is typically to reduce resource consumption such as memory usage in the client. It is usually possible to configure an EVM client to store the revert reason in the transaction receipt. For example Hyperledger Besu™ provides the --revert-reason-enabled configuration option. If the transaction receipt does not contain the revert reason it is possible to request that an EVM client re-run the transaction and return a trace of all of the op-codes, including the final REVERT REASON. This can be a resource intensive request to submit to an EVM client, and is only available on archive nodes or for very recent blocks.

    - -

    The firefly-evmconnect blockchain connector attempts to obtain the reason for a transaction revert and include it in the extraInfo field. It uses the following mechanisms, in this order:

    - -
      -
    1. Checks if the blockchain transaction receipt contains the revert reason.
    2. -
    3. If the revert reason is not in the receipt, and the connector.traceTXForRevertReason configuration option is set to true, calls debug_traceTransaction to obtain a full trace of the transaction and extract the revert reason. By default, connector.traceTXForRevertReason is set to false to avoid submitting high-resource requests to the EVM client.
    4. -
    - -

    If the revert reason can be obtained using either mechanism above, the revert reason bytes are decoded in the following way:

    - diff --git a/head/architecture/index.html b/head/architecture/index.html index 050d4c5cf..228f4a964 100644 --- a/head/architecture/index.html +++ b/head/architecture/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/architecture/internal_event_sequencing.html b/head/architecture/internal_event_sequencing.html index 854b66c68..5654e8938 100644 --- a/head/architecture/internal_event_sequencing.html +++ b/head/architecture/internal_event_sequencing.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/architecture/multiparty_event_sequencing.html b/head/architecture/multiparty_event_sequencing.html index b5f9b0498..cc26fac9d 100644 --- a/head/architecture/multiparty_event_sequencing.html +++ b/head/architecture/multiparty_event_sequencing.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/architecture/node_component_architecture.html b/head/architecture/node_component_architecture.html index 8c326fdf5..0e521ea80 100644 --- a/head/architecture/node_component_architecture.html +++ b/head/architecture/node_component_architecture.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/architecture/ping_pong_txflow.html b/head/architecture/ping_pong_txflow.html index d9585e370..6a32abf5a 100644 --- a/head/architecture/ping_pong_txflow.html +++ b/head/architecture/ping_pong_txflow.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/architecture/plugin_architecture.html b/head/architecture/plugin_architecture.html index 461b1fe65..2ae119f44 100644 --- a/head/architecture/plugin_architecture.html +++ b/head/architecture/plugin_architecture.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/assets/js/search-data.json b/head/assets/js/search-data.json index beb36ddaf..8b5bc23ce 100644 --- a/head/assets/js/search-data.json +++ b/head/assets/js/search-data.json @@ -475,7 +475,7 @@ },"79": { "doc": "Blockchain Connector Toolkit", "title": "Table of contents", - "content": ". | Blockchain Connector Framework | Connector Toolkit Architecture | Assumptions / Requirements | Nonce management in the simple transaction handler . | Avoid multiple nonce management systems against the same signing key | Why “at source” nonce management was chosen vs. “at target” | . | Transaction Handler | Event Streams | Blockchain error messages . | Format of a firefly-evmconnect error message | Retrieving EVM blockchain transaction errors | . | . ", + "content": ". | Blockchain Connector Framework | Connector Toolkit Architecture | Assumptions / Requirements | Nonce management in the simple transaction handler . | Avoid multiple nonce management systems against the same signing key | Why “at source” nonce management was chosen vs. “at target” | . | Transaction Handler | Event Streams | . ", "url": "/firefly/head/architecture/blockchain_connector_framework.html#table-of-contents", "relUrl": "/architecture/blockchain_connector_framework.html#table-of-contents" },"80": { @@ -515,4680 +515,4704 @@ "url": "/firefly/head/architecture/blockchain_connector_framework.html#event-streams", "relUrl": "/architecture/blockchain_connector_framework.html#event-streams" },"86": { - "doc": "Blockchain Connector Toolkit", - "title": "Blockchain error messages", - "content": "The receipt for a FireFly blockchain operation contains an extraInfo section that records additional information about the transaction. For example: . \"receipt\": { ... \"extraInfo\": [ { { \"contractAddress\":\"0x87ae94ab290932c4e6269648bb47c86978af4436\", \"cumulativeGasUsed\":\"33812\", \"from\":\"0x2b1c769ef5ad304a4889f2a07a6617cd935849ae\", \"to\":\"0x302259069aaa5b10dc6f29a9a3f72a8e52837cc3\", \"gasUsed\":\"33812\", \"status\":\"0\", \"errorMessage\":\"Not enough tokens\", } } ], ... }, . The errorMessage field can be be set by a blockchain connector to provide FireFly and the end-user with more information about the reason why a tranasction failed. The blockchain connector can choose what information to include in errorMessage field. It may be set to an error message relating to the blockchain connector itself or an error message passed back from the blockchain or smart contract that was invoked. Format of a firefly-evmconnect error message . The following section describes the way that the firefly-evmconnect plugin uses the errorMessage field. This serves both as an explanation of how EVM-based transaction errors will be formatted, and as a guide that other blockchain connectors may decide to follow. The errorMessage field for a firefly-evmconnect transaction may contain one of the following: . | An error message from the FireFly blockchain connector . | For example \"FF23054\", \"Error return value unavailable\" | . | A decoded error string from the blockchain transaction . | For example Not enough tokens | This could be an error string from a smart contract e.g. require(requestedTokens <= allowance, \"Not enough tokens\"); | . | An un-decoded byte string from the blockchain transaction . | For example FF23053: Error return value for custom error: 0x1320fa6a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000010 . | This could be a custom error from a smart contract e.g. error AllowanceTooSmall(uint256 requested, uint256 allowance); ... revert AllowanceTooSmall({ requested: 100, allowance: 20 }); . | If an error reason cannot be decoded the returnValue of the extraInfo will be set to the raw byte string. For example: \"receipt\": { ... \"extraInfo\": [ { { \"contractAddress\":\"0x87ae94ab290932c4e6269648bb47c86978af4436\", \"cumulativeGasUsed\":\"33812\", \"from\":\"0x2b1c769ef5ad304a4889f2a07a6617cd935849ae\", \"to\":\"0x302259069aaa5b10dc6f29a9a3f72a8e52837cc3\", \"gasUsed\":\"33812\", \"status\":\"0\", \"errorMessage\":\"FF23053: Error return value for custom error: 0x1320fa6a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000010\", \"returnValue\":\"0x1320fa6a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000010\" } } ], ... }, . | . | . Retrieving EVM blockchain transaction errors . The ability of a blockchain connector such as firefly-evmconnect to retrieve the reason for a transaction failure, is dependent on by the configuration of the blockchain it is connected to. For an EVM blockchain the reason why a transaction failed is recorded with the REVERT op code, with a REASON set to the reason for the failure. By default, most EVM clients do not store this reason in the transaction receipt. This is typically to reduce resource consumption such as memory usage in the client. It is usually possible to configure an EVM client to store the revert reason in the transaction receipt. For example Hyperledger Besu™ provides the --revert-reason-enabled configuration option. If the transaction receipt does not contain the revert reason it is possible to request that an EVM client re-run the transaction and return a trace of all of the op-codes, including the final REVERT REASON. This can be a resource intensive request to submit to an EVM client, and is only available on archive nodes or for very recent blocks. The firefly-evmconnect blockchain connector attempts to obtain the reason for a transaction revert and include it in the extraInfo field. It uses the following mechanisms, in this order: . | Checks if the blockchain transaction receipt contains the revert reason. | If the revert reason is not in the receipt, and the connector.traceTXForRevertReason configuration option is set to true, calls debug_traceTransaction to obtain a full trace of the transaction and extract the revert reason. By default, connector.traceTXForRevertReason is set to false to avoid submitting high-resource requests to the EVM client. | . If the revert reason can be obtained using either mechanism above, the revert reason bytes are decoded in the following way: . | Attempts to decode the bytes as the standard Error(string) signature format and includes the decoded string in the errorMessage | If the reason is not a standard Error(String) error, sets the errorMessage to FF23053: Error return value for custom error: <raw hex string> and includes the raw byte string in the returnValue field. | . ", - "url": "/firefly/head/architecture/blockchain_connector_framework.html#blockchain-error-messages", - "relUrl": "/architecture/blockchain_connector_framework.html#blockchain-error-messages" + "doc": "Blockchain Operation Errors", + "title": "Blockchain Operation Errors", + "content": " ", + "url": "/firefly/head/reference/blockchain_operation_errors.html", + "relUrl": "/reference/blockchain_operation_errors.html" },"87": { + "doc": "Blockchain Operation Errors", + "title": "Table of contents", + "content": ". | Blockchain error messages | Default error format with Hyperledger FireFly 1.3 and Hyperledger Besu 24.3.0 | Error retrieval details . | Format of a firefly-evmconnect error message | Retrieving EVM blockchain transaction errors | . | . ", + "url": "/firefly/head/reference/blockchain_operation_errors.html#table-of-contents", + "relUrl": "/reference/blockchain_operation_errors.html#table-of-contents" + },"88": { + "doc": "Blockchain Operation Errors", + "title": "Blockchain error messages", + "content": "The receipt for a FireFly blockchain operation contains an extraInfo section that records additional information about the transaction. For example: . \"receipt\": { ... \"extraInfo\": [ { { \"contractAddress\":\"0x87ae94ab290932c4e6269648bb47c86978af4436\", \"cumulativeGasUsed\":\"33812\", \"from\":\"0x2b1c769ef5ad304a4889f2a07a6617cd935849ae\", \"to\":\"0x302259069aaa5b10dc6f29a9a3f72a8e52837cc3\", \"gasUsed\":\"33812\", \"status\":\"0\", \"errorMessage\":\"Not enough tokens\", } } ], ... }, . The errorMessage field can be be set by a blockchain connector to provide FireFly and the end-user with more information about the reason why a tranasction failed. The blockchain connector can choose what information to include in errorMessage field. It may be set to an error message relating to the blockchain connector itself or an error message passed back from the blockchain or smart contract that was invoked. ", + "url": "/firefly/head/reference/blockchain_operation_errors.html#blockchain-error-messages", + "relUrl": "/reference/blockchain_operation_errors.html#blockchain-error-messages" + },"89": { + "doc": "Blockchain Operation Errors", + "title": "Default error format with Hyperledger FireFly 1.3 and Hyperledger Besu 24.3.0", + "content": "If FireFly is configured to connect to a Besu EVM client, and Besu has been configured with the revert-reason-enabled=true setting (note - the default value for Besu is false) error messages passed to FireFly from the blockchain client itself will be set correctly in the FireFly blockchain operation. For example: . | \"errorMessage\":\"Not enough tokens\" for a revert error string from a smart contract | . If the smart contract uses a custom error type, Besu will return the revert reason to FireFly as a hexadecimal string but FireFly will be unable to decode it into. In this case the blockchain operation error message and return values will be set to: . | \"errorMessage\":\"FF23053: Error return value for custom error: <revert hex string> | \"returnValue\":\"<revert hex string>\" | . A future update to FireFly could be made to automatically decode custom error revert reasons if FireFly knows the ABI for the custom error. See FireFly issue 1466 which describes the current limitation. If FireFly is configured to connect to Besu without revert-reason-enabled=true the error message will be set to: . | \"errorMessage\":\"FF23054: Error return value unavailable\" | . ", + "url": "/firefly/head/reference/blockchain_operation_errors.html#default-error-format-with-hyperledger-firefly-13-and-hyperledger-besu-2430", + "relUrl": "/reference/blockchain_operation_errors.html#default-error-format-with-hyperledger-firefly-13-and-hyperledger-besu-2430" + },"90": { + "doc": "Blockchain Operation Errors", + "title": "Error retrieval details", + "content": "The precise format of the error message in a blockchain operation can vary based on different factors. The sections below describe in detail how the error message is populted, with specific references to the firefly-evmconnect blockchain connector. Format of a firefly-evmconnect error message . The following section describes the way that the firefly-evmconnect plugin uses the errorMessage field. This serves both as an explanation of how EVM-based transaction errors will be formatted, and as a guide that other blockchain connectors may decide to follow. The errorMessage field for a firefly-evmconnect transaction may contain one of the following: . | An error message from the FireFly blockchain connector . | For example \"FF23054: Error return value unavailable\" | . | A decoded error string from the blockchain transaction . | For example Not enough tokens | This could be an error string from a smart contract e.g. require(requestedTokens <= allowance, \"Not enough tokens\"); | . | An un-decoded byte string from the blockchain transaction . | For example FF23053: Error return value for custom error: 0x1320fa6a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000010 . | This could be a custom error from a smart contract e.g. error AllowanceTooSmall(uint256 requested, uint256 allowance); ... revert AllowanceTooSmall({ requested: 100, allowance: 20 }); . | If an error reason cannot be decoded the returnValue of the extraInfo will be set to the raw byte string. For example: \"receipt\": { ... \"extraInfo\": [ { { \"contractAddress\":\"0x87ae94ab290932c4e6269648bb47c86978af4436\", \"cumulativeGasUsed\":\"33812\", \"from\":\"0x2b1c769ef5ad304a4889f2a07a6617cd935849ae\", \"to\":\"0x302259069aaa5b10dc6f29a9a3f72a8e52837cc3\", \"gasUsed\":\"33812\", \"status\":\"0\", \"errorMessage\":\"FF23053: Error return value for custom error: 0x1320fa6a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000010\", \"returnValue\":\"0x1320fa6a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000010\" } } ], ... }, . | . | . Retrieving EVM blockchain transaction errors . The ability of a blockchain connector such as firefly-evmconnect to retrieve the reason for a transaction failure, is dependent on by the configuration of the blockchain it is connected to. For an EVM blockchain the reason why a transaction failed is recorded with the REVERT op code, with a REASON set to the reason for the failure. By default, most EVM clients do not store this reason in the transaction receipt. This is typically to reduce resource consumption such as memory usage in the client. It is usually possible to configure an EVM client to store the revert reason in the transaction receipt. For example Hyperledger Besu™ provides the --revert-reason-enabled configuration option. If the transaction receipt does not contain the revert reason it is possible to request that an EVM client re-run the transaction and return a trace of all of the op-codes, including the final REVERT REASON. This can be a resource intensive request to submit to an EVM client, and is only available on archive nodes or for very recent blocks. The firefly-evmconnect blockchain connector attempts to obtain the reason for a transaction revert and include it in the extraInfo field. It uses the following mechanisms, in this order: . | Checks if the blockchain transaction receipt contains the revert reason. | If the revert reason is not in the receipt, and the connector.traceTXForRevertReason configuration option is set to true, calls debug_traceTransaction to obtain a full trace of the transaction and extract the revert reason. By default, connector.traceTXForRevertReason is set to false to avoid submitting high-resource requests to the EVM client. | . If the revert reason can be obtained using either mechanism above, the revert reason bytes are decoded in the following way: . | Attempts to decode the bytes as the standard Error(string) signature format and includes the decoded string in the errorMessage | If the reason is not a standard Error(String) error, sets the errorMessage to FF23053: Error return value for custom error: <raw hex string> and includes the raw byte string in the returnValue field. | . ", + "url": "/firefly/head/reference/blockchain_operation_errors.html#error-retrieval-details", + "relUrl": "/reference/blockchain_operation_errors.html#error-retrieval-details" + },"91": { "doc": "Blockchain Operation Status", "title": "Blockchain Operation Status", "content": " ", "url": "/firefly/head/reference/blockchain_operation_status.html", "relUrl": "/reference/blockchain_operation_status.html" - },"88": { + },"92": { "doc": "Blockchain Operation Status", "title": "Table of contents", "content": ". | Blockchain Operations | Blockchain Operation Status . | Blockchain Operation Example | . | Detail Status Structure . | History Example | History Summary Example | . | Public Chain Operations . | Polygon Example | . | . ", "url": "/firefly/head/reference/blockchain_operation_status.html#table-of-contents", "relUrl": "/reference/blockchain_operation_status.html#table-of-contents" - },"89": { + },"93": { "doc": "Blockchain Operation Status", "title": "Blockchain Operations", "content": "Every FireFly Transaction can involve zero or more Operations. Blockchain operations are handled by the blockchain connector configured for the namespace and represent a blockchain transaction being handled by that connector. ", "url": "/firefly/head/reference/blockchain_operation_status.html#blockchain-operations", "relUrl": "/reference/blockchain_operation_status.html#blockchain-operations" - },"90": { + },"94": { "doc": "Blockchain Operation Status", "title": "Blockchain Operation Status", "content": "A blockchain operation can require the connector to go through various stages of processing in order to successfully confirm the transaction on the blockchain. The orchestrator in FireFly receives updates from the connector to indicate when the operation has been completed and determine when the FireFly transaction as a whole has finished. These updates must contain enough information to correlate the operation to the FireFly transaction but it can be useful to see more detailed information about how the transaction was processed. FireFly 1.2 introduced the concept of sub-status types that allow a blockchain connector to distinguish between the intermediate steps involved in progressing a transaction. It also introduced the concept of an action which a connector might carry out in order to progress between types of sub-status. This can be described as a state machine as shown in the following diagram: . To access detailed information about a blockchain operation FireFly 1.2 introduced a new query parameter, fetchStatus, to the /transaction/{txid}/operation/{opid} API. When FireFly receives an API request that includes the fetchStatus query parameter it makes a synchronous call directly to the blockchain connector, requesting all of blockchain transaction detail it has. This payload is then included in the FireFly operation response under a new detail field. Blockchain Operation Example . { \"id\": \"04a8b0c4-03c2-4935-85a1-87d17cddc20a\", \"created\": \"2022-05-16T01:23:15Z\", \"namespace\": \"ns1\", \"tx\": \"99543134-769b-42a8-8be4-a5f8873f969d\", \"type\": \"blockchain_invoke\", \"status\": \"Succeeded\", \"plugin\": \"ethereum\", \"input\": { // Input used to initiate the blockchain operation }, \"output\": { // Minimal blockchain operation data necessary // to resolve the FF transaction }, \"detail\": { // Full blockchain operation information, including sub-status // transitions that took place for the operation to succeed. } } . ", "url": "/firefly/head/reference/blockchain_operation_status.html", "relUrl": "/reference/blockchain_operation_status.html" - },"91": { + },"95": { "doc": "Blockchain Operation Status", "title": "Detail Status Structure", "content": "The structure of a blockchain operation follows the structure described in Operations. In FireFly 1.2, 2 new attributes were added to that structure to allow more detailed status information to be recorded: . | history an ordered list of status changes that have taken place during processing of the transaction | historySummary an un-ordered list any sub-status type that the blockchain connector uses, and any action type that the blockchain connector carries out as part of processing the transaction. | . The history field is designed to record an ordered list of sub-status changes that the transaction has gone through. Within each sub-status change are the actions that have been carried out to try and move the transaction on to a new sub-status. Some transactions might spend a long time going looping between different sub-status types so this field records the N most recent sub-status changes (where the size of N is determined by blockchain connector and its configuration). The follow example shows a transaction going starting at Received, moving to Tracking, and finally ending up as Confirmed. In order to move from Received to Tracking several actions were performed: AssignNonce, RetrieveGasPrice, and SubmitTransaction. History Example . { ... \"lastSubmit\": \"2023-01-27T17:11:41.222375469Z\", \"nonce\": \"14\", \"history\": [ { \"subStatus\": \"Received\", \"time\": \"2023-01-27T17:11:41.122965803Z\", \"actions\": [ { \"action\": \"AssignNonce\", \"count\": 1, \"lastInfo\": {   \"nonce\": \"14\" }, \"lastOccurrence\": \"2023-01-27T17:11:41.122967219Z\", \"time\": \"2023-01-27T17:11:41.122967136Z\" },   { \"action\": \"RetrieveGasPrice\", \"count\": 1, \"lastInfo\": { \"gasPrice\": \"0\" }, \"lastOccurrence\": \"2023-01-27T17:11:41.161213303Z\", \"time\": \"2023-01-27T17:11:41.161213094Z\" }, { \"action\": \"SubmitTransaction\", \"count\": 1,   \"lastInfo\": { \"txHash\": \"0x4c37de1cf320a1d5c949082bbec8ad5fe918e6621cec3948d609ec3f7deac243\" },   \"lastOccurrence\": \"2023-01-27T17:11:41.222374636Z\",   \"time\": \"2023-01-27T17:11:41.222374553Z\"   }   ],   },   {    \"subStatus\": \"Tracking\", \"time\": \"2023-01-27T17:11:41.222400219Z\",   \"actions\": [     {      \"action\": \"ReceiveReceipt\",      \"count\": 2,      \"lastInfo\": {       \"protocolId\": \"000001265122/000000\"      },      \"lastOccurrence\": \"2023-01-27T17:11:57.93120838Z\",      \"time\": \"2023-01-27T17:11:47.930332625Z\"     },     {      \"action\": \"Confirm\",      \"count\": 1,      \"lastOccurrence\": \"2023-01-27T17:12:02.660275549Z\",      \"time\": \"2023-01-27T17:12:02.660275382Z\"     }    ],   },   {    \"subStatus\": \"Confirmed\",    \"time\": \"2023-01-27T17:12:02.660309382Z\",    \"actions\": [],   } ] ... } . Because the history field is a FIFO structure describing the N most recent sub-status changes, some early sub-status changes or actions may be lost over time. For example an action of assignNonce might only happen once when the transaction is first processed by the connector. The historySummary field ensures that a minimal set of information is kept about every single subStatus type and action that has been recorded. History Summary Example . { ... \"historySummary\": [ { \"count\": 1,   \"firstOccurrence\": \"2023-01-27T17:11:41.122966136Z\", \"lastOccurrence\": \"2023-01-27T17:11:41.122966136Z\",   \"subStatus\": \"Received\" }, { \"count\": 1, \"firstOccurrence\": \"2023-01-27T17:11:41.122967219Z\", \"lastOccurrence\": \"2023-01-27T17:11:41.122967219Z\", \"action\": \"AssignNonce\" }, { \"count\": 1, \"firstOccurrence\": \"2023-01-27T17:11:41.161213303Z\", \"lastOccurrence\": \"2023-01-27T17:11:41.161213303Z\", \"action\": \"RetrieveGasPrice\" }, { \"count\": 1, \"firstOccurrence\": \"2023-01-27T17:11:41.222374636Z\", \"lastOccurrence\": \"2023-01-27T17:11:41.222374636Z\", \"action\": \"SubmitTransaction\" }, {   \"count\": 1,   \"firstOccurrence\": \"2023-01-27T17:11:41.222400678Z\", \"lastOccurrence\": \"\",   \"subStatus\": \"Tracking\" }, { \"count\": 1, \"firstOccurrence\": \"2023-01-27T17:11:57.93120838Z\", \"lastOccurrence\": \"2023-01-27T17:11:57.93120838Z\", \"action\": \"ReceiveReceipt\" }, { \"count\": 1, \"firstOccurrence\": \"2023-01-27T17:12:02.660309382Z\", \"lastOccurrence\": \"2023-01-27T17:12:02.660309382Z\", \"action\": \"Confirm\" }, {   \"count\": 1,   \"firstOccurrence\": \"2023-01-27T17:12:02.660309757Z\", \"lastOccurrence\": \"2023-01-27T17:12:02.660309757Z\",   \"subStatus\": \"Confirmed\" } ] } . ", "url": "/firefly/head/reference/blockchain_operation_status.html#detail-status-structure", "relUrl": "/reference/blockchain_operation_status.html#detail-status-structure" - },"92": { + },"96": { "doc": "Blockchain Operation Status", "title": "Public Chain Operations", "content": "Blockchain transactions submitted to a public chain, for example to Polygon PoS, might take longer and involve more sub-status transitions before being confirmed. One reason for this could be because of gas price fluctuations of the chain. In this case the history for a public blockchain operation might include a large number of subStatus entries. Using the example sub-status values above, a blockchain operation might move from Tracking to Stale, back to Tracking, back to Stale and so on. Below is an example of the history for a public blockchain operation. Polygon Example . { ... \"lastSubmit\": \"2023-01-27T17:11:41.222375469Z\", \"nonce\": \"14\", \"history\": [ { \"subStatus\": \"Received\", \"time\": \"2023-01-27T17:11:41.122965803Z\", \"actions\": [ { \"action\": \"AssignNonce\", \"count\": 1, \"lastInfo\": {   \"nonce\": \"1\" }, \"lastOccurrence\": \"2023-01-27T17:11:41.122967219Z\", \"time\": \"2023-01-27T17:11:41.122967136Z\" },   { \"action\": \"RetrieveGasPrice\", \"count\": 1, \"lastInfo\": { \"gasPrice\": \"34422243\" }, \"lastOccurrence\": \"2023-01-27T17:11:41.161213303Z\", \"time\": \"2023-01-27T17:11:41.161213094Z\" }, { \"action\": \"SubmitTransaction\", \"count\": 1,   \"lastInfo\": { \"txHash\": \"0x83ba5e1cf320a1d5c949082bbec8ae7fe918e6621cec39478609ec3f7deacbdb\" },   \"lastOccurrence\": \"2023-01-27T17:11:41.222374636Z\",   \"time\": \"2023-01-27T17:11:41.222374553Z\"   }   ],   },   {    \"subStatus\": \"Tracking\", \"time\": \"2023-01-27T17:11:41.222400219Z\",   \"actions\": [],   },   {    \"subStatus\": \"Stale\", \"time\": \"2023-01-27T17:13:21.222100434Z\",   \"actions\": [     {      \"action\": \"RetrieveGasPrice\",      \"count\": 1, \"lastInfo\": { \"gasPrice\": \"44436243\" },      \"lastOccurrence\": \"2023-01-27T17:13:22.93120838Z\",      \"time\": \"2023-01-27T17:13:22.93120838Z\"     }, { \"action\": \"SubmitTransaction\", \"count\": 1,   \"lastInfo\": { \"txHash\": \"0x7b3a5e1ccbc0a1d5c949082bbec8ae7fe918e6621cec39478609ec7aea6103d5\" },   \"lastOccurrence\": \"2023-01-27T17:13:32.656374637Z\",   \"time\": \"2023-01-27T17:13:32.656374637Z\"   }    ],   },   {    \"subStatus\": \"Tracking\", \"time\": \"2023-01-27T17:13:33.434400219Z\",   \"actions\": [],   },   {    \"subStatus\": \"Stale\", \"time\": \"2023-01-27T17:15:21.222100434Z\",   \"actions\": [     {      \"action\": \"RetrieveGasPrice\",      \"count\": 1, \"lastInfo\": { \"gasPrice\": \"52129243\" },      \"lastOccurrence\": \"2023-01-27T17:15:22.93120838Z\",      \"time\": \"2023-01-27T17:15:22.93120838Z\"     }, { \"action\": \"SubmitTransaction\", \"count\": 1,   \"lastInfo\": { \"txHash\": \"0x89995e1ccbc0a1d5c949082bbec8ae7fe918e6621cec39478609ec7a8c64abc\" },   \"lastOccurrence\": \"2023-01-27T17:15:32.656374637Z\",   \"time\": \"2023-01-27T17:15:32.656374637Z\"   }    ],   },   {    \"subStatus\": \"Tracking\", \"time\": \"2023-01-27T17:15:33.434400219Z\",   \"actions\": [     {      \"action\": \"ReceiveReceipt\",      \"count\": 1,      \"lastInfo\": {       \"protocolId\": \"000004897621/000000\"      },      \"lastOccurrence\": \"2023-01-27T17:15:33.94120833Z\",      \"time\": \"2023-01-27T17:15:33.94120833Z\"     },     {      \"action\": \"Confirm\",      \"count\": 1,      \"lastOccurrence\": \"2023-01-27T17:16:02.780275549Z\",      \"time\": \"2023-01-27T17:16:02.780275382Z\"     }    ],   },   {    \"subStatus\": \"Confirmed\",    \"time\": \"2023-01-27T17:16:03.990309381Z\",    \"actions\": [],   } ] ... } . ", "url": "/firefly/head/reference/blockchain_operation_status.html#public-chain-operations", "relUrl": "/reference/blockchain_operation_status.html#public-chain-operations" - },"93": { + },"97": { "doc": "BlockchainEvent", "title": "BlockchainEvent", "content": " ", "url": "/firefly/head/reference/types/blockchainevent.html", "relUrl": "/reference/types/blockchainevent.html" - },"94": { + },"98": { "doc": "BlockchainEvent", "title": "Table of contents", "content": ". | BlockchainEvent . | Protocol ID | Example | Field Descriptions | . | BlockchainTransactionRef | . ", "url": "/firefly/head/reference/types/blockchainevent.html#table-of-contents", "relUrl": "/reference/types/blockchainevent.html#table-of-contents" - },"95": { + },"99": { "doc": "BlockchainEvent", "title": "BlockchainEvent", "content": "Blockchain Events are detected by the blockchain plugin: . | When a ContractListener has been configured against any custom smart contract through the FireFly API | Indirectly via a Token Connector, which understands the correct events to listen to for a Token Pool configured against a standard such as ERC-20/ERC-721/ERC-1155 | Automatically by FireFly core, for the BatchPin contract that can be used for high throughput batched pinning of off-chain data transfers to the blockchain (complementary to using your own smart contracts). | . Protocol ID . Each Blockchain Event (once final) exists in an absolute location somewhere in the transaction history of the blockchain. A particular slot, in a particular block. How to describe that position contains blockchain specifics - depending on how a particular blockchain represents transactions, blocks and events (or “logs”). So FireFly is flexible with a string protocolId in the core object to represent this location, and then there is a convention that is adopted by the blockchain plugins to try and create some consistency. An example protocolId string is: 000000000041/000020/000003 . | 000000000041 - this is the block number | 000020 - this is the transaction index within that block | 000003 - this is the event (/log) index within that transaction | . The string is alphanumerically sortable as a plain string; . Sufficient zero padding is included at each layer to support future expansion without creating a string that would no longer sort correctly. Example . { \"id\": \"e9bc4735-a332-4071-9975-b1066e51ab8b\", \"source\": \"ethereum\", \"namespace\": \"ns1\", \"name\": \"MyEvent\", \"listener\": \"c29b4595-03c2-411a-89e3-8b7f27ef17bb\", \"protocolId\": \"000000000048/000000/000000\", \"output\": { \"addr1\": \"0x55860105d6a675dbe6e4d83f67b834377ba677ad\", \"value2\": \"42\" }, \"info\": { \"address\": \"0x57A9bE18CCB50D06B7567012AaF6031D669BBcAA\", \"blockHash\": \"0xae7382ef2573553f517913b927d8b9691ada8d617266b8b16f74bb37aa78cae8\", \"blockNumber\": \"48\", \"logIndex\": \"0\", \"signature\": \"Changed(address,uint256)\", \"subId\": \"sb-e4d5efcd-2eba-4ed1-43e8-24831353fffc\", \"timestamp\": \"1653048837\", \"transactionHash\": \"0x34b0327567fefed09ac7b4429549bc609302b08a9cbd8f019a078ec44447593d\", \"transactionIndex\": \"0x0\" }, \"timestamp\": \"2022-05-16T01:23:15Z\", \"tx\": { \"blockchainId\": \"0x34b0327567fefed09ac7b4429549bc609302b08a9cbd8f019a078ec44447593d\" } } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID assigned to the event by FireFly | UUID | . | source | The blockchain plugin or token service that detected the event | string | . | namespace | The namespace of the listener that detected this blockchain event | string | . | name | The name of the event in the blockchain smart contract | string | . | listener | The UUID of the listener that detected this event, or nil for built-in events in the system namespace | UUID | . | protocolId | An alphanumerically sortable string that represents this event uniquely on the blockchain (convention for plugins is zero-padded values BLOCKNUMBER/TXN_INDEX/EVENT_INDEX) | string | . | output | The data output by the event, parsed to JSON according to the interface of the smart contract | JSONObject | . | info | Detailed blockchain specific information about the event, as generated by the blockchain connector | JSONObject | . | timestamp | The time allocated to this event by the blockchain. This is the block timestamp for most blockchain connectors | FFTime | . | tx | 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 | BlockchainTransactionRef | . ", "url": "/firefly/head/reference/types/blockchainevent.html", "relUrl": "/reference/types/blockchainevent.html" - },"96": { + },"100": { "doc": "BlockchainEvent", "title": "BlockchainTransactionRef", "content": "| Field Name | Description | Type | . | type | The type of the FireFly transaction | FFEnum: | . | id | The UUID of the FireFly transaction | UUID | . | blockchainId | The blockchain transaction ID, in the format specific to the blockchain involved in the transaction. Not all FireFly transactions include a blockchain | string | . ", "url": "/firefly/head/reference/types/blockchainevent.html#blockchaintransactionref", "relUrl": "/reference/types/blockchainevent.html#blockchaintransactionref" - },"97": { + },"101": { "doc": "pages.broadcast_data", "title": "Broadcast / shared data", "content": ". ", "url": "/firefly/head/overview/multiparty/broadcast.html#broadcast--shared-data", "relUrl": "/overview/multiparty/broadcast.html#broadcast--shared-data" - },"98": { + },"102": { "doc": "pages.broadcast_data", "title": "Introduction", "content": "Multi-party systems are about establishing a shared source of truth, and often that needs to include certain reference data that is available to all parties in the network. The data needs to be “broadcast” to all members, and also need to be available to new members that join the network . ", "url": "/firefly/head/overview/multiparty/broadcast.html#introduction", "relUrl": "/overview/multiparty/broadcast.html#introduction" - },"99": { + },"103": { "doc": "pages.broadcast_data", "title": "Blockchain backed broadcast", "content": "In order to maintain a complete history of all broadcast data for new members joining the network, FireFly uses the blockchain to sequence the broadcasts with pinning transactions referring to the data itself. Using the blockchain also gives a global order of events for these broadcasts, which allows them to be processed by each member in a way that allows them to derive the same result - even though the processing logic on the events themselves is being performed independently by each member. For more information see Multiparty Event Sequencing. ", "url": "/firefly/head/overview/multiparty/broadcast.html#blockchain-backed-broadcast", "relUrl": "/overview/multiparty/broadcast.html#blockchain-backed-broadcast" - },"100": { + },"104": { "doc": "pages.broadcast_data", "title": "Shared data", "content": "The data included in broadcasts is not recorded on the blockchain. Instead a pluggable shared storage mechanism is used to contain the data itself. The on-chain transaction just contains a hash of the data that is stored off-chain. This is because the data itself might be too large to be efficiently stored and transferred via the blockchain itself, or subject to deletion at some point in the future through agreement by the members in the network. While the data should be reliably stored with visibility to all members of the network, the data can still be secured from leakage outside of the network. The InterPlanetary File System (IPFS) is an example of a distributed technology for peer-to-peer storage and distribution of such data in a decentralized multi-party system. It provides secure connectivity between a number of nodes, combined with a decentralized index of data that is available, and native use of hashes within the technology as the way to reference data by content. ", "url": "/firefly/head/overview/multiparty/broadcast.html#shared-data", "relUrl": "/overview/multiparty/broadcast.html#shared-data" - },"101": { + },"105": { "doc": "pages.broadcast_data", "title": "FireFly built-in broadcasts", "content": "FireFly uses the broadcast mechanism internally to distribute key information to all parties in the network: . | Network map . | Organizational identities | Nodes | See Identities in the reference section for more information | . | Datatype definitions . | See Datatype in the reference section for more information | . | Namespaces . | See Namespaces for more information | . | . These definitions rely on the same assurances provided by blockchain backed broadcast that FireFly applications do. | Verification of the identity of the party in the network that performed the broadcast | Deterministic assignment of a namespace+name to an unique item of data . | If two parties in the network broadcast the same data at similar times, the same one “wins” for all parties in the network (including the broadcaster) | . | . ", "url": "/firefly/head/overview/multiparty/broadcast.html#firefly-built-in-broadcasts", "relUrl": "/overview/multiparty/broadcast.html#firefly-built-in-broadcasts" - },"102": { + },"106": { "doc": "pages.broadcast_data", "title": "pages.broadcast_data", "content": " ", "url": "/firefly/head/overview/multiparty/broadcast.html", "relUrl": "/overview/multiparty/broadcast.html" - },"103": { + },"107": { "doc": "pages.broadcast_data", "title": "Broadcast data", "content": " ", "url": "/firefly/head/tutorials/broadcast_data.html#broadcast-data", "relUrl": "/tutorials/broadcast_data.html#broadcast-data" - },"104": { + },"108": { "doc": "pages.broadcast_data", "title": "Table of contents", "content": ". | Quick reference | Additional info | Example 1: Inline string data | Example message response | Example 2: Inline object data to a topic (no datatype verification) | Notes on why setting a topic is important | Example 3: Upload a blob with metadata and broadcast . | Multipart form post of a file | Example data response from Blob upload | Broadcast the uploaded data | . | Broadcasting Messages using the Sandbox | . ", "url": "/firefly/head/tutorials/broadcast_data.html#table-of-contents", "relUrl": "/tutorials/broadcast_data.html#table-of-contents" - },"105": { + },"109": { "doc": "pages.broadcast_data", "title": "Quick reference", "content": ". | Sends a message visible to all parties in the network . | The message describes who sent it, and exactly what data was sent | . | A message has one or more attached pieces of business data . | Can be sent in-line, uploaded in advanced, or received from other parties | Can include smaller JSON payloads suitable for database storage . | These can be verified against a datatype | . | Can include references to large (multi megabyte/gigabyte) Blob data | . | Sequenced via the blockchain . | The blockchain does not contain any data, just a hash pin | . | Batched for efficiency . | One batch can pin hundreds of message broadcasts | The whole batch is written to the shared storage | . | . ", "url": "/firefly/head/tutorials/broadcast_data.html#quick-reference", "relUrl": "/tutorials/broadcast_data.html#quick-reference" - },"106": { + },"110": { "doc": "pages.broadcast_data", "title": "Additional info", "content": ". | Key Concepts: Broadcast / shared data | Swagger Reference: POST /api/v1/namespaces/{ns}/messages/broadcast | . ", "url": "/firefly/head/tutorials/broadcast_data.html#additional-info", "relUrl": "/tutorials/broadcast_data.html#additional-info" - },"107": { + },"111": { "doc": "pages.broadcast_data", "title": "Example 1: Inline string data", "content": "POST /api/v1/namespaces/default/messages/broadcast . { \"data\": [ { \"value\": \"a string\" } ] } . ", "url": "/firefly/head/tutorials/broadcast_data.html#example-1-inline-string-data", "relUrl": "/tutorials/broadcast_data.html#example-1-inline-string-data" - },"108": { + },"112": { "doc": "pages.broadcast_data", "title": "Example message response", "content": "{ \"header\": { \"id\": \"607e22ad-04fa-434a-a073-54f528ca14fb\", // uniquely identifies this broadcast message \"type\": \"broadcast\", // set automatically \"txtype\": \"batch_pin\", // message will be batched, and sequenced via the blockchain \"author\": \"0x0a65365587a65ce44938eab5a765fe8bc6532bdf\", // set automatically in this example to the node org \"created\": \"2021-07-01T18:06:24.5817016Z\", // set automatically \"namespace\": \"default\", // the 'default' namespace was set in the URL \"topics\": [ \"default\" // the default topic that the message is published on, if no topic is set ], // datahash is calculated from the data array below \"datahash\": \"5a7bbc074441fa3231d9c8fc942d68ef9b9b646dd234bb48c57826dc723b26fd\" }, \"hash\": \"81acf8c8f7982dbc49258535561461601cbe769752fecec0f8ce0358664979e6\", // hash of the header \"state\": \"ready\", // this message is stored locally but not yet confirmed \"data\": [ // one item of data was stored { \"id\": \"8d8635e2-7c90-4963-99cc-794c98a68b1d\", // can be used to query the data in the future \"hash\": \"c95d6352f524a770a787c16509237baf7eb59967699fb9a6d825270e7ec0eacf\" // sha256 hash of `\"a string\"` } ] } . ", "url": "/firefly/head/tutorials/broadcast_data.html#example-message-response", "relUrl": "/tutorials/broadcast_data.html#example-message-response" - },"109": { + },"113": { "doc": "pages.broadcast_data", "title": "Example 2: Inline object data to a topic (no datatype verification)", "content": "It is very good practice to set a tag and topic in each of your messages: . | tag should tell the apps receiving the broadcast (including the local app), what to do when it receives the message. Its the reason for the broadcast - an application specific type for the message. | topic should be something like a well known identifier that relates to the information you are publishing. It is used as an ordering context, so all broadcasts on a given topic are assured to be processed in order. | . POST /api/v1/namespaces/default/messages/broadcast . { \"header\": { \"tag\": \"new_widget_created\", \"topics\": [\"widget_id_12345\"] }, \"data\": [ { \"value\": { \"id\": \"widget_id_12345\", \"name\": \"superwidget\" } } ] } . ", "url": "/firefly/head/tutorials/broadcast_data.html#example-2-inline-object-data-to-a-topic-no-datatype-verification", "relUrl": "/tutorials/broadcast_data.html#example-2-inline-object-data-to-a-topic-no-datatype-verification" - },"110": { + },"114": { "doc": "pages.broadcast_data", "title": "Notes on why setting a topic is important", "content": "The FireFly aggregator uses the topic (obfuscated on chain) to determine if a message is the next message in an in-flight sequence for any groups the node is involved in. If it is, then that message must receive all off-chain private data and be confirmed before any subsequent messages can be confirmed on the same sequence. So if you use the same topic in every message, then a single failed send on one topic blocks delivery of all messages between those parties, until the missing data arrives. Instead it is best practice to set the topic on your messages to a value that identifies an ordered stream of business processing. Some examples: . | A long-running business process instance identifier assigned at initiation | A real-world business transaction identifier used off-chain | The agreed identifier of an asset you are attaching a stream of evidence to | An NFT identifier that is assigned to an asset (digital twin scenarios) | An agreed primary key for a data resource being reconciled between multiple parties | . The topic field is an array, because there are cases (such as merging two identifiers) where you need a message to be deterministically ordered across multiple sequences. However, this is an advanced use case and you are likely to set a single topic on the vast majority of your messages. ", "url": "/firefly/head/tutorials/broadcast_data.html#notes-on-why-setting-a-topic-is-important", "relUrl": "/tutorials/broadcast_data.html#notes-on-why-setting-a-topic-is-important" - },"111": { + },"115": { "doc": "pages.broadcast_data", "title": "Example 3: Upload a blob with metadata and broadcast", "content": "Here we make two API calls. 1) Create the data object explicitly, using a multi-part form upload . | You can also just post JSON to this endpoint | . 2) Broadcast a message referring to that data . | The Blob attachment gets published to shared storage . | This happens the first time a broadcast happens on a data attachment | . | A pin goes to the blockchain | The metadata goes into a batch with the message | . Multipart form post of a file . Example curl command (Linux/Mac) to grab an image from the internet, and pipe it into a multi-part form post to FireFly. Note we use autometa to cause FireFly to automatically add the filename, and size, to the JSON part of the data object for us. curl -sLo - https://github.com/hyperledger/firefly/raw/main/docs/firefly_logo.png \\ | curl --form autometa=true --form file=@- \\ http://localhost:5000/api/v1/namespaces/default/data . Example data response from Blob upload . Status: 200 OK - your data is uploaded to your local FireFly node . At this point the data has not be shared with anyone else in the network . { // A uniquely generated ID, we can refer to when sending this data to other parties \"id\": \"97eb750f-0d0b-4c1d-9e37-1e92d1a22bb8\", \"validator\": \"json\", // the \"value\" part is JSON \"namespace\": \"default\", // from the URL // The hash is a combination of the hash of the \"value\" metadata, and the // hash of the blob \"hash\": \"997af6a9a19f06cc8a46872617b8bf974b106f744b2e407e94cc6959aa8cf0b8\", \"created\": \"2021-07-01T20:20:35.5462306Z\", \"value\": { \"filename\": \"-\", // dash is how curl represents the filename for stdin \"size\": 31185 // the size of the blob data }, \"blob\": { // A hash reference to the blob \"hash\": \"86e6b39b04b605dd1b03f70932976775962509d29ae1ad2628e684faabe48136\" // Note at this point there is no public reference. The only place // this data has been uploaded to is our own private data exchange. // It's ready to be published to everyone (broadcast), or privately // transferred (send) to other parties in the network. But that hasn't // happened yet. } } . Broadcast the uploaded data . Just include a reference to the id returned from the upload. POST /api/v1/namespaces/default/messages/broadcast . { \"data\": [ { \"id\": \"97eb750f-0d0b-4c1d-9e37-1e92d1a22bb8\" } ] } . ", "url": "/firefly/head/tutorials/broadcast_data.html#example-3-upload-a-blob-with-metadata-and-broadcast", "relUrl": "/tutorials/broadcast_data.html#example-3-upload-a-blob-with-metadata-and-broadcast" - },"112": { + },"116": { "doc": "pages.broadcast_data", "title": "Broadcasting Messages using the Sandbox", "content": "All of the functionality discussed above can be done through the FireFly Sandbox. To get started, open up the Web UI and Sanbox UI for at least one of your members. The URLs for these were printed in your terminal when you started your FireFly stack. In the sandbox, enter your message into the message field as seen in the screenshot below. Notice how the data field in the center panel updates in real time. Click the blue Run button. This should return a 202 response immediately in the Server Response section and will populate the right hand panel with transaction information after a few seconds. Go back to the FireFly UI (the URL for this would have been shown in the terminal when you started the stack) and you’ll see your successful blockchain transaction . ", "url": "/firefly/head/tutorials/broadcast_data.html#broadcasting-messages-using-the-sandbox", "relUrl": "/tutorials/broadcast_data.html#broadcasting-messages-using-the-sandbox" - },"113": { + },"117": { "doc": "pages.broadcast_data", "title": "pages.broadcast_data", "content": " ", "url": "/firefly/head/tutorials/broadcast_data.html", "relUrl": "/tutorials/broadcast_data.html" - },"114": { + },"118": { "doc": "pages.code_hierarchy", "title": "Firefly Code Hierarchy", "content": " ", "url": "/firefly/head/contributors/code_hierarchy.html#firefly-code-hierarchy", "relUrl": "/contributors/code_hierarchy.html#firefly-code-hierarchy" - },"115": { + },"119": { "doc": "pages.code_hierarchy", "title": "Table of contents", "content": ". Use the following diagram to better understand the hierarchy amongst the core FireFly components, plugins and utility frameworks: . ┌──────────┐ ┌───────────────┐ │ cmd ├──┤ firefly [Ff]│ - CLI entry point └──────────┘ │ │ - Creates parent context │ │ - Signal handling └─────┬─────────┘ │ ┌──────────┐ ┌─────┴─────────┐ - HTTP listener (Gorilla mux) │ internal ├──┤ api [As]│ * TLS (SSL), CORS configuration etc. └──────────┘ │ server │ * WS upgrade on same port │ │ - REST route definitions └─────┬─────────┘ * Simple routing logic only, all processing deferred to orchestrator │ ┌─────┴─────────┐ - REST route definition framework │ openapi [Oa]│ * Standardizes Body, Path, Query, Filter semantics │ spec | - OpenAPI 3.0 (Swagger) generation └─────┬─────────┘ * Including Swagger. UI │ ┌─────┴─────────┐ - WebSocket server │ [Ws]│ * Developer friendly JSON based protocol business app development │ websockets │ * Reliable sequenced delivery └─────┬─────────┘ * _Event interface [Ei] supports lower level integration with other compute frameworks/transports_ │ ┌─────┴─────────┐ - Extension point interface to listen for database change events │ admin [Ae]│ * For building microservice extensions to the core that run externally │ events | * Used by the Transaction Manager component └─────┬─────────┘ * Filtering to specific object types │ ┌─────┴─────────┐ - Core data types │ fftypes [Ft]│ * Used for API and Serialization │ │ * APIs can mask fields on input via router definition └─────┬─────────┘ │ ┌─────┴─────────┐ - Core runtime server. Initializes and owns instances of: │ [Or]│ * Components: Implement features ┌───────┬───┤ orchestrator │ * Plugins: Pluggable infrastructure services │ │ │ │ - Exposes actions to router │ │ └───────────────┘ * Processing starts here for all API calls │ │ │ Components: Components do the heavy lifting within the engine │ │ │ │ ┌───────────────┐ - Integrates with Blockchain Smart Contract logic across blockchain technologies │ ├───┤ contract [Cm]│ * Generates OpenAPI 3 / Swagger definitions for smart contracts, and propagates to network │ │ │ manager │ * Manages listeners for native Blockchain events, and routes those to application events │ │ └───────────────┘ * Convert to/from native Blockchain interfaces (ABI etc.) and FireFly Interface [FFI] format │ │ │ │ ┌───────────────┐ - Maintains a view of the entire network │ ├───┤ network [Nm]│ * Integrates with network permissioning [NP] plugin │ │ │ map │ * Integrates with broadcast plugin │ │ └───────────────┘ * Handles hierarchy of member identity, node identity and signing identity │ │ │ │ ┌───────────────┐ - Broadcast of data to all parties in the network │ ├───┤ broadcast [Bm]│ * Implements dispatcher for batch component │ │ │ manager | * Integrates with shared storage interface [Ss] plugin │ │ └───────────────┘ * Integrates with blockchain interface [Bi] plugin │ │ │ │ ┌───────────────┐ - Send private data to individual parties in the network │ ├───┤ private [Pm]│ * Implements dispatcher for batch component │ │ │ messaging | * Integrates with the data exchange [Dx] plugin │ │ └──────┬────────┘ * Messages can be pinned and sequenced via the blockchain, or just sent │ │ │ │ │ ┌──────┴────────┐ - Groups of parties, with isolated data and/or blockchains │ │ │ group [Gm]│ * Integrates with data exchange [Dx] plugin │ │ │ manager │ * Integrates with blockchain interface [Bi] plugin │ │ └───────────────┘ │ │ │ │ ┌───────────────┐ - Private data management and validation │ ├───┤ data [Dm]│ * Implements dispatcher for batch component │ │ │ manager │ * Integrates with data exchange [Dx] plugin │ │ └──────┬────────┘ * Integrates with blockchain interface [Bi] plugin │ │ │ │ │ ┌──────┴────────┐ - JSON data schema management and validation (architecture extensible to XML and more) │ │ │ json [Jv]│ * JSON Schema validation logic for outbound and inbound messages │ │ │ validator │ * Schema propagation │ │ └──────┬────────┘ * Integrates with broadcast plugin │ │ │ │ │ ┌──────┴────────┐ - Binary data addressable via ID or Hash │ │ │ blobstore [Bs]│ * Integrates with data exchange [Dx] plugin │ │ │ │ * Hashes data, and maintains mapping to payload references in blob storage │ │ └───────────────┘ * Integrates with blockchain interface [Bi] plugin │ │ │ │ ┌───────────────┐ - Download from shared storage │ ├───┤ shared [Sd]│ * Parallel asynchronous download │ │ │ download │ * Resilient retry and crash recovery │ │ └───────────────┘ * Notification to event aggregator on completion │ │ │ │ ┌───────────────┐ │ ├───┤ identity [Im] │ - Central identity management service across components │ │ │ manager │ * Resolves API input identity + key combos (short names, formatting etc.) │ │ │ │ * Resolves registered on-chain signing keys back to identities │ │ └───────────────┘ * Integrates with Blockchain Interface and pluggable Identity Interface (TBD) │ │ │ │ ┌───────────────┐ - Keeps track of all operations performed against external components via plugins │ ├───┤ operation [Om]│ * Updates database with inputs/outputs │ │ │ manager │ * Provides consistent retry semantics across plugins │ │ └───────────────┘ │ │ │ │ ┌───────────────┐ - Private data management and validation │ ├───┤ event [Em]│ * Implements dispatcher for batch component │ │ │ manager │ * Integrates with data exchange [Dx] plugin │ │ └──────┬────────┘ * Integrates with blockchain interface [Bi] plugin │ │ │ │ │ ┌──────┴────────┐ - Handles incoming external data │ │ │ [Ag]│ * Integrates with data exchange [Dx] plugin │ │ │ aggregator │ * Integrates with shared storage interface [Ss] plugin │ │ │ │ * Integrates with blockchain interface [Bi] plugin │ │ │ │ - Ensures valid events are dispatched only once all data is available │ │ └──────┬────────┘ * Context aware, to prevent block-the-world scenarios │ │ │ │ │ ┌──────┴────────┐ - Subscription manager │ │ │ [Sm]│ * Creation and management of subscriptions │ │ │ subscription │ * Creation and management of subscriptions │ │ │ manager │ * Message to Event matching logic │ │ └──────┬────────┘ │ │ │ │ │ ┌──────┴────────┐ - Manages delivery of events to connected applications │ │ │ event [Ed]│ * Integrates with data exchange [Dx] plugin │ │ │ dispatcher │ * Integrates with blockchain interface [Bi] plugin │ │ └───────────────┘ │ │ │ │ ┌───────────────┐ - Token creation/transfer initiation, indexing and coordination │ ├───┤ asset [Am]│ * Fungible tokens: Digitized value/settlement (coins) │ │ │ manager │ * Non-fungible tokens: NFTs / globally uniqueness / digital twins │ │ └───────────────┘ * Full indexing of transaction history │ │ [REST/WebSockets] │ │ ┌─────┴─────────────┐ ┌──────────┐ ┌─ │ │ │ ERC-20 / ERC-721 ├───┤ ERC-1155 ├───┤ Simple framework for building token connectors │ │ └───────────────────┘ └──────────┘ └─ │ │ │ │ ┌───────────────┐ │ ├───┤ sync / [Sa] │ - Sync/Async Bridge │ │ │ async bridge │ * Provides synchronous request/reply APIs │ │ │ │ * Translates to underlying event-driven API │ │ └───────────────┘ │ │ │ │ ┌───────────────┐ - Aggregates messages and data, with rolled up hashes for pinning │ ├───┤ batch [Ba]│ * Pluggable dispatchers │ │ │ manager │ - Database decoupled from main-line API processing │ │ │ │ * See architecture diagrams for more info on active/active sequencing │ │ └──────┬────────┘ - Manages creation of batch processor instances │ │ │ │ │ ┌──────┴────────┐ - Short lived agent spun up to assemble batches on demand │ │ │ batch [Bp]│ * Coupled to an author+type of messages │ │ │ processor │ - Builds batches of 100s messages for efficient pinning │ │ │ │ * Aggregates messages and data, with rolled up hashes for pinning │ │ └───────────────┘ - Shuts down automatically after a configurable inactivity period │ ... more TBD │ Plugins: Each plugin comprises a Go shim, plus a remote agent microservice runtime (if required) │ │ ┌───────────────┐ - Blockchain Interface ├───────────┤ [Bi]│ * Transaction submission - including signing key management │ │ blockchain │ * Event listening │ │ interface │ * Standardized operations, and custom on-chain coupling │ └─────┬─────────┘ │ │ │ ├─────────────────────┬───────────────────┐ │ ┌─────┴─────────┐ ┌───────┴───────┐ ┌───────┴────────┐ │ │ ethereum │ │ fabric │ │ corda/cordapps │ │ └─────┬─────────┘ └───────────────┘ └────────────────┘ │ [REST/WebSockets] │ ┌─────┴────────────────────┐ ┌────────────────────────┐ ┌─ │ │ transaction manager [Tm] ├───┤ Connector API [ffcapi] ├───┤ Simple framework for building blockchain connectors │ └──────────────────────────┘ └────────────────────────┘ └─ │ │ ┌───────────────┐ - Token interface ├───────────┤ tokens [Ti]│ * Standardizes core concepts: token pools, transfers, approvals │ │ interface │ * Pluggable across token standards │ └───────────────┘ * Supports simple implementation of custom token standards via microservice connector │ [REST/WebSockets] │ ┌─────┴─────────────┐ ┌──────────┐ ┌─ │ │ ERC-20 / ERC-721 ├───┤ ERC-1155 ├───┤ Simple framework for building token connectors │ └───────────────────┘ └──────────┘ └─ │ │ ┌───────────────┐ - P2P Content Addresssed Filesystem ├───────────┤ shared [Si]│ * Payload upload / download │ │ storage │ * Payload reference management │ │ interface │ │ └─────┬─────────┘ │ │ │ ├───────── ... extensible to any shared storage sytem, accessible to all members │ ┌─────┴─────────┐ │ │ ipfs │ │ └───────────────┘ │ │ ┌───────────────┐ - Private Data Exchange ├───────────┤ data [Dx]│ * Blob storage │ │ exchange │ * Private secure messaging │ └─────┬─────────┘ * Secure file transfer │ │ │ ├─────────────────────┬────────── ... extensible to any private data exchange tech │ ┌─────┴─────────┐ ┌───────┴───────┐ │ │ https / MTLS │ │ Kaleido │ │ └───────────────┘ └───────────────┘ │ │ ┌───────────────┐ - API Authentication and Authorization Interface ├───────────┤ api auth [Aa]│ * Authenticates security credentials (OpenID Connect id token JWTs etc.) │ │ │ * Extracts API/user identity (for identity interface to map) │ └─────┬─────────┘ * Enforcement point for fine grained API access control │ │ │ ├─────────────────────┬────────── ... extensible other single sign-on technologies │ ┌─────┴─────────┐ ┌───────┴───────┐ │ │ apikey │ │ jwt │ │ └───────────────┘ └───────────────┘ │ │ ┌───────────────┐ - Database Interactions ├───────────┤ database [Di]│ * Create, Read, Update, Delete (CRUD) actions │ │ interace │ * Filtering and update definition interace │ └─────┬─────────┘ * Migrations and Indexes │ │ │ ├───────── ... extensible to NoSQL (CouchDB / MongoDB etc.) │ ┌─────┴─────────┐ │ │ sqlcommon │ │ └─────┬─────────┘ │ ├───────────────────────┬───────── ... extensible other SQL databases │ ┌─────┴─────────┐ ┌───────┴────────┐ │ │ postgres │ │ sqlite3 │ │ └───────────────┘ └────────────────┘ │ │ ┌───────────────┐ - Connects the core event engine to external frameworks and applications ├───────────┤ event [Ei]│ * Supports long-lived (durable) and ephemeral event subscriptions │ │ interface │ * Batching, filtering, all handled in core prior to transport │ └─────┬─────────┘ * Interface supports connect-in (websocket) and connect-out (broker runtime style) plugins │ │ │ ├───────────────────────┬────────── ... extensible to additional event buses (Kafka, NATS, AMQP etc.) │ ┌─────┴─────────┐ ┌───────┴────────┐ │ │ websockets │ │ webhooks │ │ └───────────────┘ └────────────────┘ │ ... more TBD Additional utility framworks ┌───────────────┐ - REST API client │ rest [Re]│ * Provides convenience and logging │ client │ * Standardizes auth, config and retry logic └───────────────┘ * Built on Resty ┌───────────────┐ - WebSocket client │ wsclient [Wc]│ * Provides convenience and logging │ │ * Standardizes auth, config and reconnect logic └───────────────┘ * Built on Gorilla WebSockets ┌───────────────┐ - Translation framework │ i18n [In]│ * Every translations must be added to `en_translations.json` - with an `FF10101` key │ │ * Errors are wrapped, providing extra features from the `errors` package (stack etc.) └───────────────┘ * Description translations also supported, such as OpenAPI description ┌───────────────┐ - Logging framework │ log [Lo]│ * Logging framework (logrus) integrated with context based tagging │ │ * Context is used throughout the code to pass API invocation context, and logging context └───────────────┘ * Example: Every API call has an ID that can be traced, as well as a timeout ┌───────────────┐ - Configuration │ config [Co]│ * File and Environment Variable based logging framework (viper) │ │ * Primary config keys all defined centrally └───────────────┘ * Plugins integrate by returning their config structure for unmarshaling (JSON tags) . ", "url": "/firefly/head/contributors/code_hierarchy.html#table-of-contents", "relUrl": "/contributors/code_hierarchy.html#table-of-contents" - },"116": { + },"120": { "doc": "pages.code_hierarchy", "title": "pages.code_hierarchy", "content": " ", "url": "/firefly/head/contributors/code_hierarchy.html", "relUrl": "/contributors/code_hierarchy.html" - },"117": { + },"121": { "doc": "pages.code_overview", "title": "Firefly Code Overview", "content": " ", "url": "/firefly/head/contributors/code_overview.html#firefly-code-overview", "relUrl": "/contributors/code_overview.html#firefly-code-overview" - },"118": { + },"122": { "doc": "pages.code_overview", "title": "Table of contents", "content": ". | Developer Intro | Directories | . ", "url": "/firefly/head/contributors/code_overview.html#table-of-contents", "relUrl": "/contributors/code_overview.html#table-of-contents" - },"119": { + },"123": { "doc": "pages.code_overview", "title": "Developer Intro", "content": "FireFly is a second generation implementation re-engineered from the ground up to improve developer experience, runtime performance, and extensibility. This means a simplified REST/WebSocket programming model for app development, and a wider range of infrastructure options for deployment. It also means a focus on an architecture and code structure for a vibrant open source community. A few highlights: . | Golang codebase . | Strong coding standards, including unit test coverage, translation support, logging and more | Fast starting, low memory footprint, multi-threaded runtime | . | OpenAPI 3.0 API specification (Swagger) . | Generated from the API router code, to avoid divergence with the implementation | . | Active/active HA architecture for the core runtime . | Deferring to the core database for state high availability | Exploiting leader election where required | . | Fully pluggable architecture . | Everything from Database through to Blockchain, and Compute | Golang plugin infrastructure to decouple the core code from the implementation | Remote Agent model to decouple code languages, and HA designs | . | Updated API resource model . | Asset, Data, Message, Event, Topic, Transaction | . | Added flexibility, with simplified the developer experience: . | Versioning of data definitions | Introducing a first class Context construct link related events into a single sequence | Allow many pieces of data to be attached to a single message, and be automatically re-assembled on arrival | Clearer separation of concerns between the FireFly DB and the Application DB | Better search, filter and query support | . ", "url": "/firefly/head/contributors/code_overview.html#developer-intro", "relUrl": "/contributors/code_overview.html#developer-intro" - },"120": { + },"124": { "doc": "pages.code_overview", "title": "Directories", "content": "| internal: The core Golang implementation code | pkg: Interfaces intended for external project use | cmd: The command line entry point | smart_contracts: smart contract code for FireFly’s onchain logic | . ", "url": "/firefly/head/contributors/code_overview.html#directories", "relUrl": "/contributors/code_overview.html#directories" - },"121": { + },"125": { "doc": "pages.code_overview", "title": "pages.code_overview", "content": " ", "url": "/firefly/head/contributors/code_overview.html", "relUrl": "/contributors/code_overview.html" - },"122": { + },"126": { "doc": "pages.code_repositories", "title": "Code Repositories", "content": " ", "url": "/firefly/head/contributors/code_repositories.html#code-repositories", "relUrl": "/contributors/code_repositories.html#code-repositories" - },"123": { + },"127": { "doc": "pages.code_repositories", "title": "Table of contents", "content": ". FireFly has a plugin based architecture design, with a microservice runtime footprint. As such there are a number of repos, and the list will grow as the community evolves. But not to worry, one of those repos is a CLI designed to get you running with all the components you need in minutes! . | CLI / Developer experience | FireFly Samples | UI Explorer | Core | HTTP Data Exchange | Ethereum (Hyperledger Besu / Quorum) connector | Corda connector | Hyperledger Fabric connector | Token connector reference implementation (ERC1155) | . Note only the projects that are primarily built to support FireFly are listed here, not all of the ecosystem of projects that integrate underneath the plugins. ", "url": "/firefly/head/contributors/code_repositories.html#table-of-contents", "relUrl": "/contributors/code_repositories.html#table-of-contents" - },"124": { + },"128": { "doc": "pages.code_repositories", "title": "pages.code_repositories", "content": " ", "url": "/firefly/head/contributors/code_repositories.html", "relUrl": "/contributors/code_repositories.html" - },"125": { + },"129": { "doc": "Configuration Reference", "title": "Configuration Reference", "content": ". ", "url": "/firefly/head/reference/config.html", "relUrl": "/reference/config.html" - },"126": { + },"130": { "doc": "Configuration Reference", "title": "admin", "content": "| Key | Description | Type | Default Value | . | enabled | Deprecated - use spi.enabled instead | boolean | <nil> | . ", "url": "/firefly/head/reference/config.html#admin", "relUrl": "/reference/config.html#admin" - },"127": { + },"131": { "doc": "Configuration Reference", "title": "api", "content": "| Key | Description | Type | Default Value | . | defaultFilterLimit | The maximum number of rows to return if no limit is specified on an API request | int | 25 | . | dynamicPublicURLHeader | Dynamic header that informs the backend the base public URL for the request, in order to build URL links in OpenAPI/SwaggerUI | string | <nil> | . | maxFilterLimit | The largest value of limit that an HTTP client can specify in a request | int | 1000 | . | passthroughHeaders | A list of HTTP request headers to pass through to dependency microservices | []string | [] | . | requestMaxTimeout | The maximum amount of time that an HTTP client can specify in a Request-Timeout header to keep a specific request open | time.Duration | 10m | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 120s | . ", "url": "/firefly/head/reference/config.html#api", "relUrl": "/reference/config.html#api" - },"128": { + },"132": { "doc": "Configuration Reference", "title": "asset.manager", "content": "| Key | Description | Type | Default Value | . | keyNormalization | Mechanism to normalize keys before using them. Valid options are blockchain_plugin - use blockchain plugin (default) or none - do not attempt normalization (deprecated - use namespaces.predefined[].asset.manager.keyNormalization) | string | blockchain_plugin | . ", "url": "/firefly/head/reference/config.html#assetmanager", "relUrl": "/reference/config.html#assetmanager" - },"129": { + },"133": { "doc": "Configuration Reference", "title": "batch.manager", "content": "| Key | Description | Type | Default Value | . | minimumPollDelay | The minimum time the batch manager waits between polls on the DB - to prevent thrashing | time.Duration | 100ms | . | pollTimeout | How long to wait without any notifications of new messages before doing a page query | time.Duration | 30s | . | readPageSize | The size of each page of messages read from the database into memory when assembling batches | int | 100 | . ", "url": "/firefly/head/reference/config.html#batchmanager", "relUrl": "/reference/config.html#batchmanager" - },"130": { + },"134": { "doc": "Configuration Reference", "title": "batch.retry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor | float32 | 2 | . | initDelay | The initial retry delay | time.Duration | 250ms | . | maxDelay | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#batchretry", "relUrl": "/reference/config.html#batchretry" - },"131": { + },"135": { "doc": "Configuration Reference", "title": "blobreceiver.retry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor | float32 | 2 | . | initialDelay | The initial retry delay | time.Duration | 250ms | . | maxDelay | The maximum retry delay | time.Duration | 1m | . ", "url": "/firefly/head/reference/config.html#blobreceiverretry", "relUrl": "/reference/config.html#blobreceiverretry" - },"132": { + },"136": { "doc": "Configuration Reference", "title": "blobreceiver.worker", "content": "| Key | Description | Type | Default Value | . | batchMaxInserts | The maximum number of items the blob receiver worker will insert in a batch | int | 200 | . | batchTimeout | The maximum amount of the the blob receiver worker will wait | time.Duration | 50ms | . | count | The number of blob receiver workers | int | 5 | . ", "url": "/firefly/head/reference/config.html#blobreceiverworker", "relUrl": "/reference/config.html#blobreceiverworker" - },"133": { + },"137": { "doc": "Configuration Reference", "title": "broadcast.batch", "content": "| Key | Description | Type | Default Value | . | agentTimeout | How long to keep around a batching agent for a sending identity before disposal | string | 2m | . | payloadLimit | The maximum payload size of a batch for broadcast messages | BytesSize | 800Kb | . | size | The maximum number of messages that can be packed into a batch | int | 200 | . | timeout | The timeout to wait for a batch to fill, before sending | time.Duration | 1s | . ", "url": "/firefly/head/reference/config.html#broadcastbatch", "relUrl": "/reference/config.html#broadcastbatch" - },"134": { + },"138": { "doc": "Configuration Reference", "title": "cache", "content": "| Key | Description | Type | Default Value | . | enabled | Enables caching, defaults to true | boolean | true | . ", "url": "/firefly/head/reference/config.html#cache", "relUrl": "/reference/config.html#cache" - },"135": { + },"139": { "doc": "Configuration Reference", "title": "cache.addressresolver", "content": "| Key | Description | Type | Default Value | . | limit | Max number of cached items for address resolver | int | 1000 | . | ttl | Time to live of cached items for address resolver | string | 24h | . ", "url": "/firefly/head/reference/config.html#cacheaddressresolver", "relUrl": "/reference/config.html#cacheaddressresolver" - },"136": { + },"140": { "doc": "Configuration Reference", "title": "cache.batch", "content": "| Key | Description | Type | Default Value | . | limit | Max number of cached items for batches | int | 100 | . | ttl | Time to live of cache items for batches | string | 5m | . ", "url": "/firefly/head/reference/config.html#cachebatch", "relUrl": "/reference/config.html#cachebatch" - },"137": { + },"141": { "doc": "Configuration Reference", "title": "cache.blockchain", "content": "| Key | Description | Type | Default Value | . | limit | Max number of cached items for blockchain | int | 100 | . | ttl | Time to live of cached items for blockchain | string | 5m | . ", "url": "/firefly/head/reference/config.html#cacheblockchain", "relUrl": "/reference/config.html#cacheblockchain" - },"138": { + },"142": { "doc": "Configuration Reference", "title": "cache.blockchainevent", "content": "| Key | Description | Type | Default Value | . | limit | Max number of cached blockchain events for transactions | int | 1000 | . | ttl | Time to live of cached blockchain events for transactions | string | 5m | . ", "url": "/firefly/head/reference/config.html#cacheblockchainevent", "relUrl": "/reference/config.html#cacheblockchainevent" - },"139": { + },"143": { "doc": "Configuration Reference", "title": "cache.eventlistenertopic", "content": "| Key | Description | Type | Default Value | . | limit | Max number of cached items for blockchain listener topics | int | 100 | . | ttl | Time to live of cached items for blockchain listener topics | string | 5m | . ", "url": "/firefly/head/reference/config.html#cacheeventlistenertopic", "relUrl": "/reference/config.html#cacheeventlistenertopic" - },"140": { + },"144": { "doc": "Configuration Reference", "title": "cache.group", "content": "| Key | Description | Type | Default Value | . | limit | Max number of cached items for groups | int | 50 | . | ttl | Time to live of cached items for groups | string | 1h | . ", "url": "/firefly/head/reference/config.html#cachegroup", "relUrl": "/reference/config.html#cachegroup" - },"141": { + },"145": { "doc": "Configuration Reference", "title": "cache.identity", "content": "| Key | Description | Type | Default Value | . | limit | Max number of cached identities for identity manager | int | 100 | . | ttl | Time to live of cached identities for identity manager | string | 1h | . ", "url": "/firefly/head/reference/config.html#cacheidentity", "relUrl": "/reference/config.html#cacheidentity" - },"142": { + },"146": { "doc": "Configuration Reference", "title": "cache.message", "content": "| Key | Description | Type | Default Value | . | size | Max size of cached messages for data manager | BytesSize | 50Mb | . | ttl | Time to live of cached messages for data manager | string | 5m | . ", "url": "/firefly/head/reference/config.html#cachemessage", "relUrl": "/reference/config.html#cachemessage" - },"143": { + },"147": { "doc": "Configuration Reference", "title": "cache.methods", "content": "| Key | Description | Type | Default Value | . | limit | Max number of cached items for schema validations on blockchain methods | int | 200 | . | ttl | Time to live of cached items for schema validations on blockchain methods | string | 5m | . ", "url": "/firefly/head/reference/config.html#cachemethods", "relUrl": "/reference/config.html#cachemethods" - },"144": { + },"148": { "doc": "Configuration Reference", "title": "cache.operations", "content": "| Key | Description | Type | Default Value | . | limit | Max number of cached items for operations | int | 1000 | . | ttl | Time to live of cached items for operations | string | 5m | . ", "url": "/firefly/head/reference/config.html#cacheoperations", "relUrl": "/reference/config.html#cacheoperations" - },"145": { + },"149": { "doc": "Configuration Reference", "title": "cache.tokenpool", "content": "| Key | Description | Type | Default Value | . | limit | Max number of cached items for token pools | int | 100 | . | ttl | Time to live of cached items for token pool | string | 1h | . ", "url": "/firefly/head/reference/config.html#cachetokenpool", "relUrl": "/reference/config.html#cachetokenpool" - },"146": { + },"150": { "doc": "Configuration Reference", "title": "cache.transaction", "content": "| Key | Description | Type | Default Value | . | size | Max size of cached transactions | BytesSize | 1Mb | . | ttl | Time to live of cached transactions | string | 5m | . ", "url": "/firefly/head/reference/config.html#cachetransaction", "relUrl": "/reference/config.html#cachetransaction" - },"147": { + },"151": { "doc": "Configuration Reference", "title": "cache.validator", "content": "| Key | Description | Type | Default Value | . | size | Max size of cached validators for data manager | BytesSize | 1Mb | . | ttl | Time to live of cached validators for data manager | string | 1h | . ", "url": "/firefly/head/reference/config.html#cachevalidator", "relUrl": "/reference/config.html#cachevalidator" - },"148": { + },"152": { "doc": "Configuration Reference", "title": "config", "content": "| Key | Description | Type | Default Value | . | autoReload | Monitor the configuration file for changes, and automatically add/remove/reload namespaces and plugins | boolean | <nil> | . ", "url": "/firefly/head/reference/config.html#config", "relUrl": "/reference/config.html#config" - },"149": { + },"153": { "doc": "Configuration Reference", "title": "cors", "content": "| Key | Description | Type | Default Value | . | credentials | CORS setting to control whether a browser allows credentials to be sent to this API | boolean | true | . | debug | Whether debug is enabled for the CORS implementation | boolean | false | . | enabled | Whether CORS is enabled | boolean | true | . | headers | CORS setting to control the allowed headers | []string | [*] | . | maxAge | The maximum age a browser should rely on CORS checks | time.Duration | 600 | . | methods | CORS setting to control the allowed methods | []string | [GET POST PUT PATCH DELETE] | . | origins | CORS setting to control the allowed origins | []string | [*] | . ", "url": "/firefly/head/reference/config.html#cors", "relUrl": "/reference/config.html#cors" - },"150": { + },"154": { "doc": "Configuration Reference", "title": "debug", "content": "| Key | Description | Type | Default Value | . | address | The HTTP interface the go debugger binds to | string | localhost | . | port | An HTTP port on which to enable the go debugger | int | -1 | . ", "url": "/firefly/head/reference/config.html#debug", "relUrl": "/reference/config.html#debug" - },"151": { + },"155": { "doc": "Configuration Reference", "title": "download.retry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor | float32 | 2 | . | initialDelay | The initial retry delay | time.Duration | 100ms | . | maxAttempts | The maximum number attempts | int | 100 | . | maxDelay | The maximum retry delay | time.Duration | 1m | . ", "url": "/firefly/head/reference/config.html#downloadretry", "relUrl": "/reference/config.html#downloadretry" - },"152": { + },"156": { "doc": "Configuration Reference", "title": "download.worker", "content": "| Key | Description | Type | Default Value | . | count | The number of download workers | int | 10 | . | queueLength | The length of the work queue in the channel to the workers - defaults to 2x the worker count | int | <nil> | . ", "url": "/firefly/head/reference/config.html#downloadworker", "relUrl": "/reference/config.html#downloadworker" - },"153": { + },"157": { "doc": "Configuration Reference", "title": "event.aggregator", "content": "| Key | Description | Type | Default Value | . | batchSize | The maximum number of records to read from the DB before performing an aggregation run | BytesSize | 200 | . | batchTimeout | How long to wait for new events to arrive before performing aggregation on a page of events | time.Duration | 0ms | . | firstEvent | The first event the aggregator should process, if no previous offest is stored in the DB. Valid options are oldest or newest | string | oldest | . | pollTimeout | The time to wait without a notification of new events, before trying a select on the table | time.Duration | 30s | . | rewindQueryLimit | Safety limit on the maximum number of records to search when performing queries to search for rewinds | int | 1000 | . | rewindQueueLength | The size of the queue into the rewind dispatcher | int | 10 | . | rewindTimeout | The minimum time to wait for rewinds to accumulate before resolving them | time.Duration | 50ms | . ", "url": "/firefly/head/reference/config.html#eventaggregator", "relUrl": "/reference/config.html#eventaggregator" - },"154": { + },"158": { "doc": "Configuration Reference", "title": "event.aggregator.retry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor | float32 | 2 | . | initDelay | The initial retry delay | time.Duration | 100ms | . | maxDelay | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#eventaggregatorretry", "relUrl": "/reference/config.html#eventaggregatorretry" - },"155": { + },"159": { "doc": "Configuration Reference", "title": "event.dbevents", "content": "| Key | Description | Type | Default Value | . | bufferSize | The size of the buffer of change events | BytesSize | 100 | . ", "url": "/firefly/head/reference/config.html#eventdbevents", "relUrl": "/reference/config.html#eventdbevents" - },"156": { + },"160": { "doc": "Configuration Reference", "title": "event.dispatcher", "content": "| Key | Description | Type | Default Value | . | batchTimeout | A short time to wait for new events to arrive before re-polling for new events | time.Duration | 0ms | . | bufferLength | The number of events + attachments an individual dispatcher should hold in memory ready for delivery to the subscription | int | 5 | . | pollTimeout | The time to wait without a notification of new events, before trying a select on the table | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#eventdispatcher", "relUrl": "/reference/config.html#eventdispatcher" - },"157": { + },"161": { "doc": "Configuration Reference", "title": "event.dispatcher.retry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor | float32 | <nil> | . | initDelay | The initial retry delay | time.Duration | <nil> | . | maxDelay | The maximum retry delay | time.Duration | <nil> | . ", "url": "/firefly/head/reference/config.html#eventdispatcherretry", "relUrl": "/reference/config.html#eventdispatcherretry" - },"158": { + },"162": { "doc": "Configuration Reference", "title": "event.transports", "content": "| Key | Description | Type | Default Value | . | default | The default event transport for new subscriptions | string | websockets | . | enabled | Which event interface plugins are enabled | boolean | [websockets webhooks] | . ", "url": "/firefly/head/reference/config.html#eventtransports", "relUrl": "/reference/config.html#eventtransports" - },"159": { + },"163": { "doc": "Configuration Reference", "title": "events.webhooks", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | headers | Adds custom headers to HTTP requests | map[string]string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . ", "url": "/firefly/head/reference/config.html#eventswebhooks", "relUrl": "/reference/config.html#eventswebhooks" - },"160": { + },"164": { "doc": "Configuration Reference", "title": "events.webhooks.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#eventswebhooksauth", "relUrl": "/reference/config.html#eventswebhooksauth" - },"161": { + },"165": { "doc": "Configuration Reference", "title": "events.webhooks.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to connect through | string | <nil> | . ", "url": "/firefly/head/reference/config.html#eventswebhooksproxy", "relUrl": "/reference/config.html#eventswebhooksproxy" - },"162": { + },"166": { "doc": "Configuration Reference", "title": "events.webhooks.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#eventswebhooksretry", "relUrl": "/reference/config.html#eventswebhooksretry" - },"163": { + },"167": { "doc": "Configuration Reference", "title": "events.webhooks.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#eventswebhookstls", "relUrl": "/reference/config.html#eventswebhookstls" - },"164": { + },"168": { "doc": "Configuration Reference", "title": "events.websockets", "content": "| Key | Description | Type | Default Value | . | readBufferSize | WebSocket read buffer size | BytesSize | 16Kb | . | writeBufferSize | WebSocket write buffer size | BytesSize | 16Kb | . ", "url": "/firefly/head/reference/config.html#eventswebsockets", "relUrl": "/reference/config.html#eventswebsockets" - },"165": { + },"169": { "doc": "Configuration Reference", "title": "histograms", "content": "| Key | Description | Type | Default Value | . | maxChartRows | The maximum rows to fetch for each histogram bucket | int | 100 | . ", "url": "/firefly/head/reference/config.html#histograms", "relUrl": "/reference/config.html#histograms" - },"166": { + },"170": { "doc": "Configuration Reference", "title": "http", "content": "| Key | Description | Type | Default Value | . | address | The IP address on which the HTTP API should listen | IP Address string | 127.0.0.1 | . | port | The port on which the HTTP API should listen | int | 5000 | . | publicURL | The fully qualified public URL for the API. This is used for building URLs in HTTP responses and in OpenAPI Spec generation | URL string | <nil> | . | readTimeout | The maximum time to wait when reading from an HTTP connection | time.Duration | 15s | . | shutdownTimeout | The maximum amount of time to wait for any open HTTP requests to finish before shutting down the HTTP server | time.Duration | 10s | . | writeTimeout | The maximum time to wait when writing to an HTTP connection | time.Duration | 15s | . ", "url": "/firefly/head/reference/config.html#http", "relUrl": "/reference/config.html#http" - },"167": { + },"171": { "doc": "Configuration Reference", "title": "http.auth", "content": "| Key | Description | Type | Default Value | . | type | The auth plugin to use for server side authentication of requests | string | <nil> | . ", "url": "/firefly/head/reference/config.html#httpauth", "relUrl": "/reference/config.html#httpauth" - },"168": { + },"172": { "doc": "Configuration Reference", "title": "http.auth.basic", "content": "| Key | Description | Type | Default Value | . | passwordfile | The path to a .htpasswd file to use for authenticating requests. Passwords should be hashed with bcrypt. | string | <nil> | . ", "url": "/firefly/head/reference/config.html#httpauthbasic", "relUrl": "/reference/config.html#httpauthbasic" - },"169": { + },"173": { "doc": "Configuration Reference", "title": "http.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#httptls", "relUrl": "/reference/config.html#httptls" - },"170": { + },"174": { "doc": "Configuration Reference", "title": "log", "content": "| Key | Description | Type | Default Value | . | compress | Determines if the rotated log files should be compressed using gzip | boolean | <nil> | . | filename | Filename is the file to write logs to. Backup log files will be retained in the same directory | string | <nil> | . | filesize | MaxSize is the maximum size the log file before it gets rotated | BytesSize | 100m | . | forceColor | Force color to be enabled, even when a non-TTY output is detected | boolean | <nil> | . | includeCodeInfo | Enables the report caller for including the calling file and line number, and the calling function. If using text logs, it uses the logrus text format rather than the default prefix format. | boolean | false | . | level | The log level - error, warn, info, debug, trace | string | info | . | maxAge | The maximum time to retain old log files based on the timestamp encoded in their filename | time.Duration | 24h | . | maxBackups | Maximum number of old log files to retain | int | 2 | . | noColor | Force color to be disabled, event when TTY output is detected | boolean | <nil> | . | timeFormat | Custom time format for logs | Time format string | 2006-01-02T15:04:05.000Z07:00 | . | utc | Use UTC timestamps for logs | boolean | false | . ", "url": "/firefly/head/reference/config.html#log", "relUrl": "/reference/config.html#log" - },"171": { + },"175": { "doc": "Configuration Reference", "title": "log.json", "content": "| Key | Description | Type | Default Value | . | enabled | Enables JSON formatted logs rather than text. All log color settings are ignored when enabled. | boolean | false | . ", "url": "/firefly/head/reference/config.html#logjson", "relUrl": "/reference/config.html#logjson" - },"172": { + },"176": { "doc": "Configuration Reference", "title": "log.json.fields", "content": "| Key | Description | Type | Default Value | . | file | configures the JSON key containing the calling file | string | file | . | func | Configures the JSON key containing the calling function | string | func | . | level | Configures the JSON key containing the log level | string | level | . | message | Configures the JSON key containing the log message | string | message | . | timestamp | Configures the JSON key containing the timestamp of the log | string | @timestamp | . ", "url": "/firefly/head/reference/config.html#logjsonfields", "relUrl": "/reference/config.html#logjsonfields" - },"173": { + },"177": { "doc": "Configuration Reference", "title": "message.writer", "content": "| Key | Description | Type | Default Value | . | batchMaxInserts | The maximum number of database inserts to include when writing a single batch of messages + data | int | 200 | . | batchTimeout | How long to wait for more messages to arrive before flushing the batch | time.Duration | 10ms | . | count | The number of message writer workers | int | 5 | . ", "url": "/firefly/head/reference/config.html#messagewriter", "relUrl": "/reference/config.html#messagewriter" - },"174": { + },"178": { "doc": "Configuration Reference", "title": "metrics", "content": "| Key | Description | Type | Default Value | . | address | The IP address on which the metrics HTTP API should listen | int | 127.0.0.1 | . | enabled | Enables the metrics API | boolean | true | . | path | The path from which to serve the Prometheus metrics | string | /metrics | . | port | The port on which the metrics HTTP API should listen | int | 6000 | . | publicURL | The fully qualified public URL for the metrics API. This is used for building URLs in HTTP responses and in OpenAPI Spec generation | URL string | <nil> | . | readTimeout | The maximum time to wait when reading from an HTTP connection | time.Duration | 15s | . | shutdownTimeout | The maximum amount of time to wait for any open HTTP requests to finish before shutting down the HTTP server | time.Duration | 10s | . | writeTimeout | The maximum time to wait when writing to an HTTP connection | time.Duration | 15s | . ", "url": "/firefly/head/reference/config.html#metrics", "relUrl": "/reference/config.html#metrics" - },"175": { + },"179": { "doc": "Configuration Reference", "title": "metrics.auth", "content": "| Key | Description | Type | Default Value | . | type | The auth plugin to use for server side authentication of requests | string | <nil> | . ", "url": "/firefly/head/reference/config.html#metricsauth", "relUrl": "/reference/config.html#metricsauth" - },"176": { + },"180": { "doc": "Configuration Reference", "title": "metrics.auth.basic", "content": "| Key | Description | Type | Default Value | . | passwordfile | The path to a .htpasswd file to use for authenticating requests. Passwords should be hashed with bcrypt. | string | <nil> | . ", "url": "/firefly/head/reference/config.html#metricsauthbasic", "relUrl": "/reference/config.html#metricsauthbasic" - },"177": { + },"181": { "doc": "Configuration Reference", "title": "metrics.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#metricstls", "relUrl": "/reference/config.html#metricstls" - },"178": { + },"182": { "doc": "Configuration Reference", "title": "namespaces", "content": "| Key | Description | Type | Default Value | . | default | The default namespace - must be in the predefined list | string | default | . | predefined | A list of namespaces to ensure exists, without requiring a broadcast from the network | List string | <nil> | . ", "url": "/firefly/head/reference/config.html#namespaces", "relUrl": "/reference/config.html#namespaces" - },"179": { + },"183": { "doc": "Configuration Reference", "title": "namespaces.predefined[]", "content": "| Key | Description | Type | Default Value | . | defaultKey | A default signing key for blockchain transactions within this namespace | string | <nil> | . | description | A description for the namespace | string | <nil> | . | name | The name of the namespace (must be unique) | string | <nil> | . | plugins | The list of plugins for this namespace | string | <nil> | . ", "url": "/firefly/head/reference/config.html#namespacespredefined", "relUrl": "/reference/config.html#namespacespredefined" - },"180": { + },"184": { "doc": "Configuration Reference", "title": "namespaces.predefined[].asset.manager", "content": "| Key | Description | Type | Default Value | . | keyNormalization | Mechanism to normalize keys before using them. Valid options are blockchain_plugin - use blockchain plugin (default) or none - do not attempt normalization | string | <nil> | . ", "url": "/firefly/head/reference/config.html#namespacespredefinedassetmanager", "relUrl": "/reference/config.html#namespacespredefinedassetmanager" - },"181": { + },"185": { "doc": "Configuration Reference", "title": "namespaces.predefined[].multiparty", "content": "| Key | Description | Type | Default Value | . | enabled | Enables multi-party mode for this namespace (defaults to true if an org name or key is configured, either here or at the root level) | boolean | <nil> | . | networknamespace | The shared namespace name to be sent in multiparty messages, if it differs from the local namespace name | string | <nil> | . ", "url": "/firefly/head/reference/config.html#namespacespredefinedmultiparty", "relUrl": "/reference/config.html#namespacespredefinedmultiparty" - },"182": { + },"186": { "doc": "Configuration Reference", "title": "namespaces.predefined[].multiparty.contract[]", "content": "| Key | Description | Type | Default Value | . | firstEvent | The first event the contract should process. Valid options are oldest or newest | string | <nil> | . | location | A blockchain-specific contract location. For example, an Ethereum contract address, or a Fabric chaincode name and channel | string | <nil> | . | options | Blockchain-specific contract options | string | <nil> | . ", "url": "/firefly/head/reference/config.html#namespacespredefinedmultipartycontract", "relUrl": "/reference/config.html#namespacespredefinedmultipartycontract" - },"183": { + },"187": { "doc": "Configuration Reference", "title": "namespaces.predefined[].multiparty.node", "content": "| Key | Description | Type | Default Value | . | description | A description for the node in this namespace | string | <nil> | . | name | The node name for this namespace | string | <nil> | . ", "url": "/firefly/head/reference/config.html#namespacespredefinedmultipartynode", "relUrl": "/reference/config.html#namespacespredefinedmultipartynode" - },"184": { + },"188": { "doc": "Configuration Reference", "title": "namespaces.predefined[].multiparty.org", "content": "| Key | Description | Type | Default Value | . | description | A description for the local root organization within this namespace | string | <nil> | . | key | The signing key allocated to the root organization within this namespace | string | <nil> | . | name | A short name for the local root organization within this namespace | string | <nil> | . ", "url": "/firefly/head/reference/config.html#namespacespredefinedmultipartyorg", "relUrl": "/reference/config.html#namespacespredefinedmultipartyorg" - },"185": { + },"189": { "doc": "Configuration Reference", "title": "namespaces.predefined[].tlsConfigs[]", "content": "| Key | Description | Type | Default Value | . | name | Name of the TLS Config | string | <nil> | . ", "url": "/firefly/head/reference/config.html#namespacespredefinedtlsconfigs", "relUrl": "/reference/config.html#namespacespredefinedtlsconfigs" - },"186": { + },"190": { "doc": "Configuration Reference", "title": "namespaces.predefined[].tlsConfigs[].tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#namespacespredefinedtlsconfigstls", "relUrl": "/reference/config.html#namespacespredefinedtlsconfigstls" - },"187": { + },"191": { "doc": "Configuration Reference", "title": "namespaces.retry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor | float32 | 2 | . | initDelay | The initial retry delay | time.Duration | 5s | . | maxDelay | The maximum retry delay | time.Duration | 1m | . ", "url": "/firefly/head/reference/config.html#namespacesretry", "relUrl": "/reference/config.html#namespacesretry" - },"188": { + },"192": { "doc": "Configuration Reference", "title": "node", "content": "| Key | Description | Type | Default Value | . | description | The description of this FireFly node | string | <nil> | . | name | The name of this FireFly node | string | <nil> | . ", "url": "/firefly/head/reference/config.html#node", "relUrl": "/reference/config.html#node" - },"189": { + },"193": { "doc": "Configuration Reference", "title": "opupdate.retry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor | float32 | 2 | . | initialDelay | The initial retry delay | time.Duration | 250ms | . | maxDelay | The maximum retry delay | time.Duration | 1m | . ", "url": "/firefly/head/reference/config.html#opupdateretry", "relUrl": "/reference/config.html#opupdateretry" - },"190": { + },"194": { "doc": "Configuration Reference", "title": "opupdate.worker", "content": "| Key | Description | Type | Default Value | . | batchMaxInserts | The maximum number of database inserts to include when writing a single batch of messages + data | int | 200 | . | batchTimeout | How long to wait for more messages to arrive before flushing the batch | time.Duration | 50ms | . | count | The number of operation update works | int | 5 | . | queueLength | The size of the queue for the Operation Update worker | int | 50 | . ", "url": "/firefly/head/reference/config.html#opupdateworker", "relUrl": "/reference/config.html#opupdateworker" - },"191": { + },"195": { "doc": "Configuration Reference", "title": "orchestrator", "content": "| Key | Description | Type | Default Value | . | startupAttempts | The number of times to attempt to connect to core infrastructure on startup | string | 5 | . ", "url": "/firefly/head/reference/config.html#orchestrator", "relUrl": "/reference/config.html#orchestrator" - },"192": { + },"196": { "doc": "Configuration Reference", "title": "org", "content": "| Key | Description | Type | Default Value | . | description | A description of the organization to which this FireFly node belongs (deprecated - should be set on each multi-party namespace instead) | string | <nil> | . | key | The signing key allocated to the organization (deprecated - should be set on each multi-party namespace instead) | string | <nil> | . | name | The name of the organization to which this FireFly node belongs (deprecated - should be set on each multi-party namespace instead) | string | <nil> | . ", "url": "/firefly/head/reference/config.html#org", "relUrl": "/reference/config.html#org" - },"193": { + },"197": { "doc": "Configuration Reference", "title": "plugins", "content": "| Key | Description | Type | Default Value | . | auth | Authorization plugin configuration | map[string]string | <nil> | . | blockchain | The list of configured Blockchain plugins | string | <nil> | . | database | The list of configured Database plugins | string | <nil> | . | dataexchange | The array of configured Data Exchange plugins | string | <nil> | . | identity | The list of available Identity plugins | string | <nil> | . | sharedstorage | The list of configured Shared Storage plugins | string | <nil> | . | tokens | The token plugin configurations | string | <nil> | . ", "url": "/firefly/head/reference/config.html#plugins", "relUrl": "/reference/config.html#plugins" - },"194": { + },"198": { "doc": "Configuration Reference", "title": "plugins.auth[]", "content": "| Key | Description | Type | Default Value | . | name | The name of the auth plugin to use | string | <nil> | . | type | The type of the auth plugin to use | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsauth", "relUrl": "/reference/config.html#pluginsauth" - },"195": { + },"199": { "doc": "Configuration Reference", "title": "plugins.auth[].basic", "content": "| Key | Description | Type | Default Value | . | passwordfile | The path to a .htpasswd file to use for authenticating requests. Passwords should be hashed with bcrypt. | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsauthbasic", "relUrl": "/reference/config.html#pluginsauthbasic" - },"196": { + },"200": { "doc": "Configuration Reference", "title": "plugins.blockchain[]", "content": "| Key | Description | Type | Default Value | . | name | The name of the configured Blockchain plugin | string | <nil> | . | type | The type of the configured Blockchain Connector plugin | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchain", "relUrl": "/reference/config.html#pluginsblockchain" - },"197": { + },"201": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.addressResolver", "content": "| Key | Description | Type | Default Value | . | alwaysResolve | Causes the address resolver to be invoked on every API call that submits a signing key, regardless of whether the input string conforms to an 0x address. Also disables any result caching | boolean | <nil> | . | bodyTemplate | The body go template string to use when making HTTP requests. The template input contains ‘.Key’ and ‘.Intent’ string variables. | Go Template string | <nil> | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | headers | Adds custom headers to HTTP requests | string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | method | The HTTP method to use when making requests to the Address Resolver | string | GET | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | responseField | The name of a JSON field that is provided in the response, that contains the ethereum address (default address) | string | address | . | retainOriginal | When true the original pre-resolved string is retained after the lookup, and passed down to Ethconnect as the from address | boolean | <nil> | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . | url | The URL of the Address Resolver | string | <nil> | . | urlTemplate | The URL Go template string to use when calling the Address Resolver. The template input contains ‘.Key’ and ‘.Intent’ string variables. | Go Template string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumaddressresolver", "relUrl": "/reference/config.html#pluginsblockchainethereumaddressresolver" - },"198": { + },"202": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.addressResolver.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumaddressresolverauth", "relUrl": "/reference/config.html#pluginsblockchainethereumaddressresolverauth" - },"199": { + },"203": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.addressResolver.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to use when connecting to the Address Resolver | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumaddressresolverproxy", "relUrl": "/reference/config.html#pluginsblockchainethereumaddressresolverproxy" - },"200": { + },"204": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.addressResolver.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumaddressresolverretry", "relUrl": "/reference/config.html#pluginsblockchainethereumaddressresolverretry" - },"201": { + },"205": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.addressResolver.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumaddressresolvertls", "relUrl": "/reference/config.html#pluginsblockchainethereumaddressresolvertls" - },"202": { + },"206": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.ethconnect", "content": "| Key | Description | Type | Default Value | . | batchSize | The number of events Ethconnect should batch together for delivery to FireFly core. Only applies when automatically creating a new event stream | int | 50 | . | batchTimeout | How long Ethconnect should wait for new events to arrive and fill a batch, before sending the batch to FireFly core. Only applies when automatically creating a new event stream | time.Duration | 500 | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | fromBlock | The first event this FireFly instance should listen to from the BatchPin smart contract. Default=0. Only affects initial creation of the event stream | Address string | 0 | . | headers | Adds custom headers to HTTP requests | map[string]string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | instance | The Ethereum address of the FireFly BatchPin smart contract that has been deployed to the blockchain | Address string | <nil> | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | prefixLong | The prefix that will be used for Ethconnect specific HTTP headers when FireFly makes requests to Ethconnect | string | firefly | . | prefixShort | The prefix that will be used for Ethconnect specific query parameters when FireFly makes requests to Ethconnect | string | fly | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . | topic | The websocket listen topic that the node should register on, which is important if there are multiple nodes using a single ethconnect | string | <nil> | . | url | The URL of the Ethconnect instance | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumethconnect", "relUrl": "/reference/config.html#pluginsblockchainethereumethconnect" - },"203": { + },"207": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.ethconnect.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumethconnectauth", "relUrl": "/reference/config.html#pluginsblockchainethereumethconnectauth" - },"204": { + },"208": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.ethconnect.backgroundStart", "content": "| Key | Description | Type | Default Value | . | enabled | Start the Ethconnect plugin in the background and enter retry loop if failed to start | boolean | <nil> | . | factor | Set the factor by which the delay increases when retrying | float32 | 2 | . | initialDelay | Delay between restarts in the case where we retry to restart the ethereum plugin | time.Duration | 5s | . | maxDelay | Max delay between restarts in the case where we retry to restart the ethereum plugin | time.Duration | 1m | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumethconnectbackgroundstart", "relUrl": "/reference/config.html#pluginsblockchainethereumethconnectbackgroundstart" - },"205": { + },"209": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.ethconnect.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to use when connecting to Ethconnect | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumethconnectproxy", "relUrl": "/reference/config.html#pluginsblockchainethereumethconnectproxy" - },"206": { + },"210": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.ethconnect.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumethconnectretry", "relUrl": "/reference/config.html#pluginsblockchainethereumethconnectretry" - },"207": { + },"211": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.ethconnect.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumethconnecttls", "relUrl": "/reference/config.html#pluginsblockchainethereumethconnecttls" - },"208": { + },"212": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.ethconnect.ws", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The amount of time to wait while establishing a connection (or auto-reconnection) | time.Duration | 45s | . | heartbeatInterval | The amount of time to wait between heartbeat signals on the WebSocket connection | time.Duration | 30s | . | initialConnectAttempts | The number of attempts FireFly will make to connect to the WebSocket when starting up, before failing | int | 5 | . | path | The WebSocket sever URL to which FireFly should connect | WebSocket URL string | <nil> | . | readBufferSize | The size in bytes of the read buffer for the WebSocket connection | BytesSize | 16Kb | . | url | URL to use for WebSocket - overrides url one level up (in the HTTP config) | string | <nil> | . | writeBufferSize | The size in bytes of the write buffer for the WebSocket connection | BytesSize | 16Kb | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumethconnectws", "relUrl": "/reference/config.html#pluginsblockchainethereumethconnectws" - },"209": { + },"213": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.fftm", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | headers | Adds custom headers to HTTP requests | map[string]string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . | url | The URL of the FireFly Transaction Manager runtime, if enabled | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumfftm", "relUrl": "/reference/config.html#pluginsblockchainethereumfftm" - },"210": { + },"214": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.fftm.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumfftmauth", "relUrl": "/reference/config.html#pluginsblockchainethereumfftmauth" - },"211": { + },"215": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.fftm.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to use when connecting to the Transaction Manager | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumfftmproxy", "relUrl": "/reference/config.html#pluginsblockchainethereumfftmproxy" - },"212": { + },"216": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.fftm.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumfftmretry", "relUrl": "/reference/config.html#pluginsblockchainethereumfftmretry" - },"213": { + },"217": { "doc": "Configuration Reference", "title": "plugins.blockchain[].ethereum.fftm.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainethereumfftmtls", "relUrl": "/reference/config.html#pluginsblockchainethereumfftmtls" - },"214": { + },"218": { "doc": "Configuration Reference", "title": "plugins.blockchain[].fabric.fabconnect", "content": "| Key | Description | Type | Default Value | . | batchSize | The number of events Fabconnect should batch together for delivery to FireFly core. Only applies when automatically creating a new event stream | int | 50 | . | batchTimeout | The maximum amount of time to wait for a batch to complete | time.Duration | 500 | . | chaincode | The name of the Fabric chaincode that FireFly will use for BatchPin transactions (deprecated - use fireflyContract[].chaincode) | string | <nil> | . | channel | The Fabric channel that FireFly will use for BatchPin transactions | string | <nil> | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | headers | Adds custom headers to HTTP requests | map[string]string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | prefixLong | The prefix that will be used for Fabconnect specific HTTP headers when FireFly makes requests to Fabconnect | string | firefly | . | prefixShort | The prefix that will be used for Fabconnect specific query parameters when FireFly makes requests to Fabconnect | string | fly | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | signer | The Fabric signing key to use when submitting transactions to Fabconnect | string | <nil> | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . | topic | The websocket listen topic that the node should register on, which is important if there are multiple nodes using a single Fabconnect | string | <nil> | . | url | The URL of the Fabconnect instance | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainfabricfabconnect", "relUrl": "/reference/config.html#pluginsblockchainfabricfabconnect" - },"215": { + },"219": { "doc": "Configuration Reference", "title": "plugins.blockchain[].fabric.fabconnect.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainfabricfabconnectauth", "relUrl": "/reference/config.html#pluginsblockchainfabricfabconnectauth" - },"216": { + },"220": { "doc": "Configuration Reference", "title": "plugins.blockchain[].fabric.fabconnect.backgroundStart", "content": "| Key | Description | Type | Default Value | . | enabled | Start the fabric plugin in the background and enter retry loop if failed to start | boolean | <nil> | . | factor | Set the factor by which the delay increases when retrying | float32 | 2 | . | initialDelay | Delay between restarts in the case where we retry to restart the fabric plugin | time.Duration | 5s | . | maxDelay | Max delay between restarts in the case where we retry to restart the fabric plugin | time.Duration | 1m | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainfabricfabconnectbackgroundstart", "relUrl": "/reference/config.html#pluginsblockchainfabricfabconnectbackgroundstart" - },"217": { + },"221": { "doc": "Configuration Reference", "title": "plugins.blockchain[].fabric.fabconnect.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to use when connecting to Fabconnect | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainfabricfabconnectproxy", "relUrl": "/reference/config.html#pluginsblockchainfabricfabconnectproxy" - },"218": { + },"222": { "doc": "Configuration Reference", "title": "plugins.blockchain[].fabric.fabconnect.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainfabricfabconnectretry", "relUrl": "/reference/config.html#pluginsblockchainfabricfabconnectretry" - },"219": { + },"223": { "doc": "Configuration Reference", "title": "plugins.blockchain[].fabric.fabconnect.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainfabricfabconnecttls", "relUrl": "/reference/config.html#pluginsblockchainfabricfabconnecttls" - },"220": { + },"224": { "doc": "Configuration Reference", "title": "plugins.blockchain[].fabric.fabconnect.ws", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The amount of time to wait while establishing a connection (or auto-reconnection) | time.Duration | 45s | . | heartbeatInterval | The amount of time to wait between heartbeat signals on the WebSocket connection | time.Duration | 30s | . | initialConnectAttempts | The number of attempts FireFly will make to connect to the WebSocket when starting up, before failing | int | 5 | . | path | The WebSocket sever URL to which FireFly should connect | WebSocket URL string | <nil> | . | readBufferSize | The size in bytes of the read buffer for the WebSocket connection | BytesSize | 16Kb | . | url | URL to use for WebSocket - overrides url one level up (in the HTTP config) | string | <nil> | . | writeBufferSize | The size in bytes of the write buffer for the WebSocket connection | BytesSize | 16Kb | . ", "url": "/firefly/head/reference/config.html#pluginsblockchainfabricfabconnectws", "relUrl": "/reference/config.html#pluginsblockchainfabricfabconnectws" - },"221": { + },"225": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.addressResolver", "content": "| Key | Description | Type | Default Value | . | alwaysResolve | Causes the address resolver to be invoked on every API call that submits a signing key. Also disables any result caching | boolean | <nil> | . | bodyTemplate | The body go template string to use when making HTTP requests | Go Template string | <nil> | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | headers | Adds custom headers to HTTP requests | map[string]string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | method | The HTTP method to use when making requests to the Address Resolver | string | GET | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | responseField | The name of a JSON field that is provided in the response, that contains the tezos address (default address) | string | address | . | retainOriginal | When true the original pre-resolved string is retained after the lookup, and passed down to Tezosconnect as the from address | boolean | <nil> | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . | url | The URL of the Address Resolver | string | <nil> | . | urlTemplate | The URL Go template string to use when calling the Address Resolver. The template input contains ‘.Key’ and ‘.Intent’ string variables. | Go Template string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezosaddressresolver", "relUrl": "/reference/config.html#pluginsblockchaintezosaddressresolver" - },"222": { + },"226": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.addressResolver.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezosaddressresolverauth", "relUrl": "/reference/config.html#pluginsblockchaintezosaddressresolverauth" - },"223": { + },"227": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.addressResolver.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to connect through | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezosaddressresolverproxy", "relUrl": "/reference/config.html#pluginsblockchaintezosaddressresolverproxy" - },"224": { + },"228": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.addressResolver.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezosaddressresolverretry", "relUrl": "/reference/config.html#pluginsblockchaintezosaddressresolverretry" - },"225": { + },"229": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.addressResolver.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezosaddressresolvertls", "relUrl": "/reference/config.html#pluginsblockchaintezosaddressresolvertls" - },"226": { + },"230": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.tezosconnect", "content": "| Key | Description | Type | Default Value | . | batchSize | The number of events Tezosconnect should batch together for delivery to FireFly core. Only applies when automatically creating a new event stream | int | 50 | . | batchTimeout | How long Tezosconnect should wait for new events to arrive and fill a batch, before sending the batch to FireFly core. Only applies when automatically creating a new event stream | time.Duration | 500 | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | headers | Adds custom headers to HTTP requests | map[string]string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | prefixLong | The prefix that will be used for Tezosconnect specific HTTP headers when FireFly makes requests to Tezosconnect | string | firefly | . | prefixShort | The prefix that will be used for Tezosconnect specific query parameters when FireFly makes requests to Tezosconnect | string | fly | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . | topic | The websocket listen topic that the node should register on, which is important if there are multiple nodes using a single tezosconnect | string | <nil> | . | url | The URL of the Tezosconnect instance | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezostezosconnect", "relUrl": "/reference/config.html#pluginsblockchaintezostezosconnect" - },"227": { + },"231": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.tezosconnect.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezostezosconnectauth", "relUrl": "/reference/config.html#pluginsblockchaintezostezosconnectauth" - },"228": { + },"232": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.tezosconnect.backgroundStart", "content": "| Key | Description | Type | Default Value | . | enabled | Start the Tezosconnect plugin in the background and enter retry loop if failed to start | boolean | <nil> | . | factor | Set the factor by which the delay increases when retrying | float32 | 2 | . | initialDelay | Delay between restarts in the case where we retry to restart the tezos plugin | time.Duration | 5s | . | maxDelay | Max delay between restarts in the case where we retry to restart the tezos plugin | time.Duration | 1m | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezostezosconnectbackgroundstart", "relUrl": "/reference/config.html#pluginsblockchaintezostezosconnectbackgroundstart" - },"229": { + },"233": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.tezosconnect.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to use when connecting to Tezosconnect | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezostezosconnectproxy", "relUrl": "/reference/config.html#pluginsblockchaintezostezosconnectproxy" - },"230": { + },"234": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.tezosconnect.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezostezosconnectretry", "relUrl": "/reference/config.html#pluginsblockchaintezostezosconnectretry" - },"231": { + },"235": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.tezosconnect.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezostezosconnecttls", "relUrl": "/reference/config.html#pluginsblockchaintezostezosconnecttls" - },"232": { + },"236": { "doc": "Configuration Reference", "title": "plugins.blockchain[].tezos.tezosconnect.ws", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The amount of time to wait while establishing a connection (or auto-reconnection) | time.Duration | 45s | . | heartbeatInterval | The amount of time to wait between heartbeat signals on the WebSocket connection | time.Duration | 30s | . | initialConnectAttempts | The number of attempts FireFly will make to connect to the WebSocket when starting up, before failing | int | 5 | . | path | The WebSocket sever URL to which FireFly should connect | WebSocket URL string | <nil> | . | readBufferSize | The size in bytes of the read buffer for the WebSocket connection | BytesSize | 16Kb | . | url | URL to use for WebSocket - overrides url one level up (in the HTTP config) | string | <nil> | . | writeBufferSize | The size in bytes of the write buffer for the WebSocket connection | BytesSize | 16Kb | . ", "url": "/firefly/head/reference/config.html#pluginsblockchaintezostezosconnectws", "relUrl": "/reference/config.html#pluginsblockchaintezostezosconnectws" - },"233": { + },"237": { "doc": "Configuration Reference", "title": "plugins.database[]", "content": "| Key | Description | Type | Default Value | . | name | The name of the Database plugin | string | <nil> | . | type | The type of the configured Database plugin | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsdatabase", "relUrl": "/reference/config.html#pluginsdatabase" - },"234": { + },"238": { "doc": "Configuration Reference", "title": "plugins.database[].postgres", "content": "| Key | Description | Type | Default Value | . | maxConnIdleTime | The maximum amount of time a database connection can be idle | time.Duration | 1m | . | maxConnLifetime | The maximum amount of time to keep a database connection open | time.Duration | <nil> | . | maxConns | Maximum connections to the database | int | 50 | . | maxIdleConns | The maximum number of idle connections to the database | int | <nil> | . | url | The PostgreSQL connection string for the database | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsdatabasepostgres", "relUrl": "/reference/config.html#pluginsdatabasepostgres" - },"235": { + },"239": { "doc": "Configuration Reference", "title": "plugins.database[].postgres.migrations", "content": "| Key | Description | Type | Default Value | . | auto | Enables automatic database migrations | boolean | false | . | directory | The directory containing the numerically ordered migration DDL files to apply to the database | string | ./db/migrations/postgres | . ", "url": "/firefly/head/reference/config.html#pluginsdatabasepostgresmigrations", "relUrl": "/reference/config.html#pluginsdatabasepostgresmigrations" - },"236": { + },"240": { "doc": "Configuration Reference", "title": "plugins.database[].sqlite3", "content": "| Key | Description | Type | Default Value | . | maxConnIdleTime | The maximum amount of time a database connection can be idle | time.Duration | 1m | . | maxConnLifetime | The maximum amount of time to keep a database connection open | time.Duration | <nil> | . | maxConns | Maximum connections to the database | int | 1 | . | maxIdleConns | The maximum number of idle connections to the database | int | <nil> | . | url | The SQLite connection string for the database | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsdatabasesqlite3", "relUrl": "/reference/config.html#pluginsdatabasesqlite3" - },"237": { + },"241": { "doc": "Configuration Reference", "title": "plugins.database[].sqlite3.migrations", "content": "| Key | Description | Type | Default Value | . | auto | Enables automatic database migrations | boolean | false | . | directory | The directory containing the numerically ordered migration DDL files to apply to the database | string | ./db/migrations/sqlite | . ", "url": "/firefly/head/reference/config.html#pluginsdatabasesqlite3migrations", "relUrl": "/reference/config.html#pluginsdatabasesqlite3migrations" - },"238": { + },"242": { "doc": "Configuration Reference", "title": "plugins.dataexchange[]", "content": "| Key | Description | Type | Default Value | . | name | The name of the configured Data Exchange plugin | string | <nil> | . | type | The Data Exchange plugin to use | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsdataexchange", "relUrl": "/reference/config.html#pluginsdataexchange" - },"239": { + },"243": { "doc": "Configuration Reference", "title": "plugins.dataexchange[].ffdx", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | headers | Adds custom headers to HTTP requests | map[string]string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | initEnabled | Instructs FireFly to always post all current nodes to the /init API before connecting or reconnecting to the connector | boolean | false | . | manifestEnabled | Determines whether to require+validate a manifest from other DX instances in the network. Must be supported by the connector | string | false | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . | url | The URL of the Data Exchange instance | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsdataexchangeffdx", "relUrl": "/reference/config.html#pluginsdataexchangeffdx" - },"240": { + },"244": { "doc": "Configuration Reference", "title": "plugins.dataexchange[].ffdx.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsdataexchangeffdxauth", "relUrl": "/reference/config.html#pluginsdataexchangeffdxauth" - },"241": { + },"245": { "doc": "Configuration Reference", "title": "plugins.dataexchange[].ffdx.backgroundStart", "content": "| Key | Description | Type | Default Value | . | enabled | Start the data exchange plugin in the background and enter retry loop if failed to start | boolean | false | . | factor | Set the factor by which the delay increases when retrying | float32 | 2 | . | initialDelay | Delay between restarts in the case where we retry to restart the data exchange plugin | time.Duration | 5s | . | maxDelay | Max delay between restarts in the case where we retry to restart the data exchange plugin | time.Duration | 1m | . ", "url": "/firefly/head/reference/config.html#pluginsdataexchangeffdxbackgroundstart", "relUrl": "/reference/config.html#pluginsdataexchangeffdxbackgroundstart" - },"242": { + },"246": { "doc": "Configuration Reference", "title": "plugins.dataexchange[].ffdx.eventRetry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor, for event processing | float32 | 2 | . | initialDelay | The initial retry delay, for event processing | time.Duration | 50ms | . | maxDelay | The maximum retry delay, for event processing | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginsdataexchangeffdxeventretry", "relUrl": "/reference/config.html#pluginsdataexchangeffdxeventretry" - },"243": { + },"247": { "doc": "Configuration Reference", "title": "plugins.dataexchange[].ffdx.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to use when connecting to the Data Exchange | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsdataexchangeffdxproxy", "relUrl": "/reference/config.html#pluginsdataexchangeffdxproxy" - },"244": { + },"248": { "doc": "Configuration Reference", "title": "plugins.dataexchange[].ffdx.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginsdataexchangeffdxretry", "relUrl": "/reference/config.html#pluginsdataexchangeffdxretry" - },"245": { + },"249": { "doc": "Configuration Reference", "title": "plugins.dataexchange[].ffdx.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsdataexchangeffdxtls", "relUrl": "/reference/config.html#pluginsdataexchangeffdxtls" - },"246": { + },"250": { "doc": "Configuration Reference", "title": "plugins.dataexchange[].ffdx.ws", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The amount of time to wait while establishing a connection (or auto-reconnection) | time.Duration | 45s | . | heartbeatInterval | The amount of time to wait between heartbeat signals on the WebSocket connection | time.Duration | 30s | . | initialConnectAttempts | The number of attempts FireFly will make to connect to the WebSocket when starting up, before failing | int | 5 | . | path | The WebSocket sever URL to which FireFly should connect | WebSocket URL string | <nil> | . | readBufferSize | The size in bytes of the read buffer for the WebSocket connection | BytesSize | 16Kb | . | url | URL to use for WebSocket - overrides url one level up (in the HTTP config) | string | <nil> | . | writeBufferSize | The size in bytes of the write buffer for the WebSocket connection | BytesSize | 16Kb | . ", "url": "/firefly/head/reference/config.html#pluginsdataexchangeffdxws", "relUrl": "/reference/config.html#pluginsdataexchangeffdxws" - },"247": { + },"251": { "doc": "Configuration Reference", "title": "plugins.identity[]", "content": "| Key | Description | Type | Default Value | . | name | The name of a configured Identity plugin | string | <nil> | . | type | The type of a configured Identity plugin | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginsidentity", "relUrl": "/reference/config.html#pluginsidentity" - },"248": { + },"252": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[]", "content": "| Key | Description | Type | Default Value | . | name | The name of the Shared Storage plugin to use | string | <nil> | . | type | The Shared Storage plugin to use | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorage", "relUrl": "/reference/config.html#pluginssharedstorage" - },"249": { + },"253": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[].ipfs.api", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | headers | Adds custom headers to HTTP requests | map[string]string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . | url | The URL for the IPFS API | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorageipfsapi", "relUrl": "/reference/config.html#pluginssharedstorageipfsapi" - },"250": { + },"254": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[].ipfs.api.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorageipfsapiauth", "relUrl": "/reference/config.html#pluginssharedstorageipfsapiauth" - },"251": { + },"255": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[].ipfs.api.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to use when connecting to the IPFS API | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorageipfsapiproxy", "relUrl": "/reference/config.html#pluginssharedstorageipfsapiproxy" - },"252": { + },"256": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[].ipfs.api.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorageipfsapiretry", "relUrl": "/reference/config.html#pluginssharedstorageipfsapiretry" - },"253": { + },"257": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[].ipfs.api.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorageipfsapitls", "relUrl": "/reference/config.html#pluginssharedstorageipfsapitls" - },"254": { + },"258": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[].ipfs.gateway", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | headers | Adds custom headers to HTTP requests | map[string]string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . | url | The URL for the IPFS Gateway | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorageipfsgateway", "relUrl": "/reference/config.html#pluginssharedstorageipfsgateway" - },"255": { + },"259": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[].ipfs.gateway.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorageipfsgatewayauth", "relUrl": "/reference/config.html#pluginssharedstorageipfsgatewayauth" - },"256": { + },"260": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[].ipfs.gateway.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to use when connecting to the IPFS Gateway | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorageipfsgatewayproxy", "relUrl": "/reference/config.html#pluginssharedstorageipfsgatewayproxy" - },"257": { + },"261": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[].ipfs.gateway.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorageipfsgatewayretry", "relUrl": "/reference/config.html#pluginssharedstorageipfsgatewayretry" - },"258": { + },"262": { "doc": "Configuration Reference", "title": "plugins.sharedstorage[].ipfs.gateway.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginssharedstorageipfsgatewaytls", "relUrl": "/reference/config.html#pluginssharedstorageipfsgatewaytls" - },"259": { + },"263": { "doc": "Configuration Reference", "title": "plugins.tokens[]", "content": "| Key | Description | Type | Default Value | . | broadcastName | The name to be used in broadcast messages related to this token plugin, if it differs from the local plugin name | string | <nil> | . | name | A name to identify this token plugin | string | <nil> | . | type | The type of the token plugin to use | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginstokens", "relUrl": "/reference/config.html#pluginstokens" - },"260": { + },"264": { "doc": "Configuration Reference", "title": "plugins.tokens[].fftokens", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted | time.Duration | 30s | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | time.Duration | 1s | . | headers | Adds custom headers to HTTP requests | map[string]string | <nil> | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | time.Duration | 475ms | . | maxConnsPerHost | The max number of connections, per unique hostname. Zero means no limit | int | 0 | . | maxIdleConns | The max number of idle connections to hold pooled | int | 100 | . | passthroughHeadersEnabled | Enable passing through the set of allowed HTTP request headers | boolean | false | . | requestTimeout | The maximum amount of time that a request is allowed to remain open | time.Duration | 30s | . | tlsHandshakeTimeout | The maximum amount of time to wait for a successful TLS handshake | time.Duration | 10s | . | url | The URL of the token connector | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginstokensfftokens", "relUrl": "/reference/config.html#pluginstokensfftokens" - },"261": { + },"265": { "doc": "Configuration Reference", "title": "plugins.tokens[].fftokens.auth", "content": "| Key | Description | Type | Default Value | . | password | Password | string | <nil> | . | username | Username | string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginstokensfftokensauth", "relUrl": "/reference/config.html#pluginstokensfftokensauth" - },"262": { + },"266": { "doc": "Configuration Reference", "title": "plugins.tokens[].fftokens.backgroundStart", "content": "| Key | Description | Type | Default Value | . | enabled | Start the tokens plugin in the background and enter retry loop if failed to start | boolean | false | . | factor | Set the factor by which the delay increases when retrying | float32 | 2 | . | initialDelay | Delay between restarts in the case where we retry to restart the token plugin | time.Duration | 5s | . | maxDelay | Max delay between restarts in the case where we retry to restart the token plugin | time.Duration | 1m | . ", "url": "/firefly/head/reference/config.html#pluginstokensfftokensbackgroundstart", "relUrl": "/reference/config.html#pluginstokensfftokensbackgroundstart" - },"263": { + },"267": { "doc": "Configuration Reference", "title": "plugins.tokens[].fftokens.eventRetry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor, for event processing | float32 | 2 | . | initialDelay | The initial retry delay, for event processing | time.Duration | 50ms | . | maxDelay | The maximum retry delay, for event processing | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginstokensfftokenseventretry", "relUrl": "/reference/config.html#pluginstokensfftokenseventretry" - },"264": { + },"268": { "doc": "Configuration Reference", "title": "plugins.tokens[].fftokens.proxy", "content": "| Key | Description | Type | Default Value | . | url | Optional HTTP proxy server to use when connecting to the token connector | URL string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginstokensfftokensproxy", "relUrl": "/reference/config.html#pluginstokensfftokensproxy" - },"265": { + },"269": { "doc": "Configuration Reference", "title": "plugins.tokens[].fftokens.retry", "content": "| Key | Description | Type | Default Value | . | count | The maximum number of times to retry | int | 5 | . | enabled | Enables retries | boolean | false | . | errorStatusCodeRegex | The regex that the error response status code must match to trigger retry | string | <nil> | . | initWaitTime | The initial retry delay | time.Duration | 250ms | . | maxWaitTime | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#pluginstokensfftokensretry", "relUrl": "/reference/config.html#pluginstokensfftokensretry" - },"266": { + },"270": { "doc": "Configuration Reference", "title": "plugins.tokens[].fftokens.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#pluginstokensfftokenstls", "relUrl": "/reference/config.html#pluginstokensfftokenstls" - },"267": { + },"271": { "doc": "Configuration Reference", "title": "plugins.tokens[].fftokens.ws", "content": "| Key | Description | Type | Default Value | . | connectionTimeout | The amount of time to wait while establishing a connection (or auto-reconnection) | time.Duration | 45s | . | heartbeatInterval | The amount of time to wait between heartbeat signals on the WebSocket connection | time.Duration | 30s | . | initialConnectAttempts | The number of attempts FireFly will make to connect to the WebSocket when starting up, before failing | int | 5 | . | path | The WebSocket sever URL to which FireFly should connect | WebSocket URL string | <nil> | . | readBufferSize | The size in bytes of the read buffer for the WebSocket connection | BytesSize | 16Kb | . | url | URL to use for WebSocket - overrides url one level up (in the HTTP config) | string | <nil> | . | writeBufferSize | The size in bytes of the write buffer for the WebSocket connection | BytesSize | 16Kb | . ", "url": "/firefly/head/reference/config.html#pluginstokensfftokensws", "relUrl": "/reference/config.html#pluginstokensfftokensws" - },"268": { + },"272": { "doc": "Configuration Reference", "title": "privatemessaging.batch", "content": "| Key | Description | Type | Default Value | . | agentTimeout | How long to keep around a batching agent for a sending identity before disposal | time.Duration | 2m | . | payloadLimit | The maximum payload size of a private message Data Exchange payload | BytesSize | 800Kb | . | size | The maximum number of messages in a batch for private messages | int | 200 | . | timeout | The timeout to wait for a batch to fill, before sending | time.Duration | 1s | . ", "url": "/firefly/head/reference/config.html#privatemessagingbatch", "relUrl": "/reference/config.html#privatemessagingbatch" - },"269": { + },"273": { "doc": "Configuration Reference", "title": "privatemessaging.retry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor | float32 | 2 | . | initDelay | The initial retry delay | time.Duration | 100ms | . | maxDelay | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#privatemessagingretry", "relUrl": "/reference/config.html#privatemessagingretry" - },"270": { + },"274": { "doc": "Configuration Reference", "title": "spi", "content": "| Key | Description | Type | Default Value | . | address | The IP address on which the admin HTTP API should listen | IP Address string | 127.0.0.1 | . | enabled | Enables the admin HTTP API | boolean | false | . | port | The port on which the admin HTTP API should listen | int | 5001 | . | publicURL | The fully qualified public URL for the admin API. This is used for building URLs in HTTP responses and in OpenAPI Spec generation | URL string | <nil> | . | readTimeout | The maximum time to wait when reading from an HTTP connection | time.Duration | 15s | . | shutdownTimeout | The maximum amount of time to wait for any open HTTP requests to finish before shutting down the HTTP server | time.Duration | 10s | . | writeTimeout | The maximum time to wait when writing to an HTTP connection | time.Duration | 15s | . ", "url": "/firefly/head/reference/config.html#spi", "relUrl": "/reference/config.html#spi" - },"271": { + },"275": { "doc": "Configuration Reference", "title": "spi.auth", "content": "| Key | Description | Type | Default Value | . | type | The auth plugin to use for server side authentication of requests | string | <nil> | . ", "url": "/firefly/head/reference/config.html#spiauth", "relUrl": "/reference/config.html#spiauth" - },"272": { + },"276": { "doc": "Configuration Reference", "title": "spi.auth.basic", "content": "| Key | Description | Type | Default Value | . | passwordfile | The path to a .htpasswd file to use for authenticating requests. Passwords should be hashed with bcrypt. | string | <nil> | . ", "url": "/firefly/head/reference/config.html#spiauthbasic", "relUrl": "/reference/config.html#spiauthbasic" - },"273": { + },"277": { "doc": "Configuration Reference", "title": "spi.tls", "content": "| Key | Description | Type | Default Value | . | caFile | The path to the CA file for TLS on this API | string | <nil> | . | certFile | The path to the certificate file for TLS on this API | string | <nil> | . | clientAuth | Enables or disables client auth for TLS on this API | string | <nil> | . | enabled | Enables or disables TLS on this API | boolean | false | . | insecureSkipHostVerify | When to true in unit test development environments to disable TLS verification. Use with extreme caution | boolean | <nil> | . | keyFile | The path to the private key file for TLS on this API | string | <nil> | . | requiredDNAttributes | A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) | map[string]string | <nil> | . ", "url": "/firefly/head/reference/config.html#spitls", "relUrl": "/reference/config.html#spitls" - },"274": { + },"278": { "doc": "Configuration Reference", "title": "spi.ws", "content": "| Key | Description | Type | Default Value | . | blockedWarnInterval | How often to log warnings in core, when an admin change event listener falls behind the stream they requested and misses events | time.Duration | 1m | . | eventQueueLength | Server-side queue length for events waiting for delivery over an admin change event listener websocket | int | 250 | . | readBufferSize | The size in bytes of the read buffer for the WebSocket connection | BytesSize | 16Kb | . | writeBufferSize | The size in bytes of the write buffer for the WebSocket connection | BytesSize | 16Kb | . ", "url": "/firefly/head/reference/config.html#spiws", "relUrl": "/reference/config.html#spiws" - },"275": { + },"279": { "doc": "Configuration Reference", "title": "subscription", "content": "| Key | Description | Type | Default Value | . | max | The maximum number of pre-defined subscriptions that can exist (note for high fan-out consider connecting a dedicated pub/sub broker to the dispatcher) | int | 500 | . ", "url": "/firefly/head/reference/config.html#subscription", "relUrl": "/reference/config.html#subscription" - },"276": { + },"280": { "doc": "Configuration Reference", "title": "subscription.defaults", "content": "| Key | Description | Type | Default Value | . | batchSize | Default read ahead to enable for subscriptions that do not explicitly configure readahead | int | 50 | . | batchTimeout | Default batch timeout | int | 50ms | . ", "url": "/firefly/head/reference/config.html#subscriptiondefaults", "relUrl": "/reference/config.html#subscriptiondefaults" - },"277": { + },"281": { "doc": "Configuration Reference", "title": "subscription.events", "content": "| Key | Description | Type | Default Value | . | maxScanLength | The maximum number of events a search for historical events matching a subscription will index from the database | int | 1000 | . ", "url": "/firefly/head/reference/config.html#subscriptionevents", "relUrl": "/reference/config.html#subscriptionevents" - },"278": { + },"282": { "doc": "Configuration Reference", "title": "subscription.retry", "content": "| Key | Description | Type | Default Value | . | factor | The retry backoff factor | float32 | 2 | . | initDelay | The initial retry delay | time.Duration | 250ms | . | maxDelay | The maximum retry delay | time.Duration | 30s | . ", "url": "/firefly/head/reference/config.html#subscriptionretry", "relUrl": "/reference/config.html#subscriptionretry" - },"279": { + },"283": { "doc": "Configuration Reference", "title": "transaction.writer", "content": "| Key | Description | Type | Default Value | . | batchMaxTransactions | The maximum number of transaction inserts to include in a batch | int | 100 | . | batchTimeout | How long to wait for more transactions to arrive before flushing the batch | time.Duration | 10ms | . | count | The number of message writer workers | int | 5 | . ", "url": "/firefly/head/reference/config.html#transactionwriter", "relUrl": "/reference/config.html#transactionwriter" - },"280": { + },"284": { "doc": "Configuration Reference", "title": "ui", "content": "| Key | Description | Type | Default Value | . | enabled | Enables the web user interface | boolean | true | . | path | The file system path which contains the static HTML, CSS, and JavaScript files for the user interface | string | <nil> | . ", "url": "/firefly/head/reference/config.html#ui", "relUrl": "/reference/config.html#ui" - },"281": { + },"285": { "doc": "pages.connector_framework", "title": "Connector Framework", "content": ". ", "url": "/firefly/head/overview/key_components/connectors.html#connector-framework", "relUrl": "/overview/key_components/connectors.html#connector-framework" - },"282": { + },"286": { "doc": "pages.connector_framework", "title": "Pluggable Microservices Architecture", "content": "The ability for every component to be pluggable is at the core of Hyperledger FireFly. A microservices approach is used, combining code plug-points in the core runtime, with API extensibility to remote runtimes implemented in a variety of programming languages. ", "url": "/firefly/head/overview/key_components/connectors.html#pluggable-microservices-architecture", "relUrl": "/overview/key_components/connectors.html#pluggable-microservices-architecture" - },"283": { + },"287": { "doc": "pages.connector_framework", "title": "Extension points", "content": ". | Blockchain - a rich framework for extensibility to any blockchain / digital ledger technology (DLT) | Tokens - mapping token standards and governance models to a common data model | Shared storage - supporting permissioned and public distributed storage technologies | Data exchange - private local/storage and encrypted transfer of data | Identity - flexibility for resolving identities via Decentralized IDentifier (DID) | Persistence - the local private database | . Learn more about the plugin architecture here . ", "url": "/firefly/head/overview/key_components/connectors.html#extension-points", "relUrl": "/overview/key_components/connectors.html#extension-points" - },"284": { + },"288": { "doc": "pages.connector_framework", "title": "Blockchain Connector Framework", "content": "The most advanced extension point is for the blockchain layer, where multiple layers of extensibility are provided to support the programming models, and behaviors of different blockchain technologies. This framework has been proven with technologies as different as EVM based Layer 2 Ethereum Scaling solutions like Polygon, all the way to permissioned Hyperledger Fabric networks. Check out instructions to connect to a list of remote blockchain networks here. Find out more about the Blockchain Connector Framework here. ", "url": "/firefly/head/overview/key_components/connectors.html#blockchain-connector-framework", "relUrl": "/overview/key_components/connectors.html#blockchain-connector-framework" - },"285": { + },"289": { "doc": "pages.connector_framework", "title": "pages.connector_framework", "content": " ", "url": "/firefly/head/overview/key_components/connectors.html", "relUrl": "/overview/key_components/connectors.html" - },"286": { + },"290": { "doc": "ContractAPI", "title": "ContractAPI", "content": " ", "url": "/firefly/head/reference/types/contractapi.html", "relUrl": "/reference/types/contractapi.html" - },"287": { + },"291": { "doc": "ContractAPI", "title": "Table of contents", "content": ". | ContractAPI . | URL | FireFly Interface (FFI) and On-chain Location | OpenAPI V3 / Swagger Definitions | Swagger UI | Example | Field Descriptions | . | FFIReference | ContractURLs | . ", "url": "/firefly/head/reference/types/contractapi.html#table-of-contents", "relUrl": "/reference/types/contractapi.html#table-of-contents" - },"288": { + },"292": { "doc": "ContractAPI", "title": "ContractAPI", "content": "Contract APIs provide generated REST APIs for on-chain smart contracts. API endpoints are generated to invoke or perform query operations against each of the functions/methods implemented by the smart contract. API endpoints are also provided to add listeners to the events of that smart contract. Note that once you have established listeners for your blockchain events into FireFly, you need to also subscribe in your application to receive the FireFly events (of type blockchain_event_received) that are emitted for each detected blockchain event. For more information see the Events reference section. URL . The base path for your Contract API is: . | /api/v1/namespaces/{ns}/apis/{apiName} | . For the default namespace, this can be shortened to: . | /api/v1/apis/{apiName} | . FireFly Interface (FFI) and On-chain Location . Contract APIs are registered against: . | A FireFly Interface (FFI) definition, which defines in a blockchain agnostic format the list of functions/events supported by the smart contract. Also detailed type information about the inputs/outputs to those functions/events. | An optional location configured on the Contract API describes where the instance of the smart contract the API should interact with exists in the blockchain layer. For example the address of the Smart Contract for an Ethereum based blockchain, or the name and channel for a Hyperledger Fabric based blockchain. | . If the location is not specified on creation of the Contract API, then it must be specified on each API call made to the Contract API endpoints. OpenAPI V3 / Swagger Definitions . Each Contract API comes with an OpenAPI V3 / Swagger generated definition, which can be downloaded from: . | /api/v1/namespaces/{namespaces}/apis/{apiName}/api/swagger.json | . Swagger UI . A browser / exerciser UI for your API is also available on: . | /api/v1/namespaces/{namespaces}/apis/{apiName}/api | . Example . { \"id\": \"0f12317b-85a0-4a77-a722-857ea2b0a5fa\", \"namespace\": \"ns1\", \"interface\": { \"id\": \"c35d3449-4f24-4676-8e64-91c9e46f06c4\" }, \"location\": { \"address\": \"0x95a6c4895c7806499ba35f75069198f45e88fc69\" }, \"name\": \"my_contract_api\", \"message\": \"b09d9f77-7b16-4760-a8d7-0e3c319b2a16\", \"urls\": { \"openapi\": \"http://127.0.0.1:5000/api/v1/namespaces/default/apis/my_contract_api/api/swagger.json\", \"ui\": \"http://127.0.0.1:5000/api/v1/namespaces/default/apis/my_contract_api/api\" }, \"published\": false } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the contract API | UUID | . | namespace | The namespace of the contract API | string | . | interface | Reference to the FireFly Interface definition associated with the contract API | FFIReference | . | location | If this API is tied to an individual instance of a smart contract, this field can include a blockchain specific contract identifier. For example an Ethereum contract address, or a Fabric chaincode name and channel | JSONAny | . | name | The name that is used in the URL to access the API | string | . | networkName | The published name of the API within the multiparty network | string | . | message | The UUID of the broadcast message that was used to publish this API to the network | UUID | . | urls | The URLs to use to access the API | ContractURLs | . | published | Indicates if the API is published to other members of the multiparty network | bool | . ", "url": "/firefly/head/reference/types/contractapi.html", "relUrl": "/reference/types/contractapi.html" - },"289": { + },"293": { "doc": "ContractAPI", "title": "FFIReference", "content": "| Field Name | Description | Type | . | id | The UUID of the FireFly interface | UUID | . | name | The name of the FireFly interface | string | . | version | The version of the FireFly interface | string | . ", "url": "/firefly/head/reference/types/contractapi.html#ffireference", "relUrl": "/reference/types/contractapi.html#ffireference" - },"290": { + },"294": { "doc": "ContractAPI", "title": "ContractURLs", "content": "| Field Name | Description | Type | . | openapi | The URL to download the OpenAPI v3 (Swagger) description for the API generated in JSON or YAML format | string | . | ui | The URL to use in a web browser to access the SwaggerUI explorer/exerciser for the API | string | . ", "url": "/firefly/head/reference/types/contractapi.html#contracturls", "relUrl": "/reference/types/contractapi.html#contracturls" - },"291": { + },"295": { "doc": "ContractListener", "title": "ContractListener", "content": " ", "url": "/firefly/head/reference/types/contractlistener.html", "relUrl": "/reference/types/contractlistener.html" - },"292": { + },"296": { "doc": "ContractListener", "title": "Table of contents", "content": ". | ContractListener . | Example | Field Descriptions | . | FFIReference | FFISerializedEvent | FFIParam | ContractListenerOptions | . ", "url": "/firefly/head/reference/types/contractlistener.html#table-of-contents", "relUrl": "/reference/types/contractlistener.html#table-of-contents" - },"293": { + },"297": { "doc": "ContractListener", "title": "ContractListener", "content": "A contract listener configures FireFly to stream events from the blockchain, from a specific location on the blockchain, according to a given definition of the interface for that event. Check out the Custom Contracts Tutorial for a walk-through of how to set up listeners for the events from your smart contracts. Example . { \"id\": \"d61980a9-748c-4c72-baf5-8b485b514d59\", \"interface\": { \"id\": \"ff1da3c1-f9e7-40c2-8d93-abb8855e8a1d\" }, \"namespace\": \"ns1\", \"name\": \"contract1_events\", \"backendId\": \"sb-dd8795fc-a004-4554-669d-c0cf1ee2c279\", \"location\": { \"address\": \"0x596003a91a97757ef1916c8d6c0d42592630d2cf\" }, \"created\": \"2022-05-16T01:23:15Z\", \"event\": { \"name\": \"Changed\", \"description\": \"\", \"params\": [ { \"name\": \"x\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ] }, \"signature\": \"Changed(uint256)\", \"topic\": \"app1_topic\", \"options\": { \"firstEvent\": \"newest\" } } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the smart contract listener | UUID | . | interface | A reference to an existing FFI, containing pre-registered type information for the event | FFIReference | . | namespace | The namespace of the listener, which defines the namespace of all blockchain events detected by this listener | string | . | name | A descriptive name for the listener | string | . | backendId | An ID assigned by the blockchain connector to this listener | string | . | location | A blockchain specific contract identifier. For example an Ethereum contract address, or a Fabric chaincode name and channel | JSONAny | . | created | The creation time of the listener | FFTime | . | event | The definition of the event, either provided in-line when creating the listener, or extracted from the referenced FFI | FFISerializedEvent | . | signature | The stringified signature of the event, as computed by the blockchain plugin | string | . | topic | 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 | string | . | options | Options that control how the listener subscribes to events from the underlying blockchain | ContractListenerOptions | . ", "url": "/firefly/head/reference/types/contractlistener.html", "relUrl": "/reference/types/contractlistener.html" - },"294": { + },"298": { "doc": "ContractListener", "title": "FFIReference", "content": "| Field Name | Description | Type | . | id | The UUID of the FireFly interface | UUID | . | name | The name of the FireFly interface | string | . | version | The version of the FireFly interface | string | . ", "url": "/firefly/head/reference/types/contractlistener.html#ffireference", "relUrl": "/reference/types/contractlistener.html#ffireference" - },"295": { + },"299": { "doc": "ContractListener", "title": "FFISerializedEvent", "content": "| Field Name | Description | Type | . | name | The name of the event | string | . | description | A description of the smart contract event | string | . | params | An array of event parameter/argument definitions | FFIParam[] | . | details | Additional blockchain specific fields about this event from the original smart contract. Used by the blockchain plugin and for documentation generation. | JSONObject | . ", "url": "/firefly/head/reference/types/contractlistener.html#ffiserializedevent", "relUrl": "/reference/types/contractlistener.html#ffiserializedevent" - },"296": { + },"300": { "doc": "ContractListener", "title": "FFIParam", "content": "| Field Name | Description | Type | . | name | The name of the parameter. Note that parameters must be ordered correctly on the FFI, according to the order in the blockchain smart contract | string | . | schema | 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 | JSONAny | . ", "url": "/firefly/head/reference/types/contractlistener.html#ffiparam", "relUrl": "/reference/types/contractlistener.html#ffiparam" - },"297": { + },"301": { "doc": "ContractListener", "title": "ContractListenerOptions", "content": "| Field Name | Description | Type | . | firstEvent | 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’ | string | . ", "url": "/firefly/head/reference/types/contractlistener.html#contractlisteneroptions", "relUrl": "/reference/types/contractlistener.html#contractlisteneroptions" - },"298": { + },"302": { "doc": "Create a custom identity", "title": "Create a Custom Identity", "content": " ", "url": "/firefly/head/tutorials/create_custom_identity.html#create-a-custom-identity", "relUrl": "/tutorials/create_custom_identity.html#create-a-custom-identity" - },"299": { + },"303": { "doc": "Create a custom identity", "title": "Table of contents", "content": ". | Quick reference | Additional info | Previous steps: Start your environment | Step 1: Create a new account | Step 2: Query the parent org for its UUID . | Request | Response | . | Step 3: Register the new custom identity with FireFly . | Request | Response | . | Step 4: Query the New Custom Identity . | Request | Response | . | . ", "url": "/firefly/head/tutorials/create_custom_identity.html#table-of-contents", "relUrl": "/tutorials/create_custom_identity.html#table-of-contents" - },"300": { + },"304": { "doc": "Create a custom identity", "title": "Quick reference", "content": "Out of the box, a FireFly Supernode contains both an org and a node identity. Your use case might demand more granular notions of identity (ex. customers, clients, etc.). Instead of creating a Supernode for each identity, you can create multiple custom identities within a FireFly Supernode. ", "url": "/firefly/head/tutorials/create_custom_identity.html#quick-reference", "relUrl": "/tutorials/create_custom_identity.html#quick-reference" - },"301": { + },"305": { "doc": "Create a custom identity", "title": "Additional info", "content": ". | Reference: Identities | Swagger: POST /api/v1/identities | . ", "url": "/firefly/head/tutorials/create_custom_identity.html#additional-info", "relUrl": "/tutorials/create_custom_identity.html#additional-info" - },"302": { + },"306": { "doc": "Create a custom identity", "title": "Previous steps: Start your environment", "content": "If you haven’t started a FireFly stack already, please go to the Getting Started guide on how to Start your environment . ← ② Start your environment . ", "url": "/firefly/head/tutorials/create_custom_identity.html#previous-steps-start-your-environment", "relUrl": "/tutorials/create_custom_identity.html#previous-steps-start-your-environment" - },"303": { + },"307": { "doc": "Create a custom identity", "title": "Step 1: Create a new account", "content": "The FireFly CLI has a helpful command to create an account in a local development environment for you. NOTE: In a production environment, key management actions such as creation, encryption, unlocking, etc. may be very different, depending on what type of blockchain node and signer your specific deployment is using. To create a new account on your local stack, run: . ff accounts create <stack_name> . { \"address\": \"0xc00109e112e21165c7065da776c75cfbc9cdc5e7\", \"privateKey\": \"...\" } . The FireFly CLI has created a new private key and address for us to be able to use, and it has loaded the encrypted private key into the signing container. However, we haven’t told FireFly itself about the new key, or who it belongs to. That’s what we’ll do in the next steps. ", "url": "/firefly/head/tutorials/create_custom_identity.html#step-1-create-a-new-account", "relUrl": "/tutorials/create_custom_identity.html#step-1-create-a-new-account" - },"304": { + },"308": { "doc": "Create a custom identity", "title": "Step 2: Query the parent org for its UUID", "content": "If we want to create a new custom identity under the organizational identity that we’re using in a multiparty network, first we will need to look up the UUID for our org identity. We can look that up by making a GET request to the status endpoint on the default namespace. Request . GET http://localhost:5000/api/v1/status . Response . { \"namespace\": {...}, \"node\": {...}, \"org\": { \"name\": \"org_0\", \"registered\": true, \"did\": \"did:firefly:org/org_0\", \"id\": \"1c0abf75-0f3a-40e4-a8cd-5ff926f80aa8\", // We need this in Step 3 \"verifiers\": [ { \"type\": \"ethereum_address\", \"value\": \"0xd7320c76a2efc1909196dea876c4c7dabe49c0f4\" } ] }, \"plugins\": {...}, \"multiparty\": {...} } . ", "url": "/firefly/head/tutorials/create_custom_identity.html#step-2-query-the-parent-org-for-its-uuid", "relUrl": "/tutorials/create_custom_identity.html#step-2-query-the-parent-org-for-its-uuid" - },"305": { + },"309": { "doc": "Create a custom identity", "title": "Step 3: Register the new custom identity with FireFly", "content": "Now we can POST to the identities endpoint to create a new custom identity. We will include the UUID of the organizational identity from the previous step in the \"parent\" field in the request. Request . POST http://localhost:5000/api/v1/identities . { \"name\": \"myCustomIdentity\", \"key\": \"0xc00109e112e21165c7065da776c75cfbc9cdc5e7\", // Signing Key from Step 1 \"parent\": \"1c0abf75-0f3a-40e4-a8cd-5ff926f80aa8\" // Org UUID from Step 2 } . Response . { \"id\": \"5ea8f770-e004-48b5-af60-01994230ed05\", \"did\": \"did:firefly:myCustomIdentity\", \"type\": \"custom\", \"parent\": \"1c0abf75-0f3a-40e4-a8cd-5ff926f80aa8\", \"namespace\": \"\", \"name\": \"myCustomIdentity\", \"messages\": { \"claim\": \"817b7c79-a934-4936-bbb1-7dcc7c76c1f4\", \"verification\": \"ae55f998-49b1-4391-bed2-fa5e86dc85a2\", \"update\": null } } . ", "url": "/firefly/head/tutorials/create_custom_identity.html#step-3-register-the-new-custom-identity-with-firefly", "relUrl": "/tutorials/create_custom_identity.html#step-3-register-the-new-custom-identity-with-firefly" - },"306": { + },"310": { "doc": "Create a custom identity", "title": "Step 4: Query the New Custom Identity", "content": "Lastly, if we want to confirm that the new identity has been created, we can query the identities endpoint to see our new custom identity. Request . GET http://localhost:5000/api/v1/identities?fetchverifiers=true . NOTE: Using fetchverifiers=true will return the cryptographic verification mechanism for the FireFly identity. Response . [ { \"id\": \"5ea8f770-e004-48b5-af60-01994230ed05\", \"did\": \"did:firefly:myCustomIdentity\", \"type\": \"custom\", \"parent\": \"1c0abf75-0f3a-40e4-a8cd-5ff926f80aa8\", \"namespace\": \"default\", \"name\": \"myCustomIdentity\", \"messages\": { \"claim\": \"817b7c79-a934-4936-bbb1-7dcc7c76c1f4\", \"verification\": \"ae55f998-49b1-4391-bed2-fa5e86dc85a2\", \"update\": null }, \"created\": \"2022-09-19T18:10:47.365068013Z\", \"updated\": \"2022-09-19T18:10:47.365068013Z\", \"verifiers\": [ { \"type\": \"ethereum_address\", \"value\": \"0xfe1ea8c8a065a0cda424e2351707c7e8eb4d2b6f\" } ] }, { ... }, { ... } ] . ", "url": "/firefly/head/tutorials/create_custom_identity.html#step-4-query-the-new-custom-identity", "relUrl": "/tutorials/create_custom_identity.html#step-4-query-the-new-custom-identity" - },"307": { + },"311": { "doc": "Create a custom identity", "title": "Create a custom identity", "content": " ", "url": "/firefly/head/tutorials/create_custom_identity.html", "relUrl": "/tutorials/create_custom_identity.html" - },"308": { + },"312": { "doc": "Data", "title": "Data", "content": " ", "url": "/firefly/head/reference/types/data.html", "relUrl": "/reference/types/data.html" - },"309": { + },"313": { "doc": "Data", "title": "Table of contents", "content": ". | Data . | Value - JSON data stored in the core database | Datatype - validation of agreed data types | Blob - binary data stored via the Data Exchange | Example | Field Descriptions | . | DatatypeRef | BlobRef | . ", "url": "/firefly/head/reference/types/data.html#table-of-contents", "relUrl": "/reference/types/data.html#table-of-contents" - },"310": { + },"314": { "doc": "Data", "title": "Data", "content": "Data is a uniquely identified piece of data available for retrieval or transfer. Multiple data items can be attached to a message when sending data off-chain to another party in a multi-party system. Note that if you pass data in-line when sending a message, those data elements will be stored separately to the message and available to retrieve separately later. An UUID is allocated to each data resource. A hash is also calculated as follows: . | If there is only data, the hash is of the value serialized as JSON with no additional whitespace (order of the keys is retained from the original upload order). | If there is only a blob attachment, the hash is of the blob data. | There is is both a blob and a value, then the hash is a hash of the concatenation of a hash of the value and a hash of the blob. | . Value - JSON data stored in the core database . Each data resource can contain a value, which is any JSON type. String, number, boolean, array or object. This value is stored directly in the FireFly database. If the value you are storing is not JSON data, but is small enough you want it to be stored in the core database, then use a JSON string to store an encoded form of your data (such as XML, CSV etc.). Datatype - validation of agreed data types . A datatype can be associated with your data, causing FireFly to verify the value against a schema before accepting it (on upload, or receipt from another party in the network). These datatypes are pre-established via broadcast messages, and support versioning. Use this system to enforce a set of common data types for exchange of data across your business network, and reduce the overhead of data verification required in the application/integration tier. More information in the Datatype section . Blob - binary data stored via the Data Exchange . Data resources can also contain a blob attachment, which is stored via the Data Exchange plugin outside of the FireFly core database. This is intended for large data payloads, which might be structured or unstructured. PDF documents, multi-MB XML payloads, CSV data exports, JPEG images video files etc. A Data resource can contain both a value JSON payload, and a blob attachment, meaning that you bind a set of metadata to a binary payload. For example a set of extracted metadata from OCR processing of a PDF document. One special case is a filename for a document. This pattern is so common for file/document management scenarios, that special handling is provided for it. If a JSON object is stored in value, and it has a property called name, then this value forms part of the data hash (as does every field in the value) and is stored in a separately indexed blob.name field. The upload REST API provides an autometa form field, which can be set to ask FireFly core to automatically set the value to contain the filename, size, and MIME type from the file upload. Example . { \"id\": \"4f11e022-01f4-4c3f-909f-5226947d9ef0\", \"validator\": \"json\", \"namespace\": \"ns1\", \"hash\": \"5e2758423c99b799f53d3f04f587f5716c1ff19f1d1a050f40e02ea66860b491\", \"created\": \"2022-05-16T01:23:15Z\", \"datatype\": { \"name\": \"widget\", \"version\": \"v1.2.3\" }, \"value\": { \"name\": \"filename.pdf\", \"a\": \"example\", \"b\": { \"c\": 12345 } }, \"blob\": { \"hash\": \"cef238f7b02803a799f040cdabe285ad5cd6db4a15cb9e2a1000f2860884c7ad\", \"size\": 12345, \"name\": \"filename.pdf\" } } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the data resource | UUID | . | validator | The data validator type | FFEnum: | . | namespace | The namespace of the data resource | string | . | hash | The hash of the data resource. Derived from the value and the hash of any binary blob attachment | Bytes32 | . | created | The creation time of the data resource | FFTime | . | datatype | The optional datatype to use of validation of this data | DatatypeRef | . | value | 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 | JSONAny | . | public | 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.) | string | . | blob | An optional hash reference to a binary blob attachment | BlobRef | . ", "url": "/firefly/head/reference/types/data.html", "relUrl": "/reference/types/data.html" - },"311": { + },"315": { "doc": "Data", "title": "DatatypeRef", "content": "| Field Name | Description | Type | . | name | The name of the datatype | string | . | version | The version of the datatype. Semantic versioning is encouraged, such as v1.0.1 | string | . ", "url": "/firefly/head/reference/types/data.html#datatyperef", "relUrl": "/reference/types/data.html#datatyperef" - },"312": { + },"316": { "doc": "Data", "title": "BlobRef", "content": "| Field Name | Description | Type | . | hash | The hash of the binary blob data | Bytes32 | . | size | The size of the binary data | int64 | . | name | The name field from the metadata attached to the blob, commonly used as a path/filename, and indexed for search | string | . | path | If a name is specified, this field stores the ‘/’ prefixed and separated path extracted from the full name | string | . | public | 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.) | string | . ", "url": "/firefly/head/reference/types/data.html#blobref", "relUrl": "/reference/types/data.html#blobref" - },"313": { + },"317": { "doc": "pages.private_data_exchange", "title": "Private data exchange", "content": ". ", "url": "/firefly/head/overview/multiparty/data_exchange.html#private-data-exchange", "relUrl": "/overview/multiparty/data_exchange.html#private-data-exchange" - },"314": { + },"318": { "doc": "pages.private_data_exchange", "title": "Introduction", "content": "Private data exchange is the way most enterprise business-to-business communication happens today. One party privately sends data to another, over a pipe that has been agreed as sufficiently secure between the two parties. That might be a REST API, SOAP Web Service, FTP / EDI, Message Queue (MQ), or other B2B Gateway technology. The ability to perform these same private data exchanges within a multi-party system is critical. In fact it’s common for the majority of business data continue to transfer over such interfaces. So real-time application to application private messaging, and private transfer of large blobs/documents, are first class constructs in the FireFly API. ", "url": "/firefly/head/overview/multiparty/data_exchange.html#introduction", "relUrl": "/overview/multiparty/data_exchange.html#introduction" - },"315": { + },"319": { "doc": "pages.private_data_exchange", "title": "Qualities of service", "content": "FireFly recognizes that a multi-party system will need to establish a secure messaging backbone, with the right qualities of service for their requirements. So the implementation is pluggable, and the plugin interface embraces the following quality of service characteristics that differ between different implementations. | Transport Encryption . | Technologies like TLS encrypt data while it is in flight, so that it cannot be sniffed by a third party that has access to the underlying network. | . | Authentication . | There are many technologies including Mutual TLS, and Java Web Tokens (JWT), that can be used to ensure a private data exchange is happening with the correct party in the system. | Most modern approaches use public/private key encryption to establish the identity during the setup phase of a connection. This means a distribution mechanism is required for public keys, which might be enhanced with a trust hierarchy (like PKI). | . | Request/Response (Sync) vs. Message Queuing (Async) . | Synchronous transports like HTTPS require both parties to be available at the time data is sent, and the transmission must be retried at the application (plugin) layer if it fails or times out. | Asynchronous transports like AMQP, MQTT or Kafka introduce one or more broker runtimes between the parties, that reliably buffer the communications if the target application falls behind or is temporarily unavailable. | . | Hub & spoke vs. Peer to peer . | Connectivity might be direct from one party to another within the network, tackling the IT security complexity of firewalls between sensitive networks. Or network shared infrastructure / as-a-service provider might be used to provide a reliable backbone for data exchange between the members. | . | End-to-end Payload Encryption . | Particularly in cases where the networking hops are complex, or involve shared shared/third-party infrastructure, end-to-end encryption can be used to additionally protect the data while in flight. This technology means data remains encrypted from the source to the target, regardless of the number of transport hops taken in-between. | . | Large blob / Managed file transfer . | The optimal approach to transferring real-time small messages (KBs in size) is different to the approach to transferring large blobs (MBs/GBs in size). For large blobs chunking, compression, and checkpoint restart are common for efficient and reliable transfer. | . | . ", "url": "/firefly/head/overview/multiparty/data_exchange.html#qualities-of-service", "relUrl": "/overview/multiparty/data_exchange.html#qualities-of-service" - },"316": { + },"320": { "doc": "pages.private_data_exchange", "title": "FireFly OSS implementation", "content": "A reference implementation of a private data exchange is provided as part of the FireFly project. This implementation uses peer-to-peer transfer over a synchronous HTTPS transport, backed by Mutual TLS authentication. X509 certificate exchange is orchestrated by FireFly, such that self-signed certificates can be used (or multiple PKI trust roots) and bound to the blockchain-backed identities of the organizations in FireFly. See hyperledger/firefly-dataexchange-https . ", "url": "/firefly/head/overview/multiparty/data_exchange.html#firefly-oss-implementation", "relUrl": "/overview/multiparty/data_exchange.html#firefly-oss-implementation" - },"317": { + },"321": { "doc": "pages.private_data_exchange", "title": "pages.private_data_exchange", "content": " ", "url": "/firefly/head/overview/multiparty/data_exchange.html", "relUrl": "/overview/multiparty/data_exchange.html" - },"318": { + },"322": { "doc": "DataRef", "title": "DataRef", "content": " ", "url": "/firefly/head/reference/types/dataref.html", "relUrl": "/reference/types/dataref.html" - },"319": { + },"323": { "doc": "DataRef", "title": "Table of contents", "content": ". | DataRef . | Example | Field Descriptions | . | . ", "url": "/firefly/head/reference/types/dataref.html#table-of-contents", "relUrl": "/reference/types/dataref.html#table-of-contents" - },"320": { + },"324": { "doc": "DataRef", "title": "DataRef", "content": "Example . { \"id\": \"5bea782a-6cf2-4e01-95ee-cb5fa05873e9\", \"hash\": \"8b7df143d91c716ecfa5fc1730022f6b421b05cedee8fd52b1fc65a96030ad52\" } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the referenced data resource | UUID | . | hash | The hash of the referenced data | Bytes32 | . ", "url": "/firefly/head/reference/types/dataref.html", "relUrl": "/reference/types/dataref.html" - },"321": { + },"325": { "doc": "Datatype", "title": "Datatype", "content": " ", "url": "/firefly/head/reference/types/datatype.html", "relUrl": "/reference/types/datatype.html" - },"322": { + },"326": { "doc": "Datatype", "title": "Table of contents", "content": ". | Datatype . | Example | Field Descriptions | . | . ", "url": "/firefly/head/reference/types/datatype.html#table-of-contents", "relUrl": "/reference/types/datatype.html#table-of-contents" - },"323": { + },"327": { "doc": "Datatype", "title": "Datatype", "content": "A datatype defines the format of some data that can be shared between parties, in a way that FireFly can enforce consistency of that data against the schema. Data that does not match the schema associated with it will not be accepted on upload to FireFly, and if this were bypassed by a participant in some way it would be rejected by all parties and result in a message_rejected event (rather than message_confirmed event). Currently JSON Schema validation of data is supported. The system for defining datatypes is pluggable, to support other schemes in the future, such as XML Schema, or CSV, EDI etc. Example . { \"id\": \"3a479f7e-ddda-4bda-aa24-56d06c0bf08e\", \"message\": \"bfcf904c-bdf7-40aa-bbd7-567f625c26c0\", \"validator\": \"json\", \"namespace\": \"ns1\", \"name\": \"widget\", \"version\": \"1.0.0\", \"hash\": \"639cd98c893fa45a9df6fd87bd0393a9b39e31e26fbb1eeefe90cb40c3fa02d2\", \"created\": \"2022-05-16T01:23:16Z\", \"value\": { \"$id\": \"https://example.com/widget.schema.json\", \"$schema\": \"https://json-schema.org/draft/2020-12/schema\", \"title\": \"Widget\", \"type\": \"object\", \"properties\": { \"id\": { \"type\": \"string\", \"description\": \"The unique identifier for the widget.\" }, \"name\": { \"type\": \"string\", \"description\": \"The person's last name.\" } }, \"additionalProperties\": false } } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the datatype | UUID | . | message | The UUID of the broadcast message that was used to publish this datatype to the network | UUID | . | validator | The validator that should be used to verify this datatype | FFEnum:\"json\"\"none\"\"definition\" | . | namespace | The namespace of the datatype. Data resources can only be created referencing datatypes in the same namespace | string | . | name | The name of the datatype | string | . | version | The version of the datatype. Multiple versions can exist with the same name. Use of semantic versioning is encourages, such as v1.0.1 | string | . | hash | 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 | Bytes32 | . | created | The time the datatype was created | FFTime | . | value | The definition of the datatype, in the syntax supported by the validator (such as a JSON Schema definition) | JSONAny | . ", "url": "/firefly/head/reference/types/datatype.html", "relUrl": "/reference/types/datatype.html" - },"324": { + },"328": { "doc": "Define a datatype", "title": "Define a datatype", "content": " ", "url": "/firefly/head/tutorials/define_datatype.html", "relUrl": "/tutorials/define_datatype.html" - },"325": { + },"329": { "doc": "Define a datatype", "title": "Table of contents", "content": ". | Quick reference | Additional info . | Example 1: Broadcast new datatype | . | Example message response | Lookup the confirmed data type | Example private send referring to the datatype | Defining Datatypes using the Sandbox | . ", "url": "/firefly/head/tutorials/define_datatype.html#table-of-contents", "relUrl": "/tutorials/define_datatype.html#table-of-contents" - },"326": { + },"330": { "doc": "Define a datatype", "title": "Quick reference", "content": "As your use case matures, it is important to agree formal datatypes between the parties. These canonical datatypes need to be defined and versioned, so that each member can extract and transform data from their internal systems into this datatype. Datatypes are broadcast to the network so everybody refers to the same JSON schema when validating their data. The broadcast must complete before a datatype can be used by an application to upload/broadcast/send data. The same system of broadcast within FireFly is used to broadcast definitions of datatypes, as is used to broadcast the data itself. ", "url": "/firefly/head/tutorials/define_datatype.html#quick-reference", "relUrl": "/tutorials/define_datatype.html#quick-reference" - },"327": { + },"331": { "doc": "Define a datatype", "title": "Additional info", "content": ". | Key Concepts: Broadcast / shared data | Swagger: POST /api/v1/namespaces/{ns}/datatypes | . Example 1: Broadcast new datatype . POST /api/v1/namespaces/{ns}/datatypes . { \"name\": \"widget\", \"version\": \"0.0.2\", \"value\": { \"$id\": \"https://example.com/widget.schema.json\", \"$schema\": \"https://json-schema.org/draft/2020-12/schema\", \"title\": \"Widget\", \"type\": \"object\", \"properties\": { \"id\": { \"type\": \"string\", \"description\": \"The unique identifier for the widget.\" }, \"name\": { \"type\": \"string\", \"description\": \"The person's last name.\" } } } } . ", "url": "/firefly/head/tutorials/define_datatype.html#additional-info", "relUrl": "/tutorials/define_datatype.html#additional-info" - },"328": { + },"332": { "doc": "Define a datatype", "title": "Example message response", "content": "Status: 202 Accepted - a broadcast message has been sent, and on confirmation the new datatype will be created (unless it conflicts with another definition with the same name and version that was ordered onto the blockchain before this definition). { \"header\": { \"id\": \"727f7d3a-d07e-4e80-95af-59f8d2ac7531\", // this is the ID of the message, not the data type \"type\": \"definition\", // a special type for system broadcasts \"txtype\": \"batch_pin\", // the broadcast is pinned to the chain \"author\": \"0x0a65365587a65ce44938eab5a765fe8bc6532bdf\", // the local identity \"created\": \"2021-07-01T21:06:26.9997478Z\", // the time the broadcast was sent \"namespace\": \"ff_system\", // the data/message broadcast happens on the system namespace \"topic\": [ \"ff_ns_default\" // the namespace itself is used in the topic ], \"tag\": \"ff_define_datatype\", // a tag instructing FireFly to process this as a datatype definition \"datahash\": \"56bd677e3e070ba62f547237edd7a90df5deaaf1a42e7d6435ec66a587c14370\" }, \"hash\": \"5b6593720243831ba9e4ad002c550e95c63704b2c9dbdf31135d7d9207f8cae8\", \"state\": \"ready\", // this message is stored locally but not yet confirmed \"data\": [ { \"id\": \"7539a0ab-78d8-4d42-b283-7e316b3afed3\", // this data object in the ff_system namespace, contains the schema \"hash\": \"22ba1cdf84f2a4aaffac665c83ff27c5431c0004dc72a9bf031ae35a75ac5aef\" } ] } . ", "url": "/firefly/head/tutorials/define_datatype.html#example-message-response", "relUrl": "/tutorials/define_datatype.html#example-message-response" - },"329": { + },"333": { "doc": "Define a datatype", "title": "Lookup the confirmed data type", "content": "GET /api/v1/namespaces/default/datatypes?name=widget&version=0.0.2 . [ { \"id\": \"421c94b1-66ce-4ba0-9794-7e03c63df29d\", // an ID allocated to the datatype \"message\": \"727f7d3a-d07e-4e80-95af-59f8d2ac7531\", // the message that broadcast this data type \"validator\": \"json\", // the type of validator that this datatype can be used for (this one is JSON Schema) \"namespace\": \"default\", // the namespace of the datatype \"name\": \"widget\", // the name of the datatype \"version\": \"0.0.2\", // the version of the data type \"hash\": \"a4dceb79a21937ca5ea9fa22419011ca937b4b8bc563d690cea3114af9abce2c\", // hash of the schema itself \"created\": \"2021-07-01T21:06:26.983986Z\", // time it was confirmed \"value\": { // the JSON schema itself \"$id\": \"https://example.com/widget.schema.json\", \"$schema\": \"https://json-schema.org/draft/2020-12/schema\", \"title\": \"Widget\", \"type\": \"object\", \"properties\": { \"id\": { \"type\": \"string\", \"description\": \"The unique identifier for the widget.\" }, \"name\": { \"type\": \"string\", \"description\": \"The person's last name.\" } } } } ] . ", "url": "/firefly/head/tutorials/define_datatype.html#lookup-the-confirmed-data-type", "relUrl": "/tutorials/define_datatype.html#lookup-the-confirmed-data-type" - },"330": { + },"334": { "doc": "Define a datatype", "title": "Example private send referring to the datatype", "content": "Once confirmed, a piece of data can be assigned that datatype and all FireFly nodes will verify it against the schema. On a sending node, the data will be rejected at upload/send time if it does not conform. On other nodes, bad data results in a message_rejected event (rather than message_confirmed) for any message that arrives referring to that data. POST /api/v1/namespaces/default/send/message . { \"header\": { \"tag\": \"new_widget_created\", \"topic\": [\"widget_id_12345\"] }, \"group\": { \"members\": [ { \"identity\": \"org_1\" } ] }, \"data\": [ { \"datatype\": { \"name\": \"widget\", \"version\": \"0.0.2\" }, \"value\": { \"id\": \"widget_id_12345\", \"name\": \"superwidget\" } } ] } . ", "url": "/firefly/head/tutorials/define_datatype.html#example-private-send-referring-to-the-datatype", "relUrl": "/tutorials/define_datatype.html#example-private-send-referring-to-the-datatype" - },"331": { + },"335": { "doc": "Define a datatype", "title": "Defining Datatypes using the Sandbox", "content": "You can also define a datatype through the FireFly Sandbox. To get started, open up the Web UI and Sanbox UI for at least one of your members. The URLs for these were printed in your terminal when you started your FireFly stack. In the sandbox, enter the datatype’s name, version, and JSON Schema as seen in the screenshot below. { \"name\": \"widget\", \"version\": \"0.0.2\", \"value\": { \"$id\": \"https://example.com/widget.schema.json\", \"$schema\": \"https://json-schema.org/draft/2020-12/schema\", \"title\": \"Widget\", \"type\": \"object\", \"properties\": { \"id\": { \"type\": \"string\", \"description\": \"The unique identifier for the widget.\" }, \"name\": { \"type\": \"string\", \"description\": \"The person's last name.\" } } } } . Notice how the data field in the center panel updates in real time. Click the blue Run button. This should return a 202 response immediately in the Server Response section and will populate the right hand panel with transaction information after a few seconds. Go back to the FireFly UI (the URL for this would have been shown in the terminal when you started the stack) and you’ll see that you’ve successfully defined your datatype . ", "url": "/firefly/head/tutorials/define_datatype.html#defining-datatypes-using-the-sandbox", "relUrl": "/tutorials/define_datatype.html#defining-datatypes-using-the-sandbox" - },"332": { + },"336": { "doc": "pages.deterministic", "title": "Deterministic Compute", "content": ". ", "url": "/firefly/head/overview/multiparty/deterministic.html#deterministic-compute", "relUrl": "/overview/multiparty/deterministic.html#deterministic-compute" - },"333": { + },"337": { "doc": "pages.deterministic", "title": "Introduction", "content": "A critical aspect of designing a multi-party systems, is choosing where you exploit the blockchain and other advanced cryptography technology to automate agreement between parties. Specifically where you rely on the computation itself to come up with a result that all parties can independently trust. For example because all parties performed the same computation independently and came up with the same result, against the same data, and agreed to that result using a consensus algorithm. The more sophisticated the agreement is you want to prove, the more consideration needs to be taken into factors such as: . | Data privacy | Data deletion | Ease of understanding by business users | Ease of audit | Autonomy of parties with proprietary business logic | Human workflows (obviously non-deterministic) | Technology complexity/maturity (particularly for privacy preserving technologies) | Cost and skills for implementation | . FireFly embraces the fact that different use cases, will make different decisions on how much of the agreement should be enforced through deterministic compute. Also that multi-party systems include a mixture of approaches in addition to deterministic compute, including traditional off-chain secure HTTP/Messaging, documents, private non-deterministic logic, and human workflows. ", "url": "/firefly/head/overview/multiparty/deterministic.html#introduction", "relUrl": "/overview/multiparty/deterministic.html#introduction" - },"334": { + },"338": { "doc": "pages.deterministic", "title": "The fundamental building blocks", "content": "There are some fundamental types of deterministic computation, that can be proved with mature blockchain technology, and all multi-party systems should consider exploiting: . | Total conservation of value . | Allows you to assign value to something, because you know it is a fraction of a total pool | This is the magic behind fungible tokens, or “coins” | The proven technology for this is a shared ledger of all previous transactions | Learn more in the Tokens section | . | Existence and ownership of a unique identifiable thing . | Gives you an anchor to attach to something in the real world | This is the magic behind non-fungible tokens (NTFs) | The proven technology for this is a shared ledger of its creation, and ownership changes | Learn more in the Tokens section | . | An agreed sequence of events . | The foundation tool that allows the building of higher level constructs (including tokens) | Not previously available when business ecosystems used HTTP/Messaging transports alone | Can be bi-lateral, multi-lateral or global | Each blockchain technology has different features to establish these “chains” of information | Different approaches provide privacy different levels of privacy on the parties and sequence | . | Identification of data by a “hash” of its contents . | The glue that binds a piece of private data, to a proof that you have a copy of that data | This is the basis of “pinning” data to the blockchain, without sharing its contents | Care needs to be taken to make sure the data is unique enough to make the hash secure | Learn more in the Gateway Features section | . | . ", "url": "/firefly/head/overview/multiparty/deterministic.html#the-fundamental-building-blocks", "relUrl": "/overview/multiparty/deterministic.html#the-fundamental-building-blocks" - },"335": { + },"339": { "doc": "pages.deterministic", "title": "Advanced Cryptography and Privacy Preserving Trusted Compute", "content": "There are use cases where a deterministic agreement on computation is desired, but the data upon which the execution is performed cannot be shared between all the parties. For example proving total conservation of value in a token trading scenario, without knowing who is involved in the individual transactions. Or providing you have access to a piece of data, without disclosing what that data is. Technologies exist that can solve these requirements, with two major categories: . | Zero Knowledge Proofs (ZKPs) . | Advanced cryptography techniques that allow one party to generate a proof that can be be verified by another party, without access to the data used to generate the proof. | . | Trusted Compute Environments (TEEs) . | Secure compute environments that provide proofs of what code was executed, such that other parties can be confident of the logic that was executed without having access to the data. | . | . FireFly today provides an orchestration engine that’s helpful in coordinating the inputs, outputs, and execution of such advanced cryptography technologies. Active collaboration between the FireFly and other projects like Hyperledger Avalon, and Hyperledger Cactus, is evolving how these technologies can plug-in with higher level patterns. ", "url": "/firefly/head/overview/multiparty/deterministic.html#advanced-cryptography-and-privacy-preserving-trusted-compute", "relUrl": "/overview/multiparty/deterministic.html#advanced-cryptography-and-privacy-preserving-trusted-compute" - },"336": { + },"340": { "doc": "pages.deterministic", "title": "Complementary approaches to deterministic computation", "content": "Enterprise multi-party systems usually operate differently to end-user decentralized applications. In particular, strong identity is established for the organizations that are involved, and those organizations usually sign legally binding commitments around their participation in the network. Those businesses then bring on-board an ecosystem of employees and or customers that are end-users to the system. So the shared source of truth empowered by the blockchain and other cryptography are not the only tools that can be used in the toolbox to ensure correct behavior. Recognizing that there are real legal entities involved, that are mature and regulated, does not undermine the value of the blockchain components. In fact it enhances it. A multi-party system can use just enough of this secret sauce in the right places, to change the dynamics of trust such that competitors in a market are willing to create value together that could never be created before. Or create a system where parties can share data with each other while still conforming to their own regulatory and audit commitments, that previously would have been impossible to share. Not to be overlooked is the sometimes astonishing efficiency increase that can be added to existing business relationships, by being able to agree the order and sequence of a set of events. Having the tools to digitize processes that previously took physical documents flying round the world, into near-immediate digital agreement where the arbitration of a dispute can be resolved at a tiny fraction of what would have been possible without a shared and immutable audit trail of who said what when. ", "url": "/firefly/head/overview/multiparty/deterministic.html#complementary-approaches-to-deterministic-computation", "relUrl": "/overview/multiparty/deterministic.html#complementary-approaches-to-deterministic-computation" - },"337": { + },"341": { "doc": "pages.deterministic", "title": "pages.deterministic", "content": " ", "url": "/firefly/head/overview/multiparty/deterministic.html", "relUrl": "/overview/multiparty/deterministic.html" - },"338": { + },"342": { "doc": "Setting up a FireFly Core Development Environment", "title": "Setting up a FireFly Core Development Environment", "content": " ", "url": "/firefly/head/contributors/dev_environment_setup.html", "relUrl": "/contributors/dev_environment_setup.html" - },"339": { + },"343": { "doc": "Setting up a FireFly Core Development Environment", "title": "Table of contents", "content": ". | Setting up a FireFly Core Development Environment . | Dependencies . | Install the FireFly CLI | Installing Go and setting up your GOPATH | . | Building FireFly | Install the CLI | Set up a development stack . | Start the stack | 1) From another terminal | 2) Using an IDE | . | Set up dev environment for other components | . | . This guide will walk you through setting up your machine for contributing to FireFly, specifically the FireFly core. ", "url": "/firefly/head/contributors/dev_environment_setup.html#table-of-contents", "relUrl": "/contributors/dev_environment_setup.html#table-of-contents" - },"340": { + },"344": { "doc": "Setting up a FireFly Core Development Environment", "title": "Dependencies", "content": "You will need a few prerequisites set up on your machine before you can build FireFly from source. We recommend doing development on macOS, Linux, or WSL 2.0. | Go 1.21 | make | GCC | openssl | . Install the FireFly CLI . The first step to setting up a local development environment is to install the FireFly CLI. Please section of the Getting Started Guide to install The FireFly CLI. Installing Go and setting up your GOPATH . We recommend following the instructions on golang.org to install Go, rather than installing Go from another package magager such as brew. Although it is possible to install Go any way you’d like, setting up your GOPATH may differ from the following instructions. After installing Go, you will need to add a few environment variables to your shell run commands file. This is usually a hidden file in your home directory called .bashrc or .zshrc, depending on which shell you’re using. Add the following lines to your .bashrc or .zshrc file: . export GOPATH=$HOME/go export GOROOT=\"/usr/local/go\" export PATH=\"$PATH:${GOPATH}/bin:${GOROOT}/bin\" . ", "url": "/firefly/head/contributors/dev_environment_setup.html#dependencies", "relUrl": "/contributors/dev_environment_setup.html#dependencies" - },"341": { + },"345": { "doc": "Setting up a FireFly Core Development Environment", "title": "Building FireFly", "content": "After installing dependencies, building FireFly from source is very easy. Just clone the repo: . git clone git@github.com:hyperledger/firefly.git && cd firefly . And run the Makefile to run tests, and compile the app . make . If you want to install the binary on your path (assuming your Go Home is already on your path), from inside the project directory you can simply run: . go install . ", "url": "/firefly/head/contributors/dev_environment_setup.html#building-firefly", "relUrl": "/contributors/dev_environment_setup.html#building-firefly" - },"342": { + },"346": { "doc": "Setting up a FireFly Core Development Environment", "title": "Install the CLI", "content": "Please check the CLI Installation instructions for the best way to install the CLI on your machine: https://github.com/hyperledger/firefly-cli#install-the-cli . ", "url": "/firefly/head/contributors/dev_environment_setup.html#install-the-cli", "relUrl": "/contributors/dev_environment_setup.html#install-the-cli" - },"343": { + },"347": { "doc": "Setting up a FireFly Core Development Environment", "title": "Set up a development stack", "content": "Now that you have both FireFly and the FireFly CLI installed, it’s time to create a development stack. The CLI can be used to create a docker-compose environment that runs the entirety of a FireFly network. This will include several different processes for each member of the network. This is very useful for people that want to build apps that use FireFly’s API. It can also be useful if you want to make changes to FireFly itself, however we need to set up the stack slightly differently in that case. Essentially what we are going to do is have docker-compose run everything in the FireFly network except one FireFly core process. We’ll run this FireFly core process on our host machine, and configure it to connect to the rest of the microservices running in docker-compose. This means we could launch FireFly from Visual Studio Code or some other IDE and use a debugger to see what’s going on inside FireFly as it’s running. We’ll call this stack dev. We’re also going to add --external 1 to the end of our command to create the new stack: . ff init dev --external 1 . This tells the CLI that we want to manage one of the FireFly core processes outside the docker-compose stack. For convenience, the CLI will still generate a config file for this process though. Start the stack . To start your new stack simply run: . ff start dev . At a certain point in the startup process, the CLI will pause and wait for up to two minutes for you to start the other FireFly node. There are two different ways you can run the external FireFly core process. 1) From another terminal . The CLI will print out the command line which can be copied and pasted into another terminal window to run FireFly. This command should be run from the firefly core project directory. Here is an example of the command that the CLI will tell you to run: . firefly -f ~/.firefly/stacks/dev/runtime/config/firefly_core_0.yml . NOTE: The first time you run FireFly with a fresh database, it will need a directory of database migrations to apply to the empty database. If you run FireFly from the firefly project directory you cloned from GitHub, it will automatically find these and apply them. If you run it from some other directory, you will have to point FireFly to the migrations on your own. 2) Using an IDE . If you named your stack dev there is a launch.json file for Visual Studio code already in the project directory. If you have the project open in Visual Studio Code, you can either press the F5 key to run it, or go to the “Run and Debug” view in Visual Studio code, and click “Run FireFly Core”. Now you should have a full FireFly stack up and running, and be able to debug FireFly using your IDE. Happy hacking! . NOTE: Because firefly-ui is a separate repo, unless you also start a UI dev server for the external FireFly core, the default UI path will not load. This is expected, and if you’re just working on FireFly core itself, you don’t need to worry about it.` . ", "url": "/firefly/head/contributors/dev_environment_setup.html#set-up-a-development-stack", "relUrl": "/contributors/dev_environment_setup.html#set-up-a-development-stack" - },"344": { + },"348": { "doc": "Setting up a FireFly Core Development Environment", "title": "Set up dev environment for other components", "content": "Refer to Advanced CLI Usage. ", "url": "/firefly/head/contributors/dev_environment_setup.html#set-up-dev-environment-for-other-components", "relUrl": "/contributors/dev_environment_setup.html#set-up-dev-environment-for-other-components" - },"345": { + },"349": { "doc": "pages.digital_assets", "title": "Digital Assets", "content": ". ", "url": "/firefly/head/overview/key_components/digital_assets.html#digital-assets", "relUrl": "/overview/key_components/digital_assets.html#digital-assets" - },"346": { + },"350": { "doc": "pages.digital_assets", "title": "Digital asset features", "content": "The modelling, transfer and management of digital assets is the core programming foundation of blockchain. Yet out of the box, raw blockchains designed to efficiently manage these assets in large ecosystems, do not come with all the building blocks needed by applications. Token API . Token standards have been evolving in the industry through standards like ERC-20/ERC-721, and the Web3 signing wallets that support these. Hyperledger FireFly bring this same standardization to the application tier. Providing APIs that work across token standards, and blockchain implementations, providing consistent and interoperable support. This means one application or set of back-end systems, can integrate with multiple blockchains, and different token implementations. Pluggability here is key, so that the rules of governance of each digital asset ecosystem can be exposed and enforced. Whether tokens are fungible, non-fungible, or some hybrid in between. Learn more about token standards for fungible tokens, and non-fungible tokens (NFTs) in this set of tutorials . Transfer history / audit trail . For efficiency blockchains do not provide a direct ability to query historical transaction information. Depending on the blockchain technology, even the current balance of your wallet can be complex to calculate - particularly for blockchain technologies based on an Unspent Transaction Output (UTXO) model. So off-chain indexing of transaction history is an absolute must-have for any digital asset solution. Hyperledger FireFly provides: . | Automatic indexing of tokens, whether existing or newly deployed | Off-chain indexing of fungible and non-fungible asset transfers & balances | Off-chain indexing of approvals | Integration with digital identity | Full extensibility across both token standards and blockchain technologies | . Wallets . Wallet and signing-key management is a critical requirement for any blockchain solution, particularly those involving the transfer of digital assets between wallets. Hyperledger FireFly provides you the ability to: . | Integrate multiple different signing/custody solutions in a proven way | Manage the mapping of off-chain identities to on-chain signing identities | Provide a plug-point for policy-based decision making on high value transactions | Manage connections to multiple different blockchain solutions | . ", "url": "/firefly/head/overview/key_components/digital_assets.html#digital-asset-features", "relUrl": "/overview/key_components/digital_assets.html#digital-asset-features" - },"347": { + },"351": { "doc": "pages.digital_assets", "title": "pages.digital_assets", "content": " ", "url": "/firefly/head/overview/key_components/digital_assets.html", "relUrl": "/overview/key_components/digital_assets.html" - },"348": { + },"352": { "doc": "Contributing to Documentation", "title": "Contributing to Documentation", "content": " ", "url": "/firefly/head/contributors/docs_setup.html", "relUrl": "/contributors/docs_setup.html" - },"349": { + },"353": { "doc": "Contributing to Documentation", "title": "Table of contents", "content": ". | Contributing to Documentation . | Process for updating documentation | Dependencies . | macOS | Linux | . | Build and serve the docs locally | . | . This guide will walk you through setting up your machine for contributing to FireFly documentation. Documentation contributions are extremely valuable. If you discover something is missing in the docs, we would love to include your additions or clarifications to help the next person who has the same question. This doc site is generated by a set of Markdown files in the main FireFly repository, under the ./docs directory. You can browse the source for the current live site in GitHub here: https://github.com/hyperledger/firefly/tree/main/docs . ", "url": "/firefly/head/contributors/docs_setup.html#table-of-contents", "relUrl": "/contributors/docs_setup.html#table-of-contents" - },"350": { + },"354": { "doc": "Contributing to Documentation", "title": "Process for updating documentation", "content": "The process for updating the documentation is really easy! You’ll follow the same basic steps outlined in the same steps outlined in the Contributor’s guide. Here are the detailed steps for contributing to the docs: . | Fork https://github.com/hyperledger/firefly | Clone your fork locally to your computer | Follow the steps below to view your local copy of the docs in a browser | Make some improvements to the Markdown files | Verify that your changes look they way you want them to in your browser | Create a new git commit with your changes. Be sure to sign-off on your commit by using git commit -s! | Push your changes | Open a Pull Request to incorporate your changes back into the hyperledger/firefly repo | . ", "url": "/firefly/head/contributors/docs_setup.html#process-for-updating-documentation", "relUrl": "/contributors/docs_setup.html#process-for-updating-documentation" - },"351": { + },"355": { "doc": "Contributing to Documentation", "title": "Dependencies", "content": "The FireFly docs site uses GitHub pages, which uses a tool called Jekyll to convert Markdown files into HTML files that can be read in your browser. Basically that means in order to build and view the pages locally on your machine, you need to have Jekyll. Jekyll is a Ruby app, so you’ll also need to have Ruby, and the Ruby bundler app to install Jekyll’s dependencies. The good news is these things are very easy to set up. macOS . If you’re using an Intel Mac, you are already good to go! macOS already comes with ruby and bundle installed and set up already. You don’t need to do anything extra. However, it may be advisable to install a newer version of Ruby anyway. NOTE: From the macOS Catalina 10.15 Release Notes: Scripting language runtimes such as Python, Ruby, and Perl are included in macOS for compatibility with legacy software. Future versions of macOS won’t include scripting language runtimes by default, and might require you to install additional packages. If your software depends on scripting languages, it’s recommended that you bundle the runtime within the app. (49764202) . If you’re using an Apple Silicon based Mac, the version of Ruby that comes with macOS supports both Intel and ARM binaries which unfortunately ends up causing some problems when installing certain gems. We recommend installing Ruby with brew and setting it on your path. This will also give you a newer version of Ruby. To do this, run: . brew install ruby echo 'export PATH=\"/opt/homebrew/opt/ruby/bin:$PATH\"' >> ~/.zshrc . Linux . You will need to install ruby and bundle and have them on your path to build and serve the docs locally. On Ubuntu, to install these, run the following commands: . sudo apt-get update sudo apt-get install ruby ruby-bundler . ", "url": "/firefly/head/contributors/docs_setup.html#dependencies", "relUrl": "/contributors/docs_setup.html#dependencies" - },"352": { + },"356": { "doc": "Contributing to Documentation", "title": "Build and serve the docs locally", "content": "To build and serve the docs locally, from the project root, navigate to the docs directory: . cd docs . Install docs dependencies: . bundle install . And start the Jekyll test server: . bundle exec jekyll serve --livereload . You should now be able to open http://127.0.0.1:4000/firefly/index.html in your browser and see a locally hosted version of the doc site. As you make changes to files in the ./docs directory, Jekyll will automatically rebuild the pages, and notify you of any errors or warnings in your terminal. If you have a browser open, it will automatically reload when changes are made to pages. ", "url": "/firefly/head/contributors/docs_setup.html#build-and-serve-the-docs-locally", "relUrl": "/contributors/docs_setup.html#build-and-serve-the-docs-locally" - },"353": { + },"357": { "doc": "ERC-1155", "title": "Use ERC-1155 tokens", "content": " ", "url": "/firefly/head/tutorials/tokens/erc1155.html#use-erc-1155-tokens", "relUrl": "/tutorials/tokens/erc1155.html#use-erc-1155-tokens" - },"354": { + },"358": { "doc": "ERC-1155", "title": "Table of contents", "content": ". | Previous steps: Install the FireFly CLI | Create a stack with an ERC-1155 connector | About the sample token contract | Use the Sandbox (optional) | Create a pool (using default token contract) | Create a pool (from a deployed token contract) | Mint tokens | Transfer tokens | Sending data with a transfer . | Broadcast message | Private message | . | Burn tokens | Token approvals . | Request | Response | . | . ", "url": "/firefly/head/tutorials/tokens/erc1155.html#table-of-contents", "relUrl": "/tutorials/tokens/erc1155.html#table-of-contents" - },"355": { + },"359": { "doc": "ERC-1155", "title": "Previous steps: Install the FireFly CLI", "content": "If you haven’t set up the FireFly CLI already, please go back to the Getting Started guide and read the section on how to Install the FireFly CLI. ← ① Install the FireFly CLI . ", "url": "/firefly/head/tutorials/tokens/erc1155.html#previous-steps-install-the-firefly-cli", "relUrl": "/tutorials/tokens/erc1155.html#previous-steps-install-the-firefly-cli" - },"356": { + },"360": { "doc": "ERC-1155", "title": "Create a stack with an ERC-1155 connector", "content": "The default token connector that the FireFly CLI sets up is for ERC-20 and ERC-721. If you would like to work with ERC-1155 tokens, you need to create a stack that is configured to use that token connector. To do that, run: . ff init ethereum -t erc-1155 . Then run: . ff start <your_stack_name> . ", "url": "/firefly/head/tutorials/tokens/erc1155.html#create-a-stack-with-an-erc-1155-connector", "relUrl": "/tutorials/tokens/erc1155.html#create-a-stack-with-an-erc-1155-connector" - },"357": { + },"361": { "doc": "ERC-1155", "title": "About the sample token contract", "content": "When the FireFly CLI set up your FireFly stack, it also deployed a sample ERC-1155 contract that conforms to the expectations of the token connector. When you create a token pool through FireFly’s token APIs, that contract will be used by default. ⚠️ WARNING: The default token contract that was deployed by the FireFly CLI is only provided for the purpose of learning about FireFly. It is not a production grade contract. If you intend to deploy a production application using tokens on FireFly, you should research token contract best practices. For details, please see the source code for the contract that was deployed. ", "url": "/firefly/head/tutorials/tokens/erc1155.html#about-the-sample-token-contract", "relUrl": "/tutorials/tokens/erc1155.html#about-the-sample-token-contract" - },"358": { + },"362": { "doc": "ERC-1155", "title": "Use the Sandbox (optional)", "content": "At this point you could open the Sandbox at http://127.0.0.1:5109/home?action=tokens.pools and perform the functions outlined in the rest of this guide. Or you can keep reading to learn how to build HTTP requests to work with tokens in FireFly. ", "url": "/firefly/head/tutorials/tokens/erc1155.html#use-the-sandbox-optional", "relUrl": "/tutorials/tokens/erc1155.html#use-the-sandbox-optional" - },"359": { + },"363": { "doc": "ERC-1155", "title": "Create a pool (using default token contract)", "content": "After your stack is up and running, the first thing you need to do is create a token pool. Every application will need at least one token pool. At a minimum, you must always specify a name and type (fungible or nonfungible) for the pool. POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/pools . { \"name\": \"testpool\", \"type\": \"fungible\" } . Other parameters: . | You must specify a connector if you have configured multiple token connectors | You may pass through a config object of additional parameters, if supported by your token connector | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | . ", "url": "/firefly/head/tutorials/tokens/erc1155.html#create-a-pool-using-default-token-contract", "relUrl": "/tutorials/tokens/erc1155.html#create-a-pool-using-default-token-contract" - },"360": { + },"364": { "doc": "ERC-1155", "title": "Create a pool (from a deployed token contract)", "content": "If you wish to use a contract that is already on the chain, it is recommended that you first upload the ABI for your specific contract by creating a FireFly contract interface. This step is optional if you’re certain that your ERC-1155 ABI conforms to the default expectations of the token connector, but is generally recommended. See the README of the token connector for details on what contract variants can currently be understood. You can pass a config object with an address when you make the request to create the token pool, and if you created a contract interface, you can include the interface ID as well. POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/pools . { \"name\": \"testpool\", \"type\": \"fungible\", \"interface\": { \"id\": \"b9e5e1ce-97bb-4a35-a25c-52c7c3f523d8\" }, \"config\": { \"address\": \"0xb1C845D32966c79E23f733742Ed7fCe4B41901FC\" } } . ", "url": "/firefly/head/tutorials/tokens/erc1155.html#create-a-pool-from-a-deployed-token-contract", "relUrl": "/tutorials/tokens/erc1155.html#create-a-pool-from-a-deployed-token-contract" - },"361": { + },"365": { "doc": "ERC-1155", "title": "Mint tokens", "content": "Once you have a token pool, you can mint tokens within it. With the default sample contract, only the creator of a pool is allowed to mint - but each contract may define its own permission model. POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/mint . { \"amount\": 10 } . Other parameters: . | You must specify a pool name if you’ve created more than one pool | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | You may specify to if you’d like to send the minted tokens to a specific identity (default is the same as key) | . ", "url": "/firefly/head/tutorials/tokens/erc1155.html#mint-tokens", "relUrl": "/tutorials/tokens/erc1155.html#mint-tokens" - },"362": { + },"366": { "doc": "ERC-1155", "title": "Transfer tokens", "content": "You may transfer tokens within a pool by specifying an amount and a destination understood by the connector (i.e. an Ethereum address). With the default sample contract, only the owner of a token or another approved account may transfer it away - but each contract may define its own permission model. POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/transfers . { \"amount\": 1, \"to\": \"0x07eab7731db665caf02bc92c286f51dea81f923f\" } . NOTE: When transferring a non-fungible token, the amount must always be 1. The tokenIndex field is also required when transferring a non-fungible token. Other parameters: . | You must specify a pool name if you’ve created more than one pool | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | You may specify from if you’d like to send tokens from a specific identity (default is the same as key) | . ", "url": "/firefly/head/tutorials/tokens/erc1155.html#transfer-tokens", "relUrl": "/tutorials/tokens/erc1155.html#transfer-tokens" - },"363": { + },"367": { "doc": "ERC-1155", "title": "Sending data with a transfer", "content": "All transfers (as well as mint/burn operations) support an optional message parameter that contains a broadcast or private message to be sent along with the transfer. This message follows the same convention as other FireFly messages, and may be comprised of text or blob data, and can provide context, metadata, or other supporting information about the transfer. The message will be batched, hashed, and pinned to the primary blockchain. The message ID and hash will also be sent to the token connector as part of the transfer operation, to be written to the token blockchain when the transaction is submitted. All recipients of the message will then be able to correlate the message with the token transfer. POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/transfers . Broadcast message . { \"amount\": 1, \"to\": \"0x07eab7731db665caf02bc92c286f51dea81f923f\", \"message\": { \"data\": [{ \"value\": \"payment for goods\" }] } } . Private message . { \"amount\": 1, \"to\": \"0x07eab7731db665caf02bc92c286f51dea81f923f\", \"message\": { \"header\": { \"type\": \"transfer_private\", }, \"group\": { \"members\": [{ \"identity\": \"org_1\" }] }, \"data\": [{ \"value\": \"payment for goods\" }] } } . Note that all parties in the network will be able to see the transfer (including the message ID and hash), but only the recipients of the message will be able to view the actual message data. ", "url": "/firefly/head/tutorials/tokens/erc1155.html#sending-data-with-a-transfer", "relUrl": "/tutorials/tokens/erc1155.html#sending-data-with-a-transfer" - },"364": { + },"368": { "doc": "ERC-1155", "title": "Burn tokens", "content": "You may burn tokens by simply specifying an amount. With the default sample contract, only the owner of a token or another approved account may burn it - but each connector may define its own permission model. POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/burn . { \"amount\": 1, } . NOTE: When burning a non-fungible token, the amount must always be 1. The tokenIndex field is also required when burning a non-fungible token. Other parameters: . | You must specify a pool name if you’ve created more than one pool | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | You may specify from if you’d like to burn tokens from a specific identity (default is the same as key) | . ", "url": "/firefly/head/tutorials/tokens/erc1155.html#burn-tokens", "relUrl": "/tutorials/tokens/erc1155.html#burn-tokens" - },"365": { + },"369": { "doc": "ERC-1155", "title": "Token approvals", "content": "You can also approve other wallets to transfer tokens on your behalf with the /approvals API. The important fields in a token approval API request are as follows: . | approved: Sets whether another account is allowed to transfer tokens out of this wallet or not. If not specified, will default to true. Setting to false can revoke an existing approval. | operator: The other account that is allowed to transfer tokens out of the wallet specified in the key field | key: The wallet address for the approval. If not set, it defaults to the address of the FireFly node submitting the transaction | . Here is an example request that would let the signing account 0x634ee8c7d0894d086c7af1fc8514736aed251528 transfer any amount of tokens from my wallet . Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/approvals . { \"operator\": \"0x634ee8c7d0894d086c7af1fc8514736aed251528\" } . Response . { \"localId\": \"46fef50a-cf93-4f92-acf8-fae161b37362\", \"pool\": \"e1477ed5-7282-48e5-ad9d-1612296bb29d\", \"connector\": \"erc1155\", \"key\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"operator\": \"0x634ee8c7d0894d086c7af1fc8514736aed251528\", \"approved\": true, \"tx\": { \"type\": \"token_approval\", \"id\": \"00faa011-f42c-403d-a047-2df7318967cd\" } } . ", "url": "/firefly/head/tutorials/tokens/erc1155.html#token-approvals", "relUrl": "/tutorials/tokens/erc1155.html#token-approvals" - },"366": { + },"370": { "doc": "ERC-1155", "title": "ERC-1155", "content": " ", "url": "/firefly/head/tutorials/tokens/erc1155.html", "relUrl": "/tutorials/tokens/erc1155.html" - },"367": { + },"371": { "doc": "ERC-20", "title": "Use ERC-20 tokens", "content": " ", "url": "/firefly/head/tutorials/tokens/erc20.html#use-erc-20-tokens", "relUrl": "/tutorials/tokens/erc20.html#use-erc-20-tokens" - },"368": { + },"372": { "doc": "ERC-20", "title": "Table of contents", "content": ". | Previous steps: Start your environment | About the sample token contracts | Use the Sandbox (optional) | Create a pool (using default token factory) . | Request | Response | Get the address of the deployed contract . | Request | Response | . | . | Create a pool (from a deployed token contract) . | Request | . | Mint tokens . | Request | Response | . | Transfer tokens . | Request | Response | . | Sending data with a transfer . | Broadcast message | Private message | . | Burn tokens | Token approvals . | Request | Response | . | Use Metamask . | Configure a new network | Import tokens | Transfer tokens | . | . ", "url": "/firefly/head/tutorials/tokens/erc20.html#table-of-contents", "relUrl": "/tutorials/tokens/erc20.html#table-of-contents" - },"369": { + },"373": { "doc": "ERC-20", "title": "Previous steps: Start your environment", "content": "If you haven’t started a FireFly stack already, please go to the Getting Started guide on how to Start your environment. This will set up a token connector that works with both ERC-20 and ERC-721 by default. ← ② Start your environment . ", "url": "/firefly/head/tutorials/tokens/erc20.html#previous-steps-start-your-environment", "relUrl": "/tutorials/tokens/erc20.html#previous-steps-start-your-environment" - },"370": { + },"374": { "doc": "ERC-20", "title": "About the sample token contracts", "content": "If you are using the default ERC-20 / ERC-721 token connector, when the FireFly CLI set up your FireFly stack, it also deployed a token factory contract. When you create a token pool through FireFly’s token APIs, the token factory contract will automatically deploy an ERC-20 or ERC-721 contract, based on the pool type in the API request. ⚠️ WARNING: The default token contract that was deployed by the FireFly CLI is only provided for the purpose of learning about FireFly. It is not a production grade contract. If you intend to deploy a production application using tokens on FireFly, you should research token contract best practices. For details, please see the source code for the contract that was deployed. ", "url": "/firefly/head/tutorials/tokens/erc20.html#about-the-sample-token-contracts", "relUrl": "/tutorials/tokens/erc20.html#about-the-sample-token-contracts" - },"371": { + },"375": { "doc": "ERC-20", "title": "Use the Sandbox (optional)", "content": "At this point you could open the Sandbox at http://127.0.0.1:5109/home?action=tokens.pools and perform the functions outlined in the rest of this guide. Or you can keep reading to learn how to build HTTP requests to work with tokens in FireFly. ", "url": "/firefly/head/tutorials/tokens/erc20.html#use-the-sandbox-optional", "relUrl": "/tutorials/tokens/erc20.html#use-the-sandbox-optional" - },"372": { + },"376": { "doc": "ERC-20", "title": "Create a pool (using default token factory)", "content": "After your stack is up and running, the first thing you need to do is create a token pool. Every application will need at least one token pool. At a minimum, you must always specify a name and type for the pool. If you’re using the default ERC-20 / ERC-721 token connector and its sample token factory, it will automatically deploy a new ERC-20 contract instance. Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/pools . { \"name\": \"testpool\", \"type\": \"fungible\" } . Response . { \"id\": \"e1477ed5-7282-48e5-ad9d-1612296bb29d\", \"type\": \"fungible\", \"namespace\": \"default\", \"name\": \"testpool\", \"key\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"connector\": \"erc20_erc721\", \"tx\": { \"type\": \"token_pool\", \"id\": \"e901921e-ffc4-4776-b20a-9e9face70a47\" } } . Other parameters: . | You must specify a connector if you have configured multiple token connectors | You may pass through a config object of additional parameters, if supported by your token connector | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | . Get the address of the deployed contract . To lookup the address of the new contract, you can lookup the token pool by its ID on the API. Creating the token pool will also emit an event which will contain the address. To query the token pool you can make a GET request to the pool’s ID: . Request . GET http://127.0.0.1:5000/api/v1/namespaces/default/tokens/pools/5811e8d5-52d0-44b1-8b75-73f5ff88f598 . Response . { \"id\": \"e1477ed5-7282-48e5-ad9d-1612296bb29d\", \"type\": \"fungible\", \"namespace\": \"default\", \"name\": \"testpool\", \"standard\": \"ERC20\", \"locator\": \"address=0xc4d02efcfab06f18ec0a68e00b98ffecf6bf7e3c&schema=ERC20WithData&type=fungible\", \"decimals\": 18, \"connector\": \"erc20_erc721\", \"message\": \"7e2f6004-31fd-4ba8-9845-15c5fe5fbcd7\", \"state\": \"confirmed\", \"created\": \"2022-04-28T14:03:16.732222381Z\", \"info\": { \"address\": \"0xc4d02efcfab06f18ec0a68e00b98ffecf6bf7e3c\", \"name\": \"testpool\", \"schema\": \"ERC20WithData\" }, \"tx\": { \"type\": \"token_pool\", \"id\": \"e901921e-ffc4-4776-b20a-9e9face70a47\" } } . ", "url": "/firefly/head/tutorials/tokens/erc20.html#create-a-pool-using-default-token-factory", "relUrl": "/tutorials/tokens/erc20.html#create-a-pool-using-default-token-factory" - },"373": { + },"377": { "doc": "ERC-20", "title": "Create a pool (from a deployed token contract)", "content": "If you wish to index and use a contract that is already on the chain, it is recommended that you first upload the ABI for your specific contract by creating a FireFly contract interface. This step is optional if you’re certain that your ERC-20 ABI conforms to the default expectations of the token connector, but is generally recommended. See the README of the token connector for details on what contract variants can currently be understood. You can pass a config object with an address and blockNumber when you make the request to create the token pool, and if you created a contract interface, you can include the interface ID as well. Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/pools . { \"name\": \"testpool\", \"type\": \"fungible\", \"interface\": { \"id\": \"b9e5e1ce-97bb-4a35-a25c-52c7c3f523d8\" }, \"config\": { \"address\": \"0xb1C845D32966c79E23f733742Ed7fCe4B41901FC\", \"blockNumber\": \"0\" } } . ", "url": "/firefly/head/tutorials/tokens/erc20.html#create-a-pool-from-a-deployed-token-contract", "relUrl": "/tutorials/tokens/erc20.html#create-a-pool-from-a-deployed-token-contract" - },"374": { + },"378": { "doc": "ERC-20", "title": "Mint tokens", "content": "Once you have a token pool, you can mint tokens within it. When using the sample contract deployed by the CLI, only the creator of a pool is allowed to mint, but a different contract may define its own permission model. NOTE: The default sample contract uses 18 decimal places. This means that if you want to create 100 tokens, the number submitted to the API / blockchain should actually be 100×1018 = 100000000000000000000. This allows users to work with “fractional” tokens even though Ethereum virtual machines only support integer arithmetic. Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/mint . { \"amount\": \"100000000000000000000\" } . Response . { \"type\": \"mint\", \"localId\": \"835fe2a1-594b-4336-bc1d-b2f59d51064b\", \"pool\": \"e1477ed5-7282-48e5-ad9d-1612296bb29d\", \"connector\": \"erc20_erc721\", \"key\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"from\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"to\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"amount\": \"100000000000000000000\", \"tx\": { \"type\": \"token_transfer\", \"id\": \"3fc97e24-fde1-4e80-bd82-660e479c0c43\" } } . Other parameters: . | You must specify a pool name if you’ve created more than one pool | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | You may specify to if you’d like to send the minted tokens to a specific identity (default is the same as key) | . ", "url": "/firefly/head/tutorials/tokens/erc20.html#mint-tokens", "relUrl": "/tutorials/tokens/erc20.html#mint-tokens" - },"375": { + },"379": { "doc": "ERC-20", "title": "Transfer tokens", "content": "You may transfer tokens within a pool by specifying an amount and a destination understood by the connector (i.e. an Ethereum address). With the default sample contract, only the owner of the tokens or another approved account may transfer their tokens, but a different contract may define its own permission model. Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/transfers . { \"amount\": \"10000000000000000000\", \"to\": \"0xa4222a4ae19448d43a338e6586edd5fb2ac398e1\" } . Response . { \"type\": \"transfer\", \"localId\": \"61f0a71f-712b-4778-8b37-784fbee52657\", \"pool\": \"e1477ed5-7282-48e5-ad9d-1612296bb29d\", \"connector\": \"erc20_erc721\", \"key\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"from\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"to\": \"0xa4222a4ae19448d43a338e6586edd5fb2ac398e1\", \"amount\": \"10000000000000000000\", \"tx\": { \"type\": \"token_transfer\", \"id\": \"c0c316a3-23a9-42f3-89b3-1cfdba6c948d\" } } . Other parameters: . | You must specify a pool name if you’ve created more than one pool | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | You may specify from if you’d like to send tokens from a specific identity (default is the same as key) | . ", "url": "/firefly/head/tutorials/tokens/erc20.html#transfer-tokens", "relUrl": "/tutorials/tokens/erc20.html#transfer-tokens" - },"376": { + },"380": { "doc": "ERC-20", "title": "Sending data with a transfer", "content": "All transfers (as well as mint/burn operations) support an optional message parameter that contains a broadcast or private message to be sent along with the transfer. This message follows the same convention as other FireFly messages, and may be comprised of text or blob data, and can provide context, metadata, or other supporting information about the transfer. The message will be batched, hashed, and pinned to the primary blockchain. The message ID and hash will also be sent to the token connector as part of the transfer operation, to be written to the token blockchain when the transaction is submitted. All recipients of the message will then be able to correlate the message with the token transfer. POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/transfers . Broadcast message . { \"amount\": 1, \"to\": \"0x07eab7731db665caf02bc92c286f51dea81f923f\", \"message\": { \"data\": [{ \"value\": \"payment for goods\" }] } } . Private message . { \"amount\": 1, \"to\": \"0x07eab7731db665caf02bc92c286f51dea81f923f\", \"message\": { \"header\": { \"type\": \"transfer_private\", }, \"group\": { \"members\": [{ \"identity\": \"org_1\" }] }, \"data\": [{ \"value\": \"payment for goods\" }] } } . Note that all parties in the network will be able to see the transfer (including the message ID and hash), but only the recipients of the message will be able to view the actual message data. ", "url": "/firefly/head/tutorials/tokens/erc20.html#sending-data-with-a-transfer", "relUrl": "/tutorials/tokens/erc20.html#sending-data-with-a-transfer" - },"377": { + },"381": { "doc": "ERC-20", "title": "Burn tokens", "content": "You may burn tokens by simply specifying an amount. With the default sample contract, only the owner of a token or another approved account may burn it, but a different contract may define its own permission model. POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/burn . { \"amount\": 1, } . Other parameters: . | You must specify a pool name if you’ve created more than one pool | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | You may specify from if you’d like to burn tokens from a specific identity (default is the same as key) | . ", "url": "/firefly/head/tutorials/tokens/erc20.html#burn-tokens", "relUrl": "/tutorials/tokens/erc20.html#burn-tokens" - },"378": { + },"382": { "doc": "ERC-20", "title": "Token approvals", "content": "You can also approve other wallets to transfer tokens on your behalf with the /approvals API. The important fields in a token approval API request are as follows: . | approved: Sets whether another account is allowed to transfer tokens out of this wallet or not. If not specified, will default to true. Setting to false can revoke an existing approval. | operator: The other account that is allowed to transfer tokens out of the wallet specified in the key field. | config.allowance: The number of tokens the other account is allowed to transfer. If 0 or not set, the approval is valid for any number. | key: The wallet address for the approval. If not set, it defaults to the address of the FireFly node submitting the transaction. | . Here is an example request that would let the signing account 0x634ee8c7d0894d086c7af1fc8514736aed251528 transfer up to 10×1018 (10000000000000000000) tokens from my wallet . Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/approvals . { \"operator\": \"0x634ee8c7d0894d086c7af1fc8514736aed251528\", \"config\": { \"allowance\": \"10000000000000000000\" } } . Response . { \"localId\": \"46fef50a-cf93-4f92-acf8-fae161b37362\", \"pool\": \"e1477ed5-7282-48e5-ad9d-1612296bb29d\", \"connector\": \"erc20_erc721\", \"key\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"operator\": \"0x634ee8c7d0894d086c7af1fc8514736aed251528\", \"approved\": true, \"tx\": { \"type\": \"token_approval\", \"id\": \"00faa011-f42c-403d-a047-2df7318967cd\" }, \"config\": { \"allowance\": \"10000000000000000000\" } } . ", "url": "/firefly/head/tutorials/tokens/erc20.html#token-approvals", "relUrl": "/tutorials/tokens/erc20.html#token-approvals" - },"379": { + },"383": { "doc": "ERC-20", "title": "Use Metamask", "content": "Now that you have an ERC-20 contract up and running, you may be wondering how to use Metamask (or some other wallet) with this contract. This section will walk you through how to connect Metamask to the blockchain and token contract that FireFly is using. Configure a new network . The first thing we need to do is tell Metamask how to connect to our local blockchain node. To do that: . | Click your account icon | In the drop down menu, click Settings . | On the left hand side of the page, click Networks | Click the Add a network button . | Fill in the network details: . | Network Name: FireFly (could be any name) | New RPC URL: http://127.0.0.1:5100 | Chain ID: 2021 | Currency Symbol: ETH | . | Click Save | . Import tokens . Metamask won’t know about our custom ERC-20 contract until we give it the Ethereum address for the contract, so that’s what we’ll do next. | Click on Import tokens . | Enter the Ethereum address of the contract | Enter a Token Symbol (can be anything you want) | Click Add Custom Token | . NOTE: You can find the address of your contract from the response to the request to create the token pool above. You can also do a GET to http://127.0.0.1:5000/api/v1/namespaces/default/tokens/pools to lookup your configured token pools. Transfer tokens . Now you can copy your account address from your Metamask wallet, and perform a transfer from FireFly’s API (as described above) to your Metamask address. After a couple seconds, you should see your tokens show up in your Metamask wallet. You can also send tokens to a FireFly address or any other Ethereum address from your Metamask wallet. NOTE: You can find the Ethereum addresses for organizations in your FireFly network in the Network → Organizations page in the FireFly explorer. Click on an organization and look under the Verifiers header for the organization’s Ethereum address. ", "url": "/firefly/head/tutorials/tokens/erc20.html#use-metamask", "relUrl": "/tutorials/tokens/erc20.html#use-metamask" - },"380": { + },"384": { "doc": "ERC-20", "title": "ERC-20", "content": " ", "url": "/firefly/head/tutorials/tokens/erc20.html", "relUrl": "/tutorials/tokens/erc20.html" - },"381": { + },"385": { "doc": "ERC-721", "title": "Use ERC-721 tokens", "content": " ", "url": "/firefly/head/tutorials/tokens/erc721.html#use-erc-721-tokens", "relUrl": "/tutorials/tokens/erc721.html#use-erc-721-tokens" - },"382": { + },"386": { "doc": "ERC-721", "title": "Table of contents", "content": ". | Previous steps: Start your environment | About the sample token contracts | Use the Sandbox (optional) | Create a pool (using default token factory) . | Request | Response | Get the address of the deployed contract . | Request | Response | . | . | Create a pool (from a deployed token contract) . | Request | . | Mint a token . | Request | Response | . | Transfer a token . | Request | Response | . | Sending data with a transfer . | Broadcast message | Private message | . | Burn tokens | Token approvals . | Request | Response | . | Use Metamask . | Configure a new network | Import tokens | Transfer tokens | . | . ", "url": "/firefly/head/tutorials/tokens/erc721.html#table-of-contents", "relUrl": "/tutorials/tokens/erc721.html#table-of-contents" - },"383": { + },"387": { "doc": "ERC-721", "title": "Previous steps: Start your environment", "content": "If you haven’t started a FireFly stack already, please go to the Getting Started guide on how to Start your environment. This will set up a token connector that works with both ERC-20 and ERC-721 by default. ← ② Start your environment . ", "url": "/firefly/head/tutorials/tokens/erc721.html#previous-steps-start-your-environment", "relUrl": "/tutorials/tokens/erc721.html#previous-steps-start-your-environment" - },"384": { + },"388": { "doc": "ERC-721", "title": "About the sample token contracts", "content": "If you are using the default ERC-20 / ERC-721 token connector, when the FireFly CLI set up your FireFly stack, it also deployed a token factory contract. When you create a token pool through FireFly’s token APIs, the token factory contract will automatically deploy an ERC-20 or ERC-721 contract, based on the pool type in the API request. ⚠️ WARNING: The default token contract that was deployed by the FireFly CLI is only provided for the purpose of learning about FireFly. It is not a production grade contract. If you intend to deploy a production application using tokens on FireFly, you should research token contract best practices. For details, please see the source code for the contract that was deployed. ", "url": "/firefly/head/tutorials/tokens/erc721.html#about-the-sample-token-contracts", "relUrl": "/tutorials/tokens/erc721.html#about-the-sample-token-contracts" - },"385": { + },"389": { "doc": "ERC-721", "title": "Use the Sandbox (optional)", "content": "At this point you could open the Sandbox at http://127.0.0.1:5109/home?action=tokens.pools and perform the functions outlined in the rest of this guide. Or you can keep reading to learn how to build HTTP requests to work with tokens in FireFly. ", "url": "/firefly/head/tutorials/tokens/erc721.html#use-the-sandbox-optional", "relUrl": "/tutorials/tokens/erc721.html#use-the-sandbox-optional" - },"386": { + },"390": { "doc": "ERC-721", "title": "Create a pool (using default token factory)", "content": "After your stack is up and running, the first thing you need to do is create a token pool. Every application will need at least one token pool. At a minimum, you must always specify a name and type for the pool. If you’re using the default ERC-20 / ERC-721 token connector and its sample token factory, it will automatically deploy a new ERC-721 contract instance. Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/pools . { \"type\": \"nonfungible\", \"name\": \"nfts\" } . Response . { \"id\": \"a92a0a25-b886-4b43-931f-4add2840258a\", \"type\": \"nonfungible\", \"namespace\": \"default\", \"name\": \"nfts\", \"key\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"connector\": \"erc20_erc721\", \"tx\": { \"type\": \"token_pool\", \"id\": \"00678116-89d2-4295-990c-bd5ffa6e2434\" } } . Other parameters: . | You must specify a connector if you have configured multiple token connectors | You may pass through a config object of additional parameters, if supported by your token connector | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | . Get the address of the deployed contract . To lookup the address of the new contract, you can lookup the token pool by its ID on the API. Creating the token pool will also emit an event which will contain the address. To query the token pool you can make a GET request to the pool’s ID: . Request . GET http://127.0.0.1:5000/api/v1/namespaces/default/tokens/pools/5811e8d5-52d0-44b1-8b75-73f5ff88f598 . Response . { \"id\": \"a92a0a25-b886-4b43-931f-4add2840258a\", \"type\": \"nonfungible\", \"namespace\": \"default\", \"name\": \"nfts\", \"standard\": \"ERC721\", \"locator\": \"address=0xc4d02efcfab06f18ec0a68e00b98ffecf6bf7e3c&schema=ERC721WithData&type=nonfungible\", \"connector\": \"erc20_erc721\", \"message\": \"53d95dda-e8ca-4546-9226-a0fdc6ec03ec\", \"state\": \"confirmed\", \"created\": \"2022-04-29T12:03:51.971349509Z\", \"info\": { \"address\": \"0xc4d02efcfab06f18ec0a68e00b98ffecf6bf7e3c\", \"name\": \"nfts\", \"schema\": \"ERC721WithData\" }, \"tx\": { \"type\": \"token_pool\", \"id\": \"00678116-89d2-4295-990c-bd5ffa6e2434\" } } . ", "url": "/firefly/head/tutorials/tokens/erc721.html#create-a-pool-using-default-token-factory", "relUrl": "/tutorials/tokens/erc721.html#create-a-pool-using-default-token-factory" - },"387": { + },"391": { "doc": "ERC-721", "title": "Create a pool (from a deployed token contract)", "content": "If you wish to index and use a contract that is already on the chain, it is recommended that you first upload the ABI for your specific contract by creating a FireFly contract interface. This step is optional if you’re certain that your ERC-721 ABI conforms to the default expectations of the token connector, but is generally recommended. See the README of the token connector for details on what contract variants can currently be understood. You can pass a config object with an address and blockNumber when you make the request to create the token pool, and if you created a contract interface, you can include the interface ID as well. Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/pools . { \"name\": \"testpool\", \"type\": \"nonfungible\", \"interface\": { \"id\": \"b9e5e1ce-97bb-4a35-a25c-52c7c3f523d8\" }, \"config\": { \"address\": \"0xb1C845D32966c79E23f733742Ed7fCe4B41901FC\", \"blockNumber\": \"0\" } } . ", "url": "/firefly/head/tutorials/tokens/erc721.html#create-a-pool-from-a-deployed-token-contract", "relUrl": "/tutorials/tokens/erc721.html#create-a-pool-from-a-deployed-token-contract" - },"388": { + },"392": { "doc": "ERC-721", "title": "Mint a token", "content": "Once you have a token pool, you can mint tokens within it. When using the sample contract deployed by the CLI, the following are true: . | only the creator of a pool is allowed to mint within that pool | the tokenIndex must be set to a unique value | the amount must be 1 | . A different ERC-721 contract may define its own requirements. Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/mint . { \"amount\": \"1\", \"tokenIndex\": \"1\" } . Response . { \"type\": \"mint\", \"localId\": \"2de2e05e-9474-4a08-a64f-2cceb076bdaa\", \"pool\": \"a92a0a25-b886-4b43-931f-4add2840258a\", \"connector\": \"erc20_erc721\", \"key\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"from\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"to\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"amount\": \"1\", \"tx\": { \"type\": \"token_transfer\", \"id\": \"0fad4581-7cb2-42c7-8f78-62d32205c2c2\" } } . Other parameters: . | You must specify a pool name if you’ve created more than one pool | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | You may specify to if you’d like to send the minted tokens to a specific identity (default is the same as key) | . ", "url": "/firefly/head/tutorials/tokens/erc721.html#mint-a-token", "relUrl": "/tutorials/tokens/erc721.html#mint-a-token" - },"389": { + },"393": { "doc": "ERC-721", "title": "Transfer a token", "content": "You may transfer tokens within a pool by specifying an amount and a destination understood by the connector (i.e. an Ethereum address). With the default sample contract, only the owner of the tokens or another approved account may transfer their tokens, but a different contract may define its own permission model. When transferring an NFT, you must also specify the tokenIndex that you wish to transfer. The tokenIndex is simply the ID of the specific NFT within the pool that you wish to transfer. NOTE: When transferring NFTs the amount must be 1. If you wish to transfer more NFTs, simply call the endpoint multiple times, specifying the token index of each token to transfer. Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/transfers . { \"amount\": \"1\", \"tokenIndex\": \"1\", \"to\": \"0xa4222a4ae19448d43a338e6586edd5fb2ac398e1\" } . Response . { \"type\": \"transfer\", \"localId\": \"f5fd0d13-db13-4d70-9a99-6bcd747f1e42\", \"pool\": \"a92a0a25-b886-4b43-931f-4add2840258a\", \"tokenIndex\": \"1\", \"connector\": \"erc20_erc721\", \"key\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"from\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"to\": \"0xa4222a4ae19448d43a338e6586edd5fb2ac398e1\", \"amount\": \"1\", \"tx\": { \"type\": \"token_transfer\", \"id\": \"63c1a89b-240c-41eb-84bb-323d56f4ba5a\" } } . Other parameters: . | You must specify a pool name if you’ve created more than one pool | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | You may specify from if you’d like to send tokens from a specific identity (default is the same as key) | . ", "url": "/firefly/head/tutorials/tokens/erc721.html#transfer-a-token", "relUrl": "/tutorials/tokens/erc721.html#transfer-a-token" - },"390": { + },"394": { "doc": "ERC-721", "title": "Sending data with a transfer", "content": "All transfers (as well as mint/burn operations) support an optional message parameter that contains a broadcast or private message to be sent along with the transfer. This message follows the same convention as other FireFly messages, and may be comprised of text or blob data, and can provide context, metadata, or other supporting information about the transfer. The message will be batched, hashed, and pinned to the primary blockchain. The message ID and hash will also be sent to the token connector as part of the transfer operation, to be written to the token blockchain when the transaction is submitted. All recipients of the message will then be able to correlate the message with the token transfer. POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/transfers . Broadcast message . { \"amount\": 1, \"tokenIndex\": \"1\", \"to\": \"0x07eab7731db665caf02bc92c286f51dea81f923f\", \"message\": { \"data\": [{ \"value\": \"payment for goods\" }] } } . Private message . { \"amount\": 1, \"tokenIndex\": \"1\", \"to\": \"0x07eab7731db665caf02bc92c286f51dea81f923f\", \"message\": { \"header\": { \"type\": \"transfer_private\", }, \"group\": { \"members\": [{ \"identity\": \"org_1\" }] }, \"data\": [{ \"value\": \"payment for goods\" }] } } . Note that all parties in the network will be able to see the transfer (including the message ID and hash), but only the recipients of the message will be able to view the actual message data. ", "url": "/firefly/head/tutorials/tokens/erc721.html#sending-data-with-a-transfer", "relUrl": "/tutorials/tokens/erc721.html#sending-data-with-a-transfer" - },"391": { + },"395": { "doc": "ERC-721", "title": "Burn tokens", "content": "You may burn a token by specifying the token’s tokenIndex. With the default sample contract, only the owner of a token or another approved account may burn it, but a different contract may define its own permission model. POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/burn . { \"amount\": 1, \"tokenIndex\": \"1\" } . Other parameters: . | You must specify a pool name if you’ve created more than one pool | You may specify a key understood by the connector (i.e. an Ethereum address) if you’d like to use a non-default signing identity | You may specify from if you’d like to burn tokens from a specific identity (default is the same as key) | . ", "url": "/firefly/head/tutorials/tokens/erc721.html#burn-tokens", "relUrl": "/tutorials/tokens/erc721.html#burn-tokens" - },"392": { + },"396": { "doc": "ERC-721", "title": "Token approvals", "content": "You can also approve other wallets to transfer tokens on your behalf with the /approvals API. The important fields in a token approval API request are as follows: . | approved: Sets whether another account is allowed to transfer tokens out of this wallet or not. If not specified, will default to true. Setting to false can revoke an existing approval. | operator: The other account that is allowed to transfer tokens out of the wallet specified in the key field | config.tokenIndex: The specific token index within the pool that the operator is allowed to transfer. If 0 or not set, the approval is valid for all tokens. | key: The wallet address for the approval. If not set, it defaults to the address of the FireFly node submitting the transaction | . Here is an example request that would let the signing account 0x634ee8c7d0894d086c7af1fc8514736aed251528 transfer tokenIndex 2 from my wallet. Request . POST http://127.0.0.1:5000/api/v1/namespaces/default/tokens/approvals . { \"operator\": \"0x634ee8c7d0894d086c7af1fc8514736aed251528\", \"config\": { \"tokenIndex\": \"2\" } } . Response . { \"localId\": \"46fef50a-cf93-4f92-acf8-fae161b37362\", \"pool\": \"e1477ed5-7282-48e5-ad9d-1612296bb29d\", \"connector\": \"erc20_erc721\", \"key\": \"0x14ddd36a0c2f747130915bf5214061b1e4bec74c\", \"operator\": \"0x634ee8c7d0894d086c7af1fc8514736aed251528\", \"approved\": true, \"tx\": { \"type\": \"token_approval\", \"id\": \"00faa011-f42c-403d-a047-2df7318967cd\" }, \"config\": { \"tokenIndex\": \"2\" } } . ", "url": "/firefly/head/tutorials/tokens/erc721.html#token-approvals", "relUrl": "/tutorials/tokens/erc721.html#token-approvals" - },"393": { + },"397": { "doc": "ERC-721", "title": "Use Metamask", "content": "Now that you have an ERC-721 contract up and running, you may be wondering how to use Metamask (or some other wallet) with this contract. This section will walk you through how to connect Metamask to the blockchain and token contract that FireFly is using. Configure a new network . The first thing we need to do is tell Metamask how to connect to our local blockchain node. To do that: . | Click your account icon | In the drop down menu, click Settings . | On the left hand side of the page, click Networks | Click the Add a network button . | Fill in the network details: . | Network Name: FireFly (could be any name) | New RPC URL: http://127.0.0.1:5100 | Chain ID: 2021 | Currency Symbol: ETH | . | Click Save | . Import tokens . Metamask won’t know about our custom ERC-721 contract until we give it the Ethereum address for the contract, so that’s what we’ll do next. | Click on Import tokens . | Enter the Ethereum address of the contract | Enter a Token Symbol (can be anything you want) | Click Add Custom Token | . NOTE: You can find the address of your contract from the response to the request to create the token pool above. You can also do a GET to http://127.0.0.1:5000/api/v1/namespaces/default/tokens/pools to lookup your configured token pools. Transfer tokens . Now you can copy your account address from your Metamask wallet, and perform a transfer from FireFly’s API (as described above) to your Metamask address. After a couple seconds, you should see your token show up in your Metamask wallet. NOTE: While the NFT token balance can be viewed in Metamask, it does not appear that Metamask supports sending these tokens to another address at this time. ", "url": "/firefly/head/tutorials/tokens/erc721.html#use-metamask", "relUrl": "/tutorials/tokens/erc721.html#use-metamask" - },"394": { + },"398": { "doc": "ERC-721", "title": "ERC-721", "content": " ", "url": "/firefly/head/tutorials/tokens/erc721.html", "relUrl": "/tutorials/tokens/erc721.html" - },"395": { + },"399": { "doc": "Ethereum", "title": "Work with Ethereum smart contracts", "content": "This guide describes the steps to deploy a smart contract to an Ethereum blockchain and use FireFly to interact with it in order to submit transactions, query for states and listening for events. NOTE: This guide assumes that you are running a local FireFly stack with at least 2 members and an Ethereum blockchain created by the FireFly CLI. If you need help getting that set up, please see the Getting Started guide to Start your environment. ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#work-with-ethereum-smart-contracts", "relUrl": "/tutorials/custom_contracts/ethereum.html#work-with-ethereum-smart-contracts" - },"396": { + },"400": { "doc": "Ethereum", "title": "Table of contents", "content": ". | Work with Ethereum smart contracts . | Example smart contract | Contract deployment . | Request | Response | . | The FireFly Interface Format . | Request | Response | . | Broadcast the contract interface . | Request | Response | . | Create an HTTP API for the contract . | Request | Response | . | View OpenAPI spec for the contract | Invoke the smart contract . | Request | Response | . | Query the current value . | Request | Response | . | Passing additional options with a request . | Request | Response | . | Create a blockchain event listener . | Request | Response | Querying listener status . | Request / Response | . | . | Subscribe to events from our contract . | Request | Response | . | Receive custom smart contract events . | WebSocket event | Subscription offset | . | Appendix I: Work with a custom contract without creating a named API . | Request | Response | . | Appendix II: Work directly with contracts with inline requests . | Request | Response | . | . | . ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#table-of-contents", "relUrl": "/tutorials/custom_contracts/ethereum.html#table-of-contents" - },"397": { + },"401": { "doc": "Ethereum", "title": "Example smart contract", "content": "For this tutorial, we will be using a well known, but slightly modified smart contract called SimpleStorage, and will be using this contract on an Ethereum blockchain. As the name implies, it’s a very simple contract which stores an unsigned 256 bit integer, emits and event when the value is updated, and allows you to retrieve the current value. Here is the source for this contract: . // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.10; // Declares a new contract contract SimpleStorage { // Storage. Persists in between transactions uint256 x; // Allows the unsigned integer stored to be changed function set(uint256 newValue) public { x = newValue; emit Changed(msg.sender, newValue); } // Returns the currently stored unsigned integer function get() public view returns (uint256) { return x; } event Changed(address indexed from, uint256 value); } . ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#example-smart-contract", "relUrl": "/tutorials/custom_contracts/ethereum.html#example-smart-contract" - },"398": { + },"402": { "doc": "Ethereum", "title": "Contract deployment", "content": "If you need to deploy an Ethereum smart contract with a signing key that FireFly will use for submitting future transactions it is recommended to use FireFly’s built in contract deployment API. This is useful in many cases. For example, you may want to deploy a token contract and have FireFly mint some tokens. Many token contracts only allow the contract deployer to mint, so the contract would need to be deployed with a FireFly signing key. You will need compile the contract yourself using solc or some other tool. After you have compiled the contract, look in the JSON output file for the fields to build the request below. Request . | Field | Description | . | key | The signing key to use to dpeloy the contract. If omitted, the namespaces’s default signing key will be used. | . | contract | The compiled bytecode for your smart contract. It should be either a hex encded string or Base64. | . | definition | The full ABI JSON array from your compiled JSON file. Copy the entire value of the abi field from the [ to the ]. | . | input | An ordered list of constructor arguments. Some contracts may not require any (such as this example). | . POST http://localhost:5000/api/v1/namespaces/default/contracts/deploy . { \"contract\": \"608060405234801561001057600080fd5b5061019e806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806360fe47b11461003b5780636d4ce63c14610057575b600080fd5b61005560048036038101906100509190610111565b610075565b005b61005f6100cd565b60405161006c919061014d565b60405180910390f35b806000819055503373ffffffffffffffffffffffffffffffffffffffff167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af5946826040516100c2919061014d565b60405180910390a250565b60008054905090565b600080fd5b6000819050919050565b6100ee816100db565b81146100f957600080fd5b50565b60008135905061010b816100e5565b92915050565b600060208284031215610127576101266100d6565b5b6000610135848285016100fc565b91505092915050565b610147816100db565b82525050565b6000602082019050610162600083018461013e565b9291505056fea2646970667358221220e6cbd7725b98b234d07bc1823b60ac065b567c6645d15c8f8f6986e5fa5317c664736f6c634300080b0033\", \"definition\": [ { \"anonymous\": false, \"inputs\": [ { \"indexed\": true, \"internalType\": \"address\", \"name\": \"from\", \"type\": \"address\" }, { \"indexed\": false, \"internalType\": \"uint256\", \"name\": \"value\", \"type\": \"uint256\" } ], \"name\": \"Changed\", \"type\": \"event\" }, { \"inputs\": [], \"name\": \"get\", \"outputs\": [ { \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" } ], \"stateMutability\": \"view\", \"type\": \"function\" }, { \"inputs\": [ { \"internalType\": \"uint256\", \"name\": \"newValue\", \"type\": \"uint256\" } ], \"name\": \"set\", \"outputs\": [], \"stateMutability\": \"nonpayable\", \"type\": \"function\" } ], \"input\": [] } . Response . { \"id\": \"aa155a3c-2591-410e-bc9d-68ae7de34689\", \"namespace\": \"default\", \"tx\": \"4712ffb3-cc1a-4a91-aef2-206ac068ba6f\", \"type\": \"blockchain_deploy\", \"status\": \"Succeeded\", \"plugin\": \"ethereum\", \"input\": { \"contract\": \"608060405234801561001057600080fd5b5061019e806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806360fe47b11461003b5780636d4ce63c14610057575b600080fd5b61005560048036038101906100509190610111565b610075565b005b61005f6100cd565b60405161006c919061014d565b60405180910390f35b806000819055503373ffffffffffffffffffffffffffffffffffffffff167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af5946826040516100c2919061014d565b60405180910390a250565b60008054905090565b600080fd5b6000819050919050565b6100ee816100db565b81146100f957600080fd5b50565b60008135905061010b816100e5565b92915050565b600060208284031215610127576101266100d6565b5b6000610135848285016100fc565b91505092915050565b610147816100db565b82525050565b6000602082019050610162600083018461013e565b9291505056fea2646970667358221220e6cbd7725b98b234d07bc1823b60ac065b567c6645d15c8f8f6986e5fa5317c664736f6c634300080b0033\", \"definition\": [ { \"anonymous\": false, \"inputs\": [ { \"indexed\": true, \"internalType\": \"address\", \"name\": \"from\", \"type\": \"address\" }, { \"indexed\": false, \"internalType\": \"uint256\", \"name\": \"value\", \"type\": \"uint256\" } ], \"name\": \"Changed\", \"type\": \"event\" }, { \"inputs\": [], \"name\": \"get\", \"outputs\": [ { \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" } ], \"stateMutability\": \"view\", \"type\": \"function\" }, { \"inputs\": [ { \"internalType\": \"uint256\", \"name\": \"newValue\", \"type\": \"uint256\" } ], \"name\": \"set\", \"outputs\": [], \"stateMutability\": \"nonpayable\", \"type\": \"function\" } ], \"input\": [], \"key\": \"0xddd93a452bfc8d3e62bbc60c243046e4d0cb971b\", \"options\": null }, \"output\": { \"headers\": { \"requestId\": \"default:aa155a3c-2591-410e-bc9d-68ae7de34689\", \"type\": \"TransactionSuccess\" }, \"contractLocation\": { \"address\": \"0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1\" }, \"protocolId\": \"000000000024/000000\", \"transactionHash\": \"0x32d1144091877266d7f0426e48db157e7d1a857c62e6f488319bb09243f0f851\" }, \"created\": \"2023-02-03T15:42:52.750277Z\", \"updated\": \"2023-02-03T15:42:52.750277Z\" } . Here we can see in the response above under the output section that our new contract address is 0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1. This is the address that we will reference in the rest of this guide. ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#contract-deployment", "relUrl": "/tutorials/custom_contracts/ethereum.html#contract-deployment" - },"399": { + },"403": { "doc": "Ethereum", "title": "The FireFly Interface Format", "content": "If you have an Ethereum ABI for an existing smart contract, there is an HTTP endpoint on the FireFly API that will take the ABI as input and automatically generate the FireFly Interface for you. Rather than handcrafting our FFI, we’ll let FireFly generate it for us using that endpoint now. Request . Here we will take the JSON ABI generated by truffle or solc and POST that to FireFly to have it automatically generate the FireFly Interface for us. Copy the abi from the compiled JSON file, and put that inside an input object like the example below: . POST http://localhost:5000/api/v1/namespaces/default/contracts/interfaces/generate . { \"input\": { \"abi\": [ { \"anonymous\": false, \"inputs\": [ { \"indexed\": true, \"internalType\": \"address\", \"name\": \"from\", \"type\": \"address\" }, { \"indexed\": false, \"internalType\": \"uint256\", \"name\": \"value\", \"type\": \"uint256\" } ], \"name\": \"Changed\", \"type\": \"event\" }, { \"inputs\": [], \"name\": \"get\", \"outputs\": [ { \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" } ], \"stateMutability\": \"view\", \"type\": \"function\" }, { \"inputs\": [ { \"internalType\": \"uint256\", \"name\": \"newValue\", \"type\": \"uint256\" } ], \"name\": \"set\", \"outputs\": [], \"stateMutability\": \"nonpayable\", \"type\": \"function\" } ] } } . Response . FireFly generates and returns the the full FireFly Interface for the SimpleStorage contract in the response body: . { \"namespace\": \"default\", \"name\": \"\", \"description\": \"\", \"version\": \"\", \"methods\": [ { \"name\": \"get\", \"pathname\": \"\", \"description\": \"\", \"params\": [], \"returns\": [ { \"name\": \"\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ] }, { \"name\": \"set\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"newValue\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ], \"returns\": [] } ], \"events\": [ { \"name\": \"Changed\", \"description\": \"\", \"params\": [ { \"name\": \"from\", \"schema\": { \"type\": \"string\", \"details\": { \"type\": \"address\", \"internalType\": \"address\", \"indexed\": true } } }, { \"name\": \"value\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ] } ] } . ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#the-firefly-interface-format", "relUrl": "/tutorials/custom_contracts/ethereum.html#the-firefly-interface-format" - },"400": { + },"404": { "doc": "Ethereum", "title": "Broadcast the contract interface", "content": "Now that we have a FireFly Interface representation of our smart contract, we want to broadcast that to the entire network. This broadcast will be pinned to the blockchain, so we can always refer to this specific name and version, and everyone in the network will know exactly which contract interface we are talking about. We will take the output from the previous HTTP response above, fill in the name and version and then POST that to the /contracts/interfaces API endpoint. Request . POST http://localhost:5000/api/v1/namespaces/default/contracts/interfaces . { \"namespace\": \"default\", \"name\": \"SimpleStorage\", \"version\": \"v1.0.0\", \"description\": \"\", \"methods\": [ { \"name\": \"get\", \"pathname\": \"\", \"description\": \"\", \"params\": [], \"returns\": [ { \"name\": \"\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ] }, { \"name\": \"set\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"newValue\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ], \"returns\": [] } ], \"events\": [ { \"name\": \"Changed\", \"description\": \"\", \"params\": [ { \"name\": \"from\", \"schema\": { \"type\": \"string\", \"details\": { \"type\": \"address\", \"internalType\": \"address\", \"indexed\": true } } }, { \"name\": \"value\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ] } ] } . Response . { \"id\": \"8bdd27a5-67c1-4960-8d1e-7aa31b9084d3\", \"message\": \"3cd0dde2-1e39-4c9e-a4a1-569e87cca93a\", \"namespace\": \"default\", \"name\": \"SimpleStorage\", \"description\": \"\", \"version\": \"v1.0.0\", \"methods\": [ { \"id\": \"56467890-5713-4463-84b8-4537fcb63d8b\", \"contract\": \"8bdd27a5-67c1-4960-8d1e-7aa31b9084d3\", \"name\": \"get\", \"namespace\": \"default\", \"pathname\": \"get\", \"description\": \"\", \"params\": [], \"returns\": [ { \"name\": \"\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ] }, { \"id\": \"6b254d1d-5f5f-491e-bbd2-201e96892e1a\", \"contract\": \"8bdd27a5-67c1-4960-8d1e-7aa31b9084d3\", \"name\": \"set\", \"namespace\": \"default\", \"pathname\": \"set\", \"description\": \"\", \"params\": [ { \"name\": \"newValue\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ], \"returns\": [] } ], \"events\": [ { \"id\": \"aa1fe67b-b2ac-41af-a7e7-7ad54a30a78d\", \"contract\": \"8bdd27a5-67c1-4960-8d1e-7aa31b9084d3\", \"namespace\": \"default\", \"pathname\": \"Changed\", \"name\": \"Changed\", \"description\": \"\", \"params\": [ { \"name\": \"from\", \"schema\": { \"type\": \"string\", \"details\": { \"type\": \"address\", \"internalType\": \"address\", \"indexed\": true } } }, { \"name\": \"value\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ] } ] } . ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#broadcast-the-contract-interface", "relUrl": "/tutorials/custom_contracts/ethereum.html#broadcast-the-contract-interface" - },"401": { + },"405": { "doc": "Ethereum", "title": "Create an HTTP API for the contract", "content": "Now comes the fun part where we see some of the powerful, developer-friendly features of FireFly. The next thing we’re going to do is tell FireFly to build an HTTP API for this smart contract, complete with an OpenAPI Specification and Swagger UI. As part of this, we’ll also tell FireFly where the contract is on the blockchain. Like the interface broadcast above, this will also generate a broadcast which will be pinned to the blockchain so all the members of the network will be aware of and able to interact with this API. We need to copy the id field we got in the response from the previous step to the interface.id field in the request body below. We will also pick a name that will be part of the URL for our HTTP API, so be sure to pick a name that is URL friendly. In this case we’ll call it simple-storage. Lastly, in the location.address field, we’re telling FireFly where an instance of the contract is deployed on-chain. NOTE: The location field is optional here, but if it is omitted, it will be required in every request to invoke or query the contract. This can be useful if you have multiple instances of the same contract deployed to different addresses. Request . POST http://localhost:5000/api/v1/namespaces/default/apis . { \"name\": \"simple-storage\", \"interface\": { \"id\": \"8bdd27a5-67c1-4960-8d1e-7aa31b9084d3\" }, \"location\": { \"address\": \"0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1\" } } . Response . { \"id\": \"9a681ec6-1dee-42a0-b91b-61d23a814b0f\", \"namespace\": \"default\", \"interface\": { \"id\": \"8bdd27a5-67c1-4960-8d1e-7aa31b9084d3\" }, \"location\": { \"address\": \"0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1\" }, \"name\": \"simple-storage\", \"message\": \"d90d0386-8874-43fb-b7d3-485c22f35f47\", \"urls\": { \"openapi\": \"http://127.0.0.1:5000/api/v1/namespaces/default/apis/simple-storage/api/swagger.json\", \"ui\": \"http://127.0.0.1:5000/api/v1/namespaces/default/apis/simple-storage/api\" } } . ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#create-an-http-api-for-the-contract", "relUrl": "/tutorials/custom_contracts/ethereum.html#create-an-http-api-for-the-contract" - },"402": { + },"406": { "doc": "Ethereum", "title": "View OpenAPI spec for the contract", "content": "You’ll notice in the response body that there are a couple of URLs near the bottom. If you navigate to the one labeled ui in your browser, you should see the Swagger UI for your smart contract. ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#view-openapi-spec-for-the-contract", "relUrl": "/tutorials/custom_contracts/ethereum.html#view-openapi-spec-for-the-contract" - },"403": { + },"407": { "doc": "Ethereum", "title": "Invoke the smart contract", "content": "Now that we’ve got everything set up, it’s time to use our smart contract! We’re going to make a POST request to the invoke/set endpoint to set the integer value on-chain. Let’s set it to the value of 3 right now. Request . POST http://localhost:5000/api/v1/namespaces/default/apis/simple-storage/invoke/set . { \"input\": { \"newValue\": 3 } } . Response . { \"id\": \"41c67c63-52cf-47ce-8a59-895fe2ffdc86\" } . You’ll notice that we just get an ID back here, and that’s expected due to the asynchronous programming model of working with smart contracts in FireFly. To see what the value is now, we can query the smart contract. In a little bit, we’ll also subscribe to the events emitted by this contract so we can know when the value is updated in realtime. ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#invoke-the-smart-contract", "relUrl": "/tutorials/custom_contracts/ethereum.html#invoke-the-smart-contract" - },"404": { + },"408": { "doc": "Ethereum", "title": "Query the current value", "content": "To make a read-only request to the blockchain to check the current value of the stored integer, we can make a POST to the query/get endpoint. Request . POST http://localhost:5000/api/v1/namespaces/default/apis/simple-storage/query/get . {} . Response . { \"output\": \"3\" } . NOTE: Some contracts may have queries that require input parameters. That’s why the query endpoint is a POST, rather than a GET so that parameters can be passed as JSON in the request body. This particular function does not have any parameters, so we just pass an empty JSON object. ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#query-the-current-value", "relUrl": "/tutorials/custom_contracts/ethereum.html#query-the-current-value" - },"405": { + },"409": { "doc": "Ethereum", "title": "Passing additional options with a request", "content": "Some smart contract functions may accept or require additional options to be passed with the request. For example, a Solidity function might be payable, meaning that a value field must be specified, indicating an amount of ETH to be transferred with the request. Each of your smart contract API’s /invoke or /query endpoints support an options object in addition to the input arguments for the function itself. Here is an example of sending 100 wei with a transaction: . Request . POST http://localhost:5000/api/v1/namespaces/default/apis/simple-storage/invoke/set . { \"input\": { \"newValue\": 3 }, \"options\": { \"value\": 100 } } . Response . { \"id\": \"41c67c63-52cf-47ce-8a59-895fe2ffdc86\" } . ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#passing-additional-options-with-a-request", "relUrl": "/tutorials/custom_contracts/ethereum.html#passing-additional-options-with-a-request" - },"406": { + },"410": { "doc": "Ethereum", "title": "Create a blockchain event listener", "content": "Now that we’ve seen how to submit transactions and preform read-only queries to the blockchain, let’s look at how to receive blockchain events so we know when things are happening in realtime. If you look at the source code for the smart contract we’re working with above, you’ll notice that it emits an event when the stored value of the integer is set. In order to receive these events, we first need to instruct FireFly to listen for this specific type of blockchain event. To do this, we create an Event Listener. The /contracts/listeners endpoint is RESTful so there are POST, GET, and DELETE methods available on it. To create a new listener, we will make a POST request. We are going to tell FireFly to listen to events with name \"Changed\" from the FireFly Interface we defined earlier, referenced by its ID. We will also tell FireFly which contract address we expect to emit these events, and the topic to assign these events to. Topics are a way for applications to subscribe to events they are interested in. Request . POST http://localhost:5000/api/v1/namespaces/default/contracts/listeners . { \"interface\": { \"id\": \"8bdd27a5-67c1-4960-8d1e-7aa31b9084d3\" }, \"location\": { \"address\": \"0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1\" }, \"eventPath\": \"Changed\", \"options\": { \"firstEvent\": \"newest\" }, \"topic\": \"simple-storage\" } . Response . { \"id\": \"1bfa3b0f-3d90-403e-94a4-af978d8c5b14\", \"interface\": { \"id\": \"8bdd27a5-67c1-4960-8d1e-7aa31b9084d3\" }, \"namespace\": \"default\", \"name\": \"sb-66209ffc-d355-4ac0-7151-bc82490ca9df\", \"protocolId\": \"sb-66209ffc-d355-4ac0-7151-bc82490ca9df\", \"location\": { \"address\": \"0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1\" }, \"created\": \"2022-02-17T22:02:36.34549538Z\", \"event\": { \"name\": \"Changed\", \"description\": \"\", \"params\": [ { \"name\": \"from\", \"schema\": { \"type\": \"string\", \"details\": { \"type\": \"address\", \"internalType\": \"address\", \"indexed\": true } } }, { \"name\": \"value\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ] }, \"options\": { \"firstEvent\": \"oldest\" } } . We can see in the response, that FireFly pulls all the schema information from the FireFly Interface that we broadcasted earlier and creates the listener with that schema. This is useful so that we don’t have to enter all of that data again. Querying listener status . If you are interested in learning about the current state of a listener you have created, you can query with the fetchstatus parameter. For FireFly stacks with an EVM compatible blockchain connector, the response will include checkpoint information and if the listener is currently in catchup mode. Request / Response . GET http://localhost:5000/api/v1/namespaces/default/contracts/listeners/1bfa3b0f-3d90-403e-94a4-af978d8c5b14?fetchstatus . { \"id\": \"1bfa3b0f-3d90-403e-94a4-af978d8c5b14\", \"interface\": { \"id\": \"8bdd27a5-67c1-4960-8d1e-7aa31b9084d3\" }, \"namespace\": \"default\", \"name\": \"sb-66209ffc-d355-4ac0-7151-bc82490ca9df\", \"protocolId\": \"sb-66209ffc-d355-4ac0-7151-bc82490ca9df\", \"location\": { \"address\": \"0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1\" }, \"created\": \"2022-02-17T22:02:36.34549538Z\", \"event\": { \"name\": \"Changed\", \"description\": \"\", \"params\": [ { \"name\": \"from\", \"schema\": { \"type\": \"string\", \"details\": { \"type\": \"address\", \"internalType\": \"address\", \"indexed\": true } } }, { \"name\": \"value\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ] }, \"status\": { \"checkpoint\": { \"block\": 0, \"transactionIndex\": -1, \"logIndex\": -1 }, \"catchup\": true }, \"options\": { \"firstEvent\": \"oldest\" } } . ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#create-a-blockchain-event-listener", "relUrl": "/tutorials/custom_contracts/ethereum.html#create-a-blockchain-event-listener" - },"407": { + },"411": { "doc": "Ethereum", "title": "Subscribe to events from our contract", "content": "Now that we’ve told FireFly that it should listen for specific events on the blockchain, we can set up a Subscription for FireFly to send events to our app. To set up our subscription, we will make a POST to the /subscriptions endpoint. We will set a friendly name simple-storage to identify the Subscription when we are connecting to it in the next step. We’re also going to set up a filter to only send events blockchain events from our listener that we created in the previous step. To do that, we’ll copy the listener ID from the step above (1bfa3b0f-3d90-403e-94a4-af978d8c5b14) and set that as the value of the listener field in the example below: . Request . POST http://localhost:5000/api/v1/namespaces/default/subscriptions . { \"namespace\": \"default\", \"name\": \"simple-storage\", \"transport\": \"websockets\", \"filter\": { \"events\": \"blockchain_event_received\", \"blockchainevent\": { \"listener\": \"1bfa3b0f-3d90-403e-94a4-af978d8c5b14\" } }, \"options\": { \"firstEvent\": \"oldest\" } } . Response . { \"id\": \"f826269c-65ed-4634-b24c-4f399ec53a32\", \"namespace\": \"default\", \"name\": \"simple-storage\", \"transport\": \"websockets\", \"filter\": { \"events\": \"blockchain_event_received\", \"message\": {}, \"transaction\": {}, \"blockchainevent\": { \"listener\": \"1bfa3b0f-3d90-403e-94a4-af978d8c5b14\" } }, \"options\": { \"firstEvent\": \"-1\", \"withData\": false }, \"created\": \"2022-03-15T17:35:30.131698921Z\", \"updated\": null } . ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#subscribe-to-events-from-our-contract", "relUrl": "/tutorials/custom_contracts/ethereum.html#subscribe-to-events-from-our-contract" - },"408": { + },"412": { "doc": "Ethereum", "title": "Receive custom smart contract events", "content": "The last step is to connect a WebSocket client to FireFly to receive the event. You can use any WebSocket client you like, such as Postman or a command line app like websocat. Connect your WebSocket client to ws://localhost:5000/ws. After connecting the WebSocket client, send a message to tell FireFly to: . | Start sending events | For the Subscription named simple-storage | On the default namespace | Automatically “ack” each event which will let FireFly immediately send the next event when available | . { \"type\": \"start\", \"name\": \"simple-storage\", \"namespace\": \"default\", \"autoack\": true } . WebSocket event . After creating the subscription, you should see an event arrive on the connected WebSocket client that looks something like this: . { \"id\": \"0f4a31d6-9743-4537-82df-5a9c76ccbd1e\", \"sequence\": 24, \"type\": \"blockchain_event_received\", \"namespace\": \"default\", \"reference\": \"dd3e1554-c832-47a8-898e-f1ee406bea41\", \"created\": \"2022-03-15T17:32:27.824417878Z\", \"blockchainevent\": { \"id\": \"dd3e1554-c832-47a8-898e-f1ee406bea41\", \"sequence\": 7, \"source\": \"ethereum\", \"namespace\": \"default\", \"name\": \"Changed\", \"listener\": \"1bfa3b0f-3d90-403e-94a4-af978d8c5b14\", \"protocolId\": \"000000000010/000000/000000\", \"output\": { \"from\": \"0xb7e6a5eb07a75a2c81801a157192a82bcbce0f21\", \"value\": \"3\" }, \"info\": { \"address\": \"0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1\", \"blockNumber\": \"10\", \"logIndex\": \"0\", \"signature\": \"Changed(address,uint256)\", \"subId\": \"sb-724b8416-786d-4e67-4cd3-5bae4a26eb0e\", \"timestamp\": \"1647365460\", \"transactionHash\": \"0xd5b5c716554097b2868d8705241bb2189bb76d16300f702ad05b0b02fccc4afb\", \"transactionIndex\": \"0x0\" }, \"timestamp\": \"2022-03-15T17:31:00Z\", \"tx\": { \"type\": \"\" } }, \"subscription\": { \"id\": \"f826269c-65ed-4634-b24c-4f399ec53a32\", \"namespace\": \"default\", \"name\": \"simple-storage\" } } . You can see in the event received over the WebSocket connection, the blockchain event that was emitted from our first transaction, which happened in the past. We received this event, because when we set up both the Listener, and the Subscription, we specified the \"firstEvent\" as \"oldest\". This tells FireFly to look for this event from the beginning of the blockchain, and that your app is interested in FireFly events since the beginning of FireFly’s event history. In the event, we can also see the blockchainevent itself, which has an output object. These are the params in our FireFly Interface, and the actual output of the event. Here we can see the value is 3 which is what we set the integer to in our original transaction. Subscription offset . If you query by the ID of your subscription with the fetchstatus parameter, you can see its current offset. GET http://localhost:5000/api/v1/namespaces/default/subscriptions/f826269c-65ed-4634-b24c-4f399ec53a32 . { \"id\": \"f826269c-65ed-4634-b24c-4f399ec53a32\", \"namespace\": \"default\", \"name\": \"simple-storage\", \"transport\": \"websockets\", \"filter\": { \"events\": \"blockchain_event_received\", \"message\": {}, \"transaction\": {}, \"blockchainevent\": { \"listener\": \"1bfa3b0f-3d90-403e-94a4-af978d8c5b14\" } }, \"options\": { \"firstEvent\": \"-1\", \"withData\": false }, \"status\": { \"offset\": 20 } \"created\": \"2022-03-15T17:35:30.131698921Z\", \"updated\": null } . You’ve reached the end of the main guide to working with custom smart contracts in FireFly. Hopefully this was helpful and gives you what you need to get up and running with your own contracts. There are several additional ways to invoke or query smart contracts detailed below, so feel free to keep reading if you’re curious. ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#receive-custom-smart-contract-events", "relUrl": "/tutorials/custom_contracts/ethereum.html#receive-custom-smart-contract-events" - },"409": { + },"413": { "doc": "Ethereum", "title": "Appendix I: Work with a custom contract without creating a named API", "content": "FireFly aims to offer a developer-friendly and flexible approach to using custom smart contracts. The guide above has detailed the most robust and feature-rich way to use custom contracts with FireFly, but there are several alternative API usage patterns available as well. It is possible to broadcast a contract interface and use a smart contract that implements that interface without also broadcasting a named API as above. There are several key differences (which may or may not be desirable) compared to the method outlined in the full guide above: . | OpenAPI Spec and Swagger UI are not available | Each HTTP request to invoke/query the contract will need to include the contract location | The contract location will not have been broadcasted to all other members of the network | The URL to invoke/query the contract will be different (described below) | . Request . POST http://localhost:5000/api/v1/namespaces/default/contracts/interfaces/8bdd27a5-67c1-4960-8d1e-7aa31b9084d3/invoke/set . { \"location\": { \"address\": \"0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1\" }, \"input\": { \"newValue\": 7 } } . Response . { \"id\": \"f310fa4a-73d8-4777-9f9d-dfa5012a052f\" } . All of the same invoke, query, and subscribe endpoints are available on the contract interface itself. ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#appendix-i-work-with-a-custom-contract-without-creating-a-named-api", "relUrl": "/tutorials/custom_contracts/ethereum.html#appendix-i-work-with-a-custom-contract-without-creating-a-named-api" - },"410": { + },"414": { "doc": "Ethereum", "title": "Appendix II: Work directly with contracts with inline requests", "content": "The final way of working with custom smart contracts with FireFly is to just put everything FireFly needs all in one request, each time a contract is invoked or queried. This is the most lightweight, but least feature-rich way of using a custom contract. To do this, we will need to put both the contract location, and a subset of the FireFly Interface that describes the method we want to invoke in the request body, in addition to the function input. Request . POST http://localhost:5000/api/v1/namespaces/default/contracts/invoke . { \"location\": { \"address\": \"0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1\" }, \"method\": { \"name\": \"set\", \"params\": [ { \"name\": \"x\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\" } } } ], \"returns\": [] }, \"input\": { \"x\": 42 } } . Response . { \"id\": \"386d3e23-e4bc-4a9b-bc1f-452f0a8c9ae5\" } . ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html#appendix-ii-work-directly-with-contracts-with-inline-requests", "relUrl": "/tutorials/custom_contracts/ethereum.html#appendix-ii-work-directly-with-contracts-with-inline-requests" - },"411": { + },"415": { "doc": "Ethereum", "title": "Ethereum", "content": " ", "url": "/firefly/head/tutorials/custom_contracts/ethereum.html", "relUrl": "/tutorials/custom_contracts/ethereum.html" - },"412": { + },"416": { "doc": "Event", "title": "Event", "content": " ", "url": "/firefly/head/reference/types/event.html", "relUrl": "/reference/types/event.html" - },"413": { + },"417": { "doc": "Event", "title": "Table of contents", "content": ". | Event . | Sequence | Reference | Correlator | Topic | Transaction | Reference, Topic and Correlator by Event Type | Example | Field Descriptions | . | . ", "url": "/firefly/head/reference/types/event.html#table-of-contents", "relUrl": "/reference/types/event.html#table-of-contents" - },"414": { + },"418": { "doc": "Event", "title": "Event", "content": "Every Event emitted by FireFly shares a common structure. See Events for a reference for how the overall event bus in Hyperledger FireFly operates, and descriptions of all the sub-categories of events. Sequence . A local sequence number is assigned to each event, and you can use an API to query events using this sequence number in exactly the same order that they are delivered to your application. Reference . Events have a reference to the UUID of an object that is the subject of the event, such as a detailed Blockchain Event, or an off-chain Message. When events are delivered to your application, the reference field is automatically retrieved and included in the JSON payload that is delivered to your application. You can use the ?fetchreferences query parameter on API calls to request the same in-line JSON payload be included in query results. The type of the reference also determines what subscription filters apply when performing server-side filters. Here is the mapping between event types, and the object that you find in the reference field. Correlator . For some event types, there is a secondary reference to an object that is associated with the event. This is set in a correlator field on the Event, but is not automatically fetched. This field is primarily used for the confirm option on API calls to allow FireFly to determine when a request has succeeded/failed. Topic . Events have a topic, and how that topic is determined is specific to the type of event. This is intended to be a property you would use to filter events to your application, or query all historical events associated with a given business data stream. For example when you send a Message, you set the topics you want that message to apply to, and FireFly ensures a consistent global order between all parties that receive that message. Transaction . When actions are submitted by a FireFly node, they are performed within a FireFly Transaction. The events that occur as a direct result of that transaction, are tagged with the transaction ID so that they can be grouped together. This construct is a distinct higher level construct than a Blockchain transaction, that groups together a number of operations/events that might be on-chain or off-chain. In some cases, such as unpinned off-chain data transfer, a FireFly transaction can exist when there is no blockchain transaction at all. Wherever possible you will find that FireFly tags the FireFly transaction with any associated Blockchain transaction(s). Note that some events cannot be tagged with a Transaction ID: . | Blockchain events, unless they were part of a batch-pin transaction for transfer of a message | Token transfers/approvals, unless they had a message transfer associated with them (and included a data payload in the event they emitted) | . Reference, Topic and Correlator by Event Type . | Types | Reference | Topic | Correlator | . | transaction_submitted | Transaction | transaction.type |   | . | message_confirmedmessage_rejected | Message | message.header.topics[i]* | message.header.cid | . | token_pool_confirmed | TokenPool | tokenPool.id |   | . | token_pool_op_failed | Operation | tokenPool.id | tokenPool.id | . | token_transfer_confirmed | TokenTransfer | tokenPool.id |   | . | token_transfer_op_failed | Operation | tokenPool.id | tokenTransfer.localId | . | token_approval_confirmed | TokenApproval | tokenPool.id |   | . | token_approval_op_failed | Operation | tokenPool.id | tokenApproval.localId | . | namespace_confirmed | Namespace | \"ff_definition\" |   | . | datatype_confirmed | Datatype | \"ff_definition\" |   | . | identity_confirmedidentity_updated | Identity | \"ff_definition\" |   | . | contract_interface_confirmed | FFI | \"ff_definition\" |   | . | contract_api_confirmed | ContractAPI | \"ff_definition\" |   | . | blockchain_event_received | BlockchainEvent | From listener ** |   | . | blockchain_invoke_op_succeeded | Operation |   |   | . | blockchain_invoke_op_failed | Operation |   |   | . | blockchain_contract_deploy_op_succeeded | Operation |   |   | . | blockchain_contract_deploy_op_failed | Operation |   |   | . | A separate event is emitted for each topic associated with a Message. | . ** The topic for a blockchain event is inherited from the blockchain listener, allowing you to create multiple blockchain listeners that all deliver messages to your application on a single FireFly topic. Example . { \"id\": \"5f875824-b36b-4559-9791-a57a2e2b30dd\", \"sequence\": 168, \"type\": \"transaction_submitted\", \"namespace\": \"ns1\", \"reference\": \"0d12aa75-5ed8-48a7-8b54-45274c6edcb1\", \"tx\": \"0d12aa75-5ed8-48a7-8b54-45274c6edcb1\", \"topic\": \"batch_pin\", \"created\": \"2022-05-16T01:23:15Z\" } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID assigned to this event by your local FireFly node | UUID | . | sequence | 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) | int64 | . | type | 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 | FFEnum:\"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\" | . | namespace | The namespace of the event. Your application must subscribe to events within a namespace | string | . | reference | 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 | UUID | . | correlator | 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 | UUID | . | tx | The UUID of a transaction that is event is part of. Not all events are part of a transaction | UUID | . | topic | 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 | string | . | created | 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 | FFTime | . ", "url": "/firefly/head/reference/types/event.html", "relUrl": "/reference/types/event.html" - },"415": { + },"419": { "doc": "Listen for events", "title": "Listen for events", "content": " ", "url": "/firefly/head/tutorials/events.html", "relUrl": "/tutorials/events.html" - },"416": { + },"420": { "doc": "Listen for events", "title": "Table of contents", "content": ". | Quick reference | Additional info | WebSockets Example 1: Ephemeral subscription with auto-commit | Example event payload | Download the message and data | Download just the data array associated with a message | WebSockets Example 2: Durable subscription for your application, with manual-commit . | Set up the WebSocket subscription | Connect to consume messages | . | Custom Contract Events | . ", "url": "/firefly/head/tutorials/events.html#table-of-contents", "relUrl": "/tutorials/events.html#table-of-contents" - },"417": { + },"421": { "doc": "Listen for events", "title": "Quick reference", "content": "Probably the most important aspect of FireFly is that it is an event-driven programming model. Parties interact by sending messages and transactions to each other, on and off chain. Once aggregated and confirmed those events drive processing in the other party. This allows orchestration of complex multi-party system applications and business processes. FireFly provides each party with their own private history, that includes all exchanges outbound and inbound performed through the node into the multi-party system. That includes blockchain backed transactions, as well as completely off-chain message exchanges. The event transports are pluggable. The core transports are WebSockets and Webhooks. We focus on WebSockets in this getting started guide. Check out the Request/Reply section for more information on Webhooks . ", "url": "/firefly/head/tutorials/events.html#quick-reference", "relUrl": "/tutorials/events.html#quick-reference" - },"418": { + },"422": { "doc": "Listen for events", "title": "Additional info", "content": ". | Key Concepts: Multi-party process flow | Reference: coming soon | . ", "url": "/firefly/head/tutorials/events.html#additional-info", "relUrl": "/tutorials/events.html#additional-info" - },"419": { + },"423": { "doc": "Listen for events", "title": "WebSockets Example 1: Ephemeral subscription with auto-commit", "content": "The simplest way to get started consuming events, is with an ephemeral WebSocket listener. Example connection URL: . ws://localhost:5000/ws?namespace=default&ephemeral&autoack&filter.events=message_confirmed . | namespace=default - event listeners are scoped to a namespace | ephemeral - listen for events that occur while this connection is active, but do not remember the app instance (great for UIs) | autoack- automatically acknowledge each event, so the next event is sent (great for UIs) | filter.events=message_confirmed - only listen for events resulting from a message confirmation | . There are a number of browser extensions that let you experiment with WebSockets: . ", "url": "/firefly/head/tutorials/events.html#websockets-example-1-ephemeral-subscription-with-auto-commit", "relUrl": "/tutorials/events.html#websockets-example-1-ephemeral-subscription-with-auto-commit" - },"420": { + },"424": { "doc": "Listen for events", "title": "Example event payload", "content": "The events (by default) do not contain the payload data, just the event and referred message. This means the WebSocket payloads are a predictably small size, and the application can use the information in the message to post-filter the event to decide if it needs to download the full data. There are server-side filters provided on events as well . { \"id\": \"8f0da4d7-8af7-48da-912d-187979bf60ed\", \"sequence\": 61, \"type\": \"message_confirmed\", \"namespace\": \"default\", \"reference\": \"9710a350-0ba1-43c6-90fc-352131ce818a\", \"created\": \"2021-07-02T04:37:47.6556589Z\", \"subscription\": { \"id\": \"2426c5b1-ffa9-4f7d-affb-e4e541945808\", \"namespace\": \"default\", \"name\": \"2426c5b1-ffa9-4f7d-affb-e4e541945808\" }, \"message\": { \"header\": { \"id\": \"9710a350-0ba1-43c6-90fc-352131ce818a\", \"type\": \"broadcast\", \"txtype\": \"batch_pin\", \"author\": \"0x1d14b65d2dd5c13f6cb6d3dc4aa13c795a8f3b28\", \"created\": \"2021-07-02T04:37:40.1257944Z\", \"namespace\": \"default\", \"topic\": [ \"default\" ], \"datahash\": \"cd6a09a15ccd3e6ed1d67d69fa4773b563f27f17f3eaad611a2792ba945ca34f\" }, \"hash\": \"1b6808d2b95b418e54e7bd34593bfa36a002b841ac42f89d00586dac61e8df43\", \"batchID\": \"16ffc02c-8cb0-4e2f-8b58-a707ad1d1eae\", \"state\": \"confirmed\", \"confirmed\": \"2021-07-02T04:37:47.6548399Z\", \"data\": [ { \"id\": \"b3a814cc-17d1-45d5-975e-90279ed2c3fc\", \"hash\": \"9ddefe4435b21d901439e546d54a14a175a3493b9fd8fbf38d9ea6d3cbf70826\" } ] } } . ", "url": "/firefly/head/tutorials/events.html#example-event-payload", "relUrl": "/tutorials/events.html#example-event-payload" - },"421": { + },"425": { "doc": "Listen for events", "title": "Download the message and data", "content": "A simple REST API is provided to allow you to download the data associated with the message: . GET /api/v1/namespaces/default/messages/{id}?data=true . ", "url": "/firefly/head/tutorials/events.html#download-the-message-and-data", "relUrl": "/tutorials/events.html#download-the-message-and-data" - },"422": { + },"426": { "doc": "Listen for events", "title": "Download just the data array associated with a message", "content": "As you already have the message object in the event delivery, you can query just the array of data objects as follows: . GET /api/v1/namespaces/default/messages/{id}/data . ", "url": "/firefly/head/tutorials/events.html#download-just-the-data-array-associated-with-a-message", "relUrl": "/tutorials/events.html#download-just-the-data-array-associated-with-a-message" - },"423": { + },"427": { "doc": "Listen for events", "title": "WebSockets Example 2: Durable subscription for your application, with manual-commit", "content": "To reliably process messages within your application, you should first set up a subscription. A subscription requests that: . | FireFly keeps a record of the latest event consumed by that application | FireFly only delivers one copy of the event to the application, even when there are multiple active connections | . This should be combined with manual acknowledgment of the events, where the application sends a payload such as the following in response to each event it receives (where the id comes from the event it received): . { \"type\": \"ack\", \"id\": \"617db63-2cf5-4fa3-8320-46150cbb5372\" } . You must send an acknowledgement for every message, or you will stop receiving messages. Set up the WebSocket subscription . Each subscription is scoped to a namespace, and must have a name. You can then choose to perform server-side filtering on the events using regular expressions matched against the information in the event. POST /namespaces/default/subscriptions . { \"transport\": \"websockets\", \"name\": \"app1\", \"filter\": { \"blockchainevent\": { \"listener\": \".*\", \"name\": \".*\" }, \"events\": \".*\", \"message\": { \"author\": \".*\", \"group\": \".*\", \"tag\": \".*\", \"topics\": \".*\" }, \"transaction\": { \"type\": \".*\" } }, \"options\": { \"firstEvent\": \"newest\", \"readAhead\": 50 } } . Connect to consume messages . Example connection URL: . ws://localhost:5000/ws?namespace=default&name=app1 . | namespace=default - event listeners are scoped to a namespace | name=app1 - the subscription name | . ", "url": "/firefly/head/tutorials/events.html#websockets-example-2-durable-subscription-for-your-application-with-manual-commit", "relUrl": "/tutorials/events.html#websockets-example-2-durable-subscription-for-your-application-with-manual-commit" - },"424": { + },"428": { "doc": "Listen for events", "title": "Custom Contract Events", "content": "If you are interested in learning more about events for custom smart contracts, please see the Working with custom smart contracts section. ", "url": "/firefly/head/tutorials/events.html#custom-contract-events", "relUrl": "/tutorials/events.html#custom-contract-events" - },"425": { + },"429": { "doc": "Event Bus", "title": "Event Bus", "content": " ", "url": "/firefly/head/reference/events.html", "relUrl": "/reference/events.html" - },"426": { + },"430": { "doc": "Event Bus", "title": "Table of contents", "content": ". | Hyperledger FireFly Event Bus | Event-Driven Application Architecture | Decentralized Event Processing . | Example 1: A fungible token balance transfer | Example 2: A step in a multi-party business process | . | Privacy groups and late join | Event Types . | Blockchain events | Token events | . | Message events: on-chain / off-chain coordinated | Transaction submission events | . ", "url": "/firefly/head/reference/events.html#table-of-contents", "relUrl": "/reference/events.html#table-of-contents" - },"427": { + },"431": { "doc": "Event Bus", "title": "Hyperledger FireFly Event Bus", "content": "The FireFly event bus provides your application with a single stream of events from all of the back-end services that plug into FireFly. Applications subscribe to these events using developer friendly protocols like WebSockets, and Webhooks. Additional transports and messaging systems like NATS, Kafka, and JMS Servers can be connected through plugins. Each application creates one or more Subscriptions to identify itself. In this subscription the application can choose to receive all events that are emitted within a namespace, or can use server-side filtering to only receive a sub-set of events. The event bus reliably keeps track of which events have been delivered to which applications, via an offset into the main event stream that is updated each time an application acknowledges receipt of events over its subscription. ", "url": "/firefly/head/reference/events.html#hyperledger-firefly-event-bus", "relUrl": "/reference/events.html#hyperledger-firefly-event-bus" - },"428": { + },"432": { "doc": "Event Bus", "title": "Event-Driven Application Architecture", "content": "Decentralized applications are built around a source of truth that is shared between multiple parties. No one party can change the state unilaterally, as their changes need to be processed in order with the other changes in the system. Each party processes requests to change shared state in the same order, against a common set of rules for what is allowed at that exact point in the processing. As a result everybody deterministically ends up with the same state at the end of the processing. This requires an event-driven programming model. You will find an event-driven model at the core of every blockchain Smart Contract technology. This event-driven approach is unavoidable regardless of how much of your business data & logic can be directly stored/processed on-chain, vs. off-chain. So Hyperledger FireFly aims to provide you with the tools to easily manage this model throughout your decentralized application stack. Your back-end application should be structured for this event-driven paradigm, with an Event Handler constantly listening for events, applying a consistent State Machine to those events and applying the changes to your Application Database. FireFly comes with a built in event processor for Token transfers & approvals, that implements this pattern to maintain balances, and transaction history in a rich query off-chain data cache. ", "url": "/firefly/head/reference/events.html#event-driven-application-architecture", "relUrl": "/reference/events.html#event-driven-application-architecture" - },"429": { + },"433": { "doc": "Event Bus", "title": "Decentralized Event Processing", "content": "In a decentralized system, you need to consider that each organization runs its own applications, and has its own private database. At any given point in time different organizations will have slightly different views of what the most up to date information is - even for the blockchain state. As well as the agreed business logic, there will be private data and core system integration that are needed to process events as they happen. Some of this data might be received privately from other parties, over a secure communications channel (not the blockchain). The system must be eventually consistent across all parties for any business data/decision that those parties need to agree on. This happens by all parties processing the same events in the same order, and by applying the same business logic (for the parts of the business logic that are agreed). This means that when processing an event, a participant must have access to enough historical data/state to reach the same conclusion as everyone else. Let’s look at a couple of examples. Example 1: A fungible token balance transfer . You need to be able to verify the complete lineage of the tokens being spent, in order to know that they cannot be double spent anywhere in the network. This means the transaction must be backed by a blockchain verifiable by all participants on the network that could hold balances of that token. You might be able to use advanced cryptography (such as zero-knowledge proofs) to mask the participants in the trade, but the transaction themselves must be verifiable to everyone in a global sequence that prevents double spending. Example 2: A step in a multi-party business process . Here it is likely you want to restrict visibility of the data to just the parties directly involved in the business process. To come to a common agreement on outcome, the parties must know they are processing the same data in the same order. So at minimum a proof (a hash of the data) needs to “pinned” to a blockchain ledger visible to all participants involved in the process. You can then choose to put more processing on the blockchain, to enforce some critical rules in the business state machine that must be executed fairly to prevent one party from cheating the system. Such as that the highest bid is chosen in a competitive bidding process, or a minimum set of parties have voted agreement before a transaction is finalized. Other steps in the process might include human decision making, private data from the core systems of one member, or proprietary business logic that one member is not willing to share. These steps are “non-deterministic” - you cannot predict the outcome, nor be guaranteed to reproduce the same outcome with the same inputs in the future. The FireFly event bus is designed to make triggering these non-deterministic steps easy, while still allowing them to be part of the overall state machine of the business process. You need to take care that the system is designed so parties cannot cheat, and must follow the rules. How much of that rule enforcement needs to be executed on-chain vs. off-chain (backed by a deterministic order through the blockchain) is different for each use case. Remember that tokens provide a great set of building blocks for on-chain steps in your decentralized applications. Enterprise NFTs allow generation of a globally unique ID, and track ownership. Fungible tokens allow value transfer, and can be extended with smart contracts that to lock/unlock funds in “digital escrow” while complex off-chain agreement happens. ", "url": "/firefly/head/reference/events.html#decentralized-event-processing", "relUrl": "/reference/events.html#decentralized-event-processing" - },"430": { + },"434": { "doc": "Event Bus", "title": "Privacy groups and late join", "content": "If a new participant needs to join into a business transaction that has already started, they must first “catch up” with the current state before they can play their part. In a real-world scenario they might not be allowed to see all the data that’s visible to the other parties, so it is common to create a new stream of communications that includes all of the existing parties, plus the new party, to continue the process. If you use the same blockchain to back both groups, then you can safely order business process steps that involve different parties across these overlapping groups of participants. Using a single Ethereum permissioned side-chain for example. Alternatively, you can create dedicated distributed ledgers (DLTs) for communication between these groups of participants. This can allow more logic and data to go on-chain directly, although you still must consider the fact that this data is immutable and can never be deleted. Using Hyperledger Fabric channels for example. On top of either type of ledger, FireFly provides a private Group construct to facilitate secure off-chain data exchanges, and to efficiently pin these communications to the blockchain in batches. These private data exchanges can also be coordinated with most sophisticated on-chain transactions, such as token transfers. ", "url": "/firefly/head/reference/events.html#privacy-groups-and-late-join", "relUrl": "/reference/events.html#privacy-groups-and-late-join" - },"431": { + },"435": { "doc": "Event Bus", "title": "Event Types", "content": "FireFly provides a number of different types of events to your application, designed to allow you to build your application state machine quickly and reliably. All events in FireFly share a common base structure, regardless of their type. They are then linked (via a reference) to an object that contains detailed information. The categories of event your application can receive are as follows: . See the Core Resources/Event page for a full list of event types, and more details on the data you can expect for each type. Blockchain events . FireFly allows your application to subscribe to any event from a blockchain smart contract. In order for applications connected to the FireFly API to receive blockchain events from a smart contracts, a ContractListener fist must be created to instruct FireFly to listen to those events from the blockchain (via the blockchain plugin). Once you have configured the blockchain event listener, every event detected from the blockchain will result in a FireFly event delivered to your application of type blockchain_event_received. Check out the Custom Contracts Tutorial for a walk-through of how to set up listeners for the events from your smart contracts. FireFly automatically establishes listeners for some blockchain events: . | Events from the FireFly BatchPin contract that is used to pin identities, off-chain data broadcast and private messaging to the blockchain. | Events from Token contracts, for which a Token Pool has been configured. These events are detected indirectly via the token connector. | . Token events . FireFly provides a Wallet API, that is pluggable to multiple token implementations without needing to change your app. The pluggable API/Event interface allows all kinds of technical implementations of tokens to be fitted into a common framework. The following wallet operations are supported. These are universal to all token implementations - NFTs and fungible tokens alike: . | Mint | Burn | Transfer | Approve | . FireFly processes, indexes and stores the events associated with these actions, for any Token Pool that has been configured on the FireFly node. See Token Transfer and Token Approval for more information on the individual operations. The token connector is responsible for mapping from the raw Blockchain Events, to the FireFly model for tokens. Reference token connector implementations are provided for common interface standards implemented by tokens - like ERC-20, ERC-721 and ERC-115. A particular token contract might have many additional features that are unique to that contract, particularly around governance. For these you would use the Smart Contract features of FireFly to interact with the blockchain API and Events directly. ", "url": "/firefly/head/reference/events.html#event-types", "relUrl": "/reference/events.html#event-types" - },"432": { + },"436": { "doc": "Event Bus", "title": "Message events: on-chain / off-chain coordinated", "content": "Event aggregation between data arriving off-chain, and the associated ordered proof/transaction events being confirmed on-chain, is a complex orchestration task. The universal order and additional transaction logic on-chain must be the source of truth for when and how an event is processed. However, that event cannot be processed until the off-chain private/broadcast data associated with that event is also available and verified against the on-chain hash of that additional data. They might arrive in any order, and no further events can be processed on that business transaction until the data is available. Multiple parties might be emitting events as part of the business transaction, and the outcome will only be assured to be the same by all parties if they process these events in the same order. Hyperledger FireFly handles this for you. Events related to a message are not emitted until both the on-chain and off-chain parts (including large binary attachments) are available+verified in your local FireFly node, and all previous messages on the same topic have been processed successfully by your application. Your application just needs to: . | Choose a suitable topic for your messages that determines the ordered stream it is part of. Such as a business transaction identifier. | Make sure the application does not acknowledge a message, until it has finished processing it. | . See Message for more information . ", "url": "/firefly/head/reference/events.html#message-events-on-chain--off-chain-coordinated", "relUrl": "/reference/events.html#message-events-on-chain--off-chain-coordinated" - },"433": { + },"437": { "doc": "Event Bus", "title": "Transaction submission events", "content": "These events are emitted each time a new transaction is initiated via the Firefly API. These events are only emitted on the local FireFly node that initiates an activity. For more information about FireFly Transactions, and how they relate to blockchain transactions, see Transaction. ", "url": "/firefly/head/reference/events.html#transaction-submission-events", "relUrl": "/reference/events.html#transaction-submission-events" - },"434": { + },"438": { "doc": "Fabric", "title": "Work with Hyperledger Fabric chaincodes", "content": "This guide describes the steps to deploy a chaincode to a Hyperledger Fabric blockchain and use FireFly to interact with it in order to submit transactions, query for states and listening for events. NOTE: This guide assumes that you are running a local FireFly stack with at least 2 members and a Fabric blockchain created by the FireFly CLI. If you need help getting that set up, please see the Getting Started guide to Start your environment. ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#work-with-hyperledger-fabric-chaincodes", "relUrl": "/tutorials/custom_contracts/fabric.html#work-with-hyperledger-fabric-chaincodes" - },"435": { + },"439": { "doc": "Fabric", "title": "Table of contents", "content": ". | Work with Hyperledger Fabric chaincodes . | Example smart contract | Create the chaincode package | Contract deployment | The FireFly Interface Format . | Input parameters | Return values | Event payloads | . | Broadcast the contract interface . | Request | Response | . | Create an HTTP API for the contract . | Request | Response | . | View OpenAPI spec for the contract . | /invoke/* endpoints | /query/* endpoints | . | Invoke the chaincode . | Request | Response | . | Query the current state . | Request | Response | . | Create a blockchain event listener . | Request | Response | . | Subscribe to events from our contract . | Request | Response | . | Receive custom smart contract events . | WebSocket event | . | . | . ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#table-of-contents", "relUrl": "/tutorials/custom_contracts/fabric.html#table-of-contents" - },"436": { + },"440": { "doc": "Fabric", "title": "Example smart contract", "content": "For this tutorial, we will be using a well known, but slightly modified smart contract called asset_transfer. It’s based on the asset-transfer-basic chaincode in the fabric-samples project. Check out the code repository and use the source code provided below to replace part of the content of the file fabric-samples/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go. Find the following return statement in the function CreateAsset: . return ctx.GetStub().PutState(id, assetJSON) . and replace it with the following, so that an event will be emitted when the transaction is committed to the channel ledger: . err = ctx.GetStub().PutState(id, assetJSON) if err != nil { return err } return ctx.GetStub().SetEvent(\"AssetCreated\", assetJSON) . ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#example-smart-contract", "relUrl": "/tutorials/custom_contracts/fabric.html#example-smart-contract" - },"437": { + },"441": { "doc": "Fabric", "title": "Create the chaincode package", "content": "Use the peer command to create the chaincode package for deployment. You can download the peer binary from the releases page of the Fabric project or build it from source. ~ johndoe$ cd fabric-samples/asset-transfer-basic/chaincode-go chaincode-go johndoe$ touch core.yaml chaincode-go johndoe$ peer lifecycle chaincode package -p . --label asset_transfer ./asset_transfer.zip . The peer command requires an empty core.yaml file to be present in the working directory to perform the packaging. That’s what touch core.yaml did above . The resulting asset_transfer.zip archive file will be used in the next step to deploy to the Fabric network used in FireFly. ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#create-the-chaincode-package", "relUrl": "/tutorials/custom_contracts/fabric.html#create-the-chaincode-package" - },"438": { + },"442": { "doc": "Fabric", "title": "Contract deployment", "content": "Deployment of smart contracts is not currently within the scope of responsibility for FireFly. You can use your standard blockchain specific tools to deploy your contract to the blockchain you are using. The FireFly CLI provides a convenient function to deploy a chaincode package to a local FireFly stack. NOTE: The contract deployment function of the FireFly CLI is a convenience function to speed up local development, and not intended for production applications . ~ johndoe$ ff help deploy fabric Deploy a packaged chaincode to the Fabric network used by a FireFly stack Usage: ff deploy fabric <stack_name> <chaincode_package> <channel> <chaincodeName> <version> [flags] . Notice the various parameters used by the command ff deploy fabric. We’ll tell the FireFly to deploy using the following parameter values, if your stack setup is different, update the command accordingly: . | stack name: dev | channel: firefly (this is the channel that is created by the FireFly CLI when bootstrapping the stack, replace if you use a different channel in your setup) | chaincode name: asset_transfer (must match the value of the --label parameter when creating the chaincode package) | version: 1.0 | . $ ff deploy fabric dev asset_transfer.zip firefly asset_transfer 1.0 installing chaincode querying installed chaincode approving chaincode committing chaincode { \"chaincode\": \"asset_transfer\", \"channel\": \"firefly\" } . ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#contract-deployment", "relUrl": "/tutorials/custom_contracts/fabric.html#contract-deployment" - },"439": { + },"443": { "doc": "Fabric", "title": "The FireFly Interface Format", "content": "In order to teach FireFly how to interact with the chaincode, a FireFly Interface (FFI) document is needed. While Ethereum (or other EVM based blockchains) requires an Application Binary Interface (ABI) to govern the interaction between the client and the smart contract, which is specific to each smart contract interface design, Fabric defines a generic chaincode interface and leaves the encoding and decoding of the parameter values to the discretion of the chaincode developer. As a result, the FFI document for a Fabric chaincode must be hand-crafted. The following FFI sample demonstrates the specification for the following common cases: . | structured JSON, used here for the list of chaincode function CreateAsset input parameters | array of JSON, used here for the chaincode function GetAllAssets output | structured JSON, used here for the list of chaincode event AssetCreated properties | . { \"namespace\": \"default\", \"name\": \"asset_transfer\", \"description\": \"Spec interface for the asset-transfer-basic golang chaincode\", \"version\": \"1.0\", \"methods\": [ { \"name\": \"GetAllAssets\", \"pathname\": \"\", \"description\": \"\", \"params\": [], \"returns\": [ { \"name\": \"\", \"schema\": { \"type\": \"array\", \"details\": { \"type\": \"object\", \"properties\": { \"type\": \"string\" } } } } ] }, { \"name\": \"CreateAsset\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"id\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"color\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"size\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"owner\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"value\", \"schema\": { \"type\": \"string\" } } ], \"returns\": [] } ], \"events\": [ { \"name\": \"AssetCreated\" } ] } . Input parameters . For the params section of the CreateAsset function, it is critical that the sequence of the properties (id, color, size, owner, value) matches the order of the input parameters in the chaincode’s function signature: . func CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error . Return values . FireFly can automatically decode JSON payloads in the return values. That’s why the returns section of the GetAllAssets function only needs to specify the type as array of objects, without having to specify the detailed structure of the JSON payload. On the other hand, if certain properties of the returned value are to be hidden, then you can provide a detailed structure of the JSON object with the desired properties. This is demonstrated in the JSON structure for the event payload, see below, where the property AppraisedValue is omitted from the output. Event payloads . For events, FireFly automatically decodes JSON payloads. If the event payload is not JSON, base64 encoded bytes will be returned instead. For the events section of the FFI, only the name property needs to be specified. ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#the-firefly-interface-format", "relUrl": "/tutorials/custom_contracts/fabric.html#the-firefly-interface-format" - },"440": { + },"444": { "doc": "Fabric", "title": "Broadcast the contract interface", "content": "Now that we have a FireFly Interface representation of our chaincode, we want to broadcast that to the entire network. This broadcast will be pinned to the blockchain, so we can always refer to this specific name and version, and everyone in the network will know exactly which contract interface we are talking about. We will use the FFI JSON constructed above and POST that to the /contracts/interfaces API endpoint. Request . POST http://localhost:5000/api/v1/namespaces/default/contracts/interfaces . { \"namespace\": \"default\", \"name\": \"asset_transfer\", \"description\": \"Spec interface for the asset-transfer-basic golang chaincode\", \"version\": \"1.0\", \"methods\": [ { \"name\": \"GetAllAssets\", \"pathname\": \"\", \"description\": \"\", \"params\": [], \"returns\": [ { \"name\": \"\", \"schema\": { \"type\": \"array\", \"details\": { \"type\": \"object\", \"properties\": { \"type\": \"string\" } } } } ] }, { \"name\": \"CreateAsset\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"id\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"color\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"size\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"owner\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"value\", \"schema\": { \"type\": \"string\" } } ], \"returns\": [] } ], \"events\": [ { \"name\": \"AssetCreated\" } ] } . Response . { \"id\": \"f1e5522c-59a5-4787-bbfd-89975e5b0954\", \"message\": \"8a01fc83-5729-418b-9706-6fc17c8d2aac\", \"namespace\": \"default\", \"name\": \"asset_transfer\", \"description\": \"Spec interface for the asset-transfer-basic golang chaincode\", \"version\": \"1.1\", \"methods\": [ { \"id\": \"b31e3623-35e8-4918-bf8c-1b0d6c01de25\", \"interface\": \"f1e5522c-59a5-4787-bbfd-89975e5b0954\", \"name\": \"GetAllAssets\", \"namespace\": \"default\", \"pathname\": \"GetAllAssets\", \"description\": \"\", \"params\": [], \"returns\": [ { \"name\": \"\", \"schema\": { \"type\": \"array\", \"details\": { \"type\": \"object\", \"properties\": { \"type\": \"string\" } } } } ] }, { \"id\": \"e5a170d1-0be1-4697-800b-f4bcfaf71cf6\", \"interface\": \"f1e5522c-59a5-4787-bbfd-89975e5b0954\", \"name\": \"CreateAsset\", \"namespace\": \"default\", \"pathname\": \"CreateAsset\", \"description\": \"\", \"params\": [ { \"name\": \"id\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"color\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"size\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"owner\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"value\", \"schema\": { \"type\": \"string\" } } ], \"returns\": [] } ], \"events\": [ { \"id\": \"27564533-30bd-4536-884e-02e5d79ec238\", \"interface\": \"f1e5522c-59a5-4787-bbfd-89975e5b0954\", \"namespace\": \"default\", \"pathname\": \"AssetCreated\", \"signature\": \"\", \"name\": \"AssetCreated\", \"description\": \"\", \"params\": null } ] } . NOTE: We can broadcast this contract interface conveniently with the help of FireFly Sandbox running at http://127.0.0.1:5108 . | Go to the Contracts Section | Click on Define a Contract Interface | Select FFI - FireFly Interface in the Interface Fromat dropdown | Copy the FFI JSON crafted by you into the Schema Field | Click on Run | . ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#broadcast-the-contract-interface", "relUrl": "/tutorials/custom_contracts/fabric.html#broadcast-the-contract-interface" - },"441": { + },"445": { "doc": "Fabric", "title": "Create an HTTP API for the contract", "content": "Now comes the fun part where we see some of the powerful, developer-friendly features of FireFly. The next thing we’re going to do is tell FireFly to build an HTTP API for this chaincode, complete with an OpenAPI Specification and Swagger UI. As part of this, we’ll also tell FireFly where the chaincode is on the blockchain. Like the interface broadcast above, this will also generate a broadcast which will be pinned to the blockchain so all the members of the network will be aware of and able to interact with this API. We need to copy the id field we got in the response from the previous step to the interface.id field in the request body below. We will also pick a name that will be part of the URL for our HTTP API, so be sure to pick a name that is URL friendly. In this case we’ll call it asset_transfer. Lastly, in the location field, we’re telling FireFly where an instance of the chaincode is deployed on-chain, which is a chaincode named asset_transfer in the channel firefly. NOTE: The location field is optional here, but if it is omitted, it will be required in every request to invoke or query the chaincode. This can be useful if you have multiple instances of the same chaincode deployed to different channels. Request . POST http://localhost:5000/api/v1/namespaces/default/apis . { \"name\": \"asset_transfer\", \"interface\": { \"id\": \"f1e5522c-59a5-4787-bbfd-89975e5b0954\" }, \"location\": { \"channel\": \"firefly\", \"chaincode\": \"asset_transfer\" } } . Response . { \"id\": \"a9a9ab4e-2544-45d5-8824-3c05074fbf75\", \"namespace\": \"default\", \"interface\": { \"id\": \"f1e5522c-59a5-4787-bbfd-89975e5b0954\" }, \"location\": { \"channel\": \"firefly\", \"chaincode\": \"asset_transfer\" }, \"name\": \"asset_transfer\", \"message\": \"5f1556a1-5cb1-4bc6-8611-d8f88ccf9c30\", \"urls\": { \"openapi\": \"http://127.0.0.1:5000/api/v1/namespaces/default/apis/asset_transfer/api/swagger.json\", \"ui\": \"http://127.0.0.1:5000/api/v1/namespaces/default/apis/asset_transfer/api\" } } . NOTE: We can create this Http API conveniently with the help of FireFly Sandbox running at http://127.0.0.1:5108 . | Go to the Contracts Section | Click on Register a Contract API | Select the name of your broadcasted FFI in the Contract Interface dropdown | In the Name Field, give a name that will be part of the URL for your Http API | In the Chaincode Field, give your chaincode name for which you wrote the FFI | In the Channel Field, give the channel name where your chaincode is deployed | Click on Run | . ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#create-an-http-api-for-the-contract", "relUrl": "/tutorials/custom_contracts/fabric.html#create-an-http-api-for-the-contract" - },"442": { + },"446": { "doc": "Fabric", "title": "View OpenAPI spec for the contract", "content": "You’ll notice in the response body that there are a couple of URLs near the bottom. If you navigate to the one labeled ui in your browser, you should see the Swagger UI for your chaincode. /invoke/* endpoints . The /invoke endpoints in the generated API are for submitting transactions. These endpoints will be mapped to the POST /transactions endpoint of the FabConnect API. /query/* endpoints . The /query endpoints in the generated API, on the other hand, are for sending query requests. These endpoints will be mapped to the POST /query endpoint of the Fabconnect API, which under the cover only sends chaincode endorsement requests to the target peer node without sending a trasaction payload to the orderer node. ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#view-openapi-spec-for-the-contract", "relUrl": "/tutorials/custom_contracts/fabric.html#view-openapi-spec-for-the-contract" - },"443": { + },"447": { "doc": "Fabric", "title": "Invoke the chaincode", "content": "Now that we’ve got everything set up, it’s time to use our chaincode! We’re going to make a POST request to the invoke/CreateAsset endpoint to create a new asset. Request . POST http://localhost:5000/api/v1/namespaces/default/apis/asset_transfer/invoke/CreateAsset . { \"input\": { \"color\": \"blue\", \"id\": \"asset-01\", \"owner\": \"Harry\", \"size\": \"30\", \"value\": \"23400\" } } . Response . { \"id\": \"b8e905cc-bc23-434a-af7d-13c6d85ae545\", \"namespace\": \"default\", \"tx\": \"79d2668e-4626-4634-9448-1b40fa0d9dfd\", \"type\": \"blockchain_invoke\", \"status\": \"Pending\", \"plugin\": \"fabric\", \"input\": { \"input\": { \"color\": \"blue\", \"id\": \"asset-02\", \"owner\": \"Harry\", \"size\": \"30\", \"value\": \"23400\" }, \"interface\": \"f1e5522c-59a5-4787-bbfd-89975e5b0954\", \"key\": \"Org1MSP::x509::CN=org_0,OU=client::CN=fabric_ca.org1.example.com,OU=Hyperledger FireFly,O=org1.example.com,L=Raleigh,ST=North Carolina,C=US\", \"location\": { \"chaincode\": \"asset_transfer\", \"channel\": \"firefly\" }, \"method\": { \"description\": \"\", \"id\": \"e5a170d1-0be1-4697-800b-f4bcfaf71cf6\", \"interface\": \"f1e5522c-59a5-4787-bbfd-89975e5b0954\", \"name\": \"CreateAsset\", \"namespace\": \"default\", \"params\": [ { \"name\": \"id\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"color\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"size\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"owner\", \"schema\": { \"type\": \"string\" } }, { \"name\": \"value\", \"schema\": { \"type\": \"string\" } } ], \"pathname\": \"CreateAsset\", \"returns\": [] }, \"methodPath\": \"CreateAsset\", \"type\": \"invoke\" }, \"created\": \"2022-05-02T17:08:40.811630044Z\", \"updated\": \"2022-05-02T17:08:40.811630044Z\" } . You’ll notice that we got an ID back with status Pending, and that’s expected due to the asynchronous programming model of working with custom onchain logic in FireFly. To see what the latest state is now, we can query the chaincode. In a little bit, we’ll also subscribe to the events emitted by this chaincode so we can know when the state is updated in realtime. ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#invoke-the-chaincode", "relUrl": "/tutorials/custom_contracts/fabric.html#invoke-the-chaincode" - },"444": { + },"448": { "doc": "Fabric", "title": "Query the current state", "content": "To make a read-only request to the blockchain to check the current list of assets, we can make a POST to the query/GetAllAssets endpoint. Request . POST http://localhost:5000/api/v1/namespaces/default/apis/asset_transfer/query/GetAllAssets . {} . Response . [ { \"AppraisedValue\": 23400, \"Color\": \"blue\", \"ID\": \"asset-01\", \"Owner\": \"Harry\", \"Size\": 30 } ] . NOTE: Some chaincodes may have queries that require input parameters. That’s why the query endpoint is a POST, rather than a GET so that parameters can be passed as JSON in the request body. This particular function does not have any parameters, so we just pass an empty JSON object. ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#query-the-current-state", "relUrl": "/tutorials/custom_contracts/fabric.html#query-the-current-state" - },"445": { + },"449": { "doc": "Fabric", "title": "Create a blockchain event listener", "content": "Now that we’ve seen how to submit transactions and preform read-only queries to the blockchain, let’s look at how to receive blockchain events so we know when things are happening in realtime. If you look at the source code for the smart contract we’re working with above, you’ll notice that it emits an event when a new asset is created. In order to receive these events, we first need to instruct FireFly to listen for this specific type of blockchain event. To do this, we create an Event Listener. The /contracts/listeners endpoint is RESTful so there are POST, GET, and DELETE methods available on it. To create a new listener, we will make a POST request. We are going to tell FireFly to listen to events with name \"AssetCreated\" from the FireFly Interface we defined earlier, referenced by its ID. We will also tell FireFly which channel and chaincode we expect to emit these events. Request . POST http://localhost:5000/api/v1/namespaces/default/contracts/listeners . { \"interface\": { \"id\": \"f1e5522c-59a5-4787-bbfd-89975e5b0954\" }, \"location\": { \"channel\": \"firefly\", \"chaincode\": \"asset_transfer\" }, \"event\": { \"name\": \"AssetCreated\" }, \"options\": { \"firstEvent\": \"oldest\" }, \"topic\": \"assets\" } . Response . { \"id\": \"6e7f5dd8-5a57-4163-a1d2-5654e784dc31\", \"namespace\": \"default\", \"name\": \"sb-2cac2bfa-38af-4408-4ff3-973421410e5d\", \"backendId\": \"sb-2cac2bfa-38af-4408-4ff3-973421410e5d\", \"location\": { \"channel\": \"firefly\", \"chaincode\": \"asset_transfer\" }, \"created\": \"2022-05-02T17:19:13.144561086Z\", \"event\": { \"name\": \"AssetCreated\", \"description\": \"\", \"params\": null }, \"signature\": \"AssetCreated\", \"topic\": \"assets\", \"options\": { \"firstEvent\": \"oldest\" } } . ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#create-a-blockchain-event-listener", "relUrl": "/tutorials/custom_contracts/fabric.html#create-a-blockchain-event-listener" - },"446": { + },"450": { "doc": "Fabric", "title": "Subscribe to events from our contract", "content": "Now that we’ve told FireFly that it should listen for specific events on the blockchain, we can set up a Subscription for FireFly to send events to our client app. To set up our subscription, we will make a POST to the /subscriptions endpoint. We will set a friendly name asset_transfer to identify the Subscription when we are connecting to it in the next step. We’re also going to set up a filter to only send events blockchain events from our listener that we created in the previous step. To do that, we’ll copy the listener ID from the step above (6e7f5dd8-5a57-4163-a1d2-5654e784dc31) and set that as the value of the listener field in the example below: . Request . POST http://localhost:5000/api/v1/namespaces/default/subscriptions . { \"namespace\": \"default\", \"name\": \"asset_transfer\", \"transport\": \"websockets\", \"filter\": { \"events\": \"blockchain_event_received\", \"blockchainevent\": { \"listener\": \"6e7f5dd8-5a57-4163-a1d2-5654e784dc31\" } }, \"options\": { \"firstEvent\": \"oldest\" } } . Response . { \"id\": \"06d18b49-e763-4f5c-9e97-c25024fe57c8\", \"namespace\": \"default\", \"name\": \"asset_transfer\", \"transport\": \"websockets\", \"filter\": { \"events\": \"blockchain_event_received\", \"message\": {}, \"transaction\": {}, \"blockchainevent\": { \"listener\": \"6e7f5dd8-5a57-4163-a1d2-5654e784dc31\" } }, \"options\": { \"firstEvent\": \"-1\", \"withData\": false }, \"created\": \"2022-05-02T17:22:06.480181291Z\", \"updated\": null } . ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#subscribe-to-events-from-our-contract", "relUrl": "/tutorials/custom_contracts/fabric.html#subscribe-to-events-from-our-contract" - },"447": { + },"451": { "doc": "Fabric", "title": "Receive custom smart contract events", "content": "The last step is to connect a WebSocket client to FireFly to receive the event. You can use any WebSocket client you like, such as Postman or a command line app like websocat. Connect your WebSocket client to ws://localhost:5000/ws. After connecting the WebSocket client, send a message to tell FireFly to: . | Start sending events | For the Subscription named asset_transfer | On the default namespace | Automatically “ack” each event which will let FireFly immediately send the next event when available | . { \"type\": \"start\", \"name\": \"asset_transfer\", \"namespace\": \"default\", \"autoack\": true } . WebSocket event . After creating the subscription, you should see an event arrive on the connected WebSocket client that looks something like this: . { \"id\": \"d9fb86b2-b25b-43b8-80d3-936c5daa5a66\", \"sequence\": 29, \"type\": \"blockchain_event_received\", \"namespace\": \"default\", \"reference\": \"e0d670b4-a1b6-4efd-a985-06dfaaa58fe3\", \"topic\": \"assets\", \"created\": \"2022-05-02T17:26:57.57612001Z\", \"blockchainEvent\": { \"id\": \"e0d670b4-a1b6-4efd-a985-06dfaaa58fe3\", \"source\": \"fabric\", \"namespace\": \"default\", \"name\": \"AssetCreated\", \"listener\": \"6e7f5dd8-5a57-4163-a1d2-5654e784dc31\", \"protocolId\": \"000000000015/000000/000000\", \"output\": { \"AppraisedValue\": 12300, \"Color\": \"red\", \"ID\": \"asset-01\", \"Owner\": \"Jerry\", \"Size\": 10 }, \"info\": { \"blockNumber\": 15, \"chaincodeId\": \"asset_transfer\", \"eventIndex\": 0, \"eventName\": \"AssetCreated\", \"subId\": \"sb-2cac2bfa-38af-4408-4ff3-973421410e5d\", \"timestamp\": 1651512414920972300, \"transactionId\": \"172637bf59a3520ca6dd02f716e1043ba080e10e1cd2f98b4e6b85abcc6a6d69\", \"transactionIndex\": 0 }, \"timestamp\": \"2022-05-02T17:26:54.9209723Z\", \"tx\": { \"type\": \"\", \"blockchainId\": \"172637bf59a3520ca6dd02f716e1043ba080e10e1cd2f98b4e6b85abcc6a6d69\" } }, \"subscription\": { \"id\": \"06d18b49-e763-4f5c-9e97-c25024fe57c8\", \"namespace\": \"default\", \"name\": \"asset_transfer\" } } . You can see in the event received over the WebSocket connection, the blockchain event that was emitted from our first transaction, which happened in the past. We received this event, because when we set up both the Listener, and the Subscription, we specified the \"firstEvent\" as \"oldest\". This tells FireFly to look for this event from the beginning of the blockchain, and that your app is interested in FireFly events since the beginning of FireFly’s event history. In the event, we can also see the blockchainEvent itself, which has an output object. This contains the event payload that was set by the chaincode. ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html#receive-custom-smart-contract-events", "relUrl": "/tutorials/custom_contracts/fabric.html#receive-custom-smart-contract-events" - },"448": { + },"452": { "doc": "Fabric", "title": "Fabric", "content": " ", "url": "/firefly/head/tutorials/custom_contracts/fabric.html", "relUrl": "/tutorials/custom_contracts/fabric.html" - },"449": { + },"453": { "doc": "pages.fabric_test_network", "title": "Work with Fabric-Samples Test Network", "content": " ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#work-with-fabric-samples-test-network", "relUrl": "/tutorials/chains/fabric_test_network.html#work-with-fabric-samples-test-network" - },"450": { + },"454": { "doc": "pages.fabric_test_network", "title": "Table of contents", "content": ". | Previous steps: Install the FireFly CLI | Start Fabric Test Network with Fabric CA | Deploy FireFly Chaincode | Create ccp.yml documents . | Organization 1 connection profile | Organization 2 connection profile | . | Create the FireFly stack | Edit docker-compose.override.yml | Start FireFly stack | Connecting to a remote Fabric Network | Troubleshooting . | No such host | No such file or directory | . | . This guide will walk you through the steps to create a local FireFly development environment and connect it to the Fabric Test Network from the Fabric Samples repo . ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#table-of-contents", "relUrl": "/tutorials/chains/fabric_test_network.html#table-of-contents" - },"451": { + },"455": { "doc": "pages.fabric_test_network", "title": "Previous steps: Install the FireFly CLI", "content": "If you haven’t set up the FireFly CLI already, please go back to the Getting Started guide and read the section on how to Install the FireFly CLI. ← ① Install the FireFly CLI . ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#previous-steps-install-the-firefly-cli", "relUrl": "/tutorials/chains/fabric_test_network.html#previous-steps-install-the-firefly-cli" - },"452": { + },"456": { "doc": "pages.fabric_test_network", "title": "Start Fabric Test Network with Fabric CA", "content": "For details about the Fabric Test Network and how to set it up, please see the Fabric Samples repo. The one important detail is that you need to start up the Test Network with a Fabric CA. This is because Fabconnect will use the Fabric CA to create an identity for its FireFly node to use. To start up the network with the CA, and create a new channel called mychannel run: ./network.sh up createChannel -ca . NOTE: If you already have the Test Network running, you will need to bring it down first, by running: ./network.sh down . ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#start-fabric-test-network-with-fabric-ca", "relUrl": "/tutorials/chains/fabric_test_network.html#start-fabric-test-network-with-fabric-ca" - },"453": { + },"457": { "doc": "pages.fabric_test_network", "title": "Deploy FireFly Chaincode", "content": "Next we will need to package and deploy the FireFly chaincode to mychannel in our new network. For more details on packaging and deploying chaincode, please see the Fabric chaincode lifecycle documentation. If you already have the FireFly repo cloned in the same directory as your fabric-samples repo, you can run the following script from your test-network directory: . NOTE: This script is provided as a convenience only, and you are not required to use it. You are welcome to package and deploy the chaincode to your test-network any way you would like. #!/bin/bash # This file should be run from the test-network directory in the fabric-samples repo # It also assumes that you have the firefly repo checked out at the same level as the fabric-samples directory # It also assumes that the test-network is up and running and a channel named 'mychannel' has already been created cd ../../firefly/smart_contracts/fabric/firefly-go GO111MODULE=on go mod vendor cd ../../../../fabric-samples/test-network export PATH=${PWD}/../bin:$PATH export FABRIC_CFG_PATH=$PWD/../config/ peer lifecycle chaincode package firefly.tar.gz --path ../../firefly/smart_contracts/fabric/firefly-go --lang golang --label firefly_1.0 export CORE_PEER_TLS_ENABLED=true export CORE_PEER_LOCALMSPID=\"Org1MSP\" export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp export CORE_PEER_ADDRESS=localhost:7051 peer lifecycle chaincode install firefly.tar.gz export CORE_PEER_LOCALMSPID=\"Org2MSP\" export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp export CORE_PEER_ADDRESS=localhost:9051 peer lifecycle chaincode install firefly.tar.gz export CC_PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq --raw-output \".installed_chaincodes[0].package_id\") peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name firefly --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile \"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem\" export CORE_PEER_LOCALMSPID=\"Org1MSP\" export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt export CORE_PEER_ADDRESS=localhost:7051 peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name firefly --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile \"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem\" peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name firefly --version 1.0 --sequence 1 --tls --cafile \"${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem\" --peerAddresses localhost:7051 --tlsRootCertFiles \"${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt\" --peerAddresses localhost:9051 --tlsRootCertFiles \"${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt\" . ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#deploy-firefly-chaincode", "relUrl": "/tutorials/chains/fabric_test_network.html#deploy-firefly-chaincode" - },"454": { + },"458": { "doc": "pages.fabric_test_network", "title": "Create ccp.yml documents", "content": "Each FireFly Supernode (specifically the Fabconnect instance in each) will need to know how to connect to the Fabric network. Fabconnect will use a Fabric Connection Profile which describes the network and tells it where the certs and keys are that it needs. Below is a ccp.yml for each organization. You will need to fill in one line by replacing the string FILL_IN_KEY_NAME_HERE, because the file name of the private key for each user is randomly generated. Organization 1 connection profile . Create a new file at ~/org1_ccp.yml with the contents below. Replace the string FILL_IN_KEY_NAME_HERE with the filename in your fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore directory. certificateAuthorities: org1.example.com: tlsCACerts: path: /etc/firefly/organizations/peerOrganizations/org1.example.com/msp/tlscacerts/ca.crt url: https://ca_org1:7054 grpcOptions: ssl-target-name-override: org1.example.com registrar: enrollId: admin enrollSecret: adminpw channels: mychannel: orderers: - fabric_orderer peers: fabric_peer: chaincodeQuery: true endorsingPeer: true eventSource: true ledgerQuery: true client: BCCSP: security: default: provider: SW enabled: true hashAlgorithm: SHA2 level: 256 softVerify: true credentialStore: cryptoStore: path: /etc/firefly/organizations/peerOrganizations/org1.example.com/msp path: /etc/firefly/organizations/peerOrganizations/org1.example.com/msp cryptoconfig: path: /etc/firefly/organizations/peerOrganizations/org1.example.com/msp logging: level: info organization: org1.example.com tlsCerts: client: cert: path: /etc/firefly/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/cert.pem key: path: /etc/firefly/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/FILL_IN_KEY_NAME_HERE orderers: fabric_orderer: tlsCACerts: path: /etc/firefly/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/tlscacerts/tls-localhost-9054-ca-orderer.pem url: grpcs://orderer.example.com:7050 organizations: org1.example.com: certificateAuthorities: - org1.example.com cryptoPath: /tmp/msp mspid: Org1MSP peers: - fabric_peer peers: fabric_peer: tlsCACerts: path: /etc/firefly/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/tlscacerts/tls-localhost-7054-ca-org1.pem url: grpcs://peer0.org1.example.com:7051 version: 1.1.0% . Organization 2 connection profile . Create a new file at ~/org2_ccp.yml with the contents below. Replace the string FILL_IN_KEY_NAME_HERE with the filename in your fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore directory. certificateAuthorities: org2.example.com: tlsCACerts: path: /etc/firefly/organizations/peerOrganizations/org2.example.com/msp/tlscacerts/ca.crt url: https://ca_org2:8054 grpcOptions: ssl-target-name-override: org2.example.com registrar: enrollId: admin enrollSecret: adminpw channels: mychannel: orderers: - fabric_orderer peers: fabric_peer: chaincodeQuery: true endorsingPeer: true eventSource: true ledgerQuery: true client: BCCSP: security: default: provider: SW enabled: true hashAlgorithm: SHA2 level: 256 softVerify: true credentialStore: cryptoStore: path: /etc/firefly/organizations/peerOrganizations/org2.example.com/msp path: /etc/firefly/organizations/peerOrganizations/org2.example.com/msp cryptoconfig: path: /etc/firefly/organizations/peerOrganizations/org2.example.com/msp logging: level: info organization: org2.example.com tlsCerts: client: cert: path: /etc/firefly/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/cert.pem key: path: /etc/firefly/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/FILL_IN_KEY_NAME_HERE orderers: fabric_orderer: tlsCACerts: path: /etc/firefly/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/tlscacerts/tls-localhost-9054-ca-orderer.pem url: grpcs://orderer.example.com:7050 organizations: org2.example.com: certificateAuthorities: - org2.example.com cryptoPath: /tmp/msp mspid: Org2MSP peers: - fabric_peer peers: fabric_peer: tlsCACerts: path: /etc/firefly/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/tlscacerts/tls-localhost-8054-ca-org2.pem url: grpcs://peer0.org2.example.com:9051 version: 1.1.0% . ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#create-ccpyml-documents", "relUrl": "/tutorials/chains/fabric_test_network.html#create-ccpyml-documents" - },"455": { + },"459": { "doc": "pages.fabric_test_network", "title": "Create the FireFly stack", "content": "Now we can create a FireFly stack and pass in these files as command line flags. NOTE: The following command should be run in the test-network directory as it includes a relative path to the organizations directory containing each org’s MSP. ff init fabric dev \\ --ccp \"${HOME}/org1_ccp.yml\" \\ --msp \"organizations\" \\ --ccp \"${HOME}/org2_ccp.yml\" \\ --msp \"organizations\" \\ --channel mychannel \\ --chaincode firefly . ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#create-the-firefly-stack", "relUrl": "/tutorials/chains/fabric_test_network.html#create-the-firefly-stack" - },"456": { + },"460": { "doc": "pages.fabric_test_network", "title": "Edit docker-compose.override.yml", "content": "The last step before starting up FireFly is to make sure that our FireFly containers have networking access to the Fabric containers. Because these are in two different Docker Compose networks by default, normally the containers would not be able to connect directly. We can fix this by instructing Docker to also attach our FireFly containers to the Fabric test network Docker Compose network. The easiest way to do that is to edit ~/.firefly/stacks/dev/docker-compose.override.yml and set its contents to the following: . # Add custom config overrides here # See https://docs.docker.com/compose/extends version: \"2.1\" networks: default: name: fabric_test external: true . ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#edit-docker-composeoverrideyml", "relUrl": "/tutorials/chains/fabric_test_network.html#edit-docker-composeoverrideyml" - },"457": { + },"461": { "doc": "pages.fabric_test_network", "title": "Start FireFly stack", "content": "Now we can start up FireFly! . ff start dev . After everything starts up, you should have two FireFly nodes that are each mapped to an Organization in your Fabric network. You can that they each use separate signing keys for their Org on messages that each FireFly node sends. ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#start-firefly-stack", "relUrl": "/tutorials/chains/fabric_test_network.html#start-firefly-stack" - },"458": { + },"462": { "doc": "pages.fabric_test_network", "title": "Connecting to a remote Fabric Network", "content": "This same guide can be adapted to connect to a remote Fabric network running somewhere else. They key takeaways are: . | You need the FireFly chaincode deployed on channel in your Fabric network | You need to pass the channel and chaincode name when you run ff init | You need to provide a connection profile and the correct certs, keys, etc. for each node when you run ff init | Your FireFly containers will need to have network access to your Fabric network | . ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#connecting-to-a-remote-fabric-network", "relUrl": "/tutorials/chains/fabric_test_network.html#connecting-to-a-remote-fabric-network" - },"459": { + },"463": { "doc": "pages.fabric_test_network", "title": "Troubleshooting", "content": "There are quite a few moving parts in this guide and if steps are missed or done out of order it can cause problems. Below are some of the common situations that you might run into while following this guide, and solutions for each. You may see a message something along the lines of: . ERROR: for firefly_core_0 Container \"bc04521372aa\" is unhealthy. Encountered errors while bringing up the project. In this case, we need to look at the container logs to get more detail about what happened. To do this, we can run ff start and tell it not to clean up the stack after the failure, to let you inspect what went wrong. To do that, you can run: . ff start dev --verbose --no-rollback . Then we could run docker logs <container_name> to see the logs for that container. No such host . Error: http://127.0.0.1:5102/identities [500] {\"error\":\"enroll failed: enroll failed: POST failure of request: POST https://ca_org1:7054/enroll\\n{\\\"hosts\\\":null,\\\"certificate_request\\\":\\\"-----BEGIN CERTIFICATE REQUEST-----\\\\nMIH0MIGcAgEAMBAxDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0D\\\\nAQcDQgAE7qJZ5nGt/kxU9IvrEb7EmgNIgn9xXoQUJLl1+U9nXdWB9cnxcmoitnvy\\\\nYN63kbBuUh0z21vOmO8GLD3QxaRaD6AqMCgGCSqGSIb3DQEJDjEbMBkwFwYDVR0R\\\\nBBAwDoIMMGQ4NGJhZWIwZGY0MAoGCCqGSM49BAMCA0cAMEQCIBcWb127dVxm/80K\\\\nB2LtenAY/Jtb2FbZczolrXNCKq+LAiAcGEJ6Mx8LVaPzuSP4uGpEoty6+bEErc5r\\\\nHVER+0aXiQ==\\\\n-----END CERTIFICATE REQUEST-----\\\\n\\\",\\\"profile\\\":\\\"\\\",\\\"crl_override\\\":\\\"\\\",\\\"label\\\":\\\"\\\",\\\"NotBefore\\\":\\\"0001-01-01T00:00:00Z\\\",\\\"NotAfter\\\":\\\"0001-01-01T00:00:00Z\\\",\\\"ReturnPrecert\\\":false,\\\"CAName\\\":\\\"\\\"}: Post \\\"https://ca_org1:7054/enroll\\\": dial tcp: lookup ca_org1 on 127.0.0.11:53: no such host\"} . If you see something in your logs that looks like the above, there could be a couple issues: . | The hostname for one of your Fabric containers could be wrong in the ccp.yml. Check the ccp.yml for that member and make sure the hostnames are correct. | The FireFly container doesn’t have networking connectivity to the Fabric containers. Check the docker-compose.override.yml file to make sure you added the fabric_test network as instructed above. | . No such file or directory . User credentials store creation failed. Failed to load identity configurations: failed to create identity config from backends: failed to load client TLSConfig : failed to load client key: failed to load pem bytes from path /etc/firefly/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/cfc50311e2204f232cfdfaf4eba7731279f2366ec291ca1c1781e2bf7bc75529_sk: open /etc/firefly/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/cfc50311e2204f232cfdfaf4eba7731279f2366ec291ca1c1781e2bf7bc75529_sk: no such file or directory . If you see something in your logs that looks like the above, it’s likely that your private key file name is not correct in your ccp.yml file for that particular member. Check your ccp.yml and make sure all the files listed there exist in your organizations directory. ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html#troubleshooting", "relUrl": "/tutorials/chains/fabric_test_network.html#troubleshooting" - },"460": { + },"464": { "doc": "pages.fabric_test_network", "title": "pages.fabric_test_network", "content": " ", "url": "/firefly/head/tutorials/chains/fabric_test_network.html", "relUrl": "/tutorials/chains/fabric_test_network.html" - },"461": { + },"465": { "doc": "FFI", "title": "FFI", "content": " ", "url": "/firefly/head/reference/types/ffi.html", "relUrl": "/reference/types/ffi.html" - },"462": { + },"466": { "doc": "FFI", "title": "Table of contents", "content": ". | FFI . | Example | Field Descriptions | . | FFIMethod | FFIParam | FFIEvent | FFIParam | FFIError | FFIParam | . ", "url": "/firefly/head/reference/types/ffi.html#table-of-contents", "relUrl": "/reference/types/ffi.html#table-of-contents" - },"463": { + },"467": { "doc": "FFI", "title": "FFI", "content": "See FireFly Interface Format . Example . { \"id\": \"c35d3449-4f24-4676-8e64-91c9e46f06c4\", \"message\": \"e4ad2077-5714-416e-81f9-7964a6223b6f\", \"namespace\": \"ns1\", \"name\": \"SimpleStorage\", \"description\": \"A simple example contract in Solidity\", \"version\": \"v0.0.1\", \"methods\": [ { \"id\": \"8f3289dd-3a19-4a9f-aab3-cb05289b013c\", \"interface\": \"c35d3449-4f24-4676-8e64-91c9e46f06c4\", \"name\": \"get\", \"namespace\": \"ns1\", \"pathname\": \"get\", \"description\": \"Get the current value\", \"params\": [], \"returns\": [ { \"name\": \"output\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\" } } } ], \"details\": { \"stateMutability\": \"viewable\" } }, { \"id\": \"fc6f54ee-2e3c-4e56-b17c-4a1a0ae7394b\", \"interface\": \"c35d3449-4f24-4676-8e64-91c9e46f06c4\", \"name\": \"set\", \"namespace\": \"ns1\", \"pathname\": \"set\", \"description\": \"Set the value\", \"params\": [ { \"name\": \"newValue\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\" } } } ], \"returns\": [], \"details\": { \"stateMutability\": \"payable\" } } ], \"events\": [ { \"id\": \"9f653f93-86f4-45bc-be75-d7f5888fbbc0\", \"interface\": \"c35d3449-4f24-4676-8e64-91c9e46f06c4\", \"namespace\": \"ns1\", \"pathname\": \"Changed\", \"signature\": \"Changed(address,uint256)\", \"name\": \"Changed\", \"description\": \"Emitted when the value changes\", \"params\": [ { \"name\": \"_from\", \"schema\": { \"type\": \"string\", \"details\": { \"type\": \"address\", \"indexed\": true } } }, { \"name\": \"_value\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\" } } } ] } ], \"published\": false } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the FireFly interface (FFI) smart contract definition | UUID | . | message | The UUID of the broadcast message that was used to publish this FFI to the network | UUID | . | namespace | The namespace of the FFI | string | . | name | The name of the FFI - usually matching the smart contract name | 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[] | . | events | An array of smart contract event definitions | FFIEvent[] | . | errors | An array of smart contract error definitions | FFIError[] | . | published | Indicates if the FFI is published to other members of the multiparty network | bool | . ", "url": "/firefly/head/reference/types/ffi.html", "relUrl": "/reference/types/ffi.html" - },"464": { + },"468": { "doc": "FFI", "title": "FFIMethod", "content": "| Field Name | Description | Type | . | id | The UUID of the FFI method definition | UUID | . | interface | The UUID of the FFI smart contract definition that this method is part of | UUID | . | name | The name of the method | string | . | namespace | The namespace of the FFI | string | . | pathname | 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 | string | . | description | A description of the smart contract method | string | . | params | An array of method parameter/argument definitions | FFIParam[] | . | returns | An array of method return definitions | FFIParam[] | . | details | Additional blockchain specific fields about this method from the original smart contract. Used by the blockchain plugin and for documentation generation. | JSONObject | . ", "url": "/firefly/head/reference/types/ffi.html#ffimethod", "relUrl": "/reference/types/ffi.html#ffimethod" - },"465": { + },"469": { "doc": "FFI", "title": "FFIParam", "content": "| Field Name | Description | Type | . | name | The name of the parameter. Note that parameters must be ordered correctly on the FFI, according to the order in the blockchain smart contract | string | . | schema | 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 | JSONAny | . ", "url": "/firefly/head/reference/types/ffi.html#ffiparam", "relUrl": "/reference/types/ffi.html#ffiparam" - },"466": { + },"470": { "doc": "FFI", "title": "FFIEvent", "content": "| Field Name | Description | Type | . | id | The UUID of the FFI event definition | UUID | . | interface | The UUID of the FFI smart contract definition that this event is part of | UUID | . | namespace | The namespace of the FFI | string | . | pathname | 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 | string | . | signature | The stringified signature of the event, as computed by the blockchain plugin | string | . | name | The name of the event | string | . | description | A description of the smart contract event | string | . | params | An array of event parameter/argument definitions | FFIParam[] | . | details | Additional blockchain specific fields about this event from the original smart contract. Used by the blockchain plugin and for documentation generation. | JSONObject | . ", "url": "/firefly/head/reference/types/ffi.html#ffievent", "relUrl": "/reference/types/ffi.html#ffievent" - },"467": { + },"471": { "doc": "FFI", "title": "FFIParam", "content": "| Field Name | Description | Type | . | name | The name of the parameter. Note that parameters must be ordered correctly on the FFI, according to the order in the blockchain smart contract | string | . | schema | 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 | JSONAny | . ", "url": "/firefly/head/reference/types/ffi.html#ffiparam-1", "relUrl": "/reference/types/ffi.html#ffiparam-1" - },"468": { + },"472": { "doc": "FFI", "title": "FFIError", "content": "| Field Name | Description | Type | . | id | The UUID of the FFI error definition | UUID | . | interface | The UUID of the FFI smart contract definition that this error is part of | UUID | . | namespace | The namespace of the FFI | string | . | pathname | The unique name allocated to this error within the FFI for use on URL paths | string | . | signature | The stringified signature of the error, as computed by the blockchain plugin | string | . | name | The name of the error | string | . | description | A description of the smart contract error | string | . | params | An array of error parameter/argument definitions | FFIParam[] | . ", "url": "/firefly/head/reference/types/ffi.html#ffierror", "relUrl": "/reference/types/ffi.html#ffierror" - },"469": { + },"473": { "doc": "FFI", "title": "FFIParam", "content": "| Field Name | Description | Type | . | name | The name of the parameter. Note that parameters must be ordered correctly on the FFI, according to the order in the blockchain smart contract | string | . | schema | 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 | JSONAny | . ", "url": "/firefly/head/reference/types/ffi.html#ffiparam-2", "relUrl": "/reference/types/ffi.html#ffiparam-2" - },"470": { + },"474": { "doc": "fftokens", "title": "fftokens", "content": " ", "url": "/firefly/head/reference/microservices/fftokens.html", "relUrl": "/reference/microservices/fftokens.html" - },"471": { + },"475": { "doc": "fftokens", "title": "Table of contents", "content": ". | fftokens . | Overview | HTTP APIs . | POST /createpool | POST /activatepool | POST /deactivatepool | POST /checkinterface | POST /mint | POST /burn | POST /transfer | POST /approval | . | Websocket Events . | receipt | token-pool | token-mint | token-burn | token-transfer | token-approval | . | Response Types . | Async Request | Receipt | Token Pool | Token Transfer | Token Approval | . | . | . ", "url": "/firefly/head/reference/microservices/fftokens.html#table-of-contents", "relUrl": "/reference/microservices/fftokens.html#table-of-contents" - },"472": { + },"476": { "doc": "fftokens", "title": "Overview", "content": "fftokens is a protocol that can be implemented by token connector runtimes in order to be usable by the fftokens plugin in FireFly. The connector runtime must expose an HTTP and websocket server, along with a minimum set of HTTP APIs and websocket events. Each connector will be strongly coupled to a specific ledger technology and token standard(s), but no assumptions are made in the fftokens spec about what these technologies must be, as long as they can satisfy the basic requirements laid out here. Note that this is an internal protocol in the FireFly ecosystem - application developers working against FireFly should never need to care about or directly interact with a token connector runtime. The audience for this document is only developers interested in creating new token connectors (or editing/forking existing ones). Two implementations of this specification have been created to date (both based on common Ethereum token standards) - firefly-tokens-erc1155 and firefly-tokens-erc20-erc721. ", "url": "/firefly/head/reference/microservices/fftokens.html#overview", "relUrl": "/reference/microservices/fftokens.html#overview" - },"473": { + },"477": { "doc": "fftokens", "title": "HTTP APIs", "content": "This is the minimum set of APIs that must be implemented by a conforming token connector. A connector may choose to expose other APIs for its own purposes. All requests and responses to the APIs below are encoded as JSON. The APIs are currently understood to live under a /api/v1 prefix. POST /createpool . Create a new token pool. The exact meaning of this is flexible - it may mean invoking a contract or contract factory to actually define a new set of tokens via a blockchain transaction, or it may mean indexing a set of tokens that already exists (depending on the options a connector accepts in config). In a multiparty network, this operation will only be performed by one of the parties, and FireFly will broadcast the result to the others. FireFly will store a “pending” token pool after a successful creation, but will replace it with a “confirmed” token pool after a successful activation (see below). Request . { \"type\": \"fungible\", \"signer\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"name\": \"FFCoin\", \"symbol\": \"FFC\", \"data\": \"pool-metadata\", \"requestId\": \"1\", \"config\": {} } . | Parameter | Type | Description | . | type | string enum | The type of pool to create. Currently supported types are “fungible” and “nonfungible”. It is recommended (but not required) that token connectors support both. Unrecognized/unsupported types should be rejected with HTTP 400. | . | signer | string | The signing identity to be used for the blockchain transaction, in a format understood by this connector. | . | name | string | (OPTIONAL) If supported by this token contract, this is a requested name for the token pool. May be ignored at the connector’s discretion. | . | symbol | string | (OPTIONAL) If supported by this token contract, this is a requested symbol for the token pool. May be ignored at the connector’s discretion. | . | requestId | string | (OPTIONAL) A unique identifier for this request. Will be included in the “receipt” websocket event to match receipts to requests. | . | data | string | (OPTIONAL) A data string that should be returned in the connector’s response to this creation request. | . | config | object | (OPTIONAL) An arbitrary JSON object where the connector may accept additional parameters if desired. Each connector may define its own valid options to influence how the token pool is created. | . Response . HTTP 200: pool creation was successful, and the pool details are returned in the response. See Response Types: Token Pool . HTTP 202: request was accepted, but pool will be created asynchronously, with “receipt” and “token-pool” events sent later on the websocket. See Response Types: Async Request . POST /activatepool . Activate a token pool to begin receiving events. Generally this means the connector will create blockchain event listeners for transfer and approval events related to the set of tokens encompassed by this token pool. In a multiparty network, this step will be performed by every member after a successful token pool broadcast. It therefore also serves the purpose of validating the broadcast info - if the connector does not find a valid pool given the poolLocator and config information passed in to this call, the pool should not get confirmed. Request . { \"poolLocator\": \"id=F1\", \"poolData\": \"extra-pool-info\", \"config\": {} } . | Parameter | Type | Description | . | poolLocator | string | The locator of the pool, as supplied by the output of the pool creation. | . | poolData | string | (OPTIONAL) A data string that should be permanently attached to this pool and returned in all events. | . | config | object | (OPTIONAL) An arbitrary JSON object where the connector may accept additional parameters if desired. This should be the same config object that was passed when the pool was created. | . Response . HTTP 200: pool activation was successful, and the pool details are returned in the response. See Response Types: Token Pool . HTTP 202: request was accepted, but pool will be activated asynchronously, with “receipt” and “token-pool” events sent later on the websocket. See Response Types: Async Request . HTTP 204: activation was successful - no separate receipt will be delivered, but “token-pool” event will be sent later on the websocket. No body . POST /deactivatepool . Deactivate a token pool to stop receiving events and delete all blockchain listeners related to that pool. Request . { \"poolLocator\": \"id=F1\", \"poolData\": \"extra-pool-info\", \"config\": {} } . | Parameter | Type | Description | . | poolLocator | string | The locator of the pool, as supplied by the output of the pool creation. | . | poolData | string | (OPTIONAL) The data string that was attached to this pool at activation. | . | config | object | (OPTIONAL) An arbitrary JSON object where the connector may accept additional parameters if desired. | . Response . HTTP 204: deactivation was successful, and one or more listeners were deleted. No body . HTTP 404: no blockchain listeners were found for the given pool information. No body . POST /checkinterface . This is an optional (but recommended) API for token connectors. If implemented, support will be indicated by the presence of the interfaceFormat field in all Token Pool responses. In the case that a connector supports multiple variants of a given token standard (such as many different ways to structure “mint” or “burn” calls on an underlying smart contract), this API allows the connector to be provided with a full description of the interface methods in use for a given token pool, so the connector can determine which methods it knows how to invoke. Request . { \"poolLocator\": \"id=F1\", \"format\": \"abi\", \"methods\": [ { \"name\": \"burn\", \"type\": \"function\", \"inputs\": [ { \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, ... ] } . | Parameter | Type | Description | . | poolLocator | string | The locator of the pool, as supplied by the output of the pool creation. | . | format | string enum | The format of the data in this payload. Should match the interfaceFormat as supplied by the output of the pool creation. | . | methods | object array | A list of all the methods available on the interface underpinning this token pool, encoded in the format specified by format. | . Response . HTTP 200: interface was successfully parsed, and methods of interest are returned in the body. The response body includes a section for each type of token operation (burn/mint/transfer/approval), which specifies a subset of the input body useful to that operation. The caller (FireFly) can then store and provide the proper subset of the interface for every future token operation (via the interface parameter). { \"burn\": { \"format\": \"abi\", \"methods\": [ { \"name\": \"burn\", \"type\": \"function\", \"inputs\": [ { \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" } ] }, \"mint\": { ... }, \"transfer\": { ... }, \"approval\": { ... } } . POST /mint . Mint new tokens. Request . { \"poolLocator\": \"id=F1\", \"signer\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"to\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"amount\": \"10\", \"tokenIndex\": \"1\", \"uri\": \"ipfs://000000\", \"requestId\": \"1\", \"data\": \"transfer-metadata\", \"config\": {}, \"interface\": {} } . | Parameter | Type | Description | . | poolLocator | string | The locator of the pool, as supplied by the output of the pool creation. | . | signer | string | The signing identity to be used for the blockchain transaction, in a format understood by this connector. | . | to | string | The identity to receive the minted tokens, in a format understood by this connector. | . | amount | number string | The amount of tokens to mint. | . | tokenIndex | string | (OPTIONAL) For non-fungible tokens that require choosing an index at mint time, the index of the specific token to mint. | . | uri | string | (OPTIONAL) For non-fungible tokens that support choosing a URI at mint time, the URI to be attached to the token. | . | requestId | string | (OPTIONAL) A unique identifier for this request. Will be included in the “receipt” websocket event to match receipts to requests. | . | data | string | (OPTIONAL) A data string that should be returned in the connector’s response to this mint request. | . | config | object | (OPTIONAL) An arbitrary JSON object where the connector may accept additional parameters if desired. Each connector may define its own valid options to influence how the mint is carried out. | . | interface | object | (OPTIONAL) Details on interface methods that are useful to this operation, as negotiated previously by a /checkinterface call. | . Response . HTTP 202: request was accepted, but mint will occur asynchronously, with “receipt” and “token-mint” events sent later on the websocket. See Response Types: Async Request . POST /burn . Burn tokens. Request . { \"poolLocator\": \"id=F1\", \"signer\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"from\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"amount\": \"10\", \"tokenIndex\": \"1\", \"requestId\": \"1\", \"data\": \"transfer-metadata\", \"config\": {}, \"interface\": {} } . | Parameter | Type | Description | . | poolLocator | string | The locator of the pool, as supplied by the output of the pool creation. | . | signer | string | The signing identity to be used for the blockchain transaction, in a format understood by this connector. | . | from | string | The identity that currently owns the tokens to be burned, in a format understood by this connector. | . | amount | number string | The amount of tokens to burn. | . | tokenIndex | string | (OPTIONAL) For non-fungible tokens, the index of the specific token to burn. | . | requestId | string | (OPTIONAL) A unique identifier for this request. Will be included in the “receipt” websocket event to match receipts to requests. | . | data | string | (OPTIONAL) A data string that should be returned in the connector’s response to this burn request. | . | config | object | (OPTIONAL) An arbitrary JSON object where the connector may accept additional parameters if desired. Each connector may define its own valid options to influence how the burn is carried out. | . | interface | object | (OPTIONAL) Details on interface methods that are useful to this operation, as negotiated previously by a /checkinterface call. | . Response . HTTP 202: request was accepted, but burn will occur asynchronously, with “receipt” and “token-burn” events sent later on the websocket. See Response Types: Async Request . POST /transfer . Transfer tokens from one address to another. Request . { \"poolLocator\": \"id=F1\", \"signer\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"from\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"to\": \"0xb107ed9caa1323b7bc36e81995a4658ec2251951\", \"amount\": \"1\", \"tokenIndex\": \"1\", \"requestId\": \"1\", \"data\": \"transfer-metadata\", \"config\": {}, \"interface\": {} } . | Parameter | Type | Description | . | poolLocator | string | The locator of the pool, as supplied by the output of the pool creation. | . | signer | string | The signing identity to be used for the blockchain transaction, in a format understood by this connector. | . | from | string | The identity to be used for the source of the transfer, in a format understood by this connector. | . | to | string | The identity to be used for the destination of the transfer, in a format understood by this connector. | . | amount | number string | The amount of tokens to transfer. | . | tokenIndex | string | (OPTIONAL) For non-fungible tokens, the index of the specific token to transfer. | . | requestId | string | (OPTIONAL) A unique identifier for this request. Will be included in the “receipt” websocket event to match receipts to requests. | . | data | string | (OPTIONAL) A data string that should be returned in the connector’s response to this transfer request. | . | config | object | (OPTIONAL) An arbitrary JSON object where the connector may accept additional parameters if desired. Each connector may define its own valid options to influence how the transfer is carried out. | . | interface | object | (OPTIONAL) Details on interface methods that are useful to this operation, as negotiated previously by a /checkinterface call. | . Response . HTTP 202: request was accepted, but transfer will occur asynchronously, with “receipt” and “token-transfer” events sent later on the websocket. See Response Types: Async Request . POST /approval . Approve another identity to manage tokens. Request . { \"poolLocator\": \"id=F1\", \"signer\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"operator\": \"0xb107ed9caa1323b7bc36e81995a4658ec2251951\", \"approved\": true, \"requestId\": \"1\", \"data\": \"approval-metadata\", \"config\": {}, \"interface\": {} } . | Parameter | Type | Description | . | poolLocator | string | The locator of the pool, as supplied by the output of the pool creation. | . | signer | string | The signing identity to be used for the blockchain transaction, in a format understood by this connector. | . | operator | string | The identity to be approved (or unapproved) for managing the signer’s tokens. | . | approved | boolean | Whether to approve (the default) or unapprove. | . | requestId | string | (OPTIONAL) A unique identifier for this request. Will be included in the “receipt” websocket event to match receipts to requests. | . | data | string | (OPTIONAL) A data string that should be returned in the connector’s response to this approval request. | . | config | object | (OPTIONAL) An arbitrary JSON object where the connector may accept additional parameters if desired. Each connector may define its own valid options to influence how the approval is carried out. | . | interface | object | (OPTIONAL) Details on interface methods that are useful to this operation, as negotiated previously by a /checkinterface call. | . Response . HTTP 202: request was accepted, but approval will occur asynchronously, with “receipt” and “token-approval” events sent later on the websocket. See Response Types: Async Request . ", "url": "/firefly/head/reference/microservices/fftokens.html#http-apis", "relUrl": "/reference/microservices/fftokens.html#http-apis" - },"474": { + },"478": { "doc": "fftokens", "title": "Websocket Events", "content": "A connector should expose a websocket at /api/ws. All emitted websocket events are a JSON string of the form: . { \"id\": \"event-id\", \"event\": \"event-name\", \"data\": {} } . The event name will match one of the names listed below, and the data payload will correspond to the linked response object. All events except the receipt event must be acknowledged by sending an ack of the form: . { \"event\": \"ack\", \"data\": { \"id\": \"event-id\" } } . Many messages may also be batched into a single websocket event of the form: . { \"id\": \"event-id\", \"event\": \"batch\", \"data\": { \"events\": [ { \"event\": \"event-name\", \"data\": {} }, ... ] } } . Batched messages must be acked all at once using the ID of the batch. receipt . An asynchronous operation has completed. See Response Types: Receipt . token-pool . A new token pool has been created or activated. See Response Types: Token Pool . token-mint . Tokens have been minted. See Response Types: Token Transfer . token-burn . Tokens have been burned. See Response Types: Token Transfer . token-transfer . Tokens have been transferred. See Response Types: Token Transfer . token-approval . Token approvals have changed. See Response Types: Token Approval . ", "url": "/firefly/head/reference/microservices/fftokens.html#websocket-events", "relUrl": "/reference/microservices/fftokens.html#websocket-events" - },"475": { + },"479": { "doc": "fftokens", "title": "Response Types", "content": "Async Request . Many operations may happen asynchronously in the background, and will return only a request ID. This may be a request ID that was passed in, or if none was passed, will be randomly assigned. This ID can be used to correlate with a receipt event later received on the websocket. { \"id\": \"b84ab27d-0d50-42a6-9c26-2fda5eb901ba\" } . Receipt . \"headers\": { \"type\": \"\", \"requestId\": \"\" } \"transactionHash\": \"\", \"errorMessage\": \"\" } . | Parameter | Type | Description | . | headers.type | string enum | The type of this response. Should be “TransactionSuccess”, “TransactionUpdate”, or “TransactionFailed”. | . | headers.requestId | string | The ID of the request to which this receipt should correlate. | . | transactionHash | string | The unique identifier for the blockchain transaction which generated this receipt. | . | errorMessage | string | (OPTIONAL) If this is a failure, contains details on the reason for the failure. | . Token Pool . { \"type\": \"fungible\", \"data\": \"pool-metadata\", \"poolLocator\": \"id=F1\", \"standard\": \"ERC20\", \"interfaceFormat\": \"abi\", \"symbol\": \"FFC\", \"decimals\": 18, \"info\": {}, \"signer\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"blockchain\": {} } . | Parameter | Type | Description | . | type | string enum | The type of pool that was created. | . | data | string | A copy of the data that was passed in on the creation request. | . | poolLocator | string | A string to identify this pool, generated by the connector. Must be unique for each pool created by this connector. Will be passed back on all operations within this pool, and may be packed with relevant data about the pool for later usage (such as the address and type of the pool). | . | standard | string | (OPTIONAL) The name of a well-defined token standard to which this pool conforms. | . | interfaceFormat | string enum | (OPTIONAL) If this connector supports the /checkinterface API, this is the interface format to be used for describing the interface underpinning this pool. Must be “abi” or “ffi”. | . | symbol | string | (OPTIONAL) The symbol for this token pool, if applicable. | . | decimals | number | (OPTIONAL) The number of decimals used for balances in this token pool, if applicable. | . | info | object | (OPTIONAL) Additional information about the pool. Each connector may define the format for this object. | . | signer | string | (OPTIONAL) If this operation triggered a blockchain transaction, the signing identity used for the transaction. | . | blockchain | object | (OPTIONAL) If this operation triggered a blockchain transaction, contains details on the blockchain event in FireFly’s standard blockchain event format. | . Token Transfer . Note that mint and burn operations are just specialized versions of transfer. A mint will omit the “from” field, while a burn will omit the “to” field. { \"id\": \"1\", \"data\": \"transfer-metadata\", \"poolLocator\": \"id=F1\", \"poolData\": \"extra-pool-info\", \"from\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"to\": \"0xb107ed9caa1323b7bc36e81995a4658ec2251951\", \"amount\": \"1\", \"tokenIndex\": \"1\", \"uri\": \"ipfs://000000\", \"signer\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"blockchain\": {} } . | Parameter | Type | Description | . | id | string | An identifier for this transfer. Must be unique for every transfer within this pool. | . | data | string | A copy of the data that was passed in on the mint/burn/transfer request. May be omitted if the token contract does not support a method of attaching extra data (will result in reduced ability for FireFly to correlate the inputs and outputs of the transaction). | . | poolLocator | string | The locator of the pool, as supplied by the output of the pool creation. | . | poolData | string | The extra data associated with the pool at pool activation. | . | from | string | The identity used for the source of the transfer. | . | to | string | The identity used for the destination of the transfer. | . | amount | number string | The amount of tokens transferred. | . | tokenIndex | string | (OPTIONAL) For non-fungible tokens, the index of the specific token transferred. | . | uri | string | (OPTIONAL) For non-fungible tokens, the URI attached to the token. | . | signer | string | (OPTIONAL) If this operation triggered a blockchain transaction, the signing identity used for the transaction. | . | blockchain | object | (OPTIONAL) If this operation triggered a blockchain transaction, contains details on the blockchain event in FireFly’s standard blockchain event format. | . Token Approval . { \"id\": \"1\", \"data\": \"transfer-metadata\", \"poolLocator\": \"id=F1\", \"poolData\": \"extra-pool-info\", \"operator\": \"0xb107ed9caa1323b7bc36e81995a4658ec2251951\", \"approved\": true, \"subject\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A:0xb107ed9caa1323b7bc36e81995a4658ec2251951\", \"info\": {}, \"signer\": \"0x0Ef1D0Dd56a8FB1226C0EaC374000B81D6c8304A\", \"blockchain\": {} } . | Parameter | Type | Description | . | id | string | An identifier for this approval. Must be unique for every approval within this pool. | . | data | string | A copy of the data that was passed in on the approval request. May be omitted if the token contract does not support a method of attaching extra data (will result in reduced ability for FireFly to correlate the inputs and outputs of the transaction). | . | poolLocator | string | The locator of the pool, as supplied by the output of the pool creation. | . | poolData | string | The extra data associated with the pool at pool activation. | . | operator | string | The identity that was approved (or unapproved) for managing tokens. | . | approved | boolean | Whether this was an approval or unapproval. | . | subject | string | A string identifying the scope of the approval, generated by the connector. Approvals with the same subject are understood replace one another, so that a previously-recorded approval becomes inactive. This string may be a combination of the identities involved, the token index, etc. | . | info | object | (OPTIONAL) Additional information about the approval. Each connector may define the format for this object. | . | signer | string | (OPTIONAL) If this operation triggered a blockchain transaction, the signing identity used for the transaction. | . | blockchain | object | (OPTIONAL) If this operation triggered a blockchain transaction, contains details on the blockchain event in FireFly’s standard blockchain event format. | . ", "url": "/firefly/head/reference/microservices/fftokens.html#response-types", "relUrl": "/reference/microservices/fftokens.html#response-types" - },"476": { + },"480": { "doc": "① Install the FireFly CLI", "title": "① Install the FireFly CLI", "content": " ", "url": "/firefly/head/gettingstarted/firefly_cli.html", "relUrl": "/gettingstarted/firefly_cli.html" - },"477": { + },"481": { "doc": "① Install the FireFly CLI", "title": "Table of contents", "content": ". | ① Install the FireFly CLI . | Prerequisites . | Linux Users | Windows Users | . | Install the CLI . | Download the package for your OS | Extract the binary and move it to /usr/bin/local | macOSUsers | Alternative installation method: Install via Go | . | Verify the installation | Next steps: Start your environment | . | . ", "url": "/firefly/head/gettingstarted/firefly_cli.html#table-of-contents", "relUrl": "/gettingstarted/firefly_cli.html#table-of-contents" - },"478": { + },"482": { "doc": "① Install the FireFly CLI", "title": "Prerequisites", "content": "In order to run the FireFly CLI, you will need a few things installed on your dev machine: . | Docker | Docker Compose | openssl | . Linux Users . NOTE: For Linux users, it is recommended that you add your user to the docker group so that you do not have to run ff or docker as root or with sudo. For more information about Docker permissions on Linux, please see Docker’s documentation on the topic. Windows Users . NOTE: For Windows users, we recommend that you use Windows Subsystem for Linux 2 (WSL2). Binaries provided for Linux will work in this environment. ", "url": "/firefly/head/gettingstarted/firefly_cli.html#prerequisites", "relUrl": "/gettingstarted/firefly_cli.html#prerequisites" - },"479": { + },"483": { "doc": "① Install the FireFly CLI", "title": "Install the CLI", "content": "There are several ways to install the FireFly CLI. The easiest way to get up and running with the FireFly CLI is to download a pre-compiled binary of the latest release. Download the package for your OS . Go to the latest release page and download the package for your OS and CPU architecture. Extract the binary and move it to /usr/bin/local . Assuming you downloaded the package from GitHub into your Downloads directory, run the following command: . sudo tar -zxf ~/Downloads/firefly-cli_*.tar.gz -C /usr/local/bin ff && rm ~/Downloads/firefly-cli_*.tar.gz . If you downloaded the package from GitHub into a different directory, you will need to change the tar command above to wherever the firefly-cli_*.tar.gz file is located. macOSUsers . NOTE: On recent versions of macOS, default security settings will prevent the FireFly CLI binary from running, because it was downloaded from the internet. You will need to allow the FireFly CLI in System Preferences, before it will run. Alternative installation method: Install via Go . If you have a local Go development environment, and you have included ${GOPATH}/bin in your path, you could also use Go to install the FireFly CLI by running: . go install github.com/hyperledger/firefly-cli/ff@latest . ", "url": "/firefly/head/gettingstarted/firefly_cli.html#install-the-cli", "relUrl": "/gettingstarted/firefly_cli.html#install-the-cli" - },"480": { + },"484": { "doc": "① Install the FireFly CLI", "title": "Verify the installation", "content": "After using either installation method above, you can verify that the CLI is successfully installed by running ff version. This should print the current version like this: . { \"Version\": \"v0.0.47\", \"License\": \"Apache-2.0\" } . ", "url": "/firefly/head/gettingstarted/firefly_cli.html#verify-the-installation", "relUrl": "/gettingstarted/firefly_cli.html#verify-the-installation" - },"481": { + },"485": { "doc": "① Install the FireFly CLI", "title": "Next steps: Start your environment", "content": "Now that you’ve got the FireFly CLI set up on your machine, the next step is to create and start a FireFly stack. ② Start your environment → . ", "url": "/firefly/head/gettingstarted/firefly_cli.html#next-steps-start-your-environment", "relUrl": "/gettingstarted/firefly_cli.html#next-steps-start-your-environment" - },"482": { + },"486": { "doc": "FireFly Interface Format", "title": "FireFly Interface Format", "content": "FireFly defines a common, blockchain agnostic way to describe smart contracts. This is referred to as a Contract Interface, and it is written in the FireFly Interface (FFI) format. It is a simple JSON document that has a name, a namespace, a version, a list of methods, and a list of events. ", "url": "/firefly/head/reference/firefly_interface_format.html", "relUrl": "/reference/firefly_interface_format.html" - },"483": { + },"487": { "doc": "FireFly Interface Format", "title": "Table of contents", "content": ". | Overview | Method | Event | Param . | Schema | Schema details | . | Automated generation of FireFly Interfaces | Full Example | . ", "url": "/firefly/head/reference/firefly_interface_format.html#table-of-contents", "relUrl": "/reference/firefly_interface_format.html#table-of-contents" - },"484": { + },"488": { "doc": "FireFly Interface Format", "title": "Overview", "content": "There are four required fields when broadcasting a contract interface in FireFly: a name, a version, a list of methods, and a list of events. A namespace field will also be filled in automatically based on the URL path parameter. Here is an example of the structure of the required fields: . { \"name\": \"example\", \"version\": \"v1.0.0\", \"methods\": [], \"events\": [] } . NOTE: Contract interfaces are scoped to a namespace. Within a namespace each contract interface must have a unique name and version combination. The same name and version combination can exist in different namespaces simultaneously. ", "url": "/firefly/head/reference/firefly_interface_format.html#overview", "relUrl": "/reference/firefly_interface_format.html#overview" - },"485": { + },"489": { "doc": "FireFly Interface Format", "title": "Method", "content": "Let’s look at a what goes inside the methods array now. It is also a JSON object that has a name, a list of params which are the arguments the function will take and a list of returns which are the return values of the function. It also has an optional description which can be helpful in OpenAPI Spec generation. Finally, it has an optional details object which wraps blockchain specific information about this method. This can be used by the blockchain plugin when invoking this function, and it is also used in documentation generation. { \"name\": \"add\", \"description\": \"Add two numbers together\", \"params\": [], \"returns\": [], \"details\": {} } . ", "url": "/firefly/head/reference/firefly_interface_format.html#method", "relUrl": "/reference/firefly_interface_format.html#method" - },"486": { + },"490": { "doc": "FireFly Interface Format", "title": "Event", "content": "What goes into the events array is very similar. It is also a JSON object that has a name and a list of params. The difference is that events don’t have returns. Arguments that are passed to the event when it is emitted are in params. It also has an optional description which can be helpful in OpenAPI Spec generation. Finally, it has an optional details object which wraps blockchain specific information about this event. This can be used by the blockchain plugin when invoking this function, and it is also used in documentation generation. { \"name\": \"added\", \"description\": \"An event that occurs when numbers have been added\", \"params\": [], \"details\": {} } . ", "url": "/firefly/head/reference/firefly_interface_format.html#event", "relUrl": "/reference/firefly_interface_format.html#event" - },"487": { + },"491": { "doc": "FireFly Interface Format", "title": "Param", "content": "Both methods, and events have lists of params or returns, and the type of JSON object that goes in each of these arrays is the same. It is simply a JSON object with a name and a schema. There is also an optional details field that is passed to the blockchain plugin for blockchain specific requirements. { \"name\": \"x\", \"schema\": { \"type\": \"integer\", \"details\": {} } } . Schema . The param schema is an important field which tells FireFly the type information about this particular field. This is used in several different places, such as OpenAPI Spec generation, API request validation, and blockchain request preparation. The schema field accepts JSON Schema (version 2020-12) with several additional requirements: . | A type field is always mandatory | The list of valid types is: . | boolean | integer | string | object | array | . | Blockchain plugins can add their own specific requirements to this list of validation rules | . NOTE: Floats or decimals are not currently accepted because certain underlying blockchains (e.g. Ethereum) only allow integers . The type field here is the JSON input type when making a request to FireFly to invoke or query a smart contract. This type can be different from the actual blockchain type, usually specified in the details field, if there is a compatible type mapping between the two. Schema details . The details field is quite important in some cases. Because the details field is passed to the blockchain plugin, it is used to encapsulate blockchain specific type information about a particular field. Additionally, because each blockchain plugin can add rules to the list of schema requirements above, a blockchain plugin can enforce that certain fields are always present within the details field. For example, the Ethereum plugin always needs to know what Solidity type the field is. It also defines several optional fields. A full Ethereum details field may look like: . { \"type\": \"uint256\", \"internalType\": \"uint256\", \"indexed\": false } . ", "url": "/firefly/head/reference/firefly_interface_format.html#param", "relUrl": "/reference/firefly_interface_format.html#param" - },"488": { + },"492": { "doc": "FireFly Interface Format", "title": "Automated generation of FireFly Interfaces", "content": "A convenience endpoint exists on the API to facilitate converting from native blockchain interface formats such as an Ethereum ABI to the FireFly Interface format. For details, please see the API documentation for the contract interface generation endpoint. For an example of using this endpoint with a specific Ethereum contract, please see the Tutorial to Work with custom smart contracts. ", "url": "/firefly/head/reference/firefly_interface_format.html#automated-generation-of-firefly-interfaces", "relUrl": "/reference/firefly_interface_format.html#automated-generation-of-firefly-interfaces" - },"489": { + },"493": { "doc": "FireFly Interface Format", "title": "Full Example", "content": "Putting it all together, here is a full example of the FireFly Interface format with all the fields filled in: . { \"namespace\": \"default\", \"name\": \"SimpleStorage\", \"description\": \"A simple smart contract that stores and retrieves an integer on-chain\", \"version\": \"v1.0.0\", \"methods\": [ { \"name\": \"get\", \"description\": \"Retrieve the value of the stored integer\", \"params\": [], \"returns\": [ { \"name\": \"output\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ], \"details\": { \"stateMutability\": \"viewable\" } }, { \"name\": \"set\", \"description\": \"Set the stored value on-chain\", \"params\": [ { \"name\": \"newValue\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ], \"returns\": [], \"details\": { \"stateMutability\": \"payable\" } } ], \"events\": [ { \"name\": \"Changed\", \"description\": \"An event that is fired when the stored integer value changes\", \"params\": [ { \"name\": \"from\", \"schema\": { \"type\": \"string\", \"details\": { \"type\": \"address\", \"internalType\": \"address\", \"indexed\": true } } }, { \"name\": \"value\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"uint256\", \"internalType\": \"uint256\" } } } ], \"details\": {} } ] } . ", "url": "/firefly/head/reference/firefly_interface_format.html#full-example", "relUrl": "/reference/firefly_interface_format.html#full-example" - },"490": { + },"494": { "doc": "pages.flows", "title": "Flows", "content": ". ", "url": "/firefly/head/overview/key_components/flows.html#flows", "relUrl": "/overview/key_components/flows.html#flows" - },"491": { + },"495": { "doc": "pages.flows", "title": "Data flow", "content": "The reality of most Web3 scenarios is that only a small part of the overall use-case can be represented inside the blockchain or distributed ledger technology. Some additional data flow is always required. This does not diminish the value of executing the kernel of the logic within the blockchain itself. Hyperledger FireFly embraces this reality, and allows an organization to keep track of the relationship between the off-chain data flow, and the on-chain transactions. Let’s look at a few common examples: . Digital Asset Transfers . Examples of common data flows performed off-chain, include Know Your Customer (KYC) and Anti Money Laundering (AML) checks that need to be performed and validated before participating in transactions. There might also be document management and business transaction flows required to verify the conditions are correct to digitally settle a transaction. Have the goods been delivered? Are the contracts in place? . In regulated enterprise scenarios it is common to see a 10-to-1 difference in the number of steps performed off-chain to complete a business transaction, vs. the number of steps performed on-chain. These off-chain data flows might be coordinated with on-chain smart contracts that lock assets in digital escrow until the off-chain steps are completed by each party, and protect each party while the steps are being completed. A common form of digital escrow is a Hashed Timelock Contract (HTLC). Non-fungible Tokens (NFTs) and hash-pinning . The data associated with an NFT might be as simple as a JSON document pointing at an interesting piece of artwork, or as complex a set of high resolution scans / authenticity documents representing a digital twin of a real world object. Here the concept of a hash pinning is used - allowing anyone who has a copy of the original data to recreate the hash that is stored in the on-chain record. With even the simplest NFT the business data is not stored on-chain, so simple data flow is always required to publish/download the off-chain data. The data might be published publicly for anyone to download, or it might be sensitive and require a detailed permissioning flow to obtain it from a current holder of that data. Dynamic NFTs and Business Transaction Flow . In an enterprise context, an NFT might have a dynamic ever-evolving trail of business transaction data associated with it. Different parties might have different views of that business data, based on their participation in the business transactions associated with it. Here the NFT becomes a like a foreign key integrated across the core systems of a set of enterprises working together in a set of business transactions. The data itself needs to be downloaded, retained, processed and rendered. Probably integrated to systems, acted upon, and used in multiple exchanges between companies on different blockchains, or off-chain. The business process is accelerated through this Enterprise NFT on the blockchain - as all parties have matched or bound their own private data store to that NFT. This means they are confident to be executing a business transaction against the same person or thing in the world. Data and Transaction Flow patterns . Hyperledger FireFly provides the raw tools for building data and transaction flow patterns, such as storing, hashing and transferring data. It provides the event bus to trigger off-chain applications and integration to participate in the flows. It also provides the higher level flow capabilities that are needed for multiple parties to build sophisticated transaction flows together, massively simplifying the application logic required: . | Coordinating the transfer of data off-chain with a blockchain sequencing transaction | Batching for high throughput transfer via the blockchain and distributed storage technologies | Managing privacy groups between parties involved in a business transaction | Masking the relationship between blockchain transactions, for sensitive data | . Learn more in Multiparty Process Flows . ", "url": "/firefly/head/overview/key_components/flows.html#data-flow", "relUrl": "/overview/key_components/flows.html#data-flow" - },"492": { + },"496": { "doc": "pages.flows", "title": "pages.flows", "content": " ", "url": "/firefly/head/overview/key_components/flows.html", "relUrl": "/overview/key_components/flows.html" - },"493": { + },"497": { "doc": "pages.web3_gateway_features", "title": "Web3 Gateway Features", "content": " ", "url": "/firefly/head/overview/gateway_features.html#web3-gateway-features", "relUrl": "/overview/gateway_features.html#web3-gateway-features" - },"494": { + },"498": { "doc": "pages.web3_gateway_features", "title": "Table of contents", "content": ". | Transfer tokenized value | Invoke any other type of smart contract | Index data from the blockchain | Reliably trigger events in your applications | Manage decentralized data (NFTs etc.) | Maintain a private address book | . Web3 Gateway features allow your FireFly Supernode to connect to any blockchain ecosystem, public or private. When a chain is connected, the FireFly Supernode may invoke custom smart contracts, interact with tokens, and monitor transactions. A single FireFly Supernode is able to have multiple namespaces, or isolated environments, where each namespace is a connection to a different chain. ", "url": "/firefly/head/overview/gateway_features.html#table-of-contents", "relUrl": "/overview/gateway_features.html#table-of-contents" - },"495": { + },"499": { "doc": "pages.web3_gateway_features", "title": "Transfer tokenized value", "content": "The Digital Asset Features allow you to connect to token economies, in multiple blockchains, using the same infrastructure and signing keys. The complexities of how each token works, and how each blockchain works, are abstracted away from you by the Hyperledger FireFly Connector Framework. All of the layers of plumbing required to execute a transaction exactly once on a blockchain, and tracking it through to completion, are part of the stack. Deploy and configure them once in your Web3 gateway, and use them for multiple use cases in your enterprise. ", "url": "/firefly/head/overview/gateway_features.html#transfer-tokenized-value", "relUrl": "/overview/gateway_features.html#transfer-tokenized-value" - },"496": { + },"500": { "doc": "pages.web3_gateway_features", "title": "Invoke any other type of smart contract", "content": "The API Generation features of Hyperledger FireFly, allow you to generate a convenient and reliable REST API for any smart contract logic. Then you just invoke that contract like you would any other API, with all the features you would expect like an OpenAPI 3.0 specification for the API, and UI explorer. The same reliable transaction submission framework is used as for token transfers, and you can use Hyperledger FireFly as a high volume staging post for those transactions. | Handles peaks in workload, drip-feeding transactions onto the chain | Handles large batch submissions, tracking | Manages nonce assignment at high volume | Idempotent APIs assuring that business transactions are submitted exactly once | . For EVM based chains, these features were significantly enhanced in the new EVMConnect connector introduced in v1.1 of FireFly (superseding EthConnect). ", "url": "/firefly/head/overview/gateway_features.html#invoke-any-other-type-of-smart-contract", "relUrl": "/overview/gateway_features.html#invoke-any-other-type-of-smart-contract" - },"497": { + },"501": { "doc": "pages.web3_gateway_features", "title": "Index data from the blockchain", "content": "Blockchain nodes are not designed for efficient querying of historical information. Instead their core function is to provide an ordered ledger of actions+events, along with a consistent world state at any point in time. This means that almost all user experiences and business APIs need a separate data store, that provides an fast indexed view of the history and current state of the chain. As an example, you’ve probably looked at a Block Explorer for a public blockchain on the web. Well, you weren’t looking directly at the blockchain node. You were querying an off-chain indexed database, of all the blocks and transactions on that chain. An indexer behind the scenes was listening to the blockchain and synchronizing the off-chain state. Hyperledger FireFly has a built-in indexer for tokens, that maps every token mint/burn/transfer/approve operation that happens on the the blockchain into the database for fast query. You just specify which tokens you’re interested in, and FireFly takes care of the rest. Additionally, FireFly does the heavy lifting part of indexing for all other types of smart contract event that might occur. It scrapes the blockchain for the events, formats them into easy to consume JSON, and reliably delivers them to your application. So your application just needs a small bit of code to take those payloads, and insert them into the database with the right database indexes you need to query your data by. ", "url": "/firefly/head/overview/gateway_features.html#index-data-from-the-blockchain", "relUrl": "/overview/gateway_features.html#index-data-from-the-blockchain" - },"498": { + },"502": { "doc": "pages.web3_gateway_features", "title": "Reliably trigger events in your applications", "content": "One of the most important universal rules about Web3 applications, is that they are event-driven. No one party in the system can chose to change the state, instead they must submit transactions that get ordered against everyone else’s transactions, and only once confirmed through the consensus algorithm are they actioned. This means the integration into your application and core systems needs to be event-driven too. The same features that support reliable indexing of the blockchain data, allow reliable triggering of application code, business workflows, and core system integrations. Learn more about the FireFly Event Bus . ", "url": "/firefly/head/overview/gateway_features.html#reliably-trigger-events-in-your-applications", "relUrl": "/overview/gateway_features.html#reliably-trigger-events-in-your-applications" - },"499": { + },"503": { "doc": "pages.web3_gateway_features", "title": "Manage decentralized data (NFTs etc.)", "content": "Your blockchain transactions are likely to refer to data that is stored off-chain. One common example is non-fungible-token (NFT) metadata, images and documents. These are not a good fit for storing directly in any blockchain ledger, so complimentary decentralized technologies like the InterPlanetary File System (IPFS) are used to make the data widely available and resilient outside of the blockchain itself. As a publisher or consumer of such metadata from decentralized storage, you need to be confident you have your own copy safe. So just like with the blockchain data, Hyperledger FireFly can act as a staging post for this data. Structured JSON data can be stored, uploaded and downloaded from the FireFly database. Large image/document/video payloads are handled by the pluggable Data Exchange microservice, which allows you to attach local or cloud storage to manage your copy of the data. FireFly then provides a standardized API to allow publishing of this data. So configuring a reliable gateway to the decentralized storage tier can be done once, and then accessed from your applications via a single Web3 Gateway. ", "url": "/firefly/head/overview/gateway_features.html#manage-decentralized-data-nfts-etc", "relUrl": "/overview/gateway_features.html#manage-decentralized-data-nfts-etc" - },"500": { + },"504": { "doc": "pages.web3_gateway_features", "title": "Maintain a private address book", "content": "You need to manage your signing keys, and know the signing keys of others you are transacting with. A blockchain address like 0x0742e81393ee79C768e84cF57F1bF314F0f31ECe is not very helpful for this. So Hyperledger FireFly provides a pluggable identity system, built on the foundation of the Decentralized IDentifier (DID). When in Web3 Gateway Mode these identities are not shared or published, and simply provide you a local address book. You can associate profile information with the identities, for example correlating them to the identifiers in your own core systems - such as an Identity and Access Management (IAM) system, or Know Your Customer (KYC) database. Learn more about Hyperledger FireFly Identities . ", "url": "/firefly/head/overview/gateway_features.html#maintain-a-private-address-book", "relUrl": "/overview/gateway_features.html#maintain-a-private-address-book" - },"501": { + },"505": { "doc": "pages.web3_gateway_features", "title": "pages.web3_gateway_features", "content": " ", "url": "/firefly/head/overview/gateway_features.html", "relUrl": "/overview/gateway_features.html" - },"502": { + },"506": { "doc": "Group", "title": "Group", "content": " ", "url": "/firefly/head/reference/types/group.html", "relUrl": "/reference/types/group.html" - },"503": { + },"507": { "doc": "Group", "title": "Table of contents", "content": ". | Group . | Group identity hash | Private messaging architecture | Example | Field Descriptions | . | Member | . ", "url": "/firefly/head/reference/types/group.html#table-of-contents", "relUrl": "/reference/types/group.html#table-of-contents" - },"504": { + },"508": { "doc": "Group", "title": "Group", "content": "A privacy group is a list of identities that should receive a private communication. When you send a private message, you can specify the list of participants in-line and it will be resolved to a group. Or you can reference the group using its identifying hash. The sender of a message must be included in the group along with the other participants. The sender receives an event confirming the message, just as any other participant would do. The sender is included automatically in the group when members are specified in-line, if it is omitted. Group identity hash . The identifying hash for a group is determined as follows: . | All identities are resolved to their DID. | An organization name or identity UUID can be used on input | . | The UUID of the node that should receive the data for each participant is determined (if not specified). | The first node found that is in the same identity hierarchy as the participant identity, will be chosen. | . | The list of participants is ordered by DID, with de-duplication of any identities. | The namespace, name, and members array are then serialized into a JSON object, without whitespace. | A SHA256 hash of the JSON object is calculated | . Private messaging architecture . The mechanism that keeps data private and ordered, without leaking data to the blockchain, is summarized in the below diagram. The key points are: . | Data is sent off-chain to all participants via the Data Exchange plugin . | The Data Exchange is responsible for encryption and off-chain identity verification | . | Only parties that are involved in the privacy group receive the data . | Other parties are only able to view the blockchain transaction | . | The hash and member list of the group are not shared outside of the privacy group . | The name of the group can be used as an additional salt in generation of the group hash | The member list must be known by all members of the group to verify the blockchain transactions, so the full group JSON structure is communicated privately with the first message sent on a group | . | The blockchain transaction is the source of truth for ordering . | All members are able to detect a blockchain transaction is part of a group they are a member of, from only the blockchain transaction - so they can block processing of subsequent messages until the off-chain data arrives (asynchronously) | . | The ordering context for messages is masked on the blockchain, so that two messages that are for same group do not contain the same context . | The ordering context (topic+group) is combined with a nonce that is incremented for each individual sender, to form a message-specific hash. | For each blockchain transaction, this hash can be compared against the expected next hash for each member to determine if it is a message on a known group - even without the private data (which might arrive later) | . | . See NextPin for more information on the structure used for storing the next expected masked context pin, for each member of the privacy group. Example . { \"namespace\": \"ns1\", \"name\": \"\", \"members\": [ { \"identity\": \"did:firefly:org/1111\", \"node\": \"4f563179-b4bd-4161-86e0-c2c1c0869c4f\" }, { \"identity\": \"did:firefly:org/2222\", \"node\": \"61a99af8-c1f7-48ea-8fcc-489e4822a0ed\" } ], \"localNamespace\": \"ns1\", \"message\": \"0b9dfb76-103d-443d-92fd-b114fe07c54d\", \"hash\": \"c52ad6c034cf5c7382d9a294f49297096a52eb55cc2da696c564b2a276633b95\", \"created\": \"2022-05-16T01:23:16Z\" } . Field Descriptions . | Field Name | Description | Type | . | namespace | The namespace of the group within the multiparty network | string | . | name | The optional name of the group, allowing multiple unique groups to exist with the same list of recipients | string | . | members | The list of members in this privacy group | Member[] | . | localNamespace | The local namespace of the group | string | . | message | The message used to broadcast this group privately to the members | UUID | . | hash | The identifier hash of this group. Derived from the name and group members | Bytes32 | . | created | The time when the group was first used to send a message in the network | FFTime | . ", "url": "/firefly/head/reference/types/group.html", "relUrl": "/reference/types/group.html" - },"505": { + },"509": { "doc": "Group", "title": "Member", "content": "| Field Name | Description | Type | . | identity | The DID of the group member | string | . | node | The UUID of the node that receives a copy of the off-chain message for the identity | UUID | . ", "url": "/firefly/head/reference/types/group.html#member", "relUrl": "/reference/types/group.html#member" - },"506": { + },"510": { "doc": "Idempotency Keys", "title": "Idempotency Keys", "content": " ", "url": "/firefly/head/reference/idempotency.html", "relUrl": "/reference/idempotency.html" - },"507": { + },"511": { "doc": "Idempotency Keys", "title": "Table of contents", "content": ". | Idempotency | FireFly Idempotency Keys | Operation Idempotency | Short term retry | Administrative operation retry | . ", "url": "/firefly/head/reference/idempotency.html#table-of-contents", "relUrl": "/reference/idempotency.html#table-of-contents" - },"508": { + },"512": { "doc": "Idempotency Keys", "title": "Idempotency", "content": "The transaction submission REST APIs of Hyperledger FireFly are idempotent. Idempotent APIs allow an application to safely submit a request multiple times, and for the transaction to only be accepted and executed once. This is the well accepted approach for REST APIs over HTTP/HTTPS to achieve resilience, as HTTP requests can fail in indeterminate ways. For example in a request or gateway timeout situation, the requester is unable to know whether the request will or will not eventually be processed. There are various types of FireFly transaction that can be submitted. These include direct submission of blockchain transactions to a smart contract, as well as more complex transactions including coordination of multiple operations across on-chain and off-chain connectors. In order for Hyperledger FireFly to deduplicate transactions, and make them idempotent, the application must supply an idempotencyKey on each API request. ", "url": "/firefly/head/reference/idempotency.html#idempotency", "relUrl": "/reference/idempotency.html#idempotency" - },"509": { + },"513": { "doc": "Idempotency Keys", "title": "FireFly Idempotency Keys", "content": ". The caller of the API specifies its own unique identifier (an arbitrary string up to 256 characters) that uniquely identifies the request, in the idempotencyKey field of the API. So if there is a network connectivity failure, or an abrupt termination of either runtime, the application can safely attempt to resubmit the REST API call and be returned a 409 Conflict HTTP code. Examples of how an app might construct such an idempotencyKey include: . | Unique business identifiers from the request that comes into its API up-stream - passing idempotency along the chain | A hash of the business unique data that relates to the request - maybe all the input data of a blockchain transaction for example, if that payload is guaranteed to be unique. Be careful of cases where the business data might not be unique - like a transfer of 10 coins from A to B. Such a transfer could happen multiple times, and each would be a separate business transaction. Where as transfer with invoice number abcd1234 of 10 coins from A to B would be assured to be unique. | A unique identifier of a business transaction generated within the application and stored in its database before submission This moves the challenge up one layer into your application. How does that unique ID get generated? Is that itself idempotent? . | . ", "url": "/firefly/head/reference/idempotency.html#firefly-idempotency-keys", "relUrl": "/reference/idempotency.html#firefly-idempotency-keys" - },"510": { + },"514": { "doc": "Idempotency Keys", "title": "Operation Idempotency", "content": "FireFly provides an idempotent interface downstream to connectors. Each operation within a FireFly transaction receives a unique ID within the overall transaction that is used as an idempotency key when invoking that connector. Well formed connectors honor this idempotency key internally, ensuring that the end-to-end transaction submission is idempotent. Key examples of such connectors are EVMConnect and others built on the Blockchain Connector Toolkit. When an operation is retried automatically, the same idempotency key is re-used to avoid resubmission. ", "url": "/firefly/head/reference/idempotency.html#operation-idempotency", "relUrl": "/reference/idempotency.html#operation-idempotency" - },"511": { + },"515": { "doc": "Idempotency Keys", "title": "Short term retry", "content": "The FireFly core uses standard HTTP request code to communicate with all connector APIs. This code include exponential backoff retry, that can be enabled with a simple boolean in the plugin of FireFly core. The minimum retry, maximum retry, and backoff factor can be tuned individually as well on each connector. See Configuration Reference for more information. ", "url": "/firefly/head/reference/idempotency.html#short-term-retry", "relUrl": "/reference/idempotency.html#short-term-retry" - },"512": { + },"516": { "doc": "Idempotency Keys", "title": "Administrative operation retry", "content": "The operations/{operationId}/retry API can be called administratively to resubmit a transaction that has reached Failed status, or otherwise been determined by an operator/monitor to be unrecoverable within the connector. In this case, the previous operation is marked Retried, a new operation ID is allocated, and the operation is re-submitted to the connector with this new ID. ", "url": "/firefly/head/reference/idempotency.html#administrative-operation-retry", "relUrl": "/reference/idempotency.html#administrative-operation-retry" - },"513": { + },"517": { "doc": "Identities", "title": "Identities", "content": " ", "url": "/firefly/head/reference/identities.html", "relUrl": "/reference/identities.html" - },"514": { + },"518": { "doc": "Identities", "title": "Table of contents", "content": ". | Overview | Types of Identities . | org | node | custom | . | Identity Claims | Messaging . | Sender | Recipients | Verification | . | . ", "url": "/firefly/head/reference/identities.html#table-of-contents", "relUrl": "/reference/identities.html#table-of-contents" - },"515": { + },"519": { "doc": "Identities", "title": "Overview", "content": "Identities are a critical part of using FireFly in a multi-party system. Every party that joins a multi-party system must begin by claiming an on- and off-chain identity, which is described with a unique DID. Each type of identity is also associated with an on- or off-chain verifier, which can be used in some way to check the authorship of a piece of data. Together, these concepts form the backbone of the trust model for exchanging multi-party data. ", "url": "/firefly/head/reference/identities.html#overview", "relUrl": "/reference/identities.html#overview" - },"516": { + },"520": { "doc": "Identities", "title": "Types of Identities", "content": "There are three types of identities: . org . Organizations are the primary identity type in FireFly. They represent a logical on-chain signing identity, and the attached verifier is therefore a blockchain key (with the exact format depending on the blockchain being used). Every party in a multi-party system must claim a root organization identity as the first step to joining the network. The root organization name and key must be defined in the FireFly config (once for every multi-party system). It can be claimed with a POST to /network/organizations/self. Organizations may have child identities of any type. node . Nodes represent a logical off-chain identity - and specifically, they are tied to an instance of a data exchange connector. The format of the attached verifier depends on the data exchange plugin being used, but it will be mapped to some validation provided by that plugin (ie the name of an X.509 certificate or similar). Every party in a multi-party system must claim a node identity when joining the network, which must be a child of one of its organization identities (but it is possible for many nodes to share a parent organization). The node name must be defined in the FireFly config (once for every multi-party system). It can be claimed with a POST to /network/nodes/self. Nodes must be a child of an organization, and cannot have any child identities of their own. Note that “nodes” as an identity concept are distinct from FireFly supernodes, from underlying blockchain nodes, and from anywhere else the term “node” happens to be used. custom . Custom identities are similar to organizations, but are provided for applications to define their own more granular notions of identity. They are associated with an on-chain verifier in the same way as organizations. They can only have child identities which are also of type “custom”. ", "url": "/firefly/head/reference/identities.html#types-of-identities", "relUrl": "/reference/identities.html#types-of-identities" - },"517": { + },"521": { "doc": "Identities", "title": "Identity Claims", "content": "Before an identity can be used within a multi-party system, it must be claimed. The identity claim is a special type of broadcast message sent by FireFly to establish an identity uniquely among the parties in the multi-party system. As with other broadcasts, this entails an on-chain transaction which contains a public reference to an off-chain piece of data (such as an IPFS reference) describing the details of the identity claim. The claim data consists of information on the identity being claimed - such as the type, the DID, and the parent (if applicable). The DID must be unique and unclaimed. The verifier will be inferred from the message - for on-chain identities (org and custom), it is the blockchain key that was used to sign the on-chain portion of the message, while for off-chain identities (nodes), is is an identifier queried from data exchange. For on-chain identities with a parent, two messages are actually required - the claim message signed with the new identity’s blockchain key, as well as a separate verification message signed with the parent identity’s blockchain key. Both messages must be received before the identity is confirmed. ", "url": "/firefly/head/reference/identities.html#identity-claims", "relUrl": "/reference/identities.html#identity-claims" - },"518": { + },"522": { "doc": "Identities", "title": "Messaging", "content": "In the context of a multi-party system, FireFly provides capabilities for sending off-chain messages that are pinned to an on-chain proof. The sender of every message must therefore have an on-chain and off-chain identity. For private messages, every recipient must also have an on-chain and off-chain identity. Sender . When sending a message, the on-chain identity of the sender is controlled by the author and key fields. | If both are blank, the root organization is assumed. | If author alone is specified, it should be the DID of an org or custom identity. The associated verifier will be looked up to use as the key. | If key alone is specified, it must match the registered blockchain verifier for an org or custom identity that was previously claimed. A reverse lookup will be used to populate the DID for the author. | If author and key are both specified, they will be used as-is (can be used to send private messages with an unregistered blockchain key). | . The resolved key will be used to sign the blockchain transaction, which establishes the sender’s on-chain identity. The sender’s off-chain identity is always controlled by the node.name from the config along with the data exchange plugin. Recipients . When specifying private message recipients, each one has an identity and a node. | If identity alone is specified, it should be the DID of an org or custom identity. The first node owned by that identity or one of its ancestors will be automatically selected. | If both identity and node are specified, they will be used as-is. The node should be a child of the given identity or one of its ancestors. | . The node in this case will control how the off-chain portion of the message is routed via data exchange. Verification . When a message is received, FireFly verifies the following: . | The sender’s author and key are specified in the message. The author must be a known org or custom identity. The key must match the blockchain key that was used to sign the on-chain portion of the message. For broadcast messages, the key must match the registered verifier for the author. | For private messages, the sending node (as reported by data exchange) must be a known node identity which is a child of the message’s author identity or one of its ancestors. The combination of the author identity and the node must also be found in the message group. | . In addition, the data exchange plugin is responsible for verifying the sending and receiving identities for the off-chain data (such as validating the relevant certificates). ", "url": "/firefly/head/reference/identities.html#messaging", "relUrl": "/reference/identities.html#messaging" - },"519": { + },"523": { "doc": "Identity", "title": "Identity", "content": " ", "url": "/firefly/head/reference/types/identity.html", "relUrl": "/reference/types/identity.html" - },"520": { + },"524": { "doc": "Identity", "title": "Table of contents", "content": ". | Identity . | DIDs | Example | Field Descriptions | . | IdentityMessages | . ", "url": "/firefly/head/reference/types/identity.html#table-of-contents", "relUrl": "/reference/types/identity.html#table-of-contents" - },"521": { + },"525": { "doc": "Identity", "title": "Identity", "content": "FireFly contains an address book of identities, which is managed in a decentralized way across a multi-party system through claim and verification system. See FIR-12 for evolution that is happening to Hyperledger FireFly to allow: . | Private address books that are not shared with other participants | Multiple address books backed by different chains, in the same node | . Root identities are registered with only a claim - which is a signed transaction from a particular blockchain account, to bind a DID with a name that is unique within the network, to that signing key. The signing key then becomes a Verifier for that identity. Using that key the root identity can be used to register a new FireFly node in the network, send and receive messages, and register child identities. When child identities are registered, a claim using a key that is going to be the Verifier for that child identity is required. However, this is insufficient to establish that identity as a child identity of the parent. There must be an additional verification that references the claim (by UUID) using the key verifier of the parent identity. DIDs . FireFly has adopted the DID standard for representing identities. A “DID Method” name of firefly is used to represent that the built-in identity system of Hyperledger FireFly is being used to resolve these DIDs. So an example FireFly DID for organization abcd1234 is: . | did:firefly:org/abcd1234 | . The adoption of DIDs in Hyperledger FireFly v1.0 is also a stepping stone to allowing pluggable DID based identity resolvers into FireFly in the future. You can also download a DID Document for a FireFly identity, which represents the verifiers and other information about that identity according to the JSON format in the DID standard. Example . { \"id\": \"114f5857-9983-46fb-b1fc-8c8f0a20846c\", \"did\": \"did:firefly:org/org_1\", \"type\": \"org\", \"parent\": \"688072c3-4fa0-436c-a86b-5d89673b8938\", \"namespace\": \"ff_system\", \"name\": \"org_1\", \"messages\": { \"claim\": \"911b364b-5863-4e49-a3f8-766dbbae7c4c\", \"verification\": \"24636f11-c1f9-4bbb-9874-04dd24c7502f\", \"update\": null }, \"created\": \"2022-05-16T01:23:15Z\" } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the identity | UUID | . | did | The DID of the identity. Unique across namespaces within a FireFly network | string | . | type | The type of the identity | FFEnum:\"org\"\"node\"\"custom\" | . | parent | The UUID of the parent identity. Unset for root organization identities | UUID | . | namespace | The namespace of the identity. Organization and node identities are always defined in the ff_system namespace | string | . | name | The name of the identity. The name must be unique within the type and namespace | string | . | description | A description of the identity. Part of the updatable profile information of an identity | string | . | profile | A set of metadata for the identity. Part of the updatable profile information of an identity | JSONObject | . | messages | References to the broadcast messages that established this identity and proved ownership of the associated verifiers (keys) | IdentityMessages | . | created | The creation time of the identity | FFTime | . | updated | The last update time of the identity profile | FFTime | . ", "url": "/firefly/head/reference/types/identity.html", "relUrl": "/reference/types/identity.html" - },"522": { + },"526": { "doc": "Identity", "title": "IdentityMessages", "content": "| Field Name | Description | Type | . | claim | The UUID of claim message | UUID | . | verification | The UUID of claim message. Unset for root organization identities | UUID | . | update | The UUID of the most recently applied update message. Unset if no updates have been confirmed | UUID | . ", "url": "/firefly/head/reference/types/identity.html#identitymessages", "relUrl": "/reference/types/identity.html#identitymessages" - },"523": { + },"527": { "doc": "pages.getting_started", "title": "Getting Started", "content": "If you’re new to FireFly, this is the perfect place to start! With the FireFly CLI and the FireFly Sandbox it’s really easy to get started building powerful blockchain apps. Just follow along with the steps below and you’ll be up and running in no time! . What you will accomplish with this guide . With this easy-to-follow guide, you’ll go from “zero” to blockchain-hero in the time it takes to drink a single cup of coffee. It will walk you through setting up your machine, all the way through sending your first blockchain transactions using the FireFly Sandbox. We’re here to help! . We want to make it as easy as possible for anyone to get started with FireFly, and we don’t want anyone to feel like they’re stuck. If you’re having trouble, or are just curious about what else you can do with FireFly we encourage you to join the Hyperledger Discord server and come chat with us in the #firefly channel. ", "url": "/firefly/head/gettingstarted/#getting-started", "relUrl": "/gettingstarted/#getting-started" - },"524": { + },"528": { "doc": "pages.getting_started", "title": "Get started: Install the FireFly CLI", "content": "Now that you’ve got the FireFly CLI set up on your machine, the next step is to create and start a FireFly stack. ① Install the FireFly CLI → . ", "url": "/firefly/head/gettingstarted/#get-started-install-the-firefly-cli", "relUrl": "/gettingstarted/#get-started-install-the-firefly-cli" - },"525": { + },"529": { "doc": "pages.getting_started", "title": "pages.getting_started", "content": " ", "url": "/firefly/head/gettingstarted/", "relUrl": "/gettingstarted/" - },"526": { + },"530": { "doc": "pages.contributors", "title": "Contributors’ Guide", "content": " ", "url": "/firefly/head/contributors/#contributors-guide", "relUrl": "/contributors/#contributors-guide" - },"527": { + },"531": { "doc": "pages.contributors", "title": "Table of contents", "content": ". | 🚀 Connect with us on Discord | 📅 Join our Community Calls | 🔍 Find your first issue . | Any level of experience | Go experience | Little or no Go experience, but want to learn | TypeScript experience | React/TypeScript experience | Go and blockchain experience | . | 📝 Make changes | 📑 Commit with Developer Certificate of Origin | 📥 Open a Pull Request | Inclusivity | . We welcome anyone to contribute to the FireFly project! If you’re interested, this is a guide on how to get started. You don’t have to be a blockchain expert to make valuable contributions! There are lots of places for developers of all experience levels to get involved. 🧑🏽‍💻 👩🏻‍💻 👩🏾‍💻 🧑🏻‍💻 🧑🏿‍💻 👨🏽‍💻 👩🏽‍💻 🧑🏾‍💻 👨🏿‍💻 👨🏾‍💻 👩🏿‍💻 👨🏻‍💻 . ", "url": "/firefly/head/contributors/#table-of-contents", "relUrl": "/contributors/#table-of-contents" - },"528": { + },"532": { "doc": "pages.contributors", "title": "🚀 Connect with us on Discord", "content": "You can chat with maintainers and other contributors on Discord in the firefly channel: https://discord.gg/hyperledger . Join Discord Server . ", "url": "/firefly/head/contributors/#-connect-with-us-on-discord", "relUrl": "/contributors/#-connect-with-us-on-discord" - },"529": { + },"533": { "doc": "pages.contributors", "title": "📅 Join our Community Calls", "content": "Community calls are a place to talk to other contributors, maintainers, and other people interested in FireFly. Maintainers often discuss upcoming changes and proposed new features on these calls. These calls are a great way for the community to give feedback on new ideas, ask questions about FireFly, and hear how others are using FireFly to solve real world problems. Please see the FireFly Calendar for the current meeting schedule, and the link to join. Everyone is welcome to join, regardless of background or experience level. ", "url": "/firefly/head/contributors/#-join-our-community-calls", "relUrl": "/contributors/#-join-our-community-calls" - },"530": { + },"534": { "doc": "pages.contributors", "title": "🔍 Find your first issue", "content": "If you’re looking for somewhere to get started in the FireFly project and want something small and relatively easy, take a look at issues tagged with “Good first issue”. You can definitely work on other things if you want to. These are only suggestions for easy places to get started. See “Good First Issues” . NOTE Hyperledger FireFly has a microservice architecture so it has many different GitHub repos. Use the link or the button above to look for “Good First Issues” across all the repos at once. Here are some other suggestions of places to get started, based on experience you may already have: . Any level of experience . If you looking to make your first open source contribution the FireFly documentation is a great place to make small, easy improvements. These improvements are also very valuable, because they help the next person that may want to know the same thing. Here are some detailed instructions on Contributing to Documentation . Go experience . If you have some experience in Go and really want to jump into FireFly, the FireFly Core is the heart of the project. Here are some detailed instructions on Setting up a FireFly Core Development Environment. Little or no Go experience, but want to learn . If you don’t have a lot of experience with Go, but are interested in learning, the FireFly CLI might be a good place to start. The FireFly CLI is a tool to set up local instances of FireFly for building apps that use FireFly, and for doing development on FireFly itself. TypeScript experience . If you have some experience in TypeScript, there are several FireFly microservices that are written in TypeScript. The Data Exchange is used for private messaging between FireFly nodes. The ERC-20/ERC-271 Tokens Connector and ERC-1155 Tokens Connector are used to abstract token contract specifics from the FireFly Core. React/TypeScript experience . If you want to do some frontend development, the FireFly UI is written in TypeScript and React. Go and blockchain experience . If you already have some experience with blockchain and want to work on some backend components, the blockchain connectors, firefly-ethconnect (for Ethereum) and firefly-fabconnect (for Fabric) are great places to get involved. ", "url": "/firefly/head/contributors/#-find-your-first-issue", "relUrl": "/contributors/#-find-your-first-issue" - },"531": { + },"535": { "doc": "pages.contributors", "title": "📝 Make changes", "content": "To contribute to the repository, please fork the repository that you want to change. Then clone your fork locally on your machine and make your changes. As you commit your changes, push them to your fork. More information on making commits below. ", "url": "/firefly/head/contributors/#-make-changes", "relUrl": "/contributors/#-make-changes" - },"532": { + },"536": { "doc": "pages.contributors", "title": "📑 Commit with Developer Certificate of Origin", "content": "As with all Hyperledger repositories, FireFly requires proper sign-off on every commit that is merged into the main branch. The sign-off indicates that you certify the changes you are submitting are in accordance with the Developer Certificate of Origin. To sign-off on your commit, you can use the -s flag when you commit changes. git commit -s -m \"Your commit message\" . This will add a string like this to the end of your commit message: . \"Signed-off-by: Your Name <your-email@address>\" . NOTE: Sign-off is not the same thing as signing your commits with a private key. Both operations use a similar flag, which can be confusing. The one you want is the lowercase -s 🙂 . ", "url": "/firefly/head/contributors/#-commit-with-developer-certificate-of-origin", "relUrl": "/contributors/#-commit-with-developer-certificate-of-origin" - },"533": { + },"537": { "doc": "pages.contributors", "title": "📥 Open a Pull Request", "content": "When you’re ready to submit your changes for review, open a Pull Request back to the upstream repository. When you open your pull request, the maintainers will automatically be notified. Additionally, a series of automated checks will be performed on your code to make sure it passes certain repository specific requirements. Maintainers may have suggestions on things to improve in your pull request. It is our goal to get code that is beneficial to the project merged as quickly as possible, so we don’t like to leave pull requests hanging around for a long time. If the project maintainers are satisfied with the changes, they will approve and merge the pull request. Thanks for your interest in collaborating on this project! . ", "url": "/firefly/head/contributors/#-open-a-pull-request", "relUrl": "/contributors/#-open-a-pull-request" - },"534": { + },"538": { "doc": "pages.contributors", "title": "Inclusivity", "content": "The Hyperledger Foundation and the FireFly project are committed to fostering a community that is welcoming to all people. When participating in community discussions, contributing code, or documentaiton, please abide by the following guidelines: . | Consider that users who will read the docs are from different background and cultures and that they have different preferences. | Avoid potential offensive terms and, for instance, prefer “allow list and deny list” to “white list and black list”. | We believe that we all have a role to play to improve our world, and even if writing inclusive doc might not look like a huge improvement, it’s a first step in the right direction. | We suggest to refer to Microsoft bias free writing guidelines and Google inclusive doc writing guide as starting points. | . ", "url": "/firefly/head/contributors/#inclusivity", "relUrl": "/contributors/#inclusivity" - },"535": { + },"539": { "doc": "pages.contributors", "title": "pages.contributors", "content": " ", "url": "/firefly/head/contributors/", "relUrl": "/contributors/" - },"536": { + },"540": { "doc": "pages.release_notes", "title": "Release Notes", "content": "Full release notes . ", "url": "/firefly/head/releasenotes/#release-notes", "relUrl": "/releasenotes/#release-notes" - },"537": { + },"541": { "doc": "pages.release_notes", "title": "v1.2.0 - February 6, 2023", "content": "Migration guide . What’s New: . | Enhanced support for token contracts generated by the OpenZepplin Wizard | Custom smart contract error types are now returned on the API | Data objects and associated blobs can now be deleted | Optional dynamic reload of core configuration file | The X-FireFly-Request-ID HTTP header is now passed through to FireFly dependency microservices | Custom HTTP headers can be passed through to FireFly dependency microservices | Evmconnect is now the default blockchain connector for Ethereum based FireFly stacks | . ", "url": "/firefly/head/releasenotes/#v120---february-6-2023", "relUrl": "/releasenotes/#v120---february-6-2023" - },"538": { + },"542": { "doc": "pages.release_notes", "title": "Release Notes", "content": "Full release notes . ", "url": "/firefly/head/releasenotes/#release-notes-1", "relUrl": "/releasenotes/#release-notes-1" - },"539": { + },"543": { "doc": "pages.release_notes", "title": "v1.1.0 - September 12, 2022", "content": "Migration guide . What’s New: . | Gateway Mode: Connect to many chains with auto-indexing of activities | Public EVM Chain Support: Manage public chain connections including Ethereum, Polygon, Arbitrum, Binance Smart Chain, Moonbeam, and more. | Namespaces: Isolated environments within a FireFly runtime allowing independent configuration of plugin and infrastructure components and more | Connector Toolkit: Quickly build custom connectors | Pluggable API Security: Plug in your own API security | Mass Scale Tokens: Support many parallel copies of token plugins for mass scale | . ", "url": "/firefly/head/releasenotes/#v110---september-12-2022", "relUrl": "/releasenotes/#v110---september-12-2022" - },"540": { + },"544": { "doc": "pages.release_notes", "title": "v1.0.3 - July 07, 2022", "content": "What’s New: . | Adds support for custom URIs for non-fungible tokens and documentation updates | Deprecate default value for “ffdx” | Back port of custom URI support for non-fungible tokens | Update token connector versions | Back port of “FAQ and FireFly Tutorial updates” | . ", "url": "/firefly/head/releasenotes/#v103---july-07-2022", "relUrl": "/releasenotes/#v103---july-07-2022" - },"541": { + },"545": { "doc": "pages.release_notes", "title": "v1.0.2 - May 12, 2022", "content": "What’s New: . | Fix invocations on custom Fabric chaincode, which were not properly reporting success/failure status back to FireFly (along with other minor bugfixes). | De-duplicate existing token approvals in database migration | Backport docs generation and versioning code for 1.0 stream | Default fabconnect calls to async | Set message header type of broadcast/private | . ", "url": "/firefly/head/releasenotes/#v102---may-12-2022", "relUrl": "/releasenotes/#v102---may-12-2022" - },"542": { + },"546": { "doc": "pages.release_notes", "title": "v1.0.1 - May 09, 2022", "content": "What’s New: . | Fixes for token approvals - previously approvals would intermittently be missed by FireFly or recorded with incorrect details. | New versions of ERC20/ERC721 connector will assume “no data” support if you create a token pool against an older version of the sample smart contracts. | . ", "url": "/firefly/head/releasenotes/#v101---may-09-2022", "relUrl": "/releasenotes/#v101---may-09-2022" - },"543": { + },"547": { "doc": "pages.release_notes", "title": "v1.0.0 - April 28, 2022", "content": "This release includes lots of major hardening, performance improvements, and bug fixes, as well as more complete documentation and OpenAPI specifications. What’s New: . | Massive performance improvements across the board | Up-to-date documentation and fully annotated OpenAPI specification | Overhaul of UI | Cleaner logs and error messages | Lots of bug fixes and miscellaneous enhancements | . ", "url": "/firefly/head/releasenotes/#v100---april-28-2022", "relUrl": "/releasenotes/#v100---april-28-2022" - },"544": { + },"548": { "doc": "pages.release_notes", "title": "v0.14.0 - March 22, 2022", "content": "What’s New: . | Major UI updates including Activity, Blockchain, Off-Chain, Tokens, Network Map, and My Node sections | Custom contract APIs | Enhanced subscription filters | Event API enrichment | Performance updates | Bug fixes | . ", "url": "/firefly/head/releasenotes/#v0140---march-22-2022", "relUrl": "/releasenotes/#v0140---march-22-2022" - },"545": { + },"549": { "doc": "pages.release_notes", "title": "v0.13.0 - February 14, 2022", "content": "What’s New: . | Hardening release with significant rework to core of FireFly, mostly to fix issues exposed by the performance testing. | Support for running on ARM-based M1 processors | Rewrite of the message batching and event aggregation logic inside FireFly, to fix numerous edge cases with lost or hung messages | Hardening of operations and transactions to behave more consistently across all types | Metrics reporting to Prometheus | Continued development to support custom on-chain logic (still in preview) | . ", "url": "/firefly/head/releasenotes/#v0130---february-14-2022", "relUrl": "/releasenotes/#v0130---february-14-2022" - },"546": { + },"550": { "doc": "pages.release_notes", "title": "v0.12.0 - February 02, 2022", "content": "What’s New: . | All APIs deprecated in v0.11.0 or earlier are removed | Preview of custom on-chain logic | Support for new ERC20 / ERC721 connector | Overhaul of Transaction type and new BlockchainEvent type | Support for delivery confirmations via DX plugin | . ", "url": "/firefly/head/releasenotes/#v0120---february-02-2022", "relUrl": "/releasenotes/#v0120---february-02-2022" - },"547": { + },"551": { "doc": "pages.release_notes", "title": "v0.11.0 - November 22, 2021", "content": "What’s New: . | Significant hardening and enhanced token functionality | Major web UI overhaul | Optimized database operations for increased transactional throughput | Fixed PostgreSQL database migrations | . ", "url": "/firefly/head/releasenotes/#v0110---november-22-2021", "relUrl": "/releasenotes/#v0110---november-22-2021" - },"548": { + },"552": { "doc": "pages.release_notes", "title": "pages.release_notes", "content": " ", "url": "/firefly/head/releasenotes/", "relUrl": "/releasenotes/" - },"549": { + },"553": { "doc": "pages.understanding_firefly", "title": "Understanding FireFly", "content": " ", "url": "/firefly/head/overview/#understanding-firefly", "relUrl": "/overview/#understanding-firefly" - },"550": { + },"554": { "doc": "pages.understanding_firefly", "title": "pages.understanding_firefly", "content": " ", "url": "/firefly/head/overview/", "relUrl": "/overview/" - },"551": { + },"555": { "doc": "pages.architecture", "title": "Architecture", "content": "This section contains a collection of technical architecture diagrams detailing the various runtime components of a FireFly deployment. ", "url": "/firefly/head/architecture/#architecture", "relUrl": "/architecture/#architecture" - },"552": { + },"556": { "doc": "pages.architecture", "title": "pages.architecture", "content": " ", "url": "/firefly/head/architecture/", "relUrl": "/architecture/" - },"553": { + },"557": { "doc": "Use tokens", "title": "Quick reference", "content": "Tokens are a critical building block in many blockchain-backed applications. Fungible tokens can represent a store of value or a means of rewarding participation in a multi-party system, while non-fungible tokens provide a clear way to identify and track unique entities across the network. FireFly provides flexible mechanisms to operate on any type of token and to tie those operations to on- and off-chain data. | FireFly provides an abstraction layer for multiple types of tokens | Tokens are grouped into pools, which each represent a particular type or class of token | Each pool is classified as fungible or non-fungible | In the case of non-fungible tokens, the pool is subdivided into individual tokens with a unique token index | Within a pool, you may mint (issue), transfer, and burn (redeem) tokens | Each operation can be optionally accompanied by a broadcast or private message, which will be recorded alongside the transfer on-chain | FireFly tracks a history of all token operations along with all current token balances | The blockchain backing each token connector may be the same or different from the one backing FireFly message pinning | . ", "url": "/firefly/head/tutorials/tokens/#quick-reference", "relUrl": "/tutorials/tokens/#quick-reference" - },"554": { + },"558": { "doc": "Use tokens", "title": "What is a pool?", "content": "Token pools are a FireFly construct for describing a set of tokens. The exact definition of a token pool is dependent on the token connector implementation. Some examples of how pools might map to various well-defined Ethereum standards: . | ERC-1155: a single contract instance can efficiently allocate many isolated pools of fungible or non-fungible tokens | ERC-20 / ERC-777: each contract instance represents a single fungible pool of value, e.g. “a coin” | ERC-721: each contract instance represents a single pool of NFTs, each with unique identities within the pool | ERC-1400 / ERC-1410: partially supported in the same manner as ERC-20/ERC-777, but would require new features for working with partitions | . These are provided as examples only - a custom token connector could be backed by any token technology (Ethereum or otherwise) as long as it can support the basic operations described here (create pool, mint, burn, transfer). Other FireFly repos include a sample implementation of a token connector for ERC-20 and ERC-721 as well as ERC-1155. ", "url": "/firefly/head/tutorials/tokens/#what-is-a-pool", "relUrl": "/tutorials/tokens/#what-is-a-pool" - },"555": { + },"559": { "doc": "Use tokens", "title": "Use tokens", "content": " ", "url": "/firefly/head/tutorials/tokens/", "relUrl": "/tutorials/tokens/" - },"556": { + },"560": { "doc": "pages.custom_smart_contracts", "title": "Quick reference", "content": "Almost all blockchain platforms offer the ability to execute smart contracts on-chain in order to manage states on the shared ledger. FireFly provides support to use RESTful APIs to interact with the smart contracts deployed in the target blockchains, and listening to events via websocket. FireFly’s unified API creates a consistent application experience regardless of the specific underlying blockchain implementation. It also provides developer-friendly features like automatic OpenAPI Specification generation for smart contracts, plus a built-in Swagger UI. ", "url": "/firefly/head/tutorials/custom_contracts/#quick-reference", "relUrl": "/tutorials/custom_contracts/#quick-reference" - },"557": { + },"561": { "doc": "pages.custom_smart_contracts", "title": "Key concepts", "content": "FireFly defines the following constructs to support custom smart contracts: . | Contract Interface: FireFly defines a common, blockchain agnostic way to describe smart contracts. This is referred to as a Contract Interface. A contract interface is written in the FireFly Interface (FFI) format. It is a simple JSON document that has a name, a namespace, a version, a list of methods, and a list of events. | . For more details, you can also have a look at the Reference page for the FireFly Interface Format. For blockchains that offer a DSL describing the smart contract interface, such as Ethereum’s ABI (Application Binary Interface), FireFly offers a convenience tool to convert the DSL into the FFI format. NOTE: Contract interfaces are scoped to a namespace. Within a namespace each contract interface must have a unique name and version combination. The same name and version combination can exist in different namespaces simultaneously. | HTTP API: Based on a Contract Interface, FireFly further defines an HTTP API for the smart contract, which is complete with an OpenAPI Specification and the Swagger UI. An HTTP API defines an /invoke root path to submit transactions, and a /query root path to send query requests to read the state back out. | . How the invoke vs. query requests get interpreted into the native blockchain requests are specific to the blockchain’s connector. For instance, the Ethereum connector translates /invoke calls to eth_sendTransaction JSON-RPC requests, while /query calls are translated into eth_call JSON-RPC requests. One the other hand, the Fabric connector translates /invoke calls to the multiple requests required to submit a transaction to a Fabric channel (which first collects endorsements from peer nodes, and then sends the assembled transaction payload to an orderer, for details please refer to the Fabric documentation). | Blockchain Event Listener: Regardless of a blockchain’s specific design, transaction processing are always asynchronous. This means a transaction is submitted to the network, at which point the submitting client gets an acknowledgement that it has been accepted for further processing. The client then listens for notifications by the blockchain when the transaction gets committed to the blockchain’s ledger. | . FireFly defines event listeners to allow the client application to specify the relevant blockchain events to keep track of. A client application can then receive the notifications from FireFly via an event subscription. | Event Subscription: While an event listener tells FireFly to keep track of certain events emitted by the blockchain, an event subscription tells FireFly to relay those events to the client application. Each subscriptions represents a stream of events that can be delivered to a listening client with various modes of delivery with at-least-once delivery guarantee. | . This is exactly the same as listening for any other events from FireFly. For more details on how Subscriptions work in FireFly you can read the Getting Started guide to Listen for events. ", "url": "/firefly/head/tutorials/custom_contracts/#key-concepts", "relUrl": "/tutorials/custom_contracts/#key-concepts" - },"558": { + },"562": { "doc": "pages.custom_smart_contracts", "title": "Custom onchain logic async programming in FireFly", "content": "Like the rest of FireFly, custom onchain logic support are implemented with an asynchronous programming model. The key concepts here are: . | Transactions are submitted to FireFly and an ID is returned. This is the Operation ID. | The transaction itself happens asynchronously from the HTTP request that initiated it | Blockchain events emitted by the custom onchain logic (Ethereum smart contracts, Fabric chaincodes, Corda flows, etc.) will be stored in FireFly’s database if FireFly has a Event Listener set up for that specific type of event. FireFly will also emit an event of type blockchain_event_received when this happens. | . ", "url": "/firefly/head/tutorials/custom_contracts/#custom-onchain-logic-async-programming-in-firefly", "relUrl": "/tutorials/custom_contracts/#custom-onchain-logic-async-programming-in-firefly" - },"559": { + },"563": { "doc": "pages.custom_smart_contracts", "title": "pages.custom_smart_contracts", "content": " ", "url": "/firefly/head/tutorials/custom_contracts/", "relUrl": "/tutorials/custom_contracts/" - },"560": { + },"564": { "doc": "pages.chains", "title": "Connect to remote blockchains", "content": "If you want to connect a local development environment, created with the FireFly CLI to another chain, there are several tutorials below to help you do that. These other chains could also be on the same machine as FireFly, or they could be somewhere on the public internet, depending on the tutorial. ", "url": "/firefly/head/tutorials/chains/#connect-to-remote-blockchains", "relUrl": "/tutorials/chains/#connect-to-remote-blockchains" - },"561": { + },"565": { "doc": "pages.chains", "title": "pages.chains", "content": " ", "url": "/firefly/head/tutorials/chains/", "relUrl": "/tutorials/chains/" - },"562": { + },"566": { "doc": "pages.tutorials", "title": "Tutorials", "content": " ", "url": "/firefly/head/tutorials/#tutorials", "relUrl": "/tutorials/#tutorials" - },"563": { + },"567": { "doc": "pages.tutorials", "title": "pages.tutorials", "content": " ", "url": "/firefly/head/tutorials/", "relUrl": "/tutorials/" - },"564": { + },"568": { "doc": "pages.faqs", "title": "FAQs", "content": "Find answers to the most commonly asked FireFly questions. ", "url": "/firefly/head/faqs/#faqs", "relUrl": "/faqs/#faqs" - },"565": { + },"569": { "doc": "pages.faqs", "title": "How does FireFly enable multi-chain applications?", "content": "It’s best to think about FireFly as a rich orchestration layer that sits one layer above the blockchain. FireFly helps to abstract away much of the complex blockchain functionality (such as data exchange, private messaging, common token functionality, etc) in a loosely coupled microservice architecture with highly pluggable components. This enables application developers to focus on building innovative Web3 applications. There aren’t any out of the box bridges to connect two separate chains together, but with a collection of FireFly instances across a consortium, FireFly could help listen for events on Blockchain A and take an action on Blockchain B when certain conditions are met. ", "url": "/firefly/head/faqs/#how-does-firefly-enable-multi-chain-applications", "relUrl": "/faqs/#how-does-firefly-enable-multi-chain-applications" - },"566": { + },"570": { "doc": "pages.faqs", "title": "📜 How do I deploy smart contracts?", "content": "The recommended way to deploy smart contracts on Ethereum chains is by using FireFly’s built in API. For a step by step example of how to do this you can refer to the Smart Contract Tutorial for Ethereum based chains. For Fabric networks, please refer to the Fabric chaincode lifecycle docs for detailed instructions on how to deploy and manage Fabric chaincode. ", "url": "/firefly/head/faqs/#-how-do-i-deploy-smart-contracts", "relUrl": "/faqs/#-how-do-i-deploy-smart-contracts" - },"567": { + },"571": { "doc": "pages.faqs", "title": "🦊 Can I connect FireFly to MetaMask?", "content": "Yes! Before you set up MetaMask you’ll likely want to create some tokens that you can use to send between wallets on your FF network. Go to the tokens tab in your FireFly node’s UI, create a token pool, and then mint some tokens. Once you’ve done this, follow the steps listed here to set up MetaMask on your network. ", "url": "/firefly/head/faqs/#-can-i-connect-firefly-to-metamask", "relUrl": "/faqs/#-can-i-connect-firefly-to-metamask" - },"568": { + },"572": { "doc": "pages.faqs", "title": "🚀 Connect with us on Discord", "content": "If your question isn’t answered here or if you have immediate questions please don’t hesitate to reach out to us on Discord in the firefly channel: . ", "url": "/firefly/head/faqs/#-connect-with-us-on-discord", "relUrl": "/faqs/#-connect-with-us-on-discord" - },"569": { + },"573": { "doc": "pages.faqs", "title": "pages.faqs", "content": " ", "url": "/firefly/head/faqs/", "relUrl": "/faqs/" - },"570": { + },"574": { "doc": "Core Resources", "title": "Core Resources", "content": " ", "url": "/firefly/head/reference/types/", "relUrl": "/reference/types/" - },"571": { + },"575": { "doc": "Microservices", "title": "Microservices", "content": " ", "url": "/firefly/head/reference/microservices/", "relUrl": "/reference/microservices/" - },"572": { + },"576": { "doc": "pages.reference", "title": "Reference", "content": ". This section contains detailed reference information for developers using FireFly. ", "url": "/firefly/head/reference/#reference", "relUrl": "/reference/#reference" - },"573": { + },"577": { "doc": "pages.reference", "title": "pages.reference", "content": " ", "url": "/firefly/head/reference/", "relUrl": "/reference/" - },"574": { + },"578": { "doc": "pages.home", "title": "Hyperledger FireFly", "content": ". Hyperledger FireFly is an open source Supernode, a complete stack for enterprises to build and scale secure Web3 applications. The easiest way to understand a FireFly Supernode is to think of it like a toolbox. Connect your existing apps and/or back office systems to the toolbox and within it there are two different sets of tools. One set of tools helps you connect to the Web3 world that already exists, and the other set allows you to build new decentralized applications quickly with security and scalability. Head to the Understanding FireFly section for more details. ", "url": "/firefly/head/#hyperledger-firefly", "relUrl": "/#hyperledger-firefly" - },"575": { + },"579": { "doc": "pages.home", "title": "Table of contents", "content": ". | Understanding FireFly | Getting Started | Tutorials | Reference | Architecture | Contributors | API Spec | FAQs | . ", "url": "/firefly/head/#table-of-contents", "relUrl": "/#table-of-contents" - },"576": { + },"580": { "doc": "pages.home", "title": "pages.home", "content": " ", "url": "/firefly/head/", "relUrl": "/" - },"577": { + },"581": { "doc": "Internal Event Sequencing", "title": "Internal Event Sequencing", "content": " ", "url": "/firefly/head/architecture/internal_event_sequencing.html", "relUrl": "/architecture/internal_event_sequencing.html" - },"578": { + },"582": { "doc": "Internal Event Sequencing", "title": "Table of contents", "content": ". | Overview | App Instances | Outbound Sequencers | Inbound Aggregator . | Events Table | . | Subscription Manager | Event Dispatcher | . ", "url": "/firefly/head/architecture/internal_event_sequencing.html#table-of-contents", "relUrl": "/architecture/internal_event_sequencing.html#table-of-contents" - },"579": { + },"583": { "doc": "Internal Event Sequencing", "title": "Overview", "content": ". One of the most important roles FireFly has, is to take actions being performed by the local apps, process them, get them confirmed, and then deliver back as “stream of consciousness” to the application alongside all the other events that are coming into the application from other FireFly Nodes in the network. You might observe the problems solved in this architecture are similar to those in a message queuing system (like Apache Kafka, or a JMS/AMQP provider like ActiveMQ etc.). However, we cannot directly replace the internal logic with such a runtime - because FireFly’s job is to aggregate data from multiple runtimes that behave similarly to these: . | Private messaging in the Data Exchange | The blockchain ledger(s) themselves, which are a stream of sequenced events | The event dispatcher delivering messages to applications that have been sequenced by FireFly | . So FireFly provides the convenient REST based management interface to simplify the world for application developers, by aggregating the data from multiple locations, and delivering it to apps in a deterministic sequence. The sequence is made deterministic: . | Globally to all apps within the scope of the ledger, when a Blockchain ledger is used to pin events (see #10) | Locally for messages delivered through a single FireFly node into the network | Locally for all messages delivered to applications connected to a FireFly node, across blockchain | . ", "url": "/firefly/head/architecture/internal_event_sequencing.html#overview", "relUrl": "/architecture/internal_event_sequencing.html#overview" - },"580": { + },"584": { "doc": "Internal Event Sequencing", "title": "App Instances", "content": ". | Broadcast messages to the network | Ingest ack when message persisted in local messages table | Consume events via Websocket connection into FireFly | . ", "url": "/firefly/head/architecture/internal_event_sequencing.html#app-instances", "relUrl": "/architecture/internal_event_sequencing.html#app-instances" - },"581": { + },"585": { "doc": "Internal Event Sequencing", "title": "Outbound Sequencers", "content": ". | Broadcast or Private through IPFS or Private Data Storage | Long-running leader-elected jobs listening to the database (via event tables in SQL, etc.) | . ", "url": "/firefly/head/architecture/internal_event_sequencing.html#outbound-sequencers", "relUrl": "/architecture/internal_event_sequencing.html#outbound-sequencers" - },"582": { + },"586": { "doc": "Internal Event Sequencing", "title": "Inbound Aggregator", "content": ". | Triggered each time an event is detected by the associated plugin. | It is the responsibility of the plugin to fire events sequentially. Can be workload managed but must be sequential. | . Events Table . | Deliberately lightweight persisted object, that is generated as a byproduct of other persistent actions. | Records the local sequence of a specific event within the local node. | The highest level event type is the confirmation of a message, however the table can be extended for more granularity on event types. | . ", "url": "/firefly/head/architecture/internal_event_sequencing.html#inbound-aggregator", "relUrl": "/architecture/internal_event_sequencing.html#inbound-aggregator" - },"583": { + },"587": { "doc": "Internal Event Sequencing", "title": "Subscription Manager", "content": ". | Responsible for filtering and delivering batches of events to the active event dispatchers. | Records the latest offset confirmed by each dispatcher. | . ", "url": "/firefly/head/architecture/internal_event_sequencing.html#subscription-manager", "relUrl": "/architecture/internal_event_sequencing.html#subscription-manager" - },"584": { + },"588": { "doc": "Internal Event Sequencing", "title": "Event Dispatcher", "content": ". | Created with leadership election when WebSocket connection is made from an app into FireFly. | Extensible to other dispatchers (AMQP, etc.). | . ", "url": "/firefly/head/architecture/internal_event_sequencing.html#event-dispatcher", "relUrl": "/architecture/internal_event_sequencing.html#event-dispatcher" - },"585": { + },"589": { "doc": "pages.key_features", "title": "Key Features", "content": ". Hyperledger FireFly provides a rich suite of features for building new applications, and connecting existing Web3 ecosystems to your business. In this section we introduce each core pillar of functionality. ", "url": "/firefly/head/overview/key_features.html#key-features", "relUrl": "/overview/key_features.html#key-features" - },"586": { + },"590": { "doc": "pages.key_features", "title": "pages.key_features", "content": " ", "url": "/firefly/head/overview/key_features.html", "relUrl": "/overview/key_features.html" - },"587": { + },"591": { "doc": "Message", "title": "Message", "content": " ", "url": "/firefly/head/reference/types/message.html", "relUrl": "/reference/types/message.html" - },"588": { + },"592": { "doc": "Message", "title": "Table of contents", "content": ". | Message . | Hash | Tag | Topics . | Using multiple topics | . | Transaction type | In-line data | Example | Field Descriptions | . | MessageHeader | TransactionRef | DataRef | . ", "url": "/firefly/head/reference/types/message.html#table-of-contents", "relUrl": "/reference/types/message.html#table-of-contents" - },"589": { + },"593": { "doc": "Message", "title": "Message", "content": "Message is the envelope by which coordinated data exchange can happen between parties in the network. Data is passed by reference in these messages, and a chain of hashes covering the data and the details of the message, provides a verification against tampering. A message is made up of three sections: . | The header - a set of metadata that determines how the message is ordered, who should receive it, and how they should process it | The data - an array of data attachments | Status information - fields that are calculated independently by each node, and hence update as the message makes it way through the system | . Hash . Sections (1) and (2) are fixed once the message is sent, and a hash is generated that provides tamper protection. The hash is a function of the header, and all of the data payloads. Calculated as follows: . | The hash of each Data element is calculated individually | A JSON array of [{\"id\":\"\",\"hash\":\"\"}] is hashed, and that hash is stored in header.datahash | The header is serialized as JSON with the deterministic order (listed below) and hashed . | JSON data is serialized without whitespace to hash it. | The hashing algorithm is SHA-256 | . | . Each node independently calculates the hash, and the hash is included in the manifest of the Batch by the node that sends the message. Because the hash of that batch manifest is included in the blockchain transaction, a message transferred to a node that does not match the original message hash is rejected. Tag . The header.tag tells the processors of the message how it should be processed, and what data they should expect it to contain. If you think of your decentralized application like a state machine, then you need to have a set of well defined transitions that can be performed between states. Each of these transitions that requires off-chain transfer of private data (optionally coordinated with an on-chain transaction) should be expressed as a type of message, with a particular tag. Every copy of the application that runs in the participants of the network should look at this tag to determine what logic to execute against it. Note: For consistency in ordering, the sender should also wait to process the state machine transitions associated with the message they send until it is ordered by the blockchain. They should not consider themselves special because they sent the message, and process it immediately - otherwise they could end up processing it in a different order to other parties in the network that are also processing the message. Topics . The header.topics strings allow you to set the the ordering context for each message you send, and you are strongly encouraged to set it explicitly on every message you send (falling back to the default topic is not recommended). A key difference between blockchain backed decentralized applications and other event-driven applications, is that there is a single source of truth for the order in which things happen. In a multi-party system with off-chain transfer of data as well as on-chain transfer of data, the two sets of data need to be coordinated together. The off-chain transfer might happen at different times, and is subject to the reliability of the parties & network links involved in that off-chain communication. A “stop the world” approach to handling a single piece of missing data is not practical for a high volume production business network. The ordering context is a function of: . | Whether the message is broadcast or private | If it is private, the privacy group associated with the message | The topic of the message | . When an on-chain transaction is detected by FireFly, it can determine the above ordering - noting that privacy is preserved for private messages by masking this ordering context message-by-message with a nonce and the group ID, so that only the participants in that group can decode the ordering context. If a piece of off-chain data is unavailable, then the FireFly node will block only streams of data that are associated with that ordering context. For your application, you should choose the most granular identifier you can for your topic to minimize the scope of any blockage if one item of off-chain data fails to be delivered or is delayed. Some good examples are: . | A business transaction identifier - to ensure all data related to particular business transaction are processed in order | A globally agreed customer identifier - to ensure all data related to a particular business entity are processed in order | . Using multiple topics . There are some advanced scenarios where you need to merge streams of ordered data, so that two previously separately ordered streams of communication (different state machines) are joined together to process a critical decision/transition in a deterministic order. A synchronization point between two otherwise independent streams of communication. To do this, simply specify two topics in the message you sent, and the message will be independently ordered against both of those topics. You will also receive two events for the confirmation of that message, one for each topic. Some examples: . | Agreeing to join two previously separate business transactions with ids 000001 and 000002, by discarding business transaction 000001 as a duplicate . | Specify topics: [\"000001\",\"000002\"] on the special merge message, and then from that point onwards you would only need to specify topics: [\"000002\"]. | . | Agreeing to join two previously separate entities with id1 and id2, into a merged entity with id3. | Specify topics: [\"id1\",\"id2\",\"id3\"] on the special merge message, and then from that point onwards you would only need to specify topics: [\"id3\"]. | . | . Transaction type . By default messages are pinned to the blockchain, within a Batch. For private messages, you can choose to disable this pinning by setting header.txtype: \"unpinned\". Broadcast messages must be pinned to the blockchain. In-line data . When sending a message you can specify the array of Data attachments in-line, as part of the same JSON payload. For example, a minimal broadcast message could be: . { \"data\": [ {\"value\": \"hello world\"} ] } . When you send this message with /api/v1/namespaces/{ns}/messages/broadcast: . | The header will be initialized with the default values, including txtype: \"batch_pin\" | The data[0] entry will be stored as a Data resource | The message will be assembled into a batch and broadcast | . Example . { \"header\": { \"id\": \"4ea27cce-a103-4187-b318-f7b20fd87bf3\", \"cid\": \"00d20cba-76ed-431d-b9ff-f04b4cbee55c\", \"type\": \"private\", \"txtype\": \"batch_pin\", \"author\": \"did:firefly:org/acme\", \"key\": \"0xD53B0294B6a596D404809b1d51D1b4B3d1aD4945\", \"created\": \"2022-05-16T01:23:10Z\", \"namespace\": \"ns1\", \"group\": \"781caa6738a604344ae86ee336ada1b48a404a85e7041cf75b864e50e3b14a22\", \"topics\": [ \"topic1\" ], \"tag\": \"blue_message\", \"datahash\": \"c07be180b147049baced0b6219d9ce7a84ab48f2ca7ca7ae949abb3fe6491b54\" }, \"localNamespace\": \"ns1\", \"state\": \"confirmed\", \"confirmed\": \"2022-05-16T01:23:16Z\", \"data\": [ { \"id\": \"fdf9f118-eb81-4086-a63d-b06715b3bb4e\", \"hash\": \"34cf848d896c83cdf433ea7bd9490c71800b316a96aac3c3a78a42a4c455d67d\" } ] } . Field Descriptions . | Field Name | Description | Type | . | header | The message header contains all fields that are used to build the message hash | MessageHeader | . | localNamespace | The local namespace of the message | string | . | hash | The hash of the message. Derived from the header, which includes the data hash | Bytes32 | . | batch | The UUID of the batch in which the message was pinned/transferred | UUID | . | txid | The ID of the transaction used to order/deliver this message | UUID | . | state | The current state of the message | FFEnum:\"staged\"\"ready\"\"sent\"\"pending\"\"confirmed\"\"rejected\"\"cancelled\" | . | confirmed | The timestamp of when the message was confirmed/rejected | FFTime | . | rejectReason | If a message was rejected, provides details on the rejection reason | string | . | data | The list of data elements attached to the message | DataRef[] | . | pins | For private messages, a unique pin hash:nonce is assigned for each topic | string[] | . | idempotencyKey | 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 | IdempotencyKey | . ", "url": "/firefly/head/reference/types/message.html", "relUrl": "/reference/types/message.html" - },"590": { + },"594": { "doc": "Message", "title": "MessageHeader", "content": "| Field Name | Description | Type | . | id | The UUID of the message. Unique to each message | UUID | . | cid | The correlation ID of the message. Set this when a message is a response to another message | UUID | . | type | The type of the message | FFEnum:\"definition\"\"broadcast\"\"private\"\"groupinit\"\"transfer_broadcast\"\"transfer_private\"\"approval_broadcast\"\"approval_private\" | . | txtype | The type of transaction used to order/deliver this message | FFEnum:\"none\"\"unpinned\"\"batch_pin\"\"network_action\"\"token_pool\"\"token_transfer\"\"contract_deploy\"\"contract_invoke\"\"contract_invoke_pin\"\"token_approval\"\"data_publish\" | . | author | The DID of identity of the submitter | string | . | key | The on-chain signing key used to sign the transaction | string | . | created | The creation time of the message | FFTime | . | namespace | The namespace of the message within the multiparty network | string | . | topics | A message topic associates this message with an ordered stream of data. A custom topic should be assigned - using the default topic is discouraged | string[] | . | tag | The message tag indicates the purpose of the message to the applications that process it | string | . | datahash | A single hash representing all data in the message. Derived from the array of data ids+hashes attached to this message | Bytes32 | . | txparent | The parent transaction that originally triggered this message | TransactionRef | . ", "url": "/firefly/head/reference/types/message.html#messageheader", "relUrl": "/reference/types/message.html#messageheader" - },"591": { + },"595": { "doc": "Message", "title": "TransactionRef", "content": "| Field Name | Description | Type | . | type | The type of the FireFly transaction | FFEnum: | . | id | The UUID of the FireFly transaction | UUID | . ", "url": "/firefly/head/reference/types/message.html#transactionref", "relUrl": "/reference/types/message.html#transactionref" - },"592": { + },"596": { "doc": "Message", "title": "DataRef", "content": "| Field Name | Description | Type | . | id | The UUID of the referenced data resource | UUID | . | hash | The hash of the referenced data | Bytes32 | . ", "url": "/firefly/head/reference/types/message.html#dataref", "relUrl": "/reference/types/message.html#dataref" - },"593": { + },"597": { "doc": "pages.moonbeam_testnet", "title": "Moonbeam Testnet", "content": " ", "url": "/firefly/head/tutorials/chains/moonbeam.html#moonbeam-testnet", "relUrl": "/tutorials/chains/moonbeam.html#moonbeam-testnet" - },"594": { + },"598": { "doc": "pages.moonbeam_testnet", "title": "Table of contents", "content": ". | Previous steps: Install the FireFly CLI | Create an evmconnect.yml config file | Creating a new stack | Start the stack | Get some DEV . | Confirm the transaction on Moonscan | . | Use the public testnet | . Starting with FireFly v1.1, it’s easy to connect to public Ethereum chains. This guide will walk you through the steps to create a local FireFly development environment and connect it to the public Moonbeam Alpha testnet. ", "url": "/firefly/head/tutorials/chains/moonbeam.html#table-of-contents", "relUrl": "/tutorials/chains/moonbeam.html#table-of-contents" - },"595": { + },"599": { "doc": "pages.moonbeam_testnet", "title": "Previous steps: Install the FireFly CLI", "content": "If you haven’t set up the FireFly CLI already, please go back to the Getting Started guide and read the section on how to Install the FireFly CLI. ← ① Install the FireFly CLI . ", "url": "/firefly/head/tutorials/chains/moonbeam.html#previous-steps-install-the-firefly-cli", "relUrl": "/tutorials/chains/moonbeam.html#previous-steps-install-the-firefly-cli" - },"596": { + },"600": { "doc": "pages.moonbeam_testnet", "title": "Create an evmconnect.yml config file", "content": "In order to connect to the Moonbeam testnet, you will need to set a few configuration options for the evmconnect blockchain connector. Create a text file called evmconnect.yml with the following contents: . confirmations: required: 4 # choose the number of confirmations you require policyengine.simple: fixedGasPrice: null gasOracle: mode: connector . For more info about confirmations, see Public vs. Permissioned . For this tutorial, we will assume this file is saved at ~/Desktop/evmconnect.yml. If your path is different, you will need to adjust the path in the next command below. ", "url": "/firefly/head/tutorials/chains/moonbeam.html#create-an-evmconnectyml-config-file", "relUrl": "/tutorials/chains/moonbeam.html#create-an-evmconnectyml-config-file" - },"597": { + },"601": { "doc": "pages.moonbeam_testnet", "title": "Creating a new stack", "content": "To create a local FireFly development stack and connect it to the Moonbeam Alpha testnet, we will use command line flags to customize the following settings: . | Create a new Ethereum based stack named moonbeam with 1 member | Disable multiparty mode. We are going to be using this FireFly node as a Web3 gateway, and we don’t need to communicate with a consortium here | Use an remote RPC node. This will create a signer locally, so that our signing key never leaves the development machine. | See the moonbeam docs and select an HTTPS RPC endpoint | Set the chain ID to 1287 (the correct ID for the Moonbeam Alpha testnet) | Merge the custom config created above with the generated evmconnect config file | . To do this, run the following command: . ff init ethereum moonbeam 1 \\ --multiparty=false \\ -n remote-rpc \\ --remote-node-url <selected RPC endpoint> \\ --chain-id 1287 \\ --connector-config ~/Desktop/evmconnect.yml . ", "url": "/firefly/head/tutorials/chains/moonbeam.html#creating-a-new-stack", "relUrl": "/tutorials/chains/moonbeam.html#creating-a-new-stack" - },"598": { + },"602": { "doc": "pages.moonbeam_testnet", "title": "Start the stack", "content": "Now you should be able to start your stack by running: . ff start moonbeam . After some time it should print out the following: . Web UI for member '0': http://127.0.0.1:5000/ui Sandbox UI for member '0': http://127.0.0.1:5109 To see logs for your stack run: ff logs moonbeam . ", "url": "/firefly/head/tutorials/chains/moonbeam.html#start-the-stack", "relUrl": "/tutorials/chains/moonbeam.html#start-the-stack" - },"599": { + },"603": { "doc": "pages.moonbeam_testnet", "title": "Get some DEV", "content": "At this point you should have a working FireFly stack, talking to a public chain. However, you won’t be able to run any transactions just yet, because you don’t have any way to pay for gas. A testnet faucet can give us some DEV, the native token for Moonbeam. First, you will need to know what signing address your FireFly node is using. To check that, you can run: . ff accounts list moonbeam [ { \"address\": \"0x02d42c32a97c894486afbc7b717edff50c70b292\", \"privateKey\": \"...\" } ] . Copy the address listed in the output from this command. Go to https://apps.moonbeam.network/moonbase-alpha/faucet/ and paste the address in the form. Click the Submit button. Confirm the transaction on Moonscan . You should be able to go lookup your account on Moonscan for the Moonbase Alpha testnet and see that you now have a sufficient balance of DEV. Simply paste in your account address to search for it. ", "url": "/firefly/head/tutorials/chains/moonbeam.html#get-some-dev", "relUrl": "/tutorials/chains/moonbeam.html#get-some-dev" - },"600": { + },"604": { "doc": "pages.moonbeam_testnet", "title": "Use the public testnet", "content": "Now that you have everything set up, you can follow one of the other FireFly guides such as Using Tokens or Custom Smart Contracts. For detailed instructions on interacting with the Moonbeam Alpha testnet, please see the Moonbeam docs. ", "url": "/firefly/head/tutorials/chains/moonbeam.html#use-the-public-testnet", "relUrl": "/tutorials/chains/moonbeam.html#use-the-public-testnet" - },"601": { + },"605": { "doc": "pages.moonbeam_testnet", "title": "pages.moonbeam_testnet", "content": " ", "url": "/firefly/head/tutorials/chains/moonbeam.html", "relUrl": "/tutorials/chains/moonbeam.html" - },"602": { + },"606": { "doc": "Multiparty Event Sequencing", "title": "Multiparty Event Sequencing", "content": " ", "url": "/firefly/head/architecture/multiparty_event_sequencing.html", "relUrl": "/architecture/multiparty_event_sequencing.html" - },"603": { + },"607": { "doc": "Multiparty Event Sequencing", "title": "Table of contents", "content": ". | Transaction Submission | Blockchain Ordering | Message Assembly | Event Processing | . ", "url": "/firefly/head/architecture/multiparty_event_sequencing.html#table-of-contents", "relUrl": "/architecture/multiparty_event_sequencing.html#table-of-contents" - },"604": { + },"608": { "doc": "Multiparty Event Sequencing", "title": "Transaction Submission", "content": ". | An individual FireFly instance preserves the order that it received messages from application instances. | Where possible, batching is used to roll-up hundreds of transactions into a single blockchain transaction. | Blockchain allows these messages to be globally sequenced with messages submitted by other members of the network. | . ", "url": "/firefly/head/architecture/multiparty_event_sequencing.html#transaction-submission", "relUrl": "/architecture/multiparty_event_sequencing.html#transaction-submission" - },"605": { + },"609": { "doc": "Multiparty Event Sequencing", "title": "Blockchain Ordering", "content": ". | All member FireFly runtimes see every transaction in the same sequence. | This includes when transactions are being submitted by both sides concurrently. | . ", "url": "/firefly/head/architecture/multiparty_event_sequencing.html#blockchain-ordering", "relUrl": "/architecture/multiparty_event_sequencing.html#blockchain-ordering" - },"606": { + },"610": { "doc": "Multiparty Event Sequencing", "title": "Message Assembly", "content": ". | A queue of events is maintained for each matching app subscription. | The public/private payloads travel separately to the blockchain, and arrive at different times. FireFly assembles these together prior to delivery. | If data associated with a blockchain transaction is late, or does not arrive, all messages on the same “context” will be blocked. | It is good practice to send messages that don’t need to be processed in order, with different “context” fields. For example use the ID of your business transaction, or other long-running process / customer identifier. | . ", "url": "/firefly/head/architecture/multiparty_event_sequencing.html#message-assembly", "relUrl": "/architecture/multiparty_event_sequencing.html#message-assembly" - },"607": { + },"611": { "doc": "Multiparty Event Sequencing", "title": "Event Processing", "content": ". | Events are processed consistently by all parties. | All FireFly runtimes see every event that they are subscribed to, in the same sequence. | The submitter must also apply the logic only in the sequence ordered by the blockhain. It cannot assume the order even if it is the member that submitted it. | . ", "url": "/firefly/head/architecture/multiparty_event_sequencing.html#event-processing", "relUrl": "/architecture/multiparty_event_sequencing.html#event-processing" - },"608": { + },"612": { "doc": "pages.multiparty_features", "title": "Enterprise multi-party systems", "content": " ", "url": "/firefly/head/overview/multiparty_features.html#enterprise-multi-party-systems", "relUrl": "/overview/multiparty_features.html#enterprise-multi-party-systems" - },"609": { + },"613": { "doc": "pages.multiparty_features", "title": "Table of contents", "content": ". | Enterprise multi-party systems . | Introduction | Points of difference | Use Case Example | . | . ", "url": "/firefly/head/overview/multiparty_features.html#table-of-contents", "relUrl": "/overview/multiparty_features.html#table-of-contents" - },"610": { + },"614": { "doc": "pages.multiparty_features", "title": "Introduction", "content": "Multiparty mode has all the features in Gateway mode with the added benefit of multi-party process flows. A multi-party system is a class of application empowered by the technology revolution of blockchain digital ledger technology (DLT), and emerging cryptographic proof technologies like zero-knowledge proofs (ZKPs) and trusted execution environments (TEEs). By combining these technologies with existing best practice technologies for data security in regulated industries, multi-party systems allow businesses to collaborate in ways previously impossible. Through agreement on a common source of truth, such as the completion of a step in a business process to proceed, or the existence and ownership of a unique asset, businesses can cut out huge inefficiencies in existing multi-party processes. New business and transaction models can be achieved, unlocking value in assets and data that were previously siloed within a single organization. Governance and incentive models can be created to enable secure collaboration in new ways, without compromising the integrity of an individual organization. The technology is most powerful in ecosystems of “coopetition”, where privacy and security requirements are high. Multi-party systems establish new models of trust, with easy to prove outcomes that minimize the need for third party arbitration, and costly investigation into disputes. ", "url": "/firefly/head/overview/multiparty_features.html#introduction", "relUrl": "/overview/multiparty_features.html#introduction" - },"611": { + },"615": { "doc": "pages.multiparty_features", "title": "Points of difference", "content": "Integration with existing systems of record is critical to unlock the potential of these new ecosystems. So multi-party systems embrace the existing investments of each party, rather than seeking to unify or replace them. Multi-party systems are different from centralized third-party systems, because each party retains sovereignty over: . | Their application instance | Their private data | Their business processes | Their proprietary business logic | Their internal business processes and IT controls | . ", "url": "/firefly/head/overview/multiparty_features.html#points-of-difference", "relUrl": "/overview/multiparty_features.html#points-of-difference" - },"612": { + },"616": { "doc": "pages.multiparty_features", "title": "Use Case Example", "content": "There are many multiparty use cases. An example for healthcare is detailed below. Patient care requires multiple entities to work together including healthcare providers, insurance companies, and medical systems. Sharing data between these parties is inefficient and prone to errors and patient information must be kept secure and up to date. Blockchain’s shared ledger makes it possible to automate data sharing while ensuring accuracy and privacy. In a Multi-party FireFly system, entities are able to share data privately as detailed in the “Data Exchange” section. For example, imagine a scenario where there is one healthcare provider and two insurance companies operating in a multi-party system. Insurance company A may send private data to the healthcare provider that insurance company B is not privy to. While insurance company B may not know the contents of data transferred, it may verify that a transfer of data did occur. This validation is all thats needed to maintain an up to date state of the blockchain. In a larger healthcare ecosystem with many members, a similar concept may emerge with multiple variations of members. ", "url": "/firefly/head/overview/multiparty_features.html#use-case-example", "relUrl": "/overview/multiparty_features.html#use-case-example" - },"613": { + },"617": { "doc": "pages.multiparty_features", "title": "pages.multiparty_features", "content": " ", "url": "/firefly/head/overview/multiparty_features.html", "relUrl": "/overview/multiparty_features.html" - },"614": { + },"618": { "doc": "pages.multiparty_flow", "title": "Multiparty Process Flows", "content": ". ", "url": "/firefly/head/overview/multiparty/multiparty_flow.html#multiparty-process-flows", "relUrl": "/overview/multiparty/multiparty_flow.html#multiparty-process-flows" - },"615": { + },"619": { "doc": "pages.multiparty_flow", "title": "Flow features", "content": "Data, value, and process flow are how decentralized systems function. In an enterprise context not all of this data can be shared with all parties, and some is very sensitive. Private data flow . Managing the flows of data so that the right information is shared with the right parties, at the right time, means thinking carefully about what data flows over what channel. The number of enterprise solutions where all data can flow directly through the blockchain, is vanishingly small. Coordinating these different data flows is often one of the biggest pieces of heavy lifting solved on behalf of the application by a robust framework like FireFly: . | Establishing the identity of participants so data can be shared | Securing the transfer of data off-chain | Coordinating off-chain data flow with on-chain data flow | Managing sequence for deterministic outcomes for all parties | Integrating off-chain private execution with multi-step stateful business logic | . Multi-party business process flow . Web3 has the potential to transform how ecosystems interact. Digitally transforming legacy process flows, by giving deterministic outcomes that are trusted by all parties, backed by new forms of digital trust between parties. Some of the most interesting use cases require complex multi-step business process across participants. The Web3 version of business process management, comes with a some new challenges. So you need the platform to: . | Provide a robust event-driven programming model fitting a “state machine” approach | Integrate with the decentralized application stack of each participant | Allow integration with the core-systems and human decision making of each participant | Provide deterministic ordering between all parties | Provide identity assurance and proofs for data flow / transition logic | . Data exchange . Business processes need data, and that data comes in many shapes and sizes. The platform needs to handle all of them: . | Large files and documents, as well as application data | Uniqueness / Enterprise NFTs - agreement on a single “foreign key” for a record | Non-repudiation, and acknowledgement of receipt | Coordination of flows of data, with flows of value - delivery vs. payment scenarios | . ", "url": "/firefly/head/overview/multiparty/multiparty_flow.html#flow-features", "relUrl": "/overview/multiparty/multiparty_flow.html#flow-features" - },"616": { + },"620": { "doc": "pages.multiparty_flow", "title": "Building multi-party flows", "content": "The ability to globally sequence events across parties is a game changing capability of a multiparty system. FireFly is designed to allow developers to harnesses that power in the application layer, to build sophisticated multi-party APIs and user experiences. | Build multi-party business processes where there is one agreed outcome: . | Agree the trigger, inputs, outputs of each step in the process | Agree any common “rules of the road” must be adhered to | . | Look back at your shared history, when deciding to commit to the next step: . | Fast rich-query cache, backed by a private database | Initiate the next step through automated or manual decision making | Only consider a step final once it’s multi-party sequence has been confirmed | . | Gain big efficiencies in how multi-party business processes work: . | Once locked in, a step is consider final - attested to by the party | If two parties submit conflicting actions, one wins, and one loses | Avoids complex compensation logic in the business orchestration layer | Provides one clear source of truth to quickly resolve multi-party disputes | . | Program multi-party apps using the tools you know: . | REST APIs for triggering the next step in a process, and querying history | WebSockets and Webhooks for events (pluggable to other event transports) | Remember - each party runs their own copy of the app, with their own private data | . | Allow each party to integrate into their existing core systems: . | Realtime or batch | Human workflows | Proprietary business logic that is unique to one party | . | Avoid sensitive data written to the blockchain: . | Works in bi-lateral and multi-lateral scenarios | Designed to limit leaking other “metadata” about the transaction as well | Share partial history with different participants in a | . | No requirement to write custom on-chain smart contract logic: . | Can be combined with rich custom on-chain logic as well | . | . ", "url": "/firefly/head/overview/multiparty/multiparty_flow.html#building-multi-party-flows", "relUrl": "/overview/multiparty/multiparty_flow.html#building-multi-party-flows" - },"617": { + },"621": { "doc": "pages.multiparty_flow", "title": "Innovate fast", "content": "Building a successful multi-party system is often about business experimentation, and business results. Proving the efficiency gains, and new business models, made possible by working together in a new way under a new system of trust. Things that can get in the way of that innovation, can include concerns over data privacy, technology maturity, and constraints on autonomy of an individual party in the system. An easy to explain position on how new technology components are used, where data lives, and how business process independence is maintained can really help parties make the leap of faith necessary to take the step towards a new model. Keys to success often include building great user experiences that help digitize clunky decades old manual processes. Also easy to integrate with APIs, what embrace the existing core systems of record that are establish within each party. ", "url": "/firefly/head/overview/multiparty/multiparty_flow.html#innovate-fast", "relUrl": "/overview/multiparty/multiparty_flow.html#innovate-fast" - },"618": { + },"622": { "doc": "pages.multiparty_flow", "title": "Consider the on-chain toolbox too", "content": "There is a huge amount of value that deterministic execution of multi-party logic within the blockchain can add. However, the more compute is made fully deterministic via a blockchain consensus algorithm validated by multiple parties beyond those with a business need for access to the data, the more sensitivity needs to be taken to data privacy. Also bear in mind any data that is used in this processing becomes immutable - it can never be deleted. The core constructs of blockchain are a great place to start. Almost every process can be enhanced with pre-built fungible and non-fungible tokens, for example. Maybe it’s to build a token economy that enhances the value parties get from the system, or to encourage healthy participation (and discourage bad behavior). Or maybe it’s to track exactly which party owns a document, asset, or action within a process using NFTs. On top of this you can add advanced tools like digital escrow, signature / threshold based voting on outcomes, and atomic swaps of value/ownership. The investment in building this bespoke on-chain logic is higher than building the off-chain pieces (and there are always some off-chain pieces as we’ve discussed), so it’s about finding the kernel of value the blockchain can provide to differentiate your solution from a centralized database solution. The power provided by deterministic sequencing of events, attested by signatures, and pinned to private data might be sufficient for some cases. In others the token constructs are the key value that differentiates the decentralized ecosystem. Whatever it is, it’s important it is identified and crafted carefully. Note that advanced privacy preserving techniques such as zero-knowledge proofs (ZKP) are gaining traction and hardening in their production readiness and efficiency. Expect these to play an increasing role in the technology stack of multiparty systems (and Hyperledger FireFly) in the future. Learn more in the Deterministic Compute section. ", "url": "/firefly/head/overview/multiparty/multiparty_flow.html#consider-the-on-chain-toolbox-too", "relUrl": "/overview/multiparty/multiparty_flow.html#consider-the-on-chain-toolbox-too" - },"619": { + },"623": { "doc": "pages.multiparty_flow", "title": "pages.multiparty_flow", "content": " ", "url": "/firefly/head/overview/multiparty/multiparty_flow.html", "relUrl": "/overview/multiparty/multiparty_flow.html" - },"620": { + },"624": { "doc": "Namespace", "title": "Namespace", "content": " ", "url": "/firefly/head/reference/types/namespace.html", "relUrl": "/reference/types/namespace.html" - },"621": { + },"625": { "doc": "Namespace", "title": "Table of contents", "content": ". | Namespace . | Example | Field Descriptions | . | . ", "url": "/firefly/head/reference/types/namespace.html#table-of-contents", "relUrl": "/reference/types/namespace.html#table-of-contents" - },"622": { + },"626": { "doc": "Namespace", "title": "Namespace", "content": "A namespace is a logical isolation domain for different applications, or tenants, that share the FireFly node. Significant evolution of the Hyperledger FireFly namespace construct, is proposed under FIR-12 . Example . { \"name\": \"default\", \"networkName\": \"default\", \"description\": \"Default predefined namespace\", \"created\": \"2022-05-16T01:23:16Z\" } . Field Descriptions . | Field Name | Description | Type | . | name | The local namespace name | string | . | networkName | The shared namespace name within the multiparty network | string | . | description | A description of the namespace | string | . | created | The time the namespace was created | FFTime | . ", "url": "/firefly/head/reference/types/namespace.html", "relUrl": "/reference/types/namespace.html" - },"623": { + },"627": { "doc": "Namespaces", "title": "Namespaces", "content": " ", "url": "/firefly/head/reference/namespaces.html", "relUrl": "/reference/namespaces.html" - },"624": { + },"628": { "doc": "Namespaces", "title": "Table of contents", "content": ". | Introduction to Namespaces . | Multi-party Namespaces | Gateway Namespaces | . | Configuration . | Config Restrictions | . | Definitions | Local Definitions | . ", "url": "/firefly/head/reference/namespaces.html#table-of-contents", "relUrl": "/reference/namespaces.html#table-of-contents" - },"625": { + },"629": { "doc": "Namespaces", "title": "Introduction to Namespaces", "content": "Namespaces are a construct for segregating data and operations within a FireFly supernode. Each namespace is an isolated environment within a FireFly runtime, that allows independent configuration of: . | Plugin and infrastructure components | API security | Identity broadcasting | On-chain data indexing | How datatypes, locations of on-chain contrats, etc. should be shared | . They can be thought of in two basic modes: . Multi-party Namespaces . This namespace is shared with one or more other FireFly nodes. It requires three types of communication plugins - blockchain, data exchange, and shared storage. Organization and node identities must be claimed with an identity broadcast when joining the namespace, which establishes credentials for blockchain and off-chain communication. Shared objects can be defined in the namespace (such as datatypes and token pools), and details of them will be implicitly broadcast to other members. This type of namespace is used when multiple parties need to share on- and off-chain data and agree upon the ordering and authenticity of that data. For more information, see the multi-party system overview. Gateway Namespaces . Nothing in this namespace will be shared automatically, and no assumptions are made about whether other parties connected through this namespace are also using Hyperledger FireFly. Plugins for data exchange and shared storage are not supported. If any identities or definitions are created in this namespace, they will be stored in the local database, but will not be shared implicitly outside the node. This type of namespace is mainly used when interacting directly with a blockchain, without assuming that the interaction needs to conform to FireFly’s multi-party system model. ", "url": "/firefly/head/reference/namespaces.html#introduction-to-namespaces", "relUrl": "/reference/namespaces.html#introduction-to-namespaces" - },"626": { + },"630": { "doc": "Namespaces", "title": "Configuration", "content": "FireFly nodes can be configured with one or many namespaces of different modes. This means that a single FireFly node can be used to interact with multiple distinct blockchains, multiple distinct token economies, and multiple business networks. Below is an example plugin and namespace configuration containing both a multi-party and gateway namespace: . plugins: database: - name: database0 type: sqlite3 sqlite3: migrations: auto: true url: /etc/firefly/db?_busy_timeout=5000 blockchain: - name: blockchain0 type: ethereum ethereum: ethconnect: url: http://ethconnect_0:8080 topic: \"0\" - name: blockchain1 type: ethereum ethereum: ethconnect: url: http://ethconnect_01:8080 topic: \"0\" dataexchange: - name: dataexchange0 type: ffdx ffdx: url: http://dataexchange_0:3000 sharedstorage: - name: sharedstorage0 type: ipfs ipfs: api: url: http://ipfs_0:5001 gateway: url: http://ipfs_0:8080 tokens: - name: erc20_erc721 broadcastName: erc20_erc721 type: fftokens fftokens: url: http://tokens_0_0:3000 namespaces: default: alpha predefined: - name: alpha description: Default predefined namespace defaultKey: 0x123456 plugins: [database0, blockchain0, dataexchange0, sharedstorage0, erc20_erc721] multiparty: networkNamespace: alpha enabled: true org: name: org0 description: org0 key: 0x123456 node: name: node0 description: node0 contract: - location: address: 0x4ae50189462b0e5d52285f59929d037f790771a6 firstEvent: 0 - location: address: 0x3c1bef20a7858f5c2f78bda60796758d7cafff27 firstEvent: 5000 - name: omega defaultkey: 0x48a54f9964d7ceede2d6a8b451bf7ad300c7b09f description: Gateway namespace plugins: [database0, blockchain1, erc20_erc721] . The namespaces.predefined object contains the follow sub-keys: . | defaultKey is a blockchain key used to sign transactions when none is specified (in multi-party mode, defaults to the org key) | plugins is an array of plugin names to be activated for this namespace (defaults to all available plugins if omitted) | multiparty.networkNamespace is the namespace name to be sent in plugin calls, if it differs from the locally used name (useful for interacting with multiple shared namespaces of the same name - defaults to the value of name) | multiparty.enabled controls if multi-party mode is enabled (defaults to true if an org key or org name is defined on this namespace or in the deprecated org section at the root) | multiparty.org is the root org identity for this multi-party namespace (containing name, description, and key) | multiparty.node is the local node identity for this multi-party namespace (containing name and description) | multiparty.contract is an array of objects describing the location(s) of a FireFly multi-party smart contract. Its children are blockchain-agnostic location and firstEvent fields, with formats identical to the same fields on custom contract interfaces and contract listeners. The blockchain plugin will interact with the first contract in the list until instructions are received to terminate it and migrate to the next. | . Config Restrictions . | name must be unique on this node | for historical reasons, “ff_system” is a reserved string and cannot be used as a name or multiparty.networkNamespace | a database plugin is required for every namespace | if multiparty.enabled is true, plugins must include one each of blockchain, dataexchange, and sharedstorage | if multiparty.enabled is false, plugins must not include dataexchange or sharedstorage | at most one of each type of plugin is allowed per namespace, except for tokens (which may have many per namespace) | . All namespaces must be called out in the FireFly config file in order to be valid. Namespaces found in the database but not represented in the config file will be ignored. ", "url": "/firefly/head/reference/namespaces.html#configuration", "relUrl": "/reference/namespaces.html#configuration" - },"627": { + },"631": { "doc": "Namespaces", "title": "Definitions", "content": "In FireFly, definitions are immutable payloads that are used to define identities, datatypes, smart contract interfaces, token pools, and other constructs. Each type of definition in FireFly has a schema that it must adhere to. Some definitions also have a name and a version which must be unique within a namespace. In a multiparty namespace, definitions are broadcasted to other organizations. ", "url": "/firefly/head/reference/namespaces.html#definitions", "relUrl": "/reference/namespaces.html#definitions" - },"628": { + },"632": { "doc": "Namespaces", "title": "Local Definitions", "content": "The following are all “definition” types in FireFly: . | datatype | group | token pool | contract interface | contract API | organization (deprecated) | node (deprecated) | identity claim | identity verification | identity update | . For gateway namespaces, the APIs which create these definitions will become an immediate local database insert, instead of performing a broadcast. Additional caveats: . | identities in this mode will not undergo any claim/verification process, but will be created and stored locally | datatypes and groups will not be supported, as they are only useful in the context of messaging (which is disabled in gateway namespaces) | . ", "url": "/firefly/head/reference/namespaces.html#local-definitions", "relUrl": "/reference/namespaces.html#local-definitions" - },"629": { + },"633": { "doc": "NextPin", "title": "NextPin", "content": " ", "url": "/firefly/head/reference/types/nextpin.html", "relUrl": "/reference/types/nextpin.html" - },"630": { + },"634": { "doc": "NextPin", "title": "Table of contents", "content": ". | NextPin . | Example | Field Descriptions | . | . ", "url": "/firefly/head/reference/types/nextpin.html#table-of-contents", "relUrl": "/reference/types/nextpin.html#table-of-contents" - },"631": { + },"635": { "doc": "NextPin", "title": "NextPin", "content": "Next-pins are maintained by each member of a privacy group, in order to detect if a on-chain transaction with a given “pin” for a message represents the next message for any member of the privacy group. This allows every member to maintain a global order of transactions within a topic in a privacy group, without leaking the same hash between the messages that are communicated in that group. See Group for more information on privacy groups. Example . { \"namespace\": \"ns1\", \"context\": \"a25b65cfe49e5ed78c256e85cf07c96da938144f12fcb02fe4b5243a4631bd5e\", \"identity\": \"did:firefly:org/example\", \"hash\": \"00e55c63905a59782d5bc466093ead980afc4a2825eb68445bcf1312cc3d6de2\", \"nonce\": 12345 } . Field Descriptions . | Field Name | Description | Type | . | namespace | The namespace of the next-pin | string | . | context | The context the next-pin applies to - the hash of the privacy group-hash + topic. The group-hash is only known to the participants (can itself contain a salt in the group-name). This context is combined with the member and nonce to determine the final hash that is written on-chain | Bytes32 | . | identity | The member of the privacy group the next-pin applies to | string | . | hash | The unique masked pin string | Bytes32 | . | nonce | The numeric index - which is monotonically increasing for each member of the privacy group | int64 | . ", "url": "/firefly/head/reference/types/nextpin.html", "relUrl": "/reference/types/nextpin.html" - },"632": { + },"636": { "doc": "Node Component Architecture", "title": "Node Component Architecture", "content": " ", "url": "/firefly/head/architecture/node_component_architecture.html", "relUrl": "/architecture/node_component_architecture.html" - },"633": { + },"637": { "doc": "Node Component Architecture", "title": "Table of contents", "content": ". | What is a FireFly Node? | Runtimes | Responsibilities & Pluggable Elements | Code Structure | . ", "url": "/firefly/head/architecture/node_component_architecture.html#table-of-contents", "relUrl": "/architecture/node_component_architecture.html#table-of-contents" - },"634": { + },"638": { "doc": "Node Component Architecture", "title": "What is a FireFly Node?", "content": "The core architecture of a FireFly node can be broken down into the following three areas: . | The various runtimes encapsulating the node. | The core runtime responsibilities and pluggable elements. | The actual code running inside the node. | . ", "url": "/firefly/head/architecture/node_component_architecture.html#what-is-a-firefly-node", "relUrl": "/architecture/node_component_architecture.html#what-is-a-firefly-node" - },"635": { + },"639": { "doc": "Node Component Architecture", "title": "Runtimes", "content": "What fundamentally is a node - left side of the above diagram. | It is a collection of multiple runtimes with a single unified HTTPS/Websocket API (exposed by the Core). | It has a private database, containing your private data, and data received from others in the network. | It has connectivity out to other parties in the network, through runtimes (Blockchain, Shared Filesystems, Messaging etc.). | . ", "url": "/firefly/head/architecture/node_component_architecture.html#runtimes", "relUrl": "/architecture/node_component_architecture.html#runtimes" - },"636": { + },"640": { "doc": "Node Component Architecture", "title": "Responsibilities & Pluggable Elements", "content": "What are the core runtime responsibilities, and pluggable elements - right side of the above diagram. | The core elements of function that FireFly performs, and which runtime is responsible. | This means some insight into core itself, and the jobs it performs, but not full code structure. | More importantly, what the split of responsibilities is between Connectors and Infrastructure Runtimes. | Connectors are the bridging runtimes, that know how to talk to a particular runtime. | They run separately to the core (like a microservice architecture of an app). | They can be written in any language (not just Go) - Java, TypeScript, Rust, Python, .NET etc. | They can use any network transport (not just HTTPS/Websockets) - GRPC, AMQP, UDP etc. | They connect to the core with a Golang shim - see separate Plugin Architecture discussion. | In some special cases (like the Database) the Golang shim does not need a connector runtime. | . | . | Infrastructure Runtimes are the core runtimes for multi-party system activities. | Blockchain nodes - Ethereum (Hyperledger Besu, Quorum, Geth), Hyperledger Fabric, Corda etc. | Shared strorage - IPFS etc. | Database - PostreSQL, CouchDB etc. | . | . | . | . ", "url": "/firefly/head/architecture/node_component_architecture.html#responsibilities--pluggable-elements", "relUrl": "/architecture/node_component_architecture.html#responsibilities--pluggable-elements" - },"637": { + },"641": { "doc": "Node Component Architecture", "title": "Code Structure", "content": "What is the code structure inside the core. | The README.md is the reference for this. | Developers contributing to FireFly, on the core, or building new plugins, need this level of detail. | A reconciliation is underway to ensure the medium-level view correlates well with this code structure. | . | . ", "url": "/firefly/head/architecture/node_component_architecture.html#code-structure", "relUrl": "/architecture/node_component_architecture.html#code-structure" - },"638": { + },"642": { "doc": "Operation", "title": "Operation", "content": " ", "url": "/firefly/head/reference/types/operation.html", "relUrl": "/reference/types/operation.html" - },"639": { + },"643": { "doc": "Operation", "title": "Table of contents", "content": ". | Operation . | Operation status | Example | Field Descriptions | . | . ", "url": "/firefly/head/reference/types/operation.html#table-of-contents", "relUrl": "/reference/types/operation.html#table-of-contents" - },"640": { + },"644": { "doc": "Operation", "title": "Operation", "content": "Operations are stateful external actions that FireFly triggers via plugins. They can succeed or fail. They are grouped into Transactions in order to accomplish a single logical task. The diagram below shows the different types of operation that are performed by each FireFly plugin type. The color coding (and numbers) map those different types of operation to the Transaction types that include those operations. Operation status . When initially created an operation is in Initialized state. Once the operation has been successfully sent to its respective plugin to be processed its status moves to Pending state. This indicates that the plugin is processing the operation. The operation will then move to Succeeded or Failed state depending on the outcome. In the event that an operation could not be submitted to the plugin for processing, for example because the plugin’s microservice was temporarily unavailable, the operation will remain in Initialized state. Re-submitting the same FireFly API call using the same idempotency key will cause FireFly to re-submit the operation to its plugin. Example . { \"id\": \"04a8b0c4-03c2-4935-85a1-87d17cddc20a\", \"namespace\": \"ns1\", \"tx\": \"99543134-769b-42a8-8be4-a5f8873f969d\", \"type\": \"sharedstorage_upload_batch\", \"status\": \"Succeeded\", \"plugin\": \"ipfs\", \"input\": { \"id\": \"80d89712-57f3-48fe-b085-a8cba6e0667d\" }, \"output\": { \"payloadRef\": \"QmWj3tr2aTHqnRYovhS2mQAjYneRtMWJSU4M4RdAJpJwEC\" }, \"created\": \"2022-05-16T01:23:15Z\" } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the operation | UUID | . | namespace | The namespace of the operation | string | . | tx | The UUID of the FireFly transaction the operation is part of | UUID | . | type | The type of the operation | FFEnum:\"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\" | . | status | The current status of the operation | OpStatus | . | plugin | The plugin responsible for performing the operation | string | . | input | The input to this operation | JSONObject | . | output | Any output reported back from the plugin for this operation | JSONObject | . | error | Any error reported back from the plugin for this operation | string | . | created | The time the operation was created | FFTime | . | updated | The last update time of the operation | FFTime | . | retry | If this operation was initiated as a retry to a previous operation, this field points to the UUID of the operation being retried | UUID | . ", "url": "/firefly/head/reference/types/operation.html", "relUrl": "/reference/types/operation.html" - },"641": { + },"645": { "doc": "OperationWithDetail", "title": "OperationWithDetail", "content": " ", "url": "/firefly/head/reference/types/operationwithdetail.html", "relUrl": "/reference/types/operationwithdetail.html" - },"642": { + },"646": { "doc": "OperationWithDetail", "title": "Table of contents", "content": ". | OperationWithDetail . | Example | Field Descriptions | . | . ", "url": "/firefly/head/reference/types/operationwithdetail.html#table-of-contents", "relUrl": "/reference/types/operationwithdetail.html#table-of-contents" - },"643": { + },"647": { "doc": "OperationWithDetail", "title": "OperationWithDetail", "content": "Operation with detail is an extension to operations that allow additional information to be encapsulated with an operation. An operation can be supplemented by a connector and that information will be returned in the detail field. Example . { \"id\": \"04a8b0c4-03c2-4935-85a1-87d17cddc20a\", \"namespace\": \"ns1\", \"tx\": \"99543134-769b-42a8-8be4-a5f8873f969d\", \"type\": \"sharedstorage_upload_batch\", \"status\": \"Succeeded\", \"plugin\": \"ipfs\", \"input\": { \"id\": \"80d89712-57f3-48fe-b085-a8cba6e0667d\" }, \"output\": { \"payloadRef\": \"QmWj3tr2aTHqnRYovhS2mQAjYneRtMWJSU4M4RdAJpJwEC\" }, \"created\": \"2022-05-16T01:23:15Z\", \"detail\": { \"created\": \"2023-01-27T17:04:24.26406392Z\", \"firstSubmit\": \"2023-01-27T17:04:24.419913295Z\", \"gas\": \"4161076\", \"gasPrice\": \"0\", \"history\": [ { \"actions\": [ { \"action\": \"AssignNonce\", \"count\": 1, \"lastOccurrence\": \"\", \"time\": \"\" }, { \"action\": \"RetrieveGasPrice\", \"count\": 1, \"lastOccurrence\": \"2023-01-27T17:11:41.161213303Z\", \"time\": \"2023-01-27T17:11:41.161213303Z\" }, { \"action\": \"Submit\", \"count\": 1, \"lastOccurrence\": \"2023-01-27T17:11:41.222374636Z\", \"time\": \"2023-01-27T17:11:41.222374636Z\" } ], \"subStatus\": \"Received\", \"time\": \"2023-01-27T17:11:41.122965803Z\" }, { \"actions\": [ { \"action\": \"ReceiveReceipt\", \"count\": 1, \"lastOccurrence\": \"2023-01-27T17:11:47.930332625Z\", \"time\": \"2023-01-27T17:11:47.930332625Z\" }, { \"action\": \"Confirm\", \"count\": 1, \"lastOccurrence\": \"2023-01-27T17:12:02.660275549Z\", \"time\": \"2023-01-27T17:12:02.660275549Z\" } ], \"subStatus\": \"Tracking\", \"time\": \"2023-01-27T17:11:41.222400219Z\" }, { \"actions\": [], \"subStatus\": \"Confirmed\", \"time\": \"2023-01-27T17:12:02.660309382Z\" } ], \"historySummary\": [ { \"count\": 1, \"subStatus\": \"Received\" }, { \"action\": \"AssignNonce\", \"count\": 1 }, { \"action\": \"RetrieveGasPrice\", \"count\": 1 }, { \"action\": \"Submit\", \"count\": 1 }, { \"count\": 1, \"subStatus\": \"Tracking\" }, { \"action\": \"ReceiveReceipt\", \"count\": 1 }, { \"action\": \"Confirm\", \"count\": 1 }, { \"count\": 1, \"subStatus\": \"Confirmed\" } ], \"sequenceId\": \"0185f42f-fec8-93df-aeba-387417d477e0\", \"status\": \"Succeeded\", \"transactionHash\": \"0xfb39178fee8e725c03647b8286e6f5cb13f982abf685479a9ee59e8e9d9e51d8\" } } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the operation | UUID | . | namespace | The namespace of the operation | string | . | tx | The UUID of the FireFly transaction the operation is part of | UUID | . | type | The type of the operation | FFEnum:\"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\" | . | status | The current status of the operation | OpStatus | . | plugin | The plugin responsible for performing the operation | string | . | input | The input to this operation | JSONObject | . | output | Any output reported back from the plugin for this operation | JSONObject | . | error | Any error reported back from the plugin for this operation | string | . | created | The time the operation was created | FFTime | . | updated | The last update time of the operation | FFTime | . | retry | If this operation was initiated as a retry to a previous operation, this field points to the UUID of the operation being retried | UUID | . | detail | Additional detailed information about an operation provided by the connector | `` | . ", "url": "/firefly/head/reference/types/operationwithdetail.html", "relUrl": "/reference/types/operationwithdetail.html" - },"644": { + },"648": { "doc": "pages.optimism", "title": "Optimism Testnet", "content": " ", "url": "/firefly/head/tutorials/chains/optimism.html#optimism-testnet", "relUrl": "/tutorials/chains/optimism.html#optimism-testnet" - },"645": { + },"649": { "doc": "pages.optimism", "title": "Table of contents", "content": ". | Previous steps: Install the FireFly CLI | Create an evmconnect.yml config file | Creating a new stack | Start the stack | Get some Optimism . | Confirm the transaction on Blockcscout | . | Use the public testnet | . Starting with FireFly v1.1, it’s easy to connect to public Ethereum chains. This guide will walk you through the steps to create a local FireFly development environment and connect it to the Optimism Goerli testnet. ", "url": "/firefly/head/tutorials/chains/optimism.html#table-of-contents", "relUrl": "/tutorials/chains/optimism.html#table-of-contents" - },"646": { + },"650": { "doc": "pages.optimism", "title": "Previous steps: Install the FireFly CLI", "content": "If you haven’t set up the FireFly CLI already, please go back to the Getting Started guide and read the section on how to Install the FireFly CLI. ← ① Install the FireFly CLI . ", "url": "/firefly/head/tutorials/chains/optimism.html#previous-steps-install-the-firefly-cli", "relUrl": "/tutorials/chains/optimism.html#previous-steps-install-the-firefly-cli" - },"647": { + },"651": { "doc": "pages.optimism", "title": "Create an evmconnect.yml config file", "content": "In order to connect to the Optimism testnet, you will need to set a few configuration options for the evmconnect blockchain connector. Create a text file called evmconnect.yml with the following contents: . confirmations: required: 4 # choose the number of confirmations you require policyengine.simple: fixedGasPrice: null gasOracle: mode: connector . For this tutorial, we will assume this file is saved at ~/Desktop/evmconnect.yml. If your path is different, you will need to adjust the path in the next command below. ", "url": "/firefly/head/tutorials/chains/optimism.html#create-an-evmconnectyml-config-file", "relUrl": "/tutorials/chains/optimism.html#create-an-evmconnectyml-config-file" - },"648": { + },"652": { "doc": "pages.optimism", "title": "Creating a new stack", "content": "To create a local FireFly development stack and connect it to the Optimism testnet, we will use command line flags to customize the following settings: . | Create a new Ethereum based stack named optimism with 1 member | Disable multiparty mode. We are going to be using this FireFly node as a Web3 gateway, and we don’t need to communicate with a consortium here | Use an remote RPC node. This will create a signer locally, so that our signing key never leaves the development machine. | See the optimism docs and select an HTTPS RPC endpoint. | Set the chain ID to 420 (the correct ID for the Optimism testnet) | Merge the custom config created above with the generated evmconnect config file | . To do this, run the following command: . ff init ethereum optimism 1 \\ --multiparty=false \\ -n remote-rpc \\ --remote-node-url <selected RPC endpoint> \\ --chain-id 420 \\ --connector-config ~/Desktop/evmconnect.yml . ", "url": "/firefly/head/tutorials/chains/optimism.html#creating-a-new-stack", "relUrl": "/tutorials/chains/optimism.html#creating-a-new-stack" - },"649": { + },"653": { "doc": "pages.optimism", "title": "Start the stack", "content": "Now you should be able to start your stack by running: . ff start optimism . After some time it should print out the following: . Web UI for member '0': http://127.0.0.1:5000/ui Sandbox UI for member '0': http://127.0.0.1:5109 To see logs for your stack run: ff logs optimism . ", "url": "/firefly/head/tutorials/chains/optimism.html#start-the-stack", "relUrl": "/tutorials/chains/optimism.html#start-the-stack" - },"650": { + },"654": { "doc": "pages.optimism", "title": "Get some Optimism", "content": "At this point you should have a working FireFly stack, talking to a public chain. However, you won’t be able to run any transactions just yet, because you don’t have any way to pay for gas. A testnet faucet can give us some OP, the native token for Optimism. First, you will need to know what signing address your FireFly node is using. To check that, you can run: . ff accounts list optimism [ { \"address\": \"0x235461d246ab95d367925b4e91bd2755a921fdd8\", \"privateKey\": \"...\" } ] . Copy the address listed in the output from this command. Go to https://optimismfaucet.xyz/. You will need to login to your Github account and paste the address in the form. Confirm the transaction on Blockcscout . You should be able to go lookup your account on Blockscout for Optimism testnet https://blockscout.com/optimism/goerli and see that you now have a balance of 100 OP. Simply paste in your account address to search for it. ", "url": "/firefly/head/tutorials/chains/optimism.html#get-some-optimism", "relUrl": "/tutorials/chains/optimism.html#get-some-optimism" - },"651": { + },"655": { "doc": "pages.optimism", "title": "Use the public testnet", "content": "Now that you have everything set up, you can follow one of the other FireFly guides such as Using Tokens or Custom Smart Contracts. For detailed instructions on deploying a custom smart contract to Optimism, please see the Optimism docs for instructions using various tools. ", "url": "/firefly/head/tutorials/chains/optimism.html#use-the-public-testnet", "relUrl": "/tutorials/chains/optimism.html#use-the-public-testnet" - },"652": { + },"656": { "doc": "pages.optimism", "title": "pages.optimism", "content": " ", "url": "/firefly/head/tutorials/chains/optimism.html", "relUrl": "/tutorials/chains/optimism.html" - },"653": { + },"657": { "doc": "pages.orchestration_engine", "title": "Orchestration Engine", "content": ". ", "url": "/firefly/head/overview/key_components/orchestration_engine.html#orchestration-engine", "relUrl": "/overview/key_components/orchestration_engine.html#orchestration-engine" - },"654": { + },"658": { "doc": "pages.orchestration_engine", "title": "FireFly Core", "content": "At the core of Hyperledger FireFly is an event-driven engine that routes, indexed, aggregates, and sequences data to and from the blockchain, and other connectors. ", "url": "/firefly/head/overview/key_components/orchestration_engine.html#firefly-core", "relUrl": "/overview/key_components/orchestration_engine.html#firefly-core" - },"655": { + },"659": { "doc": "pages.orchestration_engine", "title": "Data Layer", "content": "Your own private view of the each network you connect: . | Indexes of all tokens and NFTs that you transact with | A consistent view across multiple blockchains | High performance rich query of transaction and data audit trail | Private data you have received from other parties | Local copies of data you have download from IPFS or other shared storage tech | . ", "url": "/firefly/head/overview/key_components/orchestration_engine.html#data-layer", "relUrl": "/overview/key_components/orchestration_engine.html#data-layer" - },"656": { + },"660": { "doc": "pages.orchestration_engine", "title": "Event Bus", "content": "Whether a few dozen companies in a private blockchain consortium, or millions of users connected to a public blockchain network - one thing is always true: . Decentralized applications are event-driven. In an enterprise context, you need to think not only about how those events are being handled and made consistent within the blockchain layer, but also how those events are being processed and integrated to your core systems. FireFly provides you with the reliable streams of events you need, as well as the interfaces to subscribe to those events and integrate them into your core systems. | Token transfer events, across multiple blockchains, and varied asset types | Custom smart contract events | Correlated on-chain and off-chain data events | . Learn more about the event bus and event-driven programming in this reference document . ", "url": "/firefly/head/overview/key_components/orchestration_engine.html#event-bus", "relUrl": "/overview/key_components/orchestration_engine.html#event-bus" - },"657": { + },"661": { "doc": "pages.orchestration_engine", "title": "pages.orchestration_engine", "content": " ", "url": "/firefly/head/overview/key_components/orchestration_engine.html", "relUrl": "/overview/key_components/orchestration_engine.html" - },"658": { + },"662": { "doc": "Example Transaction Flow", "title": "Example Transaction Flow (Ping Pong)", "content": " ", "url": "/firefly/head/architecture/ping_pong_txflow.html#example-transaction-flow-ping-pong", "relUrl": "/architecture/ping_pong_txflow.html#example-transaction-flow-ping-pong" - },"659": { + },"663": { "doc": "Example Transaction Flow", "title": "Table of contents", "content": ". | Overview | Broadcast Public Description of Binary Data Asset (Member 1) | Receive Public Description & Request Asset Data (Member 2) | Authorize & Transfer Data (Member 1) | Receive Data Asset (Member 2) | . ", "url": "/firefly/head/architecture/ping_pong_txflow.html#table-of-contents", "relUrl": "/architecture/ping_pong_txflow.html#table-of-contents" - },"660": { + },"664": { "doc": "Example Transaction Flow", "title": "Overview", "content": ". This demonstrates the problem that at its core FireFly is there to solve. The internal plumbing complexity of just a very simple set of Enterprise blockchain / multi-party system interactions. | Party A: Establish existence of a digital asset. | Nothing more than some binary data (an image, a document, a specification etc.). | . | Party A: Broadcast some information about that asset to everyone, using blockchain to record, sequence and propagate. | So people can find it, or part of a more sophisticated workflow. | . | Party B: Request the actual data - with evidence of that request tied to the blockchain. | Including some private data that’s sent to the Party A, reliably off-chain. | . | Party A: Authorize the request, and send the data privately to Party B. | In this example there’s no blockchain involved in this step. | . | . This is the kind of thing that enterprise projects have been solving ground-up since the dawn of enterprise blockchain, and the level of engineering required that is completely detached from business value, is very high. The “tramlines” view shows how FireFly’s pluggable model makes the job of the developer really simple: . | A few simple API calls from a modern web app. | Event triggered execution of application logic. | . This is deliberately a simple flow, and all kinds of additional layers might well layer on (and fit within the FireFly model): . | NFTs to track ownership etc. related to the digital asset. | Tokenized rewards/payments integrated with the authorization of the transfer of data. | Proof of deterministic execution of the logic to perform the authorization (on-chain, TEEs, ZKPs). | Human workflow, that is of course completely non-deterministic. | Multiple additional process steps, deterministic or not. | Inclusion of multiple additional parties (maybe it’s a request-for-tender, submit-tender flow for example). | etc. | . ", "url": "/firefly/head/architecture/ping_pong_txflow.html#overview", "relUrl": "/architecture/ping_pong_txflow.html#overview" - },"661": { + },"665": { "doc": "Example Transaction Flow", "title": "Broadcast Public Description of Binary Data Asset (Member 1)", "content": ". | Upload Blob of the actual data . | Returns a hash of the payload | . | Upload JSON containing the public index data . | Includes the hash of the full payload | . | Send a broadcast message with the public index data . | Agree upon a primary key of the data as the “context” | . | . ", "url": "/firefly/head/architecture/ping_pong_txflow.html#broadcast-public-description-of-binary-data-asset-member-1", "relUrl": "/architecture/ping_pong_txflow.html#broadcast-public-description-of-binary-data-asset-member-1" - },"662": { + },"666": { "doc": "Example Transaction Flow", "title": "Receive Public Description & Request Asset Data (Member 2)", "content": ". | Store data in your own off-chain database for rich, efficient query | Run automated logic to decide if you want to request the full data | Upload JSON for data request | Send a private message . | Backed by blockchain in this flow | . | . ", "url": "/firefly/head/architecture/ping_pong_txflow.html#receive-public-description--request-asset-data-member-2", "relUrl": "/architecture/ping_pong_txflow.html#receive-public-description--request-asset-data-member-2" - },"663": { + },"667": { "doc": "Example Transaction Flow", "title": "Authorize & Transfer Data (Member 1)", "content": ". | Inspect the request data | Retrieve data asset by hash | Send the private data in a private message . | No blockchain in this flow | . | . ", "url": "/firefly/head/architecture/ping_pong_txflow.html#authorize--transfer-data-member-1", "relUrl": "/architecture/ping_pong_txflow.html#authorize--transfer-data-member-1" - },"664": { + },"668": { "doc": "Example Transaction Flow", "title": "Receive Data Asset (Member 2)", "content": ". | Receive a link to your local copy of the asset data | . ", "url": "/firefly/head/architecture/ping_pong_txflow.html#receive-data-asset-member-2", "relUrl": "/architecture/ping_pong_txflow.html#receive-data-asset-member-2" - },"665": { + },"669": { "doc": "Example Transaction Flow", "title": "Example Transaction Flow", "content": " ", "url": "/firefly/head/architecture/ping_pong_txflow.html", "relUrl": "/architecture/ping_pong_txflow.html" - },"666": { + },"670": { "doc": "Pinning Data", "title": "Pin off-chain data to a custom blockchain transaction", "content": "This guide describes how to associate an arbitrary off-chain payload with a blockchain transaction on a contract of your own design. A hash of the payload will be recorded as part of the blockchain transaction, and on the receiving side, FireFly will ensure that both the on-chain and off-chain pieces are received and aggregated together. NOTE: This is an advanced FireFly feature. Before following any of the steps in this guide, you should be very familiar and comfortable with the basic features of how broadcast messages and private messages work, be proficient at custom contract development on your blockchain of choice, and understand the fundamentals of how FireFly interacts with custom contracts. ", "url": "/firefly/head/tutorials/custom_contracts/pinning.html#pin-off-chain-data-to-a-custom-blockchain-transaction", "relUrl": "/tutorials/custom_contracts/pinning.html#pin-off-chain-data-to-a-custom-blockchain-transaction" - },"667": { + },"671": { "doc": "Pinning Data", "title": "Table of contents", "content": ". | Pin off-chain data to a custom blockchain transaction . | Designing a compatible contract . | Ethereum | Fabric | . | Initializing FireFly | Invoking the contract | Listening for events | . | . ", "url": "/firefly/head/tutorials/custom_contracts/pinning.html#table-of-contents", "relUrl": "/tutorials/custom_contracts/pinning.html#table-of-contents" - },"668": { + },"672": { "doc": "Pinning Data", "title": "Designing a compatible contract", "content": "In order to allow pinning a FireFly message batch with a custom contract transaction, your contract must meet certain criteria. First, any external method of the contract that will be used for associating with off-chain payloads must provide an extra parameter for passing the encoded batch data. This must be the last parameter in the method signature. This convention is chosen partly to align with the Ethereum ERC5750 standard, but should serve as a straightforward guideline for nearly any blockchain. Second, this method must emit a BatchPin event that can be received and parsed by FireFly. Exactly how the data is unpacked and used to emit this event will differ for each blockchain. Ethereum . import \"@hyperledger/firefly-contracts/contracts/IBatchPin.sol\"; contract CustomPin { IBatchPin firefly; function setFireFlyAddress(address addr) external { firefly = IBatchPin(addr); } function sayHello(bytes calldata data) external { require( address(firefly) != address(0), \"CustomPin: FireFly address has not been set\" ); /* do custom things */ firefly.pinBatchData(data); } } . | The method in question will receive packed “batch pin” data in its last method parameter (in the form of ABI-encoded bytes). The method must invoke the pinBatchData method of the FireFly Multiparty Contract and pass along this data payload. It is generally good practice to trigger this as a final step before returning, after the method has performed its own logic. | This also implies that the contract must know the on-chain location of the FireFly Multiparty Contract. How this is achieved is up to your individual implementation - the example above shows exposing a method to set the address. An application may leverage the fact that this location is available by querying the FireFly /status API (under multiparty.contract.location as of FireFly v1.1.0). However, the application must also consider how appropriately secure this functionality, and how to update this location if a multiparty “network action” is used to migrate the network onto a new FireFly multiparty contract. | . Fabric . package chaincode import ( \"encoding/json\" \"fmt\" \"github.com/hyperledger/fabric-contract-api-go/contractapi\" \"github.com/hyperledger/firefly/custompin_sample/batchpin\" ) type SmartContract struct { contractapi.Contract } func (s *SmartContract) MyCustomPin(ctx contractapi.TransactionContextInterface, data string) error { event, err := batchpin.BuildEventFromString(ctx, data) if err != nil { return err } bytes, err := json.Marshal(event) if err != nil { return fmt.Errorf(\"failed to marshal event: %s\", err) } return ctx.GetStub().SetEvent(\"BatchPin\", bytes) } . | The method in question will received packed “batch pin” data in its last method parameter (in the form of a JSON-encoded string). The method must unpack this argument into a JSON object. | The contract must directly set a BatchPin event in the same format that is used by the FireFly Multiparty Contract. | . ", "url": "/firefly/head/tutorials/custom_contracts/pinning.html#designing-a-compatible-contract", "relUrl": "/tutorials/custom_contracts/pinning.html#designing-a-compatible-contract" - },"669": { + },"673": { "doc": "Pinning Data", "title": "Initializing FireFly", "content": "Once you have a contract designed, you can initialize your environment using the blockchain of your choice. No special initialization arguments are needed for Ethereum. If you are using Fabric, you must pass the --custom-pin-support argument when initializing your FireFly stack. This will ensure that the BatchPin event listener listens to events from all chaincode deployed on the default channel, instead of only listening to events from the pre-deployed FireFly chaincode. ", "url": "/firefly/head/tutorials/custom_contracts/pinning.html#initializing-firefly", "relUrl": "/tutorials/custom_contracts/pinning.html#initializing-firefly" - },"670": { + },"674": { "doc": "Pinning Data", "title": "Invoking the contract", "content": "You can follow the normal steps for Ethereum or Fabric to define your contract interface and API in FireFly. When invoking the contract, you can include a message payload alongside the other parameters. POST http://localhost:5000/api/v1/namespaces/default/apis/custom-pin/invoke/sayHello . { \"input\": {}, \"message\": { \"data\": [ { \"value\": \"payload here\" } ] } } . ", "url": "/firefly/head/tutorials/custom_contracts/pinning.html#invoking-the-contract", "relUrl": "/tutorials/custom_contracts/pinning.html#invoking-the-contract" - },"671": { + },"675": { "doc": "Pinning Data", "title": "Listening for events", "content": "All parties that receive the message will receive a message_confirmed on their event listeners. This event confirms that the off-chain payload has been received (via data exchange or shared storage) and that the blockchain transaction has been received and sequenced. It is guaranteed that these message_confirmed events will be ordered based on the sequence of the on-chain transactions, regardless of when the off-chain payload becomes available. This means that all parties will order messages on a given topic in exactly the same order, allowing for deterministic but decentralized event-driven architecture. ", "url": "/firefly/head/tutorials/custom_contracts/pinning.html#listening-for-events", "relUrl": "/tutorials/custom_contracts/pinning.html#listening-for-events" - },"672": { + },"676": { "doc": "Pinning Data", "title": "Pinning Data", "content": " ", "url": "/firefly/head/tutorials/custom_contracts/pinning.html", "relUrl": "/tutorials/custom_contracts/pinning.html" - },"673": { + },"677": { "doc": "Plugin Architecture", "title": "Plugin Architecture", "content": " ", "url": "/firefly/head/architecture/plugin_architecture.html", "relUrl": "/architecture/plugin_architecture.html" - },"674": { + },"678": { "doc": "Plugin Architecture", "title": "Table of contents", "content": ". | Overview | FireFly Core | Plugin for Connector | Connector | Infrastructure Runtime | . This diagram shows the various plugins that are currently in the codebase and the layers in each plugin . This diagram shows the details of what goes into each layer of a FireFly plugin . ", "url": "/firefly/head/architecture/plugin_architecture.html#table-of-contents", "relUrl": "/architecture/plugin_architecture.html#table-of-contents" - },"675": { + },"679": { "doc": "Plugin Architecture", "title": "Overview", "content": "The FireFly node is built for extensibility, with separate pluggable runtimes orchestrated into a common API for developers. The mechanics of that pluggability for developers of new connectors is explained below: . This architecture is designed to provide separations of concerns to account for: . | Differences in code language for the low-level connection to a backend (Java for Corda for example) | Differences in transports, particularly for delivery of events: . | Between FireFly Core and the Connector . | Different transports other than HTTPS/WebSockets (GRPC etc.), and different wire protocols (socket.io, etc.) | . | Between the Connector and the underlying Infrastructure Runtime . | Often this is heavy lifting engineering within the connector | . | . | Differences in High Availability (HA) / Scale architectures . | Between FireFly Core, and the Connector . | Often for event management, and active/passive connector runtime is sufficient | . | Between the Connector and the Infrastructure Runtime . | The infrastructure runtimes have all kinds of variation here… think of the potential landscape here from PostreSQL through Besu/Fabric/Corda, to Hyperledger Avalon and even Main-net ethereum | . | . | . ", "url": "/firefly/head/architecture/plugin_architecture.html#overview", "relUrl": "/architecture/plugin_architecture.html#overview" - },"676": { + },"680": { "doc": "Plugin Architecture", "title": "FireFly Core", "content": ". | Golang | N-way scalable cluster . | Database is also pluggable via this architecture | . | No long lived in-memory processing . | All micro-batching must be recoverable | . | Driven by single configuration set . | Viper semantics - file, env var, cmdline flags | . | . ", "url": "/firefly/head/architecture/plugin_architecture.html#firefly-core", "relUrl": "/architecture/plugin_architecture.html#firefly-core" - },"677": { + },"681": { "doc": "Plugin Architecture", "title": "Plugin for Connector", "content": ". | Golang | Statically compiled in support at runtime . | Go dynamic plugin support too immature | . | Must be 100% FLOSS code (no GPL/LGPL etc.) | Contributed via PR to FF Core | Intended to be lightweight binding/mapping | Must adhere to FF Core Coding Standards | Scrutiny on addition of new frameworks/transports | . ", "url": "/firefly/head/architecture/plugin_architecture.html#plugin-for-connector", "relUrl": "/architecture/plugin_architecture.html#plugin-for-connector" - },"678": { + },"682": { "doc": "Plugin Architecture", "title": "Connector", "content": ". | Node.js / Java / Golang, etc. | Runs/scales independently from FF core | Coded in any language, OSS or proprietary | One runtime or multiple | HA model can be active/passive or active/active | Expectation is all plugins need a connector . | Some exceptions exist (e.g. database plugin) | . | . ", "url": "/firefly/head/architecture/plugin_architecture.html#connector", "relUrl": "/architecture/plugin_architecture.html#connector" - },"679": { + },"683": { "doc": "Plugin Architecture", "title": "Infrastructure Runtime", "content": ". | Besu, Quorum, Corda, Fabric, IPFS, Kafka, etc. | Runs/scales independently from FF Core | Coded in any language, OSS or proprietary | Not specific to FireFly | HA model can be active/passive or active/active | . ", "url": "/firefly/head/architecture/plugin_architecture.html#infrastructure-runtime", "relUrl": "/architecture/plugin_architecture.html#infrastructure-runtime" - },"680": { + },"684": { "doc": "pages.polygon_testnet", "title": "Polygon Testnet", "content": " ", "url": "/firefly/head/tutorials/chains/polygon_testnet.html#polygon-testnet", "relUrl": "/tutorials/chains/polygon_testnet.html#polygon-testnet" - },"681": { + },"685": { "doc": "pages.polygon_testnet", "title": "Table of contents", "content": ". | Previous steps: Install the FireFly CLI | Create an evmconnect.yml config file | Creating a new stack | Start the stack | Get some MATIC . | Confirm the transaction on Polygonscan | . | Use the public testnet | . Starting with FireFly v1.1, it’s easy to connect to public Ethereum chains. This guide will walk you through the steps to create a local FireFly development environment and connect it to the public Polygon Mumbai testnet. ", "url": "/firefly/head/tutorials/chains/polygon_testnet.html#table-of-contents", "relUrl": "/tutorials/chains/polygon_testnet.html#table-of-contents" - },"682": { + },"686": { "doc": "pages.polygon_testnet", "title": "Previous steps: Install the FireFly CLI", "content": "If you haven’t set up the FireFly CLI already, please go back to the Getting Started guide and read the section on how to Install the FireFly CLI. ← ① Install the FireFly CLI . ", "url": "/firefly/head/tutorials/chains/polygon_testnet.html#previous-steps-install-the-firefly-cli", "relUrl": "/tutorials/chains/polygon_testnet.html#previous-steps-install-the-firefly-cli" - },"683": { + },"687": { "doc": "pages.polygon_testnet", "title": "Create an evmconnect.yml config file", "content": "In order to connect to the Polygon testnet, you will need to set a few configuration options for the evmconnect blockchain connector. Create a text file called evmconnect.yml with the following contents: . confirmations: required: 4 # choose the number of confirmations you require policyengine.simple: fixedGasPrice: null gasOracle: mode: connector . For more info about confirmations, see Public vs. Permissioned . For this tutorial, we will assume this file is saved at ~/Desktop/evmconnect.yml. If your path is different, you will need to adjust the path in the next command below. ", "url": "/firefly/head/tutorials/chains/polygon_testnet.html#create-an-evmconnectyml-config-file", "relUrl": "/tutorials/chains/polygon_testnet.html#create-an-evmconnectyml-config-file" - },"684": { + },"688": { "doc": "pages.polygon_testnet", "title": "Creating a new stack", "content": "To create a local FireFly development stack and connect it to the Polygon Mumbai testnet, we will use command line flags to customize the following settings: . | Create a new Ethereum based stack named polygon with 1 member | Disable multiparty mode. We are going to be using this FireFly node as a Web3 gateway, and we don’t need to communicate with a consortium here | Use an remote RPC node. This will create a signer locally, so that our signing key never leaves the development machine. | See the list of Polygon RPC endpoints and select an HTTPS RPC endpoint. | Set the chain ID to 80001 (the correct ID for the Polygon Mumbai testnet) | Merge the custom config created above with the generated evmconnect config file | . To do this, run the following command: . ff init ethereum polygon 1 \\ --multiparty=false \\ -n remote-rpc \\ --remote-node-url <selected RPC endpoint> \\ --chain-id 80001 \\ --connector-config ~/Desktop/evmconnect.yml . ", "url": "/firefly/head/tutorials/chains/polygon_testnet.html#creating-a-new-stack", "relUrl": "/tutorials/chains/polygon_testnet.html#creating-a-new-stack" - },"685": { + },"689": { "doc": "pages.polygon_testnet", "title": "Start the stack", "content": "Now you should be able to start your stack by running: . ff start polygon . After some time it should print out the following: . Web UI for member '0': http://127.0.0.1:5000/ui Sandbox UI for member '0': http://127.0.0.1:5109 To see logs for your stack run: ff logs polygon . ", "url": "/firefly/head/tutorials/chains/polygon_testnet.html#start-the-stack", "relUrl": "/tutorials/chains/polygon_testnet.html#start-the-stack" - },"686": { + },"690": { "doc": "pages.polygon_testnet", "title": "Get some MATIC", "content": "At this point you should have a working FireFly stack, talking to a public chain. However, you won’t be able to run any transactions just yet, because you don’t have any way to pay for gas. A testnet faucet can give us some MATIC, the native token for Polygon. First, you will need to know what signing address your FireFly node is using. To check that, you can run: . ff accounts list polygon [ { \"address\": \"0x02d42c32a97c894486afbc7b717edff50c70b292\", \"privateKey\": \"...\" } ] . Copy the address listed in the output from this command. Go to https://faucet.polygon.technology/ and paste the address in the form. Click the Submit button, and then Confirm. Confirm the transaction on Polygonscan . You should be able to go lookup your account on Polygonscan for the Mumbai testnet and see that you now have a balance of 0.2 MATIC. Simply paste in your account address to search for it. You can also click on the Internal Txns tab from you account page to see the actual transfer of the MATIC from the faucet. ", "url": "/firefly/head/tutorials/chains/polygon_testnet.html#get-some-matic", "relUrl": "/tutorials/chains/polygon_testnet.html#get-some-matic" - },"687": { + },"691": { "doc": "pages.polygon_testnet", "title": "Use the public testnet", "content": "Now that you have everything set up, you can follow one of the other FireFly guides such as Using Tokens or Custom Smart Contracts. For detailed instructions on deploying a custom smart contract to Polygon, please see the Polygon docs for instructions using various tools. ", "url": "/firefly/head/tutorials/chains/polygon_testnet.html#use-the-public-testnet", "relUrl": "/tutorials/chains/polygon_testnet.html#use-the-public-testnet" - },"688": { + },"692": { "doc": "pages.polygon_testnet", "title": "pages.polygon_testnet", "content": " ", "url": "/firefly/head/tutorials/chains/polygon_testnet.html", "relUrl": "/tutorials/chains/polygon_testnet.html" - },"689": { + },"693": { "doc": "Privately send data", "title": "Privately send data", "content": " ", "url": "/firefly/head/tutorials/private_send.html", "relUrl": "/tutorials/private_send.html" - },"690": { + },"694": { "doc": "Privately send data", "title": "Table of contents", "content": ". | Quick reference | Additional info | Example 1: Pinned private send of in-line string data | Example message response | Example 2: Unpinned private send of in-line string data | Example 3: Inline object data to a topic (no datatype verification) | Notes on why setting a topic is important | Example 3: Upload a blob with metadata and send privately . | Multipart form post of a file | Example data response from Blob upload | Send the uploaded data privately | . | Sending Private Messages using the Sandbox | . ", "url": "/firefly/head/tutorials/private_send.html#table-of-contents", "relUrl": "/tutorials/private_send.html#table-of-contents" - },"691": { + },"695": { "doc": "Privately send data", "title": "Quick reference", "content": ". | Sends a message to a restricted set of parties . | The message describes who sent it, to whom, and exactly what data was sent | . | A message has one or more attached pieces of business data . | Can be sent in-line, uploaded in advanced, or received from other parties | Can include smaller JSON payloads suitable for database storage . | These can be verified against a datatype | . | Can include references to large (multi megabyte/gigabyte) Blob data | . | A group specifies who has visibility to the data . | The author must be included in the group - auto-added if omitted | Can be specified in-line in the message by listing recipients directly | Can be referred to by hash | . | Private sends are optionally sequenced via pinning to the blockchain . | If the send is pinned: . | The blockchain does not contain any data, just a hash pin . | Even the ordering context (topic) is obscured in the on-chain data | This is true regardless of whether a restricted set of participants are maintaining the ledger, such as in the case of a Fabric Channel. | . | The message should not be considered confirmed (even by the sender) until it has been sequenced via the blockchain and a message_confirmed event occurs | Batched for efficiency . | One batch can pin hundreds of private message sends | The batch flows privately off-chain from the sender to each recipient | . | . | If the send is unpinned: . | No data is written to the blockchain at all | The message is marked confirmed immediately . | The sender receives a message_confirmed event immediately | . | The other parties in the group get message_confirmed events as soon as the data arrives | . | . | . ", "url": "/firefly/head/tutorials/private_send.html#quick-reference", "relUrl": "/tutorials/private_send.html#quick-reference" - },"692": { + },"696": { "doc": "Privately send data", "title": "Additional info", "content": ". | Key Concepts: Private data exchange | Swagger: POST /api/v1/namespaces/{ns}/messages/private | . ", "url": "/firefly/head/tutorials/private_send.html#additional-info", "relUrl": "/tutorials/private_send.html#additional-info" - },"693": { + },"697": { "doc": "Privately send data", "title": "Example 1: Pinned private send of in-line string data", "content": "POST /api/v1/namespaces/default/messages/private . { \"data\": [ { \"value\": \"a string\" } ], \"group\": { \"members\": [ { \"identity\": \"org_1\" } ] } } . ", "url": "/firefly/head/tutorials/private_send.html#example-1-pinned-private-send-of-in-line-string-data", "relUrl": "/tutorials/private_send.html#example-1-pinned-private-send-of-in-line-string-data" - },"694": { + },"698": { "doc": "Privately send data", "title": "Example message response", "content": "Status: 202 Accepted - the message is on it’s way, but has not yet been confirmed. { \"header\": { \"id\": \"c387e9d2-bdac-44cc-9dd5-5e7f0b6b0e58\", // uniquely identifies this private message \"type\": \"private\", // set automatically \"txtype\": \"batch_pin\", // message will be batched, and sequenced via the blockchain \"author\": \"0x0a65365587a65ce44938eab5a765fe8bc6532bdf\", // set automatically in this example to the node org \"created\": \"2021-07-02T02:37:13.4642085Z\", // set automatically \"namespace\": \"default\", // the 'default' namespace was set in the URL // The group hash is calculated from the resolved list of group participants. // The first time a group is used, the participant list is sent privately along with the // batch of messages in a `groupinit` message. \"group\": \"2aa5297b5eed0c3a612a667c727ca38b54fb3b5cc245ebac4c2c7abe490bdf6c\", \"topics\": [ \"default\" // the default topic that the message is published on, if no topic is set ], // datahash is calculated from the data array below \"datahash\": \"24b2d583b87eda952fa00e02c6de4f78110df63218eddf568f0240be3d02c866\" }, \"hash\": \"423ad7d99fd30ff679270ad2b6b35cdd85d48db30bafb71464ca1527ce114a60\", // hash of the header \"state\": \"ready\", // this message is stored locally but not yet confirmed \"data\": [ // one item of data was stored { \"id\": \"8d8635e2-7c90-4963-99cc-794c98a68b1d\", // can be used to query the data in the future \"hash\": \"c95d6352f524a770a787c16509237baf7eb59967699fb9a6d825270e7ec0eacf\" // sha256 hash of `\"a string\"` } ] } . ", "url": "/firefly/head/tutorials/private_send.html#example-message-response", "relUrl": "/tutorials/private_send.html#example-message-response" - },"695": { + },"699": { "doc": "Privately send data", "title": "Example 2: Unpinned private send of in-line string data", "content": "Set header.txtype: \"none\" to disable pinning of the private message send to the blockchain. The message is sent immediately (no batching) over the private data exchange. POST /api/v1/namespaces/default/messages/private . { \"header\": { \"txtype\": \"none\" }, \"data\": [ { \"value\": \"a string\" } ], \"group\": { \"members\": [ { \"identity\": \"org_1\" } ] } } . ", "url": "/firefly/head/tutorials/private_send.html#example-2-unpinned-private-send-of-in-line-string-data", "relUrl": "/tutorials/private_send.html#example-2-unpinned-private-send-of-in-line-string-data" - },"696": { + },"700": { "doc": "Privately send data", "title": "Example 3: Inline object data to a topic (no datatype verification)", "content": "It is very good practice to set a tag and topic in each of your messages: . | tag should tell the apps receiving the private send (including the local app), what to do when it receives the message. Its the reason for the send - an application specific type for the message. | topic should be something like a well known identifier that relates to the information you are publishing. It is used as an ordering context, so all sends on a given topic are assured to be processed in order. | . POST /api/v1/namespaces/default/messages/private . { \"header\": { \"tag\": \"new_widget_created\", \"topics\": [\"widget_id_12345\"] }, \"group\": { \"members\": [ { \"identity\": \"org_1\" } ] }, \"data\": [ { \"value\": { \"id\": \"widget_id_12345\", \"name\": \"superwidget\" } } ] } . ", "url": "/firefly/head/tutorials/private_send.html#example-3-inline-object-data-to-a-topic-no-datatype-verification", "relUrl": "/tutorials/private_send.html#example-3-inline-object-data-to-a-topic-no-datatype-verification" - },"697": { + },"701": { "doc": "Privately send data", "title": "Notes on why setting a topic is important", "content": "The FireFly aggregator uses the topic (obfuscated on chain) to determine if a message is the next message in an in-flight sequence for any groups the node is involved in. If it is, then that message must receive all off-chain private data and be confirmed before any subsequent messages can be confirmed on the same sequence. So if you use the same topic in every message, then a single failed send on one topic blocks delivery of all messages between those parties, until the missing data arrives. Instead it is best practice to set the topic on your messages to value that identifies an ordered stream of business processing. Some examples: . | A long-running business process instance identifier assigned at initiation | A real-world business transaction identifier used off-chain | The agreed identifier of an asset you are attaching a stream of evidence to | An NFT identifier that is assigned to an asset (digital twin scenarios) | An agreed primary key for a data resource being reconciled between multiple parties | . The topic field is an array, because there are cases (such as merging two identifiers) where you need a message to be deterministically ordered across multiple sequences. However, this is an advanced use case and you are likely to set a single topic on the vast majority of your messages. ", "url": "/firefly/head/tutorials/private_send.html#notes-on-why-setting-a-topic-is-important", "relUrl": "/tutorials/private_send.html#notes-on-why-setting-a-topic-is-important" - },"698": { + },"702": { "doc": "Privately send data", "title": "Example 3: Upload a blob with metadata and send privately", "content": "Here we make two API calls. 1) Create the data object explicitly, using a multi-part form upload . | You can also just post JSON to this endpoint | . 2) Privately send a message referring to that data . | The Blob is sent privately to each party | A pin goes to the blockchain | The metadata goes into a batch with the message | . Multipart form post of a file . Example curl command (Linux/Mac) to grab an image from the internet, and pipe it into a multi-part form post to FireFly. Note we use autometa to cause FireFly to automatically add the filename, and size, to the JSON part of the data object for us. curl -sLo - https://github.com/hyperledger/firefly/raw/main/docs/firefly_logo.png \\ | curl --form autometa=true --form file=@- \\ http://localhost:5000/api/v1/namespaces/default/data . Example data response from Blob upload . Status: 200 OK - your data is uploaded to your local FireFly node . At this point the data has not be shared with anyone else in the network . { // A uniquely generated ID, we can refer to when sending this data to other parties \"id\": \"97eb750f-0d0b-4c1d-9e37-1e92d1a22bb8\", \"validator\": \"json\", // the \"value\" part is JSON \"namespace\": \"default\", // from the URL // The hash is a combination of the hash of the \"value\" metadata, and the // hash of the blob \"hash\": \"997af6a9a19f06cc8a46872617b8bf974b106f744b2e407e94cc6959aa8cf0b8\", \"created\": \"2021-07-01T20:20:35.5462306Z\", \"value\": { \"filename\": \"-\", // dash is how curl represents the filename for stdin \"size\": 31185 // the size of the blob data }, \"blob\": { // A hash reference to the blob \"hash\": \"86e6b39b04b605dd1b03f70932976775962509d29ae1ad2628e684faabe48136\" } } . Send the uploaded data privately . Just include a reference to the id returned from the upload. POST /api/v1/namespaces/default/messages/private . { \"data\": [ { \"id\": \"97eb750f-0d0b-4c1d-9e37-1e92d1a22bb8\" } ], \"group\":{ \"members\": [ { \"identity\":\"org_1\" } ] } } . ", "url": "/firefly/head/tutorials/private_send.html#example-3-upload-a-blob-with-metadata-and-send-privately", "relUrl": "/tutorials/private_send.html#example-3-upload-a-blob-with-metadata-and-send-privately" - },"699": { + },"703": { "doc": "Privately send data", "title": "Sending Private Messages using the Sandbox", "content": "All of the functionality discussed above can be done through the FireFly Sandbox. To get started, open up the Web UI and Sanbox UI for at least one of your members. The URLs for these were printed in your terminal when you started your FireFly stack. Make sure to expand the “Send a Private Message” section. Enter your message into the message field as seen in the screenshot below. Because we are sending a private message, make sure you’re in the “Send a Private Message” section and that you choose a message recipient . Notice how the data field in the center panel updates in real time as you update the message you wish to send. Click the blue Run button. This should return a 202 response immediately in the Server Response section and will populate the right hand panel with transaction information after a few seconds. Go back to the FireFly UI (the URL for this would have been shown in the terminal when you started the stack) and you’ll see your successful blockchain transaction. Compare the “Recent Network Changes” widget With private messages, your . ", "url": "/firefly/head/tutorials/private_send.html#sending-private-messages-using-the-sandbox", "relUrl": "/tutorials/private_send.html#sending-private-messages-using-the-sandbox" - },"700": { + },"704": { "doc": "Public and Permissioned", "title": "Public and Permissioned Blockchain", "content": " ", "url": "/firefly/head/overview/public_vs_permissioned.html#public-and-permissioned-blockchain", "relUrl": "/overview/public_vs_permissioned.html#public-and-permissioned-blockchain" - },"701": { + },"705": { "doc": "Public and Permissioned", "title": "Table of contents", "content": ". | Public and Permissioned Blockchains | Public blockchain variations | Common public considerations | FireFly architecture for public chains | . ", "url": "/firefly/head/overview/public_vs_permissioned.html#table-of-contents", "relUrl": "/overview/public_vs_permissioned.html#table-of-contents" - },"702": { + },"706": { "doc": "Public and Permissioned", "title": "Public and Permissioned Blockchains", "content": "A separate choice to the technology for your blockchain, is what combination of blockchain ecosystems you will integrate with. There are a huge variety of options, and increasingly you might find yourself integrating with multiple ecosystems in your solutions. A rough (and incomplete) high level classification of the blockchains available is as follows: . | Layer 1 public blockchains . | This is where most token ecosystems are rooted | . | Layer 2 public scaling solutions backed by a Layer 1 blockchain . | These are increasing where transaction execution takes place that needs to be reflected eventually back to a Layer 1 blockchain (due to cost/congestion in the Layer 1 chains) | . | Permissioned side-chains . | Historically this has been where the majority of production adoption of enterprise blockchain has focussed, due to the predictable cost, performance, and ability to manage the validator set and boundary API security alongside a business network governance policy | These might have their state check-pointed/rolled-up to a Layer 2 or Layer 1 chain | . | . The lines are blurring between these categorizations as the technologies and ecosystems evolve. ", "url": "/firefly/head/overview/public_vs_permissioned.html#public-and-permissioned-blockchains", "relUrl": "/overview/public_vs_permissioned.html#public-and-permissioned-blockchains" - },"703": { + },"707": { "doc": "Public and Permissioned", "title": "Public blockchain variations", "content": "For the public Layer 1 and 2 solutions, there are too many subclassifications to go into in detail here: . | Whether ecosystems supports custom smart contract execution (EVM based is most common, where contracts are supported) | What types of token standards are supported, or other chain specific embedded smart contracts | Whether the chain follows an unspent transaction output (UTXO) or Account model | How value is bridged in-to / out-of the ecosystem | How the validator set of the chain is established - most common is Proof of Stake (PoS) | How data availability is maintained - to check the working of the validators ensure the historical state is not lost | The consensus algorithm, and how it interacts with the consensus of other blockchains | How state in a Layer 2 is provable in a parent Layer 1 chain (rollup technologies etc.) | . ", "url": "/firefly/head/overview/public_vs_permissioned.html#public-blockchain-variations", "relUrl": "/overview/public_vs_permissioned.html#public-blockchain-variations" - },"704": { + },"708": { "doc": "Public and Permissioned", "title": "Common public considerations", "content": "The thing most consistent across public blockchain technologies, is that the technical decisions are backed by token economics. Put simply, creating a system where it’s more financially rewarding to behave honestly, than it is to subvert and cheat the system. This means that participation costs, and that the mechanisms needed to reliably get your transactions into these systems are complex. Also that the time it might take to get a transaction onto the chain can be much longer than for a permissioned blockchain, with the potential to have to make a number of adjustments/resubmissions. The choice of whether to run your own node, or use a managed API, to access these blockchain ecosystems is also a factor in the behavior of the transaction submission and event streaming. ", "url": "/firefly/head/overview/public_vs_permissioned.html#common-public-considerations", "relUrl": "/overview/public_vs_permissioned.html#common-public-considerations" - },"705": { + },"709": { "doc": "Public and Permissioned", "title": "FireFly architecture for public chains", "content": "One of the fastest evolving aspects of the Hyperledger FireFly ecosystem, is how it facilitates enterprises to participate in these. The architecture is summarized as follows: . | New FireFly Transaction Manager runtime . | Operates as a microservice extension of the FireFly Core | Uses the operation resource within FireFly Core to store and update state | Runs as a singleton and is responsible for nonce assignment | Takes as much heavy lifting away from blockchain specific connectors as possible | . | Lightweight FireFly Connector API (ffcapi) . | Simple synchronous RPC operations that map to the most common operations supported across public blockchain technologies | Examples: . | Find the next nonce for a given signing key | Serialize a transaction from a set of JSON inputs and an interface definition | Submit an un-signed transaction with a given gas price to the blockchain, via a signing wallet | Establish a new block listener | Poll for new blocks | Establish a new event log listener | Poll for new events | . | . | Pluggable Policy Engine . | Invoked to make decisions on transaction submission | Responsible for gas price calculation | Able to intervene and adjust the characteristics of signing/submission | OSS reference implementation provided with Gas Station REST API integration | . | Confirmation Manager . | Extracted from the Ethconnect codebase | Coupled to both transaction submission and event confirmation | Embeds an efficient block cache | . | Event Streams . | Extracted from the Ethconnect codebase | Checkpoint restart based reliable at-least-once delivery of events | WebSockets interface upstream to FireFly Core | . | . This evolution involves a significant refactoring of components used for production solutions in the FireFly Ethconnect microservice since mid 2018. This was summarized in firefly-ethconnect#149, and cumulated in the creation of a new repository in 2022. You can follow the progress and contribute in this repo: https://github.com/hyperledger/firefly-transaction-manager . ", "url": "/firefly/head/overview/public_vs_permissioned.html#firefly-architecture-for-public-chains", "relUrl": "/overview/public_vs_permissioned.html#firefly-architecture-for-public-chains" - },"706": { + },"710": { "doc": "Public and Permissioned", "title": "Public and Permissioned", "content": " ", "url": "/firefly/head/overview/public_vs_permissioned.html", "relUrl": "/overview/public_vs_permissioned.html" - },"707": { + },"711": { "doc": "Explore messages", "title": "Explore messages", "content": " ", "url": "/firefly/head/tutorials/query_messages.html", "relUrl": "/tutorials/query_messages.html" - },"708": { + },"712": { "doc": "Explore messages", "title": "Table of contents", "content": ". | Quick reference | Additional info . | Example 1: Query confirmed messages | . | Example response . | Example 2: Query all messages | . | . ", "url": "/firefly/head/tutorials/query_messages.html#table-of-contents", "relUrl": "/tutorials/query_messages.html#table-of-contents" - },"709": { + },"713": { "doc": "Explore messages", "title": "Quick reference", "content": "The FireFly Explorer is a great way to view the messages sent and received by your node. Just open /ui on your FireFly node to access it. This builds on the APIs to query and filter messages, described below . ", "url": "/firefly/head/tutorials/query_messages.html#quick-reference", "relUrl": "/tutorials/query_messages.html#quick-reference" - },"710": { + },"714": { "doc": "Explore messages", "title": "Additional info", "content": ". | Reference: API Query Syntax | Swagger: GET /api/v1/namespaces/{ns}/messages | . Example 1: Query confirmed messages . These are the messages ready to be processed in your application. All data associated with the message (including Blob attachments) is available, and if they are sequenced by the blockchain, then those blockchain transactions are complete. The order in which you process messages should be determined by absolute order of message_confirmed events - queryable via the events collection, or through event listeners (discussed next in the getting started guide). That is because messages are ordered by timestamp, which is potentially subject to adjustments of the clock. Whereas events are ordered by the insertion order into the database, and as such changes in the clock do not affect the order. GET /api/v1/namespaces/{ns}/messages?pending=false&limit=100 . ", "url": "/firefly/head/tutorials/query_messages.html#additional-info", "relUrl": "/tutorials/query_messages.html#additional-info" - },"711": { + },"715": { "doc": "Explore messages", "title": "Example response", "content": "[ { \"header\": { \"id\": \"423302bb-abfc-4d64-892d-38b2fdfe1549\", \"type\": \"private\", // this was a private send \"txtype\": \"batch_pin\", // pinned in a batch to the blockchain \"author\": \"0x1d14b65d2dd5c13f6cb6d3dc4aa13c795a8f3b28\", \"created\": \"2021-07-02T03:09:40.2606238Z\", \"namespace\": \"default\", \"group\": \"2aa5297b5eed0c3a612a667c727ca38b54fb3b5cc245ebac4c2c7abe490bdf6c\", // sent to this group \"topic\": [ \"widget_id_12345\" ], \"tag\": \"new_widget_created\", \"datahash\": \"551dd261e80ce76b1908c031cff8a707bd76376d6eddfdc1040c2ed6481ec8dd\" }, \"hash\": \"bf2ca94db8c31bae3cae974bb626fa822c6eee5f572d274d72281e72537b30b3\", \"batch\": \"f7ac773d-885a-4d73-ac6b-c09f5346a051\", // the batch ID that pinned this message to the chain \"state\": \"confirmed\", // message is now confirmed \"confirmed\": \"2021-07-02T03:09:49.9207211Z\", // timestamp when this node confirmed the message \"data\": [ { \"id\": \"914eed77-8789-451c-b55f-ba9570a71eba\", \"hash\": \"9541cabc750c692e553a421a6c5c07ebcae820774d2d8d0b88fac2a231c10bf2\" } ], \"pins\": [ // A \"pin\" is an identifier that is used by FireFly for sequencing messages. // // For private messages, it is an obfuscated representation of the sequence of this message, // on a topic, within this group, from this sender. There will be one pin per topic. You will find these // pins in the blockchain transaction, as well as the off-chain data. // Each one is unqiue, and without the group hash, very difficult to correlate - meaning // the data on-chain provides a high level of privacy. // // Note for broadcast (which does not require obfuscation), it is simply a hash of the topic. // So you will see the same pin for all messages on the same topic. \"ee56de6241522ab0ad8266faebf2c0f1dc11be7bd0c41d847998135b45685b77\" ] } ] . Example 2: Query all messages . The natural sort order the API will return for messages is: . | Pending messages first . | In descending created timestamp order | . | Confirmed messages . | In descending confirmed timestamp order | . | . GET /api/v1/namespaces/{ns}/messages . ", "url": "/firefly/head/tutorials/query_messages.html#example-response", "relUrl": "/tutorials/query_messages.html#example-response" - },"712": { + },"716": { "doc": "Release Guide", "title": "Release Guide", "content": " ", "url": "/firefly/head/contributors/release_guide.html", "relUrl": "/contributors/release_guide.html" - },"713": { + },"717": { "doc": "Release Guide", "title": "Table of contents", "content": ". | Release Guide . | Versioning scheme | The manifest.json file | Creating a new release . | 1) Navigate to the release page for the repo | 2) Click the Draft a new release button | 3) Fill out the form for your release | . | Automatic Docker builds | . | . This guide will walk you through creating a release. ", "url": "/firefly/head/contributors/release_guide.html#table-of-contents", "relUrl": "/contributors/release_guide.html#table-of-contents" - },"714": { + },"718": { "doc": "Release Guide", "title": "Versioning scheme", "content": "FireFly follows semantic versioning. For more details on how we determine which version to use please see the Versioning Scheme guide. ", "url": "/firefly/head/contributors/release_guide.html#versioning-scheme", "relUrl": "/contributors/release_guide.html#versioning-scheme" - },"715": { + },"719": { "doc": "Release Guide", "title": "The manifest.json file", "content": "FireFly has a manifest.json file in the root of the repo. This file contains a list of versions (both tag and sha) for each of the microservices that should be used with this specific commit. If you need FireFly to use a newer version of a microservice listed in this file, you should update the manifest.json file, commit it, and include it in your PR. This will trigger an end-to-end test run, using the specified versions. Here is an example of what the manifest.json looks like: . { \"ethconnect\": { \"image\": \"ghcr.io/hyperledger/firefly-ethconnect\", \"tag\": \"v3.0.4\", \"sha\": \"0b7ce0fb175b5910f401ff576ced809fe6f0b83894277c1cc86a73a2d61c6f41\" }, \"fabconnect\": { \"image\": \"ghcr.io/hyperledger/firefly-fabconnect\", \"tag\": \"v0.9.0\", \"sha\": \"a79a4c66b0a2551d5122d019c15c6426e8cdadd6566ce3cbcb36e008fb7861ca\" }, \"dataexchange-https\": { \"image\": \"ghcr.io/hyperledger/firefly-dataexchange-https\", \"tag\": \"v0.9.0\", \"sha\": \"0de5b1db891a02871505ba5e0507821416d9fa93c96ccb4b1ba2fac45eb37214\" }, \"tokens-erc1155\": { \"image\": \"ghcr.io/hyperledger/firefly-tokens-erc1155\", \"tag\": \"v0.9.0-20211019-01\", \"sha\": \"aabc6c483db408896838329dab5f4b9e3c16d1e9fa9fffdb7e1ff05b7b2bbdd4\" } } . NOTE: You can run make manifest in the FireFly core source directory, and a script will run to automatically get the latests non-pre-release version of each of FireFly’s microservices. If you need to use a snapshot or pre-release version you should edit manifest.json file manually, as this script will not fetch those versions. ", "url": "/firefly/head/contributors/release_guide.html#the-manifestjson-file", "relUrl": "/contributors/release_guide.html#the-manifestjson-file" - },"716": { + },"720": { "doc": "Release Guide", "title": "Creating a new release", "content": "Releases and builds are managed by GitHub. New binaries and/or Docker images will automatically be created when a new release is published. The easiest way to create a release is through the web UI for the repo that you wish to release. 1) Navigate to the release page for the repo . 2) Click the Draft a new release button . 3) Fill out the form for your release . It is recommended to start with the auto-generated release notes. Additional notes can be added as-needed. ", "url": "/firefly/head/contributors/release_guide.html#creating-a-new-release", "relUrl": "/contributors/release_guide.html#creating-a-new-release" - },"717": { + },"721": { "doc": "Release Guide", "title": "Automatic Docker builds", "content": "After cutting a new release, a GitHub Action will automatically start a new Docker build, if the repo has a Docker image associated with it. You can check the status of the build by clicking the “Actions” tab along the top of the page, for that repo. ", "url": "/firefly/head/contributors/release_guide.html#automatic-docker-builds", "relUrl": "/contributors/release_guide.html#automatic-docker-builds" - },"718": { + },"722": { "doc": "pages.rotate_dx_certs", "title": "Rotate Data Exchange Certificates", "content": " ", "url": "/firefly/head/tutorials/rotate_dx_certs.html#rotate-data-exchange-certificates", "relUrl": "/tutorials/rotate_dx_certs.html#rotate-data-exchange-certificates" - },"719": { + },"723": { "doc": "pages.rotate_dx_certs", "title": "Table of contents", "content": ". | Quick reference | Generate new certs and keys | Install the new certs on each Data Exchange File System | Remove old certs from the peer-certs directory | Restart each Data Exchange process | PATCH the node identity using the FireFly API . | Request | Response | Request | Response | . | . ", "url": "/firefly/head/tutorials/rotate_dx_certs.html#table-of-contents", "relUrl": "/tutorials/rotate_dx_certs.html#table-of-contents" - },"720": { + },"724": { "doc": "pages.rotate_dx_certs", "title": "Quick reference", "content": "At some point you may need to rotate certificates on your Data Exchange nodes. FireFly provides an API to update a node identity, but there are a few prerequisite steps to load a new certificate on the Data Exchange node itself. This guide will walk you through that process. For more information on different types of identities in FireFly, please see the Reference page on Identities. NOTE: This guide assumes that you are working in a local development environment that was set up with the Getting Started Guide. For a production deployment, the exact process to accomplish each step may be different. For example, you may generate your certs with a CA, or in some other manner. But the high level steps remain the same. The high level steps to the process (described in detail below) are: . | Generate new certs and keys | Install new certs and keys on each Data Exchange filesystem | Remove old certs from the peer-certs directory | Restart each Data Exchange process | PATCH the node identity using the FireFly API | . ", "url": "/firefly/head/tutorials/rotate_dx_certs.html#quick-reference", "relUrl": "/tutorials/rotate_dx_certs.html#quick-reference" - },"721": { + },"725": { "doc": "pages.rotate_dx_certs", "title": "Generate new certs and keys", "content": "To generate a new cert, we’re going to use a self signed certificate generated by openssl. This is how the FireFly CLI generated the original cert that was used when it created your stack. For the first member of a FireFly stack you run: . openssl req -new -x509 -nodes -days 365 -subj /CN=dataexchange_0/O=member_0 -keyout key.pem -out cert.pem . For the second member: . openssl req -new -x509 -nodes -days 365 -subj /CN=dataexchange_1/O=member_1 -keyout key.pem -out cert.pem . NOTE: If you perform these two commands in the same directory, the second one will overwrite the output of the first. It is advisable to run them in separate directories, or copy the cert and key to the Data Exchange file system (the next step below) before generating the next cert / key pair. ", "url": "/firefly/head/tutorials/rotate_dx_certs.html#generate-new-certs-and-keys", "relUrl": "/tutorials/rotate_dx_certs.html#generate-new-certs-and-keys" - },"722": { + },"726": { "doc": "pages.rotate_dx_certs", "title": "Install the new certs on each Data Exchange File System", "content": "For a dev environment created with the FireFly CLI, the certificate and key will be located in the /data directory on the Data Exchange node’s file system. You can use the docker cp command to copy the file to the correct location, then set the file ownership correctly. docker cp cert.pem dev_dataexchange_0:/data/cert.pem docker exec dev_dataexchange_0 chown root:root /data/cert.pem . NOTE: If your environment is not called dev you may need to change the beginning of the container name in the Docker commands listed in this guide. ", "url": "/firefly/head/tutorials/rotate_dx_certs.html#install-the-new-certs-on-each-data-exchange-file-system", "relUrl": "/tutorials/rotate_dx_certs.html#install-the-new-certs-on-each-data-exchange-file-system" - },"723": { + },"727": { "doc": "pages.rotate_dx_certs", "title": "Remove old certs from the peer-certs directory", "content": "To clear out the old certs from the first Data Exchange node run: . docker exec dev_dataexchange_0 sh -c \"rm /data/peer-certs/*.pem\" . To clear out the old certs from the second Data Exchange node run: . docker exec dev_dataexchange_1 sh -c \"rm /data/peer-certs/*.pem\" . ", "url": "/firefly/head/tutorials/rotate_dx_certs.html#remove-old-certs-from-the-peer-certs-directory", "relUrl": "/tutorials/rotate_dx_certs.html#remove-old-certs-from-the-peer-certs-directory" - },"724": { + },"728": { "doc": "pages.rotate_dx_certs", "title": "Restart each Data Exchange process", "content": "To restart your Data Exchange processes, run: . docker restart dev_dataexchange_0 . docker restart dev_dataexchange_1 . ", "url": "/firefly/head/tutorials/rotate_dx_certs.html#restart-each-data-exchange-process", "relUrl": "/tutorials/rotate_dx_certs.html#restart-each-data-exchange-process" - },"725": { + },"729": { "doc": "pages.rotate_dx_certs", "title": "PATCH the node identity using the FireFly API", "content": "The final step is to broadcast the new cert for each node, from the FireFly node that will be using that cert. You will need to lookup the UUID for the node identity in order to update it. Request . GET http://localhost:5000/api/v1/namespaces/default/identities . Response . In the JSON response body, look for the node identity that belongs on this FireFly instance. Here is the node identity from an example stack: ... { \"id\": \"20da74a2-d4e6-4eaf-8506-e7cd205d8254\", \"did\": \"did:firefly:node/node_2b9630\", \"type\": \"node\", \"parent\": \"41e93d92-d0da-4e5a-9cee-adf33f017a60\", \"namespace\": \"default\", \"name\": \"node_2b9630\", \"profile\": { \"cert\": \"-----BEGIN CERTIFICATE-----\\nMIIC1DCCAbwCCQDa9x3wC7wepDANBgkqhkiG9w0BAQsFADAsMRcwFQYDVQQDDA5k\\nYXRhZXhjaGFuZ2VfMDERMA8GA1UECgwIbWVtYmVyXzAwHhcNMjMwMjA2MTQwMTEy\\nWhcNMjQwMjA2MTQwMTEyWjAsMRcwFQYDVQQDDA5kYXRhZXhjaGFuZ2VfMDERMA8G\\nA1UECgwIbWVtYmVyXzAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJ\\nSgtJw99V7EynvqxWdJkeiUlOg3y+JtJlhxGC//JLp+4sYCtOMriULNf5ouImxniR\\nO2vEd+LNdMuREN4oZdUHtJD4MM7lOFw/0ICNEPJ+oEoUTzOC0OK68sA+OCybeS2L\\nmLBu4yvWDkpufR8bxBJfBGarTAFl36ao1Eoogn4m9gmVrX+V5SOKUhyhlHZFkZNb\\ne0flwQmDMKg6qAbHf3j8cnrrZp26n68IGjwqySPFIRLFSz28zzMYtyzo4b9cF9NW\\nGxusMHsExX5gzlTjNacGx8Tlzwjfolt23D+WHhZX/gekOsFiV78mVjgJanE2ls6D\\n5ZlXi5iQSwm8dlmo9RxFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAwr4aAvQnXG\\nkO3xNO+7NGzbb/Nyck5udiQ3RmlZBEJSUsPCsWd4SBhH7LvgbT9ECuAEjgH+2Ip7\\nusd8CROr3sTb9t+7Krk+ljgZirkjq4j/mIRlqHcBJeBtylOz2p0oPsitlI8Yea2D\\nQ4/Xru6txUKNK+Yut3G9qvg/vm9TAwkNHSthzb26bI7s6lx9ZSuFbbG6mR+RQ+8A\\nU4AX1DVo5QyTwSi1lp0+pKFEgtutmWGYn8oT/ya+OLzj+l7Ul4HE/mEAnvECtA7r\\nOC8AEjC5T4gUsLt2IXW9a7lCgovjHjHIySQyqsdYBjkKSn5iw2LRovUWxT1GBvwH\\nFkTvCpHhgko=\\n-----END CERTIFICATE-----\\n\", \"endpoint\": \"https://dataexchange_0:3001\", \"id\": \"member_0/node_2b9630\" }, \"messages\": { \"claim\": \"95da690b-bb05-4873-9478-942f607f363a\", \"verification\": null, \"update\": null }, \"created\": \"2023-02-06T14:02:50.874319382Z\", \"updated\": \"2023-02-06T14:02:50.874319382Z\" }, ... Copy the UUID from the id field, and add that to the PATCH request. In this case it is 20da74a2-d4e6-4eaf-8506-e7cd205d8254. Request . Now we will send the new certificate to FireFly. Put the contents of your cert.pem file in the cert field. NOTE: Usually the cert.pem file will contain line breaks which will not be handled correctly by JSON parsers. Be sure to replace those line breaks with \\n so that the cert field is all on one line as shown below. PATCH http://localhost:5000/api/v1/namespaces/default/identities/20da74a2-d4e6-4eaf-8506-e7cd205d8254 . { \"profile\": { \"cert\": \"-----BEGIN CERTIFICATE-----\\nMIIC1DCCAbwCCQDeKjPt3siRHzANBgkqhkiG9w0BAQsFADAsMRcwFQYDVQQDDA5k\\nYXRhZXhjaGFuZ2VfMDERMA8GA1UECgwIbWVtYmVyXzAwHhcNMjMwMjA2MTYxNTU3\\nWhcNMjQwMjA2MTYxNTU3WjAsMRcwFQYDVQQDDA5kYXRhZXhjaGFuZ2VfMDERMA8G\\nA1UECgwIbWVtYmVyXzAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCy\\nEJaqDskxhkPHmCqj5Mxq+9QX1ec19fulh9Zvp8dLA6bfeg4fdQ9Ha7APG6w/0K8S\\nEaXOflSpXb0oKMe42amIqwvQaqTOA97HIe5R2HZxA1RWqXf+AueowWgI4crxr2M0\\nZCiXHyiZKpB8nzO+bdO9AKeYnzbhCsO0gq4LPOgpPjYkHPKhabeMVZilZypDVOGk\\nLU+ReQoVEZ+P+t0B/9v+5IQ2yyH41n5dh6lKv4mIaC1OBtLc+Pd6DtbRb7pijkgo\\n+LyqSdl24RHhSgZcTtMQfoRIVzvMkhF5SiJczOC4R8hmt62jtWadO4D5ZtJ7N37/\\noAG/7KJO4HbByVf4xOcDAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKWbQftV05Fc\\niwVtZpyvP2l4BvKXvMOyg4GKcnBSZol7UwCNrjwYSjqgqyuedTSZXHNhGFxQbfAC\\n94H25bDhWOfd7JH2D7E6RRe3eD9ouDnrt+de7JulsNsFK23IM4Nz5mRhRMVy/5p5\\n9yrsdW+5MXKWgz9569TIjiciCf0JqB7iVPwRrQyz5gqOiPf81PlyaMDeaH9wXtra\\n/1ZRipXiGiNroSPFrQjIVLKWdmnhWKWjFXsiijdSV/5E+8dBb3t//kEZ8UWfBrc4\\nfYVuZ8SJtm2ZzBmit3HFatDlFTE8PanRf/UDALUp4p6YKJ8NE2T8g/uDE0ee1pnF\\nIDsrC1GX7rs=\\n-----END CERTIFICATE-----\\n\", \"endpoint\": \"https://dataexchange_0:3001\", \"id\": \"member_0\" } } . Response . { \"id\": \"20da74a2-d4e6-4eaf-8506-e7cd205d8254\", \"did\": \"did:firefly:node/node_2b9630\", \"type\": \"node\", \"parent\": \"41e93d92-d0da-4e5a-9cee-adf33f017a60\", \"namespace\": \"default\", \"name\": \"node_2b9630\", \"profile\": { \"cert\": \"-----BEGIN CERTIFICATE-----\\nMIIC1DCCAbwCCQDeKjPt3siRHzANBgkqhkiG9w0BAQsFADAsMRcwFQYDVQQDDA5k\\nYXRhZXhjaGFuZ2VfMDERMA8GA1UECgwIbWVtYmVyXzAwHhcNMjMwMjA2MTYxNTU3\\nWhcNMjQwMjA2MTYxNTU3WjAsMRcwFQYDVQQDDA5kYXRhZXhjaGFuZ2VfMDERMA8G\\nA1UECgwIbWVtYmVyXzAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCy\\nEJaqDskxhkPHmCqj5Mxq+9QX1ec19fulh9Zvp8dLA6bfeg4fdQ9Ha7APG6w/0K8S\\nEaXOflSpXb0oKMe42amIqwvQaqTOA97HIe5R2HZxA1RWqXf+AueowWgI4crxr2M0\\nZCiXHyiZKpB8nzO+bdO9AKeYnzbhCsO0gq4LPOgpPjYkHPKhabeMVZilZypDVOGk\\nLU+ReQoVEZ+P+t0B/9v+5IQ2yyH41n5dh6lKv4mIaC1OBtLc+Pd6DtbRb7pijkgo\\n+LyqSdl24RHhSgZcTtMQfoRIVzvMkhF5SiJczOC4R8hmt62jtWadO4D5ZtJ7N37/\\noAG/7KJO4HbByVf4xOcDAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKWbQftV05Fc\\niwVtZpyvP2l4BvKXvMOyg4GKcnBSZol7UwCNrjwYSjqgqyuedTSZXHNhGFxQbfAC\\n94H25bDhWOfd7JH2D7E6RRe3eD9ouDnrt+de7JulsNsFK23IM4Nz5mRhRMVy/5p5\\n9yrsdW+5MXKWgz9569TIjiciCf0JqB7iVPwRrQyz5gqOiPf81PlyaMDeaH9wXtra\\n/1ZRipXiGiNroSPFrQjIVLKWdmnhWKWjFXsiijdSV/5E+8dBb3t//kEZ8UWfBrc4\\nfYVuZ8SJtm2ZzBmit3HFatDlFTE8PanRf/UDALUp4p6YKJ8NE2T8g/uDE0ee1pnF\\nIDsrC1GX7rs=\\n-----END CERTIFICATE-----\\n\", \"endpoint\": \"https://dataexchange_0:3001\", \"id\": \"member_0\" }, \"messages\": { \"claim\": \"95da690b-bb05-4873-9478-942f607f363a\", \"verification\": null, \"update\": \"5782cd7c-7643-4d7f-811b-02765a7aaec5\" }, \"created\": \"2023-02-06T14:02:50.874319382Z\", \"updated\": \"2023-02-06T14:02:50.874319382Z\" } . Repeat these requests for the second member/node running on port 5001. After that you should be back up and running with your new certs, and you should be able to send private messages again. ", "url": "/firefly/head/tutorials/rotate_dx_certs.html#patch-the-node-identity-using-the-firefly-api", "relUrl": "/tutorials/rotate_dx_certs.html#patch-the-node-identity-using-the-firefly-api" - },"726": { + },"730": { "doc": "pages.rotate_dx_certs", "title": "pages.rotate_dx_certs", "content": " ", "url": "/firefly/head/tutorials/rotate_dx_certs.html", "relUrl": "/tutorials/rotate_dx_certs.html" - },"727": { + },"731": { "doc": "③ Use the Sandbox", "title": "Use the Sandbox", "content": " ", "url": "/firefly/head/gettingstarted/sandbox.html#use-the-sandbox", "relUrl": "/gettingstarted/sandbox.html#use-the-sandbox" - },"728": { + },"732": { "doc": "③ Use the Sandbox", "title": "Table of contents", "content": ". | Previous steps: Start your environment | Video walkthrough | Open the FireFly Sandbox for the first member | Sandbox Layout . | Left column: Prepare your request | Middle column: Preview server code and see response | Right column: Events received on the WebSocket | . | Messages . | Things to try out | . | Tokens . | Things to try out | . | Contracts . | Things to try out | . | Go forth and build! | . ", "url": "/firefly/head/gettingstarted/sandbox.html#table-of-contents", "relUrl": "/gettingstarted/sandbox.html#table-of-contents" - },"729": { + },"733": { "doc": "③ Use the Sandbox", "title": "Previous steps: Start your environment", "content": "If you haven’t started a FireFly stack already, please go back to the previous step and read the guide on how to Start your environment. ← ② Start your environment . Now that you have a full network of three Supernodes running on your machine, let’s look at the first two components that you will interact with: the FireFly Sandbox and the FireFly Explorer. ", "url": "/firefly/head/gettingstarted/sandbox.html#previous-steps-start-your-environment", "relUrl": "/gettingstarted/sandbox.html#previous-steps-start-your-environment" - },"730": { + },"734": { "doc": "③ Use the Sandbox", "title": "Video walkthrough", "content": "This video is a walkthrough of the FireFly Sandbox and FireFly Explorer from the FireFly 1.0 launch webinar. At this point you should be able to follow along and try all these same things on your own machine. ", "url": "/firefly/head/gettingstarted/sandbox.html#video-walkthrough", "relUrl": "/gettingstarted/sandbox.html#video-walkthrough" - },"731": { + },"735": { "doc": "③ Use the Sandbox", "title": "Open the FireFly Sandbox for the first member", "content": "When you set up your FireFly stack in the previous section, it should have printed some URLs like the following. Open the link in a browser for the `Sandbox UI for member ‘0’. It should be: http://127.0.0.1:5109 . ff start dev this will take a few seconds longer since this is the first time you're running this stack... done Web UI for member '0': http://127.0.0.1:5000/ui Sandbox UI for member '0': http://127.0.0.1:5109 Web UI for member '1': http://127.0.0.1:5001/ui Sandbox UI for member '1': http://127.0.0.1:5209 Web UI for member '2': http://127.0.0.1:5002/ui Sandbox UI for member '2': http://127.0.0.1:5309 To see logs for your stack run: ff logs dev . ", "url": "/firefly/head/gettingstarted/sandbox.html#open-the-firefly-sandbox-for-the-first-member", "relUrl": "/gettingstarted/sandbox.html#open-the-firefly-sandbox-for-the-first-member" - },"732": { + },"736": { "doc": "③ Use the Sandbox", "title": "Sandbox Layout", "content": ". The Sandbox is split up into three columns: . Left column: Prepare your request . On the left-hand side of the page, you can fill out simple form fields to construct messages and more. Some tabs have more types of requests on them in sections that can be expanded or collapsed. Across the top of this column there are three tabs that switch between the three main sets of functionality in the Sandbox. The next three sections of this guide will walk you through each one of these. The first tab we will explore is the MESSAGING tab. This is where we can send broadcasts and private messages. Middle column: Preview server code and see response . As you type in the form on the left side of the page, you may notice that the source code in the top middle of the page updates automatically. If you were building a backend app, this is an example of code that your app could use to call the FireFly SDK. The middle column also contains a RUN button to actually send the request. Right column: Events received on the WebSocket . On the right-hand side of the page you can see a stream of events being received on a WebSocket connection that the backend has open to FireFly. For example, as you make requests to send messages, you can see when the messages are asynchronously confirmed. ", "url": "/firefly/head/gettingstarted/sandbox.html#sandbox-layout", "relUrl": "/gettingstarted/sandbox.html#sandbox-layout" - },"733": { + },"737": { "doc": "③ Use the Sandbox", "title": "Messages", "content": "The Messages tab is where we can send broadcast and private messages to other members and nodes in the FireFly network. Messages can be a string, any arbitrary JSON object, or a binary file. For more details, please see the tutorial on Broadcasting data and Privately sending data. Things to try out . | Send a broadcast message and view the data payload in every member’s FireFly Explorer | Send a private message to one member, and verify that the data payload is not visible in the third member’s FireFly Explorer | Send an image file and download it from another member’s FireFly Explorer | . ", "url": "/firefly/head/gettingstarted/sandbox.html#messages", "relUrl": "/gettingstarted/sandbox.html#messages" - },"734": { + },"738": { "doc": "③ Use the Sandbox", "title": "Tokens", "content": "The Tokens tab is where you can create token pools, and mint, burn, or transfer tokens. This works with both fungible and non-fungible tokens (NFTs). For more details, please see the Tokens tutorials. Things to try out . | Create a fungible token pool and mint some tokens and view your balance in the FireFly Explorer | Transfer some amount of those tokens to another member and view the transfer transaction in the FireFly Explorer | Burn some amount of tokens and view the transaction and updated balances in the FireFly Explorer | Create a non-fungible token pool and mint some NFTs | Transfer an NFT to another member and verify the account balances in the FireFly Explorer | . ", "url": "/firefly/head/gettingstarted/sandbox.html#tokens", "relUrl": "/gettingstarted/sandbox.html#tokens" - },"735": { + },"739": { "doc": "③ Use the Sandbox", "title": "Contracts", "content": "The Contracts section of the Sandbox lets you interact with custom smart contracts, right from your web browser! The Sandbox also provides some helpful tips on deploying your smart contract to the blockchain. For more details, please see the tutorial on Working with custom smart contracts. Things to try out . | Create a contract interface and API, then view the Swagger UI for your new API | Create an event listener | Use the Swagger UI to call a smart contract function that emits an event. Verify that the event is received in the Sandbox and shows up in the FireFly Explorer. | . ", "url": "/firefly/head/gettingstarted/sandbox.html#contracts", "relUrl": "/gettingstarted/sandbox.html#contracts" - },"736": { + },"740": { "doc": "③ Use the Sandbox", "title": "Go forth and build!", "content": "At this point you should have a pretty good understanding of some of the major features of Hyperledger FireFly. Now, using what you’ve learned, you can go and build your own Web3 app! Don’t forget to join the Hyperledger Discord server and come chat with us in the #firefly channel. ", "url": "/firefly/head/gettingstarted/sandbox.html#go-forth-and-build", "relUrl": "/gettingstarted/sandbox.html#go-forth-and-build" - },"737": { + },"741": { "doc": "③ Use the Sandbox", "title": "③ Use the Sandbox", "content": " ", "url": "/firefly/head/gettingstarted/sandbox.html", "relUrl": "/gettingstarted/sandbox.html" - },"738": { + },"742": { "doc": "pages.security", "title": "Security", "content": ". ", "url": "/firefly/head/overview/key_components/security.html#security", "relUrl": "/overview/key_components/security.html#security" - },"739": { + },"743": { "doc": "pages.security", "title": "API Security", "content": "Hyperledger FireFly provides a pluggable infrastructure for authenticating API requests. Each namespace can be configured with a different authentication plugin, such that different teams can have different access to resources on the same FireFly server. A reference plugin implementation is provided for HTTP Basic Auth, combined with a htpasswd verification of passwords with a bcrypt encoding. See this config section for details, and the reference implementation in Github . Pre-packaged vendor extensions to Hyperledger FireFly are known to be available, addressing more comprehensive role-based access control (RBAC) and JWT/OAuth based security models. ", "url": "/firefly/head/overview/key_components/security.html#api-security", "relUrl": "/overview/key_components/security.html#api-security" - },"740": { + },"744": { "doc": "pages.security", "title": "Data Partitioning and Tenancy", "content": "Namespaces also provide a data isolation system for different applications / teams / tenants sharing a Hyperledger FireFly node. Data is partitioned within the FireFly database by namespace. It is also possible to increase the separation between namespaces, by using separate database configurations. For example to different databases or table spaces within a single database server, or even to different database servers. ", "url": "/firefly/head/overview/key_components/security.html#data-partitioning-and-tenancy", "relUrl": "/overview/key_components/security.html#data-partitioning-and-tenancy" - },"741": { + },"745": { "doc": "pages.security", "title": "Private Data Exchange", "content": "FireFly has a pluggable implementation of a private data transfer bus. This transport supports both structured data (conforming to agreed data formats), and large unstructured data & documents. A reference microservice implementation is provided for HTTPS point-to-point connectivity with mutual TLS encryption. See the reference implementation in Github . Pre-packaged vendor extensions to Hyperledger FireFly are known to be available, addressing message queue based reliable delivery of messages, hub-and-spoke connectivity models, chunking of very large file payloads, and end-to-end encryption. Learn more about these private data flows in Multiparty Process Flows. ", "url": "/firefly/head/overview/key_components/security.html#private-data-exchange", "relUrl": "/overview/key_components/security.html#private-data-exchange" - },"742": { + },"746": { "doc": "pages.security", "title": "pages.security", "content": " ", "url": "/firefly/head/overview/key_components/security.html", "relUrl": "/overview/key_components/security.html" - },"743": { + },"747": { "doc": "② Start your environment", "title": "Start your environment", "content": " ", "url": "/firefly/head/gettingstarted/setup_env.html#start-your-environment", "relUrl": "/gettingstarted/setup_env.html#start-your-environment" - },"744": { + },"748": { "doc": "② Start your environment", "title": "Table of contents", "content": ". | Previous steps: Install the FireFly CLI | A FireFly Stack | System Resources | Creating a new stack . | Stack initialization options | Start your stack | . | Next steps: Use in the Sandbox | . ", "url": "/firefly/head/gettingstarted/setup_env.html#table-of-contents", "relUrl": "/gettingstarted/setup_env.html#table-of-contents" - },"745": { + },"749": { "doc": "② Start your environment", "title": "Previous steps: Install the FireFly CLI", "content": "If you haven’t set up the FireFly CLI already, please go back to the previous step and read the guide on how to Install the FireFly CLI. ← ① Install the FireFly CLI . Now that you have the FireFly CLI installed, you are ready to run some Supernodes on your machine! . ", "url": "/firefly/head/gettingstarted/setup_env.html#previous-steps-install-the-firefly-cli", "relUrl": "/gettingstarted/setup_env.html#previous-steps-install-the-firefly-cli" - },"746": { + },"750": { "doc": "② Start your environment", "title": "A FireFly Stack", "content": "A FireFly stack is a collection of Supernodes with networking and configuration that are designed to work together on a single development machine. A stack has multiple members (also referred to organizations). Each member has their own Supernode within the stack. This allows developers to build and test data flows with a mix of public and private data between various parties, all within a single development environment. The stack also contains an instance of the FireFly Sandbox for each member. This is an example of an end-user application that uses FireFly’s API. It has a backend and a frontend which are designed to walk developers through the features of FireFly, and provides code snippets as examples of how to build those features into their own application. The next section in this guide will walk you through using the Sandbox. ", "url": "/firefly/head/gettingstarted/setup_env.html#a-firefly-stack", "relUrl": "/gettingstarted/setup_env.html#a-firefly-stack" - },"747": { + },"751": { "doc": "② Start your environment", "title": "System Resources", "content": "The FireFly stack will run in a docker-compose project. For systems that run Docker containers inside a virtual machine, like macOS, you need to make sure that you’ve allocated enough memory to the Docker virtual machine. We recommend allocating 1GB per member. In this case, we’re going to set up a stack with 3 members, so please make sure you have at least 3 GB of RAM allocated in your Docker Desktop settings. ", "url": "/firefly/head/gettingstarted/setup_env.html#system-resources", "relUrl": "/gettingstarted/setup_env.html#system-resources" - },"748": { + },"752": { "doc": "② Start your environment", "title": "Creating a new stack", "content": "It’s really easy to create a new FireFly stack. The ff init command can create a new stack for you, and will prompt you for a few details such as the name, and how many members you want in your stack. To create an Ethereum based stack, run: . ff init ethereum . To create an Fabric based stack, run: . ff init fabric . Choose a stack name. For this guide, I will choose the name dev, but you can pick whatever you want: . stack name: dev . Chose the number of members for your stack. For this guide, we should pick 3 members, so we can try out both public and private messaging use cases: . number of members: 3 . Stack initialization options . There are quite a few options that you can choose from when creating a new stack. For now, we’ll just stick with the defaults. To see the full list of Ethereum options, just run ff init ethereum --help or to see the full list of Fabric options run ff init fabric --help . ff init ethereum --help Create a new FireFly local dev stack using an Ethereum blockchain Usage: ff init ethereum [stack_name] [member_count] [flags] Flags: --block-period int Block period in seconds. Default is variable based on selected blockchain provider. (default -1) -c, --blockchain-connector string Blockchain connector to use. Options are: [evmconnect ethconnect] (default \"evmconnect\") -n, --blockchain-node string Blockchain node type to use. Options are: [geth besu remote-rpc] (default \"geth\") --chain-id int The chain ID - also used as the network ID (default 2021) --contract-address string Do not automatically deploy a contract, instead use a pre-configured address -h, --help help for ethereum --remote-node-url string For cases where the node is pre-existing and running remotely Global Flags: --ansi string control when to print ANSI control characters (\"never\"|\"always\"|\"auto\") (default \"auto\") --channel string Select the FireFly release channel to use. Options are: [stable head alpha beta rc] (default \"stable\") --connector-config string The path to a yaml file containing extra config for the blockchain connector --core-config string The path to a yaml file containing extra config for FireFly Core -d, --database string Database type to use. Options are: [sqlite3 postgres] (default \"sqlite3\") -e, --external int Manage a number of FireFly core processes outside of the docker-compose stack - useful for development and debugging -p, --firefly-base-port int Mapped port base of FireFly core API (1 added for each member) (default 5000) --ipfs-mode string Set the mode in which IFPS operates. Options are: [private public] (default \"private\") -m, --manifest string Path to a manifest.json file containing the versions of each FireFly microservice to use. Overrides the --release flag. --multiparty Enable or disable multiparty mode (default true) --node-name stringArray Node name --org-name stringArray Organization name --prometheus-enabled Enables Prometheus metrics exposition and aggregation to a shared Prometheus server --prometheus-port int Port for the shared Prometheus server (default 9090) --prompt-names Prompt for org and node names instead of using the defaults -r, --release string Select the FireFly release version to use. Options are: [stable head alpha beta rc] (default \"latest\") --request-timeout int Custom request timeout (in seconds) - useful for registration to public chains --sandbox-enabled Enables the FireFly Sandbox to be started with your FireFly stack (default true) -s, --services-base-port int Mapped port base of services (100 added for each member) (default 5100) -t, --token-providers stringArray Token providers to use. Options are: [none erc1155 erc20_erc721] (default [erc20_erc721]) -v, --verbose verbose log output . Start your stack . To start your stack simply run: . ff start dev . This may take a minute or two and in the background the FireFly CLI will do the following for you: . | Download Docker images for all of the components of the Supernode | Initialize a new blockchain and blockchain node running inside a container | Set up configuration between all the components | Deploy FireFly’s BatchPin smart contract | Deploy an ERC-1155 token smart contract | Register an identity for each member and node | . NOTE: For macOS users, the default port (5000) is already in-use by ControlCe service (AirPlay Receiver). You can either disable this service in your environment, or use a different port when creating your stack (e.g. ff init dev -p 8000) . After your stack finishes starting it will print out the links to each member’s UI and the Sandbox for that node: . ff start dev this will take a few seconds longer since this is the first time you're running this stack... done Web UI for member '0': http://127.0.0.1:5000/ui Sandbox UI for member '0': http://127.0.0.1:5109 Web UI for member '1': http://127.0.0.1:5001/ui Sandbox UI for member '1': http://127.0.0.1:5209 Web UI for member '2': http://127.0.0.1:5002/ui Sandbox UI for member '2': http://127.0.0.1:5309 To see logs for your stack run: ff logs dev . ", "url": "/firefly/head/gettingstarted/setup_env.html#creating-a-new-stack", "relUrl": "/gettingstarted/setup_env.html#creating-a-new-stack" - },"749": { + },"753": { "doc": "② Start your environment", "title": "Next steps: Use in the Sandbox", "content": "Now that you have some Supernodes running, it’s time to start playing: in the Sandbox! . ③ Use the Sandbox → . ", "url": "/firefly/head/gettingstarted/setup_env.html#next-steps-use-in-the-sandbox", "relUrl": "/gettingstarted/setup_env.html#next-steps-use-in-the-sandbox" - },"750": { + },"754": { "doc": "② Start your environment", "title": "② Start your environment", "content": " ", "url": "/firefly/head/gettingstarted/setup_env.html", "relUrl": "/gettingstarted/setup_env.html" - },"751": { + },"755": { "doc": "Simple Types", "title": "Simple Types", "content": " ", "url": "/firefly/head/reference/types/simpletypes.html", "relUrl": "/reference/types/simpletypes.html" - },"752": { + },"756": { "doc": "Simple Types", "title": "Table of contents", "content": ". | UUID | FFTime | FFBigInt | JSONAny | JSONObject | . ", "url": "/firefly/head/reference/types/simpletypes.html#table-of-contents", "relUrl": "/reference/types/simpletypes.html#table-of-contents" - },"753": { + },"757": { "doc": "Simple Types", "title": "UUID", "content": "IDs are generated as UUID V4 globally unique identifiers . ", "url": "/firefly/head/reference/types/simpletypes.html#uuid", "relUrl": "/reference/types/simpletypes.html#uuid" - },"754": { + },"758": { "doc": "Simple Types", "title": "FFTime", "content": "Times are serialized to JSON on the API in RFC 3339 / ISO 8601 nanosecond UTC time for example 2022-05-05T21:19:27.454767543Z. Note that JavaScript can parse this format happily into millisecond time with Date.parse(). Times are persisted as a nanosecond resolution timestamps in the database. On input, and in queries, times can be parsed from RFC3339, or unix timestamps (second, millisecond or nanosecond resolution). ", "url": "/firefly/head/reference/types/simpletypes.html#fftime", "relUrl": "/reference/types/simpletypes.html#fftime" - },"755": { + },"759": { "doc": "Simple Types", "title": "FFBigInt", "content": "Large integers of up to 256bits in size are common in blockchain, and handled in FireFly. In JSON output payloads in FireFly, including events, they are serialized as strings (with base 10). On input you can provide JSON string (string with an 0x prefix are parsed at base 16), or a JSON number. Be careful when using JSON numbers, that the largest number that is safe to transfer using a JSON number is 2^53 - 1. ", "url": "/firefly/head/reference/types/simpletypes.html#ffbigint", "relUrl": "/reference/types/simpletypes.html#ffbigint" - },"756": { + },"760": { "doc": "Simple Types", "title": "JSONAny", "content": "Any JSON type. An object, array, string, number, boolean or null. FireFly stores object data with the same field order as was provided on the input, but with any whitespace removed. ", "url": "/firefly/head/reference/types/simpletypes.html#jsonany", "relUrl": "/reference/types/simpletypes.html#jsonany" - },"757": { + },"761": { "doc": "Simple Types", "title": "JSONObject", "content": "Any JSON Object. Must be an object, rather than an array or a simple type. ", "url": "/firefly/head/reference/types/simpletypes.html#jsonobject", "relUrl": "/reference/types/simpletypes.html#jsonobject" - },"758": { + },"762": { "doc": "Subscription", "title": "Subscription", "content": " ", "url": "/firefly/head/reference/types/subscription.html", "relUrl": "/reference/types/subscription.html" - },"759": { + },"763": { "doc": "Subscription", "title": "Table of contents", "content": ". | Subscription . | Creating a subscription | Subscriptions and workload balancing | Pluggable Transports | WebSockets . | WebSocket protocol | Using start and ack explicitly | Auto-starting via URL query and autoack | Ephemeral WebSocket subscriptions | . | Webhooks . | Batching events | . | Example | Field Descriptions | . | SubscriptionFilter | MessageFilter | TransactionFilter | BlockchainEventFilter | SubscriptionOptions | WebhookInputOptions | WebhookRetryOptions | WebhookHTTPOptions | . ", "url": "/firefly/head/reference/types/subscription.html#table-of-contents", "relUrl": "/reference/types/subscription.html#table-of-contents" - },"760": { + },"764": { "doc": "Subscription", "title": "Subscription", "content": "Each Subscription tracks delivery of events to a particular application, and allows FireFly to ensure that messages are delivered reliably to that application. Creating a subscription . Before you can connect to a subscription, you must create it via the REST API. One special case where you do not need to do this, is Ephemeral WebSocket connections (described below). For these you can just connect and immediately start receiving events. When creating a new subscription, you give it a name which is how you will refer to it when you connect. You are also able to specify server-side filtering that should be performed against the event stream, to limit the set of events that are sent to your application. All subscriptions are created within a namespace, and automatically filter events to only those emitted within that namespace. You can create multiple subscriptions for your application, to request different sets of server-side filtering for events. You can then request FireFly to deliver events for both subscriptions over the same WebSocket (if you are using the WebSocket transport). However, delivery order is not assured between two subscriptions. Subscriptions and workload balancing . You can have multiple scaled runtime instances of a single application, all running in parallel. These instances of the application all share a single subscription. Each event is only delivered once to the subscription, regardless of how many instances of your application connect to FireFly. With multiple WebSocket connections active on a single subscription, each event might be delivered to different instance of your application. This means workload is balanced across your instances. However, each event still needs to be acknowledged, so delivery processing order can still be maintained within your application database state. If you have multiple different applications all needing their own copy of the same event, then you need to configure a separate subscription for each application. Pluggable Transports . Hyperledger FireFly has two built-in transports for delivery of events to applications - WebSockets and Webhooks. The event interface is fully pluggable, so you can extend connectivity over an external event bus - such as NATS, Apache Kafka, Rabbit MQ, Redis etc. WebSockets . If your application has a back-end server runtime, then WebSockets are the most popular option for listening to events. WebSockets are well supported by all popular application development frameworks, and are very firewall friendly for connecting applications into your FireFly server. Check out the @hyperledger/firefly-sdk SDK for Node.js applications, and the hyperledger/firefly-common module for Golang applications. These both contain reliable WebSocket clients for your event listeners. A Java SDK is a roadmap item for the community. WebSocket protocol . FireFly has a simple protocol on top of WebSockets: . | Each time you connect/reconnect you need to tell FireFly to start sending you events on a particular subscription. You can do this in two ways (described in detail below): . | Send a WSStart JSON payload | Include a namespace and name query parameter in the URL when you connect, along with query params for other fields of WSStart | . | One you have started your subscription, each event flows from the server, to your application as a JSON Event payload | For each event you receive, you need to send a WSAck payload. | Unless you specified autoack in step (1) | . | . The SDK libraries for FireFly help you ensure you send the start payload each time your WebSocket reconnects. Using start and ack explicitly . Here’s an example websocat command showing an explicit start and ack. $ websocat ws://localhost:5000/ws {\"type\":\"start\",\"namespace\":\"default\",\"name\":\"docexample\"} # ... for each event that arrives here, you send an ack ... {\"type\":\"ack\",\"id\":\"70ed4411-57cf-4ba1-bedb-fe3b4b5fd6b6\"} . When creating your subscription, you can set readahead in order to ask FireFly to stream a number of messages to your application, ahead of receiving the acknowledgements. readahead can be a powerful tool to increase performance, but does require your application to ensure it processes events in the correct order and sends exactly one ack for each event. Auto-starting via URL query and autoack . Here’s an example websocat where we use URL query parameters to avoid the need to send a start JSON payload. We also use autoack so that events just keep flowing from the server. $ websocat \"ws://localhost:5000/ws?namespace=default&name=docexample&autoack\" # ... events just keep arriving here, as the server-side auto-acknowledges # the events as it delivers them to you. Note using autoack means you can miss events in the case of a disconnection, so should not be used for production applications that require at-least-once delivery. Ephemeral WebSocket subscriptions . FireFly WebSockets provide a special option to create a subscription dynamically, that only lasts for as long as you are connected to the server. We call these ephemeral subscriptions. Here’s an example websocat command showing an an ephemeral subscription - notice we don’t specify a name for the subscription, and there is no need to have already created the subscription beforehand. Here we also include an extra query parameter to set a server-side filter, to only include message events. $ websocat \"ws://localhost:5000/ws?namespace=default&ephemeral&autoack&filter.events=message_.*\" {\"type\":\"start\",\"namespace\":\"default\",\"name\":\"docexample\"} # ... for each event that arrives here, you send an ack ... {\"type\":\"ack\",\"id\":\"70ed4411-57cf-4ba1-bedb-fe3b4b5fd6b6\"} . Ephemeral subscriptions are very convenient for experimentation, debugging and monitoring. However, they do not give reliable delivery because you only receive events that occur while you are connected. If you disconnect and reconnect, you will miss all events that happened while your application was not listening. Webhooks . The Webhook transport allows FireFly to make HTTP calls against your application’s API when events matching your subscription are emitted. This means the direction of network connection is from the FireFly server, to the application (the reverse of WebSockets). Conversely it means you don’t need to add any connection management code to your application - just expose and API that FireFly can call to process the events. Webhooks are great for serverless functions (AWS Lambda etc.), integrations with SaaS applications, and calling existing APIs. The FireFly configuration options for a Webhook subscription are very flexible, allowing you to customize your HTTP requests as follows: . | Set the HTTP request details: . | Method, URL, query, headers and input body | . | Wait for a invocation of the back-end service, before acknowledging . | To retry requests to your Webhook on a non-2xx HTTP status code or other error, you should enable and configure options.retry | The event is acknowledged once the request (with any retries), is completed - regardless of whether the outcome was a success or failure. | . | Use fastack to acknowledge against FireFly immediately and make multiple parallel calls to the HTTP API in a fire-and-forget fashion. | Set the HTTP request details dynamically from message_confirmed events: . | Map data out of the first data element in message events | Requires withData to be set on the subscription, in addition to the input.* configuration options | . | Can automatically generate a “reply” message for message_confirmed events: . | Maps the response body of the HTTP call to data in the reply message | Sets the cid and topic in the reply message to match the request | Sets a tag in the reply message, per the configuration, or dynamically based on a field in the input request data. | . | . Batching events . Webhooks have the ability to batch events into a single HTTP request instead of sending an event per HTTP request. The interface will be a JSON array of events instead of a top level JSON object with a single event. The size of the batch will be set by the readAhead limit and an optional timeout can be specified to send the events when the batch hasn’t filled. To enable this set the following configuration under SubscriptionOptions . | batch | Events are delivered in batches in an ordered array. The batch size is capped to the readAhead limit. The event payload is always an array even if there is a single event in the batch. Commonly used with Webhooks to allow events to be delivered and acknowledged in batches. | bool | . | batchTimeout | When batching is enabled, the optional timeout to send events even when the batch hasn’t filled. Defaults to 2 seconds | string | . NOTE: When batch is enabled, withData cannot be used as these may alter the HTTP request based on a single event and in batching it does not make sense for now. Example . { \"id\": \"c38d69fd-442e-4d6f-b5a4-bab1411c7fe8\", \"namespace\": \"ns1\", \"name\": \"app1\", \"transport\": \"websockets\", \"filter\": { \"events\": \"^(message_.*|token_.*)$\", \"message\": { \"tag\": \"^(red|blue)$\" }, \"transaction\": {}, \"blockchainevent\": {} }, \"options\": { \"firstEvent\": \"newest\", \"readAhead\": 50 }, \"created\": \"2022-05-16T01:23:15Z\", \"updated\": null } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the subscription | UUID | . | namespace | The namespace of the subscription. A subscription will only receive events generated in the namespace of the subscription | string | . | name | The name of the subscription. The application specifies this name when it connects, in order to attach to the subscription and receive events that arrived while it was disconnected. If multiple apps connect to the same subscription, events are workload balanced across the connected application instances | string | . | transport | The transport plugin responsible for event delivery (WebSockets, Webhooks, JMS, NATS etc.) | string | . | filter | Server-side filter to apply to events | SubscriptionFilter | . | options | Subscription options | SubscriptionOptions | . | ephemeral | Ephemeral subscriptions only exist as long as the application is connected, and as such will miss events that occur while the application is disconnected, and cannot be created administratively. You can create one over over a connected WebSocket connection | bool | . | created | Creation time of the subscription | FFTime | . | updated | Last time the subscription was updated | FFTime | . ", "url": "/firefly/head/reference/types/subscription.html", "relUrl": "/reference/types/subscription.html" - },"761": { + },"765": { "doc": "Subscription", "title": "SubscriptionFilter", "content": "| Field Name | Description | Type | . | events | Regular expression to apply to the event type, to subscribe to a subset of event types | string | . | message | Filters specific to message events. If an event is not a message event, these filters are ignored | MessageFilter | . | transaction | Filters specific to events with a transaction. If an event is not associated with a transaction, this filter is ignored | TransactionFilter | . | blockchainevent | Filters specific to blockchain events. If an event is not a blockchain event, these filters are ignored | BlockchainEventFilter | . | topic | Regular expression to apply to the topic of the event, to subscribe to a subset of topics. Note for messages sent with multiple topics, a separate event is emitted for each topic | string | . | topics | Deprecated: Please use ‘topic’ instead | string | . | tag | Deprecated: Please use ‘message.tag’ instead | string | . | group | Deprecated: Please use ‘message.group’ instead | string | . | author | Deprecated: Please use ‘message.author’ instead | string | . ", "url": "/firefly/head/reference/types/subscription.html#subscriptionfilter", "relUrl": "/reference/types/subscription.html#subscriptionfilter" - },"762": { + },"766": { "doc": "Subscription", "title": "MessageFilter", "content": "| Field Name | Description | Type | . | tag | Regular expression to apply to the message ‘header.tag’ field | string | . | group | Regular expression to apply to the message ‘header.group’ field | string | . | author | Regular expression to apply to the message ‘header.author’ field | string | . ", "url": "/firefly/head/reference/types/subscription.html#messagefilter", "relUrl": "/reference/types/subscription.html#messagefilter" - },"763": { + },"767": { "doc": "Subscription", "title": "TransactionFilter", "content": "| Field Name | Description | Type | . | type | Regular expression to apply to the transaction ‘type’ field | string | . ", "url": "/firefly/head/reference/types/subscription.html#transactionfilter", "relUrl": "/reference/types/subscription.html#transactionfilter" - },"764": { + },"768": { "doc": "Subscription", "title": "BlockchainEventFilter", "content": "| Field Name | Description | Type | . | name | Regular expression to apply to the blockchain event ‘name’ field, which is the name of the event in the underlying blockchain smart contract | string | . | listener | Regular expression to apply to the blockchain event ‘listener’ field, which is the UUID of the event listener. So you can restrict your subscription to certain blockchain listeners. Alternatively to avoid your application need to know listener UUIDs you can set the ‘topic’ field of blockchain event listeners, and use a topic filter on your subscriptions | string | . ", "url": "/firefly/head/reference/types/subscription.html#blockchaineventfilter", "relUrl": "/reference/types/subscription.html#blockchaineventfilter" - },"765": { + },"769": { "doc": "Subscription", "title": "SubscriptionOptions", "content": "| Field Name | Description | Type | . | firstEvent | Whether your application would like to receive events from the ‘oldest’ event emitted by your FireFly node (from the beginning of time), or the ‘newest’ event (from now), or a specific event sequence. Default is ‘newest’ | SubOptsFirstEvent | . | readAhead | The number of events to stream ahead to your application, while waiting for confirmation of consumption of those events. At least once delivery semantics are used in FireFly, so if your application crashes/reconnects this is the maximum number of events you would expect to be redelivered after it restarts | uint16 | . | withData | Whether message events delivered over the subscription, should be packaged with the full data of those messages in-line as part of the event JSON payload. Or if the application should make separate REST calls to download that data. May not be supported on some transports. | bool | . | batch | Events are delivered in batches in an ordered array. The batch size is capped to the readAhead limit. The event payload is always an array even if there is a single event in the batch, allowing client-side optimizations when processing the events in a group. Available for both Webhooks and WebSockets. | bool | . | batchTimeout | When batching is enabled, the optional timeout to send events even when the batch hasn’t filled. | string | . | fastack | Webhooks only: When true the event will be acknowledged before the webhook is invoked, allowing parallel invocations | bool | . | url | Webhooks only: HTTP url to invoke. Can be relative if a base URL is set in the webhook plugin config | string | . | method | Webhooks only: HTTP method to invoke. Default=POST | string | . | json | Webhooks only: Whether to assume the response body is JSON, regardless of the returned Content-Type | bool | . | reply | Webhooks only: Whether to automatically send a reply event, using the body returned by the webhook | bool | . | replytag | Webhooks only: The tag to set on the reply message | string | . | replytx | Webhooks only: The transaction type to set on the reply message | string | . | headers | Webhooks only: Static headers to set on the webhook request | `` | . | query | Webhooks only: Static query params to set on the webhook request | `` | . | tlsConfigName | The name of an existing TLS configuration associated to the namespace to use | string | . | input | Webhooks only: A set of options to extract data from the first JSON input data in the incoming message. Only applies if withData=true | WebhookInputOptions | . | retry | Webhooks only: a set of options for retrying the webhook call | WebhookRetryOptions | . | httpOptions | Webhooks only: a set of options for HTTP | WebhookHTTPOptions | . ", "url": "/firefly/head/reference/types/subscription.html#subscriptionoptions", "relUrl": "/reference/types/subscription.html#subscriptionoptions" - },"766": { + },"770": { "doc": "Subscription", "title": "WebhookInputOptions", "content": "| Field Name | Description | Type | . | query | A top-level property of the first data input, to use for query parameters | string | . | headers | A top-level property of the first data input, to use for headers | string | . | body | A top-level property of the first data input, to use for the request body. Default is the whole first body | string | . | path | A top-level property of the first data input, to use for a path to append with escaping to the webhook path | string | . | replytx | A top-level property of the first data input, to use to dynamically set whether to pin the response (so the requester can choose) | string | . ", "url": "/firefly/head/reference/types/subscription.html#webhookinputoptions", "relUrl": "/reference/types/subscription.html#webhookinputoptions" - },"767": { + },"771": { "doc": "Subscription", "title": "WebhookRetryOptions", "content": "| Field Name | Description | Type | . | enabled | Enables retry on HTTP calls, defaults to false | bool | . | count | Number of times to retry the webhook call in case of failure | int | . | initialDelay | Initial delay between retries when we retry the webhook call | string | . | maxDelay | Max delay between retries when we retry the webhookcall | string | . ", "url": "/firefly/head/reference/types/subscription.html#webhookretryoptions", "relUrl": "/reference/types/subscription.html#webhookretryoptions" - },"768": { + },"772": { "doc": "Subscription", "title": "WebhookHTTPOptions", "content": "| Field Name | Description | Type | . | proxyURL | HTTP proxy URL to use for outbound requests to the webhook | string | . | tlsHandshakeTimeout | The max duration to hold a TLS handshake alive | string | . | requestTimeout | The max duration to hold a TLS handshake alive | string | . | maxIdleConns | The max number of idle connections to hold pooled | int | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | string | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted. | string | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | string | . ", "url": "/firefly/head/reference/types/subscription.html#webhookhttpoptions", "relUrl": "/reference/types/subscription.html#webhookhttpoptions" - },"769": { + },"773": { "doc": "pages.introduction", "title": "Introduction to Hyperledger FireFly", "content": " ", "url": "/firefly/head/overview/supernode_concept.html#introduction-to-hyperledger-firefly", "relUrl": "/overview/supernode_concept.html#introduction-to-hyperledger-firefly" - },"770": { + },"774": { "doc": "pages.introduction", "title": "Table of contents", "content": ". | Your Gateway to Web3 Technologies | An Open Source Supernode for Web3 Apps | . ", "url": "/firefly/head/overview/supernode_concept.html#table-of-contents", "relUrl": "/overview/supernode_concept.html#table-of-contents" - },"771": { + },"775": { "doc": "pages.introduction", "title": "Your Gateway to Web3 Technologies", "content": ". Hyperledger FireFly is an organization’s gateway to Web3, including all the blockchain ecosystems that they participate in. Multiple blockchains, multiple token economies, and multiple business networks. FireFly is not another blockchain implementation, rather it is a pluggable API Orchestration and Data layer, integrating into all of the different types of decentralized technologies that exist in Web3: . | Public Blockchains, Layer 2 scaling solutions, Side chains, and App chains | Permissioned Blockchains and Distributed Ledger Technologies (DLTs) | Decentralized storage solutions | Token ecosystems and standards | Smart Contracts, DeFi solutions and DAOs | Private off-chain encrypted communication rails | Advanced cryptography solutions | Identity frameworks | . ", "url": "/firefly/head/overview/supernode_concept.html#your-gateway-to-web3-technologies", "relUrl": "/overview/supernode_concept.html#your-gateway-to-web3-technologies" - },"772": { + },"776": { "doc": "pages.introduction", "title": "An Open Source Supernode for Web3 Apps", "content": "Hyperledger FireFly is a toolkit for building and connecting new full-stack decentralized applications (dapps), as well as integrating your existing core systems to the world of Web3. It has a runtime engine, and it provides a data layer that synchronizes state from the blockchain and other Web3 technologies. It exposes an API and Event Bus to your business logic, that is reliable, developer friendly and ready for enterprise use. We call this a Supernode - it sits between the application and the underlying infrastructure nodes, providing layers of additional function. The concept of a Supernode has evolved over the last decade of enterprise blockchain projects, as developers realized that they need much more than a blockchain node for their projects to be successful. Without a technology like Hyperledger FireFly, the application layer becomes extremely complex and fragile. Tens of thousands of lines of complex low-level “plumbing” / “middleware” code is required to integrate the web3 infrastructure into the application. This code provides zero unique business value to the solution, but can consume a huge proportion of the engineering budget and maintenance cost if built bespoke within a solution. ", "url": "/firefly/head/overview/supernode_concept.html#an-open-source-supernode-for-web3-apps", "relUrl": "/overview/supernode_concept.html#an-open-source-supernode-for-web3-apps" - },"773": { + },"777": { "doc": "pages.introduction", "title": "pages.introduction", "content": " ", "url": "/firefly/head/overview/supernode_concept.html", "relUrl": "/overview/supernode_concept.html" - },"774": { + },"778": { "doc": "pages.api_spec", "title": "API Spec", "content": "This is the FireFly OpenAPI Specification document generated by FireFly . Note: The ‘Try it out’ buttons will not work on this page because it’s not running against a live version of FireFly. To actually try it out, we recommend using the FireFly CLI to start an instance on your local machine (which will start the FireFly core on port 5000 by default) and then open the Swagger UI associated with your local node by opening a new tab and visiting http://localhost:5000/api . | ", "url": "/firefly/head/swagger/swagger.html#api-spec", "relUrl": "/swagger/swagger.html#api-spec" - },"775": { + },"779": { "doc": "pages.api_spec", "title": "pages.api_spec", "content": " ", "url": "/firefly/head/swagger/swagger.html", "relUrl": "/swagger/swagger.html" - },"776": { + },"780": { "doc": "Tezos", "title": "Work with Tezos smart contracts", "content": "This guide describes the steps to deploy a smart contract to a Tezos blockchain and use FireFly to interact with it in order to submit transactions, query for states and listening for events. ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#work-with-tezos-smart-contracts", "relUrl": "/tutorials/custom_contracts/tezos.html#work-with-tezos-smart-contracts" - },"777": { + },"781": { "doc": "Tezos", "title": "Table of contents", "content": ". | Work with Tezos smart contracts . | Smart Contract Languages | Example smart contract | Contract deployment via SmartPy IDE | Contract deployment via HTTP API | The FireFly Interface Format . | Schema details . | Supported Tezos types | Internal type vs Internal schema | Options | . | FA2 example | . | Broadcast the contract interface . | Request | Response | . | Create an HTTP API for the contract . | Request | Response | . | View OpenAPI spec for the contract | Invoke the smart contract . | Request | Response | . | Query the current value . | Request | Response | . | . | . ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#table-of-contents", "relUrl": "/tutorials/custom_contracts/tezos.html#table-of-contents" - },"778": { + },"782": { "doc": "Tezos", "title": "Smart Contract Languages", "content": "Smart contracts on Tezos can be programmed using familiar, developer-friendly languages. All features available on Tezos can be written in any of the high-level languages used to write smart contracts, such as Archetype, LIGO, and SmartPy. These languages all compile down to Michelson and you can switch between languages based on your preferences and projects. NOTE: For this tutorial we are going to use SmartPy for building Tezos smart contracts utilizing the broadly adopted Python language. ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#smart-contract-languages", "relUrl": "/tutorials/custom_contracts/tezos.html#smart-contract-languages" - },"779": { + },"783": { "doc": "Tezos", "title": "Example smart contract", "content": "First let’s look at a simple contract smart contract called SimpleStorage, which we will be using on a Tezos blockchain. Here we have one state variable called ‘storedValue’ and initialized with the value 12. During initialization the type of the variable was defined as ‘int’. You can see more at SmartPy types. And then we added a simple test, which set the storage value to 15 and checks that the value was changed as expected. NOTE: Smart contract’s tests (marked with @sp.add_test annotation) are used to verify the validity of contract entrypoints and do not affect the state of the contract during deployment. Here is the source for this contract: . import smartpy as sp @sp.module def main(): # Declares a new contract class SimpleStorage(sp.Contract): # Storage. Persists in between transactions def __init__(self, value): self.data.x = value # Allows the stored integer to be changed @sp.entrypoint def set(self, params): self.data.x = params.value # Returns the currently stored integer @sp.onchain_view() def get(self): return self.data.x @sp.add_test() def test(): # Create a test scenario scenario = sp.test_scenario(\"Test simple storage\", main) scenario.h1(\"SimpleStorage\") # Initialize the contract c = main.SimpleStorage(12) # Run some test cases scenario += c c.set(value=15) scenario.verify(c.data.x == 15) scenario.verify(scenario.compute(c.get()) == 15) . ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#example-smart-contract", "relUrl": "/tutorials/custom_contracts/tezos.html#example-smart-contract" - },"780": { + },"784": { "doc": "Tezos", "title": "Contract deployment via SmartPy IDE", "content": "To deploy the contract, we will use SmartPy IDE. | Open an IDE; | Paste the contract code; | Click “Run code” button; | Then you will see “Show Michelson” button, click on that; | On the opened pop-up click button “Deploy Contract”; | Choose the Ghostnet network; | Select an account, which you’re going to use to deploy the contract; | Click “Estimate Cost From RPC” button; | Click “Deploy Contract” button; | . Here we can see that our new contract address is KT1ED4gj2xZnp8318yxa5NpvyvW15pqe4yFg. This is the address that we will reference in the rest of this guide. ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#contract-deployment-via-smartpy-ide", "relUrl": "/tutorials/custom_contracts/tezos.html#contract-deployment-via-smartpy-ide" - },"781": { + },"785": { "doc": "Tezos", "title": "Contract deployment via HTTP API", "content": "To deploy the contract we can use HTTP API: POST http://localhost:5000/api/v1/namespaces/default/contracts/deploy . { \"contract\": { \"code\": [ { \"prim\": \"storage\", \"args\": [ { \"prim\": \"int\" } ] }, { \"prim\": \"parameter\", \"args\": [ { \"prim\": \"int\", \"annots\": [ \"%set\" ] } ] }, { \"prim\": \"code\", \"args\": [ [ { \"prim\": \"CAR\" }, { \"prim\": \"NIL\", \"args\": [ { \"prim\": \"operation\" } ] }, { \"prim\": \"PAIR\" } ] ] }, { \"prim\": \"view\", \"args\": [ { \"string\": \"get\" }, { \"prim\": \"unit\" }, { \"prim\": \"int\" }, [ { \"prim\": \"CDR\" } ] ] } ], \"storage\": { \"int\": \"12\" } } } . The contract field has two fields - code with Michelson code of contract and storage with initial Storage values. The response of request above: . { \"id\": \"0c3810c7-baed-4077-9d2c-af316a4a567f\", \"namespace\": \"default\", \"tx\": \"21d03e6d-d106-48f4-aacd-688bf17b71fd\", \"type\": \"blockchain_deploy\", \"status\": \"Pending\", \"plugin\": \"tezos\", \"input\": { \"contract\": { \"code\": [ { \"args\": [ { \"prim\": \"int\" } ], \"prim\": \"storage\" }, { \"args\": [ { \"annots\": [ \"%set\" ], \"prim\": \"int\" } ], \"prim\": \"parameter\" }, { \"args\": [ [ { \"prim\": \"CAR\" }, { \"args\": [ { \"prim\": \"operation\" } ], \"prim\": \"NIL\" }, { \"prim\": \"PAIR\" } ] ], \"prim\": \"code\" }, { \"args\": [ { \"string\": \"get\" }, { \"prim\": \"unit\" }, { \"prim\": \"int\" }, [ { \"prim\": \"CDR\" } ] ], \"prim\": \"view\" } ], \"storage\": { \"int\": \"12\" } }, \"definition\": null, \"input\": null, \"key\": \"tz1V3spuktTP2wuEZP7D2hJruLZ5uJTuJk31\", \"options\": null }, \"created\": \"2024-04-01T14:20:20.665039Z\", \"updated\": \"2024-04-01T14:20:20.665039Z\" } . The success result of deploy can be checked by GET http://localhost:5000/api/v1/namespaces/default/operations/0c3810c7-baed-4077-9d2c-af316a4a567f where 0c3810c7-baed-4077-9d2c-af316a4a567f is operation id from response above. The success response: . { \"id\": \"0c3810c7-baed-4077-9d2c-af316a4a567f\", \"namespace\": \"default\", \"tx\": \"21d03e6d-d106-48f4-aacd-688bf17b71fd\", \"type\": \"blockchain_deploy\", \"status\": \"Succeeded\", \"plugin\": \"tezos\", \"input\": { \"contract\": { \"code\": [ { \"args\": [ { \"prim\": \"int\" } ], \"prim\": \"storage\" }, { \"args\": [ { \"annots\": [ \"%set\" ], \"prim\": \"int\" } ], \"prim\": \"parameter\" }, { \"args\": [ [ { \"prim\": \"CAR\" }, { \"args\": [ { \"prim\": \"operation\" } ], \"prim\": \"NIL\" }, { \"prim\": \"PAIR\" } ] ], \"prim\": \"code\" }, { \"args\": [ { \"string\": \"get\" }, { \"prim\": \"unit\" }, { \"prim\": \"int\" }, [ { \"prim\": \"CDR\" } ] ], \"prim\": \"view\" } ], \"storage\": { \"int\": \"12\" } }, \"definition\": null, \"input\": null, \"key\": \"tz1V3spuktTP2wuEZP7D2hJruLZ5uJTuJk31\", \"options\": null }, \"output\": { \"headers\": { \"requestId\": \"default:0c3810c7-baed-4077-9d2c-af316a4a567f\", \"type\": \"TransactionSuccess\" }, \"protocolId\": \"ProxfordYmVfjWnRcgjWH36fW6PArwqykTFzotUxRs6gmTcZDuH\", \"transactionHash\": \"ootDut4xxR2yeYz6JuySuyTVZnXgda2t8SYrk3iuJpm531TZuCj\" }, \"created\": \"2024-04-01T14:20:20.665039Z\", \"updated\": \"2024-04-01T14:20:20.665039Z\", \"detail\": { \"created\": \"2024-04-01T14:20:21.928976Z\", \"firstSubmit\": \"2024-04-01T14:20:22.714493Z\", \"from\": \"tz1V3spuktTP2wuEZP7D2hJruLZ5uJTuJk31\", \"gasPrice\": \"0\", \"historySummary\": [ { \"count\": 1, \"firstOccurrence\": \"2024-04-01T14:20:21.930764Z\", \"lastOccurrence\": \"2024-04-01T14:20:21.930765Z\", \"subStatus\": \"Received\" }, { \"action\": \"AssignNonce\", \"count\": 2, \"firstOccurrence\": \"2024-04-01T14:20:21.930767Z\", \"lastOccurrence\": \"2024-04-01T14:20:22.714772Z\" }, { \"action\": \"RetrieveGasPrice\", \"count\": 1, \"firstOccurrence\": \"2024-04-01T14:20:22.714774Z\", \"lastOccurrence\": \"2024-04-01T14:20:22.714774Z\" }, { \"action\": \"SubmitTransaction\", \"count\": 1, \"firstOccurrence\": \"2024-04-01T14:20:22.715269Z\", \"lastOccurrence\": \"2024-04-01T14:20:22.715269Z\" }, { \"action\": \"ReceiveReceipt\", \"count\": 1, \"firstOccurrence\": \"2024-04-01T14:20:29.244396Z\", \"lastOccurrence\": \"2024-04-01T14:20:29.244396Z\" }, { \"action\": \"Confirm\", \"count\": 1, \"firstOccurrence\": \"2024-04-01T14:20:29.244762Z\", \"lastOccurrence\": \"2024-04-01T14:20:29.244762Z\" } ], \"id\": \"default:0c3810c7-baed-4077-9d2c-af316a4a567f\", \"lastSubmit\": \"2024-04-01T14:20:22.714493Z\", \"nonce\": \"23094946\", \"policyInfo\": {}, \"receipt\": { \"blockHash\": \"BLvWL4t8GbaufGcQwiv3hHCsvgD6qwXfAXofyvojSMoFeGMXMR1\", \"blockNumber\": \"5868268\", \"contractLocation\": { \"address\": \"KT1CkTPsgTUQxR3CCpvtrcuQFV5Jf7cJgHFg\" }, \"extraInfo\": [ { \"consumedGas\": \"584\", \"contractAddress\": \"KT1CkTPsgTUQxR3CCpvtrcuQFV5Jf7cJgHFg\", \"counter\": null, \"errorMessage\": null, \"fee\": null, \"from\": null, \"gasLimit\": null, \"paidStorageSizeDiff\": \"75\", \"status\": \"applied\", \"storage\": null, \"storageLimit\": null, \"storageSize\": \"75\", \"to\": null } ], \"protocolId\": \"ProxfordYmVfjWnRcgjWH36fW6PArwqykTFzotUxRs6gmTcZDuH\", \"success\": true, \"transactionIndex\": \"0\" }, \"sequenceId\": \"018e9a08-582a-01ec-9209-9d79ef742c9b\", \"status\": \"Succeeded\", \"transactionData\": \"c37274b662d68da8fdae2a02ad6c460a79933c70c6fa7500dc98a9ade6822f026d00673bb6e6298063f97940953de23d441ab20bf757f602a3cd810bad05b003000000000041020000003c0500045b00000004257365740501035b050202000000080316053d036d03420991000000130100000003676574036c035b020000000203170000000000000002000c\", \"transactionHash\": \"ootDut4xxR2yeYz6JuySuyTVZnXgda2t8SYrk3iuJpm531TZuCj\", \"transactionHeaders\": { \"from\": \"tz1V3spuktTP2wuEZP7D2hJruLZ5uJTuJk31\", \"nonce\": \"23094946\" }, \"updated\": \"2024-04-01T14:20:29.245172Z\" } } . ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#contract-deployment-via-http-api", "relUrl": "/tutorials/custom_contracts/tezos.html#contract-deployment-via-http-api" - },"782": { + },"786": { "doc": "Tezos", "title": "The FireFly Interface Format", "content": "As we know from the previous section - smart contracts on the Tezos blockchain are using the domain-specific, stack-based programming language called Michelson. It is a key component of the Tezos platform and plays a fundamental role in defining the behavior of smart contracts and facilitating their execution. This language is very efficient but also a bit tricky and challenging for learning, so in order to teach FireFly how to interact with the smart contract, we will be using FireFly Interface (FFI) to define the contract inteface which later will be encoded to Michelson. Schema details . The details field is used to encapsulate blockchain specific type information about a specific field. (More details at schema details) . Supported Tezos types . | nat | integer | string | address | bytes | boolean | variant | list | struct | map | . Internal type vs Internal schema . internalType is a field which is used to describe tezos primitive types . { \"details\": { \"type\": \"address\", \"internalType\": \"address\" } } . internalSchema in turn is used to describe more complex tezos types as list, struct or variant . Struct example: . { \"details\": { \"type\": \"schema\", \"internalSchema\": { \"type\": \"struct\", \"args\": [ { \"name\": \"metadata\", \"type\": \"bytes\" }, { \"name\": \"token_id\", \"type\": \"nat\" } ] } } } . List example: . { \"details\": { \"type\": \"schema\", \"internalSchema\": { \"type\": \"struct\", \"args\": [ { \"name\": \"metadata\", \"type\": \"bytes\" }, { \"name\": \"token_id\", \"type\": \"nat\" } ] } } } . Variant example: . { \"details\": { \"type\": \"schema\", \"internalSchema\": { \"type\": \"variant\", \"variants\": [ \"add_operator\", \"remove_operator\" ], \"args\": [ { \"type\": \"struct\", \"args\": [ { \"name\": \"owner\", \"type\": \"address\" }, { \"name\": \"operator\", \"type\": \"address\" }, { \"name\": \"token_id\", \"type\": \"nat\" } ] } ] } } } . Map example: . { \"details\": { \"type\": \"schema\", \"internalSchema\": { \"type\": \"map\", \"args\": [ { \"name\": \"key\", \"type\": \"integer\" }, { \"name\": \"value\", \"type\": \"string\" } ] } } } . Options . Option type is used to indicate a value as optional (see more at smartpy options) . { \"details\": { \"type\": \"string\", \"internalType\": \"string\", \"kind\": \"option\" } } . FA2 example . The following FFI sample demonstrates the specification for the widely used FA2 (analogue of ERC721 for EVM) smart contract: . { \"namespace\": \"default\", \"name\": \"fa2\", \"version\": \"v1.0.0\", \"description\": \"\", \"methods\": [ { \"name\": \"burn\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"token_ids\", \"schema\": { \"type\": \"array\", \"details\": { \"type\": \"nat\", \"internalType\": \"nat\" } } } ], \"returns\": [] }, { \"name\": \"destroy\", \"pathname\": \"\", \"description\": \"\", \"params\": [], \"returns\": [] }, { \"name\": \"mint\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"owner\", \"schema\": { \"type\": \"string\", \"details\": { \"type\": \"address\", \"internalType\": \"address\" } } }, { \"name\": \"requests\", \"schema\": { \"type\": \"array\", \"details\": { \"type\": \"schema\", \"internalSchema\": { \"type\": \"struct\", \"args\": [ { \"name\": \"metadata\", \"type\": \"bytes\" }, { \"name\": \"token_id\", \"type\": \"nat\" } ] } } } } ], \"returns\": [] }, { \"name\": \"pause\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"pause\", \"schema\": { \"type\": \"boolean\", \"details\": { \"type\": \"boolean\", \"internalType\": \"boolean\" } } } ], \"returns\": [] }, { \"name\": \"select\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"batch\", \"schema\": { \"type\": \"array\", \"details\": { \"type\": \"schema\", \"internalSchema\": { \"type\": \"struct\", \"args\": [ { \"name\": \"token_id\", \"type\": \"nat\" }, { \"name\": \"recipient\", \"type\": \"address\" }, { \"name\": \"token_id_start\", \"type\": \"nat\" }, { \"name\": \"token_id_end\", \"type\": \"nat\" } ] } } } } ], \"returns\": [] }, { \"name\": \"transfer\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"batch\", \"schema\": { \"type\": \"array\", \"details\": { \"type\": \"schema\", \"internalSchema\": { \"type\": \"struct\", \"args\": [ { \"name\": \"from_\", \"type\": \"address\" }, { \"name\": \"txs\", \"type\": \"list\", \"args\": [ { \"type\": \"struct\", \"args\": [ { \"name\": \"to_\", \"type\": \"address\" }, { \"name\": \"token_id\", \"type\": \"nat\" }, { \"name\": \"amount\", \"type\": \"nat\" } ] } ] } ] } } } } ], \"returns\": [] }, { \"name\": \"update_admin\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"admin\", \"schema\": { \"type\": \"string\", \"details\": { \"type\": \"address\", \"internalType\": \"address\" } } } ], \"returns\": [] }, { \"name\": \"update_operators\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"requests\", \"schema\": { \"type\": \"array\", \"details\": { \"type\": \"schema\", \"internalSchema\": { \"type\": \"variant\", \"variants\": [ \"add_operator\", \"remove_operator\" ], \"args\": [ { \"type\": \"struct\", \"args\": [ { \"name\": \"owner\", \"type\": \"address\" }, { \"name\": \"operator\", \"type\": \"address\" }, { \"name\": \"token_id\", \"type\": \"nat\" } ] } ] } } } } ], \"returns\": [] } ], \"events\": [] } . ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#the-firefly-interface-format", "relUrl": "/tutorials/custom_contracts/tezos.html#the-firefly-interface-format" - },"783": { + },"787": { "doc": "Tezos", "title": "Broadcast the contract interface", "content": "Now that we have a FireFly Interface representation of our smart contract, we want to broadcast that to the entire network. This broadcast will be pinned to the blockchain, so we can always refer to this specific name and version, and everyone in the network will know exactly which contract interface we are talking about. We will use the FFI JSON constructed above and POST that to the /contracts/interfaces API endpoint. Request . POST http://localhost:5000/api/v1/namespaces/default/contracts/interfaces . { \"namespace\": \"default\", \"name\": \"simplestorage\", \"version\": \"v1.0.0\", \"description\": \"\", \"methods\": [ { \"name\": \"set\", \"pathname\": \"\", \"description\": \"\", \"params\": [ { \"name\": \"newValue\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"integer\", \"internalType\": \"integer\" } } } ], \"returns\": [] }, { \"name\": \"get\", \"pathname\": \"\", \"description\": \"\", \"params\": [], \"returns\": [] } ], \"events\": [] } . Response . { \"id\": \"f9e34787-e634-46cd-af47-b52c537404ff\", \"namespace\": \"default\", \"name\": \"simplestorage\", \"description\": \"\", \"version\": \"v1.0.0\", \"methods\": [ { \"id\": \"78f13a7f-7b85-47c3-bf51-346a9858c027\", \"interface\": \"f9e34787-e634-46cd-af47-b52c537404ff\", \"name\": \"set\", \"namespace\": \"default\", \"pathname\": \"set\", \"description\": \"\", \"params\": [ { \"name\": \"newValue\", \"schema\": { \"type\": \"integer\", \"details\": { \"type\": \"integer\", \"internalType\": \"integer\" } } } ], \"returns\": [] }, { \"id\": \"ee864e25-c3f7-42d3-aefd-a82f753e9002\", \"interface\": \"f9e34787-e634-46cd-af47-b52c537404ff\", \"name\": \"get\", \"namespace\": \"tezos\", \"pathname\": \"get\", \"description\": \"\", \"params\": [], \"returns\": [] } ] } . NOTE: We can broadcast this contract interface conveniently with the help of FireFly Sandbox running at http://127.0.0.1:5108 . | Go to the Contracts Section | Click on Define a Contract Interface | Select FFI - FireFly Interface in the Interface Fromat dropdown | Copy the FFI JSON crafted by you into the Schema Field | Click on Run | . ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#broadcast-the-contract-interface", "relUrl": "/tutorials/custom_contracts/tezos.html#broadcast-the-contract-interface" - },"784": { + },"788": { "doc": "Tezos", "title": "Create an HTTP API for the contract", "content": "Now comes the fun part where we see some of the powerful, developer-friendly features of FireFly. The next thing we’re going to do is tell FireFly to build an HTTP API for this smart contract, complete with an OpenAPI Specification and Swagger UI. As part of this, we’ll also tell FireFly where the contract is on the blockchain. Like the interface broadcast above, this will also generate a broadcast which will be pinned to the blockchain so all the members of the network will be aware of and able to interact with this API. We need to copy the id field we got in the response from the previous step to the interface.id field in the request body below. We will also pick a name that will be part of the URL for our HTTP API, so be sure to pick a name that is URL friendly. In this case we’ll call it simple-storage. Lastly, in the location.address field, we’re telling FireFly where an instance of the contract is deployed on-chain. NOTE: The location field is optional here, but if it is omitted, it will be required in every request to invoke or query the contract. This can be useful if you have multiple instances of the same contract deployed to different addresses. Request . POST http://localhost:5000/api/v1/namespaces/default/apis . { \"name\": \"simple-storage\", \"interface\": { \"id\": \"f9e34787-e634-46cd-af47-b52c537404ff\" }, \"location\": { \"address\": \"KT1ED4gj2xZnp8318yxa5NpvyvW15pqe4yFg\" } } . Response . { \"id\": \"af09de97-741d-4f61-8d30-4db5e7460f76\", \"namespace\": \"default\", \"interface\": { \"id\": \"f9e34787-e634-46cd-af47-b52c537404ff\" }, \"location\": { \"address\": \"KT1ED4gj2xZnp8318yxa5NpvyvW15pqe4yFg\" }, \"name\": \"simple-storage\", \"urls\": { \"openapi\": \"http://127.0.0.1:5000/api/v1/namespaces/default/apis/simple-storage/api/swagger.json\", \"ui\": \"http://127.0.0.1:5000/api/v1/namespaces/default/apis/simple-storage/api\" } } . ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#create-an-http-api-for-the-contract", "relUrl": "/tutorials/custom_contracts/tezos.html#create-an-http-api-for-the-contract" - },"785": { + },"789": { "doc": "Tezos", "title": "View OpenAPI spec for the contract", "content": "You’ll notice in the response body that there are a couple of URLs near the bottom. If you navigate to the one labeled ui in your browser, you should see the Swagger UI for your smart contract. ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#view-openapi-spec-for-the-contract", "relUrl": "/tutorials/custom_contracts/tezos.html#view-openapi-spec-for-the-contract" - },"786": { + },"790": { "doc": "Tezos", "title": "Invoke the smart contract", "content": "Now that we’ve got everything set up, it’s time to use our smart contract! We’re going to make a POST request to the invoke/set endpoint to set the integer value on-chain. Let’s set it to the value of 3 right now. Request . POST http://localhost:5000/api/v1/namespaces/default/apis/simple-storage/invoke/set . { \"input\": { \"newValue\": 3 } } . Response . { \"id\": \"87c7ee1b-33d1-46e2-b3f5-8566c14367cf\", \"type\": \"blockchain_invoke\", \"status\": \"Pending\", \"...\" } . You’ll notice that we got an ID back with status Pending, and that’s expected due to the asynchronous programming model of working with smart contracts in FireFly. To see what the value is now, we can query the smart contract. ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#invoke-the-smart-contract", "relUrl": "/tutorials/custom_contracts/tezos.html#invoke-the-smart-contract" - },"787": { + },"791": { "doc": "Tezos", "title": "Query the current value", "content": "To make a read-only request to the blockchain to check the current value of the stored integer, we can make a POST to the query/get endpoint. Request . POST http://localhost:5000/api/v1/namespaces/default/apis/simple-storage/query/get . {} . Response . { \"3\" } . NOTE: Some contracts may have queries that require input parameters. That’s why the query endpoint is a POST, rather than a GET so that parameters can be passed as JSON in the request body. This particular function does not have any parameters, so we just pass an empty JSON object. ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html#query-the-current-value", "relUrl": "/tutorials/custom_contracts/tezos.html#query-the-current-value" - },"788": { + },"792": { "doc": "Tezos", "title": "Tezos", "content": " ", "url": "/firefly/head/tutorials/custom_contracts/tezos.html", "relUrl": "/tutorials/custom_contracts/tezos.html" - },"789": { + },"793": { "doc": "pages.tezos_testnet", "title": "Tezos Testnet", "content": ". | Previous steps: Install the FireFly CLI | Set up the transaction signing service | Creating a new stack | Start the stack | Get some XTZ . | Confirm the transaction on TzStats | . | Use the public testnet | . This guide will walk you through the steps to create a local FireFly development environment and connect it to the public Tezos Ghostnet testnet. ", "url": "/firefly/head/tutorials/chains/tezos_testnet.html#tezos-testnet", "relUrl": "/tutorials/chains/tezos_testnet.html#tezos-testnet" - },"790": { + },"794": { "doc": "pages.tezos_testnet", "title": "Previous steps: Install the FireFly CLI", "content": "If you haven’t set up the FireFly CLI already, please go back to the Getting Started guide and read the section on how to Install the FireFly CLI. ← ① Install the FireFly CLI . ", "url": "/firefly/head/tutorials/chains/tezos_testnet.html#previous-steps-install-the-firefly-cli", "relUrl": "/tutorials/chains/tezos_testnet.html#previous-steps-install-the-firefly-cli" - },"791": { + },"795": { "doc": "pages.tezos_testnet", "title": "Set up the transaction signing service ", "content": "Signatory service allows to work with many different key-management systems. By default, FF uses local signing option. However, it is also possible to configure the transaction signing service using key management systems such as: AWS/Google/Azure KMS, HCP Vault, etc. NOTE: The default option is not secure and is mainly used for development and demo purposes. Therefore, for the production, use the selected KMS. The full list can be found here. ", "url": "/firefly/head/tutorials/chains/tezos_testnet.html#set-up-the-transaction-signing-service-", "relUrl": "/tutorials/chains/tezos_testnet.html#set-up-the-transaction-signing-service-" - },"792": { + },"796": { "doc": "pages.tezos_testnet", "title": "Creating a new stack", "content": "To create a local FireFly development stack and connect it to the Tezos Ghostnet testnet, we will use command line flags to customize the following settings: . | Create a new Tezos based stack named tezos with 1 member | Disable multiparty mode. We are going to be using this FireFly node as a Web3 gateway, and we don’t need to communicate with a consortium here | See the list of Tezos public RPC nodes and select an HTTPS RPC node. | . To do this, run the following command: . ff init tezos dev 1 \\ --multiparty=false \\ --remote-node-url <selected RPC endpoint> . NOTE: The public RPC nodes may have limitations or may not support all FF required RPC endpoints. Therefore it’s not recommended to use ones for production and you may need to run own node or use third-party vendors. ", "url": "/firefly/head/tutorials/chains/tezos_testnet.html#creating-a-new-stack", "relUrl": "/tutorials/chains/tezos_testnet.html#creating-a-new-stack" - },"793": { + },"797": { "doc": "pages.tezos_testnet", "title": "Start the stack", "content": "Now you should be able to start your stack by running: . ff start dev . After some time it should print out the following: . Web UI for member '0': http://127.0.0.1:5000/ui Sandbox UI for member '0': http://127.0.0.1:5109 To see logs for your stack run: ff logs dev . ", "url": "/firefly/head/tutorials/chains/tezos_testnet.html#start-the-stack", "relUrl": "/tutorials/chains/tezos_testnet.html#start-the-stack" - },"794": { + },"798": { "doc": "pages.tezos_testnet", "title": "Get some XTZ", "content": "At this point you should have a working FireFly stack, talking to a public chain. However, you won’t be able to run any transactions just yet, because you don’t have any way to pay transaction fee. A testnet faucet can give us some XTZ, the native token for Tezos. First, you need to get an account address, which was created during signer set up step. To check that, you can run: . ff accounts list dev [ { \"address\": \"tz1cuFw1E2Mn2bVS8q8d7QoCb6FXC18JivSp\", \"privateKey\": \"...\" } ] . After that, go to Tezos Ghostnet Faucet and paste the address in the form and click the Request button. Confirm the transaction on TzStats . You should be able to go lookup your account on TzStats for the Ghostnet testnet and see that you now have a balance of 100 XTZ (or 2001 XTZ accordingly). Simply paste in your account address to search for it. On the Transfers tab from you account page you will see the actual transfer of the XTZ from the faucet. ", "url": "/firefly/head/tutorials/chains/tezos_testnet.html#get-some-xtz", "relUrl": "/tutorials/chains/tezos_testnet.html#get-some-xtz" - },"795": { + },"799": { "doc": "pages.tezos_testnet", "title": "Use the public testnet", "content": "Now that you have everything set up, you can follow one of the other FireFly guides such as Custom Smart Contracts. For detailed instructions on deploying a custom smart contract to Tezos, please see the Tezos docs for instructions using various tools. ", "url": "/firefly/head/tutorials/chains/tezos_testnet.html#use-the-public-testnet", "relUrl": "/tutorials/chains/tezos_testnet.html#use-the-public-testnet" - },"796": { + },"800": { "doc": "pages.tezos_testnet", "title": "pages.tezos_testnet", "content": " ", "url": "/firefly/head/tutorials/chains/tezos_testnet.html", "relUrl": "/tutorials/chains/tezos_testnet.html" - },"797": { + },"801": { "doc": "pages.tls", "title": "TLS", "content": " ", "url": "/firefly/head/reference/tls.html#tls", "relUrl": "/reference/tls.html#tls" - },"798": { + },"802": { "doc": "pages.tls", "title": "Table of contents", "content": ". | TLS Overview | Configuring TLS for the API server | Configuring TLS for the webhooks | Configuring clients and websockets | Enhancing validation of certificates | . ", "url": "/firefly/head/reference/tls.html#table-of-contents", "relUrl": "/reference/tls.html#table-of-contents" - },"799": { + },"803": { "doc": "pages.tls", "title": "TLS Overview", "content": "To enable TLS in Firefly, there is a configuration available to provide certificates and keys. The common configuration is as such: . tls: enabled: true/false # Toggle on or off TLS caFile: <path to the CA file you want the client or server to trust> certFile: <path to the cert file you want the client or server to use when performing authentication in mTLS> keyFile: <path to the priavte key file you want the client or server to use when performing authentication in mTLS> clientAuth: true/false # Only applicable to the server side, to toggle on or off client authentication requiredDNAttributes: A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes) . NOTE The CAs, certificates and keys have to be in PEM format. ", "url": "/firefly/head/reference/tls.html#tls-overview", "relUrl": "/reference/tls.html#tls-overview" - },"800": { + },"804": { "doc": "pages.tls", "title": "Configuring TLS for the API server", "content": "Using the above configuration, we can place it under the http config and enable TLS or mTLS for any API call. See this config section for details . ", "url": "/firefly/head/reference/tls.html#configuring-tls-for-the-api-server", "relUrl": "/reference/tls.html#configuring-tls-for-the-api-server" - },"801": { + },"805": { "doc": "pages.tls", "title": "Configuring TLS for the webhooks", "content": "Using the above configuration, we can place it under the events.webhooks config and enable TLS or mTLS for any webhook call. See this config section for details . ", "url": "/firefly/head/reference/tls.html#configuring-tls-for-the-webhooks", "relUrl": "/reference/tls.html#configuring-tls-for-the-webhooks" - },"802": { + },"806": { "doc": "pages.tls", "title": "Configuring clients and websockets", "content": "Firefly has a set of HTTP clients and websockets that communicate the external endpoints and services that could be secured using TLS. In order to configure these clients, we can use the same configuration as above in the respective places in the config which relate to those clients. For example, if you wish to configure the ethereum blockchain connector with TLS you would look at this config section . For more clients, search in the configuration reference for a TLS section. ", "url": "/firefly/head/reference/tls.html#configuring-clients-and-websockets", "relUrl": "/reference/tls.html#configuring-clients-and-websockets" - },"803": { + },"807": { "doc": "pages.tls", "title": "Enhancing validation of certificates", "content": "In the case where we want to verify that a specific client certificate has certain attributes we can use the requiredDNAtributes configuration as described above. This will allow you by the means of a regex expresssion matching against well known distinguished names (DN). To learn more about a DNs look at this document . ", "url": "/firefly/head/reference/tls.html#enhancing-validation-of-certificates", "relUrl": "/reference/tls.html#enhancing-validation-of-certificates" - },"804": { + },"808": { "doc": "pages.tls", "title": "pages.tls", "content": " ", "url": "/firefly/head/reference/tls.html", "relUrl": "/reference/tls.html" - },"805": { + },"809": { "doc": "TokenApproval", "title": "TokenApproval", "content": " ", "url": "/firefly/head/reference/types/tokenapproval.html", "relUrl": "/reference/types/tokenapproval.html" - },"806": { + },"810": { "doc": "TokenApproval", "title": "Table of contents", "content": ". | TokenApproval . | Example | Field Descriptions | . | TransactionRef | . ", "url": "/firefly/head/reference/types/tokenapproval.html#table-of-contents", "relUrl": "/reference/types/tokenapproval.html#table-of-contents" - },"807": { + },"811": { "doc": "TokenApproval", "title": "TokenApproval", "content": "A token approval is a record that an address other than the owner of a token balance, has been granted authority to transfer tokens on the owners behalf. The approved “operator” (or “spender”) account might be a smart contract, or another individual. FireFly provides APIs for initiating and tracking approvals, which token connectors integrate with the implementation of the underlying token. The off-chain index maintained in FireFly for allowance allows you to quickly find the most recent allowance event associated with a pair of keys, using the subject field, combined with the active field. When a new Token Approval event is delivered to FireFly Core by the Token Connector, any previous approval for the same subject is marked \"active\": false, and the new approval is marked with \"active\": true . The token connector is responsible for the format of the subject field to reflect the owner / operator (spender) relationship. Example . { \"localId\": \"1cd3e2e2-dd6a-441d-94c5-02439de9897b\", \"pool\": \"1244ecbe-5862-41c3-99ec-4666a18b9dd5\", \"connector\": \"erc20_erc721\", \"key\": \"0x55860105d6a675dbe6e4d83f67b834377ba677ad\", \"operator\": \"0x30017fd084715e41aa6536ab777a8f3a2b11a5a1\", \"approved\": true, \"info\": { \"owner\": \"0x55860105d6a675dbe6e4d83f67b834377ba677ad\", \"spender\": \"0x30017fd084715e41aa6536ab777a8f3a2b11a5a1\", \"value\": \"115792089237316195423570985008687907853269984665640564039457584007913129639935\" }, \"namespace\": \"ns1\", \"protocolId\": \"000000000032/000000/000000\", \"subject\": \"0x55860105d6a675dbe6e4d83f67b834377ba677ad:0x30017fd084715e41aa6536ab777a8f3a2b11a5a1\", \"active\": true, \"created\": \"2022-05-16T01:23:15Z\", \"tx\": { \"type\": \"token_approval\", \"id\": \"4b6e086d-0e31-482d-9683-cd18b2045031\" } } . Field Descriptions . | Field Name | Description | Type | . | localId | The UUID of this token approval, in the local FireFly node | UUID | . | pool | The UUID the token pool this approval applies to | UUID | . | connector | The name of the token connector, as specified in the FireFly core configuration file. Required on input when there are more than one token connectors configured | string | . | key | The blockchain signing key for the approval request. On input defaults to the first signing key of the organization that operates the node | string | . | operator | The blockchain identity that is granted the approval | string | . | approved | Whether this record grants permission for an operator to perform actions on the token balance (true), or revokes permission (false) | bool | . | info | Token connector specific information about the approval operation, such as whether it applied to a limited balance of a fungible token. See your chosen token connector documentation for details | JSONObject | . | namespace | The namespace for the approval, which must match the namespace of the token pool | string | . | protocolId | An alphanumerically sortable string that represents this event uniquely with respect to the blockchain | string | . | subject | A string identifying the parties and entities in the scope of this approval, as provided by the token connector | string | . | active | Indicates if this approval is currently active (only one approval can be active per subject) | bool | . | message | The UUID of a message that has been correlated with this approval using the data field of the approval in a compatible token connector | UUID | . | messageHash | The hash of a message that has been correlated with this approval using the data field of the approval in a compatible token connector | Bytes32 | . | created | The creation time of the token approval | FFTime | . | tx | If submitted via FireFly, this will reference the UUID of the FireFly transaction (if the token connector in use supports attaching data) | TransactionRef | . | blockchainEvent | The UUID of the blockchain event | UUID | . | config | Input only field, with token connector specific configuration of the approval. See your chosen token connector documentation for details | JSONObject | . ", "url": "/firefly/head/reference/types/tokenapproval.html", "relUrl": "/reference/types/tokenapproval.html" - },"808": { + },"812": { "doc": "TokenApproval", "title": "TransactionRef", "content": "| Field Name | Description | Type | . | type | The type of the FireFly transaction | FFEnum: | . | id | The UUID of the FireFly transaction | UUID | . ", "url": "/firefly/head/reference/types/tokenapproval.html#transactionref", "relUrl": "/reference/types/tokenapproval.html#transactionref" - },"809": { + },"813": { "doc": "TokenPool", "title": "TokenPool", "content": " ", "url": "/firefly/head/reference/types/tokenpool.html", "relUrl": "/reference/types/tokenpool.html" - },"810": { + },"814": { "doc": "TokenPool", "title": "Table of contents", "content": ". | TokenPool . | Example token pool types | Example | Field Descriptions | . | TransactionRef | FFIReference | . ", "url": "/firefly/head/reference/types/tokenpool.html#table-of-contents", "relUrl": "/reference/types/tokenpool.html#table-of-contents" - },"811": { + },"815": { "doc": "TokenPool", "title": "TokenPool", "content": "Token pools are a FireFly construct for describing a set of tokens. The total supply of a particular fungible token, or a group of related non-fungible tokens. The exact definition of a token pool is dependent on the token connector implementation. Check the documentation for your chosen connector implementation to see the detailed options for configuring a new Token Pool. Note that it is very common to use a Token Pool to teach Hyperledger FireFly about an existing token, so that you can start interacting with a token that already exists. Example token pool types . Some examples of how the generic concept of a Token Pool maps to various well-defined Ethereum standards: . | ERC-1155: a single contract instance can efficiently allocate many isolated pools of fungible or non-fungible tokens | ERC-20 / ERC-777: each contract instance represents a single fungible pool of value, e.g. “a coin” | ERC-721: each contract instance represents a single pool of NFTs, each with unique identities within the pool | ERC-1400 / ERC-1410: partially supported in the same manner as ERC-20/ERC-777, but would require new features for working with partitions | . These are provided as examples only - a custom token connector could be backed by any token technology (Ethereum or otherwise) as long as it can support the basic operations described here (create pool, mint, burn, transfer). Other FireFly repos include a sample implementation of a token connector for ERC-20 and ERC-721 as well as ERC-1155. Example . { \"id\": \"90ebefdf-4230-48a5-9d07-c59751545859\", \"type\": \"fungible\", \"namespace\": \"ns1\", \"name\": \"my_token\", \"standard\": \"ERC-20\", \"locator\": \"address=0x056df1c53c3c00b0e13d37543f46930b42f71db0\\u0026schema=ERC20WithData\\u0026type=fungible\", \"decimals\": 18, \"connector\": \"erc20_erc721\", \"message\": \"43923040-b1e5-4164-aa20-47636c7177ee\", \"active\": true, \"created\": \"2022-05-16T01:23:15Z\", \"info\": { \"address\": \"0x056df1c53c3c00b0e13d37543f46930b42f71db0\", \"name\": \"pool8197\", \"schema\": \"ERC20WithData\" }, \"tx\": { \"type\": \"token_pool\", \"id\": \"a23ffc87-81a2-4cbc-97d6-f53d320c36cd\" }, \"published\": false } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the token pool | UUID | . | type | The type of token the pool contains, such as fungible/non-fungible | FFEnum:\"fungible\"\"nonfungible\" | . | namespace | The namespace for the token pool | string | . | name | The name of the token pool. Note the name is not validated against the description of the token on the blockchain | string | . | networkName | The published name of the token pool within the multiparty network | string | . | standard | The ERC standard the token pool conforms to, as reported by the token connector | string | . | locator | A unique identifier for the pool, as provided by the token connector | string | . | key | The signing key used to create the token pool. On input for token connectors that support on-chain deployment of new tokens (vs. only index existing ones) this determines the signing key used to create the token on-chain | string | . | symbol | The token symbol. If supplied on input for an existing on-chain token, this must match the on-chain information | string | . | decimals | Number of decimal places that this token has | int | . | connector | The name of the token connector, as specified in the FireFly core configuration file that is responsible for the token pool. Required on input when multiple token connectors are configured | string | . | message | The UUID of the broadcast message used to inform the network about this pool | UUID | . | active | Indicates whether the pool has been successfully activated with the token connector | bool | . | created | The creation time of the pool | FFTime | . | config | Input only field, with token connector specific configuration of the pool, such as an existing Ethereum address and block number to used to index the pool. See your chosen token connector documentation for details | JSONObject | . | info | Token connector specific information about the pool. See your chosen token connector documentation for details | JSONObject | . | tx | Reference to the FireFly transaction used to create and broadcast this pool to the network | TransactionRef | . | interface | A reference to an existing FFI, containing pre-registered type information for the token contract | FFIReference | . | interfaceFormat | The interface encoding format supported by the connector for this token pool | FFEnum:\"abi\"\"ffi\" | . | methods | The method definitions resolved by the token connector to be used by each token operation | JSONAny | . | published | Indicates if the token pool is published to other members of the multiparty network | bool | . ", "url": "/firefly/head/reference/types/tokenpool.html", "relUrl": "/reference/types/tokenpool.html" - },"812": { + },"816": { "doc": "TokenPool", "title": "TransactionRef", "content": "| Field Name | Description | Type | . | type | The type of the FireFly transaction | FFEnum: | . | id | The UUID of the FireFly transaction | UUID | . ", "url": "/firefly/head/reference/types/tokenpool.html#transactionref", "relUrl": "/reference/types/tokenpool.html#transactionref" - },"813": { + },"817": { "doc": "TokenPool", "title": "FFIReference", "content": "| Field Name | Description | Type | . | id | The UUID of the FireFly interface | UUID | . | name | The name of the FireFly interface | string | . | version | The version of the FireFly interface | string | . ", "url": "/firefly/head/reference/types/tokenpool.html#ffireference", "relUrl": "/reference/types/tokenpool.html#ffireference" - },"814": { + },"818": { "doc": "TokenTransfer", "title": "TokenTransfer", "content": " ", "url": "/firefly/head/reference/types/tokentransfer.html", "relUrl": "/reference/types/tokentransfer.html" - },"815": { + },"819": { "doc": "TokenTransfer", "title": "Table of contents", "content": ". | TokenTransfer . | FireFly initiated vs. non-FireFly initiated transfers | Message coordinated transfers | Transfer types | Example | Field Descriptions | . | TransactionRef | . ", "url": "/firefly/head/reference/types/tokentransfer.html#table-of-contents", "relUrl": "/reference/types/tokentransfer.html#table-of-contents" - },"816": { + },"820": { "doc": "TokenTransfer", "title": "TokenTransfer", "content": "A Token Transfer is created for each transfer of value that happens under a token pool. The transfers form an off-chain audit history (an “index”) of the transactions that have been performed on the blockchain. This historical information cannot be queried directly from the blockchain for most token implementations, because it is inefficient to use the blockchain to store complex data structures like this. So the blockchain simply emits events when state changes, and if you want to be able to query this historical information you need to track it in your own off-chain database. Hyperledger FireFly maintains this index automatically for all Token Pools that are configured. FireFly initiated vs. non-FireFly initiated transfers . There is no requirement at all to use FireFly to initiate transfers in Token Pools that Hyperledger FireFly is aware of. FireFly will listen to and update its audit history and balances for all transfers, regardless of whether they were initiated using a FireFly Supernode or not. So you could for example use Metamask to initiate a transfer directly against an ERC-20/ERC-721 contract directly on your blockchain, and you will see it appear as a transfer. Or initiate a transfer on-chain via another Smart Contract, such as a Hashed Timelock Contract (HTLC) releasing funds held in digital escrow. Message coordinated transfers . One special feature enabled when using FireFly to initiate transfers, is to coordinate an off-chain data transfer (private or broadcast) with the on-chain transfer of value. This is a powerful tool to allow transfers to have rich metadata associated that is too sensitive (or too large) to include on the blockchain itself. These transfers have a message associated with them, and require a compatible Token Connector and on-chain Smart Contract that allows a data payload to be included as part of the transfer, and to be emitted as part of the transfer event. Examples of how to do this are included in the ERC-20, ERC-721 and ERC-1155 Token Connector sample smart contracts. Transfer types . There are three primary types of transfer: . | Mint - new tokens come into existence, increasing the total supply of tokens within the pool. The from address will be unset for these transfer types. | Burn - existing tokens are taken out of circulation. The to address will be unset for these transfer types. | Transfer - tokens move from ownership by one account, to another account. The from and to addresses are both set for these type of transfers. | . Note that the key that signed the Transfer transaction might be different to the from account that is the owner of the tokens before the transfer. The Approval resource is used to track which signing accounts (other than the owner) have approval to transfer tokens on the owner’s behalf. Example . { \"type\": \"transfer\", \"pool\": \"1244ecbe-5862-41c3-99ec-4666a18b9dd5\", \"uri\": \"firefly://token/1\", \"connector\": \"erc20_erc721\", \"namespace\": \"ns1\", \"key\": \"0x55860105D6A675dBE6e4d83F67b834377Ba677AD\", \"from\": \"0x55860105D6A675dBE6e4d83F67b834377Ba677AD\", \"to\": \"0x55860105D6A675dBE6e4d83F67b834377Ba677AD\", \"amount\": \"1000000000000000000\", \"protocolId\": \"000000000041/000000/000000\", \"message\": \"780b9b90-e3b0-4510-afac-b4b1f2940b36\", \"messageHash\": \"780204e634364c42779920eddc8d9fecccb33e3607eeac9f53abd1b31184ae4e\", \"created\": \"2022-05-16T01:23:15Z\", \"tx\": { \"type\": \"token_transfer\", \"id\": \"62767ca8-99f9-439c-9deb-d80c6672c158\" }, \"blockchainEvent\": \"b57fcaa2-156e-4c3f-9b0b-ddec9ee25933\" } . Field Descriptions . | Field Name | Description | Type | . | type | The type of transfer such as mint/burn/transfer | FFEnum:\"mint\"\"burn\"\"transfer\" | . | localId | The UUID of this token transfer, in the local FireFly node | UUID | . | pool | The UUID the token pool this transfer applies to | UUID | . | tokenIndex | The index of the token within the pool that this transfer applies to | string | . | uri | The URI of the token this transfer applies to | string | . | connector | The name of the token connector, as specified in the FireFly core configuration file. Required on input when there are more than one token connectors configured | string | . | namespace | The namespace for the transfer, which must match the namespace of the token pool | string | . | key | The blockchain signing key for the transfer. On input defaults to the first signing key of the organization that operates the node | string | . | from | The source account for the transfer. On input defaults to the value of ‘key’ | string | . | to | The target account for the transfer. On input defaults to the value of ‘key’ | string | . | amount | The amount for the transfer. For non-fungible tokens will always be 1. For fungible tokens, the number of decimals for the token pool should be considered when inputting the amount. For example, with 18 decimals a fractional balance of 10.234 will be specified as 10,234,000,000,000,000,000 | FFBigInt | . | protocolId | An alphanumerically sortable string that represents this event uniquely with respect to the blockchain | string | . | message | The UUID of a message that has been correlated with this transfer using the data field of the transfer in a compatible token connector | UUID | . | messageHash | The hash of a message that has been correlated with this transfer using the data field of the transfer in a compatible token connector | Bytes32 | . | created | The creation time of the transfer | FFTime | . | tx | If submitted via FireFly, this will reference the UUID of the FireFly transaction (if the token connector in use supports attaching data) | TransactionRef | . | blockchainEvent | The UUID of the blockchain event | UUID | . | config | Input only field, with token connector specific configuration of the transfer. See your chosen token connector documentation for details | JSONObject | . ", "url": "/firefly/head/reference/types/tokentransfer.html", "relUrl": "/reference/types/tokentransfer.html" - },"817": { + },"821": { "doc": "TokenTransfer", "title": "TransactionRef", "content": "| Field Name | Description | Type | . | type | The type of the FireFly transaction | FFEnum: | . | id | The UUID of the FireFly transaction | UUID | . ", "url": "/firefly/head/reference/types/tokentransfer.html#transactionref", "relUrl": "/reference/types/tokentransfer.html#transactionref" - },"818": { + },"822": { "doc": "pages.tools", "title": "Tools", "content": ". ", "url": "/firefly/head/overview/key_components/tools.html#tools", "relUrl": "/overview/key_components/tools.html#tools" - },"819": { + },"823": { "doc": "pages.tools", "title": "FireFly CLI", "content": ". The FireFly CLI can be used to create local FireFly stacks for offline development of blockchain apps. This allows developers to rapidly iterate on their idea without needing to set up a bunch of infrastructure before they can write the first line of code. ", "url": "/firefly/head/overview/key_components/tools.html#firefly-cli", "relUrl": "/overview/key_components/tools.html#firefly-cli" - },"820": { + },"824": { "doc": "pages.tools", "title": "FireFly Sandbox", "content": ". The FireFly Sandbox sits logically outside the Supernode, and it acts like an “end-user” application written to use FireFly’s API. In your setup, you have one Sandbox per member, each talking to their own FireFly API. The purpose of the Sandbox is to provide a quick and easy way to try out all of the fundamental building blocks that FireFly provides. It also shows developers, through example code snippets, how they would implement the same functionality in their own app’s backend. 🗒 Technical details: The FireFly Sandbox is an example “full-stack” web app. It has a backend written in TypeScript / Node.js, and a frontend in TypeScript / React. When you click a button in your browser, the frontend makes a request to the backend, which then uses the FireFly Node.js SDK to make requests to FireFly’s API. ", "url": "/firefly/head/overview/key_components/tools.html#firefly-sandbox", "relUrl": "/overview/key_components/tools.html#firefly-sandbox" - },"821": { + },"825": { "doc": "pages.tools", "title": "FireFly Explorer", "content": "The FireFly explorer is a part of FireFly Core itself. It is a view into the system that allows operators to monitor the current state of the system and investigate specific transactions, messages, and events. It is also a great way for developers to see the results of running their code against FireFly’s API. ", "url": "/firefly/head/overview/key_components/tools.html#firefly-explorer", "relUrl": "/overview/key_components/tools.html#firefly-explorer" - },"822": { + },"826": { "doc": "pages.tools", "title": "pages.tools", "content": " ", "url": "/firefly/head/overview/key_components/tools.html", "relUrl": "/overview/key_components/tools.html" - },"823": { + },"827": { "doc": "Transaction", "title": "Transaction", "content": " ", "url": "/firefly/head/reference/types/transaction.html", "relUrl": "/reference/types/transaction.html" - },"824": { + },"828": { "doc": "Transaction", "title": "Table of contents", "content": ". | Transaction . | Example | Field Descriptions | . | . ", "url": "/firefly/head/reference/types/transaction.html#table-of-contents", "relUrl": "/reference/types/transaction.html#table-of-contents" - },"825": { + },"829": { "doc": "Transaction", "title": "Transaction", "content": "FireFly Transactions are a grouping construct for a number of Operations and Events that need to complete or fail as unit. FireFly Transactions are not themselves Blockchain transactions, but in many cases there is exactly one Blockchain transaction associated with each FireFly transaction. Exceptions include unpinned transactions, where there is no blockchain transaction at all. The Blockchain native transaction ID is stored in the FireFly transaction object when it is known. However, the FireFly transaction starts before a Blockchain transaction exists - because reliably submitting the blockchain transaction is one of the operations that is performed inside of the FireFly transaction. The below screenshot from the FireFly Explorer nicely illustrates how multiple operations and events are associated with a FireFly transaction. In this example, the transaction tracking is pinning of a batch of messages stored in IPFS to the blockchain. So there is a Blockchain ID for the transaction - as there is just one Blockchain transaction regardless of how many messages in the batch. There are operations for the submission of that transaction, and the upload of the data to IPFS. Then a corresponding Blockchain Event Received event for the detection of the event from the blockchain smart contract when the transaction was mined, and a Message Confirmed event for each message in the batch (in this case 1). Then here the message was a special Definition message that advertised a new Contract API to all members of the network - so there is a Contract API Confirmed event as well. Each FireFly transaction has a UUID. This UUID is propagated through to all participants in a FireFly transaction. For example in a Token Transfer that is coordinated with an off-chain private Message, the transaction ID is propagated to all parties who are part of that transaction. So the same UUID can be used to find the transaction in the FireFly Explorer of any member who has access to the message. This is possible because hash-pinned off-chain data is associated with that on-chain transfer. However, in the case of a raw ERC-20/ERC-721 transfer (without data), or any other raw Blockchain transaction, the FireFly transaction UUID cannot be propagated - so it will be local on the node that initiated the transaction. Example . { \"id\": \"4e7e0943-4230-4f67-89b6-181adf471edc\", \"namespace\": \"ns1\", \"type\": \"contract_invoke\", \"created\": \"2022-05-16T01:23:15Z\", \"blockchainIds\": [ \"0x34b0327567fefed09ac7b4429549bc609302b08a9cbd8f019a078ec44447593d\" ] } . Field Descriptions . | Field Name | Description | Type | . | id | The UUID of the FireFly transaction | UUID | . | namespace | The namespace of the FireFly transaction | string | . | type | The type of the FireFly transaction | FFEnum:\"none\"\"unpinned\"\"batch_pin\"\"network_action\"\"token_pool\"\"token_transfer\"\"contract_deploy\"\"contract_invoke\"\"contract_invoke_pin\"\"token_approval\"\"data_publish\" | . | created | The time the transaction was created on this node. Note the transaction is individually created with the same UUID on each participant in the FireFly transaction | FFTime | . | idempotencyKey | An optional unique identifier for a transaction. Cannot be duplicated within a namespace, thus allowing idempotent submission of transactions to the API | IdempotencyKey | . | blockchainIds | The blockchain transaction ID, in the format specific to the blockchain involved in the transaction. Not all FireFly transactions include a blockchain. FireFly transactions are extensible to support multiple blockchain transactions | string[] | . ", "url": "/firefly/head/reference/types/transaction.html", "relUrl": "/reference/types/transaction.html" - },"826": { + },"830": { "doc": "pages.usage_patterns", "title": "Usage Patterns", "content": " ", "url": "/firefly/head/overview/usage_patterns.html#usage-patterns", "relUrl": "/overview/usage_patterns.html#usage-patterns" - },"827": { + },"831": { "doc": "pages.usage_patterns", "title": "Table of contents", "content": ". | Web3 Gateway Mode | Multiparty Mode | . There are two modes of usage for Hyperledger Firefly: Web3 Gateway and Multiparty . A single runtime can operate in both of these modes, using different namespaces. ", "url": "/firefly/head/overview/usage_patterns.html#table-of-contents", "relUrl": "/overview/usage_patterns.html#table-of-contents" - },"828": { + },"832": { "doc": "pages.usage_patterns", "title": "Web3 Gateway Mode", "content": ". Web3 Gateway mode lets you interact with any Web3 application, regardless of whether Hyperledger FireFly is being used by other members of your business network. In this mode you can: . | Transfer tokenized value | Invoke any other type of smart contract | Index data from the blockchain | Reliably trigger events in your applications and back-office core systems | Manage decentralized data (NFTs etc.) | Use a private address book to manage signing identities and relationships | … and much more | . Learn more about Web3 Gateway Mode. ", "url": "/firefly/head/overview/usage_patterns.html#web3-gateway-mode", "relUrl": "/overview/usage_patterns.html#web3-gateway-mode" - },"829": { + },"833": { "doc": "pages.usage_patterns", "title": "Multiparty Mode", "content": "Multiparty mode is used to build multi-party systems, with a common application runtime deployed by each enterprise participant. This allows sophisticated applications to be built, that all use the pluggable APIs of Hyperledger FireFly to achieve end-to-end business value in an enterprise context. In this mode you can do everything you could do in Web3 Gateway mode, plus: . | Share and enforce common data formats | Exchange data privately, via an encrypted data bus . | Structured JSON data payloads | Large documents | . | Coordinate on-chain and off-chain data exchange . | Private data | Broadcast data | . | Mask on-chain activities using hashes | Use a shared address book to manage signing identities and relationships | … and much more | . Learn more about Multiparty Mode. ", "url": "/firefly/head/overview/usage_patterns.html#multiparty-mode", "relUrl": "/overview/usage_patterns.html#multiparty-mode" - },"830": { + },"834": { "doc": "pages.usage_patterns", "title": "pages.usage_patterns", "content": " ", "url": "/firefly/head/overview/usage_patterns.html", "relUrl": "/overview/usage_patterns.html" - },"831": { + },"835": { "doc": "Verifier", "title": "Verifier", "content": " ", "url": "/firefly/head/reference/types/verifier.html", "relUrl": "/reference/types/verifier.html" - },"832": { + },"836": { "doc": "Verifier", "title": "Table of contents", "content": ". | Verifier . | Example | Field Descriptions | . | . ", "url": "/firefly/head/reference/types/verifier.html#table-of-contents", "relUrl": "/reference/types/verifier.html#table-of-contents" - },"833": { + },"837": { "doc": "Verifier", "title": "Verifier", "content": "A verifier is a cryptographic verification mechanism for an identity in FireFly. FireFly generally defers verification of these keys to the lower layers of technologies in the stack - the blockchain (Fabric, Ethereum etc.) or Data Exchange technology. As such the details of the public key cryptography scheme are not represented in the FireFly verifiers. Only the string identifier of the verifier that is appropriate to the technology. | Ethereum blockchains: The Ethereum address hex string | Hyperledger Fabric: The fully qualified MSP Identifier string | Data exchange: The data exchange “Peer ID”, as determined by the DX plugin | . Example . { \"hash\": \"6818c41093590b862b781082d4df5d4abda6d2a4b71d737779edf6d2375d810b\", \"identity\": \"114f5857-9983-46fb-b1fc-8c8f0a20846c\", \"type\": \"ethereum_address\", \"value\": \"0x30017fd084715e41aa6536ab777a8f3a2b11a5a1\", \"created\": \"2022-05-16T01:23:15Z\" } . Field Descriptions . | Field Name | Description | Type | . | hash | Hash used as a globally consistent identifier for this namespace + type + value combination on every node in the network | Bytes32 | . | identity | The UUID of the parent identity that has claimed this verifier | UUID | . | namespace | The namespace of the verifier | string | . | type | The type of the verifier | FFEnum:\"ethereum_address\"\"tezos_address\"\"fabric_msp_id\"\"dx_peer_id\" | . | value | The verifier string, such as an Ethereum address, or Fabric MSP identifier | string | . | created | The time this verifier was created on this node | FFTime | . ", "url": "/firefly/head/reference/types/verifier.html", "relUrl": "/reference/types/verifier.html" - },"834": { + },"838": { "doc": "Versioning Scheme", "title": "Versioning Scheme", "content": " ", "url": "/firefly/head/contributors/version_scheme.html", "relUrl": "/contributors/version_scheme.html" - },"835": { + },"839": { "doc": "Versioning Scheme", "title": "Table of contents", "content": ". | Versioning Scheme . | Semantic versioning | Pre-release test versions | Candidate releases | . | . This page describes FireFly’s versioning scheme . ", "url": "/firefly/head/contributors/version_scheme.html#table-of-contents", "relUrl": "/contributors/version_scheme.html#table-of-contents" - },"836": { + },"840": { "doc": "Versioning Scheme", "title": "Semantic versioning", "content": "FireFly follows semantic versioning. In summary, this means: . Given a version number MAJOR.MINOR.PATCH, increment the: . | MAJOR version when you make incompatible API changes, | MINOR version when you add functionality in a backwards compatible manner, and | PATCH version when you make backwards compatible bug fixes. | Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. | . When creating a new release, the release name and tag should be the semantic version should be prefixed with a v . For example, a certain release name/tag could be v0.9.0. ", "url": "/firefly/head/contributors/version_scheme.html#semantic-versioning", "relUrl": "/contributors/version_scheme.html#semantic-versioning" - },"837": { + },"841": { "doc": "Versioning Scheme", "title": "Pre-release test versions", "content": "For pre-release versions for testing, we append a date and index to the end of the most recently released version. For example, if we needed to create a pre-release based on v0.9.0 and today’s date is October 22, 2021, the version name/tag would be: v0.9.0-20211022-01. If for some reason you needed to create another pre-release version in the same day (hey, stuff happens), the name/tag for that one would be v0.9.0-20211022-02. ", "url": "/firefly/head/contributors/version_scheme.html#pre-release-test-versions", "relUrl": "/contributors/version_scheme.html#pre-release-test-versions" - },"838": { + },"842": { "doc": "Versioning Scheme", "title": "Candidate releases", "content": "For pre-releases that are candidates to become a new major or minor release, the release name/tag will be based on the release that the candidate will become (as opposed to the test releases above, which are based on the previous release). For example, if the current latest release is v0.9.0 but we want to create an alpha release for 1.0, the release name/tag would be v1.0.0-alpha.1. ", "url": "/firefly/head/contributors/version_scheme.html#candidate-releases", "relUrl": "/contributors/version_scheme.html#candidate-releases" - },"839": { + },"843": { "doc": "WSAck", "title": "WSAck", "content": " ", "url": "/firefly/head/reference/types/wsack.html", "relUrl": "/reference/types/wsack.html" - },"840": { + },"844": { "doc": "WSAck", "title": "Table of contents", "content": ". | WSAck . | Example | Field Descriptions | . | SubscriptionRef | . ", "url": "/firefly/head/reference/types/wsack.html#table-of-contents", "relUrl": "/reference/types/wsack.html#table-of-contents" - },"841": { + },"845": { "doc": "WSAck", "title": "WSAck", "content": "An ack must be sent on a WebSocket for each event delivered to an application. Unless autoack is set in the WSStart payload/URL parameters to cause automatic acknowledgement. Your application should specify the id of each event that it acknowledges. If the id is omitted, then FireFly will assume the oldest message delivered to the application that has not been acknowledged is the one the ack is associated with. If multiple subscriptions are started on a WebSocket, then you need to specify the subscription namespace+name as part of each ack. If you send an acknowledgement that cannot be correlated, then a WSError payload will be sent to the application. Example . { \"type\": \"ack\", \"id\": \"f78bf82b-1292-4c86-8a08-e53d855f1a64\", \"subscription\": { \"namespace\": \"ns1\", \"name\": \"app1_subscription\" } } . Field Descriptions . | Field Name | Description | Type | . | type | WSActionBase.type | FFEnum:\"start\"\"ack\"\"protocol_error\"\"event_batch\" | . | id | WSAck.id | UUID | . | subscription | WSAck.subscription | SubscriptionRef | . ", "url": "/firefly/head/reference/types/wsack.html", "relUrl": "/reference/types/wsack.html" - },"842": { + },"846": { "doc": "WSAck", "title": "SubscriptionRef", "content": "| Field Name | Description | Type | . | id | The UUID of the subscription | UUID | . | namespace | The namespace of the subscription. A subscription will only receive events generated in the namespace of the subscription | string | . | name | The name of the subscription. The application specifies this name when it connects, in order to attach to the subscription and receive events that arrived while it was disconnected. If multiple apps connect to the same subscription, events are workload balanced across the connected application instances | string | . ", "url": "/firefly/head/reference/types/wsack.html#subscriptionref", "relUrl": "/reference/types/wsack.html#subscriptionref" - },"843": { + },"847": { "doc": "WSError", "title": "WSError", "content": " ", "url": "/firefly/head/reference/types/wserror.html", "relUrl": "/reference/types/wserror.html" - },"844": { + },"848": { "doc": "WSError", "title": "Table of contents", "content": ". | WSError . | Example | Field Descriptions | . | . ", "url": "/firefly/head/reference/types/wserror.html#table-of-contents", "relUrl": "/reference/types/wserror.html#table-of-contents" - },"845": { + },"849": { "doc": "WSError", "title": "WSError", "content": "Example . { \"type\": \"protocol_error\", \"error\": \"FF10175: Acknowledgment does not match an inflight event + subscription\" } . Field Descriptions . | Field Name | Description | Type | . | type | WSAck.type | FFEnum:\"start\"\"ack\"\"protocol_error\"\"event_batch\" | . | error | WSAck.error | string | . ", "url": "/firefly/head/reference/types/wserror.html", "relUrl": "/reference/types/wserror.html" - },"846": { + },"850": { "doc": "WSStart", "title": "WSStart", "content": " ", "url": "/firefly/head/reference/types/wsstart.html", "relUrl": "/reference/types/wsstart.html" - },"847": { + },"851": { "doc": "WSStart", "title": "Table of contents", "content": ". | WSStart . | Example | Field Descriptions | . | SubscriptionFilter | MessageFilter | TransactionFilter | BlockchainEventFilter | SubscriptionOptions | WebhookInputOptions | WebhookRetryOptions | WebhookHTTPOptions | . ", "url": "/firefly/head/reference/types/wsstart.html#table-of-contents", "relUrl": "/reference/types/wsstart.html#table-of-contents" - },"848": { + },"852": { "doc": "WSStart", "title": "WSStart", "content": "The start payload is sent after an application connects to a WebSocket, to start delivery of events over that connection. The start command can refer to a subscription by name in order to reliably receive all matching events for that subscription, including those that were emitted when the application was disconnected. Alternatively the start command can request \"ephemeral\": true in order to dynamically create a new subscription that lasts only for the duration that the connection is active. Example . { \"type\": \"start\", \"autoack\": false, \"namespace\": \"ns1\", \"name\": \"app1_subscription\", \"ephemeral\": false, \"filter\": { \"message\": {}, \"transaction\": {}, \"blockchainevent\": {} }, \"options\": {} } . Field Descriptions . | Field Name | Description | Type | . | type | WSActionBase.type | FFEnum:\"start\"\"ack\"\"protocol_error\"\"event_batch\" | . | autoack | WSStart.autoack | bool | . | namespace | WSStart.namespace | string | . | name | WSStart.name | string | . | ephemeral | WSStart.ephemeral | bool | . | filter | WSStart.filter | SubscriptionFilter | . | options | WSStart.options | SubscriptionOptions | . ", "url": "/firefly/head/reference/types/wsstart.html", "relUrl": "/reference/types/wsstart.html" - },"849": { + },"853": { "doc": "WSStart", "title": "SubscriptionFilter", "content": "| Field Name | Description | Type | . | events | Regular expression to apply to the event type, to subscribe to a subset of event types | string | . | message | Filters specific to message events. If an event is not a message event, these filters are ignored | MessageFilter | . | transaction | Filters specific to events with a transaction. If an event is not associated with a transaction, this filter is ignored | TransactionFilter | . | blockchainevent | Filters specific to blockchain events. If an event is not a blockchain event, these filters are ignored | BlockchainEventFilter | . | topic | Regular expression to apply to the topic of the event, to subscribe to a subset of topics. Note for messages sent with multiple topics, a separate event is emitted for each topic | string | . | topics | Deprecated: Please use ‘topic’ instead | string | . | tag | Deprecated: Please use ‘message.tag’ instead | string | . | group | Deprecated: Please use ‘message.group’ instead | string | . | author | Deprecated: Please use ‘message.author’ instead | string | . ", "url": "/firefly/head/reference/types/wsstart.html#subscriptionfilter", "relUrl": "/reference/types/wsstart.html#subscriptionfilter" - },"850": { + },"854": { "doc": "WSStart", "title": "MessageFilter", "content": "| Field Name | Description | Type | . | tag | Regular expression to apply to the message ‘header.tag’ field | string | . | group | Regular expression to apply to the message ‘header.group’ field | string | . | author | Regular expression to apply to the message ‘header.author’ field | string | . ", "url": "/firefly/head/reference/types/wsstart.html#messagefilter", "relUrl": "/reference/types/wsstart.html#messagefilter" - },"851": { + },"855": { "doc": "WSStart", "title": "TransactionFilter", "content": "| Field Name | Description | Type | . | type | Regular expression to apply to the transaction ‘type’ field | string | . ", "url": "/firefly/head/reference/types/wsstart.html#transactionfilter", "relUrl": "/reference/types/wsstart.html#transactionfilter" - },"852": { + },"856": { "doc": "WSStart", "title": "BlockchainEventFilter", "content": "| Field Name | Description | Type | . | name | Regular expression to apply to the blockchain event ‘name’ field, which is the name of the event in the underlying blockchain smart contract | string | . | listener | Regular expression to apply to the blockchain event ‘listener’ field, which is the UUID of the event listener. So you can restrict your subscription to certain blockchain listeners. Alternatively to avoid your application need to know listener UUIDs you can set the ‘topic’ field of blockchain event listeners, and use a topic filter on your subscriptions | string | . ", "url": "/firefly/head/reference/types/wsstart.html#blockchaineventfilter", "relUrl": "/reference/types/wsstart.html#blockchaineventfilter" - },"853": { + },"857": { "doc": "WSStart", "title": "SubscriptionOptions", "content": "| Field Name | Description | Type | . | firstEvent | Whether your application would like to receive events from the ‘oldest’ event emitted by your FireFly node (from the beginning of time), or the ‘newest’ event (from now), or a specific event sequence. Default is ‘newest’ | SubOptsFirstEvent | . | readAhead | The number of events to stream ahead to your application, while waiting for confirmation of consumption of those events. At least once delivery semantics are used in FireFly, so if your application crashes/reconnects this is the maximum number of events you would expect to be redelivered after it restarts | uint16 | . | withData | Whether message events delivered over the subscription, should be packaged with the full data of those messages in-line as part of the event JSON payload. Or if the application should make separate REST calls to download that data. May not be supported on some transports. | bool | . | batch | Events are delivered in batches in an ordered array. The batch size is capped to the readAhead limit. The event payload is always an array even if there is a single event in the batch, allowing client-side optimizations when processing the events in a group. Available for both Webhooks and WebSockets. | bool | . | batchTimeout | When batching is enabled, the optional timeout to send events even when the batch hasn’t filled. | string | . | fastack | Webhooks only: When true the event will be acknowledged before the webhook is invoked, allowing parallel invocations | bool | . | url | Webhooks only: HTTP url to invoke. Can be relative if a base URL is set in the webhook plugin config | string | . | method | Webhooks only: HTTP method to invoke. Default=POST | string | . | json | Webhooks only: Whether to assume the response body is JSON, regardless of the returned Content-Type | bool | . | reply | Webhooks only: Whether to automatically send a reply event, using the body returned by the webhook | bool | . | replytag | Webhooks only: The tag to set on the reply message | string | . | replytx | Webhooks only: The transaction type to set on the reply message | string | . | headers | Webhooks only: Static headers to set on the webhook request | `` | . | query | Webhooks only: Static query params to set on the webhook request | `` | . | tlsConfigName | The name of an existing TLS configuration associated to the namespace to use | string | . | input | Webhooks only: A set of options to extract data from the first JSON input data in the incoming message. Only applies if withData=true | WebhookInputOptions | . | retry | Webhooks only: a set of options for retrying the webhook call | WebhookRetryOptions | . | httpOptions | Webhooks only: a set of options for HTTP | WebhookHTTPOptions | . ", "url": "/firefly/head/reference/types/wsstart.html#subscriptionoptions", "relUrl": "/reference/types/wsstart.html#subscriptionoptions" - },"854": { + },"858": { "doc": "WSStart", "title": "WebhookInputOptions", "content": "| Field Name | Description | Type | . | query | A top-level property of the first data input, to use for query parameters | string | . | headers | A top-level property of the first data input, to use for headers | string | . | body | A top-level property of the first data input, to use for the request body. Default is the whole first body | string | . | path | A top-level property of the first data input, to use for a path to append with escaping to the webhook path | string | . | replytx | A top-level property of the first data input, to use to dynamically set whether to pin the response (so the requester can choose) | string | . ", "url": "/firefly/head/reference/types/wsstart.html#webhookinputoptions", "relUrl": "/reference/types/wsstart.html#webhookinputoptions" - },"855": { + },"859": { "doc": "WSStart", "title": "WebhookRetryOptions", "content": "| Field Name | Description | Type | . | enabled | Enables retry on HTTP calls, defaults to false | bool | . | count | Number of times to retry the webhook call in case of failure | int | . | initialDelay | Initial delay between retries when we retry the webhook call | string | . | maxDelay | Max delay between retries when we retry the webhookcall | string | . ", "url": "/firefly/head/reference/types/wsstart.html#webhookretryoptions", "relUrl": "/reference/types/wsstart.html#webhookretryoptions" - },"856": { + },"860": { "doc": "WSStart", "title": "WebhookHTTPOptions", "content": "| Field Name | Description | Type | . | proxyURL | HTTP proxy URL to use for outbound requests to the webhook | string | . | tlsHandshakeTimeout | The max duration to hold a TLS handshake alive | string | . | requestTimeout | The max duration to hold a TLS handshake alive | string | . | maxIdleConns | The max number of idle connections to hold pooled | int | . | idleTimeout | The max duration to hold a HTTP keepalive connection between calls | string | . | connectionTimeout | The maximum amount of time that a connection is allowed to remain with no data transmitted. | string | . | expectContinueTimeout | See ExpectContinueTimeout in the Go docs | string | . ", "url": "/firefly/head/reference/types/wsstart.html#webhookhttpoptions", "relUrl": "/reference/types/wsstart.html#webhookhttpoptions" - },"857": { + },"861": { "doc": "pages.zksync_testnet", "title": "zkSync Testnet", "content": " ", "url": "/firefly/head/tutorials/chains/zksync_testnet.html#zksync-testnet", "relUrl": "/tutorials/chains/zksync_testnet.html#zksync-testnet" - },"858": { + },"862": { "doc": "pages.zksync_testnet", "title": "Table of contents", "content": ". | Previous steps: Install the FireFly CLI | Create an evmconnect.yml config file | Creating a new stack | Start the stack | Get some ETH . | Confirm the transaction on the Etherscan Explorer | . | Use the public testnet | . Starting with FireFly v1.1, it’s easy to connect to public Ethereum chains. This guide will walk you through the steps to create a local FireFly development environment and connect it to the zkSync testnet. ", "url": "/firefly/head/tutorials/chains/zksync_testnet.html#table-of-contents", "relUrl": "/tutorials/chains/zksync_testnet.html#table-of-contents" - },"859": { + },"863": { "doc": "pages.zksync_testnet", "title": "Previous steps: Install the FireFly CLI", "content": "If you haven’t set up the FireFly CLI already, please go back to the Getting Started guide and read the section on how to Install the FireFly CLI. ← ① Install the FireFly CLI . ", "url": "/firefly/head/tutorials/chains/zksync_testnet.html#previous-steps-install-the-firefly-cli", "relUrl": "/tutorials/chains/zksync_testnet.html#previous-steps-install-the-firefly-cli" - },"860": { + },"864": { "doc": "pages.zksync_testnet", "title": "Create an evmconnect.yml config file", "content": "In order to connect to the zkSync testnet, you will need to set a few configuration options for the evmconnect blockchain connector. Create a text file called evmconnect.yml with the following contents: . confirmations: required: 4 # choose the number of confirmations you require policyengine.simple: fixedGasPrice: null gasOracle: mode: connector . For this tutorial, we will assume this file is saved at ~/Desktop/evmconnect.yml. If your path is different, you will need to adjust the path in the next command below. ", "url": "/firefly/head/tutorials/chains/zksync_testnet.html#create-an-evmconnectyml-config-file", "relUrl": "/tutorials/chains/zksync_testnet.html#create-an-evmconnectyml-config-file" - },"861": { + },"865": { "doc": "pages.zksync_testnet", "title": "Creating a new stack", "content": "To create a local FireFly development stack and connect it to the zkSync testnet, we will use command line flags to customize the following settings: . | Create a new stack named zkSync with 1 member | Disable multiparty mode. We are going to be using this FireFly node as a Web3 gateway, and we don’t need to communicate with a consortium here | Connect to an ethereum network | Use the evmconnect blockchain connector | Use an remote RPC node. This will create a signer locally, so that our signing key never leaves the development machine. | See the list of providers for zkSync docs. For this tutorial we will use https://zksync2-testnet.zksync.dev | Set the chain ID to 280 (the correct ID for the zkSync testnet) | Merge the custom config created above with the generated evmconnect config file | . To do this, run the following command: . ff init zksync 1\\ --multiparty=false \\ -b ethereum \\ -c evmconnect \\ -n remote-rpc \\ --remote-node-url https://zksync2-testnet.zksync.dev\\ --chain-id 280 \\ --connector-config ~/Desktop/evmconnect.yml . ", "url": "/firefly/head/tutorials/chains/zksync_testnet.html#creating-a-new-stack", "relUrl": "/tutorials/chains/zksync_testnet.html#creating-a-new-stack" - },"862": { + },"866": { "doc": "pages.zksync_testnet", "title": "Start the stack", "content": "Now you should be able to start your stack by running: . ff start zksync . After some time it should print out the following: . Web UI for member '0': http://127.0.0.1:5000/ui Sandbox UI for member '0': http://127.0.0.1:5109 To see logs for your stack run: ff logs zksync . ", "url": "/firefly/head/tutorials/chains/zksync_testnet.html#start-the-stack", "relUrl": "/tutorials/chains/zksync_testnet.html#start-the-stack" - },"863": { + },"867": { "doc": "pages.zksync_testnet", "title": "Get some ETH", "content": "At this point you should have a working FireFly stack, talking to a public chain. However, you won’t be able to run any transactions just yet, because you don’t have any way to pay for gas. zkSync does not currently have its own native token and instead uses Ethereum for transaction. A testnet faucet can give us some ETH. First, you will need to know what signing address your FireFly node is using. To check that, you can run: . ff accounts list zkSync [ { \"address\": \"0x8cf4fd38b2d56a905113d23b5a7131f0269d8611\", \"privateKey\": \"...\" } ] . Copy your zkSync address and go to the Goerli Ethereum faucet and paste the address in the form. Click the Request Tokens button. Note that any Goerli Ethereum faucet will work. Confirm the transaction on the Etherscan Explorer . You should be able to go lookup your account at https://etherscan.io/ and see that you now have a balance of 0.025 ETH. Simply paste in your account address to search for it. ", "url": "/firefly/head/tutorials/chains/zksync_testnet.html#get-some-eth", "relUrl": "/tutorials/chains/zksync_testnet.html#get-some-eth" - },"864": { + },"868": { "doc": "pages.zksync_testnet", "title": "Use the public testnet", "content": "Now that you have everything set up, you can follow one of the other FireFly guides such as Using Tokens or Custom Smart Contracts. For detailed instructions on deploying a custom smart contract to zkSync, please see the zkSync docs for instructions using various tools. ", "url": "/firefly/head/tutorials/chains/zksync_testnet.html#use-the-public-testnet", "relUrl": "/tutorials/chains/zksync_testnet.html#use-the-public-testnet" - },"865": { + },"869": { "doc": "pages.zksync_testnet", "title": "pages.zksync_testnet", "content": " ", diff --git a/head/contributors/advanced_cli_usage.html b/head/contributors/advanced_cli_usage.html index 40ec3d3b6..63c6832bb 100644 --- a/head/contributors/advanced_cli_usage.html +++ b/head/contributors/advanced_cli_usage.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/contributors/code_hierarchy.html b/head/contributors/code_hierarchy.html index e626ec828..2ca3ccced 100644 --- a/head/contributors/code_hierarchy.html +++ b/head/contributors/code_hierarchy.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/contributors/code_overview.html b/head/contributors/code_overview.html index 0c6606086..6f4e960be 100644 --- a/head/contributors/code_overview.html +++ b/head/contributors/code_overview.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/contributors/code_repositories.html b/head/contributors/code_repositories.html index 6c262b7d8..655910069 100644 --- a/head/contributors/code_repositories.html +++ b/head/contributors/code_repositories.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/contributors/dev_environment_setup.html b/head/contributors/dev_environment_setup.html index fe2e2e6ed..a4d2d394a 100644 --- a/head/contributors/dev_environment_setup.html +++ b/head/contributors/dev_environment_setup.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/contributors/docs_setup.html b/head/contributors/docs_setup.html index 18148499b..f02c2f9dc 100644 --- a/head/contributors/docs_setup.html +++ b/head/contributors/docs_setup.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/contributors/index.html b/head/contributors/index.html index e93e0a0fa..fe886258b 100644 --- a/head/contributors/index.html +++ b/head/contributors/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/contributors/release_guide.html b/head/contributors/release_guide.html index 6e14e328f..031a67330 100644 --- a/head/contributors/release_guide.html +++ b/head/contributors/release_guide.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/contributors/version_scheme.html b/head/contributors/version_scheme.html index 97ce144da..7d54a5dfd 100644 --- a/head/contributors/version_scheme.html +++ b/head/contributors/version_scheme.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/faqs/index.html b/head/faqs/index.html index 862ab2c48..25601ff3b 100644 --- a/head/faqs/index.html +++ b/head/faqs/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/gettingstarted/firefly_cli.html b/head/gettingstarted/firefly_cli.html index d570e4fb4..2a71dfd74 100644 --- a/head/gettingstarted/firefly_cli.html +++ b/head/gettingstarted/firefly_cli.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/gettingstarted/index.html b/head/gettingstarted/index.html index 20d2d3348..ca075b929 100644 --- a/head/gettingstarted/index.html +++ b/head/gettingstarted/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/gettingstarted/sandbox.html b/head/gettingstarted/sandbox.html index 0d564c98c..34e32140f 100644 --- a/head/gettingstarted/sandbox.html +++ b/head/gettingstarted/sandbox.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/gettingstarted/setup_env.html b/head/gettingstarted/setup_env.html index f34738d74..aa589b785 100644 --- a/head/gettingstarted/setup_env.html +++ b/head/gettingstarted/setup_env.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/index.html b/head/index.html index 7c8234f3f..68e67b1f3 100644 --- a/head/index.html +++ b/head/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/gateway_features.html b/head/overview/gateway_features.html index f5df8cb11..82e79e864 100644 --- a/head/overview/gateway_features.html +++ b/head/overview/gateway_features.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/index.html b/head/overview/index.html index 20936b956..28b11d8cd 100644 --- a/head/overview/index.html +++ b/head/overview/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/key_components/apps.html b/head/overview/key_components/apps.html index 506e55787..03361618d 100644 --- a/head/overview/key_components/apps.html +++ b/head/overview/key_components/apps.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/key_components/connectors.html b/head/overview/key_components/connectors.html index 05cee73ee..76bd2eacf 100644 --- a/head/overview/key_components/connectors.html +++ b/head/overview/key_components/connectors.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/key_components/digital_assets.html b/head/overview/key_components/digital_assets.html index 2dfa17368..46de8c702 100644 --- a/head/overview/key_components/digital_assets.html +++ b/head/overview/key_components/digital_assets.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/key_components/flows.html b/head/overview/key_components/flows.html index b9c882a45..e1b82eb9c 100644 --- a/head/overview/key_components/flows.html +++ b/head/overview/key_components/flows.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/key_components/orchestration_engine.html b/head/overview/key_components/orchestration_engine.html index 4bf2e2a67..e61622e81 100644 --- a/head/overview/key_components/orchestration_engine.html +++ b/head/overview/key_components/orchestration_engine.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/key_components/security.html b/head/overview/key_components/security.html index 807410844..318697fa4 100644 --- a/head/overview/key_components/security.html +++ b/head/overview/key_components/security.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/key_components/tools.html b/head/overview/key_components/tools.html index 26b8785de..3d677eaf3 100644 --- a/head/overview/key_components/tools.html +++ b/head/overview/key_components/tools.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/key_features.html b/head/overview/key_features.html index c3da3b814..b79b90f8c 100644 --- a/head/overview/key_features.html +++ b/head/overview/key_features.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/multiparty/broadcast.html b/head/overview/multiparty/broadcast.html index da54d1977..c53104ce3 100644 --- a/head/overview/multiparty/broadcast.html +++ b/head/overview/multiparty/broadcast.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/multiparty/data_exchange.html b/head/overview/multiparty/data_exchange.html index bea6ed0eb..5f30026c7 100644 --- a/head/overview/multiparty/data_exchange.html +++ b/head/overview/multiparty/data_exchange.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/multiparty/deterministic.html b/head/overview/multiparty/deterministic.html index ca7102e44..656e89b1d 100644 --- a/head/overview/multiparty/deterministic.html +++ b/head/overview/multiparty/deterministic.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/multiparty/multiparty_flow.html b/head/overview/multiparty/multiparty_flow.html index 97b5a5a51..178e8d551 100644 --- a/head/overview/multiparty/multiparty_flow.html +++ b/head/overview/multiparty/multiparty_flow.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/multiparty_features.html b/head/overview/multiparty_features.html index 151559bd3..c2249622c 100644 --- a/head/overview/multiparty_features.html +++ b/head/overview/multiparty_features.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/public_vs_permissioned.html b/head/overview/public_vs_permissioned.html index b204479fa..7004bcbd0 100644 --- a/head/overview/public_vs_permissioned.html +++ b/head/overview/public_vs_permissioned.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/supernode_concept.html b/head/overview/supernode_concept.html index f400f713f..691f2cfc0 100644 --- a/head/overview/supernode_concept.html +++ b/head/overview/supernode_concept.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/overview/usage_patterns.html b/head/overview/usage_patterns.html index fbdf55d04..ee9862c2a 100644 --- a/head/overview/usage_patterns.html +++ b/head/overview/usage_patterns.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/api_post_syntax.html b/head/reference/api_post_syntax.html index bb6eb3377..8570d1918 100644 --- a/head/reference/api_post_syntax.html +++ b/head/reference/api_post_syntax.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/api_query_syntax.html b/head/reference/api_query_syntax.html index d6fc9f3c6..e0d8acca4 100644 --- a/head/reference/api_query_syntax.html +++ b/head/reference/api_query_syntax.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/blockchain_operation_errors.html b/head/reference/blockchain_operation_errors.html new file mode 100644 index 000000000..ad7b7e7b5 --- /dev/null +++ b/head/reference/blockchain_operation_errors.html @@ -0,0 +1,486 @@ + + + + + + + + + Blockchain Operation Errors - Hyperledger FireFly Docs + + + + + + + + + + + + + + + + + + + + +Blockchain Operation Errors | Hyperledger FireFly Docs + + + + + + + + + + + + + + + + + + + + + Link + + + + + + Search + + + + + + Menu + + + + + + Expand + + + + + + Document + + + + + + + +
    +
    + + + + + + + +
    +
    + + + + +
    + +

    + + + Blockchain Operation Errors + + +

    + +

    + + + Table of contents + + +

    + + +
      +
    1. Blockchain error messages
    2. +
    3. Default error format with Hyperledger FireFly 1.3 and Hyperledger Besu 24.3.0
    4. +
    5. Error retrieval details
        +
      1. Format of a firefly-evmconnect error message
      2. +
      3. Retrieving EVM blockchain transaction errors
      4. +
      +
    6. +

    +

    + + + Blockchain error messages + + +

    + + +

    The receipt for a FireFly blockchain operation contains an extraInfo section that records additional information about the transaction. For example:

    + +
    "receipt": {
    +  ...
    +  "extraInfo": [
    +    {
    +      {
    +        "contractAddress":"0x87ae94ab290932c4e6269648bb47c86978af4436",
    +        "cumulativeGasUsed":"33812",
    +        "from":"0x2b1c769ef5ad304a4889f2a07a6617cd935849ae",
    +        "to":"0x302259069aaa5b10dc6f29a9a3f72a8e52837cc3",
    +        "gasUsed":"33812",
    +        "status":"0",
    +        "errorMessage":"Not enough tokens", 
    +      }
    +    }
    +  ],
    +  ...
    +},
    +
    + +

    The errorMessage field can be be set by a blockchain connector to provide FireFly and the end-user with more information about the reason why a tranasction failed. The blockchain connector can choose what information to include in errorMessage field. It may be set to an error message relating to the blockchain connector itself or an error message passed back from the blockchain or smart contract that was invoked.

    +

    + + + Default error format with Hyperledger FireFly 1.3 and Hyperledger Besu 24.3.0 + + +

    + + +

    If FireFly is configured to connect to a Besu EVM client, and Besu has been configured with the revert-reason-enabled=true setting (note - the default value for Besu is false) error messages passed to FireFly from the blockchain client itself will be set correctly in the FireFly blockchain operation. For example:

    + +
      +
    • "errorMessage":"Not enough tokens" for a revert error string from a smart contract
    • +
    + +

    If the smart contract uses a custom error type, Besu will return the revert reason to FireFly as a hexadecimal string but FireFly will be unable to decode it into. In this case the blockchain operation error message and return values will be set to:

    + +
      +
    • "errorMessage":"FF23053: Error return value for custom error: <revert hex string>
    • +
    • "returnValue":"<revert hex string>"
    • +
    + +

    A future update to FireFly could be made to automatically decode custom error revert reasons if FireFly knows the ABI for the custom error. See FireFly issue 1466 which describes the current limitation.

    + +

    If FireFly is configured to connect to Besu without revert-reason-enabled=true the error message will be set to:

    + +
      +
    • "errorMessage":"FF23054: Error return value unavailable"
    • +
    +

    + + + Error retrieval details + + +

    + + +

    The precise format of the error message in a blockchain operation can vary based on different factors. The sections below describe in detail how the error message is populted, with specific references to the firefly-evmconnect blockchain connector.

    +

    + + + Format of a firefly-evmconnect error message + + +

    + + +

    The following section describes the way that the firefly-evmconnect plugin uses the errorMessage field. This serves both as an explanation of how EVM-based transaction errors will be formatted, and as a guide that other blockchain connectors may decide to follow.

    + +

    The errorMessage field for a firefly-evmconnect transaction may contain one of the following:

    + +
      +
    1. An error message from the FireFly blockchain connector +
        +
      • For example "FF23054: Error return value unavailable"
      • +
      +
    2. +
    3. A decoded error string from the blockchain transaction +
        +
      • For example Not enough tokens
      • +
      • This could be an error string from a smart contract e.g. require(requestedTokens <= allowance, "Not enough tokens");
      • +
      +
    4. +
    5. An un-decoded byte string from the blockchain transaction +
        +
      • For example +
        FF23053: Error return value for custom error: 0x1320fa6a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000010
        +
        +
      • +
      • This could be a custom error from a smart contract e.g. +
        error AllowanceTooSmall(uint256 requested, uint256 allowance);
        +...
        +revert AllowanceTooSmall({ requested: 100, allowance: 20 });
        +
        +
      • +
      • If an error reason cannot be decoded the returnValue of the extraInfo will be set to the raw byte string. For example: +
        "receipt": {
        +  ...
        +  "extraInfo": [
        +  {
        +{
        +  "contractAddress":"0x87ae94ab290932c4e6269648bb47c86978af4436",
        +  "cumulativeGasUsed":"33812",
        +  "from":"0x2b1c769ef5ad304a4889f2a07a6617cd935849ae",
        +  "to":"0x302259069aaa5b10dc6f29a9a3f72a8e52837cc3",
        +  "gasUsed":"33812",
        +  "status":"0",
        +  "errorMessage":"FF23053: Error return value for custom error: 0x1320fa6a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000010", 
        +  "returnValue":"0x1320fa6a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000010"
        +}
        +  }
        +  ],
        +  ...
        +},
        +
        +
      • +
      +
    6. +
    +

    + + + Retrieving EVM blockchain transaction errors + + +

    + + +

    The ability of a blockchain connector such as firefly-evmconnect to retrieve the reason for a transaction failure, is dependent on by the configuration of the blockchain it is connected to. For an EVM blockchain the reason why a transaction failed is recorded with the REVERT op code, with a REASON set to the reason for the failure. By default, most EVM clients do not store this reason in the transaction receipt. This is typically to reduce resource consumption such as memory usage in the client. It is usually possible to configure an EVM client to store the revert reason in the transaction receipt. For example Hyperledger Besu™ provides the --revert-reason-enabled configuration option. If the transaction receipt does not contain the revert reason it is possible to request that an EVM client re-run the transaction and return a trace of all of the op-codes, including the final REVERT REASON. This can be a resource intensive request to submit to an EVM client, and is only available on archive nodes or for very recent blocks.

    + +

    The firefly-evmconnect blockchain connector attempts to obtain the reason for a transaction revert and include it in the extraInfo field. It uses the following mechanisms, in this order:

    + +
      +
    1. Checks if the blockchain transaction receipt contains the revert reason.
    2. +
    3. If the revert reason is not in the receipt, and the connector.traceTXForRevertReason configuration option is set to true, calls debug_traceTransaction to obtain a full trace of the transaction and extract the revert reason. By default, connector.traceTXForRevertReason is set to false to avoid submitting high-resource requests to the EVM client.
    4. +
    + +

    If the revert reason can be obtained using either mechanism above, the revert reason bytes are decoded in the following way:

    +
      +
    • Attempts to decode the bytes as the standard Error(string) signature format and includes the decoded string in the errorMessage
    • +
    • If the reason is not a standard Error(String) error, sets the errorMessage to FF23053: Error return value for custom error: <raw hex string> and includes the raw byte string in the returnValue field.
    • +
    + + + + + + + + +
    +
    + + + + +
    + +
    + + + diff --git a/head/reference/blockchain_operation_status.html b/head/reference/blockchain_operation_status.html index 128f26a5b..189c72beb 100644 --- a/head/reference/blockchain_operation_status.html +++ b/head/reference/blockchain_operation_status.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/config.html b/head/reference/config.html index 982ea943d..5e5cfebf0 100644 --- a/head/reference/config.html +++ b/head/reference/config.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/events.html b/head/reference/events.html index 1f5ed8df0..8e239195f 100644 --- a/head/reference/events.html +++ b/head/reference/events.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/firefly_interface_format.html b/head/reference/firefly_interface_format.html index 79dd00cb7..c2433bc6b 100644 --- a/head/reference/firefly_interface_format.html +++ b/head/reference/firefly_interface_format.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/idempotency.html b/head/reference/idempotency.html index 502ce27f2..b1a43e8ee 100644 --- a/head/reference/idempotency.html +++ b/head/reference/idempotency.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/identities.html b/head/reference/identities.html index 535da46dd..e232bacd4 100644 --- a/head/reference/identities.html +++ b/head/reference/identities.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/index.html b/head/reference/index.html index c9a56b375..8ce6f6161 100644 --- a/head/reference/index.html +++ b/head/reference/index.html @@ -196,7 +196,7 @@ WSAck @@ -309,6 +309,10 @@

    Table of contents

    Blockchain Operation Status +
  • + Blockchain Operation Errors +
  • +
  • Event Bus
  • diff --git a/head/reference/microservices/fftokens.html b/head/reference/microservices/fftokens.html index 4252087ff..e5785fd8b 100644 --- a/head/reference/microservices/fftokens.html +++ b/head/reference/microservices/fftokens.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/microservices/index.html b/head/reference/microservices/index.html index 2564e2685..8179a5023 100644 --- a/head/reference/microservices/index.html +++ b/head/reference/microservices/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/namespaces.html b/head/reference/namespaces.html index f313f7853..0d9190787 100644 --- a/head/reference/namespaces.html +++ b/head/reference/namespaces.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/tls.html b/head/reference/tls.html index 8d3845eef..9f0c1d320 100644 --- a/head/reference/tls.html +++ b/head/reference/tls.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/batch.html b/head/reference/types/batch.html index cfb2ceb62..88d0fb5f3 100644 --- a/head/reference/types/batch.html +++ b/head/reference/types/batch.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/blockchainevent.html b/head/reference/types/blockchainevent.html index c1149bd27..eccded2eb 100644 --- a/head/reference/types/blockchainevent.html +++ b/head/reference/types/blockchainevent.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/contractapi.html b/head/reference/types/contractapi.html index 563661447..7416c85f5 100644 --- a/head/reference/types/contractapi.html +++ b/head/reference/types/contractapi.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/contractlistener.html b/head/reference/types/contractlistener.html index 8086653af..6d1a8207d 100644 --- a/head/reference/types/contractlistener.html +++ b/head/reference/types/contractlistener.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/data.html b/head/reference/types/data.html index f4a546026..4828468f5 100644 --- a/head/reference/types/data.html +++ b/head/reference/types/data.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/dataref.html b/head/reference/types/dataref.html index 042f6f420..c8b7b02da 100644 --- a/head/reference/types/dataref.html +++ b/head/reference/types/dataref.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/datatype.html b/head/reference/types/datatype.html index f380d8d2b..5050270ea 100644 --- a/head/reference/types/datatype.html +++ b/head/reference/types/datatype.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/event.html b/head/reference/types/event.html index b48213908..e0d1f484b 100644 --- a/head/reference/types/event.html +++ b/head/reference/types/event.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/ffi.html b/head/reference/types/ffi.html index dbeffeae5..dd2d6509a 100644 --- a/head/reference/types/ffi.html +++ b/head/reference/types/ffi.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/group.html b/head/reference/types/group.html index 7dc225ddd..588121bdf 100644 --- a/head/reference/types/group.html +++ b/head/reference/types/group.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/identity.html b/head/reference/types/identity.html index 5f5fa4489..e365b632e 100644 --- a/head/reference/types/identity.html +++ b/head/reference/types/identity.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/index.html b/head/reference/types/index.html index 2a3e078f6..84ec81214 100644 --- a/head/reference/types/index.html +++ b/head/reference/types/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/message.html b/head/reference/types/message.html index 8f38f9cc8..5584cedb8 100644 --- a/head/reference/types/message.html +++ b/head/reference/types/message.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/namespace.html b/head/reference/types/namespace.html index ccc0831fc..1052b7135 100644 --- a/head/reference/types/namespace.html +++ b/head/reference/types/namespace.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/nextpin.html b/head/reference/types/nextpin.html index 059ad5f70..9e5ce42d2 100644 --- a/head/reference/types/nextpin.html +++ b/head/reference/types/nextpin.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/operation.html b/head/reference/types/operation.html index 0746bba23..120935d7e 100644 --- a/head/reference/types/operation.html +++ b/head/reference/types/operation.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/operationwithdetail.html b/head/reference/types/operationwithdetail.html index 683bd4be4..181dc9566 100644 --- a/head/reference/types/operationwithdetail.html +++ b/head/reference/types/operationwithdetail.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/simpletypes.html b/head/reference/types/simpletypes.html index 0bfcc9e69..af0b56cbb 100644 --- a/head/reference/types/simpletypes.html +++ b/head/reference/types/simpletypes.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/subscription.html b/head/reference/types/subscription.html index 236dc8109..bf72ce71f 100644 --- a/head/reference/types/subscription.html +++ b/head/reference/types/subscription.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/tokenapproval.html b/head/reference/types/tokenapproval.html index 443948fbf..aa3435b4b 100644 --- a/head/reference/types/tokenapproval.html +++ b/head/reference/types/tokenapproval.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/tokenpool.html b/head/reference/types/tokenpool.html index de39516df..d027a5a7d 100644 --- a/head/reference/types/tokenpool.html +++ b/head/reference/types/tokenpool.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/tokentransfer.html b/head/reference/types/tokentransfer.html index 00c34a55b..f54be1973 100644 --- a/head/reference/types/tokentransfer.html +++ b/head/reference/types/tokentransfer.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/transaction.html b/head/reference/types/transaction.html index 4a165a9ff..d0e6d646b 100644 --- a/head/reference/types/transaction.html +++ b/head/reference/types/transaction.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/verifier.html b/head/reference/types/verifier.html index 8c0bc95b0..ff6f32b7a 100644 --- a/head/reference/types/verifier.html +++ b/head/reference/types/verifier.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/wsack.html b/head/reference/types/wsack.html index b2fac6b70..632c068f9 100644 --- a/head/reference/types/wsack.html +++ b/head/reference/types/wsack.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/wserror.html b/head/reference/types/wserror.html index ad31382d4..30f512412 100644 --- a/head/reference/types/wserror.html +++ b/head/reference/types/wserror.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/reference/types/wsstart.html b/head/reference/types/wsstart.html index e237d9cc8..d688fa42d 100644 --- a/head/reference/types/wsstart.html +++ b/head/reference/types/wsstart.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/releasenotes/1.1_migration_guide.html b/head/releasenotes/1.1_migration_guide.html index 5703aed46..5d89f6dc7 100644 --- a/head/releasenotes/1.1_migration_guide.html +++ b/head/releasenotes/1.1_migration_guide.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/releasenotes/1.2_migration_guide.html b/head/releasenotes/1.2_migration_guide.html index d5c639c4b..2865a8e58 100644 --- a/head/releasenotes/1.2_migration_guide.html +++ b/head/releasenotes/1.2_migration_guide.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/releasenotes/index.html b/head/releasenotes/index.html index 7af2d9e3e..6d7e4197f 100644 --- a/head/releasenotes/index.html +++ b/head/releasenotes/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/swagger/swagger.html b/head/swagger/swagger.html index 33bc8b322..c1845feb7 100644 --- a/head/swagger/swagger.html +++ b/head/swagger/swagger.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/basic_auth.html b/head/tutorials/basic_auth.html index a7c551928..809a10493 100644 --- a/head/tutorials/basic_auth.html +++ b/head/tutorials/basic_auth.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/broadcast_data.html b/head/tutorials/broadcast_data.html index 77017c4ba..bd1dd8481 100644 --- a/head/tutorials/broadcast_data.html +++ b/head/tutorials/broadcast_data.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/chains/arbitrum.html b/head/tutorials/chains/arbitrum.html index 5e59e298e..ccc398860 100644 --- a/head/tutorials/chains/arbitrum.html +++ b/head/tutorials/chains/arbitrum.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/chains/avalanche.html b/head/tutorials/chains/avalanche.html index a309023b0..04406ea2f 100644 --- a/head/tutorials/chains/avalanche.html +++ b/head/tutorials/chains/avalanche.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/chains/binance_smart_chain.html b/head/tutorials/chains/binance_smart_chain.html index b19298bcc..009b32004 100644 --- a/head/tutorials/chains/binance_smart_chain.html +++ b/head/tutorials/chains/binance_smart_chain.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/chains/fabric_test_network.html b/head/tutorials/chains/fabric_test_network.html index 5d17b27cb..a2eff5d87 100644 --- a/head/tutorials/chains/fabric_test_network.html +++ b/head/tutorials/chains/fabric_test_network.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/chains/index.html b/head/tutorials/chains/index.html index 60d4af465..244d4aa40 100644 --- a/head/tutorials/chains/index.html +++ b/head/tutorials/chains/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/chains/moonbeam.html b/head/tutorials/chains/moonbeam.html index d2031db03..35f2921a5 100644 --- a/head/tutorials/chains/moonbeam.html +++ b/head/tutorials/chains/moonbeam.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/chains/optimism.html b/head/tutorials/chains/optimism.html index 26bc33480..f48b41a16 100644 --- a/head/tutorials/chains/optimism.html +++ b/head/tutorials/chains/optimism.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/chains/polygon_testnet.html b/head/tutorials/chains/polygon_testnet.html index 0d7e763be..5c341775b 100644 --- a/head/tutorials/chains/polygon_testnet.html +++ b/head/tutorials/chains/polygon_testnet.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/chains/tezos_testnet.html b/head/tutorials/chains/tezos_testnet.html index bb4df2894..f9576de0f 100644 --- a/head/tutorials/chains/tezos_testnet.html +++ b/head/tutorials/chains/tezos_testnet.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/chains/zksync_testnet.html b/head/tutorials/chains/zksync_testnet.html index ebd23138b..5da06a5d0 100644 --- a/head/tutorials/chains/zksync_testnet.html +++ b/head/tutorials/chains/zksync_testnet.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/create_custom_identity.html b/head/tutorials/create_custom_identity.html index 3d8fccfac..963fcf439 100644 --- a/head/tutorials/create_custom_identity.html +++ b/head/tutorials/create_custom_identity.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/custom_contracts/ethereum.html b/head/tutorials/custom_contracts/ethereum.html index b5f928c78..3f3c97fd6 100644 --- a/head/tutorials/custom_contracts/ethereum.html +++ b/head/tutorials/custom_contracts/ethereum.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/custom_contracts/fabric.html b/head/tutorials/custom_contracts/fabric.html index 94d6dbd4f..c3ce317a7 100644 --- a/head/tutorials/custom_contracts/fabric.html +++ b/head/tutorials/custom_contracts/fabric.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/custom_contracts/index.html b/head/tutorials/custom_contracts/index.html index 28c81bbc1..a5c2d16c8 100644 --- a/head/tutorials/custom_contracts/index.html +++ b/head/tutorials/custom_contracts/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/custom_contracts/pinning.html b/head/tutorials/custom_contracts/pinning.html index c167a00cb..9f127c7ae 100644 --- a/head/tutorials/custom_contracts/pinning.html +++ b/head/tutorials/custom_contracts/pinning.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/custom_contracts/tezos.html b/head/tutorials/custom_contracts/tezos.html index 902bde95d..dcb7498de 100644 --- a/head/tutorials/custom_contracts/tezos.html +++ b/head/tutorials/custom_contracts/tezos.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/define_datatype.html b/head/tutorials/define_datatype.html index 1c63025c5..0542130cb 100644 --- a/head/tutorials/define_datatype.html +++ b/head/tutorials/define_datatype.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/events.html b/head/tutorials/events.html index ef4358118..d9378ce26 100644 --- a/head/tutorials/events.html +++ b/head/tutorials/events.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/index.html b/head/tutorials/index.html index 380d76908..ee2ada558 100644 --- a/head/tutorials/index.html +++ b/head/tutorials/index.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/private_send.html b/head/tutorials/private_send.html index fe3d58f00..f5fb43243 100644 --- a/head/tutorials/private_send.html +++ b/head/tutorials/private_send.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/query_messages.html b/head/tutorials/query_messages.html index 8f4ffed67..e9cc2c35e 100644 --- a/head/tutorials/query_messages.html +++ b/head/tutorials/query_messages.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/rotate_dx_certs.html b/head/tutorials/rotate_dx_certs.html index b49a8ae3e..35be440bd 100644 --- a/head/tutorials/rotate_dx_certs.html +++ b/head/tutorials/rotate_dx_certs.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/tokens/erc1155.html b/head/tutorials/tokens/erc1155.html index fe5b09fcd..a658d2c8f 100644 --- a/head/tutorials/tokens/erc1155.html +++ b/head/tutorials/tokens/erc1155.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/tokens/erc20.html b/head/tutorials/tokens/erc20.html index 30092c5ba..6791a7131 100644 --- a/head/tutorials/tokens/erc20.html +++ b/head/tutorials/tokens/erc20.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/tokens/erc721.html b/head/tutorials/tokens/erc721.html index 5ea0a7549..6f1084d6d 100644 --- a/head/tutorials/tokens/erc721.html +++ b/head/tutorials/tokens/erc721.html @@ -196,7 +196,7 @@ WSAck diff --git a/head/tutorials/tokens/index.html b/head/tutorials/tokens/index.html index 836ba41d1..70a3d21e2 100644 --- a/head/tutorials/tokens/index.html +++ b/head/tutorials/tokens/index.html @@ -196,7 +196,7 @@ WSAck