Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • feat/network_reset_tools
  • poka/prepare-gtest-reboot-october-25
  • tuxmain/longer-distance-period
  • master
  • set_UniversalDividendApi_in_RuntimeApiCollection
  • network/gtest-1000
  • upgradable-multisig
  • runtime/gtest-1000
  • network/gdev-800
  • cgeek/issue-297-cpu
  • gdev-800-tests
  • update-docker-compose-rpc-squid-names
  • fix-252
  • 1000i100-test
  • hugo/tmp-0.9.1
  • network/gdev-803
  • hugo/endpoint-gossip
  • network/gdev-802
  • hugo/distance-precompute
  • network/gdev-900
  • tuxmain/anonymous-tx
  • debug/podman
  • hugo/195-doc
  • hugo/195-graphql-schema
  • hugo-tmp-dockerfile-cache
  • release/client-800.2
  • release/runtime-800
  • feature/show_milestone
  • release/runtime-701
  • hugo-release/runtime-701
  • release/runtime-700
  • pini-check-password
  • tuxmain/benchmark-distance
  • release/runtime-600
  • feature/dc-dump
  • tests/distance-with-oracle
  • release/runtime-500
  • feature/distance-rule
  • release/hugo-chainspec-gdev5
  • release/runtime-401
  • 105_gitlab_container_registry
  • ci_cache
  • release/poka-chainspec-gdev5-pini-docker
  • release/poka-chainspec-gdev5
  • release/runtime-400
  • release/runtime-300
  • release/runtime-200
  • release/runtime-100
  • elois-duniter-storage
  • elois-compose-metrics
  • elois-smoldot
  • gdev-1000-test
  • gdev-800
  • gdev-800-0.8.0
  • gdev-802
  • gdev-803
  • gdev-900-0.10.0
  • gdev-900-0.10.1
  • gdev-900-0.9.0
  • gdev-900-0.9.1
  • gdev-900-0.9.2
  • gtest-1000
  • gtest-1000-0.11.0
  • gtest-1000-0.11.1
  • runtime-100
  • runtime-101
  • runtime-102
  • runtime-103
  • runtime-104
  • runtime-105
  • runtime-200
  • runtime-201
  • runtime-300
  • runtime-301
  • runtime-302
  • runtime-303
  • runtime-400
  • runtime-401
  • runtime-500
  • runtime-600
  • runtime-700
  • runtime-701
  • runtime-800
  • runtime-800-backup
  • runtime-800-bis
  • runtime-801
  • v0.1.0
  • v0.2.0
  • v0.3.0
  • v0.4.0
  • v0.4.1
91 results

Target

Select target project
No results found
Select Git revision
  • upgrade_polkadot_v0.9.42
  • archive_upgrade_polkadot_v0.9.42
  • pallet-benchmark
  • master
  • jrx/workspace_tomls
  • hugo-gtest
  • hugo-rework-genesis
  • hugo-remove-duniter-account
  • hugo-tmp
  • release/poka-chainspec-gdev5-pini-docker
  • release/poka-chainspec-gdev5
  • ud-time-64
  • distance
  • david-wot-scenarios-cucumber
  • release/runtime-400
  • elois-revoc-with-old-key
  • elois-smish-members-cant-change-or-rem-idty
  • release/runtime-300
  • elois-fix-idty-post-genesis
  • elois-fix-sufficients-change-owner-key
  • test-gen-new-owner-key-msg
  • elois-substrate-v0.9.23
  • elois-technical-commitee
  • elois-opti-cert
  • release/runtime-200
  • elois-fix-85
  • elois-rework-certs
  • elois-remove-renewable-period
  • elois-ci-binary-release
  • release/runtime-100
  • elois-duniter-storage
  • elois-compose-metrics
  • elois-smoldot
  • no-bootnodes
  • ts-types
  • runtime-100
  • runtime-101
  • runtime-102
  • runtime-103
  • runtime-104
  • runtime-105
  • runtime-200
  • runtime-201
  • runtime-300
  • runtime-301
  • runtime-302
  • runtime-303
  • runtime-400
  • v0.1.0
  • v0.2.0
  • v0.3.0
  • v0.4.0
52 results
Show changes
419 files
+ 771644
113599
Compare changes
  • Side-by-side
  • Inline

Files

.cargo/config

deleted100644 → 0
+0 −8
Original line number Original line Diff line number Diff line
[alias]
cucumber = "test -p duniter-end2end-tests --test cucumber_tests --"
sanity-gdev = "test -p duniter-live-tests --test sanity_gdev -- --nocapture"
tu = "test --workspace --exclude duniter-end2end-tests --exclude duniter-live-tests"
tb = "test --features runtime-benchmarks -p"
rbp = "run --release --features runtime-benchmarks -- benchmark pallet --chain=dev --steps=50 --repeat=20 --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --output=. --pallet"
xtask = "run --package xtask --"

.cargo/config.toml

