github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/docs/source/architecture/events_and_transactions_receipts.rst (about)

     1  *******************************
     2  Events and Transaction Receipts
     3  *******************************
     4  
     5  Hyperledger Sawtooth supports creating and broadcasting events.
     6  This allows applications to do the following:
     7  
     8  - Subscribe to events that occur related to the blockchain, such
     9    as a new block being committed or switching to a new fork.
    10  - Subscribe to application specific events defined by a transaction family.
    11  - Relay information about the execution of a transaction back to
    12    clients without storing that data in state.
    13  
    14  .. image:: ../images/event_subsystem.*
    15     :width: 80%
    16     :align: center
    17     :alt: Event Subsystem
    18  
    19  .. _events-reference-label:
    20  
    21  Events
    22  ======
    23  
    24  Events are represented with the following protobuf message:
    25  
    26  .. code-block:: protobuf
    27  
    28    message Event {
    29      // Used to subscribe to events and servers as a hint for how to deserialize
    30      // event_data and what pairs to expect in attributes.
    31      string event_type = 1;
    32  
    33      // Transparent data defined by the event_type.
    34      message Attribute {
    35        string key = 1;
    36        string value = 2;
    37      }
    38      repeated Attribute attributes = 2;
    39  
    40      // Opaque data defined by the event_type.
    41      bytes  data = 3;
    42    }
    43  
    44  
    45  Events are extracted from other data structures such as blocks or
    46  transaction receipts. In order to treat this extraction uniformly, an
    47  EventExtractor interface is implemented for each event source. The
    48  EventExtractor interface takes a list of EventSubscriptions and will only
    49  generate events that are in the union of all subscriptions. An event is "in a
    50  subscription" if the event's event_type field matches the subscription's
    51  event_type field and the filter's key-value pair (if the subscription has
    52  any filters) matches a key-value pair in the event's attribute field.
    53  
    54  .. code-block:: python
    55  
    56    interface EventExtractor:
    57      // Construct all the events of interest by taking the union of all subscriptions.
    58      // One extractor should be created for each input source that events can be
    59      // extracted from. This input source should be passed to the implementation through
    60      // the constructor.
    61      extract(list<EventSubscription> subscriptions) -> list<Event>
    62  
    63    // If no subscriptions of a given event_type are passed to EventExtractor.extract,
    64    // the extractor does not need to return events of that type.
    65    class EventSubscription:
    66      string event_type
    67      list<EventFilter> filters
    68  
    69  The following filters are implemented:
    70  
    71  SIMPLE_ANY
    72    Represents a subset of events within an event type.
    73  
    74    Since multiple event attributes with the same key can be present in an
    75    event, an event is considered part of this filter if its match string matches
    76    the value of ANY attribute with the filter's key.
    77  
    78    For example, if an event has the following attributes:
    79  
    80        - Attribute(key="address", value="abc")
    81        - Attribute(key="address", value="def")
    82  
    83    it will pass the following filter:
    84  
    85        SimpleAnyFilter(key="address", match_string"abc")
    86  
    87    Because it matches one of the two attributes with the key "address".
    88  
    89  SIMPLE_ALL
    90    Represents a subset of events within an event type.
    91  
    92    Since multiple event attributes with the same key can be present in an
    93    event, an event is considered part of this filter if its match string matches
    94    the value of ALL attribute with the filter's key.
    95  
    96    For example, if an event has the following attributes:
    97  
    98        - Attribute(key="address", value="abc")
    99        - Attribute(key="address", value="def")
   100  
   101    it will NOT pass this filter:
   102  
   103        SimpleAllFilter(key="address", value="abc")
   104  
   105    Because it does not match all attributes with the key "address".
   106  
   107  REGEX_ANY
   108    Represents a subset of events within an event type. Pattern must be a
   109    valid regular expression that can be compiled by the re module.
   110  
   111    Since multiple event attributes with the same key can be present in an
   112    event, an event is considered part of this filter if its pattern matches
   113    the value of ANY attribute with the filter's key.
   114  
   115    For example, if an event has the following attributes:
   116  
   117        - Attribute(key="address", value="abc")
   118        - Attribute(key="address", value="def")
   119  
   120    it will pass the following filter:
   121  
   122        AnyRegexFilter(key="address", value="abc")
   123  
   124    Because it matches one of the two attributes with the key "address".
   125  
   126  REGEX_ALL
   127    Represents a subset of events within an event type. Pattern must be a
   128    valid regular expression that can be compiled by the re module.
   129  
   130    Since multiple event attributes with the same key can be present in an
   131    event, an event is considered part of this filter if its pattern matches
   132    the value of ALL attribute with the filter's key.
   133  
   134    For example, if an event has the following attributes:
   135  
   136        - Attribute(key="address", value="abc")
   137        - Attribute(key="address", value="def")
   138  
   139    it will NOT pass this filter:
   140  
   141        AllRegexFilter(key="address", value="abc")
   142  
   143    Because it does not match all attributes with the key "address".
   144  
   145  An EventBroadcaster manages external event subscriptions and forwards events to
   146  subscribers as they occur. In order for the EventBroadcaster to learn about
   147  events, the ChainController class implements the Observer pattern. The
   148  ChainController acts as the subject and observers of the ChainController
   149  implement the ChainObserver interface.
   150  
   151  .. code-block:: python
   152  
   153    interface ChainObserver:
   154      // This method is called by the ChainController on block boundaries.
   155      chain_update(Block block, list<TransactionReceipt> receipts)
   156  
   157    class EventBroadcaster:
   158      // Register the subscriber for the given event subscriptions and begin sending it
   159      // events on block boundaries.
   160      //
   161      // If any of the block ids in last_known_block_ids are part of the current chain,
   162      // the observer will be notified of all events that it would have received based on
   163      // its subscriptions for each block in the chain since the most recent
   164      // block in last_known_block_ids.
   165      //
   166      // Raises an exception if:
   167      // 1. The subscription is unsuccessful.
   168      // 2. None of the block ids in last_known_block_ids are part of the current chain.
   169      add_subscriber(string connection_id, list<EventSubscription> subscriptions,
   170                     list<string> last_known_block_ids)
   171  
   172      // Stop sending events to the subscriber
   173      remove_subscriber(string connection_id)
   174  
   175      // Notify all observers of all events they are subscribed to.
   176      chain_update(Block block, list<TransactionReceipt> receipts)
   177  
   178  
   179  On receiving a chain_update() notification from the ChainController, the
   180  EventBroadcaster instantiates a new EventExtractor, passes each extractor all
   181  the EventSubscriptions for all subscribers, and receives the list of events
   182  that is the union of the events that all subscribers are interested in. The
   183  EventBroadcaster then distributes the events to each subscriber based on
   184  the subscriber's list of subscriptions.
   185  
   186  To reduce the number of messages sent to subscribers, multiple Event messages
   187  are wrapped in an EventList message when possible:
   188  
   189  .. code-block:: python
   190  
   191    EventList {
   192      repeated Event events = 1;
   193    }
   194  
   195  ClientEventSubscribeRequest messages are sent by external clients to the
   196  validator in order to subscribe to events. ClientEventSubscribeResponse messages
   197  are sent by the validator to the client in response to notify the client whether
   198  their subscription was successful. When an external client subscribes to events,
   199  they may optionally send a list of block ids along with their subscriptions. If
   200  any of the blocks sent are in the current chain, the EventBroadcaster will bring
   201  the client up to date by sending it events for all blocks since the most recent
   202  block sent with the subscribe request.
   203  
   204  .. code-block:: protobuf
   205  
   206    message ClientEventsSubscribeRequest {
   207        repeated EventSubscription subscriptions = 1;
   208        // The block id (or ids, if trying to walk back a fork) the subscriber last
   209        // received events on. It can be set to empty if it has not yet received the
   210        // genesis block.
   211        repeated string last_known_block_ids = 2;
   212    }
   213  
   214    message ClientEventsSubscribeResponse {
   215        enum Status {
   216             OK = 0;
   217             INVALID_FILTER = 1;
   218             UNKNOWN_BLOCK = 2;
   219        }
   220        Status status = 1;
   221        // Additional information about the response status
   222        string response_message = 2;
   223    }
   224  
   225  Event Extractors
   226  ----------------
   227  
   228  Two event extractors are created to extract events from blocks and
   229  transaction receipts: BlockEventExtractor and ReceiptEventExtractor. The
   230  BlockEventExtractor will extract events of type "sawtooth/block-commit". The
   231  ReceiptEventExtractor will extract events of type "sawtooth/state-delta" and
   232  events defined by transaction families.
   233  
   234  Example events generated by BlockEventExtractor:
   235  
   236  .. code-block:: protobuf
   237  
   238    // Example sawtooth/block-commit event
   239    Event {
   240      event_type = "sawtooth/block-commit",
   241      attributes = [
   242        Attribute { key = "block_id", value = "abc...123" },
   243        Attribute { key = "block_num", value = "523" },
   244        Attribute { key = "state_root_hash", value = "def...456" },
   245        Attribute { key = "previous_block_id", value = "acf...146" },
   246      ],
   247    }
   248  
   249  Example events generated by ReceiptEventExtractor:
   250  
   251  .. code-block:: protobuf
   252  
   253  
   254    // Example transaction family specific event
   255    Event {
   256      event_type = "xo/create",
   257      attributes = [Attribute { key = "game_name", value = "game0" }],
   258    }
   259  
   260    // Example sawtooth/block-commit event
   261    Event {
   262      event_type = "sawtooth/state-delta",
   263      attributes = [Attribute { key = "address", value = "abc...def" }],
   264      event_data = <bytes>
   265    }
   266  
   267  
   268  Transaction Receipts
   269  ====================
   270  
   271  Transaction receipts provide clients with information that is related to the
   272  execution of a transaction but should not be stored in state, such as:
   273  
   274     - Whether the transaction was valid
   275     - How the transaction changed state
   276     - Events of interest that occurred during execution of the transaction
   277     - Other transaction-family-specific execution information
   278  
   279  Transaction receipts can also provide the validator with information about
   280  transaction execution without re-executing the transaction.
   281  
   282  Sawtooth transaction receipts are represented as a protobuf message when exposed
   283  to clients. A transaction receipt contains a list of StateChange messages, a
   284  list of Event messages, and a list of TransactionReceipt.Data messages:
   285  
   286  .. code-block:: protobuf
   287  
   288    message TransactionReceipt {
   289      // State changes made by this transaction
   290      // StateChange is already defined in protos/state_delta.proto
   291      repeated StateChange state_changes = 1;
   292      // Events fired by this transaction
   293      repeated Event events = 2;
   294      // Transaction family defined data
   295      repeated bytes data = 3;
   296  
   297      string transaction_id = 4;
   298    }
   299  
   300  The fields in the TransactionReceipt.Data are opaque to Sawtooth and their
   301  interpretation is left up to the transaction family. TransactionReceipt.Data
   302  can be requested for a transaction that has been committed and should only be
   303  used to store information about a transaction’s execution that should not be
   304  kept in state.  Clients can use the event system described above to subscribe to
   305  events produced by transaction processors.
   306  
   307  Transaction Receipt Store
   308  -------------------------
   309  
   310  The TransactionReceiptStore class stores receipts. New receipts are written to
   311  the TransactionReceiptStore after a block is validated.
   312  
   313  Transaction receipts will only be stored in this off-chain store and will not
   314  be included in the block. Note that because a transaction may exist in multiple
   315  blocks at a time, the transaction receipt is stored by both transaction id and
   316  block state root hash.
   317  
   318  .. code-block:: python
   319  
   320    class TransactionReceiptStore:
   321    	def put_receipt(self, txn_id, receipt):
   322        	"""Add the given transaction receipt to the store. Does not guarantee
   323           	it has been written to the backing store.
   324  
   325        	Args:
   326            	txn_id (str): the id of the transaction being stored.
   327            	state_root_hash: the state root of the block this transaction was
   328              executed in.
   329            	receipt (TransactionReceipt): the receipt object to store.
   330        	"""
   331  
   332    	def get_receipt(self, txn_id):
   333        	"""Returns the TransactionReceipt
   334  
   335        	Args:
   336            	txn_id (str): the id of the transaction for which the receipt
   337              should be retrieved.
   338            	state_root_hash: the state root of the block this transaction was
   339              executed in.
   340  
   341        	Returns:
   342            	TransactionReceipt: The receipt for the given transaction id.
   343  
   344        	Raises:
   345            	KeyError: if the transaction id is unknown.
   346        	"""
   347  
   348  Message Handlers
   349  ----------------
   350  
   351  Once transaction receipts are stored in the TransactionReceiptStore, clients
   352  can request a transaction receipt for a given transaction id.
   353  
   354  .. code-block:: protobuf
   355  
   356    // Fetches a specific txn by its id (header_signature) from the blockchain.
   357    message ClientReceiptGetRequest {
   358        repeated string transaction_ids = 1;
   359    }
   360  
   361    // A response that returns the txn receipt specified by a
   362    // ClientReceiptGetRequest.
   363    //
   364    // Statuses:
   365    //   * OK - everything worked as expected, txn receipt has been fetched
   366    //   * INTERNAL_ERROR - general error, such as protobuf failing to deserialize
   367    //   * NO_RESOURCE - no receipt exists for the transaction id specified
   368    message ClientReceiptGetResponse {
   369        enum Status {
   370            OK = 0;
   371            INTERNAL_ERROR = 1;
   372            NO_RESOURCE = 4;
   373        }
   374        Status status = 1;
   375        repeated TransactionReceipt receipts = 2;
   376  
   377  .. Licensed under Creative Commons Attribution 4.0 International License
   378  .. https://creativecommons.org/licenses/by/4.0/