Skip to content
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

Architecture design of Kuai runtime #7

Closed
Keith-CY opened this issue Oct 14, 2022 · 12 comments
Closed

Architecture design of Kuai runtime #7

Keith-CY opened this issue Oct 14, 2022 · 12 comments
Assignees
Labels
documentation Improvements or additions to documentation

Comments

@Keith-CY
Copy link
Member

Keith-CY commented Oct 14, 2022

Architecture of Kuai runtime at the components level

    C4Context
      title Architecture of Kuai runtime

      Container_Boundary(b0, "Kuai runtime") {


        Boundary(io_comp, "Input/Output", "Component") {
            System(ckb, "CKB Node", "Chain data")
            System(input, "input", "Requests from users/dapps")
            System(output, "output", "Responses to users/dapps")
            System(main_entry, "main_entry", "Entry of DApp that launches components")

            Rel(input, main_entry, "")
            Rel(output, main_entry, "")
            Rel(main_entry, token, "manage")
            Rel(main_entry, contract, "manage")
            Rel(ckb, resource_binding, "bind")
        }

        Boundary(ckb_comp, "CKB related", "Component") {
          Boundary(b5, "CKB models", "System") {
            Component(store, "Store model")
            Component(contract, "Contract model")
            Component(token, "Token model")

            Rel(token, contract, "extend")
            Rel(contract, store, "extend")
            Rel(store, actor_models, "extend")

          }
          System(resource_binding, "Resource binding", "Trigger state update by on-chain transactions")
          Rel(resource_binding, store, "trigger")
        }

        Boundary(basic_comp, "CKB-independent", "Component") {
          System(actor_models, "Actors", "Encapsulate code and data in a reusable actor as the most basic computation unit")
          System(secrets, "Secrets", "Limit access to secrets, adopt secret scope policy with restriction permission")
          System(configuration, "Configuration")      
          System(observability, "Observability", "Metrics, logs, and data tracing")   
    
          Rel(secrets, actor_models, "implement")
          Rel(configuration, actor_models, "implement")
          Rel(observability, actor_models, "extends")
        }

        Boundary(db_comp, "Database", "Component") {
          System(storage, "Storage", "With pluggable DBMS for storing and querying data")
          Rel(storage, store, "data query and update")
        }

        Boundary(external_services, "External Services", "Component") {
          SystemDb_Ext(database, "DBMS")
          System_Ext(secrets_manager, "Secret manager")
          System_Ext(config_manager, "Configuration manager")
          System_Ext(metrics, "Metrics service")
          System_Ext(logs, "Logs service")
          System_Ext(health_check, "Health check service")

          Rel(database, storage, "connect")
          Rel(secrets_manager, secrets, "")
          Rel(config_manager, configuration, "")
          Rel(metrics, observability, "")
          Rel(logs, observability, "")
          Rel(health_check, observability, "")
        }

        UpdateLayoutConfig($c4ShapeInRow="10", $c4BoundaryInRow="1")
      }
Loading

There're 5 main components running in runtime

  • Input/Output Component: there're only two directions of data flow on CKB: chain -> user and user -> chain, so they are grouped together as an IO component. This component is to handle messages/data from the two endpoints.

  • CKB Related Component: this component is a group of dapp business rules. There're 3 basic abstractions of CKB's unit, store, contract, and token to be extended for dapp specific rules. Each model extended from the basic abstraction could be regarded as a use case.

  • CKB-independent Component: this component provides general functions of a framework, especially those that are not coupled with CKB cell models. From this perspective, the dapp could be platform-agnostic.

  • Database Component: database component is outlined for flexibility, with this component, state storage could be decoupled from an explicit database.

  • External Services Component: some third-party services could be used to enhance functions of kuai.

@Keith-CY Keith-CY self-assigned this Oct 14, 2022
@Keith-CY Keith-CY added the documentation Improvements or additions to documentation label Oct 14, 2022
@Keith-CY Keith-CY changed the title Brief docs of kuai Architecture design of Kuai runtime Oct 14, 2022
@Keith-CY Keith-CY added this to the 2022/10/13 - 2022/10/20 milestone Oct 14, 2022
@Keith-CY
Copy link
Member Author

Keith-CY commented Oct 19, 2022

This is a succinct demonstration of model tree + merkle-like solution

Domain registration service: https://seekdid.com/

