# How Does the Proof of Scan Consensus Mechanism Work in 3DPass?

> Discover how 3DPass uses Proof of Scan PoScan consensus combining PoW mining with 3D object validation for secure network operations.

- Repository: [3Dpass/3dp](https://github.com/3dpass/3dp)
- Tags: how-to-guide
- Published: 2026-02-23

---

**The Proof of Scan (PoScan) consensus mechanism in 3DPass combines Proof-of-Work mining with scan-based 3D object validation, requiring miners to compute valid object hashes using the PoscanAlgorithm, seal blocks with cryptographic proofs meeting network difficulty targets, and submit them through the PowBlockImport for runtime verification and finalization.**

The 3DPass blockchain utilizes the **Proof of Scan consensus mechanism** to secure its ledger while incentivizing the creation and validation of unique 3D digital assets. Implemented as a Substrate-based consensus module, this mechanism ties block production to the computational verification of 3D objects stored on-chain. Unlike traditional Proof of Work, PoScan requires miners to demonstrate both computational work and successful object scanning to produce valid blocks.

## Core Architecture of Proof of Scan

The PoScan engine orchestrates several specialized components that bridge the node service layer with the runtime.

**POSCAN Primitives** define the consensus engine identifiers and data structures in [`primitives/consensus/poscan/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/primitives/consensus/poscan/src/lib.rs). This module declares constants like `POSCAN_ENGINE_ID`, algorithm versions including `POSCAN_ALGO_GRID2D_V3A` and `POSCAN_ALGO_GRID2D_V3_1`, and the `PoscanApi` trait for runtime communication.

**The PoScan Algorithm** ([`consensus/poscan_algo/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/consensus/poscan_algo/src/lib.rs)) implements `get_obj_hashes`, which transforms 3D object data into deterministic hash sets using the Grid2D algorithm. It manages RandomX rotation for newer consensus versions and provides the `DoubleHash` struct for combining parent hashes with object hashes.

