ckb-js / kuai

A protocol and framework for building universal dapps on Nervos CKB
MIT License
22 stars 11 forks source link

Implement API service without business logic #89

Closed Keith-CY closed 1 year ago

Keith-CY commented 1 year ago

PRD: https://github.com/ckb-js/kuai/issues/54

PainterPuppets commented 1 year ago

https://github.com/ckb-js/kuai/issues/1#issuecomment-1280014575

Which directory should the api of a kuai project be placed in?

Keith-CY commented 1 year ago

#1 (comment)

Which directory should the api of a kuai project be placed in?

How about creating a private demo repo and link dependencies to local kuai project

PainterPuppets commented 1 year ago

#1 (comment) Which directory should the api of a kuai project be placed in?

How about creating a private demo repo and link dependencies to local kuai project

Ok, I thought kuai project template included the api, similar to nestjs

Keith-CY commented 1 year ago

#1 (comment) Which directory should the api of a kuai project be placed in?

How about creating a private demo repo and link dependencies to local kuai project

Ok, I thought kuai project template included the api, similar to nestjs

It would be better to provide a template of API service if we could.

The template could be added in kuai and initialize a project by kuai-cli linked locally

Keith-CY commented 1 year ago

#1 (comment) Which directory should the api of a kuai project be placed in?

How about creating a private demo repo and link dependencies to local kuai project

Ok, I thought kuai project template included the api, similar to nestjs

Would you add a backend template or create a new project from scratch temporarily? If one of them will be done by you, I will finish the UI part. Or you can take over the UI part and I'm going to work on the server part

PainterPuppets commented 1 year ago

Would you add a backend template or create a new project from scratch temporarily? If one of them will be done by you, I will finish the UI part. Or you can take over the UI part and I'm going to work on the server part

Ok, I'm adding the api part to the initial project template. I can follow the documentation to mock api input and output first, and then integrate the specific logic after the store part is done.

And other qustion, mvp project files should be placed where, a new repository?

Keith-CY commented 1 year ago

Would you add a backend template or create a new project from scratch temporarily? If one of them will be done by you, I will finish the UI part. Or you can take over the UI part and I'm going to work on the server part

Ok, I'm adding the api part to the initial project template. I can follow the documentation to mock api input and output first, and then integrate the specific logic after the store part is done.

And other qustion, mvp project files should be placed where, a new repository?

Opening a private repo in https://github.com/Magickbase/ is fine

Keith-CY commented 1 year ago

How is it going

PainterPuppets commented 1 year ago

The current api server side code is here: https://github.com/Magickbase/kuai-mvp-server run this projecy need link the local kuai package, the operating steps are written in readme.md

need review this peoject structure, if not problem , this structure will integrate to kuai init as project template

PainterPuppets commented 1 year ago

create a pull request: https://github.com/Magickbase/kuai-mvp-server/pull/1

Keith-CY commented 1 year ago

https://github.com/Magickbase/kuai-mvp-server/pull/1 has been approved by 2 reviewers and was merged into the main branch. Please add it in kuai as the backend template.

PainterPuppets commented 1 year ago

Will be pull request later

Keith-CY commented 1 year ago

After the template is ready in kuai, please add a directory named samples, and use the cli to create an mvp-dapp project in the directory, just as nest.js dis https://github.com/nestjs/nest/tree/master/sample @PainterPuppets

Once the mvp-dapp skeleton is ready, we should start the actual coding. I'd like to divide the job into 3 tasks from the perspective of MVC

  1. View:
    1. when claim, set, clear APIs are called, inputs and outputs will be returned from storage model, and should be transformed into a raw transaction to the front-end
    2. when read, load APIs are called, structured data should be returned to the front-end
  2. Controller: define the interface of APIs and parse arguments. The second function has been implemented by @kuai/io, so only function one should be considered. Mainly about the identity of requests cuz business logic is simple.
  3. Model: the storage model. The MVP dapp simply covers the preset methods, so only the schema should be implemented additionally.

Would you pick one up from tasks? @PainterPuppets @Daryl-L @yanguoyu

The tasks not picked will be arranged later(about 18:30 this day).

PainterPuppets commented 1 year ago

I will be doing the controller part, which is more related to kuai/io.

Daryl-L commented 1 year ago

After the template is ready in kuai, please add a directory named samples, and use the cli to create an mvp-dapp project in the directory, just as nest.js dis https://github.com/nestjs/nest/tree/master/sample @PainterPuppets