image

Model tree

flowchart BT
    subgraph UI_A
      UI_A_Actions[/register 1111, 11111, 12345/]
    end
    subgraph UI_B
      UI_B_Actions[/register 11111, 22222/]
    end
    subgraph Server
    A([Endpoint]) -->|register 1111, 11111, 12345, 11111, 22222| B[Domain registry model]
    B -->|1111| C[4D model]
    B -->|11111, 12345, 11111, 22222| D[5D model]
    B --> E[6D model]
    D -->|12345| F[ABCDE model]
    D -->|11111, 11111, 22222| G[AAAAA model]
    D --> H[ABCBA model]
    G --> I[Trie model] --> L[(Store)] & M[(Store)] & N[(Store)]
    G -->|11111,11111| J[Trie model] --> O[(Store)] & P[(Store)] & Q[(Store)]
    G -->|22222| K[Trie model] --> R[(Store)] & S[(Store)] & T[(Store)]
    end
    UI_A --> |1111, 11111, 12345| Server --> |Input & Output Stores|UI_A
    UI_B --> |11111, 22222| Server --> |Input & Output Stores|UI_B
Loading

Merkle-like solution

flowchart TB
  Actions["Action(s)"]
  Storage["MerkleXStorage"]

  subgraph Transaction
    direction LR
    subgraph Inputs
      MerkleRoot
    end

    subgraph Outputs
      MerkleRoot'
    end

    Inputs -.transition replay.-> Outputs
  end

  subgraph ActionExecutor
    Storage --> State
    State --> State'
    State' --> TransitionProof
    State' --> Storage
  end

  Actions -.-> Sequencer
  Sequencer --> ActionExecutor
  TransitionProof --> Transaction

Loading

Adopt Merkle-like solution with model tree and it would be like

flowchart TB
  Actions["Action(s)"]
  Storage["MerkleXStorage"]

  subgraph Transaction
    direction LR
    subgraph Inputs
      MerkleRoot
    end

    subgraph Outputs
      MerkleRoot'
    end

    Inputs -.transition replay.-> Outputs
  end

  subgraph ActionExecutor
    Storage --> State

    State' --> TransitionProof
    subgraph ModelTree
        State --> State'
        State' --> Storage
    end
  end

  Actions -.-> Sequencer
  Sequencer --> ModelTree
  TransitionProof --> Transaction

Loading

How a single model works as an actor

Take the following actions as an example

flowchart TB
Sequencer -->|11111, 11111', 22222| ModelTree[Model Tree] --> TransitionProof[Transition Proof]
Loading

The underlying model working here is AAAAA Model and its internal workflow would be like

