Skip to content
Snippets Groups Projects

WIP: RFC 5 : New Scalable Blockchain Protocol

Closed nanocryk requested to merge rfc5-duniter-protocol-rework into master
Compare and
1 file
+ 1107
0
Compare changes
  • Side-by-side
  • Inline
+ 1107
0
 
# #5 Duniter Protocol Rework (V11)
 
 
```txt
 
RFC: 5
 
Title: Duniter Protocol Rework (V11)
 
Type: Hard-fork
 
Status: WIP
 
Author: nanocryk <nanocryk@duniter.org>
 
Created: 2018-01-29
 
Last edited: 2018-02-15
 
License: AGPL-3
 
```
 
 
This document provide specifications of a reworked protocol for the Duniter project.
 
 
It aims to provide an efficient and strong base for future developments by taking the actual
 
protocol (version 10), simplifying it and adding usefull elements to increase performance and
 
extensibility.
 
 
This document is written in a "no previous knowledge" fachion to allow anyone to understand it,
 
and will allow to directly use it as documentation if changes are accepted and implemented.
 
 
> This document is in writing process and may not be complete nor accurate. Reviews and comments
 
> are welcome.
 
 
## Summary
 
 
1. [A brief description of Duniter](#1-a-brief-description-of-duniter)
 
1. [Protocol conventions](#2-protocol-conventions)
 
1. [Keys, addresses and accounts.](#3-keys-addresses-and-accounts)
 
1. [Identities and the Web of Trust](#4-identities-and-the-web-of-trust)
 
1. [Transactions between accounts](#5-transactions-between-accounts)
 
1. [Usage of V10 documents](#6-usage-of-v10-documents)
 
1. [In depth block structure](#7-in-depth-block-structure)
 
1. Deployement plan
 
 
## 1. A brief description of Duniter
 
 
The **Duniter software** aims to provide a **Universal *Dividend** based crypto-currency based on
 
*Stephane Laborde's [Relative Theory of Money]*. It aims to provide money creation equality between
 
all users of the currency in space [of users] and time [users join and leave]. Money is
 
co-created by all the users and this process is automated by **Duniter**, allowing any user without
 
any technical skills to take part of the money creation. The name is made of `D + unit + er` as "a
 
tool to create UD units".
 
 
[Relative Theory of Money]: http://en.trm.creationmonetaire.info/
 
 
Each *Duniter* currency is built on a consecutive list of **blocks** linked together using
 
[cryptographic hashes], hense the name **blockchain**. Each block represent a new valid state of the
 
system and contains data to transform this valid state into a new valid state. This process is
 
applyed by any nodes in the network to ensure changes meet consensus.
 
 
Each block store the *proof of integrity* of the state and transformations as the *root* of a
 
[Merkle tree] (the Merkle root). This *Merkle root* needs to have specific properties to be
 
considered valid and computationnal work is needed to satisfy them. This process is called a
 
**Proof of Work** and allow to randomly pick writer for the next block, preventing an individual or
 
a group to take control of the currency.
 
 
[cryptographic hashes]: https://en.wikipedia.org/wiki/Cryptographic_hash_function
 
[Merkle tree]: https://en.wikipedia.org/wiki/Merkle_tree
 
 
Since we want to provide a *Universal Dividend*, we need to ensure that a real living user can
 
only have one identity per currency. To avoid computationnal attacks on the blockchain, we also
 
desire to have a "one user, one vote" *Proof of Work* system. To achieve this we use a
 
[Web of Trust] between members. Each member can give and receive certifications to allow other
 
identities to become and stay a member. This *Web of Trust* is stored in the blockchain, and
 
only *members* are allowed to write blocks. Thus, the *blockchain* is secured from the inside and
 
can't be easily attacked by external entities. The *Web of Trust* have more rules to resist attacks
 
which will be discribed later in this document.
 
 
As a currency, transactions can be made from *accounts* to others with programmable conditions that
 
can be used to create smart-contracts. Anyone can use the currency for transactions, not only
 
members.
 
 
[Web of Trust]: https://en.wikipedia.org/wiki/Web_of_trust
 
 
## 2. Protocol conventions
 
 
### Data format
 
 
Documents are structured and stored in binary formats to allow efficient storage, network
 
transmission and reading. All data is [big-endian] unless otherwise specified and [aligned] in 4
 
bytes blocks to improve memory speeds. All given sizes are given in *bytes* unless otherwise
 
specified.
 
 
[big-endian]: https://en.wikipedia.org/wiki/Endianness
 
[aligned]: https://en.wikipedia.org/wiki/Data_structure_alignment
 
 
### Hashes
 
 
*Cryptographic hashes* are done with the [SHA-256] algorithm unless otherwise specified. They are
 
stored as raw bytes arrays and should be displayed in hexadecimal format.
 
 
[SHA-256]: https://en.wikipedia.org/wiki/SHA-2
 
 
### Formating
 
 
Some formats are used to improve display or storage of some data :
 
 
- **Base58** (display) : Mainly used in addresses.
 
 
The alphabet is `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`.
 
- **Base64** (display) : Data format used for non user-friendly data such as signatures.
 
 
The alphabet is `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`.
 
- **Name64** (storage) : Allow to store names in a more compact way that raw ASCII/UTF-8 text.
 
Each character is stored on 6bits, and prevent any invalid characters.
 
 
The alphabet is `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-`.
 
 
### Block IDs and blockstamps
 
 
Each block is indexed by its **block ID** stored as a *4 bytes unsigned integer*.
 
The ***genesis block*** *ID* is `0`, and each following block have a *block ID* incremented
 
by `1`.
 
 
To refeer a *block*, we use it's **blockstamp** made of its *block ID* and its *Merkle root*.
 
The *blockstamp* of the genesis block *might be* `0-883228A23F8A75B342E912DF439738450AE94F5D`
 
and the *blockstamp* of block `433` *might be* `433-FB11681FC1B3E36C9B7A74F4DDE2D07EC2637957`.
 
 
Since hashes are stored on 32 bytes, a *blockstamp* is stored on a 36 bytes value.
 
 
> Note that is says "might be" because the hash is not known in advence.
 
 
### Currency amounts
 
 
Currency amounts are stored as integer values of the smallest unit. In clients, this amount is
 
displayed with a decimal part which is absent from the protocol.
 
 
A base is also defined to manage big numbers due to the exponentialy increasing amount on currency
 
produced with the Universal Dividend.
 
 
Currency amounts are stored as :
 
 
| Size | Data |
 
|:----:|:-----|
 
| *1 byte* | Base
 
| *7 bytes* | Signed amount in units
 
 
> The amount needs to be signed to allow operations on them within scripts.
 
 
The real amount is calculated as :
 
 
```txt
 
RealAmount = Amount * 10^Base
 
```
 
 
Since the base will grow forever, it needs to cycle. We can compare amounts in an interval of
 
`[-128;127]` around the main base.
 
 
> TODO : better explain ranges
 
 
This base incrementation will be very slow and a full cycle won't append until a long time. When the
 
UD becomes greater than a fixed value, we increment the base.
 
 
### Dates
 
 
All dates are stored in [UNIX timestamp format], as the number of seconds
 
since 00:00:00 UTC on January 1, 1970. They are stored in a 64bit format to
 
avoid [year 2038 problem]. In this format the counter will overflow
 
in approximately 293 billion years.
 
 
[UNIX timestamp format]: https://en.wikipedia.org/wiki/Unix_time
 
[year 2038 problem]: https://en.wikipedia.org/wiki/Unix_time#Representing_the_number
 
 
Durations are expressed in eleapsed time between 2 *timestamps*.
 
 
Another way to provide dates is to reference a *blockstamp*.
 
Dates in the *blockchain* are calculated as the average time provided in a window of
 
`MedianTimeBlocks` blocks. It should be preferred to use *blockstamps* since its independent
 
of any external influences.
 
 
> `MedianTimeBlocks = 24` in Ǧ1 currency.
 
 
### Documents structure
 
 
Most transformations of the state are made through **documents** composed of a **header**, a
 
**payload** and one or more **signatures**. The pair `(currency code, document type)` is used in
 
signatures, but is ellided when written into a block since they can be deduced from block data and
 
context. This prevent documents from other currencies to be compatible or to be used in another
 
context (joining/leaving documents have the same structure, only a different document type).
 
 
An **extention field** is provided to allow future protocol extensions without modifying this
 
document structure. It can contain any data but should have some sort of standard format to target
 
specific extensions. This format is not yet defined and will be in a future RFC, for now this
 
extension field should be empty (size of 0).
 
 
The *header* and *payload* are hashed to optain a **document ID**, then *signatures* are made on it.
 
 
The header is composed of :
 
 
| Size | Data |
 
|:----:|:-----|
 
| *2 bytes* | Currency code
 
| *2 bytes* | Document type
 
| *2 bytes* | Payload size in bytes
 
| *2 bytes* | Number of issuers
 
| ... | List of issuers *generic public keys* with alignement padding for each
 
| *1 byte* | Extension field size in bytes (0 to 255)
 
| ... | Extension field with alignement padding
 
 
> Payload and each signatures have alignement padding.
 
 
> Currency code should be chosen to form a recognizable prefix in addresses.
 
> Exemple : g1 (todo: code ?), gt (todo: code ?)
 
 
Cryptographic systems of signatures are not provided and matching public key types are used. A
 
document is valid if we can make pairs of well-formed `(public key, signature)` (with 0 bytes left
 
and no overflows) and each signature is valid for the document content and the public key.
 
 
The document types are the following :
 
 
| Name | Code |
 
|:-----|:----:|
 
| Transaction | `0x00` |
 
| Identity | `0x01` |
 
| Membership / Leaving | `0x02`/`0x03` |
 
| Certification | `0x04` |
 
| Revocation | `0x05` |
 
| V10Document | `0x06` |
 
 
`V10Document` allow to use V10 non-transaction documents. This will allow a smooth transition
 
between the 2 protocols, pending documents in pool will be usable on the new blockchain without
 
needing user intervention.V10 transaction documents can't be used with the new transaction system.
 
However, unspent transaction outputs in the last v10 block will be converted to v11
 
*account system*.
 
 
## 3. Keys, addresses and accounts
 
 
To allow funds to be spent only by authorized users, we make us of [Public-key cryptography].
 
User can generate `(public key, private key)` pairs, use the **private key** to sign data and get
 
a **signature**, and **verify** this *signature* with the the associated *public key*.
 
 
[Public-key cryptography]: https://en.wikipedia.org/wiki/Public-key_cryptography
 
 
Cryptographic data is stored in a special format to allow to :
 
 
- provide the type of data it contains
 
- link a key with a specific currency to avoid cross-blockchain [replay attacks].
 
- encode checksum to add error detection and close-looking attacks difficult
 
- human readable format
 
 
[replay attacks]: https://en.wikipedia.org/wiki/Replay_attack
 
 
This format (called an **address**) is structured as :
 
 
| Size | Data |
 
|:----:|:-----|
 
| 2 | Currency code
 
| 1 | Data type (determine `size` of payload)
 
| 1 | Checksum
 
| `size` | Payload
 
 
| Data type | Payload size | Description
 
|:---------:|:------------:|:------
 
| 0 | ... | complete script (first 2 bytes contains script size)
 
| 1 | 32 | account (script hash)
 
| 2 | 32/64 | [ed25519] public/private key
 
| 3 | 32 | [ed25519] public key hash
 
 
With type `1` a client can query a node to obtain the underlying script.
 
With types `2` and above, the client can build the script locking funds with this public key hash.
 
 
> More data types will be added in the future.
 
 
[ed25519]: https://en.wikipedia.org/wiki/EdDSA
 
 
The difference between public and private keys can be infered by the context and size.
 
 
The checksum is the first byte of `SHA256(CurrencyCode ++ DataType ++ Payload)`
 
 
> With this format it will be very unlikely someone send to an unwanted address.
 
 
## 4. Identities and the Web of Trust
 
 
An identity provide the relation between a *public key* and *an arbitrary identity*. This link is
 
done through an `Identity` document containing :
 
 
| Size | Data |
 
|:----:|:-----|
 
| 36 | *Time of signature* blockstamp
 
| 1 | Username length (1 to 127)
 
| ... | Username in *Name64* format *(with alignement padding)*
 
 
This document must have only one issuer and the username must not be
 
used by any active members or passed members for a defined period of time. We can compute an
 
**identity hash** as
 
`IdentityHash = SHA256(Username ++ KeyHashAddress ++ Blockstamp)`.
 
 
This identity can be revoked using a `Revocation` document containing the *identity hash* to revocate. Of
 
course, this document is only valid if its unique issuer is associated with the provided *identity hash*.
 
 
Then, a `Membership` document has to be created for a newcomer to *express their will* to integrate
 
the *Web of Trust*.
 
 
| Size | Data |
 
|:----:|:-----|
 
| 36 | *Time of signature* blockstamp
 
| 32 | *identity hash*
 
 
This document is only valid for a short time outside the blockchain starting at the provided
 
*blockstamp*.
 
 
To allow this document to be inserted in the blockchain, the `Identity` document must receive
 
certifications from members of the *Web of Trust* as `Certification` documents :
 
 
| Size | Data |
 
|:----:|:-----|
 
| 36 | *Time of signature* blockstamp
 
| 32 | *Document ID* if an `Identity` document
 
 
If not enough certifications are made before the `Membership` document expires, a new `Membership`
 
document and new certifications must be made. The number of certifications necessary is defined in
 
the parameters of the currency as `CertThreshold`.
 
 
Other rules impact if this set of documents can be inserted into the blockchain.
 
 
First, there is a **distance rule** to avoid [sybil attacks]. When a member have received and gave
 
at least `Y[N]` certifications each, where `Y[N] = N^(1/5)` and `N` is the number of members of the
 
*WoT*, he's called a **sentry**. Since certifications are unidirectionnal, the *Web of Trust* is a
 
directed graph with edges connecting *certifiers* to *certified*. We call the **distance** between A
 
and B the minimum number of edges we need to use to go from point A to point B in the graph. The
 
*distance rule* consist in computing the distance between each *sentry* and the newcoming indentity,
 
and testing that this distance is less than or equal to `StepMax` for at least `XPercent` of the
 
*sentries*, where `StepMax` and `XPercent` are parameters of the currency.
 
 
[sybil attacks]: https://en.wikipedia.org/wiki/Sybil_attack
 
 
Also, when a certification of a member reach the blockchain, no other certifications will be valid
 
in a `CertPeriod` time interval.
 
 
Finally, a member can't have more than `CertStock` active certifications in the blockchain. A
 
certification expires after a `CertValidity` period, allowing the member to certify other identities
 
(or to renew its previous certification).
 
 
When an identity enters the *WoT*, he can co-create the *Universal Dividend* and is allowed to
 
participate in the writing process of the blockchain. This identity is valid for a
 
`MembershipValidity` period, but can be renewed sooner after a `MembershipPeriod` period. This
 
renewing will only be accepted if the above rules are still applying (distance rule, certification
 
count).
 
 
If the `Membership` document expires, the identity leaves the *WoT*, and have another
 
`MembershipValidity` period to enters again the *WoT*, otherwise the identity is revoked and will
 
never be able to join again. An identity also leaves the *WoT* if at any time he have less than
 
the required minimum.
 
 
This leaving state can also be acheived manually by issuing a `Leaver` document (having the same
 
structure as the `Membership` document but with a different *document type*). An identity can
 
also be manualy revoked by issuing a `Revocation` document (with again the same structure).
 
 
It's important for users to precompute and sign a `Revocation` document and store it in a safe
 
place to be able to use it if their privare key is compromised or lost. It's fine to revocate an
 
identity and to create a new one, but members won't allow someone to create a new account while
 
the previous is not revoked, since it still can produce *Universal Divideds* and could allow the
 
user to produce more than one.
 
 
## 5. Transactions between accounts
 
 
### Notion of accounts
 
 
First, we need to define more precisely what is an **account**. An *account* can be anything that
 
holds funds.
 
 
In the previous protocol, there were only **unspent transactions outputs** (**UTXO**) and **UDs**.
 
A transaction consisted as a list of outputs, and list of outputs of previous transactions (sources)
 
and UDs, with each output locked by a condition satisfied by the next transaction. Thus, there
 
weren't any notion of account, only a set of *UTXOs* someone way able to spend. However for this
 
system to work it's mandatory to store all history of transactions, and many outputs spendable by
 
the same entity were in separate record and required more disk space. It also required to list
 
multiple sources if individual ones didn't hold enough money.
 
 
In this new protocol, *UTXOs* sharing the same spending condition are stored together unless
 
the issuers don't want to, as this merging mecanism is not compatible with some sorts of smart
 
contracts. However the vast majority of *UTXO* are mergeable and allow many things :
 
 
- Take less space on disk, in the blockchain and in network communications
 
- Make it easier for client to know how much they can spend
 
- Avoid to provide multiple inputs with the same condition, making simpler transactions documents
 
and removing duplicated signatures and proofs.
 
- UD spending condition is the same script as members identity account, so the set of "not yet spent
 
UDs" can be directly merged into the identity account.
 
 
### The Transaction document
 
 
A `Transaction` document contains the following :
 
 
| Size | Data |
 
|:----:|:-----|
 
| 1 | Number of inputs
 
| 1 | Number of outputs
 
| 2 | *(padding)*
 
|
 
| | **For each source** :
 
| 32 | Source
 
| 8 | Currency amount taken from this account
 
| 2 | Script size
 
| ... | *Unlock script (with alignement padding with `Nop` opcodes)*
 
|
 
| | **For each output** :
 
| 8 | Currency amount to send to this account
 
| 1 | Output type
 
| 1 | Script system version
 
| 2 | Script size
 
| ... | *Lock script (with alignement padding with `Nop` opcodes)*
 
 
The source field can be either :
 
 
- A lock script hash : we consume funds from any previous transaction made with this lock script.
 
```txt
 
Source = SHA256(ScriptHash ++ Index)
 
```
 
The `Index` is used to prevent double spending. The first time an account is a source, this
 
`Index` must be 0 and each time the account is used, this number must be increased by 1. This
 
prevent the same transaction document to be used multiple times on the same source to withdraw
 
more funds that the signer aggreed. With this technique it's also possible to generate in advance
 
multiple transaction by using consecutive *indexes*, each one becoming valid when the previous
 
one is included in the blockchain.
 
> The first time the source will be `SHA256(ScriptHash ++ 0)`, then `SHA256(ScriptHash ++ 1)`,
 
> then `SHA256(ScriptHash ++ 2)`, etc.
 
 
- A transaction id : we consume funds from a specific non-merged transaction
 
```txt
 
Source = SHA256(TransactionID ++ Index)
 
```
 
The **transaction ID** is the *document ID* of the source transaction, and the *index* allow to
 
target a specific output of this source transaction. It can only be used once as a source and
 
the amount needs to be equal to the output amount provided in the source transaction. After it's
 
used, it can be forgotten.
 
 
In each case, this hash, the `ScriptHash`/`TransactionID` and the `Index` are stored in the
 
blockchain to resolve where are the funds.
 
 
The output type can be :
 
 
| Type | Description |
 
|:----:|:-----|
 
| 0 | Merge/account, complete script
 
| 1 | Non-merge/UTXO, complete script
 
 
### The script system
 
 
> This system is heavily inspired by Bitcoin script system discribed
 
> [here](https://en.bitcoin.it/wiki/Script). It adds to it transaction data fetching (such as
 
> outputs, amounts); merkelized scripts and multiple cryptographic systems support.
 
 
The script system is simple, **stack-based** and processed from left to right. It is intentionnaly
 
**not Turing-complete, with no loops**.
 
 
The stack hold *byte arrays*. When used as numbers, byte arrays are interpreted as
 
**big-endian variable-length integers** with two's complement for sign handling. 0 can also be
 
represented by a null-length array. Byte array are interpreted as *booleans* where `false` is
 
represented by 0 and `true` by any other value.
 
 
A **main stack** and **alt stack** are available and empty by default. The executed script is the
 
concatenation of the *unlock script* and the *lock script*. The *unlock script* is a
 
script putting data onto the stack which will be used by the *lock script*.
 
 
A *transaction* is valid if nothing in the script triggers a failure, the main stack contains only
 
one `true` value and the alt stack is empty. A transaction can be made valid for undefined
 
behaviors to allow soft-forks.
 
 
> We'll refeer to the **main stack** as **the stack** and precise **alt stack** when necessary.
 
 
#### Opcodes
 
 
| Opcode | Hex | Word | Input | Output | Description |
 
|:------:|:---:|:-----|:------|:-------|:------------|
 
| | | | | | **Constants**
 
| `0` | `0x00` | `C0`, `Zero`, `False` | *none* | *empty value* | An empty array is pushed on the stack.
 
| `1-75` | `0x01-0x4b` | `PushData1-PushData75` | *special* | *data* | The next *opcode* bytes is data to be pushed on the stack.
 
| `76` | `0x4c` | `PushData1B` | *special* | *data* | The next byte contains the number of bytes to be pushed on the stack.
 
| `77` | `0x4d` | `PushData2B` | *special* | *data* | The next two bytes contains the number of bytes to be pushed on the stack.
 
| `78` | `0x4e` | `PushData4B` | *special* | *data* | The next four bytes contains the number of bytes to be pushed on the stack.
 
| `80` | `0x50` | `CN1`, `NegOne`| *nothing* | `-1` | The number -1 is pushed onto the stack.
 
| `81` | `0x51` | `C1`, `One`, `True` | *nothing* | `1` | The number 1 is pushed onto the stack.
 
| `82-96` | `0x52-0x60` | `C2-C16` | *nothing* | `2-16` | The number in the word name (2-16) is pushed onto the stack.
 
|
 
| | | | | | **Flow control**
 
| `97` | `0x61` | `Nop` | *nothing* | *nothing* | Does nothing.
 
| `98` | `0x62` | `If` | `condition` | *nothing* | If the top stack value (`condition`) is not `false`, opcodes until an `Else` or `Fi` are executed, otherwise they are ignored. The top stack value is always removed.
 
| `99` | `0x63` | `IfNot` | `condition` | *nothing* | If the top stack value (`condition`) is `false`, opcodes until an `Else` or `Fi` are executed, otherwise they are ignored. The top stack value is always removed.
 
| `100` | `0x64` | `Else` | *nothing* | *nothing* | If the preceding `If`/`IfNot` was not executed then opcodes until a `Fi` are executed, otherwise they are ignored.
 
| `101` | `0x65` | `Fi` | *nothing* | *nothing* | Ends an if/else block. All blocks must end, or the transaction is **invalid**. A `Fi` without `If`/`IfNot` earlier is also not valid.
 
| `102` | `0x66` | `Assert`/`Verify` | `true`/`false` | *nothing* / *panic* | **Marks transaction as invalid** if top stack value in not `true`. The top stack value is removed.
 
| `103` | `0x67` | `Panic`/`Return` | *nothing* | *panic* | **Marks transaction as invalid.**
 
|
 
| | | | | | **Stack**
 
| `104` | `0x68` | `ToAltStack` | `xn .. x2 x1 x0 <n>` | `(alt) x0 x1 x2 .. xn` | Puts the `n` items on top of the main stack onto the top of the alt stack, one by one. Removes them from the main stack.
 
| `105` | `0x69` | `FromAltStack` | `(alt) xn .. x2 x1 x0 (main) <n>` | `x0 x1 x2 .. xn` | Puts the `n` items on top of the alt stack onto the top of the main stack, one by one. Removes them from the alt stack.
 
| `106` | `0x6a` | `Depth` | *nothing* | `<stack size>` | Puts the number of stack items onto the stack.
 
| `107` | `0x6b` | `IfDup` | `x` | `x`/`x x` | If the stop stack value is not `0`, duplicate it.
 
| `108` | `0x6c` | `Drop` | `x` | *nothing* | Removes the top stack item.
 
| `109` | `0x6d` | `Dup` | `x` | `x x` | Duplicate the top stack item.
 
| `110` | `0x6e` | `Nip` | `x1 x2` | `x2` | Removes the second-to-top stack item.
 
| `111` | `0x6f` | `Over` | `x1 x2` | `x1 x2 x1` | Copies the second-to-top stack item to the top.
 
| `112` | `0x70` | `Pick` | `xn ... x2 x1 x0 <n>` | `xn .. x2 x1 x0 xn` | The item `n` back in the stack is copied to the top.
 
| `113` | `0x71` | `Roll` | `xn ... x2 x1 x0 <n>` | `.. x2 x1 x0 xn` | The item `n` back in the stack is moved to the top.
 
| `114` | `0x71` | `Rot` | `x1 x2 x3` | `x2 x3 x1` | The top three item on the stack are rotated to the left.
 
| `115` | `0x72` | `Swap` | `x1 x2` | `x2 x1` | The top two items on the stack are swapped.
 
| `116` | `0x73` | `Tuck` | `x1 x2` | `x2 x1 x2` | The item at the top of the stack is copied and inserted before the second-to-top item.
 
| `117` | `0x74` | `Drop2` | `x1 x2` | *nothing* | Removes the top two stack items.
 
| `118` | `0x75` | `Dup2` | `x1 x2` | `x1 x2 x1 x2` | Duplicates the top two stack items.
 
| `119` | `0x76` | `Dup3` | `x1 x2 x3` | `x1 x2 x3 x1 x2 x3` | Duplicates the top three stack items.
 
| `120` | `0x77` | `Over2` | `x1 x2 x3 x4` | `x1 x2 x3 x4 x1 x2` | Copies the pair of items two spaces back in the stack to the front.
 
| `121` | `0x78` | `Rot2` | `x1 x2 x3 x4 x5 x6` | `x3 x4 x5 x6 x1 x2` | The fifth and sixth items back are moved to the top of the stack.
 
| `122` | `0x79` | `Swap2` | `x1 x2 x3 x4` | `x3 x4 x1 x2` | Swaps the top two pairs of items.
 
| `123` | `0x7a` | `IsEmpty` | `in` | `true`/`false` | Returns 1 if the top of the stack in a zero-length vector. It consumes the input, so if it needs to be used it should be duplicated first.
 
| `124` | `0x7b` | `Split` | `value index` | `tail head` | Split the top of the stack in 2 parts, the tail starting at given index. If `index` is greater than the size of `value`, tail will be an *empty value*. If `index` is 0, head will be an *empty value*.
 
|
 
| | | | | | **Bitwise Logic**
 
| `128` | `0x80` | `Invert` | `in` | `out` | Flips all of the bits in the input.
 
| `129` | `0x81` | `BitAnd` | `x1 x2` | `out` | Bolean *and* between each bit in the inputs.
 
| `130` | `0x82` | `BitOr` | `x1 x2` | `out` | Bolean *or* between each bit in the inputs.
 
| `131` | `0x83` | `BitXor` | `x1 x2` | `out` | Bolean *exclusive or* between each bit in the inputs.
 
| `132` | `0x84` | `BitEqual` | `x1 x2` | `true`/`false` | Return 1 if the inputs are exactly equal, 0 otherwise.
 
|
 
| | | | | | **Arithmetic**
 
| | | | | | *Arithmetic inputs are limited to signed 64-bit integers, but may overflow their output.*
 
| `144` | `0x90` | `Add1` | `in` | `out` | 1 is added to the input.
 
| `145` | `0x91` | `Sub1` | `in` | `out` | 1 is subtracted from the input.
 
| `146` | `0x92` | `Negate` | `in` | `out` | The sign of the input is flipped.
 
| `147` | `0x93` | `Abs` | `in` | `out` | The input is made positive.
 
| `148` | `0x94` | `Not` | `in` | `out` | If the input is 0 or 1, it is flipped. Otherwise the output will be 0.
 
| `149` | `0x95` | `Not0` | `in` | `out` | Returns 0 if the input is 0, 1 otherwise.
 
| `150` | `0x96` | `Add` | `a b` | `out` | a is added to b.
 
| `151` | `0x97` | `Sub` | `a b` | `out` | b is subtracted from a.
 
| `152` | `0x98` | `And` | `a b` | `out` | If both a and b are not 0, the output is 1, otherwise 0.
 
| `153` | `0x99` | `Or` | `a b` | `out` | If a or b in not 0, the output is 1, otherwise 0.
 
| `154` | `0x9a` | `NumEqual` | `a b` | `out` | Returns 1 if numbers are equal, otherwise 0.
 
| `155` | `0x9b` | `NumNotEqual` | `a b` | `out` | Returns 1 if numbers are not equal, otherwise 0.
 
| `156` | `0x9c` | `NumLessThan` | `a b` | `out` | Returns 1 if a is less than b, 0 otherwise.
 
| `157` | `0x9d` | `NumGreaterThan` | `a b` | `out` | Returns 1 if a is greater than b, 0 otherwise.
 
| `158` | `0x9e` | `NumLessThanOrEqual` | `a b` | `out` | Returns 1 if a is less than or equal to b, 0 otherwise.
 
| `159` | `0x9f` | `NumGreaterThanOrEqual` | `a b` | `out` | Returns 1 if a is greater than or equal to b, 0 otherwise.
 
| `160` | `0xa0` | `Min` | `a b` | `out` | Returns the smaller of a and b.
 
| `161` | `0xa1` | `Max` | `a b` | `out` | Returns the larger of a and b.
 
| `162` | `0xa2` | `Within` | `x min max` | `out` | Returns 1 if x is within the specified range (left-inclusive), 0 otherwise.
 
| `163` | `0xa3` | `Sum` | `xn .. x2 x1 x0 <n>` | `out` | Returns the sum of the `n` top values from the stack.
 
| | | | | | ***Arithmetic operations on currency values (takes account of the base) :***
 
| `164` | `0xa4` | `CurrencyEqual` | `a b` | `out` | Returns 1 if numbers are equal, otherwise 0.
 
| `165` | `0xa5` | `CurrencyNotEqual` | `a b` | `out` | Returns 1 if numbers are not equal, otherwise 0.
 
| `166` | `0xa6` | `CurrencyLessThan` | `a b` | `out` | Returns 1 if a is less than b, 0 otherwise.
 
| `167` | `0xa7` | `CurrencyGreaterThan` | `a b` | `out` | Returns 1 if a is greater than b, 0 otherwise.
 
| `168` | `0xa8` | `CurrencyLessThanOrEqual` | `a b` | `out` | Returns 1 if a is less than or equal to b, 0 otherwise.
 
| `169` | `0xa9` | `CurrencyGreaterThanOrEqual` | `a b` | `out` | Returns 1 if a is greater than or equal to b, 0 otherwise.
 
| `170` | `0xaa` | `CurrencyMin` | `a b` | `out` | Returns the smaller of a and b.
 
| `171` | `0xab` | `CurrencyMax` | `a b` | `out` | Returns the larger of a and b.
 
| `172` | `0xac` | `CurrencyWithin` | `x min max` | `out` | Returns 1 if x is within the specified range (left-inclusive), 0 otherwise.
 
| `173` | `0xad` | `CurrencySum` | `xn .. x2 x1 x0 <n>` | `out` | Returns the sum of the `n` top values from the stack.
 
|
 
| | | | | | **Crypto**
 
| `176` | `0xb0` | `Hash` | `value algo` | `hash` | The input is hashed using `algo` hashing algorithm. The list of algorithms is available below.
 
| `177` | `0xb1` | `CheckSig` | `pubkey sig msg pubkeyhash` | `true`/`false` | The signature must be a valid signature of `msg` and given *public key* (in key format described before). `pubkeyhash` must also correspond to `pubkey`. If it is, 1 is returned, 0 otherwise. If the `pubkeyhash` indicate an unknown cryptographic system, it returns 1 to allow backward-compatible addition of new ones. It can be used for smart contracts by requiering a signed known-in-advance message from an oracle/third-party.
 
| `178` | `0xb2` | `CheckMultiSig` | `pub1 pub2 ... sig1 sig2 ... msg pubhash1 pubhash2 <count>` | valid sig count | Verify each group `(sign, pubn, pubhashn)`, return the sum of each internal `CheckMsgSig`.
 
| `179` | `0xb3` | `EvalScript` | `script hash` | *special* | Evaluate `script` as if it were in-place. The script must have a Merkle root equal to `hash`. If not, **transaction is invalid**. If the script *panic* (says the transaction is invalid), the **transaction is invalid**. The script hashing algorithm is described later in this document.
 
| `180` | `0xb4` | `UnusedBranch` | *special* | `false` | Returns `false`. The `(opcode ++ hash)` of this instruction are the **next 33 bytes in the script**. It allow to only provide hashes of unused code when using `Eval` opcode. Can only be used in *unlock script* and an output having an `Unused` opcode in its lock script is **invalid**.
 
|
 
| | | | | | **Data fetching**
 
| `192` | `0xc0` | `FetchTxHash` | *nothing* | `transaction_hash` | Returns the current transaction hash used to compute signatures.
 
| `193` | `0xc1` | `FetchTxSig` | `index` | `signature`/*empty* | Returns the transaction document signature at this index, or an *empty value* if out of bounds. This allow to segregate signatures outside of the transaction body and prevent transaction malleability. It should never be used in an lock script since the order of signature could not be guaranted with multiple sources. It should only be used in the unlock script.
 
| `194` | `0xc2` | `FetchSourceBlockTime` | *nothing* | `timestamp blockid` | Returns the timestamp and blockid corresponding to the block in which the source transaction document appears. One of the 2 dates can be discarded with `Drop` or `Nip` opcodes. If the output is in merge-mode, this opcode returns the date of the last time this account has been used as input. It can be used to allow spending X times per period, or to define new conditions after a spending is done at a given time.
 
| `195` | `0xc3` | `FetchTargetBlockTime` | *nothing* | `timestamp blockid` | Returns the timestamp and blockid corresponding to the block in which the spending transaction document appears. One of the 2 dates can be discarded with `Drop` or `Nip` opcodes. It can be used to prevent using a source based on the date of the spending transaction.
 
| `196` | `0xc4` | `FetchDeltaBlockTime` | *nothing* | `delta_timestamp delta_blockid` | Returns the difference between `FetchTargetBlockTime` and `FetchSourceBlockTime`.
 
| `197` | `0xc5` | `FetchOutputAmount` | `output_index` | `amount base`/*empty* *empty* | Returns the amount spent by a specific output. Returns an empty value if this index is out of bound.
 
| `198` | `0xc6` | `FetchOutputAddress` | `output_index` | `address`/*empty* | Returns the script hash (address) of a specific output. Returns an empty value if this index is out of bound. It can be used to force specific conditions for an output.
 
 
Any **undefined operators** will prevent the script from running and mark the transaction as
 
**valid**. They cause an **anyone can spend** behavior. With this construct, giving them a new
 
meaning can only restrict the set of valid transactions and outdated client will never see new
 
opcodes as invalid to their rules. It can be used to add new backward-compatible features.
 
 
If no backward-compatible features needs to be added, we can add them as part of a new version of
 
the script system. The current one is version 0, and any unknown script system version makes the
 
transaction valid without even looking at the script content, allowing to make these changes in
 
a backward-compatible way.
 
 
> Client should show warnings when they see an "anyone-can-spend" script.
 
 
Padding is done through `Nop` operators, and any leading `Nop` opcodes will be discarded before any
 
treatment (hashing, execution).
 
 
#### Hashing algorithms list
 
 
| Algo | Function |
 
|:----:|:-----|
 
| `0` | SHA-256(value)
 
 
Any other hashing code will mark the transaction as **valid**, allowing no hashing algorithms to be
 
added by soft-forks.
 
 
> More hashing algorithms will be added later.
 
 
#### Script examples
 
 
To simplify our scripts examples, we write constants as `<data>` fields, and the stack push
 
is implied. When a signature is used, the use of `FetchTxSig` is implied.
 
 
- Classic pay-to-pubkey script
 
 
```txt
 
Lock : FetchTxHash <pubkeyhash> CheckSig
 
Unlock : <pubkey> 0 FetchTxSig
 
```
 
 
Here is a step by step execution of the script
 
 
| Stack | Script | Description |
 
|:------|:-------|:------------
 
| | `<pubkey> 0 FetchTxSig FetchTxHash <pubkeyhash> CheckDocSig` | Lock and unlock scripts are merged.
 
| `<pubkey> 0` | `FetchTxSig FetchTxHash <pubkeyhash> CheckDocSig` | Data is pushed on the stack.
 
| `<pubkey> <sig>` | `FetchTxHash <pubkeyhash> CheckDocSig` | Signature is pushed on the stack.
 
| `<pubkey> <sig> <tx_hash>` | `<pubkeyhash> CheckDocSig` | Transaction hash is pushed on the stack.
 
| `<pubkey> <sig> <tx_hash> <pubkeyhash>` | `CheckDocSig` | Public key hash is pushed on the stack.
 
| `true` | | Signature is checked.
 
 
There is only `true` in the stack, so this transaction is valid.
 
 
- 2-of-3-multisig script
 
 
```txt
 
Lock : FetchTxHash <pubkeyhash1> <pubkeyhash2> <pubkeyhash3> 3 CheckMultiSig 2 NumGreaterThanEqual
 
Unlock : <pubkey1> <empty> <pubkey3> 0 FetchTxSig <empty> 1 FetchTxSig
 
```
 
 
#### Script hashing
 
 
We must find a way to translate a stack-based script into a graph of dependency between
 
operations. Each operator consumes inputs and produces outputs than can be used to build
 
a graph. It's not a tree since a value can be used multiple time with a `Dup` opcode, but it
 
should not cause problems in bluiding a Merkle Tree with duplicated branches.
 
 
Each opcode becomes a node of the tree, and each producer of its input is a child, and the
 
consumers of its outputs are parents.
 
 
Let's build a 1-of-2-multisig script with separated checks :
 
 
```txt
 
Lock : FetchTxHash <pubkeyhash a> CheckSig 1 ToAltStack
 
FetchTxHash <pubkeyhash b> CheckSig 1 FromAltStack
 
Or
 
```
 
 
We have a first opcode pushing `<compact key a>` on the stack. Then `CheckSig` consume
 
it and some items from the stack, and push the result on the stack. The opcode `<compact key a>`
 
is a child of `CheckSig`. We can apply this rule to all of the operators to obtain this
 
tree :
 
 
```txt
 
-------Or--------
 
| |
 
---FromAltStack--- |
 
| | |
 
------ToAltStack---- 1 |
 
| | |
 
----CheckSig---- 1 ----CheckSig----
 
| | | |
 
FetchTxHash <pubkeyhash a> FetchTxHash <pubkeyhash b>
 
```
 
 
If an operator have multiple children, we add them in a tree in the same order as the inputs.
 
Here `ToAltStack` take in input `xn ... x2 x1 x0 <n>`, so they are inserted in the tree in
 
the same order from right to left.
 
 
The rules for the hash of an opcode are :
 
 
- If it consumes items from stacks, we add `SHA-256(SHA-256(child1) + SHA-256(child2) + ...)`
 
- If it provide data (`PushDataX` opcodes), we add `SHA-256(data)`
 
- We then hash all the above with `SHA-256`.
 
- We prefix the opcode.
 
 
The only exception is the `UnusedBranch` opcode having the `(opcode, hash)` pair in the 33 following
 
bytes. This is used to hide the unused branches at spending.
 
 
Exemple :
 
 
```txt
 
C4 PushData1B <data on 4 bytes>
 
```
 
 
becomes
 
 
```txt
 
PushData1B
 
+ SHA-256(
 
+ SHA-256(C4)
 
+ SHA-256(<data on 4 bytes>)
 
)
 
```
 
 
An opcode can be replaced by an `UnusedBranch` opcode **only if it always push one boolean value (0
 
or 1) on the main stack**. `UnusedBranch` will push `false` on the stack *as if* the underlying
 
branch returned false.
 
 
In the above example only the 2 `CheckDocSig` and the `Or` can be replaced by their hash.
 
Note that it's praticaly no possible to replace the `Or`, since it will return `false` and
 
the transaction will be invalid.
 
 
If we consider `<script_hash>` as the Merkle Root of the above script, we can have as a lock
 
script :
 
 
```txt
 
<script_hash> Eval
 
```
 
 
Then at spending we should have as unlock script :
 
 
```txt
 
<pubkey a> 0 FetchTxSig
 
[
 
FetchTxHash <pubkeyhash a> CheckSig 1 ToAltStack
 
UnusedBranch [CheckSig <branch hash>] 1 FromAltStack
 
Or
 
] -- this script is pushed in one byte array on top of the stack
 
```
 
 
or
 
 
```txt
 
<pubkey b> 0 FetchTxSig
 
[
 
UnusedBranch [CheckSig <branch hash>] 1 ToAltStack
 
FetchTxHash <pubkeyhash b> CheckSig 1 FromAltStack
 
Or
 
] -- this script is pushed in one byte array on top of the stack
 
```
 
 
In each case, the `UnusedBranch` opcode returns `false` but the other returns `true`, so `Or`
 
return `true`.
 
 
> **Warning** : A script developper should always expect a `true` value from a succesful non-pruned
 
> branch, otherwise pruning the branch may lead to an unwanted way to consume funds. If in a
 
> contract a `false` value is expected to validate a script, it should not be done in the MAST part.
 
 
#### Allow usage of V10 outputs
 
 
To allow spending of transaction in V10 format, we must translate the old scripts in this new format
 
and have the exact same behavior.
 
 
| V10 script | V11 lock script | V10 parameters | V11 unlock script
 
|:-----------|:------------|:---------------|:----
 
| `SIG(pubkey)` | `FetchTxHash <pubkeyhash> CheckSig` | `SIG(sig_index)` | `<pubkey> <sig_index> FetchTxSig`
 
| `XHX(sha256_hash)` | `1 Hash <sha256_hash> BitEqual` | `XHX(pass)` | `<pass>`
 
| `CLVT(timestamp)` | `FetchSourceBlockTime Drop <timestamp> NumGreaterThanOrEqual` | *nothing* | *nothing*
 
| `CSV(delay)` | `FetchDeltaBlockTime Drop <delay> NumGreaterThanOrEqual` | *nothing* | *nothing*
 
|
 
| `{X} AND {Y}` | `{X} 1 ToAltStack {Y} 1 FromAltStack And` | `{X} {Y}` | `{Y} {X}`
 
| `{X} OR {Y}` | `{X} 1 ToAltStack {Y} 1 FromAltStack Or` | `{X} {Y}` | `{Y} {X}`
 
 
> TODO : Need peer reviewing since it's a critical part of this protocol change.
 
 
## 6. Usage of V10 documents
 
 
For any currency running with the v10 Duniter protocol wanting to migrate to this new protocol, it's
 
necessary to be able to use v10 documents that are still in pools, such as identities or
 
certifications. Transaction are mostly inserted in the blockchain in the next block, so it's not
 
usefull to accept them, as it will result in complications to be compatible with the new
 
*account system*.
 
 
To include v10 documents, we can use the `V10Document` document type composed of :
 
 
| Size | Data |
 
|:----:|:-----|
 
| 2 | Size of the payload
 
| ... | Payload
 
 
with the payload being the text v10 document. This document don't need any issuer or signatures
 
since these are already in the v10 document.
 
 
When inserted into the state, signatures are no longer needed and documents can be converted in the
 
new format.
 
 
## 7. In depth block structure
 
 
### State machine logic
 
 
Each block tracks the transformation of one valid state to a new one.
 
 
```txt
 
State(t+1) = Transform(t+1, State(t))
 
```
 
 
A transformation is made of a succession of events. The order of these events can't be changed
 
since an event can use the consequence of a previous event. An event can be a document issued by a
 
user or a spontaneous event such as UD creation or document expiration.
 
 
```txt
 
State(t+1) = Event3(Event2(Event1(State(t))))
 
```
 
 
To allow forks handling it must be possible to find the previous state based on the new state and
 
the transformations.
 
 
```txt
 
State(t) = ReverseTransform(t+1, State(t+1))
 
State(t) = ReverseEvent1(ReverseEvent2(ReverseEvent3(State(t+1))))
 
```
 
 
### Main data structure : binary trees
 
 
When we have a set of entries to store in a Merkle tree, we divide them in 2 parts recursively. For
 
exemple if we have the set of documents `A, B, C, D, E, F`, we'll end up in 2 groups `A, B, C` and
 
`D, E, F`. Then `A, B, C` will then be decomposed in `A` and `B, C` (we use the Euclidan division,
 
`3 / 2 = 1`), same for `D, E, F`.
 
 
Finally alongside the root we store the hash of the entries list.
 
 
```txt
 
/\
 
/ \
 
entries list /\
 
/ \
 
/ \
 
/ \
 
/ \
 
/\ /\
 
/ \ / \
 
/ /\ / /\
 
A B C D E F
 
```
 
 
With this list we know that all items are in the tree and can be queried. Each node use the list
 
`A, B, C, D, E, F` to compute the tree and the list, and verify that the final hash corresponds. No
 
documents can be added or removed without updating the list.
 
 
This list need to have a consensual order to allow nodes to compute the same tree. For most trees
 
they will be ordered by alphabetic or numeric order, but some lists such as the events list must
 
not be sorted.
 
 
Entries can be documents (issued by users), some internal data of the system or subtrees.
 
Only documents hashes are stored in the tree, and they must be stored alongside the tree on disk
 
to be retreived.
 
 
By convention, if our root node is named `root`, then `root/A` qualifies the hash of the `A`
 
entry stored in this binary tree structure and we omit its path in the tree.
 
 
### Global structure of the tree
 
 
The Merkle tree is made as the following
 
 
- `/signature` : signature of the `container` with the issuer public key.
 
- `/container` : contains data signed by the block issuer.
 
- `issuer` : issuer public key.
 
- `nonce` : nonce used in the Proof of Work mechanism.
 
- `date` : block forging date
 
- `previous_root` : hash of the previous block `/`
 
- `transform` : list of events discribing transformations on the previous state
 
- `final_state` : state after all transformations
 
 
`/signature` and `/container` are in this order, and `/container` children are sorted in alphabetic
 
order.
 
 
Other fields are allowed and don't make the block invalid to allow future features to be
 
backward compatible (soft fork).
 
 
### State structure
 
 
The `state` is made of 2 parts :
 
 
- a `data` tree containing the actual state of the system. It contains only updated data and all
 
outdated ones are removed.
 
- a `requests` tree storing common request answers about the system is a `RememberWindow` block
 
period. This allow clients to make requests on "maybe outdated" data such as identity memberships,
 
spent UTXOs or emptied accounts.
 
 
Since all changes reflects `data` changes or "forgetings" after a defined window, this part can be
 
computed by each node and verified in a new block. None of the contents need to be propagated on
 
the network, only its hash `helpers` is needed. However if its invalid and the block is rejected,
 
a node can query its data to investigate where the problem comes from.
 
 
If the request is a "Yes/No" question, the client can compute both `Yes` and `No` answer and ask a
 
node which is in the tree. It prevent any attack by omission in the `RememberWindow`.
 
 
Nodes are only required to answer these requests in the `ForkWindow` blocks to be considered
 
cooperative. It means a client can request informations on deleted data in a
 
`ForkWindow + ForgetWindow` time period, and older informations can be discarded unless the node
 
wants to keep it for archives purposes.
 
 
The state contains the following data :
 
 
- `data/system/parameters` : stores system parameters
 
 
> All delays or periods are expressed in seconds
 
 
Contains as entries :
 
 
- `UDReevaluationPeriod` : Time period between two UD re-evaluations (v10 `dtReeval`)
 
- `UDReevaluationGrowth` : The %growth of the UD every `UDReevaluationPeriod` (v10 `c`)
 
- `UDFirstReevaluation` : Time of the first UD re-evaluation (v10 `udReevalTime0`)
 
- `UDCreationPeriod` : Time period between two UD creations (v10 `dt`)
 
- `UDFirstCreation` : Time of the first UD creation (v10 `udTime0`)
 
- `UDLastCreation` : Time of the last UD creation
 
- `UDFirstValue` : The first value of a UD (v10 `ud0`)
 
- `UDCurrentValue` : The current value of a UD
 
- `CertPeriod` : Minimum delay between 2 certifications of a same issuer (v10 `sigPeriod`)
 
- `CertStock` : Maxiumum quantity of active certifications made by a member (v10 `sigStock`)
 
- `CertWindow` : Maximum age a certification can have before being expired for non-writing (v10
 
`sigWindow`)
 
- `CertValidity` : Maximum age of an active signature (v10 `sigValidity`)
 
- `CertThreshold` : Minimim quantty of certifications to be member of the WoT (v10 `sigQty`)
 
- `MembershipPeriod` : Minimum delay between 2 memberships of a same issuer (v10 `msPeriod`)
 
- `MembershipWindow` : Maximum age a membership can have before being expired for non-writing (v10
 
`msWindow`)
 
- `MembershipValidity` : Maximum age of an active membership (v10 `msValidity`)
 
- `IdentityWindow`: Maximum age an identity can have before being expired for non-writing (v10
 
`idtyWindow`)
 
- `IdentityForgetPeriod` : Time after a revoked identity can be forgoten, allowing the username
 
and public key to be reused.
 
- `WoTSentriesPercent` : Minimum percent of sentries to reach to match the distance rule (v10
 
`xpercent`)
 
- `WotStepMax` : Maximum distance between each WoT member and a newcomer for the distance rule
 
(v10 `stepMax`)
 
- `BlockMedianTimeWindow` : number of blocs used for calculating median time (v10
 
`medianTimeBlock`)
 
- `BlockTargetPeriod` : Target time between 2 blocks (v10 `avgGenTime`)
 
- `PoWMin` : minimum block difficulty for all members
 
- `PoWReevaluationPeriod` : The number of blocks requiered to evaluate `BlockPoWMin` value
 
(v10 `dtDiffEval`)
 
- `PowExcludedCalculators` : The percent of previous issuers to reach for personalized difficulty (v10
 
`percentRot`)
 
- `BlockHeadersRememberWindow` : Time after an old block header is removed from `data/system/headers`.
 
- `RequestRememberWindow` : Time after an outdated answser can be removed from requests.
 
- `CurrencyUnitBase` : Applied as a power of 10 to currency amounts. Allow value rotations and
 
management of big numbers caused by the exponentional growth of units due to UD creation.
 
- `CurrencyBaseShiftThreshold` : When the UD is greater than this number, the unit base is
 
increased.
 
 
- `data/system/headers` : stores past block headers (with only hashes of `/container` children)
 
 
Each block header is indexed and sorted by its blockstamp. Since a blockstamp starts with the
 
block id, they are sorted by block ids in chronological order.
 
 
- `data/currency/accounts` : stores account.
 
 
Each account is indexed and sorted by its account ID (lock script hash) and contains :
 
 
- `script` : complete script (in tree : raw data hash instead of script hash)
 
- `balance` : amount on this account
 
- `index` : chaining index
 
- `last_output_time` : last `(timestamp, blockid)` it was listed as output (receive funds)
 
- `last_input_time` : last `(timestamp, blockid)` it was listed as input (spent funds,
 
`(0, -1)` if never spent)
 
 
- `data/currency/utxos` : stores UTXOs.
 
 
Each UTXO is indexed and sorted by its `(TransactionID, Index)` and contains :
 
 
- `script` : complete script (raw data hash in tree)
 
- `amount` : amount in this UTXO
 
- `time` : `(timestamp, blockid)` at which the transaction as been inserted in block
 
 
- `data/wot/members` : stores active identities.
 
 
Each identity is indexed and sorted by its identity hash and contains :
 
 
- `username`
 
- `public key hash`
 
- `created_timestamp`
 
- `last_renewal_timestamp`
 
 
- `data/wot/excluded` : stores excluded identities.
 
 
Each identity is indexed and sorted by its identity hash and contains :
 
 
- `username`
 
- `public key hash`
 
- `exclusion_timestamp`
 
 
- `data/wot/certifications` : stores active certifications.
 
 
Each certification is indexed and sorted by its document ID and contains :
 
 
- `certifier`
 
- `certified`
 
- `certification_timestamp` : blockstamp contained in the certification document
 
 
- `data/wot/revoked` : stores revoked identities.
 
 
Each indentity is indexed and sorted by its identity hash and contains :
 
 
- `username`
 
- `public_key_hash`
 
- `revocation_timestamp`
 
 
- `requests/wot/username_is_member` : "Is X a member ?" answer for all active members and old
 
members for a fixed amount of time.
 
 
Each answer is indexed and stored by its username. The entry must be the hash of
 
`<username> is a member` or `<username> is not a member`.
 
 
- `requests/username_received_certifications` : store the list of received certifications (document
 
ids) for each member.
 
 
Each answer is indexed and stored by its username.
 
- `requests/username_emited_certifications` : store the list of emited certifications (document ids)
 
for each member.
 
 
Each answer is indexed and stored by its username.
 
 
> For each `requests/wot/username_XXX` request there is a corresponding `requests/wot/identity_hash_XXX`
 
> request indexed by the identity hash of the member.
 
 
> TODO : Maybe add `username_is_outdistanced`. It needs to be done once every block so it's
 
> maybe not too much computationaly heavy for 5 minutes blocks.
 
 
> This tree is not yet complete and is subject to changes.
 
 
### Transform structure
 
 
The `transform` is made of a list of events applied to the previous state and computing the new
 
state. These events must not be sorted since their application may not be commutative. They can be
 
issued by users to use the currency or interact with the WoT or be spontaneous if they issued by the
 
system. The later can be a UD creation, certification or identity expiration, data deletion, etc.
 
 
Everytime a data is destroyed in the forward application, its content is included in the event
 
data so it can be applied in reverse and restored.
 
 
Each event have this data structure :
 
 
| Size | Data |
 
|:----:|:-----|
 
| 2 | Event type
 
| 2 | Event payload size in bytes
 
| ... | Payload
 
 
We'll now list all possible events, their validity rules and how they affect the state (in forward
 
or reverse) :
 
 
#### `Transaction` user event : spend funds from sources to outputs.
 
 
Payload content :
 
 
- Transaction document
 
- Destroyed accounts data
 
- Destroyed UTXOs data
 
 
Rules :
 
 
- Sources must be account with enough funds, or UTXOs.
 
- All sources script locks must return true.
 
- All outputs scripts must be well-formed.
 
- The sum of input amounts must be equal to the sum of output amounts.
 
 
Forward application :
 
 
- Each account source amount is decreased by the provided amount, and empty accounts are
 
destroyed.
 
- Each UTXO source is destroyed.
 
- Each account output amount is increased by the provided amount, or created if it doesn't exist
 
yet.
 
- Each UTXO output is created.
 
 
Backward application :
 
 
- Each UTXO output is destroyed.
 
- Each account output amount is decreased by the provided amount, and destroyed if it now equals
 
0.
 
- Each UTXO source is created.
 
- Each account source amount is increased by the provided amount, or created if it was destroyed.
 
 
#### `DividendCreation` spontaneous event : create UD for all active members
 
 
Payload content :
 
 
- Previous UD creation timestamp (0 if first UD creation).
 
- Current UD creation timestamp.
 
- UD amount.
 
 
Rules :
 
 
- For first UD : the first block having a median timestamp greater than `UDFirstCreation` must
 
have this event.
 
- For other UDs : the first block having a median timestamp greater than `UDLastCreation` +
 
`UDCreationPeriod` must have this event.
 
- All payload data matches.
 
 
Forward application :
 
 
- Add `UDCurrentValue` to the account of each active member in this block. The account of a member
 
have a script of `<pubkeyhash> CheckDocSig`.
 
- Set `UDLastCreation` to the block median time.
 
 
Backward application :
 
 
- Set `UDLastCreation` to the previous UD creation timestamp.
 
- Remove UD amount from the account of each active member in this block.
 
 
#### `GarbageCollection` spontaneous event : destroy account with amounts under the minimum allowed
 
 
Payload content :
 
 
- Destroyed accounts data
 
 
Rules :
 
 
- Must contains all and only account with amounts under the minimum allowed.
 
- Must exist if it's possible to destroy an account.
 
- Must not exist if it's not the case.
 
 
Forward application :
 
 
- Destroy all provided accounts.
 
 
Backward application :
 
 
- Create all provided accounts.
 
 
> TODO : Provide order of event types
 
\ No newline at end of file
Loading