Once the mvp-dapp skeleton is ready, we should start the actual coding. I'd like to divide the job into 3 tasks from the perspective of MVC

  1. View:

    1. when claim, set, clear APIs are called, inputs and outputs will be returned from storage model, and should be transformed into a raw transaction to the front-end
    2. when read, load APIs are called, structured data should be returned to the front-end
  2. Controller: define the interface of APIs and parse arguments. The second function has been implemented by @kuai/io, so only function one should be considered. Mainly about the identity of requests cuz business logic is simple.
  3. Model: the storage model. The MVP dapp simply covers the preset methods, so only the schema should be implemented additionally.

Would you pick one up from tasks? @PainterPuppets @Daryl-L @yanguoyu

The tasks not picked will be arranged later(about 18:30 this day).

I think the View partial is front end in this project according to this demo, right?

Keith-CY commented 1 year ago

After the template is ready in kuai, please add a directory named samples, and use the cli to create an mvp-dapp project in the directory, just as nest.js dis nestjs/nest@master/sample @PainterPuppets Once the mvp-dapp skeleton is ready, we should start the actual coding. I'd like to divide the job into 3 tasks from the perspective of MVC

  1. View:

    1. when claim, set, clear APIs are called, inputs and outputs will be returned from storage model, and should be transformed into a raw transaction to the front-end
    2. when read, load APIs are called, structured data should be returned to the front-end
  2. Controller: define the interface of APIs and parse arguments. The second function has been implemented by @kuai/io, so only function one should be considered. Mainly about the identity of requests cuz business logic is simple.
  3. Model: the storage model. The MVP dapp simply covers the preset methods, so only the schema should be implemented additionally.

Would you pick one up from tasks? @PainterPuppets @Daryl-L @yanguoyu The tasks not picked will be arranged later(about 18:30 this day).

I think the View partial is front end in this project according to this demo, right?

It could be done in either backend or front-end.

The main work of View is to transform inputs and outputs into a transaction to sign.

If inputs and outputs are returned from API, front-end should construct the transaction and request a signature via metamask, then the View is in UI.

If inputs and outputs are returned from model but are constructed into a transaction just before responding to the front-end, then the View is in backend.

Either is fine.

yanguoyu commented 1 year ago

I think there is only Model left for me. I will do it.

Daryl-L commented 1 year ago

I'm going to finish View part.

Keith-CY commented 1 year ago

Will be pull request later

How is it going?

Keith-CY commented 1 year ago

Will be pull request later

How is it going?

PR: https://github.com/ckb-js/kuai/pull/121

Keith-CY commented 1 year ago

After the template is ready in kuai, please add a directory named samples, and use the cli to create an mvp-dapp project in the directory, just as nest.js dis nestjs/nest@master/sample @PainterPuppets

Once the mvp-dapp skeleton is ready, we should start the actual coding. I'd like to divide the job into 3 tasks from the perspective of MVC

  1. View:

    1. when claim, set, clear APIs are called, inputs and outputs will be returned from storage model, and should be transformed into a raw transaction to the front-end
    2. when read, load APIs are called, structured data should be returned to the front-end
  2. Controller: define the interface of APIs and parse arguments. The second function has been implemented by @kuai/io, so only function one should be considered. Mainly about the identity of requests cuz business logic is simple.
  3. Model: the storage model. The MVP dapp simply covers the preset methods, so only the schema should be implemented additionally.

Would you pick one up from tasks? @PainterPuppets @Daryl-L @yanguoyu

The tasks not picked will be arranged later(about 18:30 this day).

Please create a project named mvp-dapp in kuai/samples, then we can start the coding of MVP @PainterPuppets

Keith-CY commented 1 year ago

Model, View, and Controller will be ready for code review by 02-03

Keith-CY commented 1 year ago

Model, View, and Controller will be ready for code review by 02-03

Any problem with proposing PRs for review today?

Daryl-L commented 1 year ago

pr for resource binding to initiate Store while registered #125

Daryl-L commented 1 year ago

Model, View, and Controller will be ready for code review by 02-03

Any problem with proposing PRs for review today?

The PR for View will be proposed as soon as possible rest of today. And I think the bootstrap is more complex than expected after finishing the ResourceBinding, so I think maybe it is necessary for me to participate in.

yanguoyu commented 1 year ago

Model definition. https://github.com/ckb-js/kuai/pull/126

Daryl-L commented 1 year ago

View #127

Keith-CY commented 1 year ago