initialize a model
mailbox                   : []
state                     : [0_, 1_, 2_, 3_, 4_, 5_, 6_, 7_, 8_, 9_] + proof(null)
------------------------------------------------------------------------------------------
push   11111  message
mailbox                   : [11111]
state                     : [0_, 1_, 2_, 3_, 4_, 5_, 6_, 7_, 8_, 9_] + proof(null)
------------------------------------------------------------------------------------------
push   11111' message
mailbox                   : [11111, 11111']
state                     : [0_, 1_, 2_, 3_, 4_, 5_, 6_, 7_, 8_, 9_] + proof(null)
------------------------------------------------------------------------------------------
push   22222  message
mailbox                   : [11111, 11111', 22222]
state                     : [0_, 1_, 2_, 3_, 4_, 5_, 6_, 7_, 8_, 9_] + proof(null)
------------------------------------------------------------------------------------------
handle 11111  message
mailbox                   : [11111', 22222]
state                     : [0_, --, 2_, 3_, 4_, 5_, 6_, 7_, 8_, 9_] + proof(11111)
respond                   : succeed
------------------------------------------------------------------------------------------
handle 11111' message
mailbox                   : [22222]
state                     : [0_, --, 2_, 3_, 4_, 5_, 6_, 7_, 8_, 9_] + proof(11111)
respond                   : fail
------------------------------------------------------------------------------------------
handle 22222  message
mailbox                   : []
state                     : [0_, --, --, 3_, 4_, 5_, 6_, 7_, 8_, 9_] + proof(11111, 22222)
respond                   : succeed
------------------------------------------------------------------------------------------
destroy the model and respond with the final state and proof(11111, 22222)

@Keith-CY
Copy link
Member Author

@homura @felicityin @yanguoyu The architecture design was postponed because an unexpected task appeared so I added a diagram to illustrate the model tree with an explicit example.

I also modified the diagram from #6 (comment) to show the relation between model tree and merkle-like solution that they are not conflicted because they are dealing with different problems.

@Keith-CY
Copy link
Member Author

sequenceDiagram
  participant Action Source
  participant On Chain Contract
  participant Node
  participant Sequencer
  participant DApp Model
  participant 4D Contract Model
  participant 5D Contract Model
  participant AAAAA Contract Model
  participant ABCDE Contract Model
  participant AAAAA Store Model
  participant ABCDE Store Model
  participant AAAAA tree as AAAAA Sub-tree in MerkleXStorage
  Note over DApp Model, AAAAA tree: Action Executor
  Note over DApp Model, ABCDE Store Model: Model Tree
  Note over AAAAA Store Model, AAAAA tree: MerkleXStorage Operator

  Action Source ->> Sequencer: register 11111
  Action Source ->> Sequencer: register 11111'
  Action Source ->> Sequencer: register 12345
  Action Source ->> Sequencer: register 22222
  Action Source ->> Sequencer: register 1111
  Sequencer ->> DApp Model: register [11111, 11111', 12345, 22222, 1111]
  par
  DApp Model ->> 4D Contract Model: register [1111]
  activate 4D Contract Model
  4D Contract Model ->> DApp Model: transition(1111) + proof(1111)
  deactivate 4D Contract Model
  and
  DApp Model ->> 5D Contract Model: register [11111, 11111', 12345, 22222]
  activate 5D Contract Model
    par
      5D Contract Model ->> ABCDE Contract Model: register [12345]
      ABCDE Contract Model ->> 5D Contract Model: transition(12345) + proof(12345)
    and
      5D Contract Model ->> AAAAA Contract Model: register [11111, 11111', 22222]
      AAAAA Contract Model ->> AAAAA Store Model: register [11111]
      AAAAA Contract Model ->> AAAAA Store Model: register [11111']
      AAAAA Contract Model ->> AAAAA Store Model: register [22222]
      AAAAA Store Model ->> AAAAA tree: update 11111
      AAAAA tree ->> AAAAA Store Model: success
      AAAAA Store Model -->> AAAAA Store Model: fail to update 11111'
      AAAAA Store Model ->> AAAAA tree: update 22222,
      AAAAA tree ->> AAAAA Store Model: success
      AAAAA Store Model ->> AAAAA Contract Model: transition(11111, 22222) + proof(11111, 22222)
      AAAAA Contract Model ->> 5D Contract Model: transition(11111, 22222) + proof(11111, 22222)
    end
    5D Contract Model ->> DApp Model: transition(11111, 22222, 12345) + proof(11111, 22222, 12345)
    deactivate 5D Contract Model
  end
  DApp Model ->> Node: transition(11111, 22222, 12345, 1111) + proof(11111, 22222, 12345, 1111)
  Node ->> On Chain Contract: transition(11111, 22222, 12345, 1111) + proof(11111, 22222, 12345, 1111)
  On Chain Contract ->> On Chain Contract: replay transition(11111, 22222, 12345, 1111) and verify proof(11111, 22222, 12345, 1111)
Loading

The sequence diagram of model tree working inside merkle-like solution has been updated, please have a review @homura @felicityin @yanguoyu

@Keith-CY
Copy link
Member Author

Keith-CY commented Nov 2, 2022

I've just updated the architecture design of kuai runtime at the components level in the top message, please have a review @homura @felicityin @yanguoyu @IronLu233

@yanguoyu
Copy link
Contributor

yanguoyu commented Nov 3, 2022

I got that only <<component>> needs users to achieve. If so, shall we move Input and Output(From users/dapps) to <<component>>

@Keith-CY
Copy link
Member Author

Keith-CY commented Nov 3, 2022

I got that only <<component>> needs users to achieve. If so, shall we move Input and Output(From users/dapps) to <<component>>

Input/Output has been grouped with CKB node as a component to be an IO layer so I don't get what move means here.

Besides,

only <<component>> needs users to achieve

is not exactly correct, components can be thought of as decoupled layers in the project

  • users of kuai should focus on extending IO component and ckb-related component to build a dapp
  • developers of kuai should focus on implementing ckb-related component, ckb-independent component, and database component and shelter details from kuai users.

@homura
Copy link
Contributor

homura commented Nov 3, 2022

The following is my understanding of the Input/Output layer, I am not sure if it is correct, please correct me if it is wrong

What is Input/Output of Kuai?

Input/Output is the communication between Kuai's service and the outside world, which may be a dapp user or CKB.

What does Input/Output provide?

  • HTTP/RPC server, to receive and reply to user requests
  • Blockchain client, fetch data from blockchain
  • Event listener, listens for new transactions from CKB
  • Tx sender, sends transactions to CKB
  • Push service, pushing the transaction status to the client
  • And maybe more...

@Keith-CY
Copy link
Member Author

Keith-CY commented Nov 4, 2022

What is Input/Output of Kuai?

Input/Output is the communication between Kuai's service and the outside world, which may be a dapp user or CKB.

Almost there, Input/Output is an abstract layer between Kuai's business logic and external entities. Specifically, the external entities could be a user/dapp or a CKB node. More than communication, prep- and post-process could be done before reaching and after leaving the business logic, quite similar to middleware in koa, e.g. rate limiting, message serialization/deserialization.

What does Input/Output provide?

  • HTTP/RPC server, to receive and reply to user requests
  • Blockchain client, fetch data from blockchain
  • Event listener, listens for new transactions from CKB
  • Tx sender, sends transactions to CKB
  • Push service, pushing the transaction status to the client
  • And maybe more...

Seems good, looking forward to the final design

@felicityin
Copy link
Contributor

What is Sorage Database

  • Whether to implement components similar to typeorm or use typeorm?

@Keith-CY
Copy link
Member Author

Keith-CY commented Nov 4, 2022

What is Sorage Database

  • Whether to implement components similar to typeorm or use typeorm?

Quite similar to typeorm which is used to shelter developers from the implementation of how to connect to a database. The goal of the database layer is to allow dapps to migrate between databases at a lower cost(dapps won't migrate databases often but it's a prominent characteristic of this layer).

Here are some modules in Nest.js database for the same target.

@Keith-CY
Copy link
Member Author

Code snippets of MVP based on IO Component design and CKB-independent Component design to update a store of block statistics are as follows:

MVP

// index.ts
const cor = new Cor()
const blockTipChanged = new BlockTipChanged()

enum Signal {
  BlockTipChanged = Symbol('block-tip-changed')
}

blockTipChanged.on(tipNumber => {
  cor.dispatch({
    type: Signal.BlockTipChanged,
    value: tipNumber,
  })
})
// app/index.ts
@Application()
class App extends Actor<AppState, AppMessage>{ // instantiated by IoC container on app launch
  blockStats: Actor // instantiated by IoC container on App instantiation

  @HandleCall(Signal.BlockTipChanged) // match Signal.BlockTipChanged event from cor
  handleTipNumberChanged(
    @Message('tipNumber') tipNumber: string, // pick the tipNumber field from the incoming message
  ) {
    const { status, message } = Actor.call( // send the message to a child actor
      this.blockStats.id,
      { signal: Signal.BlockTipChanged, message: tipNumber })
    )
    console.info(status, message)
  }
}
// app/block_stats.ts
@ActorProvider()
class BlockStats extends Actor<BlockStatsState, BlockStatsMessage> {
  @State() // declare the tipNumber in internal state
  tipNumber: string
  
  @HandleCall(Signal.BlockTipChanged)
  handleTipBlockNumberChanged(
    @Message('tipNumber') tipNumber: string,
    @InternalState() state: BlockStatsState
  ) {
    return {
      status: 'ok',
      message: { ...state, tipNumber }, // return the last stats to the caller
      state: { ...state, tipNumber } // update the internal state
    }
  } 
}

@Keith-CY
Copy link
Member Author

This is the document of the kuai runtime we're working on now and main works are split into 4 pieces

  1. I/O component: Design of Input/Ouptut component of Kuai runtime #15
  2. CKB-related component: Design Store model #2, Design Contract model #3, Design Token model #5
  3. CKB-independent component: Design of CKB-independent component of Kuai runtime #17
  4. Database component: Design of Database component of Kuai runtime #16

@zhengjianhui @Daryl-L @pygman

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
Archived in project
Development

No branches or pull requests

4 participants