Skip to main content

Blockchain basics

A blockchain is a shared, append-only database that thousands of independent computers keep in agreement. Nobody can edit a past entry, and anyone can read every entry. Certichain uses an Ethereum-compatible chain as a public notice board: institutions post signed fingerprints of credentials, and verifiers read them back. This page explains the parts of Ethereum that the rest of the docs assume.

Accounts and keys​

Ethereum has two kinds of account.

KindControlled byHas codeCan sign a message
Externally owned account (EOA)A private key on the secp256k1 curve, usually held in a wallet such as MetaMaskNoYes, with the private key
Contract accountIts own code, deployed on chainYesNo private key; it can approve a signature through ERC-1271 (see Signatures)

An address is 20 bytes, written as 0x followed by 40 hex characters. For an EOA it is derived from the public key, so whoever holds the private key controls the address. A multisig wallet such as a Safe is a contract account whose code asks for approval from several EOAs.

In Certichain​

  • Issuers, holders and guardians are addresses. An issuer is an address the admin has registered with a name in the IssuerRegistry.
  • The admin on Sepolia is a Safe, a contract account with 2-of-3 owners.
  • The app tells the two kinds apart by asking the chain for code at the address (isContractAccount in src/services/credentials/credential-gateway.ts, which calls getCode). Some features need an EOA because they derive keys from deterministic signatures; a contract wallet gets a clear error instead, for example "This account is a contract wallet, which cannot protect documents yet. Use a plain wallet account."

Transactions and signatures​

A wallet can do two different things when the app asks, and the difference matters to users.

Wallet promptWhat happensCostVisible on chain
Signature requestThe wallet signs a message or typed data with the private key and hands the signature to the page.FreeNo, unless the page later submits it
TransactionThe wallet signs and broadcasts an instruction to the network, for example "call issue on the CredentialRegistry".Gas, paid in the chain's currencyYes, permanently

Many Certichain actions combine both: issuing a credential first asks for an EIP-712 signature over the credential fields and then a transaction that submits the fields and the signature to the registry.

Gas and fees​

Every transaction pays gas for the computation and storage it uses. A contract that loops over an unbounded list can become too expensive to call, so the v0.3 registries are written to do a constant amount of work per call (see Gas and limits). Reads (view functions) cost nothing when called through an RPC endpoint, because they are not mined into a block.

On Sepolia gas is paid in test ether, which has no value. Issuers still need some to send transactions; verifiers need none.

Blocks, time and ordering​

Transactions are grouped into blocks. Each block has a number and a timestamp (block.timestamp), set by the block producer within narrow rules. Contracts use the timestamp as "now".

In Certichain​

  • A credential's validUntil is compared with the block timestamp in StatusRegistry.isValid. The issue form sets validUntil to 0, which means "no expiry".
  • The access gate counts epochs as whole days since the Unix epoch from the block timestamp (EPOCH_SECONDS = 1 days in blockchain/contracts/zk/CertichainAccessGate.sol).
  • An invitation may not expire more than 30 days after the block that redeems it (MAX_INVITATION_TTL = 30 days in blockchain/contracts/v03/HolderRegistry.sol). The client offers at most 29 days to leave room for clock drift (src/lib/invitation.ts).

Events and logs​

A contract can emit events. They are stored in the transaction receipt as logs, which are cheap to write and cannot be read by other contracts, but any client can query them. Up to three event arguments can be indexed, which makes them filterable topics.

In Certichain​

Certichain has no application database. Lists such as "credentials I issued", "credentials issued to me" and "documents shared with me" are rebuilt by scanning logs:

  • src/services/indexing/log-scan.ts reads logs in windows of up to 20,000 blocks, halves the window down to 500 blocks when an endpoint refuses a range, retries a failed request three times with a growing delay starting at 500 ms, and caps one scan at 1,000 requests (DEFAULT_SCAN_OPTIONS).
  • Results are cached in the browser (src/services/indexing/browser-cache.ts, storage-scan-cache.ts).
  • The issuer's EIP-712 signature is carried in the CredentialSigned event rather than in contract storage, which keeps issuance cheaper; src/services/indexing/signature-lookup.ts finds it again.