0 → 100644
+13 −0
Original line number Original line Diff line number Diff line
[alias]
sanity-gdev = "test -Zgit=shallow-deps -p duniter-live-tests --test sanity_gdev -- --nocapture"
tu = "test -Zgit=shallow-deps --workspace --exclude duniter-end2end-tests --exclude duniter-live-tests --features constant-fees" # Unit tests with constant-fees
tf = "test -Zgit=shallow-deps --workspace --exclude duniter-end2end-tests --exclude duniter-live-tests test_fee" # Custom fee model tests
# `te` and `cucumber` are synonyms
te = "test -p duniter-end2end-tests --test cucumber_tests --features constant-fees --"
cucumber-build = "build -Zgit=shallow-deps --features constant-fees"
cucumber = "test -Zgit=shallow-deps -p duniter-end2end-tests --test cucumber_tests --"
ta = "test -Zgit=shallow-deps --workspace --exclude duniter-live-tests --features constant-fees"
tb = "test -Zgit=shallow-deps --features runtime-benchmarks -p"
rbp = "run -Zgit=shallow-deps --release --features runtime-benchmarks -- benchmark pallet --chain=dev --steps=50 --repeat=20 --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --output=. --pallet"
xtask = "run -Zgit=shallow-deps --package xtask --"
cucumber-node = "run -Zgit=shallow-deps -- --chain=gdev_dev --execution=Native --sealing=manual --force-authoring --rpc-cors=all --tmp --rpc-port 9944 --alice --features constant-fees"
+1 −0
Original line number Original line Diff line number Diff line
@@ -6,3 +6,4 @@ docker/Dockerfile
docker-compose.yml
docker-compose.yml
arm-build/
arm-build/
**/target/
**/target/
build/
+435 −187

File changed.

Preview size limit exceeded, changes collapsed.

Original line number Original line Diff line number Diff line
@@ -29,7 +29,7 @@ USER duniter
# check if executable works in this container
# check if executable works in this container
RUN /usr/local/bin/duniter --version
RUN /usr/local/bin/duniter --version


EXPOSE 30333 9933 9944
EXPOSE 30333 9944
VOLUME ["/duniter"]
VOLUME ["/duniter"]


ENTRYPOINT ["/usr/local/bin/duniter"]
ENTRYPOINT ["/usr/local/bin/duniter"]
Original line number Original line Diff line number Diff line
@@ -4,7 +4,7 @@
    100
    100
  ],
  ],
  "[json]": {
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
    "editor.defaultFormatter": "vscode.json-language-features"
  },
  },
  "[yaml]": {
  "[yaml]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
    "editor.defaultFormatter": "esbenp.prettier-vscode"
@@ -14,5 +14,6 @@
    "port_p2p": 19931,
    "port_p2p": 19931,
    "port_rpc": 19932,
    "port_rpc": 19932,
    "port_ws": 19933
    "port_ws": 19933
  }
  },
  "rust-analyzer.showUnlinkedFileNotification": false
}
}
 No newline at end of file
+11 −8
Original line number Original line Diff line number Diff line
@@ -4,7 +4,7 @@ Before contributing, please make sure that your development environment is prope


[Setting up your development environment]
[Setting up your development environment]


Sign-ups on our gitlab are disabled. If you would like to contribute, please ask for its creation on [the technical forum].
Sign-ups on our gitlab are disabled. If you would like to contribute, please ask for an account on [the technical forum].


When contributing to this repository, please first discuss the change you wish to make via issue or
When contributing to this repository, please first discuss the change you wish to make via issue or
via [the technical forum] before making a change.
via [the technical forum] before making a change.
@@ -13,13 +13,15 @@ Please note we have a specific workflow, please follow it in all your interactio


## Developer documentation
## Developer documentation


Please read [Developer documentation] before contribute.
Please read [Developer documentation] before contributing.


## Workflow
## Workflow


- If there is an unassigned issue about the thing you want to contribute to, assign the issue to yourself.
- Create a branch based on `master` and prefixed with your nickname. Give your branch a short name indicating the subject.
- Create a branch based on `master` and prefixed with your nickname. Give your branch a short name indicating the subject.
- Create an MR from your branch to `master`.
- Create an MR from your branch to `master`. Prefix the title with `Draft: ` until it's ready to be merged.
- Never contribute to a branch of another contributor! If the contributor makes a `git rebase` your commit will be lost!
- If the MR is related to an issue, mention the issue in the description using the `#42` syntax.
- Never push to a branch of another contributor! If the contributor makes a `git rebase` your commit will be lost!
- Before you push your commit:
- Before you push your commit:
  - Apply formatters (rustfmt and prettier) and linter (clippy)
  - Apply formatters (rustfmt and prettier) and linter (clippy)
  - Document your code
  - Document your code
