The Transactor peer nodes are responsible for writing data to the system and ensuring consistency.
Transactors have two main client-facing interfaces:
- writing data to persistent storage (e.g. IPFS) on behalf of clients
- informing clients of changes to the Journal when updates are made
As well as "internal" responsibilities:
- maintaining the chain of updates for metadata entries
- communication with other transactor nodes to achieve consensus
The transactor accepts data in the format described by RFC-1, with the
important exception that the chain
field for the various ChainCell
s is not
filled in by the client.
Since non-Transactor peers do not participate in the consensus process, they cannot know with certainty whether their pointer to the head of a given chain will still be correct when the transaction is committed and written to the Journal.
RFC-2 describes a strategy for resolving conflicting updates with "merge" cells that resolve forks into a single chain while preserving the data from both forks.
In the short term, our plan is for client nodes to defer the "chaining" of
updates to the Transactor peers. A client will therefore submit updates
with all information except the chain
field, which will be determined by
the Transactor when the update is committed.
This has implications for signing, in that the chain
field will need to be
omitted when verifying signatures for a cell, as it is unavailable to the client
when signing.
There are two fundamental write operations that clients can submit:
- creation of a new Canonical metadata entry (
Entity
orArtefact
) - updates to an existing entry
In both cases, RPC messages are sent to a service endpoint requesting that the data be added to the system. The format of the messages should track closely to that described in RFC-1.
The server will respond synchronously with either an "acknowledgement" response, or a validation error if the message cannot be parsed or otherwise fails an initial validation pass.
Importantly, the initial validation does not ensure that the data is guaranteed
to be accepted, only that it is consistent with the expected format, and that it
has no "dangling references", etc. For example, attempting to issue an update
to a non-existent Artefact
would immediately fail. Other causes of validation
failure might include failing to conform to an expected schema (an invalid
timestamp
format, for example), or trying to submit an EntityUpdateCell
that
refers to an Artefact
instead of an Entity
.
In other words, initial validation only covers what can be known at the immediate time of submission. However, since the block consensus protocol for confirming a transaction may take an indeterminate amount of time, it is undesirable to "block" the connection until confirmation occurs. Instead, the transactor returns an immediate validation response, and the client must track journal updates to confirm that the data was written successfully.
Alternatively, the acknowledgement response could include a unique token that identifies the write request. When the transaction completes (successfully or otherwise), the Transactor can send a message to the client with the status and include the token. The client can then either mark the transaction as successful, or retry on failure if possible.
To be honest I am not 100% sure whether we decided to go with this approach (omit
chain
, transactor linearizes and writes to IPFS) or a lightweight version of the RFC-specified approach (client writes to IPFS, transactor accepts, we assume no conflicts for now) as the first to implement API. The signature stuff does make things a bit hairier in the former case.