github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-supply-chain-master/docs/source/family_specification.rst (about)

     1  ******************************************************
     2  Sawtooth Supply Chain Transaction Family Specification
     3  ******************************************************
     4  
     5  Overview
     6  ========
     7  
     8  The Sawtooth Supply Chain transaction family allows users to track
     9  goods as they move through a supply chain. Records for goods include a
    10  history of ownership and custodianship, as well as histories for a
    11  variety of properties such as temperature and location. These
    12  properties are managed through a user-specifiable system of record
    13  types.
    14  
    15  
    16  State
    17  =====
    18  
    19  All Supply Chain objects are serialized using Protocol Buffers before being
    20  stored in state. These objects include: Agents, Properties
    21  (accompanied by their auxiliary PropertyPage objects), Proposals,
    22  Records, and RecordTypes. As described in the Addressing_ section
    23  below, these objects are stored in separate sub-namespaces under the
    24  Supply Chain namespace. To handle hash collisions, all objects are stored in
    25  lists within protobuf "Container" objects.
    26  
    27  
    28  Records
    29  -------
    30  
    31  Records represent the goods being tracked by Supply Chain. Almost
    32  every transaction references some Record.
    33  
    34  A Record contains a unique identifier, the name of a RecordType, and
    35  lists containing the history of its owners and custodians. It also
    36  contains a ``final`` flag indicating whether further updates can be
    37  made to the Record and its Properties. If this flag is set to true,
    38  then no further updates can be made to the Record, including changing
    39  its ``final`` flag.
    40  
    41  .. code-block:: protobuf
    42  
    43     message Record {
    44         message AssociatedAgent {
    45             // The Agent's public key
    46             string agent_id = 1;
    47  
    48             // Approximately when this agent was associated, as a Unix UTC timestamp
    49             uint64 timestamp = 2;
    50         }
    51  
    52         // The unique user-defined natural key which identifies the
    53         // object in the real world (for example, a serial number)
    54         string identifier = 1;
    55  
    56         string record_type = 2;
    57  
    58         // Ordered oldest to newest by timestamp
    59         repeated AssociatedAgent owners = 3;
    60         repeated AssociatedAgent custodians = 4;
    61  
    62         // Flag indicating whether the Record can be updated. If it is set
    63         // to true, then the record has been finalized and no further
    64         // changes can be made to it or its Properties.
    65         bool final = 5;
    66     }
    67  
    68  
    69  Note that while information about a Record's owners and custodians are
    70  included in the object, information about its Properties are stored
    71  separately (see the Properties_ section below).
    72  
    73  Records whose addresses collide are stored in a list alphabetically by
    74  identifier.
    75  
    76  .. code-block:: protobuf
    77  
    78     message RecordContainer {
    79         repeated Record entries = 1;
    80     }
    81  
    82  .. _Properties:
    83  
    84  Properties
    85  ----------
    86  
    87  Historical data pertaining to a particular data field of a tracked
    88  object are stored as Properties, represented as a list of values
    89  accompanied by a timestamp and a reporter identifier.
    90  
    91  The whole history of updates to Record data is stored in current state
    92  because this allows for more flexibility in writing transaction rules.
    93  For example, in a fish track-and-trade system, there might be a rule
    94  that no fish can be exchanged whose temperature has gone above 40
    95  degrees. This means, however, that it would be impractical to store
    96  all of a Record's data at one address, since adding a single update
    97  would require reading the entire history of each of the Record's
    98  Properties out of state, adding the update, then writing it all back.
    99  
   100  To solve this problem, Properties are stored in their own namespace
   101  derived from their name and associated Record. Since some Properties
   102  may have thousands of updates, four characters are reserved at the end
   103  of that namespace in order to paginate a Property's history. The
   104  Property itself (along with name, Record identifier, authorized
   105  reporters, and paging information) is stored at the namespace ending
   106  in ``0000``. The namespaces ending in ``0001`` to ``ffff`` will each
   107  store a PropertyPage containing up to 256 reported values (which
   108  include timestamps and their reporter's identity). Any Transaction
   109  updating the value of a Property first reads out the PropertyContainer
   110  object at ``0000`` and then reads out the appropriate
   111  PropertyPageContainer before adding the update and writing the new
   112  PropertyPageContainer back to state.
   113  
   114  The Transaction Processor treats these pages as a ring buffer, so that
   115  when page ``ffff`` is filled, the next update will erase the entries
   116  at page ``0001`` and be stored there, and subsequent page-filling will
   117  continue to overwrite the next oldest page. This ensures no Property
   118  ever runs out of space for new updates. Under this scheme, 16^2 *
   119  (16^4 - 1) = 16776960 entries can be stored before older updates are
   120  overwritten.
   121  
   122  Updates to Properties can have one of the following protobuf types:
   123  ``bytes``, ``string``, ``sint64``, ``float``, or ``Location`` (see the
   124  section on RecordTypes_ below). The type of an update is indicated by
   125  a tag belonging to the PropertySchema object.
   126  
   127  .. code-block:: protobuf
   128  
   129     message Property {
   130         message Reporter {
   131             // The public key of the Agent authorized to report updates.
   132  	   string public_key = 1;
   133  
   134  	   // A flag indicating whether the reporter is authorized to
   135  	   // send updates. When a reporter is added, this is set to
   136  	   // true, and a `RevokeReporter` transaction sets it to false.
   137  	   bool authorized = 2;
   138  
   139  	   // An update must be stored with some way of identifying which
   140  	   // Agent sent it. Storing a full public key for each update would
   141  	   // be wasteful, so instead Reporters are identified by their index
   142  	   // in the `reporters` field.
   143  	   uint32 index = 3;
   144         }
   145  
   146         // The name of the Property, e.g. "temperature". This must be unique
   147         // among Properties.
   148         string name = 1;
   149  
   150         // The natural key of the Property's associated Record.
   151         string record_id = 2;
   152  
   153         // The Property's type (int, string, etc.)
   154         PropertySchema.DataType data_type = 3;
   155  
   156         // The Reporters authorized to send updates, sorted by index. New
   157         // Reporters should be given an index equal to the number of
   158         // Reporters already authorized.
   159         repeated Reporter reporters = 4;
   160  
   161         // The page to which new updates are added. This number represents
   162         // the last 4 hex characters of the page's address. Consequently,
   163         // it should not exceed 16^4 = 65536.
   164         uint32 current_page = 5;
   165  
   166         // A flag indicating whether the first 16^4 pages have been filled.
   167         // This is used to calculate the last four hex characters of the
   168         // address of the page containing the earliest updates. When it is
   169         // false, the earliest page's address will end in "0001". When it is
   170         // true, the earliest page's address will be one more than the
   171         // current_page, or "0001" if the current_page is "ffff".
   172         bool wrapped = 6;
   173     }
   174  
   175     message PropertyPage {
   176         message ReportedValue {
   177             // The index of the reporter id in reporters field
   178             uint32 reporter_index = 1;
   179             // Approximately when this value was reported, as a Unix UTC timestamp
   180             uint64 timestamp = 2;
   181  
   182             // The type-specific value of the update. Only one of these
   183             // fields should be used, and it should match the type
   184             // specified for this Property in the RecordType.
   185             bytes bytes_value = 11;
   186             string string_value = 12;
   187             sint64 int_value = 13;
   188             float float_value = 14;
   189             Location location_value = 15;
   190         }
   191  
   192         // The name of the page's associated Property and the record_id of
   193         // its associated Record. These are required to distinguish pages
   194         // with colliding addresses.
   195         string name = 1;
   196         string record_id = 2;
   197  
   198         // ReportedValues are sorted first by timestamp, then by reporter_index.
   199         repeated ReportedValue reported_values = 4;
   200     }
   201  
   202  
   203  Properties and PropertyPages whose addresses collide are stored in
   204  lists alphabetized by Property name.
   205  
   206  .. code-block:: protobuf
   207  
   208     message PropertyContainer {
   209         repeated Property entries = 1;
   210     }
   211  
   212     message PropertyPageContainer {
   213         repeated PropertyPage entries = 1;
   214     }
   215  
   216  .. _RecordTypes:
   217  
   218  Record Types
   219  ------------
   220  
   221  In order to validate incoming tracking data, Records are assigned a
   222  RecordType at creation. A RecordType is a user-defined list of
   223  PropertySchemas, each of which has a name and data type.
   224  PropertySchemas may be designated as ``required``. A required Property
   225  must be initialized with a value at the time of a Record's creation.
   226  For example, a ``Fish`` type might list ``species`` as required, but
   227  not ``temperature``, since temperature wouldn't be known until
   228  measurements were taken. Properties not specified at Record creation
   229  are initialized as empty lists.
   230  
   231  .. code-block:: protobuf
   232  
   233     message PropertySchema {
   234         enum DataType {
   235             BYTES = 0;
   236  	   STRING = 1;
   237  	   INT = 2;
   238  	   FLOAT = 3;
   239  	   LOCATION = 4;
   240         }
   241  
   242         // The name of the property, e.g. "temperature"
   243         string name = 1;
   244  
   245         // The Property's type (int, string, etc.)
   246         DataType data_type = 2;
   247  
   248         // A flag indicating whether initial values must be provided for the
   249         // Property when a Record is created.
   250         bool required = 3;
   251     }
   252  
   253  
   254     message RecordType {
   255         // A unique human-readable designation for the RecordType
   256         string name = 1;
   257  
   258         repeated PropertySchema properties = 2;
   259     }
   260  
   261  
   262  Each Record will have exactly the Properties listed in its type. New
   263  Records cannot be created without a type; consequently, a
   264  type-creation transaction must be executed before any Records can be
   265  created.
   266  
   267  RecordTypes whose addresses collide are stored in a list alphabetized
   268  by name.
   269  
   270  .. code-block:: protobuf
   271  
   272     message RecordTypeContainer {
   273         repeated RecordType entries = 1;
   274     }
   275  
   276  
   277  Because it is expected to be used for many RecordTypes, a dedicated
   278  Location protobuf message is used, the values of which are latitude
   279  and longitude.
   280  
   281  .. code-block:: protobuf
   282  
   283    message Location {
   284          // Coordinates are expected to be in millionths of a degree
   285          sint64 latitude = 1;
   286          sint64 longitude = 2;
   287    }
   288  
   289  
   290  Agents
   291  ------
   292  
   293  Agents are entities that can send transactions affecting Records. This
   294  could include not only humans and companies that act as owners and
   295  custodians of objects being tracked, but also autonomous sensors
   296  sending transactions that update Records' data. All Agents must be
   297  created (registered on-chain) before interacting with Records.
   298  
   299  .. code-block:: protobuf
   300  
   301      message Agent {
   302          // The Agent's public key. This must be unique.
   303          string public_key = 1;
   304  
   305          // A human-readable name identifying the Agent.
   306          string name = 2;
   307  
   308          // Approximately when the Agent was registered, as a Unix UTC timestamp
   309          uint64 timestamp = 3;
   310      }
   311  
   312  Agents whose keys have the same hash are stored in a list alphabetized
   313  by public key.
   314  
   315  .. code-block:: protobuf
   316  
   317      message AgentContainer {
   318          repeated Agent entries = 1;
   319      }
   320  
   321  
   322  Proposals
   323  ---------
   324  
   325  A Proposal is an offer from the owner or custodian of a Record to
   326  authorize another Agent as an owner, custodian, or reporter for that
   327  Record. Proposals are tagged as being for transfer of ownership,
   328  transfer of custodianship, or authorization of a reporter for some
   329  Properties. Proposals are also tagged as being open, accepted,
   330  rejected, or canceled. There cannot be more than one open Proposal for
   331  a specified role for each combination of Record, receiving Agent, and
   332  issuing Agent.
   333  
   334  .. code-block:: protobuf
   335  
   336     message Proposal {
   337         enum Role {
   338             OWNER = 1;
   339             CUSTODIAN = 2;
   340             REPORTER = 3;
   341         }
   342  
   343         enum Status {
   344             OPEN = 1;
   345             ACCEPTED = 2;
   346             REJECTED = 3;
   347             CANCELED = 4;
   348         }
   349  
   350         // The id of the Record with which this Proposal deals
   351         string record_id = 1;
   352  
   353         // Approximately when this proposal was created, as a Unix UTC timestamp
   354         uint64 timestamp = 2;
   355  
   356         // The public key of the Agent that created the Proposal
   357         string issuing_agent = 3;
   358  
   359         // The public key of the Agent to which the Proposal is addressed
   360         string receiving_agent = 4;
   361  
   362         // Whether the Proposal is for transfer of ownership or
   363         // custodianship or reporter authorization
   364         Role role = 5;
   365  
   366         // The names of properties for which the reporter is being authorized
   367         // (empty for owner or custodian transfers)
   368         repeated string properties = 6;
   369  
   370         // Whether the Proposal is open, accepted, rejected, or canceled.
   371         // For a given Record and receiving Agent, there can be only one
   372         // open Proposal at a time for each role.
   373         Status status = 7;
   374  
   375         // human-readable terms of transfer
   376         string terms = 8;
   377     }
   378  
   379  
   380  Proposals with the same address are stored in a list sorted
   381  alphabetically first by ``record_id``, then by ``receiving_agent``,
   382  then by ``timestamp`` (earliest to latest).
   383  
   384  .. code-block:: protobuf
   385  
   386     message ProposalContainer {
   387         repeated Proposal entries = 1;
   388     }
   389  
   390  .. _Addressing:
   391  
   392  Addressing
   393  ----------
   394  
   395  Supply Chain objects are stored under the namespace obtained by taking the
   396  first six characters of the SHA-512 hash of the string
   397  ``supply_chain``:
   398  
   399  .. code-block:: pycon
   400  
   401     >>> def get_hash(string):
   402     ...     return hashlib.sha512(string.encode('utf-8')).hexdigest()
   403     ...
   404     >>> get_hash('supply_chain')[:6]
   405     '3400de'
   406  
   407  After its namespace prefix, the next two characters of a Supply Chain object's
   408  address are a string based on the object's type:
   409  
   410  - Agent: ``ae``
   411  - Property / PropertyPage: ``ea``
   412  - Proposal: ``aa``
   413  - Record: ``ec``
   414  - Record Type: ``ee``
   415  
   416  The remaining 62 characters of an object's address are determined by
   417  its type:
   418  
   419  - Agent: the first 62 characters of the hash of its public key.
   420  - Property: the concatenation of the following:
   421  
   422    - The first 36 characters of the hash of the identifier of its
   423      associated Record plus the first 22 characters of the hash of its
   424      Property name.
   425    - The string ``0000``.
   426  
   427  - PropertyPage: the address of the page to which updates are to be
   428    written is the concatenation of the following:
   429  
   430    - The first 36 characters of the hash of the identifier of its
   431      associated Record.
   432    - The first 22 characters of the hash of its Property name.
   433    - The hex representation of the ``current_page`` of its associated
   434      Property left-padded to length 4 with 0s.
   435  
   436  - Proposal: the concatenation of the following:
   437  
   438    - The first 36 characters of the hash of the identifier of
   439      its associated Record.
   440    - The first 22 characters of its ``receiving_agent``.
   441    - The first 4 characters of the hash of its ``timestamp``.
   442  
   443  - Record: the first 62 characters of the hash of its identifier.
   444  - Record Type: the first 62 characters of the hash of the name of the
   445    type.
   446  
   447  For example, if ``fish-456`` is a Record with a ``temperature``
   448  Property and a ``current_page`` of 28, the address for that
   449  PropertyPage is:
   450  
   451  .. code-block:: pycon
   452  
   453      >>> get_hash('supply_chain')[:6] + 'ea'  + get_hash('fish-456')[:36] + get_hash('temperature')[:22] + hex(28)[2:].zfill(4)
   454      '3400deea840d00edc7507ed05cfb86938e3624ada6c7f08bfeb8fd09b963f81f9d001c'
   455  
   456  
   457  Transactions
   458  ============
   459  
   460  Transaction Payload
   461  -------------------
   462  
   463  All Supply Chain transactions are wrapped in a tagged payload object to allow
   464  for the transaction to be dispatched to appropriate handling logic.
   465  
   466  .. code-block:: protobuf
   467  
   468     message SCPayload {
   469         enum Action {
   470             CREATE_AGENT = 1;
   471             CREATE_RECORD = 2;
   472             FINALIZE_RECORD = 3;
   473             CREATE_RECORD_TYPE = 4;
   474             UPDATE_PROPERTIES = 5;
   475             CREATE_PROPOSAL = 6;
   476             ANSWER_PROPOSAL = 7;
   477             REVOKE_REPORTER = 8;
   478         }
   479  
   480         Action action = 1;
   481  
   482         // Approximately when transaction was submitted, as a Unix UTC timestamp
   483         uint64 timestamp = 2;
   484  
   485         CreateAgentAction create_agent = 3;
   486         CreateRecordAction create_record = 4;
   487         FinalizeRecordAction finalize_record = 5;
   488         CreateRecordTypeAction create_record_type = 6;
   489         UpdatePropertiesAction update_properties = 7;
   490         CreateProposalAction create_proposal = 8;
   491         AnswerProposalAction answer_proposal = 9;
   492         RevokeReporterAction revoke_reporter = 10;
   493     }
   494  
   495  
   496  Any transaction is invalid if its timestamp is greater than the
   497  validator's system time.
   498  
   499  
   500  Create Agent
   501  ------------
   502  
   503  Create an Agent that can interact with Records. The ``signer_pubkey``
   504  in the transaction header is used as the Agent's public key.
   505  
   506  .. code-block:: protobuf
   507  
   508     message CreateAgentAction {
   509        // The human-readable name of the Agent, not necessarily unique
   510        string name = 1;
   511     }
   512  
   513  
   514  A CreateAgent transaction is invalid if there is already an Agent with
   515  the signer's public key or if the name is the empty string.
   516  
   517  
   518  .. _CreateRecord:
   519  
   520  Create Record
   521  -------------
   522  
   523  When an Agent creates a Record, the Record is initialized with that
   524  Agent as both owner and custodian. Any Properties required of the
   525  Record by its RecordType must have initial values provided.
   526  
   527  .. code-block:: protobuf
   528  
   529     message PropertyValue {
   530         // The name of the property being set
   531         string name = 1;
   532         PropertySchema.DataType data_type = 2;
   533  
   534         // The type-specific value to initialize or update a Property. Only
   535         // one of these fields should be used, and it should match the type
   536         // specified for this Property in the RecordType.
   537         bytes bytes_value = 11;
   538         string string_value = 12;
   539         sint64 int_value = 13;
   540         float float_value = 14;
   541         Location location_value = 15;
   542     }
   543  
   544     message CreateRecordAction {
   545         // The natural key of the Record
   546         string record_id = 1;
   547  
   548         // The name of the RecordType this Record belongs to
   549         string record_type = 2;
   550  
   551         repeated PropertyValue properties = 3;
   552     }
   553  
   554  
   555  A CreateRecord transaction is invalid if one of the following
   556  conditions occurs:
   557  
   558  - The signer is not registered as an Agent.
   559  - The identifier is the empty string.
   560  - The identifier belongs to an existing Record.
   561  - A valid RecordType is not specified.
   562  - Initial values are not provided for all of the Properties specified
   563    as required by the RecordType.
   564  - Initial values of the wrong type are provided.
   565  
   566  
   567  Finalize Record
   568  ---------------
   569  
   570  A FinalizeRecord Transaction sets a Record’s ``final`` flag to true. A
   571  finalized Record and its Properties cannot be updated. A Record cannot
   572  be finalized except by its owner, and cannot be finalized if the owner
   573  and custodian are not the same.
   574  
   575  .. code-block:: protobuf
   576  
   577     message FinalizeRecordAction {
   578         string record_id = 1;
   579     }
   580  
   581  
   582  A FinalizeRecord transaction is invalid if one of the following
   583  conditions occurs:
   584  
   585  - The Record it targets does not exist.
   586  - The Record it targets is already final.
   587  - The signer is not both the Record's owner and custodian.
   588  
   589  
   590  Create Record Type
   591  ------------------
   592  
   593  The payload of the Transaction that creates RecordTypes is the same as
   594  the RecordType object itself: it has a name and a list of Properties.
   595  
   596  .. code-block:: protobuf
   597  
   598     message CreateRecordTypeAction {
   599         string name = 1;
   600  
   601         repeated PropertySchema properties = 2;
   602     }
   603  
   604  
   605  A CreateRecordType transaction is invalid if one of the following
   606  conditions occurs:
   607  
   608  - The signer is not registered as an Agent.
   609  - Its list of Properties is empty.
   610  - The name of the RecordType is the empty string.
   611  - A RecordType with its name already exists.
   612  
   613  
   614  Update Properties
   615  -----------------
   616  
   617  An UpdateProperties transaction contains a ``record_id`` and a list of
   618  PropertyValues (see CreateRecord_ above). It can only be (validly)
   619  sent by an Agent authorized to report on the Property.
   620  
   621  .. code-block:: protobuf
   622  
   623     message UpdatePropertiesAction {
   624         // The natural key of the Record
   625         string record_id = 1;
   626  
   627         repeated PropertyValue properties = 2;
   628     }
   629  
   630  
   631  An UpdateProperties transaction is invalid if one of the following
   632  conditions occurs:
   633  
   634  - The Record does not exist.
   635  - The Record is final.
   636  - Its signer is not authorized to report on that Record.
   637  - None of the provided PropertyValues match the types specified in the
   638    Record's RecordType.
   639  
   640  
   641  Create Proposal
   642  ---------------
   643  
   644  A CreateProposal transaction creates an open Proposal concerning some
   645  Record from the signer to the receiving Agent. This Proposal can be
   646  for transfer of ownership, transfer of custodianship, or authorization
   647  to report. If it is a reporter authorization Proposal, a nonempty list
   648  of Property names must be included.
   649  
   650  .. code-block:: protobuf
   651  
   652     message CreateProposalPayload {
   653         enum Role {
   654             OWNER = 1;
   655             CUSTODIAN = 2;
   656             REPORTER = 3;
   657         }
   658  
   659         string record_id = 1;
   660  
   661         // The public key of the Agent to whom the Proposal is sent
   662         // (must be different from the Agent sending the Proposal).
   663         string receiving_agent = 3;
   664  
   665         repeated string properties = 4;
   666  
   667         Role role = 5;
   668     }
   669  
   670  
   671  A CreateProposal transaction is invalid if one of the following
   672  conditions occurs:
   673  
   674  - The signer is not the owner and the Proposal is for transfer of
   675    ownership or reporter authorization.
   676  - The signer is not the custodian and the Proposal is for transfer of
   677    custodianship.
   678  - The receiving Agent is not registered (the signer must be registered
   679    as well, but this is implied by the previous two conditions).
   680  - There is already an open Proposal for the Record and receiving Agent
   681    for the specified role.
   682  - The Record is final.
   683  - The Proposal is for reporter authorization and the list of Property
   684    names is empty.
   685  
   686  
   687  Answer Proposal
   688  ---------------
   689  
   690  An Agent who is the receiving Agent for a Proposal for some Record can
   691  accept or reject that Proposal, marking the Proposal's status as
   692  ``accepted`` or ``rejected``. The Proposal's ``issuing_agent`` cannot
   693  accept or reject it, but can cancel it. This will mark the Proposal's
   694  status as ``canceled`` rather than ``rejected``.
   695  
   696  .. code-block:: protobuf
   697  
   698     message AnswerProposalPayload {
   699         enum Role {
   700             OWNER = 1;
   701             CUSTODIAN = 2;
   702             REPORTER = 3;
   703         }
   704  
   705         enum Response {
   706             ACCEPT = 1;
   707             REJECT = 2;
   708             CANCEL = 3;
   709         }
   710  
   711         string record_id = 1;
   712         string receiving_agent = 2;
   713         Role role = 3;
   714         Response response = 4;
   715     }
   716  
   717  
   718  Proposals can conflict, in the sense that a Record's owner might have
   719  opened ownership transfer Proposals with several Agents at once. These
   720  Proposals will not be closed if one of them is accepted. Instead, an
   721  ``accept`` answer will check to verify that the issuing Agent is still
   722  the owner or custodian of the Record.
   723  
   724  An AnswerProposal transaction is invalid if one of the following
   725  conditions occurs:
   726  
   727  - There is no Proposal for that receiving agent, record, and role.
   728  - The signer is not the receiving or issuing Agent of the Proposal.
   729  - The signer is the receiving Agent and answers ``cancel``.
   730  - The signer is the issuing Agent and answers anything other than
   731    ``cancel``.
   732  - The response is ``accept``, but the issuing Agent is no longer the
   733    owner or custodian (as appropriate to the role) of the Record.
   734  
   735  
   736  Revoke Reporter
   737  ---------------
   738  
   739  The owner of a Record can send a RevokeReporter transaction to remove
   740  a reporter's authorization to report on one or more Properties for
   741  that Record. This creates a Proposal which is immediately closed and
   742  marked as accepted.
   743  
   744  .. code-block:: protobuf
   745  
   746     message RevokeReporterPayload {
   747         string record_id = 1;
   748         string reporter_id = 2;
   749  
   750         // the Properties for which the reporter's authorization is revoked
   751         repeated string properties = 3;
   752     }
   753  
   754  A RevokeReporter transaction is invalid if one of the following
   755  conditions occurs:
   756  
   757  - The Record does not exist.
   758  - The Record is final.
   759  - The signer is not the Record's owner.
   760  - The reporter whose authorization is to be revoked is not an
   761    authorized reporter for the Record.