diff --git a/README.md b/README.md index 4b57476..1a2b58c 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,39 @@ # node-rs -A Rust implementation of KeetaNet node +This repository is a Rust workspace for Keeta Network node crates. -## Development +The toolchain pin is Rust `1.94.0` in `rust-toolchain.toml`. -### Quick Start +## Commands -For first-time setup, simply run: +First-time setup: ```bash make developer ``` -This will: - -- Install Rust (if not already installed) -- Install development tools -- Run initial build and tests - -### Building +Debug build: ```bash -# Debug build make build - -# Release build -make release - -# Check compilation without building -make check -``` - -### Testing - -```bash -# Test defaults with all features -make test - -# Test all features individually from packages with features -make test-feat - -# Test everything -make test-all -``` - -### Code Coverage - -```bash -# Generate HTML coverage report (opens in browser) -make coverage -``` - -### Linting - -```bash -# Format code and run clippy -make do-lint ``` -### Documentation +Release build: ```bash -# Generate documentation and open it -make do-docs +make build release=1 ``` -### Other Commands +Check compilation without a full build: ```bash -# Clean build artifacts -make clean - -# Show all available commands -make help +make check ``` -### CI Commands +## Documentation -```bash -# Generate LCOV coverage report for CI -make coverage-ci - -# Format code and clippy without fixes -make do-lint-ci -``` +- [Overview](docs/README.md) +- [Quickstart](docs/QUICKSTART.md) +- [Architecture](docs/ARCHITECTURE.md) +- [Crate docs](docs/README.md#crate-docs) +- [Documentation Standard](docs/STANDARD.md) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..7215c70 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,115 @@ +# Architecture + +## Abstract + +This page states how the `node-rs` workspace crates depend on each other and how they collaborate on a signed write. It holds the crate-boundary graph and the interaction path that no single crate rustdoc can show. Per-crate architecture lives under each product crate `docs/ARCHITECTURE.md` listed on [Overview](README.md). + +## Purpose + +An engineer reads this page to learn how work moves from an account identity through a block, a vote staple, the HTTP client, and the host ABIs. After reading, the engineer can name the crate that owns each step and open that crate `docs/ARCHITECTURE.md`. + +## Related documents + +- [Overview](README.md) for the table of contents into crate `docs/` entries. +- [Quickstart](QUICKSTART.md) for install, build, test, and first use. +- [Documentation Standard](STANDARD.md) for the inclusion test and page shape. + +## Collaboration graph + +Root `Cargo.toml` `[workspace].members` lists the workspace crates. Each product crate listed on [Overview](README.md) holds architecture under that crate `docs/ARCHITECTURE.md`. `keetanetwork-node` and `keetanetwork-ledger` keep reserved names. Their `lib.rs` files export no types. Those crates hold a minimal `docs/README.md` only. + +The arrows follow member `Cargo.toml` path dependencies that the product path uses. Foundation crates feed identity. Identity feeds signed objects. Signed objects feed the client. The client and the shared bindings crate feed the browser and WASI ABIs. + +```mermaid +flowchart TB + crate_error[keetanetwork-error] + crate_utils[keetanetwork-utils] + crate_crypto[keetanetwork-crypto] + crate_asn1[keetanetwork-asn1] + crate_account[keetanetwork-account] + crate_x509[keetanetwork-x509] + crate_block[keetanetwork-block] + crate_vote[keetanetwork-vote] + crate_client[keetanetwork-client] + crate_bindings[keetanetwork-bindings] + crate_wasm[keetanetwork-client-wasm] + crate_wasi[keetanetwork-client-wasi] + crate_node[keetanetwork-node] + crate_ledger[keetanetwork-ledger] + crate_error --> crate_account + crate_utils --> crate_account + crate_crypto --> crate_account + crate_asn1 --> crate_crypto + crate_account --> crate_x509 + crate_account --> crate_block + crate_account --> crate_vote + crate_account --> crate_client + crate_account --> crate_bindings + crate_x509 --> crate_block + crate_block --> crate_vote + crate_block --> crate_client + crate_vote --> crate_client + crate_client --> crate_wasm + crate_client --> crate_wasi + crate_bindings --> crate_wasm + crate_bindings --> crate_wasi +``` + +`crate_node` and `crate_ledger` sit in the workspace with no product types. The `crate_client` to `crate_wasi` arrow is the `p2` feature. Feature `p1` stays on the pure surface. + +Each crate architecture names the remaining `Cargo.toml` edges that this diagram omits, such as `keetanetwork-asn1` into `keetanetwork-block` and `keetanetwork-vote`. + +## How the crates interact + +A signed write walks one path. + +An account crate identity starts the path. `keetanetwork-account` owns `Account`, `GenericAccount`, `KeyPairType`, and identifier accounts. Higher crates take those types. They do not invent a second identity model. `CertSigner` and `CertVerifier` live on the account crate. Certificate builders and stores live in `keetanetwork-x509`. + +`keetanetwork-block` turns that identity into a signed object. `Block`, `BlockBuilder`, `Operation`, and `AccountRef` live there. Opening-hash and signing rules live in that crate. The client builder uses the same rules when it assembles a first block or a successor. + +`keetanetwork-vote` commits those block hashes. A `Vote` is a representative's signed commitment. A `VoteQuote` is a non-binding vote used during fee negotiation. A `VoteStaple` is the compressed bundle of votes and the blocks they cover. `keetanetwork-client` re-exports `Vote`, `VoteQuote`, and `VoteStaple` for callers. + +`keetanetwork-client` is the orchestrator. `KeetaClient`, `UserClient`, and `TransactionBuilder` live there. HTTP transport is generated at build time from `keetanetwork-client/openapi/keetanet-node.yaml` through progenitor. The generated types are exposed as the `generated` module when the `codec` feature is on. The rustdoc example in `keetanetwork-client/src/lib.rs` constructs `KeetaClient::new("http://localhost:8080/api")`. + +`keetanetwork-bindings` is the shared, target-agnostic projection. It maps account algorithms, parses host input, and reduces core errors. `keetanetwork-client-wasm` is the browser ABI. Amounts are decimal strings. Errors carry `error.code`. `keetanetwork-client-wasi` selects exactly one of `p1` or `p2` on a WASI target. + +Foundation crates sit under that path. `keetanetwork-error` holds shared error types. `keetanetwork-crypto` holds algorithm-agnostic primitives. `keetanetwork-asn1` holds the encoding codecs. `keetanetwork-utils` holds test macros, the `build` helpers, and the `node-harness` feature that [Quickstart](QUICKSTART.md) names as the Packages gate. + +## Build contracts that span crates + +These statements are the positive feature contracts that more than one crate must honor. + +`keetanetwork-asn1` enables at least one of `der` or `rasn`. Both features may be on together. The `compile_error!` in `keetanetwork-asn1/src/lib.rs` is the enforcement point. Higher crates that expose `der` or `rasn` forward those names to `keetanetwork-asn1`. + +`keetanetwork-client` feature `http` pairs with a runtime. Native builds enable `std`. Browser builds enable `wasm` on `wasm32-unknown-unknown`. The `compile_error!` in `keetanetwork-client/src/lib.rs` is the enforcement point. + +`keetanetwork-client-wasi` selects exactly one of `p1` or `p2` on a WASI target. Feature `p2` pulls `keetanetwork-client`. Feature `p1` stays on the pure surface. The `compile_error!` in `keetanetwork-client-wasi/src/lib.rs` is the enforcement point. + +Workspace crates share the `std` and `alloc` feature names so a `no_std` consumer can stay on `alloc` through the identity and object crates. + +## Crate architecture homes + +Each product crate holds architecture under that crate `docs/ARCHITECTURE.md`. That page holds the crate's consumer contract and the crates that call it. This page does not copy those contracts. + +| Crate | Architecture | +| --- | --- | +| `keetanetwork-account` | [Account](../keetanetwork-account/docs/ARCHITECTURE.md) | +| `keetanetwork-error` | [Error](../keetanetwork-error/docs/ARCHITECTURE.md) | +| `keetanetwork-crypto` | [Crypto](../keetanetwork-crypto/docs/ARCHITECTURE.md) | +| `keetanetwork-x509` | [X.509](../keetanetwork-x509/docs/ARCHITECTURE.md) | +| `keetanetwork-asn1` | [ASN.1](../keetanetwork-asn1/docs/ARCHITECTURE.md) | +| `keetanetwork-utils` | [Utils](../keetanetwork-utils/docs/ARCHITECTURE.md) | +| `keetanetwork-block` | [Block](../keetanetwork-block/docs/ARCHITECTURE.md) | +| `keetanetwork-vote` | [Vote](../keetanetwork-vote/docs/ARCHITECTURE.md) | +| `keetanetwork-client` | [Client](../keetanetwork-client/docs/ARCHITECTURE.md) | +| `keetanetwork-bindings` | [Bindings](../keetanetwork-bindings/docs/ARCHITECTURE.md) | +| `keetanetwork-client-wasm` | [Client wasm](../keetanetwork-client-wasm/docs/ARCHITECTURE.md) | +| `keetanetwork-client-wasi` | [Client WASI](../keetanetwork-client-wasi/docs/ARCHITECTURE.md) | +| `keetanetwork-node` | [Node](../keetanetwork-node/docs/README.md) | +| `keetanetwork-ledger` | [Ledger](../keetanetwork-ledger/docs/README.md) | + +Crate identity, versions, and field lists live in each member `Cargo.toml` and in rustdoc. This tree does not copy those lists. + +## Falsified by + +A change to the workspace `members` or `exclude` lists in root `Cargo.toml`. A change that adds product types to `keetanetwork-node/src/lib.rs` or `keetanetwork-ledger/src/lib.rs`. A change to the `compile_error!` gates in `keetanetwork-asn1/src/lib.rs`, `keetanetwork-client/src/lib.rs` (`http` runtime pairing), or `keetanetwork-client-wasi/src/lib.rs` (`p1` / `p2`). A change that moves the OpenAPI document away from `keetanetwork-client/openapi/keetanet-node.yaml`. A change to the product-crate set that [Overview](README.md) indexes under each crate `docs/` directory. diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md new file mode 100644 index 0000000..deca61a --- /dev/null +++ b/docs/QUICKSTART.md @@ -0,0 +1,126 @@ +# Quickstart + +## Abstract + +This page is the install, build, test, and first-use path for the `node-rs` workspace. It records the Makefile targets from the repository Makefile. It also states the GitHub Packages gate and the cargo-only path. + +## Purpose + +Read this page when you clone the repository or when you need a correct Make command. After reading you can set up the toolchain and run a debug or release build. You can also choose a test path and start from an existing rustdoc example. + +## Pin the toolchain + +Use Rust `1.94.0` from `rust-toolchain.toml`. After you clone, that pin wins over a default rustup toolchain. + +The file also requests `rustfmt`, `clippy`, and `llvm-tools-preview`. It also requests the `wasm32-unknown-unknown`, `wasm32-wasip1`, and `wasm32-wasip2` targets. + +## Set up the tree + +Run first-time setup. + +```bash +make developer +``` + +`make developer` installs rustc through `scripts/rustup-init.sh -y --default-toolchain stable` when rustc is missing. That script requests the `stable` toolchain. The repo pin still selects `1.94.0` for this tree after clone. + +## Build + +Use the Make targets. Use `make build release=1` for a release build. + +| Target | What you get | +| --- | --- | +| `make developer` | First-time toolchain and tool setup | +| `make build` | Debug build through `cargo build` | +| `make build release=1` | Release build through `cargo build --release` | +| `make check` | Compilation check through `cargo check` | + +Release build: + +```bash +make build release=1 +``` + +`make release` runs `scripts/release.sh` and publishes crates to crates.io. That target is a publish path. It is not a release build. + +## Test + +`make test` depends on `make node-harness`. It then runs `cargo test --all-features --workspace`. + +| Target | What you get | +| --- | --- | +| `make test` | Harness build, then workspace tests with all features | +| `make test-feat` | Feature matrix from the `Makefile` `test-feat` recipe | +| `make test-all` | `make test` and then `make test-feat` | + +Those targets need the Packages gate below. Use the cargo-only path when you lack Packages read. + +## Wasm and WASI + +Name these targets when you need those ABIs. They also need the Packages gate. The Make targets are the first-use path for those ABIs. + +| Target | What you get | +| --- | --- | +| `make build-wasm` | `wasm-pack build` for `keetanetwork-client-wasm` | +| `make test-wasm` | Harness, wasm-pack node tests, and Playwright in `keetanetwork-client-wasm/tests` | +| `make build-wasi` | WASI P1 and P2 debug artifacts for `keetanetwork-client-wasi` | +| `make test-wasi` | Harness, WASI artifacts, and host tests under `keetanetwork-client-wasi/host-tests` | + +`make test-wasi` selects `p1` for `wasm32-wasip1` and `p2` for `wasm32-wasip2`. [Architecture](ARCHITECTURE.md) holds that one-feature contract. + +## rustdoc + +| Target | What you get | +| --- | --- | +| `make do-docs` | `cargo doc` for the workspace, then opens the result | +| `make do-docs-ci` | The same rustdoc build without opening a browser | + +## GitHub Packages gate + +`keetanetwork-utils/node-harness/.npmrc` sets `@keetanetwork:registry=https://npm.pkg.github.com`. The harness `package.json` depends on `@keetanetwork/keetanet-node` from that registry. + +`make node-harness`, `make test`, `make test-all`, `make test-wasm`, and `make test-wasi` need read access to that package. CI sets `NODE_AUTH_TOKEN` for those jobs in `.github/workflows/ci.yml`. + +Set `NODE_AUTH_TOKEN` or `GITHUB_TOKEN` to a GitHub personal access token with `read:packages`. Authorize SSO for the organization when the organization requires it. + +Rust crates in this workspace use path dependencies. `.cargo/config.toml` sets a `wasm32-unknown-unknown` `getrandom` cfg. It does not set a private Cargo registry. + +## Cargo-only path + +Skip the harness when you do not have Packages read. + +```bash +cargo check +cargo build +``` + +You can also run crate tests that do not enable the `node-harness` feature. `make test` still needs the harness and auth. + +## First use + +Start from the rustdoc examples that already live in the crates. This tree does not add an `examples/` directory. + +Construct a `KeetaClient` against the local API from [`keetanetwork-client/src/lib.rs`](https://github.com/KeetaNetwork/node-rs/blob/285ce02435bbcc120e86a7c78d2865a034679453/keetanetwork-client/src/lib.rs#L11-L37). + +```rust +let client = KeetaClient::new("http://localhost:8080/api").with_network(0u8); +``` + +`UserClient` signing tests live in [`keetanetwork-client/tests/user_signing.rs`](https://github.com/KeetaNetwork/node-rs/blob/285ce02435bbcc120e86a7c78d2865a034679453/keetanetwork-client/tests/user_signing.rs#L8-L20). A live harness cookbook lives in [`keetanetwork-client/tests/e2e.rs`](https://github.com/KeetaNetwork/node-rs/blob/285ce02435bbcc120e86a7c78d2865a034679453/keetanetwork-client/tests/e2e.rs#L164). + +Build a signed opening block from [`keetanetwork-block/src/lib.rs`](https://github.com/KeetaNetwork/node-rs/blob/285ce02435bbcc120e86a7c78d2865a034679453/keetanetwork-block/src/lib.rs#L8-L39). + +```rust +let unsigned = BlockBuilder::default() + .with_network(0u8) + .with_account(account.clone()) + .as_opening() + .build()?; +let block = unsigned.sign()?; +``` + +A harness opening-block cookbook lives in [`keetanetwork-block/tests/e2e.rs`](https://github.com/KeetaNetwork/node-rs/blob/285ce02435bbcc120e86a7c78d2865a034679453/keetanetwork-block/tests/e2e.rs#L116-L119). + +## Falsified by + +A change to the `developer`, `build`, `check`, `test`, `test-feat`, `test-all`, `build-wasm`, `test-wasm`, `build-wasi`, `test-wasi`, `do-docs`, `do-docs-ci`, or `release` targets in `Makefile`. A change to the channel in `rust-toolchain.toml`. A change to the registry line in `keetanetwork-utils/node-harness/.npmrc`. A change to the `KeetaClient` or `BlockBuilder` rustdoc examples in those crate `lib.rs` files. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..bdc578b --- /dev/null +++ b/docs/README.md @@ -0,0 +1,116 @@ +# Overview + +## Abstract + +This guide is the table of contents for the `node-rs` workspace documentation. Workspace contracts live on [Architecture](ARCHITECTURE.md), [Quickstart](QUICKSTART.md), and [Documentation Standard](STANDARD.md). Each product crate holds its architecture under that crate `docs/` directory. + +## Purpose + +An engineer reads this guide to find the page that holds each inbound question. After reading, the engineer can open the workspace page or the crate `docs/` entry that owns that question. + +| Next question | The page | +| --- | --- | +| How do the crates depend on and call each other? | [Architecture](ARCHITECTURE.md) | +| How does a reader install, build, and test? | [Quickstart](QUICKSTART.md) | +| How does a writer review a page in this tree? | [Documentation Standard](STANDARD.md) | +| Where do account identities live? | [Account](../keetanetwork-account/docs/README.md) | +| Where do shared errors live? | [Error](../keetanetwork-error/docs/README.md) | +| Where do signing primitives live? | [Crypto](../keetanetwork-crypto/docs/README.md) | +| Where do certificate builders live? | [X.509](../keetanetwork-x509/docs/README.md) | +| Where does the ASN.1 codec contract live? | [ASN.1](../keetanetwork-asn1/docs/README.md) | +| Where do test helpers and the harness live? | [Utils](../keetanetwork-utils/docs/README.md) | +| Where do opening-hash and block signing live? | [Block](../keetanetwork-block/docs/README.md) | +| Where do vote, quote, and staple live? | [Vote](../keetanetwork-vote/docs/README.md) | +| Where do `KeetaClient` and HTTP generation live? | [Client](../keetanetwork-client/docs/README.md) | +| Where does the shared host projection live? | [Bindings](../keetanetwork-bindings/docs/README.md) | +| Where does the browser ABI live? | [Client wasm](../keetanetwork-client-wasm/docs/README.md) | +| Where does the WASI `p1` / `p2` contract live? | [Client WASI](../keetanetwork-client-wasi/docs/README.md) | +| Where are the reserved stub crates named? | [Node](../keetanetwork-node/docs/README.md) and [Ledger](../keetanetwork-ledger/docs/README.md) | + +## What this workspace is + +This repository is a Cargo workspace of Keeta Network node crates. Root `Cargo.toml` `[workspace].members` is the member list. Crate identity lives in each member `Cargo.toml` `description` plus rustdoc on that crate `lib.rs`. + +Each product crate listed on this guide holds architecture on that crate `docs/ARCHITECTURE.md`. The crate `docs/README.md` states purpose, Quickstart, and examples. `keetanetwork-node` and `keetanetwork-ledger` are empty stubs. Those crates hold a minimal `docs/README.md` only. [Architecture](ARCHITECTURE.md) names that boundary. + +Each member crate carries its own version in that crate `Cargo.toml`. This guide does not treat the unused workspace package version as the repository version. This table of contents does not stamp versions. + +The files state three license strings. Root `LICENSE` is the Keeta Token Network Community License (v1.0). Workspace `Cargo.toml` `license` is `MIT`. `keetanetwork-utils/node-harness/package.json` `license` is `Keeta Token Network Community License`. This guide cites those files as written. + +## Crate docs + +These entries are the living table of contents for crate documentation. [Architecture](ARCHITECTURE.md) draws the collaboration graph. Each crate architecture names the crates that call that crate. + +| Crate | Entry | +| --- | --- | +| `keetanetwork-account` | [Account](../keetanetwork-account/docs/README.md) | +| `keetanetwork-error` | [Error](../keetanetwork-error/docs/README.md) | +| `keetanetwork-crypto` | [Crypto](../keetanetwork-crypto/docs/README.md) | +| `keetanetwork-x509` | [X.509](../keetanetwork-x509/docs/README.md) | +| `keetanetwork-asn1` | [ASN.1](../keetanetwork-asn1/docs/README.md) | +| `keetanetwork-utils` | [Utils](../keetanetwork-utils/docs/README.md) | +| `keetanetwork-block` | [Block](../keetanetwork-block/docs/README.md) | +| `keetanetwork-vote` | [Vote](../keetanetwork-vote/docs/README.md) | +| `keetanetwork-client` | [Client](../keetanetwork-client/docs/README.md) | +| `keetanetwork-bindings` | [Bindings](../keetanetwork-bindings/docs/README.md) | +| `keetanetwork-client-wasm` | [Client wasm](../keetanetwork-client-wasm/docs/README.md) | +| `keetanetwork-client-wasi` | [Client WASI](../keetanetwork-client-wasi/docs/README.md) | +| `keetanetwork-node` | [Node](../keetanetwork-node/docs/README.md) | +| `keetanetwork-ledger` | [Ledger](../keetanetwork-ledger/docs/README.md) | + +## Where the tree lives + +| Path | Role | +| --- | --- | +| Root `README.md` | Thin pointer into this tree | +| `docs/README.md` | This overview | +| `docs/STANDARD.md` | Documentation contract | +| `docs/ARCHITECTURE.md` | Collaboration graph and interaction path | +| `docs/QUICKSTART.md` | Install, build, test, and first use | +| `keetanetwork-*/docs/README.md` | Crate purpose, Quickstart, and examples | +| `keetanetwork-*/docs/ARCHITECTURE.md` | Product-crate architecture | + +GitHub issues and pull requests stay the history home. + +## Day-to-day + +### Tooling + +- The toolchain pin is Rust `1.94.0` in `rust-toolchain.toml`. +- The primary targets are `make developer`, `make build`, `make build release=1`, and `make check`. +- `make test` and the wasm or WASI test targets need GitHub Packages read. [Quickstart](QUICKSTART.md) holds the cargo-only path. +- Crate rustdoc opens through `make do-docs`. + +### Where to put work + +| Change | Place | +| --- | --- | +| A crate-boundary invariant | The crate source, then [Architecture](ARCHITECTURE.md) and that crate `docs/ARCHITECTURE.md` | +| An install or build step | `Makefile`, then [Quickstart](QUICKSTART.md) | +| A documentation page | This tree or the crate `docs/` directory, then the next-question table on this guide. Writers follow [Documentation Standard](STANDARD.md). | +| A public type contract | rustdoc on that type | + +### First-week reading order + +1. This guide. +2. [Architecture](ARCHITECTURE.md). +3. The crate `docs/ARCHITECTURE.md` for the crate under change. +4. [Quickstart](QUICKSTART.md). +5. [Documentation Standard](STANDARD.md) before a docs edit. +6. The crate `lib.rs` rustdoc for the crate under change. + +## Cultural one-liners + +- **Make owns the build.** Prefer the `Makefile` targets over raw tool invocations. +- **The toolchain file wins after clone.** `rust-toolchain.toml` selects Rust `1.94.0`. +- **Release build is `make build release=1`.** That target is not `make release`. +- **Stubs stay stubs.** `keetanetwork-node` and `keetanetwork-ledger` have no product types. +- **rustdoc is the API reference.** This tree holds cross-file contracts. +- **Packages read is a test gate.** `cargo check` and `cargo build` stay open without it. + +## Falsified by + +- A change to the living documentation map that the first-week links follow. +- A change to the workspace `members` list in root `Cargo.toml`. +- A change that adds product types to `keetanetwork-node` or `keetanetwork-ledger`. +- A change to the license strings in root `LICENSE`, workspace `Cargo.toml`, or `keetanetwork-utils/node-harness/package.json`. diff --git a/docs/STANDARD.md b/docs/STANDARD.md new file mode 100644 index 0000000..171dbad --- /dev/null +++ b/docs/STANDARD.md @@ -0,0 +1,89 @@ +# Documentation Standard + +## Abstract + +This page is the documentation contract for the `node-rs` workspace. It states what belongs in a documentation page. It also fixes the prose, the register, and the page shape. + +## Purpose + +An engineer reads this page before writing or reviewing documentation in this repository. After reading, the engineer can tell whether a page belongs in the tree. The engineer can also write the page in the expected prose and shape. + +## Requirements Language + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) [RFC 8174](https://datatracker.ietf.org/doc/html/rfc8174) when, and only when, they appear in all capitals, as shown here. + +This page is the one home for that declaration. Other pages in this tree MAY use those keywords under this home. They MUST NOT repeat this section. + +## The inclusion test + +Documentation earns its maintenance cost by holding the knowledge that lives outside any one file. A page MUST carry at least one of the following. + +- An invariant that spans several files, which puts it beyond the reach of a single file. +- A decision and the alternative it rejected, so a later reader keeps it closed. +- A contract that binds consumer behavior, such as a feature gate or a signing rule. +- A procedure an operator runs under pressure. + +A page MUST NOT carry the following. The source is the one correct home for each one. + +- Barrel maps, export lists, or directory listings. +- Field tables that repeat crate rustdoc without adding operator semantics. +- One crate-root README that only restates that crate `Cargo.toml` and `pub use`. +- A product Architecture page for `keetanetwork-node` or `keetanetwork-ledger` while those crates remain empty stubs. +- A decision log, a changelog of past reviews, or a ticket or phase diary. + +One body of knowledge takes one page as its home. A second page that needs it MUST link to that home rather than restate it. The [Overview](README.md) names the living pages. + +[Architecture](ARCHITECTURE.md) holds the workspace collaboration graph and the interaction path. Product-crate architecture lives under that crate `docs/ARCHITECTURE.md`. That page MUST describe internal module responsibilities. It MUST include at least one Mermaid diagram with keyword-safe ids. It MUST name inbound and outbound neighbor crates. It MUST state feature and build contracts in the positive. It MUST NOT restate that crate `pub use` list. It MUST NOT carry fenced rust or JavaScript examples. The [Overview](README.md) is the table of contents into those paths. + +A product-crate `docs/README.md` MUST state what the crate is for. It MUST name the features and the `cargo test -p` command or Make target. It MUST include at least two labeled fenced code examples copied from crate rustdoc or a test. It MUST link to that crate `docs/ARCHITECTURE.md` and the workspace [Overview](README.md). A stub crate MAY carry a minimal `docs/README.md` that names the reserved crate. It MUST NOT carry a product Architecture page. + +A concept page under `docs/concepts/` lands only when it still holds a non-rustdoc invariant after the workspace Architecture draft and the crate architecture. A candidate that collapses to a field list MUST NOT land. + +When a page must name a symbol, it cites that symbol as `Symbol` in `path/to/file`. The source carries its own detail. + +## Prose + +A page uses full sentences and keeps their articles. A sentence holds one topic. A sentence does not join independent clauses with a semicolon. Prose uses the active voice and the present tense. + +A page uses the exact technical noun, in code font, on every mention of the same thing. A page uses the ASCII hyphen only and writes each relation as words. A page prefers a table, a list, or a diagram when that form reorganizes substance. + +A page states contracts in the positive. A page names the command or path that Makefile, Cargo.toml, rust-toolchain.toml, or the cited source file states. + +Each register addresses its reader differently. A page MUST hold one register throughout. + +| Register | Reader | Voice | +| --- | --- | --- | +| Concept | An engineer building a model of the system | Third person, declarative | +| Implementation | An engineer integrating the software into a service | Second person, imperative | +| Operations | An operator under time pressure | Second person, imperative, one action per step | +| Reference | An engineer checking an exact contract | Third person, terse, declarative | + +## Page shape + +Every shaped page under workspace `docs/` and every crate `docs/ARCHITECTURE.md` MUST carry the following sections, in the following order. + +1. **Title.** The subject of the page, as a noun phrase. +2. **Abstract.** Two or three sentences on what the page holds. +3. **Purpose.** Who reads the page, and what they can do afterward. +4. **Body.** The sections that carry the content, which SHOULD sit in the correct dependency order. +5. **Falsified by.** The changes that make the page wrong. + +The closing section is the maintenance contract. It MUST name the code or tree changes that invalidate the page. + +A page SHOULD cite the test or rustdoc example that encodes an invariant when that file is the enforcement point. One citation replaces a prose argument that the guarantee holds. + +The root `README.md` MAY stay a thin pointer. A stub crate `docs/README.md` MAY stay a thin pointer. Those pages do not use this page shape. They MUST NOT redeclare Requirements Language. A product-crate `docs/README.md` uses the crate-entry sections above instead of this page shape. + +Navigation and audience live on the [Overview](README.md). This page MUST NOT carry a page index. + +A Mermaid diagram, when used, MUST give every node and participant an id that is not a Mermaid keyword. Ids such as `crate_account` and `crate_client` stay keyword-safe. A bare id `graph`, `end`, or `subgraph` is invalid. + +## rustdoc comments + +A `///` comment MUST add signal that the signature cannot carry. It MUST NOT narrate the next line. It MUST NOT add a historical aside. Happy-path comments MUST state the contract in the positive. + +Public surfaces that already have rustdoc examples MUST keep a short snippet. Full flows belong as GitHub line links into tests in the repository. This tree MUST NOT invent an `examples/` directory. + +## Falsified by + +A change to the prose contract, to the inclusion test, or to the page shape. diff --git a/keetanetwork-account/docs/ARCHITECTURE.md b/keetanetwork-account/docs/ARCHITECTURE.md new file mode 100644 index 0000000..e5e5eeb --- /dev/null +++ b/keetanetwork-account/docs/ARCHITECTURE.md @@ -0,0 +1,52 @@ +# Account + +## Abstract + +This page is the internal design of `keetanetwork-account`. The crate turns seeds and key material into typed identities, then erases the algorithm at crate boundaries. Neighbor crates consume those identities. They do not invent a second account model. + +## Purpose + +An engineer reads this page before changing how an identity is constructed or shared. After reading, the engineer can name the module that owns typing, erasure, certificate-mode signing, and errors. + +## Internal design + +`account` owns `Account`, `GenericAccount`, `KeyPairType`, and identifier accounts. A typed `Account` is bound to one algorithm marker such as `KeyED25519`. `GenericAccount` is the type-erased form that block, vote, and client carry across crate edges. Identifier kinds (`NETWORK`, `TOKEN`, `STORAGE`, `MULTISIG`) are accounts that do not sign. + +`cert` owns `CertSigner` and `CertVerifier`. Certificate mode is the message-handling convention used by vote certificates and other X.509-shaped artifacts. ECDSA signs a SHA3-256 digest as DER `r` and `s`. Ed25519 signs the message directly. Identifier accounts cannot sign or verify in this mode. + +`error` owns `AccountError`. `constants` holds shared numeric and string constants. `utils` holds small helpers used by account construction. `doc_utils` is documentation-only test-key construction. + +```mermaid +flowchart LR + mod_account[account] + mod_cert[cert] + mod_error[error] + type_typed[Account] + type_erased[GenericAccount] + crate_crypto[keetanetwork-crypto] + crate_block[keetanetwork-block] + crate_vote[keetanetwork-vote] + crate_x509[keetanetwork-x509] + crate_crypto -->|keys and signatures| mod_account + mod_account --> type_typed + type_typed --> type_erased + mod_account --> mod_cert + mod_error --> mod_account + type_erased --> crate_block + type_erased --> crate_vote + mod_cert --> crate_x509 +``` + +## Collaboration + +Inbound: `keetanetwork-crypto` supplies derivation, signing, and encryption. `keetanetwork-error` and `keetanetwork-utils` sit under those paths. `keetanetwork-asn1` is optional behind `der` and `rasn`. + +Outbound: `keetanetwork-block` wraps `GenericAccount` as `AccountRef`. `keetanetwork-vote` uses that same `AccountRef` as a vote issuer. `keetanetwork-x509` calls `CertSigner` and `CertVerifier`. `keetanetwork-client` and `keetanetwork-bindings` take identities at the HTTP and host ABI edges. + +## Feature contract + +Default features are `std` and `rasn`. `std` implies `alloc`. Features `der` and `rasn` forward to `keetanetwork-asn1` and `keetanetwork-crypto`. A `no_std` consumer enables `alloc` and at least one codec when it needs the ASN.1 path. + +## Falsified by + +A change that moves `Account`, `GenericAccount`, `KeyPairType`, `CertSigner`, or `CertVerifier` off this crate. A change that adds a second identity model in block, vote, x509, client, or bindings. A change to the `der` / `rasn` forwarding in `keetanetwork-account/Cargo.toml`. diff --git a/keetanetwork-account/docs/README.md b/keetanetwork-account/docs/README.md new file mode 100644 index 0000000..2bc4531 --- /dev/null +++ b/keetanetwork-account/docs/README.md @@ -0,0 +1,52 @@ +# keetanetwork-account + +This crate owns typed and type-erased identities for the workspace. `Account` is bound to one `KeyPairType`. `GenericAccount` is the type-erased account used at crate boundaries. `CertSigner` and `CertVerifier` sign and verify X.509-shaped artifacts. + +## Quickstart + +Default features are `std` and `rasn`. `std` implies `alloc`. Features `der` and `rasn` forward to `keetanetwork-asn1`. + +```bash +cargo test -p keetanetwork-account +``` + +`make test-feat` also runs this crate with `std,der` and `std,rasn`. + +## Examples + +### Create from seed and sign + +From `keetanetwork-account/src/account.rs` rustdoc. + +```rust +use keetanetwork_account::{Account, KeyED25519}; +use keetanetwork_crypto::algorithms::ed25519::Ed25519Derivation; +use keetanetwork_crypto::prelude::KeyDerivation; +use keetanetwork_crypto::utils::generate_random_seed; + +let seed = generate_random_seed()?; +let private_key = Ed25519Derivation::derive_from_seed(seed)?; +let account = Account::::from(private_key); + +let message = b"Hello, Keeta Network!"; +let signature = account.sign(message, None)?; +assert!(account.verify(message, &signature, None).is_ok()); +# Ok::<(), Box>(()) +``` + +### Identifier account + +From `keetanetwork-account/src/account.rs` rustdoc. + +```rust +use keetanetwork_account::{Account, KeyNETWORK, KeyPairType}; + +let network_account = Account::::generate_network_address(12345)?; +let token_account = network_account.generate_identifier(KeyPairType::TOKEN, None, 0)?; +# Ok::<(), Box>(()) +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-account/src/lib.rs b/keetanetwork-account/src/lib.rs index 9476991..ee52b77 100644 --- a/keetanetwork-account/src/lib.rs +++ b/keetanetwork-account/src/lib.rs @@ -1,4 +1,11 @@ //! Account management and cryptographic identities for Keetanetwork. +//! +//! [`Account`] is the typed identity bound to one [`KeyPairType`]. +//! [`GenericAccount`] is the type-erased account used at crate boundaries. +//! [`KeyPairType`] names signing algorithms and identifier accounts. +//! [`CertSigner`] signs X.509-shaped artifacts in certificate mode. +//! [`CertVerifier`] verifies those certificate-mode signatures. +//! Block, vote, x509, client, and bindings crates consume these identities. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/keetanetwork-asn1/docs/ARCHITECTURE.md b/keetanetwork-asn1/docs/ARCHITECTURE.md new file mode 100644 index 0000000..ca2357d --- /dev/null +++ b/keetanetwork-asn1/docs/ARCHITECTURE.md @@ -0,0 +1,53 @@ +# ASN.1 + +## Abstract + +This page is the internal design of `keetanetwork-asn1`. The crate is the shared codec layer. Identity, certificate, block, and vote types encode through at least one of `der` or `rasn`. + +## Purpose + +An engineer reads this page before changing a codec feature or adding a third ASN.1 stack. After reading, the engineer knows how the `der` and `rasn` backends sit under the block and vote transport modules. + +## Internal design + +`der` is the `der` crate backend. `rasn` is the `rasn` crate backend. When both features are on, unprefixed re-exports prefer `der` so x509, account, and crypto keep their legacy surface. `BitStringExt` and `ObjectIdentifierExt` surface whenever `rasn` is on. + +`block` and `vote` are backend-neutral transport modules. They require `chrono` plus at least one codec. `asn1_time` owns `Asn1Time`. `oids` owns shared object identifiers. `utils` owns small codec helpers. `error` owns `Asn1Error`. + +`generated` and `schema_codec` are rasn-only generation and positional DER paths. `testing` is present when `testing` and `der` are on. + +```mermaid +flowchart TB + feat_der[feature_der] + feat_rasn[feature_rasn] + mod_der[der] + mod_rasn[rasn] + mod_block[block] + mod_vote[vote] + crate_x509[keetanetwork-x509] + crate_block[keetanetwork-block] + crate_vote[keetanetwork-vote] + feat_der --> mod_der + feat_rasn --> mod_rasn + mod_der --> mod_block + mod_rasn --> mod_block + mod_der --> mod_vote + mod_rasn --> mod_vote + mod_der --> crate_x509 + mod_block --> crate_block + mod_vote --> crate_vote +``` + +## Collaboration + +Inbound: `keetanetwork-utils` is a path dependency. The `build` feature on that crate supplies generation helpers used by this crate's build script. + +Outbound: account, crypto, x509, block, vote, and bindings crates depend on this crate when they encode or decode shared structures. Those crates expose `der` and `rasn` under the same names and forward them here. + +## Feature contract + +A consumer enables at least one of `der` or `rasn`. Both features may be on together. The `compile_error!` in `keetanetwork-asn1/src/lib.rs` is the enforcement point. Default features are `std`, `serde`, and `rasn`. `std` implies `alloc`. + +## Falsified by + +A change to the `compile_error!` that no longer requires at least one of `der` or `rasn`. A change that adds a third codec feature without updating this page. A change that stops account, block, or vote from forwarding `der` and `rasn` here. diff --git a/keetanetwork-asn1/docs/README.md b/keetanetwork-asn1/docs/README.md new file mode 100644 index 0000000..ec3bd0a --- /dev/null +++ b/keetanetwork-asn1/docs/README.md @@ -0,0 +1,51 @@ +# keetanetwork-asn1 + +This crate owns the encoding codecs that identity, certificate, block, and vote types share. A build enables at least one of `der` or `rasn`. Both features may be on together. + +## Quickstart + +Default features are `std`, `serde`, and `rasn`. Enable at least one of `der` or `rasn`. + +```bash +cargo test -p keetanetwork-asn1 +``` + +`make test-feat` also runs this crate with `std,der` and `std,rasn`. + +## Examples + +### Encode a vote staple + +From `keetanetwork-asn1/tests/vote_codec_vectors.rs` `test_vote_staple_reference_bytes`. + +```rust +use keetanetwork_asn1::vote::{codec, VoteStapleBundle}; + +let bundle = VoteStapleBundle { + blocks: vec![vec![1, 2, 3]], + votes: vec![vec![4, 5, 6]], +}; +let encoded = codec::encode_vote_staple(&bundle).expect("encode staple"); +assert!(!encoded.is_empty()); +``` + +### Decode a vote staple + +From `keetanetwork-asn1/tests/vote_codec_vectors.rs` `test_vote_staple_reference_bytes`. + +```rust +use keetanetwork_asn1::vote::{codec, VoteStapleBundle}; + +let bundle = VoteStapleBundle { + blocks: vec![vec![1, 2, 3]], + votes: vec![vec![4, 5, 6]], +}; +let encoded = codec::encode_vote_staple(&bundle).expect("encode staple"); +let decoded = codec::decode_vote_staple(&encoded).expect("decode staple"); +assert_eq!(decoded, bundle); +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-asn1/src/lib.rs b/keetanetwork-asn1/src/lib.rs index 5be7232..c07ef87 100644 --- a/keetanetwork-asn1/src/lib.rs +++ b/keetanetwork-asn1/src/lib.rs @@ -11,7 +11,8 @@ //! - `rasn` - Use the `rasn` crate for ASN.1 handling //! - `serde` - Enable serde serialization support //! -//! Exactly one of `der` or `rasn` must be enabled. +//! Enable at least one of the `der` and `rasn` features. +//! Both features may be on together. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/keetanetwork-bindings/docs/ARCHITECTURE.md b/keetanetwork-bindings/docs/ARCHITECTURE.md new file mode 100644 index 0000000..0ef3e0f --- /dev/null +++ b/keetanetwork-bindings/docs/ARCHITECTURE.md @@ -0,0 +1,50 @@ +# Bindings + +## Abstract + +This page is the internal design of `keetanetwork-bindings`. The crate is the shared, target-agnostic projection. Browser and WASI ABIs call these modules so each host does not grow a second parser or algorithm map. + +## Purpose + +An engineer reads this page before adding host-facing parsing in `keetanetwork-client-wasm` or `keetanetwork-client-wasi`. After reading, the engineer knows which module owns amounts, algorithms, errors, and certificates. + +## Internal design + +`parse` owns decimal `amount` parsing, adjust methods, purposes, and permission flag names. Rejected input becomes `ParseError` with a stable `code` such as `INVALID_AMOUNT`. + +`account` owns `CRYPTO_ALGORITHMS`, `algorithm_name`, seed and public-key construction, and sign, verify, encrypt, and decrypt helpers. The default algorithm name is `ecdsa_secp256k1`. Identifier accounts map to `"other"`. + +`error` owns `CodedError`, the reduced error shape hosts throw. `permissions` owns permission projection. `x509` owns certificate DER and PEM helpers. `time` owns moment parsing. `registry` owns small lookup tables. `client` is present when the `client` feature is on and pulls `keetanetwork-client`. + +```mermaid +flowchart LR + mod_parse[parse] + mod_account[account] + mod_error[error] + mod_x509[x509] + crate_account[keetanetwork-account] + crate_block[keetanetwork-block] + crate_wasm[keetanetwork-client-wasm] + crate_wasi[keetanetwork-client-wasi] + crate_account --> mod_account + crate_block -->|Amount| mod_parse + mod_parse --> mod_error + mod_account --> crate_wasm + mod_parse --> crate_wasm + mod_x509 --> crate_wasi + mod_account --> crate_wasi +``` + +## Collaboration + +Inbound: account, crypto, block, vote, x509, and asn1 crates are path dependencies with `alloc` and `rasn`. Feature `client` pulls `keetanetwork-client`. + +Outbound: `keetanetwork-client-wasm` depends on this crate with the `client` feature. `keetanetwork-client-wasi` depends on this crate on every build. Feature `p2` on the WASI crate also enables `keetanetwork-bindings/client`. + +## Feature contract + +Default features include `std`. Feature `client` is opt-in. A target crate that only needs the pure projection leaves `client` off. + +## Falsified by + +A change that moves account-algorithm mapping or core-error reduction into wasm or WASI without this crate. A change to the `client` feature in `keetanetwork-bindings/Cargo.toml`. A change that drops this crate from either host ABI crate. diff --git a/keetanetwork-bindings/docs/README.md b/keetanetwork-bindings/docs/README.md new file mode 100644 index 0000000..5e12643 --- /dev/null +++ b/keetanetwork-bindings/docs/README.md @@ -0,0 +1,42 @@ +# keetanetwork-bindings + +This crate is the shared, target-agnostic projection used by the browser and WASI ABIs. It owns input parsing, account-algorithm mapping, and core-error reduction. + +## Quickstart + +Default features include `std`. Feature `client` is opt-in. + +```bash +cargo test -p keetanetwork-bindings +``` + +## Examples + +### Parse amount + +From `keetanetwork-bindings/src/parse.rs` `amount_round_trips_decimal_strings`. + +```rust +use keetanetwork_bindings::parse::{amount, amount_to_string}; + +let parsed = amount("1000").expect("a decimal string must parse"); +assert_eq!(amount_to_string(parsed), "1000"); +``` + +### Algorithm map + +From `keetanetwork-bindings/src/account.rs` `algorithm_names_round_trip_every_crypto_type`. + +```rust +use keetanetwork_account::KeyPairType; +use keetanetwork_bindings::account::{algorithm_name, CRYPTO_ALGORITHMS}; + +assert_eq!(algorithm_name(KeyPairType::ED25519), "ed25519"); +assert_eq!(algorithm_name(KeyPairType::TOKEN), "other"); +assert_eq!(CRYPTO_ALGORITHMS[1].0, "ecdsa_secp256k1"); +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-block/docs/ARCHITECTURE.md b/keetanetwork-block/docs/ARCHITECTURE.md new file mode 100644 index 0000000..8c19883 --- /dev/null +++ b/keetanetwork-block/docs/ARCHITECTURE.md @@ -0,0 +1,52 @@ +# Block + +## Abstract + +This page is the internal design of `keetanetwork-block`. The crate turns an account identity and a list of operations into a signed block. Opening-hash and successor rules live here. Vote and client consume the resulting hashes and bytes. + +## Purpose + +An engineer reads this page before changing how a first block or a successor is signed. After reading, the engineer can name the path from `BlockBuilder` through `UnsignedBlock` to `Block`, and which operation variants that builder accepts. + +## Internal design + +`builder` owns `BlockBuilder`. The builder collects network, account, previous hash, and operations. `as_opening` selects the opening previous. `with_previous` selects a successor. `build` produces `UnsignedBlock`. + +`block` owns `UnsignedBlock`, `Block`, `BlockData`, `BlockPurpose`, and `Signature`. `UnsignedBlock::sign` attaches the account signature and yields `Block`. `Block::try_from` decodes bytes. `Hashable` comes from `keetanetwork-crypto` and is re-exported as `BlockHash`. + +`operation` owns `Operation` and `OperationType`. Variants are `Send`, `SetRep`, `SetInfo`, `ModifyPermissions`, `CreateIdentifier`, `TokenAdminSupply`, `TokenAdminModifyBalance`, `Receive`, and `ManageCertificate`. Each variant validates itself against the surrounding block. + +`signer` owns `AccountRef` and `Signer`. `AccountRef` wraps `GenericAccount` from the account crate. `account_util` is crate-private dispatch over `GenericAccount` variants for parse, verify, and equality. `amount` owns `Amount`. `permissions` owns permission flags and groups. `time` owns `BlockTime`. `validation` owns `ValidationConfig` and text rules. `transport` owns byte encoding. `error` owns `BlockError`. `testing` is present when the `testing` feature is on. + +```mermaid +flowchart LR + crate_account[keetanetwork-account] + type_ref[AccountRef] + type_op[Operation] + type_builder[BlockBuilder] + type_unsigned[UnsignedBlock] + type_block[Block] + crate_vote[keetanetwork-vote] + crate_client[keetanetwork-client] + crate_account -->|GenericAccount| type_ref + type_ref --> type_builder + type_op --> type_builder + type_builder -->|build| type_unsigned + type_unsigned -->|sign| type_block + type_block -->|block hash| crate_vote + type_block --> crate_client +``` + +## Collaboration + +Inbound: `keetanetwork-account` supplies the identity inside `AccountRef`. `keetanetwork-crypto` supplies `Hashable` and signatures. `keetanetwork-asn1` and `keetanetwork-x509` supply encoding and certificate material for `ManageCertificate`. + +Outbound: `keetanetwork-vote` covers block hashes. `keetanetwork-client` assembles blocks through `TransactionBuilder` using the same opening-hash and signing rules. Bindings and host ABI crates project the same block types. + +## Feature contract + +Default features are `std` and `rasn`. `std` implies `alloc`. Features `der` and `rasn` forward to asn1, account, crypto, and x509. A `no_std` consumer enables `alloc` and at least one codec. + +## Falsified by + +A change to `Block`, `BlockBuilder`, `UnsignedBlock`, `Operation`, or `AccountRef` ownership. A change that lets the client compute an opening hash without this crate. A change to the rustdoc example in `keetanetwork-block/src/lib.rs`. diff --git a/keetanetwork-block/docs/README.md b/keetanetwork-block/docs/README.md new file mode 100644 index 0000000..8e97767 --- /dev/null +++ b/keetanetwork-block/docs/README.md @@ -0,0 +1,105 @@ +# keetanetwork-block + +This crate owns `Block`, `BlockBuilder`, `Operation`, and `AccountRef`. Opening-hash and signing rules live here. The client builder uses the same rules. + +## Quickstart + +Default features are `std` and `rasn`. + +```bash +cargo test -p keetanetwork-block +``` + +`make test-feat` also runs this crate with `std,der` and `std,rasn`. + +## Examples + +### Opening block and sign + +From `keetanetwork-block/src/lib.rs` rustdoc. + +```rust +use keetanetwork_account::{Account, Accountable, GenericAccount, KeyED25519, KeyPairType, Keyable}; +use keetanetwork_block::{AccountRef, Block, BlockBuilder, Receive}; +use keetanetwork_crypto::hash::Hashable; +use keetanetwork_crypto::prelude::IntoSecret; + +let seed = [7u8; 32].into_secret(); +let account = Account::::try_from(Accountable::KeyAndType( + Keyable::Seed((seed, 0)), + KeyPairType::ED25519, +))?; +let token = account.generate_identifier(KeyPairType::TOKEN, None, 0)?; +let account = AccountRef::from(GenericAccount::Ed25519(account)); + +let unsigned = BlockBuilder::default() + .with_network(0u8) + .with_account(account.clone()) + .as_opening() + .with_operation(Receive { + amount: 10u64.into(), + token: token.into(), + from: account.clone(), + exact: false, + forward: None, + }) + .build()?; + +let block = unsigned.sign()?; +let decoded = Block::try_from(block.to_bytes())?; +assert_eq!(decoded.hash(), block.hash()); +# Ok::<(), keetanetwork_block::BlockError>(()) +``` + +### Successor with previous hash + +From `keetanetwork-block/src/lib.rs` rustdoc for the opening, plus `keetanetwork-block/tests/e2e.rs` successor `Send`. + +```rust +use keetanetwork_account::{Account, Accountable, GenericAccount, KeyED25519, KeyPairType, Keyable}; +use keetanetwork_block::{AccountRef, BlockBuilder, Receive, Send}; +use keetanetwork_crypto::hash::Hashable; +use keetanetwork_crypto::prelude::IntoSecret; + +let seed = [7u8; 32].into_secret(); +let account = Account::::try_from(Accountable::KeyAndType( + Keyable::Seed((seed, 0)), + KeyPairType::ED25519, +))?; +let token = account.generate_identifier(KeyPairType::TOKEN, None, 0)?; +let account = AccountRef::from(GenericAccount::Ed25519(account)); + +let opening = BlockBuilder::default() + .with_network(0u8) + .with_account(account.clone()) + .as_opening() + .with_operation(Receive { + amount: 10u64.into(), + token: token.clone().into(), + from: account.clone(), + exact: false, + forward: None, + }) + .build()? + .sign()?; + +let successor = BlockBuilder::default() + .with_network(0u8) + .with_account(account.clone()) + .with_previous(opening.hash()) + .with_operation(Send { + to: account.clone(), + amount: 1u64.into(), + token: token.into(), + external: None, + }) + .build()? + .sign()?; +assert_ne!(successor.hash(), opening.hash()); +# Ok::<(), keetanetwork_block::BlockError>(()) +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-block/src/lib.rs b/keetanetwork-block/src/lib.rs index b2dd31c..b26d700 100644 --- a/keetanetwork-block/src/lib.rs +++ b/keetanetwork-block/src/lib.rs @@ -37,6 +37,9 @@ //! assert_eq!(decoded.hash(), block.hash()); //! # Ok::<(), keetanetwork_block::BlockError>(()) //! ``` +//! +//! A live harness cookbook lives in +//! [keetanetwork-block/tests/e2e.rs](https://github.com/KeetaNetwork/node-rs/blob/e34666e6693eca47d587b48172fd5058e607e019/keetanetwork-block/tests/e2e.rs#L116-L124). #![cfg_attr(not(feature = "std"), no_std)] diff --git a/keetanetwork-client-wasi/docs/ARCHITECTURE.md b/keetanetwork-client-wasi/docs/ARCHITECTURE.md new file mode 100644 index 0000000..174fbc4 --- /dev/null +++ b/keetanetwork-client-wasi/docs/ARCHITECTURE.md @@ -0,0 +1,46 @@ +# Client WASI + +## Abstract + +This page is the internal design of `keetanetwork-client-wasi`. The crate is two feature-selected WASI flavors over one shared `pure` module. Feature `p2` networks. Feature `p1` stays on the pure surface. + +## Purpose + +An engineer reads this page before changing a WASI feature or adding a second networking path on `p1`. After reading, the engineer knows which module is shared, which module is P1, and which module is P2. + +## Internal design + +`pure` is always compiled. It re-exports account and certificate helpers from `keetanetwork-bindings` and adds block, vote, and identifier operations that both ABIs call. Off a WASI target, `p1` and `p2` compile out and leave `pure`. + +`p1` is present when feature `p1` is on and the target is WASI. It is a core module over a flat ABI. P1 has no outbound `connect`. The host dials. + +`p2` is present when feature `p2` is on and the target is WASI. It is a `wit-bindgen` component that networks over `wasi:http`. That feature pulls `keetanetwork-client` with the `wasi` feature and enables `keetanetwork-bindings/client`. + +A WASI build enables exactly one of `p1` or `p2`. The `compile_error!` in `keetanetwork-client-wasi/src/lib.rs` is the enforcement point. + +```mermaid +flowchart TB + mod_pure[pure] + mod_p1[p1] + mod_p2[p2] + crate_bindings[keetanetwork-bindings] + crate_client[keetanetwork-client] + crate_bindings --> mod_pure + mod_pure --> mod_p1 + mod_pure --> mod_p2 + crate_client -->|feature p2| mod_p2 +``` + +## Collaboration + +Inbound: this crate always depends on account, block, crypto, vote, x509, and bindings. Feature `p2` adds `keetanetwork-client`. + +Outbound: host tests under `keetanetwork-client-wasi/host-tests/` exercise P1 and P2 artifacts. `make build-wasi` and `make test-wasi` select `p1` for `wasm32-wasip1` and `p2` for `wasm32-wasip2`. + +## Feature contract + +Select exactly one of `p1` or `p2` per WASI build. Feature `p2` is the only edge from this crate to `keetanetwork-client`. Feature `p1` stays on the pure surface. + +## Falsified by + +A change to the `compile_error!` in `keetanetwork-client-wasi/src/lib.rs`. A change that lets a WASI build enable both `p1` and `p2`, or neither. A change that pulls `keetanetwork-client` on feature `p1`. A change to the `p1` / `p2` selection in the `Makefile` `build-wasi` or `test-wasi` targets. diff --git a/keetanetwork-client-wasi/docs/README.md b/keetanetwork-client-wasi/docs/README.md new file mode 100644 index 0000000..e5cdebf --- /dev/null +++ b/keetanetwork-client-wasi/docs/README.md @@ -0,0 +1,55 @@ +# keetanetwork-client-wasi + +This crate is the WASI ABI over a shared `pure` module. A WASI build selects exactly one of `p1` or `p2`. Feature `p2` pulls `keetanetwork-client`. Feature `p1` stays on the pure surface. + +## Quickstart + +Select exactly one of `p1` or `p2` per WASI build. + +```bash +make build-wasi +make test-wasi +``` + +Those Make targets select `p1` for `wasm32-wasip1` and `p2` for `wasm32-wasip2`. Off a WASI target both features compile out and leave `pure`. + +```bash +cargo test -p keetanetwork-client-wasi +``` + +## Examples + +### Seed and account on the pure surface + +From `keetanetwork-bindings/src/account.rs` `account_round_trips_through_seed_and_public_key_string`, re-exported by `keetanetwork-client-wasi/src/pure.rs`. + +```rust +use keetanetwork_client_wasi::pure; + +let seed = pure::generate_seed().expect("seed generation must succeed"); +let account = pure::account_from_seed(&seed, 0, pure::DEFAULT_ALGORITHM) + .expect("account derivation must succeed"); +let public_key_string = pure::account_public_key_string(&account); +assert!(!public_key_string.is_empty()); +``` + +### Identifier from a pure account + +From `keetanetwork-client-wasi/src/pure.rs` `generate_identifier`. + +```rust +use keetanetwork_account::KeyPairType; +use keetanetwork_client_wasi::pure; + +let seed = pure::generate_seed().expect("seed generation must succeed"); +let account = pure::account_from_seed(&seed, 0, pure::DEFAULT_ALGORITHM) + .expect("account derivation must succeed"); +let token = pure::generate_identifier(&account, KeyPairType::TOKEN, None, 0) + .expect("identifier derivation must succeed"); +assert_ne!(pure::account_public_key_string(&account), pure::account_public_key_string(&token)); +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-client-wasm/docs/ARCHITECTURE.md b/keetanetwork-client-wasm/docs/ARCHITECTURE.md new file mode 100644 index 0000000..803bffd --- /dev/null +++ b/keetanetwork-client-wasm/docs/ARCHITECTURE.md @@ -0,0 +1,46 @@ +# Client wasm + +## Abstract + +This page is the internal design of `keetanetwork-client-wasm`. The crate is the browser ABI. It projects `keetanetwork-client` and `keetanetwork-bindings` into JavaScript. Amounts stay decimal strings. Errors carry `error.code`. + +## Purpose + +An engineer reads this page before changing the browser ABI or adding a JavaScript `number` amount. After reading, the engineer can name which module owns the client, the user facade, and the conversions that keep amounts as strings. + +## Internal design + +`client` and `user` own the JavaScript `KeetaClient` and `UserClient`. `builder` and `block_builder` own multi-operation assembly on the JS side. `account` owns seed and public-key construction. `block`, `vote`, `certificate`, and `x509` project those domain types. + +`convert` and `dto` own the boundary conversions. Amounts become decimal strings. Cryptographic bytes become `Uint8Array`. Hashes and keys become hex strings. `options` owns `TransmitOptions`. `permissions`, `rep`, `pending`, and `swap` project the remaining client surfaces. + +The crate is gated to `wasm32-unknown-unknown`. It depends on `keetanetwork-client` with the `wasm` feature so `http` pairs with `WasmRuntime`. + +```mermaid +flowchart LR + js_caller[JavaScript caller] + mod_user[user] + mod_client[client] + mod_convert[convert] + crate_bindings[keetanetwork-bindings] + crate_client[keetanetwork-client] + js_caller -->|decimal string amounts| mod_user + mod_user --> mod_client + mod_convert --> mod_user + crate_bindings --> mod_convert + crate_client --> mod_client +``` + +## Collaboration + +Inbound: `keetanetwork-client` with `wasm`, `keetanetwork-bindings` with `client`, plus account, block, crypto, x509, and asn1. + +Outbound: this crate is a leaf ABI. Browser callers import the `wasm-pack` package. They do not take a Rust path dependency on the other workspace crates. + +## Feature contract + +The client `wasm` feature enables `http` on `wasm32-unknown-unknown`. That pairing satisfies the `compile_error!` in `keetanetwork-client/src/lib.rs`. Amounts are decimal strings. Errors are JavaScript `Error` objects that carry `error.code`. + +## Falsified by + +A change that accepts a JavaScript `number` as an amount. A change that drops `error.code` from thrown errors. A change that builds this crate without client feature `wasm` or bindings feature `client`. diff --git a/keetanetwork-client-wasm/docs/README.md b/keetanetwork-client-wasm/docs/README.md new file mode 100644 index 0000000..8e0a3dd --- /dev/null +++ b/keetanetwork-client-wasm/docs/README.md @@ -0,0 +1,67 @@ +# keetanetwork-client-wasm + +This crate is the browser ABI over `keetanetwork-client` and `keetanetwork-bindings`. Amounts are decimal strings. Errors carry `error.code`. + +## Quickstart + +This crate depends on `keetanetwork-client` with the `wasm` feature and `keetanetwork-bindings` with the `client` feature. + +```bash +make build-wasm +make test-wasm +``` + +Those Make targets need GitHub Packages read. [Workspace Quickstart](../../docs/QUICKSTART.md) holds the Packages gate. + +## Examples + +### Send through UserClient + +From `keetanetwork-client-wasm/src/lib.rs` rustdoc. + +```js +import init, { KeetaClient, UserClient, Account, TransmitOptions } from './pkg/keetanetwork_client_wasm.js'; + +await init(); +const client = KeetaClient.forNetwork('test'); +const me = Account.fromSeed(Account.generateSeed(), 0); +const token = Account.fromPublicKeyString('keeta_...token...'); +const to = Account.fromPublicKeyString('keeta_...recipient...'); + +const user = UserClient.fromClient(client, me); +await user.send(to, '1000', token); + +const builder = user.initBuilder(); +builder.send(to, '250', token); +await user.transmit(await builder.build(), new TransmitOptions()); +``` + +### Sign, verify, and coded amount error + +From `keetanetwork-client-wasm/src/lib.rs` rustdoc. + +```js +import init, { KeetaClient, UserClient, Account } from './pkg/keetanetwork_client_wasm.js'; + +await init(); +const client = KeetaClient.forNetwork('test'); +const me = Account.fromSeed(Account.generateSeed(), 0); +const token = Account.fromPublicKeyString('keeta_...token...'); +const to = Account.fromPublicKeyString('keeta_...recipient...'); +const user = UserClient.fromClient(client, me); + +const message = new TextEncoder().encode('hello'); +const signature = me.sign(message); +const ok = me.verify(message, signature); // true + +try { + await user.send(to, 'not-a-number', token); +} catch (error) { + console.error(error.code, error.message); // INVALID_AMOUNT +} +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-client/docs/ARCHITECTURE.md b/keetanetwork-client/docs/ARCHITECTURE.md new file mode 100644 index 0000000..8c2d8cc --- /dev/null +++ b/keetanetwork-client/docs/ARCHITECTURE.md @@ -0,0 +1,53 @@ +# Client + +## Abstract + +This page is the internal design of `keetanetwork-client`. The crate is the orchestrator. It assembles blocks with the same rules as `keetanetwork-block`, then transmits vote staples through a generated HTTP transport. + +## Purpose + +An engineer reads this page before changing client construction, HTTP generation, or the `http` runtime pairing. After reading, the engineer can name the path from `KeetaClient` through `TransactionBuilder` and `UserClient` to the generated transport. + +## Internal design + +`client` owns `KeetaClient`. Construction is `KeetaClient::new` plus `with_network`, or `with_parts` for a `no_std` consumer that supplies a `Runtime` and a `NodeTransport`. + +`builder` owns `TransactionBuilder`. It assembles operations into blocks using block opening-hash and signing rules. `user` owns `UserClient`. A `UserClient` binds a signer and an optional operating account. Writes originate for the account and are signed by the bound signer. A client without a signer is read-only. + +`transport` owns `NodeTransport` and `TransportFactory`. Feature `http` generates the HTTP client from `keetanetwork-client/openapi/keetanet-node.yaml` through progenitor into the `generated` module when `codec` is on. `runtime` owns `Runtime`, `TokioRuntime` on `std`, `WasmRuntime` on `wasm`, and `WasiRuntime` on `wasi`. + +`model` owns query and response types. `rep` owns representative selection. `network` is present with `http`. `config` owns `ClientConfig`. `codec` owns transport-agnostic encoding when the `codec` feature is on. `genesis` owns network initialization helpers. `swap` owns swap request types. `math` owns quorum and backoff helpers. `sync` owns the `no_std` lock primitives that the orchestrator shares. `marker` owns `MaybeSend` and `MaybeSync`. `error` owns `ClientError`. + +```mermaid +flowchart LR + type_client[KeetaClient] + type_user[UserClient] + type_tx[TransactionBuilder] + type_runtime[Runtime] + type_transport[NodeTransport] + mod_generated[generated] + crate_block[keetanetwork-block] + crate_vote[keetanetwork-vote] + type_client --> type_user + type_user --> type_tx + type_client --> type_runtime + type_client --> type_transport + mod_generated --> type_transport + crate_block --> type_tx + type_tx -->|blocks| crate_vote + crate_vote -->|VoteStaple| type_client +``` + +## Collaboration + +Inbound: `keetanetwork-account` supplies `AccountRef`. `keetanetwork-block` supplies opening-hash and signing. `keetanetwork-vote` supplies vote types that this crate re-exports. `keetanetwork-error` supplies `KeetaNetError`, also re-exported. + +Outbound: `keetanetwork-client-wasm` enables the `wasm` feature. `keetanetwork-client-wasi` enables this crate only on feature `p2`. `keetanetwork-bindings` takes this crate behind its `client` feature. + +## Feature contract + +Default features include `std`. Feature `std` enables `http` and a native Tokio runtime. Feature `wasm` enables `http` on `wasm32-unknown-unknown`. Feature `wasi` enables `codec` without pulling Tokio. Feature `http` pairs with a runtime. The `compile_error!` in `keetanetwork-client/src/lib.rs` is the enforcement point. The orchestrator is `no_std` plus `alloc` when `std`, `http`, and `wasi` are off. + +## Falsified by + +A change to `KeetaClient`, `UserClient`, or `TransactionBuilder` ownership. A change that moves the OpenAPI document away from `keetanetwork-client/openapi/keetanet-node.yaml`. A change to the `compile_error!` that pairs `http` with a runtime. diff --git a/keetanetwork-client/docs/README.md b/keetanetwork-client/docs/README.md new file mode 100644 index 0000000..4a65369 --- /dev/null +++ b/keetanetwork-client/docs/README.md @@ -0,0 +1,70 @@ +# keetanetwork-client + +This crate owns `KeetaClient`, `UserClient`, and `TransactionBuilder`. HTTP transport is generated from `keetanetwork-client/openapi/keetanet-node.yaml`. + +## Quickstart + +Default features include `std`. Feature `http` pairs with a runtime. Native builds enable `std`. Browser builds enable `wasm`. + +```bash +cargo test -p keetanetwork-client --test user_signing +``` + +`make test` runs the workspace tests after the node harness. [Workspace Quickstart](../../docs/QUICKSTART.md) holds the Packages gate. + +## Examples + +### KeetaClient builder + +From `keetanetwork-client/src/lib.rs` rustdoc. + +```rust +use std::sync::Arc; + +use keetanetwork_account::GenericAccount; +use keetanetwork_account::doc_utils::create_ed25519_test_keys; +use keetanetwork_block::AccountRef; +use keetanetwork_client::KeetaClient; + +let client = KeetaClient::new("http://localhost:8080/api").with_network(0u8); +let (_, _, signer) = create_ed25519_test_keys(None); +let account: AccountRef = Arc::new(GenericAccount::Ed25519(signer)); + +let blocks = client + .builder(&account) + .with_previous(account.to_opening_hash()) + .set_rep(&account) + .build() + .await?; +assert_eq!(blocks.len(), 1); +# Ok::<(), keetanetwork_client::ClientError>(()) +``` + +### UserClient signing + +From `keetanetwork-client/tests/user_signing.rs` `delegated_writes_are_signed_by_the_bound_signer`. + +```rust +use std::sync::Arc; + +use keetanetwork_block::testing::generate_ed25519_ref; +use keetanetwork_client::{KeetaClient, UserClient}; + +let client = KeetaClient::new("http://127.0.0.1:0/api").with_network(1u8); +let account = generate_ed25519_ref(0x40); +let signer = generate_ed25519_ref(0x41); +let rep = generate_ed25519_ref(0x43); +let user = UserClient::from_parts(client, Some(Arc::clone(&signer))).with_account(Arc::clone(&account)); + +let mut builder = user.init_builder()?; +builder.with_previous(account.to_opening_hash()); +builder.set_rep(&rep); +let blocks = builder.build().await?; +assert_eq!(blocks[0].data().signer().principal().to_string(), signer.to_string()); +# Ok::<(), keetanetwork_client::ClientError>(()) +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-client/src/lib.rs b/keetanetwork-client/src/lib.rs index 2af1ef9..6ba8329 100644 --- a/keetanetwork-client/src/lib.rs +++ b/keetanetwork-client/src/lib.rs @@ -36,6 +36,11 @@ //! # } //! ``` //! +//! A live harness cookbook lives in +//! [keetanetwork-client/tests/e2e.rs](https://github.com/KeetaNetwork/node-rs/blob/e34666e6693eca47d587b48172fd5058e607e019/keetanetwork-client/tests/e2e.rs#L164). +//! `UserClient` signing tests live in +//! [keetanetwork-client/tests/user_signing.rs](https://github.com/KeetaNetwork/node-rs/blob/e34666e6693eca47d587b48172fd5058e607e019/keetanetwork-client/tests/user_signing.rs#L15-L20). +//! //! ## `no_std` //! //! The orchestrator ([`KeetaClient`]) is `no_std`+`alloc`: it is written diff --git a/keetanetwork-crypto/docs/ARCHITECTURE.md b/keetanetwork-crypto/docs/ARCHITECTURE.md new file mode 100644 index 0000000..129556d --- /dev/null +++ b/keetanetwork-crypto/docs/ARCHITECTURE.md @@ -0,0 +1,48 @@ +# Crypto + +## Abstract + +This page is the internal design of `keetanetwork-crypto`. The crate is the algorithm-agnostic primitive layer. Account, block, and vote crates derive keys, hash, and sign through these modules. They do not embed a second crypto stack. + +## Purpose + +An engineer reads this page before adding a signing or hashing path in a higher crate. After reading, the engineer can name the module that owns algorithms, hashes, KDF, and secret handling. + +## Internal design + +`algorithms` owns secp256k1, secp256r1, and Ed25519 derivation and key types. `hash` owns `HashAlgorithm`, `hash_default`, `Hashable`, and `BlockHash`. `kdf` owns HKDF-style derivation used by some algorithms. `operations` owns higher-level sign and encrypt entry points. `verify` owns verification helpers. + +`utils` owns `generate_random_seed` and related byte helpers. `prelude` re-exports `IntoSecret`, `ExposeSecret`, and the traits higher crates import. `bigint` owns big-integer helpers used by encodings. `error` owns `CryptoError`. `constants` holds algorithm constants. `test_utils` is present in test builds. + +```mermaid +flowchart LR + mod_algo[algorithms] + mod_hash[hash] + mod_kdf[kdf] + mod_ops[operations] + mod_utils[utils] + crate_account[keetanetwork-account] + crate_block[keetanetwork-block] + crate_vote[keetanetwork-vote] + mod_utils -->|seed| mod_algo + mod_kdf --> mod_algo + mod_algo --> mod_ops + mod_hash --> crate_block + mod_ops --> crate_account + mod_hash --> crate_vote + mod_ops --> crate_vote +``` + +## Collaboration + +Inbound: `keetanetwork-utils` is a path dependency. `keetanetwork-error` is optional and comes on with `std`. `keetanetwork-asn1` is optional behind `der` and `rasn`. + +Outbound: `keetanetwork-account` enables `signature` and `encryption`. `keetanetwork-block` and `keetanetwork-vote` enable `signature` and hash through `Hashable`. `keetanetwork-x509`, `keetanetwork-client`, and `keetanetwork-bindings` call the same primitives. + +## Feature contract + +Default features are `std`, `signature`, `encryption`, and `rasn`. `std` implies `alloc`. Features `der` and `rasn` forward to optional `keetanetwork-asn1`. A `no_std` consumer enables `alloc` plus `signature` or `encryption` as the call site needs. + +## Falsified by + +A change that moves hashing or signing primitives out of this crate. A change that lets account, block, or vote sign without this crate. A change to the `signature`, `encryption`, `der`, or `rasn` features in `keetanetwork-crypto/Cargo.toml`. diff --git a/keetanetwork-crypto/docs/README.md b/keetanetwork-crypto/docs/README.md new file mode 100644 index 0000000..721d654 --- /dev/null +++ b/keetanetwork-crypto/docs/README.md @@ -0,0 +1,45 @@ +# keetanetwork-crypto + +This crate owns algorithm-agnostic primitives for keys, hashes, signatures, and encryption. Account, block, and vote crates call these modules. They do not embed a second crypto stack. + +## Quickstart + +Default features are `std`, `signature`, `encryption`, and `rasn`. `std` implies `alloc`. + +```bash +cargo test -p keetanetwork-crypto +``` + +`make test-feat` also runs this crate with `std,signature`, `std,encryption`, `std,der`, and `std`. + +## Examples + +### Default hash + +From `keetanetwork-crypto/src/hash.rs` `hash_default`. + +```rust +use keetanetwork_crypto::hash::hash_default; + +let digest = hash_default(b"hello world"); +assert_eq!(digest.len(), 32); +``` + +### Random seed + +From `keetanetwork-crypto/src/utils.rs` `test_generate_random_seed`. + +```rust +use keetanetwork_crypto::prelude::ExposeSecret; +use keetanetwork_crypto::utils::generate_random_seed; + +let seed = generate_random_seed()?; +assert_eq!(seed.expose_secret().len(), 32); +assert_ne!(*seed.expose_secret(), [0u8; 32]); +# Ok::<(), keetanetwork_crypto::error::CryptoError>(()) +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-error/docs/ARCHITECTURE.md b/keetanetwork-error/docs/ARCHITECTURE.md new file mode 100644 index 0000000..ebfa50a --- /dev/null +++ b/keetanetwork-error/docs/ARCHITECTURE.md @@ -0,0 +1,49 @@ +# Error + +## Abstract + +This page is the internal design of `keetanetwork-error`. The crate is a single-module envelope. It turns a node error `type` field into `NodeErrorType`, then builds a typed `KeetaNetError` from decoded parts. + +## Purpose + +An engineer reads this page before adding a crate-local error envelope that callers must learn twice. After reading, the engineer knows how a node envelope becomes `Code`, `Ledger`, `LedgerVote`, or `LedgerIdempotent`. + +## Internal design + +The crate has no submodule split. `NodeErrorType` is the category taken from the envelope `type` field. Known categories are `Account`, `Api`, `Block`, `Certificate`, `Client`, `Kv`, `Ledger`, `Permissions`, `Vote`, and `Generic`. + +`NodeErrorParts` is the decoded envelope used to construct `KeetaNetError`. Non-ledger kinds collapse to `KeetaNetError::Code`. Ledger codes in `LEDGER_NOT_SUCCESSOR` and `LEDGER_NOT_OPENING` become `LedgerVote` when accounts are present. `LEDGER_IDEMPOTENT_KEY_EXISTS` becomes `LedgerIdempotent` when both block hashes are present. Other ledger codes become `Ledger` and may carry retry data. + +`KeetaNetError` also has `Internal`, `Unknown`, and `NotImplemented` for local failures that are not node envelopes. `node_type` recovers a category from a coded variant by reading the code prefix. + +```mermaid +flowchart TD + type_parts[NodeErrorParts] + type_kind[NodeErrorType] + var_code[KeetaNetError_Code] + var_ledger[KeetaNetError_Ledger] + var_vote[KeetaNetError_LedgerVote] + var_idem[KeetaNetError_LedgerIdempotent] + var_internal[KeetaNetError_Internal] + type_local[local failure] + type_parts --> type_kind + type_kind -->|non ledger| var_code + type_kind -->|ledger base| var_ledger + type_kind -->|ledger vote codes| var_vote + type_kind -->|ledger idempotent codes| var_idem + type_local --> var_internal +``` + +## Collaboration + +Inbound: this crate depends only on `snafu`. It does not depend on other workspace crates. + +Outbound: `keetanetwork-account`, `keetanetwork-block`, `keetanetwork-vote`, `keetanetwork-x509`, and `keetanetwork-client` return or wrap these types. `keetanetwork-client` re-exports `KeetaNetError` and `NodeErrorType`. `keetanetwork-crypto` takes this crate only when `std` is on. + +## Feature contract + +Default features include `std`. `std` implies `alloc`. The crate builds under `no_std` with `alloc`. + +## Falsified by + +A change to `KeetaNetError` or `NodeErrorType` in `keetanetwork-error/src/lib.rs`. A change that drops the client re-export of those two types. A change to the ledger code tables that select `LedgerVote` or `LedgerIdempotent`. diff --git a/keetanetwork-error/docs/README.md b/keetanetwork-error/docs/README.md new file mode 100644 index 0000000..38cea08 --- /dev/null +++ b/keetanetwork-error/docs/README.md @@ -0,0 +1,46 @@ +# keetanetwork-error + +This crate owns shared error types that higher crates return. `KeetaNetError` carries an internal failure or a node-emitted coded error. `NodeErrorType` is the category taken from the `type` field of a node error envelope. + +## Quickstart + +Default features include `std`. `std` implies `alloc`. + +```bash +cargo test -p keetanetwork-error +``` + +## Examples + +### Coded node envelope + +From `keetanetwork-error/src/lib.rs` `non_ledger_collapses_to_code`. + +```rust +use keetanetwork_error::{KeetaNetError, NodeErrorParts, NodeErrorType}; + +let parts = NodeErrorParts { + kind: NodeErrorType::Api, + code: "API_INVALID_SIDE".into(), + message: "boom".into(), + ..Default::default() +}; +let error = KeetaNetError::from(parts); +assert!(matches!(error, KeetaNetError::Code { code, .. } if code == "API_INVALID_SIDE")); +``` + +### Internal construction + +From `keetanetwork-error/src/lib.rs` `KeetaNetError::Internal`. + +```rust +use keetanetwork_error::KeetaNetError; + +let error = KeetaNetError::Internal; +assert_eq!(error.node_type(), None); +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-ledger/docs/README.md b/keetanetwork-ledger/docs/README.md new file mode 100644 index 0000000..6e337d8 --- /dev/null +++ b/keetanetwork-ledger/docs/README.md @@ -0,0 +1,5 @@ +# Ledger + +`keetanetwork-ledger` is a reserved crate name. `keetanetwork-ledger/src/lib.rs` exports no types. + +[Workspace architecture](../../docs/ARCHITECTURE.md) names that boundary. diff --git a/keetanetwork-node/docs/README.md b/keetanetwork-node/docs/README.md new file mode 100644 index 0000000..3a0bc88 --- /dev/null +++ b/keetanetwork-node/docs/README.md @@ -0,0 +1,5 @@ +# Node + +`keetanetwork-node` is a reserved crate name. `keetanetwork-node/src/lib.rs` exports no types. + +[Workspace architecture](../../docs/ARCHITECTURE.md) names that boundary. diff --git a/keetanetwork-utils/docs/ARCHITECTURE.md b/keetanetwork-utils/docs/ARCHITECTURE.md new file mode 100644 index 0000000..93ddcc0 --- /dev/null +++ b/keetanetwork-utils/docs/ARCHITECTURE.md @@ -0,0 +1,47 @@ +# Utils + +## Abstract + +This page is the internal design of `keetanetwork-utils`. The crate is shared tooling under the product path. It owns test macros, optional ASN.1 build helpers, and the node harness client. + +## Purpose + +An engineer reads this page before adding a workspace-wide test helper or changing the harness feature. After reading, the engineer knows which module is compile-time, which module is test-only, and which module talks to GitHub Packages. + +## Internal design + +`testing` owns `test_error_variants` and `test_error_from_conversions`. Those macros generate Display, Debug, and conversion tests that workspace crates share. + +`errors` owns `impl_source_error_from` and related From-boilerplate macros. Domain crates use those macros so each error enum does not hand-write the same conversions. + +`build` is present when the `build` feature is on. It wraps `rasn-compiler` and cleans generated ASN.1 Rust. `keetanetwork-asn1` and `keetanetwork-x509` call it from their build scripts. + +`node_harness` is present when the `node-harness` feature is on. It talks to `@keetanetwork/keetanet-node` through `keetanetwork-utils/node-harness/.npmrc`. + +```mermaid +flowchart TB + mod_testing[testing] + mod_errors[errors] + mod_build[build] + mod_harness[node_harness] + crate_asn1[keetanetwork-asn1] + crate_x509[keetanetwork-x509] + crate_tests[workspace tests] + mod_errors --> crate_tests + mod_testing --> crate_tests + mod_build --> crate_asn1 + mod_build --> crate_x509 + mod_harness --> crate_tests +``` + +## Collaboration + +This crate is not on the signed-write collaboration path. Account, crypto, asn1, x509, block, and vote crates depend on it for helpers. Test binaries enable `std` and `node-harness` when they talk to a live node. + +## Feature contract + +Default features include `std`. Feature `build` is opt-in and enables `rasn-compiler`. Feature `node-harness` is opt-in and pulls `serde_json` and `snafu`. `make test`, `make test-wasm`, and `make test-wasi` need `node-harness`. + +## Falsified by + +A change to the `build` or `node-harness` features in `keetanetwork-utils/Cargo.toml`. A change to the registry line in `keetanetwork-utils/node-harness/.npmrc`. A change that moves workspace test macros out of `keetanetwork-utils/src/lib.rs`. diff --git a/keetanetwork-utils/docs/README.md b/keetanetwork-utils/docs/README.md new file mode 100644 index 0000000..807c89a --- /dev/null +++ b/keetanetwork-utils/docs/README.md @@ -0,0 +1,69 @@ +# keetanetwork-utils + +This crate owns shared test macros, optional ASN.1 build helpers, and the `node-harness` feature that talks to the private GitHub Packages package. + +## Quickstart + +Default features include `std`. Feature `build` is opt-in. Feature `node-harness` is opt-in. + +```bash +cargo test -p keetanetwork-utils +``` + +[Workspace Quickstart](../../docs/QUICKSTART.md) holds the Packages token steps for `node-harness`. + +## Examples + +### Error variant tests + +From `keetanetwork-utils/src/testing.rs` `test_error_variants`. + +```rust +use keetanetwork_utils::test_error_variants; + +#[derive(Debug, PartialEq, Eq)] +enum TestError { + Simple, + WithData { message: String }, +} + +impl std::fmt::Display for TestError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + TestError::Simple => write!(f, "Simple error"), + TestError::WithData { message } => write!(f, "Error: {message}"), + } + } +} + +test_error_variants! { + test_error_formatting, [ + TestError::Simple, + TestError::WithData { message: "test".to_string() }, + ] +} +``` + +### Source error From impls + +From `keetanetwork-utils/src/errors.rs` rustdoc on `impl_source_error_from`. + +```rust +use keetanetwork_utils::impl_source_error_from; + +#[derive(Debug)] +enum MyError { + IoError { source: std::io::Error }, + ParseError { source: std::num::ParseIntError }, +} + +impl_source_error_from!(MyError, { + std::io::Error => IoError, + std::num::ParseIntError => ParseError, +}); +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-vote/docs/ARCHITECTURE.md b/keetanetwork-vote/docs/ARCHITECTURE.md new file mode 100644 index 0000000..5d73056 --- /dev/null +++ b/keetanetwork-vote/docs/ARCHITECTURE.md @@ -0,0 +1,53 @@ +# Vote + +## Abstract + +This page is the internal design of `keetanetwork-vote`. The crate turns block hashes into a representative commitment, then compresses votes and blocks into a staple. The client re-exports the consumer-facing vote types. + +## Purpose + +An engineer reads this page before changing vote construction or adding a second staple type in the client. After reading, the engineer can name the path from `VoteBuilder` to `Vote`, from `VoteQuoteBuilder` to `VoteQuote`, and from `VoteStapleBuilder` to `VoteStaple`. + +## Internal design + +`builder` owns the three fluent builders. `VoteBuilder` produces `UnsignedVote` or a signed `Vote`. `VoteQuoteBuilder` wraps `VoteBuilder` and forces `quote = true` on the fee schedule. A quote cannot be stapled or used to confirm blocks. `VoteStapleBuilder` collects votes and blocks, applies canonical ordering, and builds a `VoteStaple`. + +`vote` owns `Vote`, `VoteQuote`, `UnsignedVote`, and `PossiblyExpiredVote`. A possibly expired vote is parsed and signature-verified. Its validity window may have ended. + +`staple` owns `VoteStaple`. `Vote::verify` decodes bytes, rejects non-canonical DER, and checks the issuer signature. `VoteStaple::verify` also enforces canonical ordering, an agreed block set, a single issuer, and uniform permanence at a caller-supplied moment. + +`cert` owns certificate-shaped encoding that uses account `CertSigner`. `fee` owns `Fee` and `Fees` as `Single` or `Multiple`. `validity` owns the validity window. `hash` owns `VoteBlockHash`, `VoteHash`, and `VoteStapleHash`. `validation` owns `ValidationConfig`. `error` owns `VoteError`. `testing` is present when the `testing` feature is on. + +```mermaid +flowchart LR + crate_block[keetanetwork-block] + type_builder[VoteBuilder] + type_quote_builder[VoteQuoteBuilder] + type_vote[Vote] + type_quote[VoteQuote] + type_staple_builder[VoteStapleBuilder] + type_staple[VoteStaple] + crate_client[keetanetwork-client] + crate_block -->|block hash| type_builder + type_builder -->|build_signed| type_vote + type_quote_builder -->|quote true| type_quote + type_vote --> type_staple_builder + crate_block -->|Block| type_staple_builder + type_staple_builder --> type_staple + type_vote --> crate_client + type_staple --> crate_client +``` + +## Collaboration + +Inbound: `keetanetwork-block` supplies `AccountRef`, `Block`, and `BlockHash`. `keetanetwork-account` supplies the issuer and `CertSigner`. `keetanetwork-crypto` supplies signatures. `keetanetwork-asn1` supplies vote transport codecs. + +Outbound: `keetanetwork-client` re-exports `Vote`, `VoteQuote`, `VoteStaple`, and `VoteBlockHash`. `keetanetwork-bindings` and `keetanetwork-client-wasi` project vote types at host ABIs. + +## Feature contract + +Default features are `std` and `rasn`. `std` implies `alloc`. Features `der` and `rasn` forward to asn1, account, crypto, and block. A `no_std` consumer enables `alloc` and at least one codec. + +## Falsified by + +A change to `Vote`, `VoteQuote`, `VoteStaple`, or `PossiblyExpiredVote` ownership. A change that drops the client re-export of `Vote`, `VoteQuote`, or `VoteStaple`. A change to the rustdoc example in `keetanetwork-vote/src/lib.rs`. diff --git a/keetanetwork-vote/docs/README.md b/keetanetwork-vote/docs/README.md new file mode 100644 index 0000000..95461fb --- /dev/null +++ b/keetanetwork-vote/docs/README.md @@ -0,0 +1,76 @@ +# keetanetwork-vote + +This crate owns `Vote`, `VoteQuote`, `VoteStaple`, and `PossiblyExpiredVote`. A quote is for fee negotiation. A staple is the bundle that operators transmit. + +## Quickstart + +Default features are `std` and `rasn`. + +```bash +cargo test -p keetanetwork-vote +``` + +## Examples + +### VoteBuilder signed vote + +From `keetanetwork-vote/src/lib.rs` rustdoc. + +```rust +use std::sync::Arc; + +use keetanetwork_account::GenericAccount; +use keetanetwork_account::doc_utils::create_ed25519_test_keys; +use keetanetwork_block::{AccountRef, BlockTime}; +use keetanetwork_vote::VoteBuilder; + +let (_, _, signer) = create_ed25519_test_keys(None); +let issuer: AccountRef = Arc::new(GenericAccount::Ed25519(signer)); +let from = BlockTime::from_unix_millis(1_000_000).expect("moment in range"); +let to = BlockTime::from_unix_millis(2_000_000).expect("moment in range"); + +let vote = VoteBuilder::new() + .serial(1u64) + .issuer(issuer.clone()) + .validity(from, to) + .add_block(issuer.to_opening_hash()) + .build_signed(issuer.as_ref())?; +assert!(!vote.as_bytes().is_empty()); +# Ok::<(), keetanetwork_vote::VoteError>(()) +``` + +### VoteQuoteBuilder + +From `keetanetwork-vote/src/builder.rs` `test_vote_quote_builder_forces_quote_flag`. + +```rust +use std::sync::Arc; + +use keetanetwork_account::GenericAccount; +use keetanetwork_account::doc_utils::create_ed25519_test_keys; +use keetanetwork_block::{AccountRef, BlockTime}; +use keetanetwork_vote::{Fee, Fees, VoteQuoteBuilder}; + +let (_, _, signer) = create_ed25519_test_keys(None); +let issuer: AccountRef = Arc::new(GenericAccount::Ed25519(signer)); +let from = BlockTime::from_unix_millis(1_000_000).expect("moment in range"); +let to = BlockTime::from_unix_millis(2_000_000).expect("moment in range"); + +let quote = VoteQuoteBuilder::new() + .serial(1u64) + .issuer(issuer.clone()) + .validity(from, to) + .add_block(issuer.to_opening_hash()) + .fees(Fees::Single { + quote: true, + fee: Fee { amount: 1u64.into(), pay_to: None, token: None }, + }) + .build(issuer.as_ref())?; +assert!(quote.as_vote().is_quote()); +# Ok::<(), keetanetwork_vote::VoteError>(()) +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md) diff --git a/keetanetwork-x509/docs/ARCHITECTURE.md b/keetanetwork-x509/docs/ARCHITECTURE.md new file mode 100644 index 0000000..64ca09b --- /dev/null +++ b/keetanetwork-x509/docs/ARCHITECTURE.md @@ -0,0 +1,48 @@ +# X.509 + +## Abstract + +This page is the internal design of `keetanetwork-x509`. The crate builds, stores, and validates certificates. Account crate traits sign and verify those artifacts. This crate does not grow a second signer trait. + +## Purpose + +An engineer reads this page before adding a certificate builder in another crate. After reading, the engineer can name the module that owns builders, certificate types, distinguished names, and validation. + +## Internal design + +`builder` owns `CertificateBuilder` and `ExtensionBuilder`. A builder assembles subject, issuer, serial, validity, and extensions, then signs through `CertSigner` on the account crate. + +`certificates` owns the parsed certificate types and verification entry points. `utils` owns `create_dn` and other name helpers. `oids` owns certificate object identifiers. `asn1` owns crate-local ASN.1 helpers used by builders. `error` owns `CertificateError`. + +`serde` is present when the `serde` feature is on. `testing` and `doc_utils` are test and rustdoc helpers. + +```mermaid +flowchart LR + mod_utils[utils] + mod_builder[builder] + mod_certs[certificates] + mod_oids[oids] + crate_account[keetanetwork-account] + crate_asn1[keetanetwork-asn1] + crate_block[keetanetwork-block] + mod_oids --> mod_utils + mod_utils -->|DistinguishedName| mod_builder + crate_account -->|CertSigner| mod_builder + crate_asn1 --> mod_builder + mod_builder -->|signed certificate| mod_certs + mod_certs --> crate_block +``` + +## Collaboration + +Inbound: `keetanetwork-account` supplies `CertSigner` and `CertVerifier`. `keetanetwork-asn1` and `keetanetwork-crypto` supply encodings and key material. `keetanetwork-utils` with the `build` feature supports the crate build script. + +Outbound: `keetanetwork-block` depends on this crate so a block can carry certificate material. `keetanetwork-bindings`, `keetanetwork-client-wasm`, and `keetanetwork-client-wasi` project certificates at host ABIs. + +## Feature contract + +Default features are `std`, `serde`, and `rasn`. `std` implies `alloc`. Features `der` and `rasn` forward to `keetanetwork-asn1`, `keetanetwork-crypto`, and `keetanetwork-account`. A `no_std` consumer enables `alloc` and at least one codec. + +## Falsified by + +A change that moves certificate builders or stores off this crate. A change that adds a signer trait on this crate that duplicates `CertSigner` or `CertVerifier`. A change to the `der` / `rasn` forwarding in `keetanetwork-x509/Cargo.toml`. diff --git a/keetanetwork-x509/docs/README.md b/keetanetwork-x509/docs/README.md new file mode 100644 index 0000000..fabb9b0 --- /dev/null +++ b/keetanetwork-x509/docs/README.md @@ -0,0 +1,66 @@ +# keetanetwork-x509 + +This crate owns X.509 certificate builders, stores, and validation. Account crate traits `CertSigner` and `CertVerifier` sign and verify those artifacts. + +## Quickstart + +Default features are `std`, `serde`, and `rasn`. Features `der` and `rasn` forward to `keetanetwork-asn1`. + +```bash +cargo test -p keetanetwork-x509 +``` + +`make test-feat` also runs this crate with `std,der` and `std,rasn`. + +## Examples + +### Distinguished name + +From `keetanetwork-x509/src/utils.rs` rustdoc on `create_dn`. + +```rust +use keetanetwork_asn1::oids; +use keetanetwork_x509::utils::create_dn; + +let pairs = &[ + (oids::CN, "example.com"), + (oids::O, "Example Organization"), +]; +let dn = create_dn(pairs)?; +# Ok::<(), Box>(()) +``` + +### Certificate builder + +From `keetanetwork-x509/src/builder.rs` rustdoc. + +```rust +use keetanetwork_account::{Account, KeyED25519}; +use keetanetwork_asn1::SubjectPublicKeyInfo; +use keetanetwork_crypto::algorithms::ed25519::Ed25519Derivation; +use keetanetwork_crypto::prelude::KeyDerivation; +use keetanetwork_crypto::utils::generate_random_seed; +use keetanetwork_x509::builder::CertificateBuilder; +use keetanetwork_x509::{oids, utils, SerialNumber}; + +let seed = generate_random_seed()?; +let private_key = Ed25519Derivation::derive_from_seed(seed)?; +let account = Account::::from(private_key); +let public_key_info = SubjectPublicKeyInfo::from(account.keypair.to_public_key()); +let subject_dn = utils::create_dn(&[(oids::CN, "Example Certificate")])?; + +let certificate = CertificateBuilder::new() + .with_subject_public_key(public_key_info.clone()) + .with_subject_dn(subject_dn.clone()) + .with_issuer_dn(subject_dn) + .with_serial_number(SerialNumber::from(1u64)) + .with_validity_days(365) + .build(&account)?; +assert!(certificate.verify_signature(&public_key_info).is_ok()); +# Ok::<(), Box>(()) +``` + +## Related documents + +- [Architecture](ARCHITECTURE.md) +- [Workspace overview](../../docs/README.md)