**Mining Worker** logic resides in [`nodes/poscan-consensus/src/service.rs`](https://github.com/3dpass/3dp/blob/main/nodes/poscan-consensus/src/service.rs), where `start_mining_worker` spawns the asynchronous thread responsible for fetching metadata, computing seals, and submitting valid blocks.

**PowBlockImport** bridges PoScan seals with Substrate's block import pipeline, verifying difficulty and signatures before forwarding to Grandpa finality.

**Pallet Poscan** ([`pallets/poscan/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/pallets/poscan/src/lib.rs)) maintains the on-chain object state machine, quality control transitions, and reward distribution.

## The Mining Loop and Block Production

The mining process begins when the service layer initializes the worker thread in [`nodes/poscan-consensus/src/service.rs`](https://github.com/3dpass/3dp/blob/main/nodes/poscan-consensus/src/service.rs).

### Service Initialization

The node bootstraps the consensus engine by creating a `PoscanAlgorithm` instance and passing it to `start_mining_worker`:

```rust
let (worker, worker_task) = sc_consensus_poscan::start_mining_worker(
    Box::new(pow_block_import),
    client.clone(),
    select_chain,
    PoscanAlgorithm::new(client.clone()),
    proposer,
    network.clone(),
    network.clone(),
    Some(author.encode()),
    CreateInherentDataProviders { author: Some(author.encode()) },
    Duration::from_secs(10),
    Duration::from_secs(10),
    can_author_with,
);

```

This returns a worker handle for block submission and a task handle for the mining thread.

### Hash Computation and Sealing

Inside the mining loop, the worker retrieves pending objects from the mining pool or deque, then computes hashes based on the current chain specification version. When the block number exceeds `REJECT_OLD_ALGO_SINCE`, the system uses `POSCAN_ALGO_GRID2D_V3A` with RandomX rotation; otherwise it uses `POSCAN_ALGO_GRID2D_V3_1`.

For consensus version 2 (`CONS_V2_SPEC_VER`), the algorithm generates a rotation hash using RandomX and recomputes object hashes:

```rust
let rotation_hash = randomx(&buf)?;
let hashes = get_obj_hashes(mining_algo, &mp.pre_obj, &rotation_hash, patch_rot);

```

The miner constructs a `DoubleHash` from the pre-hash and first object hash, then calculates the PoScan hash using either `calc_hash` (legacy) or `calc_hash_randomx` (current). This feeds into `ComputeV2` (or `ComputeV1` for older blocks), which is signed with the miner's key pair to create the seal.

### Difficulty Verification and Submission

Before submission, the worker verifies that `hash_meets_difficulty(&seal.work, seal.difficulty)` returns true. Valid seals are encoded and submitted via `worker.submit`:

```rust
if hash_meets_difficulty(&seal.work, seal.difficulty) {
    futures::executor::block_on(
        worker.submit(seal.encode(), &psdata)
    );
}

```

## Runtime Validation and Block Import

Once submitted, the sealed block enters the `PowBlockImport` queue. The import process performs cryptographic verification before accepting the block into the chain.

The validation sequence in the runtime:
1. Decodes the seal and verifies the signature against the author's public key
2. Recomputes the PoScan hash using `DoubleHash` to confirm it matches the sealed value
3. Validates difficulty via `hash_meets_difficulty`
4. Calls `PoscanApi::check_object` to verify object existence and state
5. Forwards the block to Grandpa for finality

The runtime implementation in [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs) fulfills the `PoscanApi` and `DifficultyApi` traits, querying pallet-poscan for object metadata and current difficulty targets.

## Difficulty Adjustment and Object Lifecycle

### Retargeting Algorithm

PoScan implements a timestamp-based difficulty adjustment using parameters defined in the primitives:
- **Window**: `DIFFICULTY_ADJUST_WINDOW` (approximately 1 hour)
- **Dampening**: `DIFFICULTY_DAMP_FACTOR` and `CLAMP_FACTOR` prevent extreme fluctuations
- **Bounds**: `MIN_DIFFICULTY` and `MAX_DIFFICULTY` enforce network security limits

The runtime calculates the next target difficulty via `DifficultyApi::difficulty()`, which the mining worker queries through the metadata at each loop iteration.

### Object State Machine and Rewards

The **pallet-poscan** manages objects through a strict state machine: `Created` → `QCInspecting` → `QCPassed`/`QCRejected` → `Estimated` → `Approved` → `SelfProved`. State transitions trigger reward distributions (`author_rewards`, `est_rewards`) and fee processing.

Miners can participate individually or through pools using the `MiningPoolApi`, which provides pool-specific difficulty calculations and membership verification.

## Practical Implementation Examples

### Running a PoScan Node

Start a validator node with the consensus service:

```bash
cargo build --release -p poscan-consensus
./target/release/poscan-consensus \
    --chain poscan-dev \
    --author //Alice \
    --pruning archive \
    --validator

```

The `--author` flag specifies the miner's key for block signing.

### Submitting 3D Objects via RPC

Clients submit objects for scanning through the `poscan_putObject` RPC method defined in [`nodes/poscan-consensus/src/rpc.rs`](https://github.com/3dpass/3dp/blob/main/nodes/poscan-consensus/src/rpc.rs):

```rust
let obj_data: Vec<u8> = std::fs::read("model.obj.lzss").unwrap();
let _: () = client.request(
    "poscan_putObject",
    (AccountId32::from([0u8; 32]), obj_data, 0u8, false)
).await.unwrap();

```

This creates a `MiningProposal` that enters the worker's pending object deque.

### Runtime Seal Verification

The pallet validates seals using the same cryptographic primitives as the node:

```rust
fn validate_seal(seal: PoscanSeal, pre_hash: H256, difficulty: U256) -> DispatchResult {
    let compute = Compute::decode(&mut &seal[..])?;
    let dh = DoubleHash { pre_hash, obj_hash: compute.obj_hash };
    let expected = dh.calc_hash();
    ensure!(expected == compute.poscan_hash, Error::<T>::InvalidPoscanHash);
    ensure!(hash_meets_difficulty(&compute.work, difficulty), Error::<T>::DifficultyNotMet);
    Ok(())
}

```

## Summary

- The **Proof of Scan consensus mechanism** merges Proof-of-Work with 3D object validation, requiring miners to compute valid object hashes alongside cryptographic seals.
- Mining occurs in [`nodes/poscan-consensus/src/service.rs`](https://github.com/3dpass/3dp/blob/main/nodes/poscan-consensus/src/service.rs) through the `start_mining_worker` thread, which uses `PoscanAlgorithm` to generate hashes via `get_obj_hashes` in [`consensus/poscan_algo/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/consensus/poscan_algo/src/lib.rs).
- The system supports algorithm versioning (`POSCAN_ALGO_GRID2D_V3A` vs `POSCAN_ALGO_GRID2D_V3_1`) and consensus upgrades (`CONS_V2_SPEC_VER`) with RandomX rotation for enhanced security.
- Block validation relies on `PowBlockImport` and runtime APIs (`PoscanApi`, `DifficultyApi`) to verify seals, difficulty, and object integrity before Grandpa finalization.
- Difficulty retargets every `DIFFICULTY_ADJUST_WINDOW` using clamped dampening factors, while [`pallets/poscan/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/pallets/poscan/src/lib.rs) manages object states and miner rewards.

## Frequently Asked Questions

### What is Proof of Scan in 3DPass?

Proof of Scan (PoScan) is a hybrid consensus mechanism that requires miners to perform computational work while simultaneously validating unique 3D objects. It functions as a Substrate PoW module where block production depends on successfully scanning and hashing 3D geometric data according to the PoscanAlgorithm specifications.

### How does PoScan differ from traditional Proof of Work?

Traditional Proof of Work relies solely on hash rate to secure the network, whereas PoScan adds a **scan-based validation layer** where miners must possess valid 3D objects to create block seals. The `DoubleHash` structure combines block headers with object hashes, ensuring consensus participation requires both computational resources and digital asset ownership.

### What role do 3D objects play in the consensus process?

3D objects serve as the "work payload" for mining. Miners retrieve pending objects from the mining pool or deque, process them through `get_obj_hashes` to generate deterministic hash sets, and incorporate these into the `ComputeV1` or `ComputeV2` structures. The runtime verifies object integrity via `PoscanApi::check_object` before accepting blocks.

### How does the network adjust mining difficulty?

The runtime calculates difficulty using a timestamp-based retargeting algorithm with a `DIFFICULTY_ADJUST_WINDOW` of approximately one hour. The system applies `DIFFICULTY_DAMP_FACTOR` and `CLAMP_FACTOR` to smooth adjustments while respecting `MIN_DIFFICULTY` and `MAX_DIFFICULTY` bounds, ensuring consistent block times regardless of total network hash rate.