@@ -30,14 +32,15 @@ Please read [Developer documentation] before contribute.
1. Ensure you rebased your branch on the latest `master` commit to avoid any merge conflicts.
1. Ensure you rebased your branch on the latest `master` commit to avoid any merge conflicts.
1. Ensure that you respect the [commit naming conventions].
1. Ensure that you respect the [commit naming conventions].
1. Ensure that all automated tests pass with the `cargo test` command.
1. Ensure that all automated tests pass with the `cargo test` command.
1. Ensure that the code is well formated `cargo fmt` and comply with the good practices `cargo clippy`. If you have been working on tests, check everything with `cargo clippy --all --tests`.
1. Ensure that the code is well formatted `cargo fmt` and complies with the good practices `cargo clippy`. If you have been working on tests, check everything with `cargo clippy --all --tests`.
1. Update the documentation with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters.
1. Update the documentation with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters.
1. Push your branch on the gitlab and create a merge request. Briefly explain the purpose of your contribution in the description of the merge request.
1. Push your branch on the gitlab and create a merge request. Briefly explain the purpose of your contribution in the description of the merge request.
1. Tag a Duniter reviewer so they will review your contribution. If you still have no news after several weeks, tag another reviewer or/and talk about your contribution on [the technical forum].
1. Mark the MR as ready (or remove the `Draft: ` prefix) only when you think it can be reviewed or merged.
1. Assign a Duniter reviewer so they will review your contribution. If you still have no news after several weeks, ask explicitly for a review, or tag another reviewer or/and talk about your contribution on [the technical forum].


## List of Duniter's reviewers
## List of Duniter's reviewers


- @librelois
- @HugoTrentesaux
- @tuxmain
- @tuxmain


[commit naming conventions]: ./docs/dev/git-conventions.md#naming-commits
[commit naming conventions]: ./docs/dev/git-conventions.md#naming-commits
+11430 −6444

File changed.

Preview size limit exceeded, changes collapsed.

+208 −207

File changed.

Preview size limit exceeded, changes collapsed.

+40 −189
Original line number Original line Diff line number Diff line
@@ -10,32 +10,46 @@
    <img alt="logov2" src="https://duniter.fr/img/duniterv2.svg" width="128" height="128"/>
    <img alt="logov2" src="https://duniter.fr/img/duniterv2.svg" width="128" height="128"/>
</div>
</div>


## Documentation TOC
## Documentation


- [README](./README.md)
Multiple documentation sources are available depending on the level of detail you need.

- Full technical Rust doc (auto-generated with `cargo xtask gen-doc`) : https://doc-duniter-org.ipns.pagu.re/duniter/
- User and client developer doc (official website) : https://duniter.org/wiki/duniter-v2/
- Internal documentation (within git repository), see table of contents below : [./doc](./doc)

### Internal documentation TOC