View: https://github.com/ckb-js/kuai/pull/127 Controller: https://github.com/ckb-js/kuai/pull/124 Model: https://github.com/ckb-js/kuai/pull/126 have been merged, the backend service could be launched now

Keith-CY commented 1 year ago

Some logic may have to be complemented in app.controller.ts, all routes are expected to parse params/body, and redirect them to model which returns inputs/outputs or structured data, then respond them via view. If the response is a structured data, UI will render them directly, if the response is a transaction constructed by view, UI will request a signature from metamask

Keith-CY commented 1 year ago

Some logic may have to be complemented in app.controller.ts, all routes are expected to parse params/body, and redirect them to model which returns inputs/outputs or structured data, then respond them via view. If the response is a structured data, UI will render them directly, if the response is a transaction constructed by view, UI will request a signature from metamask

@PainterPuppets

Keith-CY commented 1 year ago

We may need 2 models for the controller

The one that has been added(https://github.com/ckb-js/kuai/blob/develop/packages/samples/mvp-dapp/src/record/record.model.ts) works with a claimed store, it can be set, get and load, but cannot be initialized by the claim method

So another model is required to transform a group of omnilock cells into a store cell(named record in this case).

The possible workflow would be as follows:

  1. user => claim 610 CKB => model_a gathers 10 61 CKB and turns them into 1 610 CKB with a specific pattern for record model, say, data starts withmvp_dapp`
  2. user => load store => record model syncs the 610 CKB cell by the pattern set by model_a and returns the empty data structure parsed from the 610 CKB
  3. user => set store => record model syncs the 610 CKB and adopts modification on it, returns inputs/outputs, in this case, 610 CKB/610 CKB

Correct me if it doesn't work or is unnecessary @yanguoyu

yanguoyu commented 1 year ago

We may need 2 models for the controller

The one that has been added(https://github.com/ckb-js/kuai/blob/develop/packages/samples/mvp-dapp/src/record/record.model.ts) works with a claimed store, it can be set, get and load, but cannot be initialized by the claim method

So another model is required to transform a group of omnilock cells into a store cell(named record in this case).

The possible workflow would be as follows:

  1. user => claim 610 CKB => model_a gathers 10 61 CKB and turns them into 1 610 CKB with a specific pattern for record model, say, data starts withmvp_dapp`
  2. user => load store => record model syncs the 610 CKB cell by the pattern set by model_a and returns the empty data structure parsed from the 610 CKB
  3. user => set store => record model syncs the 610 CKB and adopts modification on it, returns inputs/outputs, in this case, 610 CKB/610 CKB

Correct me if it doesn't work or is unnecessary @yanguoyu

I thought ActorBase is enough, it only needs to gather spec256 cells, and there are no data needed to serialize or deserialize.

Keith-CY commented 1 year ago

We may need 2 models for the controller The one that has been added(develop/packages/samples/mvp-dapp/src/record/record.model.ts) works with a claimed store, it can be set, get and load, but cannot be initialized by the claim method So another model is required to transform a group of omnilock cells into a store cell(named record in this case). The possible workflow would be as follows: 1. user => claim 610 CKB => model_a gathers 10 61 CKB and turns them into 1 610 CKB with a specific pattern for record model, say, data starts withmvp_dapp2. user => load store =>record modelsyncs the 610 CKB cell by the pattern set bymodel_aand returns the emptydata structureparsed from the 610 CKB 3. user => set store =>record modelsyncs the 610 CKB and adopts modification on it, returnsinputs/outputs, in this case,610 CKB/610 CKB` Correct me if it doesn't work or is unnecessary @yanguoyu

I thought ActorBase is enough, it only needs to gather spec256 cells, and there are no data needed to serialize or deserialize.

secp256k1 doesn't work with metamask, so omnilock will be used, but it's not the point. My point is how can the record model construct a cell to store data without a claim action. Will the cells be gathered by demand, like,

  1. user => load store => no cells
  2. user => set store => fetch a cell and update its data
  3. user => set store => update the same cell if capacity is enough, or fetch a new cell to construct a bigger cell for storage
yanguoyu commented 1 year ago

Do you mean how to init a cell with initialization data? @Keith-CY

I think it may init like this: Init the output cell's data by initOnChain, and then gather needs capacity cells as inputs.

const initModel = new RecordModel()
const { data } = initModel.initOnChain({
  data: {
    profile: [],
    addresses: [],
    custom: [],
    dweb: [],
  }
})
const tx = {
inputs,
outputs,
outputs_data: [data]
}

Then broadcast the tx to init a cell

Keith-CY commented 1 year ago

Do you mean how to init a cell with initialization data? @Keith-CY

I think it may init like this: Init the output cell's data by initOnChain, and then gather needs capacity cells as inputs.

const initModel = new RecordModel()
const { data } = initModel.initOnChain({
  data: {
    profile: [],
    addresses: [],
    custom: [],
    dweb: [],
  }
})
const tx = {
inputs,
outputs,
outputs_data: [data]
}

Then broadcast the tx to init a cell

Get it, except one point we can talk about later. If 2 services are running, without a pattern for record, how can the cell initialized by service A be detected by service B

yanguoyu commented 1 year ago

If 2 services are running, without a pattern for record, how can the cell initialized by service A be detected by service B

The above-defined RecordModel is only used to get the outputs_data, but not a RecordModel for resource-binding, RecordModel need to define a pattern with resource-binding. After the tx is broadcast, service B will receive the tx and store it in record by resource-binding.

Keith-CY commented 1 year ago

If 2 services are running, without a pattern for record, how can the cell initialized by service A be detected by service B

The above-defined RecordModel is only used to get the outputs_data, but not a RecordModel for resource-binding, RecordModel need to define a pattern with resource-binding. After the tx is broadcast, service B will receive the tx and store it in record by resource-binding.

Here's my understanding(https://github.com/ckb-js/kuai/issues/85#issuecomment-1368789335), but it was not confirmed or disputed by @Daryl-L

From the code(https://github.com/ckb-js/kuai/blob/develop/packages/models/src/resource-binding/manager.ts#L20) we can see that resource-binding doesn't care about an explicit pattern, the key was roughly set type_script + lock_script.

That means, not every cell sent from resource binding manager to store will update internal state of the store, store should filter out cells those not match pattern defined in store

yanguoyu commented 1 year ago

If 2 services are running, without a pattern for record, how can the cell initialized by service A be detected by service B

The above-defined RecordModel is only used to get the outputs_data, but not a RecordModel for resource-binding, RecordModel need to define a pattern with resource-binding. After the tx is broadcast, service B will receive the tx and store it in record by resource-binding.

Here's my understanding(#85 (comment)), but it was not confirmed or disputed by @Daryl-L

From the code(https://github.com/ckb-js/kuai/blob/develop/packages/models/src/resource-binding/manager.ts#L20) we can see that resource-binding doesn't care about an explicit pattern, the key was roughly set type_script + lock_script.

That means, not every cell sent from resource binding manager to store will update internal state of the store, store should filter out cells those not match pattern defined in store

Do you mean I forget to filter cells in handleCall by pattern? If so, I will add it later.

Keith-CY commented 1 year ago

If 2 services are running, without a pattern for record, how can the cell initialized by service A be detected by service B

The above-defined RecordModel is only used to get the outputs_data, but not a RecordModel for resource-binding, RecordModel need to define a pattern with resource-binding. After the tx is broadcast, service B will receive the tx and store it in record by resource-binding.

Here's my understanding(#85 (comment)), but it was not confirmed or disputed by @Daryl-L From the code(develop/packages/models/src/resource-binding/manager.ts#L20) we can see that resource-binding doesn't care about an explicit pattern, the key was roughly set type_script + lock_script. That means, not every cell sent from resource binding manager to store will update internal state of the store, store should filter out cells those not match pattern defined in store

Do you mean I forget to filter cells in handleCall by pattern? If so, I will add it later.

It should be done in resource-binding, but could be too hurry to finish it for now, filtering in store would be simple in the MVP dapp

Daryl-L commented 1 year ago

If 2 services are running, without a pattern for record, how can the cell initialized by service A be detected by service B

The above-defined RecordModel is only used to get the outputs_data, but not a RecordModel for resource-binding, RecordModel need to define a pattern with resource-binding. After the tx is broadcast, service B will receive the tx and store it in record by resource-binding.

Here's my understanding(https://github.com/ckb-js/kuai/issues/85#issuecomment-1368789335), but it was not confirmed or disputed by @Daryl-L

From the code(https://github.com/ckb-js/kuai/blob/develop/packages/models/src/resource-binding/manager.ts#L20) we can see that resource-binding doesn't care about an explicit pattern, the key was roughly set type_script + lock_script.

That means, not every cell sent from resource binding manager to store will update internal state of the store, store should filter out cells those not match pattern defined in store

So the resource binding manager should not only filter the cells by type script and lock script, but also parse the data with storage and filter the cells out by pattern, right?

Keith-CY commented 1 year ago

If 2 services are running, without a pattern for record, how can the cell initialized by service A be detected by service B

The above-defined RecordModel is only used to get the outputs_data, but not a RecordModel for resource-binding, RecordModel need to define a pattern with resource-binding. After the tx is broadcast, service B will receive the tx and store it in record by resource-binding.

Here's my understanding(#85 (comment)), but it was not confirmed or disputed by @Daryl-L From the code(develop/packages/models/src/resource-binding/manager.ts#L20) we can see that resource-binding doesn't care about an explicit pattern, the key was roughly set type_script + lock_script. That means, not every cell sent from resource binding manager to store will update internal state of the store, store should filter out cells those not match pattern defined in store

So the resource binding manager should not only filter the cells by type script and lock script, but also parse the data with storage and filter the cells out by pattern, right?

We haven't discussed it much, so there's no conclusion yet.

For me, yes. Resource-binding means providing resources asked by others. Say that, module A declares that it wants A, B, C, to Z, they are all letters, then resource-binding should give letters to module A, but not characters which covers letters and digits.

However, in a meeting, we've talked about a compromise that resource-binding could provide a superset of cells to store while store filter them again to update its internal state.

yanguoyu commented 1 year ago

This is my understanding of the MVP API process:

  1. claim
    • get init output_data
    • create output by lock
    • gather inputs
    • create tx and return
  2. read
    • register lock/type by resource-binding
    • generator/get store
    • send message to store to save data to state
    • return data by store
  3. set
    • register lock/type by resource-binding
    • generator/get store
    • send message to store to save data to state
    • send message to store to set data
    • get inputs and outputs from store
    • if capacity is not enough, gather extra inputs
    • create tx and return
  4. load: I think it seems as read when calling it without a path.
  5. clear
    • register lock/type by resource-binding
    • generator/get store
    • send message to store to save data to state
    • clear data by store
    • get inputs and outputs from store
    • create tx and return

I think there are some things we need to implement:

  1. gather extra inputs when the inputs' capacity is not enough.
  2. generator and register store, I don't know when we need to register store and what will be set as the store's path.
  3. create an instance of ChainSource to instantiate a resource-binding.
  4. gather a tx from inputs, outputs, and outputs_data
Keith-CY commented 1 year ago

This is my understanding of the MVP API process:

  1. claim
    • get init output_data create output by lock gather inputs * create tx and return
  2. read
    • register lock/type by resource-binding generator/get store send message to store to save data to state * return data by store
  3. set
    • register lock/type by resource-binding generator/get store send message to store to save data to state send message to store to set data get inputs and outputs from store if capacity is not enough, gather extra inputs create tx and return
  4. load: I think it seems as read when calling it without a path.
  5. clear
    • register lock/type by resource-binding generator/get store send message to store to save data to state clear data by store get inputs and outputs from store * create tx and return

I think there are some things we need to implement:

  1. gather extra inputs when the inputs' capacity is not enough.
  2. generator and register store, I don't know when we need to register store and what will be set as the store's path.
  3. create an instance of ChainSource to instantiate a resource-binding.
  4. gather a tx from inputs, outputs, and outputs_data

The confusion may come from the timing of claim and register a store

As the PRD(https://github.com/ckb-js/kuai/issues/54#issuecomment-1365629078) said

claim(capacity): Transaction: claim a group of cells with a given capacity as the user info Store to store user info

claim(capacity) gathers cells to instantiate a store with empty data. after claim, a cell should be on the chain to hold the user's info. Then the user's info could be updated and loaded.

Besides, the capacity of a store is declared at first, so once data written to the cell is out of limit, it should be rejected.

Keith-CY commented 1 year ago

Missing parts:

  1. Controller, assigned to @PainterPuppets :
    1. Restful request URI, as /claim/:address
    2. Parameters validation
    3. Error handling
    4. Delegate messages to model and format responses with view
  2. Model and claim method, assigned to @yanguoyu :
    1. Omnilock Model:
      1. Claim: gather cells into an integrated cell with specific capacity and predefined data prefix
      2. Instantiate omnilock model and register it in the resource binding
    2. Record Model:
      1. Update: receive message of set and return inputs/outputs
  3. Resource-binding, assigned @Daryl-L :
    1. Chain source instance
      1. get cells to initiate states of stores
      2. get blocks to update states of stores
yanguoyu commented 1 year ago

Model and claim method https://github.com/ckb-js/kuai/pull/137