What is Type Id

Type Id is a digest of a unique type script.

The unique type script consists of three parts:

1
2
3
code_hash: type id contract code hash
hash_type: type # use the `type` kind code hash for upgradability
args: hash(this_transaction.inputs[0]) | output_index_of_this_cell

The uniqueness of the generated type script is guaranteed by the type id contract and hash(this_transaction.input[0]) | output_index_of_this_cell since

No man ever steps in the same river twice, for it’s not the same river and he’s not the same man.

The type id contract checks if the unique_type_script.args matches the deployment_transaction.inputs[0]. Once it’s deployed on the chain successfully, the deployment_transaction.inputs[0] cannot be used to deploy the same unique type script again since it’s comsumed, like the water gone, i.e. the unique_type_script.args cannot be used to deploy again and the uniqueness of the unique type script is promised.

Why Type Id is Important

The contract cell, i.e. the cell dep referenced in a transaction, is upgradable when it’s located via its type script. By deploying a new cell with new contract code but having the same type script as the deprecated one, it can be indexed by the same [code_hash, hash_type] conditions.

graph LR
  id1[code_hash: hash_a, hash_type: type]-->|OutPoint of Deprecated Cell|id2[Deprecated Contract]
  id1[code_hash: hash_a, hash_type: type]-->|OutPoint of Latest Deployed Cell|id3[Latest Deploayed Contract]

By this way, an attacker can deploy a malicious contract with the same type script of the targeted contract to bypass script validation and confuse users.

graph LR
  id1[code_hash: hash_a, hash_type: type]-->|OutPoint of Deprecated Cell|id2[Deprecated Contract]
  id1[code_hash: hash_a, hash_type: type]-->|OutPoint of Latest Deployed Cell|id3[Latest Deploayed Contract]
  id1[code_hash: hash_a, hash_type: type]-->|OutPoint of Malicious Cell|id3[Malicious Contract]

An exclusive type script is necessary in this mode.

How to Create a Unique Type Script

There are 4 rules to deploy an unique type script(with unique args)

  1. Count how many output cells use current type script, if there’re more than one cell with current type script, throw an error since an attacker is trying to create more than one cells with the same type script, which is not expected.

  2. Count how many input cells use current type script, if there’s only one input cell with the current type script, return success.

  3. Use CKB Syscall to read the first input’s OutPoint in the current transaction and if it matches the args field of the type script, return success.

    • Since the first input can only be comsumed once, its unique OutPoint guarantees the uniqueness of the type script.
    • An attacker cannot use the same args to deploy the type script since the unique cell has been consumed.
  4. Otherwise throw an error.

Get Unique Type Id

Simply hash the type script

1
hash([codeHash, hashType, args]) | output_index

Resolve Scripts in CKB Transaction via Type Id

Since Type Script is used, the contract depends on it has hash type = type.

In this case, the ckb vm loops all cell deps and try to find a dep whose type script has the corresponding hash(type script).

Once a cell dep meeting the condition is found, it’s used as the dependency of the contract.

Appendix

The type id contract can be implemented in CKB VM, but now it exists in CKB node as a system script and can be referenced by a special code hash, ascii code in hex of the text TYPE_ID

1
0x00000000000000000000000000000000000000000000000000545950455f4944