- [README](./README.md) (this file)
  - [Use](#use)
  - [Use](#use)
  - [Test](#test)
  - [Contribute](#contribute)
  - [Contribute](#contribute)
  - [Structure](#project-structure)
  - [License](#license)
- [docs](./docs/)
- [docs](./docs/) internal documentation
  - [api](./docs/api/)
  - [api](./docs/api/) API
    - [manual](./docs/api/manual.md)
    - [manual](./docs/api/manual.md) manage account and identities
    - [runtime-calls](./docs/api/runtime-calls.md) the calls you can submit through the RPC API
    - [runtime-calls](./docs/api/runtime-calls.md) the calls you can submit through the RPC API
  - [dev](./docs/dev/)
    - [runtime-errors](./docs/api/runtime-errors.md) the errors you can get submitting a call
    - [runtime-events](./docs/api/runtime-events.md) the events you can get submitting a call
  - [dev](./docs/dev/) developer documentation
    - [beginner-walkthrough](./docs/dev/beginner-walkthrough.md)
    - [beginner-walkthrough](./docs/dev/beginner-walkthrough.md)
    - [git-conventions](./docs/dev/git-conventions.md)
    - [git-conventions](./docs/dev/git-conventions.md)
    - [pallet_conventions](./docs/dev/pallet_conventions.md)
    - [launch-a-live-network](./docs/dev/launch-a-live-network.md)
    - [launch-a-live-network](./docs/dev/launch-a-live-network.md)
    - [setup](./docs/dev/setup.md)
    - [setup](./docs/dev/setup.md)
    - [compilation features](./docs/dev/compilation.md)
    - [verify-runtime-code](./docs/dev/verify-runtime-code.md)
    - [verify-runtime-code](./docs/dev/verify-runtime-code.md)
    - [weights-benchmarking](./docs/dev/weights-benchmarking.md)
    - [weights-benchmarking](./docs/dev/weights-benchmarking.md)
    - [upgrade-substrate](./docs/dev/upgrade-substrate.md)
    - [upgrade-substrate](./docs/dev/upgrade-substrate.md)
  - [test](./docs/test/)
    - [replay-block](./docs/test/replay-block.md)
    - [replay-block](./docs/test/replay-block.md)
  - [user](./docs/user/)
  - [user](./docs/user/) user documentation
    - [autocompletion](./docs/user/autocompletion.md)
    - [autocompletion](./docs/user/autocompletion.md)
    - [build-for-arm](./docs/user/build-for-arm.md)
    - [debian installation](./docs/user/installation_debian.md)
    - [rpc](./docs/user/rpc.md) deploy a permanent ǦDev mirror node
    - [distance](./docs/user/distance.md)
    - [smith](./docs/user/smith.md) deploy a permanent ǦDev validator node
    - [fees](./docs/user/fees.md)
  - [packaging](./docs/packaging/) packaging
    - [build-for-arm](./docs/packaging/build-for-arm.md) build for ARM architecture
    - [build-debian](./docs/packaging/build-deb.md) build a native Debian package
- [docker](./docker/) docker-related documentation
- [end2end-tests](./end2end-tests/) automated end to end tests written with cucumber
- [end2end-tests](./end2end-tests/) automated end to end tests written with cucumber
- [live-tests](./live-tests/) sanity checks to test the storage of a live chain
- [live-tests](./live-tests/) sanity checks to test the storage of a live chain


@@ -45,24 +59,23 @@


The easiest way is to use the docker image.
The easiest way is to use the docker image.


Minimal command to deploy a **temporary** mirror peer:
Minimal command to deploy a temporary mirror peer:


```docker
```docker
docker run -it -p9944:9944 -e DUNITER_CHAIN_NAME=gdev duniter/duniter-v2s:v0.4.0 --tmp --execution=Wasm
docker run -it -p9944:9944 -e DUNITER_CHAIN_NAME=gdev duniter/duniter-v2s-gdev-800:latest
```
```


To go further, read [How to deploy a permanent mirror node on ĞDev network](./docs/user/rpc.md).
To go further, read [How to deploy a permanent mirror node on ĞDev network 🔗](https://duniter.org/wiki/duniter-v2/#run-a-mirror-node).


### Create your local blockchain
### Create your local blockchain


It can be useful to deploy your local blockchain, for instance to have a controlled environement
It can be useful to deploy your local blockchain, for instance to have a controlled environment to develop/test an application that interacts with the blockchain.
to develop/test an application that interacts with the blockchain.


```docker
```docker
docker run -it -p9944:9944 duniter/duniter-v2s:v0.4.0 --tmp
docker run -it -p9944:9944 duniter/duniter-v2s-gdev-800:latest
```
```


Or use the `docker-compose.yml` at the root of this repository.
Or use the [`docker-compose.yml`](./docker-compose.yml) at the root of this repository.


#### Control when your local blockchain should produce blocks
#### Control when your local blockchain should produce blocks


@@ -73,34 +86,9 @@ You can decide when to produce blocks with the cli option `--sealing` which has
- `--sealing=instant`: produce a block immediately upon receiving a transaction into the transaction pool
- `--sealing=instant`: produce a block immediately upon receiving a transaction into the transaction pool
- `--sealing=manual`: produce a block upon receiving an RPC request (method `engine_createBlock`).
- `--sealing=manual`: produce a block upon receiving an RPC request (method `engine_createBlock`).


### Autocompletion
### Shell autocompletion

See [autocompletion](./docs/user/autocompletion.md).

## Test

### Test a specific commit

At each commit on master, an image with the tag `debug-sha-********` is published, where `********`
corresponds to the first 8 hash characters of the commit.

Usage:

```docker
docker run -it -p9944:9944 --name duniter-v2s duniter/duniter-v2s:debug-sha-b836f1a6
```

Then open `https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944` in a browser.

Enable detailed logging:


```docker
See [autocompletion](./docs/user/autocompletion.md) to generate shell autocompletion for duniter commands.
docker run -it -p9944:9944 --name duniter-v2s \
  -e RUST_LOG=debug \
  -e RUST_BACKTRACE=1 \
  -lruntime=debug \
  duniter/duniter-v2s:debug-sha-b836f1a6
```


## Contribute
## Contribute


@@ -127,20 +115,11 @@ cargo build
Use Rust's native `cargo` command to build and launch the node:
Use Rust's native `cargo` command to build and launch the node:


```sh
```sh
cargo run -- --dev --tmp
cargo run -- --dev
```
```


This will deploy a local blockchain with test accounts (Alice, Bob, etc) in the genesis.
This will deploy a local blockchain with test accounts (Alice, Bob, etc) in the genesis.

Open `https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944` to watch and interact with your node.
## Single-Node Development Chain

This command will start the single-node development chain with persistent state:

```bash
./target/debug/duniter --dev --tmp
```

Then open `https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944` in a browser.


Start the development chain with detailed logging:
Start the development chain with detailed logging:


@@ -148,140 +127,11 @@ Start the development chain with detailed logging:
RUST_LOG=debug RUST_BACKTRACE=1 ./target/debug/duniter -lruntime=debug --dev
RUST_LOG=debug RUST_BACKTRACE=1 ./target/debug/duniter -lruntime=debug --dev
```
```


## Multi-Node Local Testnet
## License

If you want to see the multi-node consensus algorithm in action, refer to
[our Start a Private Network tutorial](https://substrate.dev/docs/en/tutorials/start-a-private-network/).

### Purge previous local testnet

```
./target/debug/duniter purge-chain --base-path /tmp/alice --chain local
./target/debug/duniter purge-chain --base-path /tmp/bob --chain local

```

### Start Alice's node

```bash
./target/debug/duniter \
  --base-path /tmp/alice \
  --chain local \
  --alice \
  --port 30333 \
  --ws-port 9945 \
  --rpc-port 9933 \
  --node-key 0000000000000000000000000000000000000000000000000000000000000001 \
  --validator
```

### Start Bob's node


```bash
See [LICENSE](./LICENSE)
./target/debug/duniter \
  --base-path /tmp/bob \
  --chain local \
  --bob \
  --port 30334 \
  --ws-port 9946 \
  --rpc-port 9934 \
  --validator \
  --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp
```


## Project Structure

A Substrate project such as this consists of a number of components that are spread across a few
directories.

### Node

A blockchain node is an application that allows users to participate in a blockchain network.
Substrate-based blockchain nodes expose a number of capabilities:

- Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking stack to allow the
  nodes in the network to communicate with one another.
- Consensus: Blockchains must have a way to come to
  [consensus](https://substrate.dev/docs/en/knowledgebase/advanced/consensus) on the state of the
  network. Substrate makes it possible to supply custom consensus engines and also ships with
  several consensus mechanisms that have been built on top of
  [Web3 Foundation research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html).
- RPC Server: A remote procedure call (RPC) server is used to interact with Substrate nodes.

There are several files in the `node` directory - take special note of the following:

- [`chain_spec.rs`](./node/src/chain_spec.rs): A
  [chain specification](https://substrate.dev/docs/en/knowledgebase/integrate/chain-spec) is a
  source code file that defines a Substrate chain's initial (genesis) state. Chain specifications
  are useful for development and testing, and critical when architecting the launch of a
  production chain. Take note of the `development_chain_spec` and `testnet_genesis` functions, which
  are used to define the genesis state for the local development chain configuration. These
  functions identify some
  [well-known accounts](https://substrate.dev/docs/en/knowledgebase/integrate/subkey#well-known-keys)
  and use them to configure the blockchain's initial state.
- [`service.rs`](./node/src/service.rs): This file defines the node implementation. Take note of
  the libraries that this file imports and the names of the functions it invokes. In particular,
  there are references to consensus-related topics, such as the
  [longest chain rule](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#longest-chain-rule),
  the [Babe](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#babe) block authoring
  mechanism and the
  [GRANDPA](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#grandpa) finality
  gadget.

After the node has been [built](#build), refer to the embedded documentation to learn more about the
capabilities and configuration parameters that it exposes:

```shell
./target/debug/duniter --help
```
```

### Runtime

In Substrate, the terms
"[runtime](https://substrate.dev/docs/en/knowledgebase/getting-started/glossary#runtime)" and
"[state transition function](https://substrate.dev/docs/en/knowledgebase/getting-started/glossary#stf-state-transition-function)"
are analogous - they refer to the core logic of the blockchain that is responsible for validating
blocks and executing the state changes they define. The Substrate project in this repository uses
the [FRAME](https://substrate.dev/docs/en/knowledgebase/runtime/frame) framework to construct a
blockchain runtime. FRAME allows runtime developers to declare domain-specific logic in modules
called "pallets". At the heart of FRAME is a helpful
[macro language](https://substrate.dev/docs/en/knowledgebase/runtime/macros) that makes it easy to
create pallets and flexibly compose them to create blockchains that can address
[a variety of needs](https://www.substrate.io/substrate-users/).

Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this template and note
the following:

- This file configures several pallets to include in the runtime. Each pallet configuration is
  defined by a code block that begins with `impl $PALLET_NAME::Config for Runtime`.
- The pallets are composed into a single runtime by way of the
  [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html)
  macro, which is part of the core
  [FRAME Support](https://substrate.dev/docs/en/knowledgebase/runtime/frame#support-library)
  library.

### Pallets

The runtime in this project is constructed using many FRAME pallets that ship with the
[core Substrate repository](https://github.com/paritytech/substrate/tree/master/frame) and a
template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs) directory.

A FRAME pallet is compromised of a number of blockchain primitives:

- Storage: FRAME defines a rich set of powerful
  [storage abstractions](https://substrate.dev/docs/en/knowledgebase/runtime/storage) that makes
  it easy to use Substrate's efficient key-value database to manage the evolving state of a
  blockchain.
- Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched)
  from outside of the runtime in order to update its state.
- Events: Substrate uses [events](https://substrate.dev/docs/en/knowledgebase/runtime/events) to
  notify users of important changes in the runtime.
- Errors: When a dispatchable fails, it returns an error.
- Config: The `Config` configuration interface is used to define the types and parameters upon
  which a FRAME pallet depends.

## License

CopyLeft 2021-2023 Axiom-Team
CopyLeft 2021-2023 Axiom-Team


Some parts borrowed from Polkadot (Parity Technologies (UK) Ltd.)
Some parts borrowed from Polkadot (Parity Technologies (UK) Ltd.)
@@ -297,3 +147,4 @@ GNU Affero General Public License for more details.


You should have received a copy of the GNU Affero General Public License
You should have received a copy of the GNU Affero General Public License
along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
```
+42 −0
Original line number Original line Diff line number Diff line
[package]
edition.workspace = true
homepage.workspace = true
license.workspace = true
description = "Duniter client distance"
name = "dc-distance"
readme = "README.md"
version = "1.0.0"
repository.workspace = true

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[features]
std = [
	"frame-support/std",
	"pallet-distance/std",
	"sp-core/std",
	"sp-distance/std",
	"sp-runtime/std",
]
runtime-benchmarks = [
	"frame-support/runtime-benchmarks",
	"pallet-distance/runtime-benchmarks",
	"sp-runtime/runtime-benchmarks",
]
try-runtime = [
	"frame-support/try-runtime",
	"pallet-distance/try-runtime",
	"sp-distance/try-runtime",
	"sp-runtime/try-runtime",
]

[dependencies]
frame-support = { workspace = true }
log = { workspace = true }
pallet-distance = { workspace = true }
sc-client-api = { workspace = true }
sp-core = { workspace = true }
sp-distance = { workspace = true }
sp-runtime = { workspace = true }
thiserror = { workspace = true }
+3 −0
Original line number Original line Diff line number Diff line
# Distance Oracle Inherent Data Provider

You can find the autogenerated documentation at: [https://doc-duniter-org.ipns.pagu.re/dc_distance/index.html](https://doc-duniter-org.ipns.pagu.re/dc_distance/index.html).
+189 −0
Original line number Original line Diff line number Diff line
// Copyright 2022 Axiom-Team
//
// This file is part of Substrate-Libre-Currency.
//
// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Substrate-Libre-Currency is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.

//! # Distance Oracle Inherent Data Provider
//!
//! This crate provides functionality for creating an **inherent data provider**
//! specifically designed for the "Distance Oracle".
//! The inherent data provider is responsible for fetching and delivering
//! computation results required for the runtime to process distance evaluations.
//!
//! ## Relationship with Distance Oracle
//!
//! The **distance-oracle** is responsible for computing distance evaluations,
//! storing the results to be read in the next period, and saving them to files.
//! These files are then read by **this inherent data provider**
//! to provide the required data to the runtime.
//!
//! ## Overview
//!
//! - Retrieves **period index** and **evaluation results** from the storage and file system.
//! - Determines whether the computation results for the current period have already been published.
//! - Reads and parses evaluation result files when available, providing the necessary data to the runtime.

use frame_support::pallet_prelude::*;
use sc_client_api::{ProvideUncles, StorageKey, StorageProvider};
use sp_runtime::{AccountId32, generic::BlockId, traits::Block as BlockT};
use std::path::PathBuf;

/// The file version that should match the distance oracle one.
/// This ensures that the smith avoids accidentally submitting invalid data
/// in case there are changes in logic between the runtime and the oracle,
/// thereby preventing potential penalties.
const VERSION_PREFIX: &str = "001-";

type IdtyIndex = u32;

#[derive(Debug, thiserror::Error)]
pub enum Error<B: BlockT> {
    #[error("Could not retrieve the block hash for block id: {0:?}")]
    NoHashForBlockId(BlockId<B>),
}

/// Create a new [`sp_distance::InherentDataProvider`] at the given block.
pub fn create_distance_inherent_data_provider<B, C, Backend>(
    client: &C,
    parent: B::Hash,
    distance_dir: PathBuf,
    owner_keys: &[sp_core::sr25519::Public],
) -> sp_distance::InherentDataProvider<IdtyIndex>
where
    B: BlockT,
    C: ProvideUncles<B> + StorageProvider<B, Backend>,
    Backend: sc_client_api::Backend<B>,
    IdtyIndex: Decode + Encode + PartialEq + TypeInfo,
{
    // Retrieve the period_index from storage.
    let period_index = client
        .storage(
            parent,
            &StorageKey(
                frame_support::storage::storage_prefix(b"Distance", b"CurrentPeriodIndex").to_vec(),
            ),
        )
        .ok()
        .flatten()
        .and_then(|raw| u32::decode(&mut &raw.0[..]).ok());

    // Return early if the storage is inaccessible or the data is corrupted.
    let period_index = match period_index {
        Some(index) => index,
        None => {
            log::error!("🧙 [distance inherent] PeriodIndex decoding failed.");
            return sp_distance::InherentDataProvider::<IdtyIndex>::new(None);
        }
    };

    // Retrieve the published_results from storage.
    let published_results = client
        .storage(
            parent,
            &StorageKey(
                frame_support::storage::storage_prefix(
                    b"Distance",
                    match period_index % 3 {
                        0 => b"EvaluationPool0",
                        1 => b"EvaluationPool1",
                        2 => b"EvaluationPool2",
                        _ => unreachable!("n<3"),
                    },
                )
                .to_vec(),
            ),
        )
        .ok()
        .flatten()
        .and_then(|raw| {
            pallet_distance::EvaluationPool::<AccountId32, IdtyIndex>::decode(&mut &raw.0[..]).ok()
        });

    // Return early if the storage is inaccessible or the data is corrupted.
    let published_results = match published_results {
        Some(published_results) => published_results,
        None => {
            log::info!("🧙 [distance inherent] No published result at this block.");
            return sp_distance::InherentDataProvider::<IdtyIndex>::new(None);
        }
    };

    // Find the account associated with the BABE key that is in our owner keys.
    let mut local_account = None;
    for key in owner_keys {
        // Session::KeyOwner is StorageMap<_, Twox64Concat, (KeyTypeId, Vec<u8>), AccountId32, OptionQuery>
        // Slices (variable length) and array (fixed length) are encoded differently, so the `.as_slice()` is needed
        let item_key = (sp_runtime::KeyTypeId(*b"babe"), key.0.as_slice()).encode();
        let mut storage_key =
            frame_support::storage::storage_prefix(b"Session", b"KeyOwner").to_vec();
        storage_key.extend_from_slice(&sp_core::twox_64(&item_key));
        storage_key.extend_from_slice(&item_key);

        if let Some(raw_data) = client
            .storage(parent, &StorageKey(storage_key))
            .ok()
            .flatten()
        {
            if let Ok(key_owner) = AccountId32::decode(&mut &raw_data.0[..]) {
                local_account = Some(key_owner);
                break;
            } else {
                log::warn!("🧙 [distance inherent] Cannot decode key owner value");
            }
        }
    }

    // Have we already published a result for this period?
    if let Some(local_account) = local_account {
        if published_results.evaluators.contains(&local_account) {
            log::debug!("🧙 [distance inherent] Already published a result for this period");
            return sp_distance::InherentDataProvider::<IdtyIndex>::new(None);
        }
    } else {
        log::error!("🧙 [distance inherent] Cannot find our BABE owner key");
        return sp_distance::InherentDataProvider::<IdtyIndex>::new(None);
    }

    // Read evaluation result from file, if it exists
    log::debug!(
        "🧙 [distance inherent] Reading evaluation result from file {:?}",
        distance_dir.clone().join(period_index.to_string())
    );
    let evaluation_result = match std::fs::read(
        distance_dir.join(VERSION_PREFIX.to_owned() + &period_index.to_string()),
    ) {
        Ok(data) => data,
        Err(e) => {
            match e.kind() {
                std::io::ErrorKind::NotFound => {
                    log::debug!(
                        "🧙 [distance inherent] Evaluation result file not found. Please ensure that the oracle version matches {}",
                        VERSION_PREFIX
                    );
                }
                _ => {
                    log::error!(
                        "🧙 [distance inherent] Cannot read distance evaluation result file: {e:?}"
                    );
                }
            }
            return sp_distance::InherentDataProvider::<IdtyIndex>::new(None);
        }
    };

    log::info!("🧙 [distance inherent] Providing evaluation result");
    sp_distance::InherentDataProvider::<IdtyIndex>::new(Some(
        sp_distance::ComputationResult::decode(&mut evaluation_result.as_slice()).unwrap(),
    ))
}
+52 −0
Original line number Original line Diff line number Diff line
[package]
name = "distance-oracle"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
license.workspace = true
edition.workspace = true

[[bin]]
name = "distance-oracle"
required-features = ["standalone"]

[features]
default = ["gdev", "standalone", "std"]
gdev = []
gtest = []
g1 = []
# Feature standalone is for CLI executable
standalone = ["clap", "tokio"]
# Feature std is needed
std = [
	"codec/std",
	"fnv/std",
	"sp-core/std",
	"sp-distance/std",
	"sp-runtime/std",
]
try-runtime = ["sp-distance/try-runtime", "sp-runtime/try-runtime"]

[dependencies]
clap = { workspace = true, features = ["derive"], optional = true }
codec = { workspace = true }
fnv = { workspace = true }
log = { workspace = true }
rayon = { workspace = true }
simple_logger = { workspace = true }
sp-core = { workspace = true }
sp-distance = { workspace = true }
sp-runtime = { workspace = true }
subxt = { workspace = true, features = [
	"native",
	"jsonrpsee",
] }
tokio = { workspace = true, features = [
	"rt-multi-thread",
	"macros",
], optional = true }

[dev-dependencies]
bincode = { workspace = true }
dubp-wot = { workspace = true }
flate2 = { workspace = true, features = ["zlib-ng-compat"] }
+3 −0
Original line number Original line Diff line number Diff line
# Distance Oracle

You can find the autogenerated documentation at: [https://doc-duniter-org.ipns.pagu.re/distance_oracle/index.html](https://doc-duniter-org.ipns.pagu.re/distance_oracle/index.html).
+176 −0
Original line number Original line Diff line number Diff line
// Copyright 2023 Axiom-Team
//
// This file is part of Duniter-v2S.
//
// Duniter-v2S is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Duniter-v2S is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.

#![allow(clippy::type_complexity)]

use crate::runtime;
use log::debug;

pub type Client = subxt::OnlineClient<crate::RuntimeConfig>;
pub type AccountId = subxt::utils::AccountId32;
pub type IdtyIndex = u32;
pub type EvaluationPool =
    runtime::runtime_types::pallet_distance::types::EvaluationPool<AccountId, IdtyIndex>;
pub type H256 = subxt::utils::H256;

pub async fn client(rpc_url: impl AsRef<str>) -> Client {
    Client::from_insecure_url(rpc_url)
        .await
        .expect("Cannot create RPC client")
}

pub async fn parent_hash(client: &Client) -> H256 {
    client
        .blocks()
        .at_latest()
        .await
        .expect("Cannot fetch latest block hash")
        .hash()
}

pub async fn current_period_index(client: &Client, parent_hash: H256) -> u32 {
    client
        .storage()
        .at(parent_hash)
        .fetch(&runtime::storage().distance().current_period_index())
        .await
        .expect("Cannot fetch current pool index")
        .unwrap_or_default()
}

pub async fn current_pool(
    client: &Client,
    parent_hash: H256,
    current_pool_index: u32,
) -> Option<EvaluationPool> {
    client
        .storage()
        .at(parent_hash)
        .fetch(&match current_pool_index {
            0 => {
                debug!("Looking at Pool1 for pool index {}", current_pool_index);
                runtime::storage().distance().evaluation_pool1()
            }
            1 => {
                debug!("Looking at Pool2 for pool index {}", current_pool_index);
                runtime::storage().distance().evaluation_pool2()
            }
            2 => {
                debug!("Looking at Pool0 for pool index {}", current_pool_index);
                runtime::storage().distance().evaluation_pool0()
            }
            _ => unreachable!("n<3"),
        })
        .await
        .expect("Cannot fetch current pool")
}

pub async fn evaluation_block(client: &Client, parent_hash: H256) -> H256 {
    client
        .storage()
        .at(parent_hash)
        .fetch(&runtime::storage().distance().evaluation_block())
        .await
        .expect("Cannot fetch evaluation block")
        .expect("No evaluation block")
}

pub async fn max_referee_distance(client: &Client) -> u32 {
    client
        .constants()
        .at(&runtime::constants().distance().max_referee_distance())
        .expect("Cannot fetch referee distance")
}

pub async fn member_iter(client: &Client, evaluation_block: H256) -> MemberIter {
    MemberIter(
        client
            .storage()
            .at(evaluation_block)
            .iter(runtime::storage().membership().membership_iter())
            .await
            .expect("Cannot fetch memberships"),
    )
}

pub struct MemberIter(
    subxt::backend::StreamOfResults<
        subxt::storage::StorageKeyValuePair<
            subxt::storage::StaticAddress<
                (),
                runtime::runtime_types::sp_membership::MembershipData<u32>,
                (),
                (),
                subxt::utils::Yes,
            >,
        >,
    >,
);

impl MemberIter {
    pub async fn next(&mut self) -> Result<Option<IdtyIndex>, subxt::error::Error> {
        self.0
            .next()
            .await
            .transpose()
            .map(|i| i.map(|j| idty_id_from_storage_key(&j.key_bytes)))
    }
}

pub async fn cert_iter(client: &Client, evaluation_block: H256) -> CertIter {
    CertIter(
        client
            .storage()
            .at(evaluation_block)
            .iter(runtime::storage().certification().certs_by_receiver_iter())
            .await
            .expect("Cannot fetch certifications"),
    )
}

pub struct CertIter(
    subxt::backend::StreamOfResults<
        subxt::storage::StorageKeyValuePair<
            subxt::storage::StaticAddress<
                (),
                Vec<(u32, u32)>,
                (),
                subxt::utils::Yes,
                subxt::utils::Yes,
            >,
        >,
    >,
);

impl CertIter {
    pub async fn next(
        &mut self,
    ) -> Result<Option<(IdtyIndex, Vec<(IdtyIndex, u32)>)>, subxt::error::Error> {
        self.0
            .next()
            .await
            .transpose()
            .map(|i| i.map(|j| (idty_id_from_storage_key(&j.key_bytes), j.value)))
    }
}

fn idty_id_from_storage_key(storage_key: &[u8]) -> IdtyIndex {
    u32::from_le_bytes(
        storage_key[40..44]
            .try_into()
            .expect("Cannot convert StorageKey to IdtyIndex"),
    )