-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Design Store
model
#2
Comments
A rough to-do list of
We can talk a bit more about details and I'll enrich the to-do list along with the discussion. @janx @homura @felicityin @yanguoyu |
Define cell storage struct to gather by the specific pattern. |
Does this mean how to match a pattern with a given cell storage struct? Take the issues in GitHub as an example If we are building an issue system on-chain and every issue is stored as a cell, it would be structured as
While we can filter cells/issues out by a pattern as Would the question be |
Yeah, on the other hand, how to store this information on the chain? Or how to transform these data to bytecode and store them in the cell? |
That's the detail we're going to confirm in this issue. |
I have designed something about
type StorageLoc = 'data' | 'witness'
type OneOfStorageLoc<T> = { data: T; witness?: T } | { data?: T; witness: T }
type StorageOffChain = OneOfStorageLoc<any>
type StorageOnChain = OneOfStorageLoc<Uint8Array>
type StorageOffset = Partial<Record<StorageLoc, number>>
abstract class Storage<T extends StorageOffChain> {
abstract serialize(data: T): StorageOnChain
abstract deserialize(data: StorageOnChain): T
}
class JSONStorage<T extends StorageOffChain> extends Storage<T> {
serialize(data: T): StorageOnChain {
return {
data: data.data ? Buffer.from(JSON.stringify(data.data)) : undefined,
witness: data.witness ? Buffer.from(JSON.stringify(data.witness)) : undefined,
}
}
deserialize(data: StorageOnChain): T {
const dataStr = data?.data?.toString()
const witnessStr = data?.witness?.toString()
return {
data: dataStr ? JSON.parse(dataStr) : undefined,
witness: witnessStr ? JSON.parse(witnessStr) : undefined,
} as T
}
} Make assume, a Dapp's scheme is unique. Then we can transfer it to kuai as a parameter. declare function hexToBytes(rawhex: string | number | bigint): Uint8Array
class App<T extends StorageOffChain> {
storageInstance: Storage<T>
offset: StorageOffset
constructor(type: Storage<T> = new JSONStorage<T>(), offset?: StorageOffset) {
this.storageInstance = type
this.offset = offset
}
sync(tx: CKBComponents.Transaction) {
//Get State from tx by S and transfter State to Store by message
const data = tx.outputsData
const witness = tx.witnesses
for (let i = 0; i < data.length; i++) {
const item = data[i];
// contract data and witness
const curData = data[i].slice(this.offset.data || 0)
const curWitmess = witness[i].slice(this.offset.witness || 0)
const dataOffChain = this.storageInstance.deserialize({
data: hexToBytes(curData),
witness: hexToBytes(curWitmess)
})
// send message to actors to sync data
}
}
} Then Dapp developers can transfer schema like this: type BitSchema = {
'data': {
name: string
version: string
},
'witness': {
domain: {
name: string
createTime: string
count: number
value: BigInt
}
}
}
const app = new App<BitSchema>()
app.start() They can also define customer Storage class Molecule<T extends StorageOffChain> extends Storage<T> {
serialize(data: T): StorageOnChain {
return {
data: new Uint8Array(),
witness: new Uint8Array(),
}
}
deserialize(data: StorageOnChain): T {
return {} as T
}
}
const moleculeApp = new App<BitSchema>(new Molecule())
export interface PatternItem {
field: string
match: {
op: 'eq' | 'lt' | 'gt' | 'lte' | 'gte' | 'in'
value: any
} | RegExp
}
export type Pattern = {
aggregate: 'OR' | 'AND'
patterns: PatternItem[]
}[] | PatternItem I can define a pattern to match [
{
aggregate: 'or',
patterns: [
{
field: 'data.domain',
match: {
op: 'in',
value: 'AAAAA'
}
},
{
field: 'data.domain',
match: {
op: 'in',
value: 'BBBBB'
}
}
]
}
] Or simply define a pattern {
field: 'data.domain',
match: {
op: 'in',
value: new RegExp('^(A|B){5}$')
}
}
export class Store<S extends State = State, M extends Message = Message> extends Actor {
pattern: Pattern;
protected states: Record<OutPointString, S> = {}
private messageList: M[] = []
constructor(pattern: Pattern) {
super()
this.pattern = pattern
}
// sync from tx or database
private addState(addStates: Record<OutPointString, S>) {
this.states = {
...this.states,
...addStates
}
}
// sync from tx
private removeState(keys: OutPointString[]) {
keys.forEach(key => {
delete this.states[key]
})
}
duplicate() {
const store = new Store(this.pattern)
// copy states and messages
return store
}
handle(message: M) {
switch (message.type) {
case 'add-state':
// if match pattern
this.addState(message.data)
break;
case 'remove-state':
// if match pattern
this.removeState(message.data)
break;
default:
break;
}
}
get(path: StataPath) {
if (path.path) {
return this.states[path.key][path.path]
}
return this.states[path.key]
}
set(path: StataPath, value: any) {
if (path.path) {
this.states[path.key][path.path] = value
}
this.states[path.key] = value
}
remove(path: StataPath) {
if (path.path) {
delete this.states[path.key][path.path]
}
delete this.states[path.key]
}
finalize() {
this.messageList.forEach(message => {
this.handle(message)
})
return this.states;
}
} |
|
It's a good suggestion, I will update it later.
I think we should make the const bitSchema: Schema[] = [
{
name: 'string',
version: 'string',
[loc]: 'data',
domain: {
[loc]: 'witness',
name: 'string',
createTime: 'string',
}
}
]
It should sync from a block, I just described how it will deserialize from a transaction. |
I see the design was updated 2 days ago, is it ready for review again? |
Yeah, I have updated the serialization of storage. |
Store
modelStore
modelStore
model from plain cells with the same dataThe text was updated successfully, but these errors were encountered: