The current Cobuild-OTX can only determine Input_cells, output_cells, cell_deps, and header_deps to be covered by the hash of OTX, without the ability to control more finely, such as excluding output_data from an output. This limitation constrains the flexibility in designing applications with OTX. Previously, Xuejie designed a more complex OTX RFC: Composable Open Transaction Lock Script that could control the signature coverage range more finely, but it had security issues in some cases, so the plan was changed to the current solution.
However, based on the current Cobuild-OTX scheme, is it possible to make some minor modifications to support fine-grained control?
First, we need to analyze which parts can be controlled more finely. Cell_deps and header_deps do not need this because they only have a fixed single attribute.
For inputs and outputs, however, fine-grained control is possible.
For inputs, there are two attributes to adjust: since, outpoint. This can be expressed with 2 bits. Given that input_cells are the number of inputs, only input_cells * 2 bits are needed to finely control the range covered by each input’s signature in the signature. For example, the first bit represents since, when it is 0, it covers since, and when it is 1, it does not cover since. Similarly, the second bit represents the outpoint. When this flag is set to 11, it effectively applies no constraints to the input. However, since the final signature verification requires unlocking the lock, it implicitly imposes a constraint on the lock.
For Outputs, there are four attributes to adjust: lock, type, capacity, output_data. A set with four elements has 16 subsets, excluding the empty set leaves 15, which can be expressed with 4 bits for each output’s coverage range. Once the mapping relationship is determined, for example, the first bit represents lock, when it is 0, it covers lock, and when it is 1, it does not cover lock. Similarly, the second bit represents type, the third bit represents capacity, and the fourth represents output_data. According to this rule, 0000 represents full signature, 0001 means not signing output_data, 1000 means not signing lock, 1010 means not signing lock and capacity, 1111 means covering nothing, but an output placeholder is needed in the corresponding position. Therefore, only the number of outputs multiplied by 4 bits is needed to achieve fine-grained control, for example, for 20 outputs, only 10 bytes of data are needed to constrain.
We supplement the data structures in CKB Open Transaction (OTX) CoBuild Protocol Overview with the following changes:
// A full CKB Transaction can only contain one OtxStart structure, denoting the
// start for Otxs in the CKB Transaction. The include 4 fields here mark
// the starting indices of input cells, output cells, cell deps and header deps
// that belong to an Otx. There is no need to mark the starting index for Otx
// witnesses, since OtxStart itself already decides the starting index for Otx
// related witnesses.
//
// Several Otx structure would follow OtxStart structure in the witnesses array,
// each denoting a different Otx packed in current CKB Transaction.
table OtxStart {
start_input_cell: Uint32,
start_output_cell: Uint32,
start_cell_deps: Uint32,
start_header_deps: Uint32,
}
table SealPair {
script_hash: Byte32,
seal: ByteVec,
}
vector Seals <SealPair>;
// Otx structure denotes an Otx included in the Transaction, each Otx has exactly
// one Otx structure in the witnesses array. The index of a particular Otx witness
// in the witnesses array, has nothing to do with the indices of input / output
// cells that belong to this particular Otx.
table Otx {
// Assuming an Otx has 3 input cells, those 3 input cells might choose to use
// different lock scripts, signed by different signature verfication algorithms.
// Following the above discussion, an Otx has a single Otx witness structure.
// We need a way here to keep multiple signatures for different lock scripts
// in a single witness.
// This is why seals is designed in the way it is, each SealPair in Seals
// resembles Action in the CoBuild message definition. We use script_hash
// included in SealPair to distinguish among different lock scripts. A lock
// script will first find a SealPair whose script_hash matches its own lock
// script hash, then exact the seal field from the correct SealPair, which
// might contain the actual signature.
seals: Seals,
// input_cells is an integer number representing the number of input cells
// belonging to current Otx.
// output_cells / cell_deps / header_deps function in similar way.
// input_flags is an byteVec representing which attributes should be covered
// output_flags function in similar way.
input_cells: Uint32,
input_flags: ByteVec,
output_cells: Uint32,
output_flags: ByteVec,
cell_deps: Uint32,
header_deps: Uint32,
message: Message,
}
Supplementary content, for cell_deps and header_deps, we can use 1bit for each item for fine-grained control. When it is 0, it means that the signature covers this attribute. When it is 1, it means that the signature does not cover this attribute and only verifies the placeholder. .