# PoScan Pallet Object States: Complete Guide to the 3DPass Object Lifecycle

> Explore the PoScan pallet's 9 object states guiding 3D object verification from creation to self-proof on the 3DPass blockchain. Understand the complete object lifecycle.

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

---

**The PoScan pallet defines nine distinct object states—from `Created` to `SelfProved`—that manage 3D object verification through quality control, validator estimation, and consensus approval on the 3DPass blockchain.**

The 3DPass blockchain utilizes the PoScan pallet to establish a rigorous on-chain lifecycle for physical 3D objects. Understanding these **PoScan pallet object states** is critical for developers integrating with the `3dpass/3dp` repository, as each variant in the `ObjectState` enum represents a specific validation checkpoint tracked across the network.

## The Nine Object States in the PoScan Pallet

The core state machine is defined in [`primitives/consensus/poscan/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/primitives/consensus/poscan/src/lib.rs) (lines 59-76) as a generic Rust enum that tracks block numbers and inspector accounts. Each variant represents a distinct phase in the object's verification journey:

```rust
pub enum ObjectState<Block, Account>
where
    Block: Encode + Decode + TypeInfo + Member,
    Account: Encode + Decode + TypeInfo + Member,
{
    Created(Block),
    QCInspecting(Account, Block),
    QCPassed(Account, Block),
    QCRejected(Account, Block),
    Estimating(Block),
    Estimated(Block, u64),
    NotApproved(Block),
    Approved(Block),
    SelfProved(Block),
}

```

### Initial Submission and Quality Control

- **`Created(Block)`** — Marks the initial submission when an object is first recorded on-chain at the specified block height.
- **`QCInspecting(Account, Block)`** — Indicates the object is under **quality-control inspection** by the specified inspector account, with the block marking when inspection began.
- **`QCPassed(Account, Block)`** — Signifies the inspector has **approved** the object, recording the approval block.
- **`QCRejected(Account, Block)`** — Records when an inspector has **rejected** the object, capturing the rejection block for accountability.

### Validator Estimation Phase

- **`Estimating(Block)`** — The object awaits **estimation** of verification time or other metrics from network validators.
- **`Estimated(Block, u64)`** — Estimation is complete. The first block indicates when estimation finished, while the `u64` holds the calculated average time in a concise numeric format.

### Final Resolution States

- **`NotApproved(Block)`** — A terminal failure state indicating the object **failed** to obtain required approvals due to estimation timeout, QC timeout, or explicit rejection.
- **`Approved(Block)`** — The object has met **consensus criteria** and is officially approved for the network.
- **`SelfProved(Block)`** — Reserved for **self-proved replicas** where proof-of-existence is submitted directly. This is a terminal state distinct from the standard approval flow.

## State Transitions During Block Initialization

State advancement is handled by the pallet's runtime logic in [`pallets/poscan/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/pallets/poscan/src/lib.rs) within the `on_initialize` hook (see lines 31-74). The function matches `obj_data.state` to enforce valid transitions:

- **`Created → Estimating`** occurs immediately upon initialization.
- **`Estimating → Estimated`** triggers when sufficient validator estimations are collected; otherwise transitions to `NotApproved` on timeout.
- **`Estimated → NotApproved`** occurs if the approval period expires before consensus is reached.
- **`QCInspecting → NotApproved`** on QC timeout, or to **`QCPassed`**/`QCRejected`** based on the inspector's decision.
- **`QCPassed → SelfProved`** if the object represents a self-proved replica; otherwise, the object returns to `Created` for additional processing.

## Querying Object States via RPC

External applications can retrieve current object states through the PoScan RPC interface defined in [`nodes/poscan-consensus/src/poscan_rpc.rs`](https://github.com/3dpass/3dp/blob/main/nodes/poscan-consensus/src/poscan_rpc.rs). The runtime API exposes `get_poscan_object` which returns `Option<ObjData<…>>` containing the current state variant:

```rust
let obj_opt = client
    .runtime_api()
    .get_poscan_object(&BlockId::Hash(best_hash), obj_idx);
if let Ok(Some(obj)) = obj_opt {
    println!("Object state: {:?}", obj.state);
}

```

For external tooling and precompiled contract interactions, [`precompiles/poscan/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/precompiles/poscan/src/lib.rs) provides helper functions mapping these enum variants to numeric codes.

## Summary

- The **PoScan pallet** manages object verification through nine discrete states defined in [`primitives/consensus/poscan/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/primitives/consensus/poscan/src/lib.rs).
- **Quality control states** (`QCInspecting`, `QCPassed`, `QCRejected`) track inspector accountability via associated `Account` parameters.
- **Validator estimation** progresses from `Estimating` to `Estimated`, capturing timing data as a `u64`.
- **Terminal states** include `Approved` for consensus-backed objects, `SelfProved` for proof-of-existence replicas, and `NotApproved` for failed validations.
- State transitions execute automatically during `on_initialize` in [`pallets/poscan/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/pallets/poscan/src/lib.rs), enforcing protocol rules without manual intervention.

## Frequently Asked Questions

### What triggers the transition from `Estimating` to `Estimated`?

The transition occurs when the pallet's `on_initialize` function detects that enough validator estimations have been collected for the object. According to the implementation in [`pallets/poscan/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/pallets/poscan/src/lib.rs), validators submit time estimates during the estimation window, and once the threshold is met, the state advances to `Estimated(Block, u64)` where the `u64` stores the calculated average verification time.

### What is the difference between `QCPassed` and `Approved` states?

`QCPassed(Account, Block)` indicates that an individual quality-control inspector has approved the object, representing a single checkpoint in the workflow. `Approved(Block)` signifies that the object has met **consensus criteria** across the entire validator set, representing the final acceptance of the object into the 3DPass ecosystem. An object typically passes through `QCPassed` before reaching the final `Approved` state.

### How can developers query the current state of a PoScan object programmatically?

Developers should use the PoScan RPC methods exposed in [`nodes/poscan-consensus/src/poscan_rpc.rs`](https://github.com/3dpass/3dp/blob/main/nodes/poscan-consensus/src/poscan_rpc.rs). The `get_poscan_object` runtime API accepts a block hash and object index, returning an `Option<ObjData>` structure where the `state` field contains the current `ObjectState` variant. For Solidity integrations, the precompile contract in [`precompiles/poscan/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/precompiles/poscan/src/lib.rs) exposes these states as numeric codes.

### What happens to objects that reach the `QCRejected` state?

Objects in the `QCRejected(Account, Block)` state have been explicitly rejected by the assigned quality-control inspector. According to the state transition logic in the PoScan pallet, rejected objects do not return to `Created` for immediate reprocessing. Instead, they typically proceed to `NotApproved(Block)` if no further action is taken, effectively removing them from the active verification pipeline unless a new submission is initiated.