See Reading the chain for the full indexing design.

Chain ids and networks​

Every Ethereum network has a chain id. Ethereum mainnet is 1; Sepolia, the public test network Certichain uses, is 11155111. A signature or a transaction made for one chain id is not valid on another, which stops a test-network signature from being replayed on mainnet.

In Certichain​

  • Every EIP-712 domain that names a contract includes the chain id and the contract address, so a credential signature is bound to one registry on one chain (src/lib/eip712.ts).
  • The app reads its expected network from NEXT_PUBLIC_NETWORK_ID. When the wallet is on a different chain, the service layer refuses writes and the page offers a network switch (see Wallet and network).
  • Contracts on Sepolia are listed in the deployment manifest src/contracts/v03/deployment.11155111.json (see Deployment manifest).

RPC endpoints​

A browser or a server does not talk to the blockchain directly. It sends JSON-RPC requests (eth_call, eth_getLogs, eth_sendRawTransaction and so on) to an RPC endpoint, a node run by the user, a provider such as Infura, or a public service.

In Certichain​

  • Reads in the browser go to the endpoints in NEXT_PUBLIC_RPC_URLS (or the single NEXT_PUBLIC_RPC_URL), so a verifier needs no wallet. Writes go through the wallet's own connection.
  • Server routes use RPC_URLS or RPC_URL.
  • src/lib/rpc/provider.ts wraps several endpoints in one failover provider: each call has an 8 second timeout (DEFAULT_RPC_TIMEOUT_MS), a failing endpoint rests for 30 seconds (DEFAULT_RPC_COOLDOWN_MS), and contract errors such as a revert are treated as answers and never retried on another endpoint.

Finality and reorganisations​

A transaction in the latest block can still be undone if the network briefly disagrees and settles on a different chain of blocks (a reorganisation). After enough blocks, or once the network marks a block finalized, the result is practically permanent.

In Certichain​

  • After sending a transaction, the app waits for its receipt with one confirmation (tx.wait() in src/services/contracts/tx.ts) and reads the emitted event to confirm, for example that the registry issued exactly the credential id the browser computed.
  • The log scanner treats the most recent 12 blocks as unsettled and scans them again on the next pass (reorgDepth: 12), so a cached list heals after a reorganisation.
  • Reads use the public RPC and can lag a just-mined change by a few seconds. The pages say so where it matters, for example after a revocation.

Smart contracts and immutability​

A smart contract is code deployed at an address. Its code cannot change after deployment. Some projects use proxy contracts to swap the code behind an address; Certichain does not. Instead it deploys a new contract set next to the old one and lets the app read every listed set, so credentials issued under an older set keep verifying (see Contract versions and sets).

Test networks​

A test network runs the same software as mainnet with valueless currency. Certichain is deployed only on Sepolia and uses synthetic data. Local development uses a Hardhat node on chain id 31337, which the end-to-end tests also start (see Local development).

Source files​

  • src/services/credentials/credential-gateway.ts (reads, writes, contract account check)
  • src/services/contracts/tx.ts (send and wait)
  • src/services/indexing/log-scan.ts, src/services/indexing/browser-cache.ts, src/services/indexing/signature-lookup.ts
  • src/lib/rpc/provider.ts, src/lib/rpc/env.ts
  • src/lib/chain.ts
  • blockchain/contracts/v03/StatusRegistry.sol, blockchain/contracts/v03/HolderRegistry.sol
  • blockchain/contracts/zk/CertichainAccessGate.sol

Tests​

  • src/lib/rpc/provider.test.ts, src/lib/rpc/env.test.ts
  • src/services/indexing/log-scan.test.ts, src/services/indexing/browser-cache.test.ts, src/services/indexing/storage-scan-cache.test.ts
  • src/lib/chain.test.ts
  • blockchain/test/v03/ExpiryBoundary.test.ts, blockchain/test/v03/BoundedWork.test.ts