Skip to content

Commit

Permalink
Merge pull request #1554 from hyperledger/docs_v1.3.1_awr
Browse files Browse the repository at this point in the history
Additional info and clarification in listener docs
  • Loading branch information
awrichar authored Aug 5, 2024
2 parents 5cf2669 + 0a9a64c commit c5718bb
Showing 1 changed file with 66 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,95 @@ a walk-through of how to set up listeners for the events from your smart contrac

See below for a deep dive into the format of contract listeners and important concepts to understand when managing them.

### Multiple filters
### Event filters

From v1.3.1 onwards, a contract listener can be created with multiple filters under a single topic when supported by the connector.
#### Multiple filters

Before this change, each contract listener would only support listening to one specific event from an interface previously defined. Each listener would be comprised of:
From v1.3.1 onwards, a contract listener can be created with multiple filters under a single topic, when supported by the connector. Each filter contains:

- a reference to a specific blockchain event to listen for
- (optional) a specific location/address to listen from
- a connector-specific signature (generated from the event), which allows you to easily identify and search for the contact listener for an event
- a `topic` which determines the ordered stream that these events are part of
- a connector-specific signature (generated from the event and the location)

This format is still supported by the API. However, it may not fully guarantee accurate ordering of events coming from multiple listeners, even if they share the same `topic` (such as during cases of blockchain catch-up, or when one listener is created much later than the others).
In addition to this list of multiple filters, the listener specifies a single `topic` to identify the stream of events.

From v1.3.1, you can supply multiple filters on a single listener. Each filter contains:
Creating a single listener that listens for multiple events will allow for the easiest management of listeners, and for strong ordering of the events that they process.

#### Single filter

Before v1.3.1, each contract listener would only support listening to one specific event from a contract interface. Each listener would be comprised of:

- a reference to a specific blockchain event to listen for
- (optional) a specific location/address to listen from
- a connector-specific signature (generated from the event and the location)
- a connector-specific signature (generated from the event), which allows you to easily identify and search for the contact listener for an event
- a `topic` which determines the ordered stream that these events are part of

For backwards compatibility, this format is still supported by the API.

### Signature strings

#### String format

Each filter is identified by a generated `signature` that matches a single event, and each contract listener is identified by a `signature` computed from its filters.

Ethereum provides a string standard for event signatures, of the form `EventName(uint256,bytes)`. Prior to v1.3.1, the signature of each Ethereum contract listener would exactly follow this Ethereum format.

As of v1.3.1, Ethereum signature strings have been changed, because this format does not fully describe the event - particularly because each top-level parameter can in the ABI definition be marked as `indexed`. For example, while the following two Solidity events have the same signature, they are serialized differently due to the different placement of `indexed` parameters, and thus a listener must define both individually to be able to process them:

- ERC-20 `Transfer`

```solidity
event Transfer(address indexed _from, address indexed _to, uint256 _value)
```

- ERC-721 `Transfer`

```solidity
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
```

The two above are now expressed in the following manner by the Ethereum blockchain connector:

```solidity
Transfer(address,address,uint256) [i=0,1]
Transfer(address,address,uint256) [i=0,1,2]
```

The `[i=]` listing at the end of the signature indicates the position of all parameters that are marked as `indexed`.

Building on the blockchain-specific signature format for each event, FireFly will then compute the final signature for each filter and each contract listener as follows:

In addition to this list of multiple filters, the listener specifies a single `topic` to identify the stream of events. This new feature will allow better management of contract listeners and strong ordering of all of the events your application cares about.
- Each filter signature is a combination of the location and the specific connector event signature, such as `0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1:Changed(address,uint256) [i=0]`
- Each contract listener signature is a concatenation of all the filter signatures, separated by `;`

Note: For backwards compatibility, the response from the API will populate top-level `event` and `location` fields with the contents of the first event filter in the array.
#### Duplicate filters

### Duplicate filters
FireFly restricts the creation of a contract listener containing duplicate filters.

FireFly will restrict the creation of a contract listener with duplicate filters or superset filters. For example, if two filters are listening to the same event, but one has specified a location and the other hasn't, then the latter will be a superset, and already be listening to all the events matching the first filter. Creation of duplicate or superset filters will be blocked.
This includes the special case where one filter is a superset of another filter, due to a wildcard location.

### Duplicate listeners
For example, if two filters are listening to the same event, but one has specified a location and the other hasn't, then the latter will be a superset, and already be listening to all the events matching the first filter. Creation of duplicate or superset filters within a single listener will be blocked.

As of v1.3.1, each filter on a listener includes a signature generated from the filter location + event, and the listener concatenates all of these signatures to build the overall contract listener signature. This contract listener signature - containing all the locations and event signatures combined with the listener topic - will guarantee uniqueness of the contract listener. If you tried to create the same listener again, you would receive HTTP 409. This combination can allow a developer to assert that their listener exists, without the risk of creating duplicates.
#### Duplicate listeners

Note: Prior to v1.3.1, FireFly would detect duplicates simply by requiring a unique combination of signature + topic + location for each listener. When using muliple filters, we cannot rely on the signature of one event and the location of one filter to calculate uniqueness of a contract listener, hence the need for the more sophisticated uniqueness checks described here.
As noted above, each listener has a generated signature. This signature - containing all the locations and event signatures combined with the listener topic - will guarantee uniqueness of the contract listener. If you tried to create the same listener again, you would receive HTTP 409. This combination can allow a developer to assert that their listener exists, without the risk of creating duplicates.

### Signature enhancements
**Note:** Prior to v1.3.1, FireFly would detect duplicates simply by requiring a unique combination of signature + topic + location for each listener. The updated behavior for the listener signature is intended to preserve similar functionality, even when dealing with listeners that contain many event filters.

As mentioned above, we have introduced a new format for signatures of contract listener and filter signature:
### Backwards compatibility

- Each filter signature will be a combination of the location and the specific connector event signature
- Each contract listener signature will be a concatenation of all the filter signatures
As noted throughout this document, the behavior of listeners is changed in v1.3.1. However, the following behaviors are retained for backwards-compatibility, to ensure that code written prior to v1.3.1 should continue to function.

Furthermore, because Ethereum ABI does not include a differentiation between indexed and non-indexed fields, we have included a new section in the Ethereum-specific event signature to add the index of the indexed fields. As such, a filter listening to the event `Changed(address indexed from, uint256 value)` at address `0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1` will result in `0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1:Changed(address,uint256) [i=0]` where `[i=0]` specifies that the first field is indexed. If there were more indexed fields, it will be a comma-separated list of the index of those indexed fields such as `[i=0,2,3]` (specifies that fields at index 0, 2, and 3 are indexed fields).
- The response from all query APIs of `listeners` will continue to populate top-level `event` and `location` fields
- The first entry from the `filters` array is duplicated to these fields
- On input to create a new `listener`, the `event` and `location` fields are still supported
- They function identically to supplying a `filters` array with a single entry
- The `signature` field is preserved at the listener level
- The format has been changed as described above

### Formats supported
### Input formats

As described above, there are two input formats supported by the API for backwards compatibility with previous releases.
The two input formats supported when creating a contract listener are shown below.

**Muliple Filters**

Expand Down

0 comments on commit c5718bb

Please sign in to comment.