Install
$ agentstack add skill-grantkee-claude-extensions-tn-rust-skills ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Telcoin Network Rust Conventions
Reference material for all tn-* agents working in the telcoin-network codebase. Invoke this skill to load coding conventions, rules, and anti-patterns before writing or reviewing Rust code.
Project Context
The node runs epochs. Each epoch has a committee of BLS-keyed validators that run:
- Workers — build transaction batches, seal them via quorum, gossip batch digests
- Primary — propose DAG headers referencing batch digests, collect votes, form certificates
- Bullshark consensus — order the certificate DAG into a committed sequence
- Executor — subscribe to committed subdags, build
ConsensusOutput - Engine — receive
ConsensusOutput, execute EVM blocks via Reth, extend canonical chain
At epoch boundaries the on-chain committee contract is read, a new committee is formed, and all epoch-scoped resources (TaskManager, ConsensusBus epoch channels, storage) are recycled. Non-validator "observer" nodes follow consensus headers via gossipsub and execute blocks without participating in DAG construction.
Dependency direction rules: tn-types is the foundation — almost everything depends on it. Dependencies flow downward through layers (types → storage → consensus/execution → engine → node → CLI → binary). Never introduce upward dependencies (e.g., tn-types must not depend on tn-storage).
Architecture Awareness
Before writing code, study the codebase architecture. Pay close attention to:
- Domain boundaries: execution, consensus, worker, primary, networking, storage, etc.
- Module organization: understand which crate/module owns which responsibility
- Existing patterns: match the idioms, error handling, and abstractions already in use
- Dependency direction: never introduce circular dependencies or violate layering
If your change touches a domain boundary, pause and verify you're putting logic in the correct domain. Domain-level logic must stay isolated.
New Crate Policy
Always ask permission before adding a new crate to Cargo.toml. Explain:
- What the crate does
- Why it's needed (vs implementing it or using an existing dependency)
- Its maintenance status and trust level
Conventions
Toolchain
- Edition: Rust 2021
- MSRV: 1.94
- Nightly for fmt/clippy:
nightly-2026-03-20(used viacargo +nightly-2026-03-20 fmt) - Test runner:
cargo nextest(parallel execution) - Workspace lints (in root
Cargo.toml): unused_must_use = "deny"-- allResultand#[must_use]values must be handledmissing_docs = "warn"-- add doc comments to public itemsunreachable_pub = "warn"-- preferpub(crate)overpubfor internal itemsunused_crate_dependencies = "warn"-- every dep must be usedrust_2018_idioms = "deny"-- modern Rust style enforced
Error handling
- Domain errors: Use
thiserrorwith enum variants. Each domain has its own error type
(e.g., DagError, HeaderError, CertificateError, BlockSealError, SubscriberError).
- Result type aliases: Define
pub type FooResult = Result;alongside the error enum. - Context propagation: Use
eyre::Result(viaeyre::Report) for storage and infra errors
where you want .wrap_err("context") chains rather than typed variants.
ensure!macro: Defined intn_types::error(andtn_executor::errors). Usage:
``rust use tn_types::ensure; ensure!(condition, DagError::InvalidEpoch { expected, received }); ` This returns Err(e) if condition is false. Do NOT use anyhow::ensure!` -- use the crate's own.
StoreError: Type alias foreyre::Report, used throughout storage.- No
unwrap()in production code -- useexpect("reason")only where the invariant is truly
guaranteed and document why. In test code, unwrap() is acceptable.
Async patterns
TaskManager / TaskSpawner
Structured concurrency primitive defined in tn_types::task_manager.
TaskManagerowns aFuturesUnorderedand tracks critical/non-critical tasksTaskSpawnerisClone, lives with components that need to spawn short-lived work- Critical tasks: when they exit, the manager breaks its join loop and triggers shutdown
- Non-critical tasks: exit silently, other tasks continue
TaskManager::dropcallslocal_shutdown.notify()-- all spawned tasks get cancelled- Epoch-scoped managers are dropped at epoch boundaries to clean up all epoch tasks
- Get a spawner:
let spawner = task_manager.get_spawner(); - Spawn:
spawner.spawn_task("name", async { ... })orspawner.spawn_critical_task("name", future) - Also implements
reth_tasks::TaskSpawnerfor Reth integration
Notifier / Noticer (shutdown)
Defined in tn_types::notifier. Lightweight one-shot broadcast for shutdown signals.
NotifierisClone-- hand it to things that need to trigger shutdownNoticeris aFuturethat resolves whennotifier.notify()is called- Noticer is NOT Clone -- each subscriber gets its own via
notifier.subscribe() - Use in
tokio::select!:
``rust let rx_shutdown = shutdown.subscribe(); tokio::select! { _ = &rx_shutdown => { /* shutdown */ } msg = channel.recv() => { /* work */ } } ``
- Check without awaiting:
rx_shutdown.noticed()returnsbool
ConsensusBus
Defined in crates/consensus/primary/src/consensus_bus.rs. Central channel container for consensus message flow. Two lifetimes:
- App-lifetime (
ConsensusBusApp):watchchannels for round updates, sync status, recent
blocks, epoch records. Persists across epochs.
- Epoch-lifetime (
ConsensusBusEpochInner):QueChannels for certificates, headers,
digests, committed subdags. Recycled each epoch.
QueChannel / TnSender / TnReceiver
Defined in tn_types::sync. Abstraction over tokio channel types:
TnSender: trait implemented bympsc::Senderandbroadcast::SenderTnReceiver: trait implemented bympsc::Receiverandbroadcast::ReceiverQueChannel: managed mpsc channel wrapper used in ConsensusBus, enforces single-subscriberCHANNEL_CAPACITY: default 10,000- Broadcast
recv()handlesLaggedby logging and continuing (not returningNone)
Future-as-struct pattern
Long-running services implement Future directly on their struct (e.g., TaskHandle). This avoids boxing and gives clear ownership semantics.
Concurrency
parking_lotfor synchronous mutexes. NEVER hold aparking_lotlock across an.await
point -- this will deadlock the tokio runtime.
dashmapfor concurrent hash maps where read-heavy access patterns dominate.tokio::sync::Mutex/tokio::sync::RwLockwhen you must hold a lock across.await.Arc>(parking_lot) for shared state within a single async task tree.
Serialization
Three serialization formats, each with a specific purpose:
- BCS (
bcscrate) -- consensus messages, network wire payload (before compression),
general encode/decode. Functions: tn_types::encode(), tn_types::decode(), tn_types::try_decode(), tn_types::encode_into_buffer(). Deterministic and canonical.
- bincode (big-endian, fixint) -- DB keys ONLY. Functions:
tn_types::encode_key(),
tn_types::decode_key(), tn_types::try_decode_key(). Produces binary-sortable bytes required for ordered iteration in the storage layer. NEVER use for non-key data.
- snap (Snappy compression) -- network wire format wraps BCS-encoded bytes in snappy
frames. Wire format: [4-byte uncompressed_len][4-byte compressed_len][compressed_data]. Implemented in crates/network-libp2p/src/codec.rs via TNCodec.
Cryptography
- BLS12-381 via the
blstcrate (min-sig variant) BlsSignertrait (tn_types::crypto):request_signature_direct(&self, msg)(sync,
runs on blocking thread pool) and request_signature(&self, msg) (async wrapper). Also: public_key(&self) -> BlsPublicKey.
IntentMessagewrapping: ALL signatures signIntentMessage { intent, value }--
never raw data. The intent includes IntentScope, IntentVersion, and AppId to prevent cross-domain replay.
- Intent scopes:
ProofOfPossession,EpochBoundary,ConsensusDigest,SystemMessage - Proof of Possession: validators prove key ownership when joining the committee
- secp256k1: used for Ethereum-compatible signing (validator rewards, etc.)
- blake3: used for hashing in some contexts
Determinism rules
These are consensus-critical. Violations cause chain splits.
- No
HashMap/HashSetin consensus paths -- iteration order is non-deterministic.
Use BTreeMap/BTreeSet or IndexMap (with consistent insertion order).
- No floating point in consensus calculations
- No
SystemTimefor consensus timestamps -- use the crate'snow()function
(tn_types::now) which returns TimestampSec
- BCS for canonical encoding -- it produces deterministic byte output for the same input
- No thread-dependent ordering in consensus logic
Storage
Database traits (tn_types::database_traits)
Database: top-level trait.Send + Sync + Clone + Unpin + 'static.
Methods: open_table, read_txn, write_txn, get, insert, remove, iter, skip_to, reverse_iter, last_record, compact, persist.
DbTx: read transaction.get,contains_key.DbTxMut: write transaction (extendsDbTx).insert,remove,clear_table,commit.Tabletrait:Key: KeyT,Value: ValueT,const NAME,const HINT: TableHint.KeyT/ValueT:Serialize + DeserializeOwned + Send + Sync + Clone + Debug + 'static
(KeyT also requires Ord).
TableHint
TableHint::Epoch-- cleared/recycled at epoch boundariesTableHint::Kad-- kademlia DHT records, persisted across epochsTableHint::Cache-- temporary cache data, can be cleared
tables! macro (crates/storage/src/lib.rs)
Generates table structs implementing the Table trait:
tables!(
Certificates;CERTIFICATES_CF;TableHint::Epoch;,
Payload;PAYLOAD_CF;TableHint::Epoch;
);
Dual backend
- redb: default persistent backend for consensus data
- mdbx: optional via
reth-libmdbxfeature flag CompositeDatabasecomposes backends based onTableHintMemDatabase: in-memory implementation for tests
Networking
libp2p (v0.56)
The TNBehavior struct composes sub-behaviors using #[derive(NetworkBehaviour)]:
struct TNBehavior {
peer_manager: PeerManager, // MUST be first -- ban enforcement
gossipsub: gossipsub::Behaviour,
req_res: request_response::Behaviour,
kademlia: kad::Behaviour>,
stream: StreamBehavior,
}
Field order matters: NetworkBehaviour derive calls handle_established_*_connection in declaration order, short-circuiting on ConnectionDenied. peer_manager first means banned peers are rejected before other behaviors register them.
NetworkHandle / NetworkCommand
Command pattern: components send NetworkCommand variants through NetworkHandle (wraps an mpsc::Sender). The network event loop processes commands and emits NetworkEvents.
Wire format
BCS serialization + Snappy compression via TNCodec. Messages implement the TNMessage trait (adds peer_exchange_msg() interception at the network layer).
Testing
Conventions
- proptest files: named
*_props.rs(e.g.,consensus_props.rs,economics_props.rs) - Unit test modules: inline
#[cfg(test)] mod test { ... }or via#[path]attribute:
``rust #[cfg(test)] #[path = "tests/proposer_tests.rs"] mod proposer_tests; ``
- Integration tests: in
crates/*/tests/it/directories CommitteeFixture: builder pattern for test committees. Fromtn-test-utils-committee:
``rust let fixture = CommitteeFixture::builder(MemDatabase::default).randomize_ports(true).build(); ``
test-utilsfeature flag: crates expose test helpers behind[features] test-utils = [].
Dev-dependencies enable this: tn-types = { workspace = true, features = ["test-utils"] }.
- Unused test deps: suppress
unused_crate_dependencieswarnings withuse crate_name as _;
at the crate root under #[cfg(test)]: ``rust #[cfg(test)] use tn_test_utils as _; ``
MemDatabase: in-memory DB for tests, avoids filesystemtempfile: for tests needing real file paths
Test commands
cargo nextest run --workspace --no-fail-fast # all unit tests
cargo nextest run -p tn-primary --no-fail-fast # single crate
cargo nextest run -p e2e-tests --run-ignored ignored-only --all-features # e2e
Code style
rustfmt.toml
imports_granularity = "Crate"-- merge imports per crateuse_field_init_shorthand = true--Foo { name }notFoo { name: name }reorder_imports = true-- alphabeticalwrap_comments = true,comment_width = 100use_small_heuristics = "Max"
Tracing
Use string targets prefixed with tn:::
tracing::info!(target: "tn::consensus", round, "proposing header");
tracing::error!(target: "tn::tasks", "task failed: {err}");
tracing::warn!(target: "tn::network", peer_id = %id, "peer misbehaved");
tracing::debug!(target: "tn::execution", ?block_hash, "executing block");
Common targets: tn::tasks, tn::consensus, tn::execution, tn::network, tn::reth, tn::config, tn::observer, tn::generate_keys, tn::storage.
Documentation
- Add
//!module-level docs to every file - Use
///for public items (workspace lint warns on missing) - Doc comments on error variants in thiserror enums
Imports
- Group: std, external crates, workspace crates (tn_*), crate-local
- Use
crate::imports granularity within the crate - Avoid glob imports except in
mod testsblocks and re-exports
Code Formatting
Run make fmt after writing or modifying code. Do not present code as complete without formatting.
Type Ordering in Files
Follow this strict ordering convention:
useimports- The file's primary type (matching the filename) — struct/enum + impl blocks
- Public auxiliary types that support the primary type
- Public traits related to the primary type
- Private helper types
- Private helper functions
Never add new types or traits above the file's primary type.
Doc Comments
Write doc comments for the intended audience of code maintainers and security researchers. Use proper punctuation, complete sentences, and natural human writing style.
- Every public type, trait, and function must have a doc comment
- Start with a concise summary line
- Add detail paragraphs for complex behavior, constraints, safety requirements
- Document panics, errors, and safety invariants
- Use
///for item docs,//!for module docs
Example:
/// Validates a block's transaction list against consensus rules.
///
/// Returns an error if any transaction violates the current fork's
/// gas limits or signature requirements. Empty transaction lists
/// are valid per EIP-1559.
pub fn validate_transactions(block: &Block) -> Result
Code Comments
Write concise code comments in all lowercase letters. Comments must remain valuable after the PR is merged — future readers only see the current code, not PR context.
Comment when:
- Non-obvious behavior or edge cases
- Performance trade-offs
- Safety requirements (unsafe blocks must always be documented)
- Limitations or gotchas
- Why simpler alternatives don't work
- Constraints and assumptions
Don't comment when:
- Code is self-explanatory
- Just restating the code in English
- Describing what changed (PR context)
- Stating the obvious
Comment style:
// hashmap provides o(1) symbol lookups during trace replay
// timeout set to 5s to match evm block processing limits
// we reset limits at task start because tokio reuses
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [grantkee](https://github.com/grantkee)
- **Source:** [grantkee/claude-extensions](https://github.com/grantkee/claude-extensions)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.