Regulation Compliance Extension
Regulation Compliance Extension (RCE) is an xUDT extension that enhance UDT with regulation compliance capabilities. It provides the following features:
- Transfer Whitelist
- Transfer Blacklist
- Emergency Halt
- PKI Style Regulation Agency Support
While the RCE script itself implements only the above features, an accompanying Administrator Lock script provides following additional features:
- Multiple Administrators
It is up to the regulators to decide if the accompanying RCE-lock script shall be used.
Regulation Compliance Extension (RCE) script
A RCE script has the following structure:
Code hash: RCE script code hash
Hash type: RCE script hash type
Args: <type ID args for RCE cell>
A RCE script, as shown above, only contains the type ID args used by a special RCE Cell. The RCE Cell holds a molecule serialized RCData structure described below in its cell data part:
array Byte32 [byte; 32];
array Uint128 [byte; 16];
struct RCRule { // RC stands for Regulation Compliance
smt_root: Byte32,
flags: byte,
}
vector RCCellVec <Byte32>;
union RCData {
RCRule,
RCCellVec,
}
Each RCRule
structure can either represents a blacklist SMT tree, or a whitelist SMT tree. If flags & 0x2 == 1
, it means smt_root
is used as a whitelist, otherwise it is used as a blacklist.
If flags & 0x1 == 0x1
, the current RCRule
is put in Emergency Halt mode.
From this we can see, the cell data of a RCE cell, can be any of the following formats:
- A normal RCRule structure. When executing, the RCE script would load data from the RCE cell denoted by type ID args, and enforce the following checking:
- If current
RCRule
uses whitelist, all the lock script hashes of xUDT cells in current transaction, must be present in the whitelist SMT tree. The details on how SMT works, will be explained below. - If current
RCRule
uses blacklist, none of the lock script hashes of xUDT cells in current transaction, can be present in the blacklist SMT tree. - Current
RCRule
must not be in Emergency Halt mode.
- If current
- A
RCCellVec
structure works in slightly different rules:- First, a nested
RCCellVec
structure is flattened as a plain array containing onlyRCRule
structure. For simplicity, we will add a limitation, so that any RCE cell can contain at most 8192RCRule
structures. Any moreRCRule
structures will result in an immediate failure. - None of the lock script hash used by current xUDT cells in current transaction, can be found in any of the SMT trees in
RCRule
structures using blacklists. - As long as any of the
RCRule
structure uses whitelists, all the lock script hashes used by current xUDT cells in current transaction, must be found in the SMT tree of at least oneRCRule
structure using whitelists, which is not in Emergency Halt mode.
- First, a nested
SMT
RCE scripts leverage optimized sparse merkle tree(SMT) extensively to reduce storage costs. For each sparse merkle tree used here, the key will be lock script hash, values are either 0 or 1: 0 represents the corresponding lock hash is missing in the sparse merkle tree, whereas 1 means the lock hash is included in the sparse merkle tree.
Generators will need to attach proofs of SMT for certain keys in transaction’s witness, so as to prove the following properties:
- A lock hash is included in the whitelist SMT
- A lock hash is not included in the blacklist SMT
See the next sections for real examples.
Operations
Transfer
Here is an example of a transfer operation with RCE whitelist enabled:
CellDeps:
<vec> RCE cell
Inputs:
<vec> xUDT_Cell
Data:
<amount: uint128> <xudt data>
Type:
code_hash: extensible_udt type script
args: <owner lock script hash> <xudt args for RCE script>
Lock:
<user defined lock 1>
<...>
Outputs:
<vec> xUDT_Cell
Data:
<amount: uint128> <xudt data>
Type:
code_hash: extensible_udt type script
args: <owner lock script hash> <xudt args for RCE script>
Lock:
<user defined lock 2>
<...>
Witnesses:
WitnessArgs structure:
Lock: <user defined>
Input Type:
<vec> Bytes structure:
<proof length>
<proof that lock 1 & 2 are both mapped to 1 in SMT>
<...>
The proof of an SMT given certain keys, is just a series of raw bytes generated by the SMT library. See here for some examples.
Update Whitelist SMT in RCE cell
Inputs:
<vec> RCE Cell
Data:
RCRule:
<old smt root>
<flags>
Type:
<type id type script>
Lock:
<user defined lock>
<...>
Outputs:
<vec> RCE Cell
Data:
RCRule:
<new smt root>
<flags>
Type:
<type id type script>
Lock:
<user defined lock>
<...>
Witnesses:
WitnessArgs structure:
Lock: <user defined>
Input Type:
<vec> Bytes structure:
<number of updated keys>
<updated key 1> <updated value 1> <old value 1>
<updated key 2> <updated value 2> <old value 2>
<...>
<proof length>
<proof for the updated keys in the old SMT>
<...>
The SMT validation flow works like following:
- Using the given proof, we first test the updated keys and provided old values are correct given the old SMT root hash.
- Now we use the given proof, we test that using the updated keys and updated values, the new SMT root hash could be calculated.
An example for this flow can be found here. Notice this workflow has already been tested and used in the v1 version of polyjuice, as well as current version of godwoken.