This document outlines a data model and syntax for expressing a set of ordered events in a decentralized system in way that can be cryptographically verified. This technology is useful when coordinating the recording of events, such as financial transactions, transfer of property, or time-stamped data that must be shared among coordinating parties. A primary goal of this ledger format is flexibility, allowing the pluggability of consensus algorithms, data structures for recording history, and the type of data that can be stored in the ledger. The format and protocol described in this document can be used by existing systems (e.g. Bitcoin, Ethereum, etc.) to expose their data and functionality in an interoperable fashion.
There are a number of ways that one may participate in the development of this specification:
Decentralized systems often need to coordinate information on their operational state. While the entire state of the system doesn't need to be shared, the parts that affect the operation of the entire system are important. At their most basic, a decentralized system can be viewed as a state machine where events modify the state of the machine resulting in a new state:
There may be many different types of events in the system. Some events may handle system configuration, defining what the system is and isn't allowed to do. Some events may store data in the system that must be accessible by the entire system while other events snapshot the state of the system for performance and auditing purposes. Other events record the consensus of the system as a whole at a given point in time so that participants in the system can know that other participants agree with their view of the system.
Each event may affect the global system state in some way. This means that the current state is a representation of all the states and events that came before it.
It is typically important to optimize the storage of the events and package these events into a data structure called a block. These blocks are then "chained" together into a system that is often referred to as a blockchain.
In certain decentralized systems, like financial or healthcare systems, auditing these states and events is important to ensure that they are operating in an acceptable way from a regulatory perspective. Thus a verifiable record of these events and states is an important component of the system design, but has not been a practical endeavor until recently.
Due to recent advances in cryptography and decentralized systems design a new set of technologies called cryptographic ledgers (aka blockchains) have enabled the recording of state and events in a ledger where the ledger can be distributed and independently verified using cryptography. Some of these ledger systems are trustless, meaning that no trust (other than a trust in mathematics) is necessary in order to participate in the system. Other ledger systems are permissioned, meaning that some trust in third parties is required to ensure the accuracy of the ledger.
These cryptographic ledgers operate in an ecosystem consisting of the following actors. A ledger node modifies an instance of a cryptographic ledger based on the current configuration of the ledger. The ledger node tracks a set of pending ledger events that are candidates for being written to the ledger and writes them to the ledger when it believes consensus has been reached. A ledger agent may be used by any system that communicates over HTTP to instruct a ledger node to perform a specified action on the ledger.
This specification details an extensible data model and syntax for expressing cryptographic ledgers and a protocol for reading and writing to ledgers. The data model in this specification is designed to be protocol-agnostic and flexible, supporting pluggability of consensus algorithms, various data structures for recording history, and enabling a wide range of data types to be stored in the ledger.
This document is a detailed specification for ...
This document is organized as follows:
To provide the greatest amount of flexibility, the data model is a graph. If a formalized data model is desired, RDF may be utilized but is not necessary.
To ensure that the syntax will be easily adopted by developers, and supports a graph-based data model, it is RECOMMENDED that the implementation syntax is JSON-LD (or similarly compatible syntax). Other RDF-compatible syntaxes MAY also be used to express the ledger semantics. This ensures that the syntax is processable by widely adopted JSON tooling while also ensuring that the data model is robust enough to handle decentralized extensibility without name clashes or conflicts.
A ledger consists of a series of entries. This section outlines the basic types of entries that all Web Ledgers support. A particular Web Ledger MAY contain more than these basic entries.
A block contains one or more changes to the state machine. Blocks are typically used as a storage optimization to bundle a set of changes to the state machine. There can be many types of blocks. This specification details the basic set of blocks that all Web Ledgers may express.
A configuration block specifies which software algorithms should be applied when processing a particular Web Ledger. The first entry in a Ledger is typically an entry called a genesis block. The genesis block has the following basic layout:
{ "@context": "https://w3id.org/web-ledger/v1", "id": BLOCK_ID, "type": "LedgerConfigurationBlock", "ledgerConfig": { "id": LEDGER_ID, "type": "LedgerConfiguration", "name": "example", "description": "This is an example ledger.", "storageMechanism": STORAGE_DATA_STRUCTURE, "consensusAlgorithm": CONSENSUS_ALGORITHM, "previousBlock": { "hash": "urn:sha256:0000000000000000000000000000000000000000000000000000000000000000" }, "signature": SIGNATURE_VALUE }
In the example above, LEDGER_ID
is used to uniquely identify the
ledger (e.g. did:f6ea280f-8011-4502-a29f-464954de3427
).
BLOCK_ID
is used to uniquely identify the block in the ledger
(e.g. did:f6ea280f-8011-4502-a29f-464954de3427/blocks/1
.
STORAGE_DATA_STRUCTURE
is used to identify the storage mechanism
that is used in the ledger (e.g. SequentialList
) so that
serializing and
deserializing the contents of the ledger remains consistent across ledgers.
SIGNATURE_VALUE
is used to perform the cryptographic proof that
the ledger block was created by the entity identified in the signature. A more
complete example of a genesis block is
available in the appendix.
A standard configuration block update only differs from a genesis block in
that the previousBlock
value refers to the block before the
current block:
{ "@context": "https://w3id.org/web-ledger/v1", "id": BLOCK_ID, "type": "LedgerConfigurationBlock", "ledgerConfig": { "id": LEDGER_ID, "type": "LedgerConfiguration", "name": "example", "description": "This is an example ledger.", "storageMechanism": STORAGE_DATA_STRUCTURE, "consensusAlgorithm": CONSENSUS_ALGORITHM, "previousBlock": { "id": PREVIOUS_BLOCK_ID, "hash": PREVIOUS_BLOCK_HASH }, "signature": SIGNATURE_VALUE }
The PREVIOUS_BLOCK_ID
is the identifier of the previous
block in the ledger (e.g.
did:f6ea280f-8011-4502-a29f-464954de3427/blocks/1
) and the
PREVIOUS_BLOCK_HASH
value (e.g.
urn:sha256:abd465d34f7a3f0f7d849550eb9fc32c17d12881da6b524da0a96e12cc984538
is a hash of the previous block in the ledger.
A storage block stores data in a ledger and has the following general layout:
{ "@context": ["https://w3id.org/web-ledger/v1", MARKET_VERTICAL_CONTEXT], "id": BLOCK_ID, "type": "LedgerStorageBlock", "setObject": [ OBJECTS ], "previousBlock": { "id": PREVIOUS_BLOCK_ID "hash": PREVIOUS_BLOCK_HASH }, "signature": SIGNATURE_VALUE }
When storing data in the ledger, one may use a
MARKET_VERTICAL_CONTEXT
to add semantics to the objects stored in
OBJECTS
(e.g. https://w3id.org/vaccinations/v1
).
OBJECTS
are one or more JSON objects that can be stored in
the ledger. It is expected that each object has a unique identifier to
enable searching based on that identifier. A detailed
example of a storage event is included in
the appendix.
It's currently not specified in a configuration event how often consensus events should occur. The options are: per event, or every N events. This is an active area of research and debate.
A consensus event is an assertion that there is agreement on a subset of entries in a ledger. Some ledgers do not require consensus events as each event establishes an acceptable level of consensus. Other ledgers require consensus events after a pre-determined amount of time. An example of the basic layout of a consensus event is shown below:
{ "@context": "https://w3id.org/web-ledger/v1", "id": BLOCK_ID, "type": "ConsensusBlock", "previousBlock": { "id": PREVIOUS_BLOCK_ID "hash": PREVIOUS_BLOCK_HASH }, "signature": [ SIGNATURES ] }
A consensus event has a relatively simple definition. It consists of a
number of SIGNATURES
from notaries as determined by the previous
configuration event. A more complete
example of a consensus event
is located in the appendix.
A checkpoint event may be used to quickly bootstrap new mirrors for a ledger. An example of the basic layout of a checkpoint event is shown below:
{ "@context": "https://w3id.org/web-ledger/v1", "id": BLOCK_ID, "type": "LedgerCheckpointBlock", "checkpointLog": CHECKPOINT_LOG_URL, "checkpointLogHash": CHECKPOINT_LOG_HASH, "signature": [ SIGNATURES ] }
A checkpoint event declares a CHECKPOINT_LOG_URL
(e.g. https://example.org/ledger-agents/example/checkpoints/132
) and a
CHECKPOINT_LOG_HASH
(e.g. urn:sha256:7fa3b9eaa8d92d2b87abf83d88a92ff23
).
All notaries typically download the checkpoint log and
check it before providing signatures noting that the checkpoint log is valid.
There is a detailed
example of a checkpoint event
in the appendix.
How checkpoints are generated are a current topic of debate. The configuration event doesn't specify how often checkpoints can/should happen. It is also debatable that a checkpoint should be included in a consensus event and shouldn't be a separate event.
The previous section defined the data model and messages that can be used to create and operate a ledger. This section provides the Ledger Agent HTTP API endpoints that may be used in conjunction with the messages in the previous section to create and operate a ledger.
Note that the API proposed here only has one implementation and, while designed to be flexible, does not have enough deployment experience to be used in production systems that require strong interoperability guarantees. This is a work in progress.
The `ledgerAgentStatusService` may not be necessary. Instead some text could be added indicating that the `id` of the Ledger Agent can be retrieved to get its status information.
Service | Example URL | Description |
---|---|---|
ledgerAgentCreateService | POST /ledger-agents | Create a ledger agent. |
ledgerAgentListService | GET /ledger-agents | Get all ledger agents. |
ledgerAgentStatusService | GET /ledger-agents/{agent} | Get the current status of the ledger agent. |
ledgerEventService | POST /ledger-agents/{agent}/events | Request the addition of an event to ledger. |
ledgerBlockService | GET /ledger-agents/{agent}/blocks | Get a specific block from the ledger. |
ledgerQueryService | GET /ledger-agents/{agent}/query | Query the current state of the ledger. |
A website may provide service endpoint discover by embedding JSON-LD in their
top-most HTML web page (e.g. at https://example.com/
):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Example Website</title> <link rel="stylesheet" href="style.css"> <script src="script.js"></script> <script type="application/ld+json"> { "@context": "https://w3id.org/discovery/v1", "id": "https://example.com/", "name": "Example Website", "ledgerAgentCreateService": "https://example.com/ledger-agents", "ledgerAgentListService": "https://example.com/ledger-agents" } </script> </head> <body> <!-- page content --> </body> </html>
Service descriptions may also be requested via content negotiation.
In the following example a JSON-compatible service description is provided
(e.g. curl -H "Accept: application/json" https://example.com/
):
{ "@context": "https://w3id.org/discovery/v1", "id": "https://example.com/", "name": "Example Website", "ledgerAgentCreateService": "https://example.com/ledger-agents", "ledgerAgentListService": "https://example.com/ledger-agents" }
A ledger is created by performing an HTTP POST of a
LedgerConfigurationBlock
to the ledgerAgentCreateService
. The following HTTP status codes
are defined for this service:
HTTP Status | Description |
---|---|
201 |
Ledger creation was successful. The HTTP Location header will
contain the URL for the newly created ledger.
|
400 | Ledger creation failed. |
409 | A duplicate ledger exists. |
An example exchange of a ledger creation is shown below:
POST /ledger-agents HTTP/1.1 Host: example.com Content-Type: application/ld+json Content-Length: 1062 Accept: application/ld+json, application/json, text/plain, */* Accept-Encoding: gzip, deflate { "@context": "https://w3id.org/web-ledger/v1", "id": "did:1628bf39-c8f9-453f-93d7-0fbdebb3dfef/blocks/1", "type": "LedgerConfigurationBlock", "ledgerConfig": { "id": "did:1628bf39-c8f9-453f-93d7-0fbdebb3dfef", "type": "LedgerConfiguration", "name": "example", "description": "An example ledger.", "storageMechanism": "SequentialList", "consensusAlgorithm": { "type": "ProofOfSignature2016", "approvedSigner": [ "http://blue.example.com/keys/234", "http://red.example.com/keys/987", ], "minimumSignaturesRequired":1 } }, "previousBlock": { "hash": "urn:sha256:0000000000000000000000000000000000000000000000000000000000000000" }, "signature": { "type": "RsaSignature2016", "created": "2016-10-14T18:35:33Z", "creator": "http://blue.example.com/keys/234", "signatureValue": "HvfvRQ57EO...J0Q==" } }
If the creation of the ledger was successful, an HTTP 201 status code is expected in return:
HTTP/1.1 201 Created Location: http://ledger.example.com/ledger-agents/example Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache Expires: 0 Date: Fri, 14 Oct 2016 18:35:33 GMT Connection: keep-alive Transfer-Encoding: chunked
One can get a list of active ledgers on a server by performing an HTTP GET on
the ledgerListService
. The following HTTP status codes
are defined for this service:
HTTP Status | Description |
---|---|
200 | The list of ledgers was found and will be returned in the body of the response. |
404 | The list of ledgers was not found at the given URL. |
An example exchange of getting a list of ledgers on an HTTP server is shown below:
GET /ledger-agents HTTP/1.1 Host: example.com Connection: keep-alive Accept: application/ld+json, application/json, text/plain, */* Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8
If retrieving the list of ledgers is successful, a HTTP 200 response is expected:
HTTP/1.1 200 OK Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache Expires: 0 Access-Control-Allow-Origin: * Vary: Accept, Accept-Encoding Content-Type: application/ld+json; charset=utf-8 Etag: W/"91d-mHiDWL0kix4rxP7JCtfVCA" Content-Encoding: gzip Date: Fri, 14 Oct 2016 18:46:04 GMT Connection: keep-alive Transfer-Encoding: chunked { "ledgerAgent": [ { "id": "https://example.com/ledger-agents/example", "name": "example", "ledgerAgentStatusService": "https://example.com/ledger-agents/example", "ledgerQueryService": "https://example.com/ledger-agents/example/query", "ledgerEventService": "https://example.com/ledger-agents/example/events", "ledgerBlockService": "https://example.com/ledger-agents/example/blocks", "ledgerConfig": { "id": "did:de7adbe7-79f2-425a-9dfb-76a234782f30", "type": "LedgerConfiguration", "name": "example", "description": "An example ledger.", "storageMechanism": "SequentialList", "consensusAlgorithm": { "type": "ProofOfSignature2016", "approvedSigner": [ "https://blue.example.com/keys/234", "https://red.example.com/keys/789" ], "minimumSignaturesRequired": 1 } }, "latestBlock": { "id": "did:de7adbe7-79f2-425a-9dfb-76a234782f30/blocks/1", "hash": "urn:sha256:7eb0603c9a3982284c7db09b1eb40bc85a1177bdc594b027fba0e746b79db15b" }, "nextBlock": { "id": "did:de7adbe7-79f2-425a-9dfb-76a234782f30/blocks/2" } }, { ... NEXT_LEDGER_IN_LIST ... } ] }
The metadata related to a ledger agent may be fetched by performing an HTTP GET
on the ledgerAgentStatusService
. The following HTTP status codes
are defined for this service:
HTTP Status | Description |
---|---|
200 | The ledger agent status was found and will be returned in the body of the response. |
404 | The ledger agent status was not found at the given URL. |
An example exchange of fetching metadata for a ledger is shown below:
GET /ledger-agents/example HTTP/1.1 Host: example.com Connection: keep-alive Accept: application/ld+json, application/json, text/plain, */* Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8
If retrieving the ledger metadata is successful, an HTTP 200 response is expected:
HTTP/1.1 200 OK Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache Expires: 0 Access-Control-Allow-Origin: * Vary: Accept, Accept-Encoding Content-Type: application/ld+json; charset=utf-8 Etag: W/"91d-mHiDWL0kix4rxP7JCtfVCA" Content-Encoding: gzip Date: Fri, 14 Oct 2016 18:46:04 GMT Connection: keep-alive Transfer-Encoding: chunked { "id": "https://example.com/ledger-agents/example", "name": "example", "ledgerAgentStatusService": "https://example.com/ledger-agents/example", "ledgerQueryService": "https://example.com/ledger-agents/example/query", "ledgerEventService": "https://example.com/ledger-agents/example/events", "ledgerBlockService": "https://example.com/ledger-agents/example/blocks", "ledgerConfig": { "id": "did:de7adbe7-79f2-425a-9dfb-76a234782f30", "type": "LedgerConfiguration", "name": "example", "description": "An example ledger.", "storageMechanism": "SequentialList", "consensusAlgorithm": { "type": "ProofOfSignature2016", "approvedSigner": [ "https://blue.example.com/keys/234", "https://red.example.com/keys/789" ], "minimumSignaturesRequired":1 } }, "latestBlock": { "id": "did:de7adbe7-79f2-425a-9dfb-76a234782f30/blocks/1", "hash": "urn:sha256:7eb0603c9a3982284c7db09b1eb40bc85a1177bdc594b027fba0e746b79db15b" }, "nextBlock": { "id": "did:de7adbe7-79f2-425a-9dfb-76a234782f30/blocks/2" } }
Appending to a ledger can be achieved by performing an HTTP POST of a
LedgerStorageBlock
to the ledgerAppendService
. The following HTTP status codes
are defined for this service:
HTTP Status | Description |
---|---|
201 | The ledger block was sucessfully appended. |
400 | The ledger block failed to be appended. |
409 | The ledger block with the given identifier already exists. |
An example of an event being appended to a ledger is shown below:
POST /ledger-agents/example/events HTTP/1.1 Host: example.com Connection: keep-alive Content-Length: 1054 Content-Type: application/json;charset=UTF-8 Accept: application/ld+json, application/json, text/plain, */* Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.8 { "@context": ["https://w3id.org/web-ledger/v1", "https://w3id.org/fema/v1"], "type": "LedgerStorageEvent", "setObject": [{ "id": "https://fema.gov/credentials/9754457", "type": ["Credential", "EmergencyResponderCredential"], "claim": { "id": "did:bc380e48-a6d9-4602-ab20-1beb403d4bcc", "emsLicense": { "id": "ems:FF-12-01655", "status": "valid" } } }], "signature": { "type": "RsaSignature2016", "created": "2016-10-14T19:47:15Z", "creator": "https://example.com/keys/fema-key-1", "signatureValue": "JoS27wqaTX...s0mpBFMgXIMw==" } }
If the storage attempt is successful, a HTTP 200 response is expected:
HTTP/1.1 201 Created Location: https://example.com/ledger-agents/example/events?id=d1328828-3d44-4e14-9c3a-263af54ed032 Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache Expires: 0 Date: Fri, 14 Oct 2016 19:47:16 GMT Connection: keep-alive Transfer-Encoding: chunked
A ledger read for an block is achieved by performing an HTTP GET on
a ledger block identifier. The list of ledger blocks is available by performing
an HTTP GET on the ledgerBlockService
. The following HTTP status
codes are defined for this service:
HTTP Status | Description |
---|---|
200 | Retrieval of the ledger block was successful. |
404 | The ledger block was not found at the given URL. |
An example retrieval of a ledger block is shown below:
GET /ledger-agents/example/blocks?id=did:de7adbe7-79f2-425a-9dfb-76a234782f30/blocks/2 HTTP/1.1 Host: example.com Connection: keep-alive Accept: application/ld+json, application/json, text/plain, */* Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8
If the ledger block retrieval is successful, a HTTP 200 response is expected:
HTTP/1.1 200 OK Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache Expires: 0 Access-Control-Allow-Origin: * Vary: Accept, Accept-Encoding Content-Type: application/ld+json; charset=utf-8 Etag: W/"41e-PJKXv/OxofX29WykKb3PZg" Content-Encoding: gzip Date: Fri, 14 Oct 2016 20:20:44 GMT Connection: keep-alive Transfer-Encoding: chunked { "@context": ["https://w3id.org/web-ledger/v1", "https://w3id.org/fema/v1"], "id": "did:de7adbe7-79f2-425a-9dfb-76a234782f30/blocks/2", "type": "LedgerStorageBlock", "setObject": [{ "id": "https://fema.gov/credentials/9754457", "type": ["Credential", "EmergencyResponderCredential"], "claim": { "id": "did:bc380e48-a6d9-4602-ab20-1beb403d4bcc", "emsLicense": { "id": "ems:FF-12-01655", "status": "valid" } } }], "previousBlock": { "id": "did:de7adbe7-79f2-425a-9dfb-76a234782f30/blocks/1", "hash": "urn:sha256:7eb0603c9a3982284c7db09b1eb40bc85a1177bdc594b027fba0e746b79db15b" }, "signature": { "type": "RsaSignature2016", "created": "2016-10-14T19:47:15Z", "creator": "http://example.com/keys/789", "signatureValue": "JoS27wqa...BFMgXIMw==" } }
The current state machine of a ledger may be queried by performing an
HTTP GET on the ledgerQueryService
. The following HTTP status
codes are defined for this service:
HTTP Status | Description |
---|---|
200 | Retrieval of the latest state machine object was successful. |
400 | The query was malformed. |
404 | The given state machine object was not found. |
An example query of a state machine in a ledger is shown below:
GET /ledger-agents/example/query?id=http://www.coupon-clearing.org/coupons/486211708 HTTP/1.1 Host: example.com Connection: keep-alive Accept: application/ld+json, application/json, text/plain, */* Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8
If the query is successful, a HTTP 200 response is expected:
{ "id": "http://www.coupon-clearing.org/coupons/486211708", "type": ["Credential", "DiscountCoupon"], "claim": { "id": "upc:956578900933", "discount": "$3", "description": "Discount when you buy 5 pounds of JuicyGreen Apples", "status": "redeemed" } }
{ "@context": "https://w3id.org/web-ledger/v1", "id": "did:f6ea280f-8011-4502-a29f-464954de3427/blocks/1", "type": "LedgerConfigurationBlock", "ledgerConfig": { "id": "did:f6ea280f-8011-4502-a29f-464954de3427", "type": "LedgerConfiguration", "name": "example", "description": "example ledger", "storageMechanism": "SequentialList", "consensusAlgorithm": { "type": "ProofOfSignature2016", "approvedSigner": [ "https://blue.example.com/keys/j37f8", "https://red.example.com/keys/83hfk", ], "minimumSignaturesRequired":1 } }, "previousBlock": { "hash": "urn:sha256:0000000000000000000000000000000000000000000000000000000000000000" }, "signature": { "type": "RsaSignature2016", "created": "2016-10-05T11:47:26Z", "creator": "http://blue.example.com/keys/j37f8", "signatureValue": "RG+t2EbnMKr4zIwgncLHTb/JvAZ/EIXmTXrrad7DBdlchKPPC9j91N793eHY5UYx4zx7PTDnU2HlW9zqQD1EMBwI7TtqE7BfvxOFodjKJ/Aw16vpAmw2h2Jo9NBu4BvFWsLPCiMLHuW7Vxo7XDkGVfaZUqk/X2q/xpRmqJ1tOlNgivUH8bIm/TUAG3g90DMN9s5zImVyB4B20zMJk8K50BbpHYKUVNWCaHnv9F4VvUUa+AdNeNlC8W1F5j2WChyXzd+51bervxQErZUDFyocW/xEYPvJXPSGnL0ARBDggKQDe1M3bg8w7GnMGrJBieNZAuK2mxOtF2rOPDU3oMk3ZQ==" } }
{ "@context": "https://w3id.org/web-ledger/v1", "id": "https://example.us.gov/ledger-agents/emergency-response/1", "type": "LedgerConfigurationBlock", "storageMechanism": "SequentialList", "consensusAlgorithm": { "type": "ProofOfSignature2016", "approvedSigner": [ "https://fema.example.us.gov/i/ofp", "https://tsa.example.us.gov/i/vclaims", "https://dhs.example.us.gov/i/credentialing", ], "minimumSignaturesRequired": 1 }, "nextBlock": "https://example.us.gov/ledger-agents/emergency-response/2", "signature": { "type": "LinkedDataSignature2016", "created": "2016-09-19T17:19:52Z", "creator": "https://fema.example.gov/i/credentialing/keys/7f6", "signatureValue": "pjeyuFq9idhwHGfGFzv...9fjsk==" } }
{ "@context": [ "https://w3id.org/web-ledger/v1", "https://w3id.org/cryptocurrencies/v1" ], "id": "bytecoin:block:23fa73bb201c738d", "type": "LedgerConfigurationBlock", "storageMechanism": "MerkleTree", "consensusAlgorithm": { "type": "ProofOfWork2016", "proofOfWorkAlgorithm": "Bitcoin", "targetDifficulty": "199312067531.243" }, "signature": { "type": "LinkedDataSignature2016", "created": "2017-01-24T02:10:21Z", "creator": "bytecoin:keys:23f3b2c8183bdd52aff689", "signatureValue": "90D4cFqT/yKPiwd/GFzv...NJGL==" } }
{ "@context": [ "https://w3id.org/web-ledger/v1", "https://w3id.org/cryptocurrencies/v1" ], "id": "https://example-consortium.com/private-ledgers/loans/real-estate/1", "type": "LedgerConfigurationBlock", "storageMechanism": "SequentialList", "consensusAlgorithm": { "type": "ProofOfBallot2015", "minimumQuorumPercentage": "0.51", "minimumVotePercentage": "0.67", "approvedSigner": [ "https://regulator-a.gov/i/bank-oversight", "https://regulator-b.gov/i/consumer-protection", "https://bank-x.com/i/housing", "https://bank-y.com/i/corporate-loans", "https://bank-z.com/i/swaps", ] }, "signature": [{ "type": "LinkedDataSignature2016", "created": "2018-04-16T19:34:18Z", "creator": "https://regulator-b.gov/i/consumer-protection/keys/2f73", "signatureValue": "Piw90D4cFqT/yKd/JGLv...NGFz==" }, ... // there will be at least 3 more signatures here ] }
The use of nextBlock
is unlikely here, it is more
likely to be prevBlock
and potentially include
a hash of that event depending on configuration.
{ "@context": ["https://w3id.org/web-ledger/v1", "https://w3id.org/dhs/v1"], "id": "did:f6ea280f-8011-4502-a29f-464954de3427/blocks/2", "type": "LedgerStorageBlock", "setObject": [{ "id": "https://hhs.gov/vaccinations/6080026", "type": ["Credential", "VaccinationCredential"], "claim": { "id": "did:e277ce82-bf9d-413a-a6fe-fde877fd19b1", "vaccination": { "type": "IPV", "vaccinationDate": "2004-07-17", "vaccinationProvider": "Alameda County Hospital, California, USA" } } }], "previousBlock": { "id": "did:f6ea280f-8011-4502-a29f-464954de3427/blocks/1", "hash": "urn:sha256:f04524659baa027ea49e7d0635bc6b1869d3e7d811f6bfefeb3aae1adcae0362" }, "signature": { "type": "RsaSignature2016", "created": "2016-10-12T18:37:27Z", "creator": "http://ledger.example.com/keys/fema-key-1", "signatureValue": "ITv0b9tTIjgBMgu4jUOsuU9Y2t9rsq+rKrbJHfcKWmDQZE1X6VpqKowv3l27WN0w5NyECIkJx6oy94nlM375ivmhQf6iYd6R7IizVBiRiLl3HeNXdaxBpyYMn6OiP8MYVdJt2g5vj+xhP9AadXnRL0TYmE6qH1LtOw42SQtfseQDb8xF1Bsjie7KmKK/G+B1yoKqg1L34NLSAnHpnqRGAen9OEMi0hwBrVD8HIRFkdCehh4T07HRrZe2mwhfY0gOA54j02qWZxidvYUYAV8vax4AhFyk0Vsaibo9yt85uU8Tc8a4e5hjS7nCAya8FMzDd0xEOp1q9MeC5vgJHKz29g==" } }
{ "@context": [ "https://w3id.org/web-ledger/v1", "https://w3id.org/housing/v1", ], "id": "https://vhda.va.us.gov/ledger-agents/webville/houses/2", "type": "LedgerStorageBlock", "previousBlock": "https://example-consortium.com/private-ledgers/loans/real-estate/1", "setObject": [{ "id": "https://vhda.va.us.gov/properties/3829344", "propertyAddress": { "street": "263 Main Street", "locality": "Webville", "region": "VA", "postalCode": "24736-3726", "country": "US" }, "owner": { "name": "Jane Smith", "postalAddress": { ... } }], "signature": { "type": "LinkedDataSignature2016", "created": "2016-02-22T02:10:21Z", "creator": "https://webville.va.us.gov/i/planning-department/keys/1", "signatureValue": "cNJGLFqT/d/90D4GFzv...yKPiw==" } }
{ "@context": [ "https://w3id.org/web-ledger/v1", "https://w3id.org/dhs/credentials/v1", ], "id": "https://example.us.gov/ledger-agents/emergency-response/2", "type": "LedgerStorageBlock", "previousBlock": "https://example.us.gov/ledger-agents/emergency-response/1", "setObject": [{ "id": "https://example.us.gov/credentials/234234542", "type": ["Credential", "EmergencyResponseCredential"] "claim": { "id": "did:3f32-23425-53-241442", "emsLicense": { "id": "FF-37-48573", "status": "valid" }, }], "signature": { "type": "LinkedDataSignature2016", "created": "2016-09-19T17:19:52Z", "creator": "https://fema.example.gov/i/credentialing/keys/7f6", "signatureValue": "pjeyuFq9idhwHGfGFzv...9fjsk==" } }
{ "@context": [ "https://w3id.org/web-ledger/v1", "https://w3id.org/cryptocurrencies/v1" ], "id": "bytecoin:block:83ba663df28372718", "type": "LedgerStorageBlock", "previousBlock": "bytecoin:block:271863df2883ba637", "addsObject": [{ "transaction": [{ "https://w3id.org/bytecoin/v1", "source": "bytecoin:2892316f63778", "destination": "bytecoin:983bba526fd6", "input": [...], // the inputs to the transaction "output": [...], // the outputs from the transaction "transfer": { "amount": "0.3928621", "currency": "bytecoin:currency:bco" } }], ... // there could be hundreds to thousands more of these }] "signature": { "type": "LinkedDataSignature2016", "created": "2017-01-24T02:11:16Z", "creator": "bytecoin:key:23fa73bb201c738d", "signatureValue": "90D4cFqT/yKPiwd/GFzv...NJGL==" } }
{ "@context": [ "https://w3id.org/web-ledger/v1", "https://w3id.org/real-estate/v1" ], "id": "https://example-consortium.com/private-ledgers/loans/real-estate/2", "type": "LedgerStorageBlock", "previousBlock": "https://example-consortium.com/private-ledgers/loans/real-estate/1", "addsObject": [{ "id": "https://example-consortium.com/private-ledgers/loans/real-estate/transactions/238947234", "transaction": { "source": "lei:HB7FFAZIO0MZ8PP8OE26", // compliant to ISO 17442 standard "destination": "lei:PP8OEHB7FFAZIO0MZ826", "transfer": { "loanId": "lei:FAZIO0PP8OEHB7FMZ826" } } }], "signature": [{ "type": "LinkedDataSignature2016", "created": "2018-04-16T19:34:18Z", "creator": "https://regulator-b.gov/i/consumer-protection/keys/2f73", "signatureValue": "Piw90D4cFqT/yKd/JGLv...NGFz==" }, ... // there will be at least 3 more signatures here ] }
{ "@context": "https://w3id.org/web-ledger/v1", "id": "did:f6ea280f-8011-4502-a29f-464954de3427/blocks/100", "type": "ConsensusBlock", "previousBlock": { "id": "did:f6ea280f-8011-4502-a29f-464954de3427/blocks/99", "hash": "urn:sha256:0877a494ce1705117f917a3af3fc48190b1fdbca04fdba8e995fd6c15fb2fe71" }, "signature": [{ "type": "RsaSignature2016", "created": "2016-10-12T19:54:12Z", "creator": "https://notary1.example.org/keys/124", "signatureValue": "skeJ4...lBUiI858=" }, { "type": "RsaSignature2016", "created": "2016-10-12T19:54:32Z", "creator": "https://notary2.example.org/keys/f31", "signatureValue": "iamOjOGncO...gRXfsG0=" }, { "type": "RsaSignature2016", "created": "2016-10-12T19:54:56Z", "creator": "https://notary3.example.org/keys/35", "signatureValue": "cPehH...iI858=" }, { "type": "RsaSignature2016", "created": "2016-10-12T19:54:23Z", "creator": "https://notary4.example.org/keys/ugref2", "signatureValue": "hMaD22...ONwzsgo=" }] }
A checkpoint log is an entry in the ledger that
Don't really know if checkpoints are /that/ useful without
prevId
entries. Don't really know if checkpoints
are that useful at all? Seems to be the only use is a link
to a compressed/checksummed file?
{ "@context": "https://w3id.org/web-ledger/v1", "id": "https://example.org/ledger-agents/example/6372463", "type": "LedgerCheckpointBlock", "checkpointLog": "https://example.org/ledger-agents/example/checkpoints/132", "checkpointLogHash": "urn:sha256:7fa3b9eaa8d92d2b87abf83d88a92ff23", "signature": [{ "type": "LinkedDataSignature2016", "created": "2018-04-16T19:34:18Z", "creator": "https://example.org/i/master/keys/32", "signatureValue": "Piw90D4cFqT/yKd/JGLv...NGFz==" }, ... // there may be multiple counter-signatures here ] }
{ "@context": [ "https://w3id.org/web-ledger/v1", "https://w3id.org/cryptocurrencies/v1" ], "id": "https://example.org/ledger-agents/example/5", "type": "LedgerStorageBlock", "previousBlock": "https://example.org/ledger-agents/example/4", "addsObject": [{ "transaction": [{ "source": "https://example.org/accounts/jane/7", "destination": "https://foo.com/accounts/bob/3", "remoteLedger": "https://foo.com/ledger-agents/blah/3445", "transfer": { "amount": "23.45", "currency": "USD" } }], ... // there could be hundreds to thousands more of these }] "signature": { "type": "LinkedDataSignature2016", "created": "2017-01-24T02:11:16Z", "creator": "bytecoin:key:23fa73bb201c738d", "signatureValue": "90D4cFqT/yKPiwd/GFzv...NJGL==" } }
This specification, a part of the "Credentials on Public/Private Linked Ledgers" project, has been funded in part by the United States Department of Homeland Security's Science and Technology Directorate under contract HSHQDC-16-C-00058. The content of this specification does not necessarily reflect the position or the policy of the U.S. Government and no official endorsement should be inferred.
The editor would like to thank the Web Payments Community Group and the Blockchain Community Group.
Thanks to the following individuals, in order of their first name, for their input on the specification: ...