-
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 actor system #4
Comments
The main spec of an actor has been updated, please have a review @homura @felicityin @yanguoyu @IronLu233 |
|
I thought |
Yes, class Store extends Actor<DefaultState, DefaultMessage> {
@State()
#state: DefaultState
@HandleCall(sync)
function sync (
message: { blockNumber?: number },
from: ActorAddress,
_state: DefaultState,
) {
const state = this.#sync(message.blockNumber)
from.reply({
status: ok,
message: null,
state,
})
}
@HandleCall(get)
function get (
message: { path: string },
from: ActorAddress,
state: DefaultState,
) {
const value = state.get(path)
from.reply({
status: ok,
message: value,
state,
})
}
@HandleCall(set)
function set (
message: { path: string, value: DefaultState['path'] },
from: ActorAddress,
state: DefaultState,
) {
state.set(message.path, message.value)
from.reply({
status: ok,
message: null,
state,
})
}
// ...
} Developers could implement their own |
Usually, the For example, the |
I believe this actor model might be cool, but I don't quite understand how this actor model would work with the cell model The main purpose of Kuai is to help developers lower the barrier, and as we work on the design, I think we can describe how Kuai will be used from the dApp user's and developer user's perspective.
I mention this because I believe Run has a particularly easy to understand design, but Run's NFT metadata is not validated on BSV, and the consensus of these state is ensured by the Run network, which may not be the Kuai wants, because I think Kuai should be a development framework, not a Network. The state of a dApp should be verified by a CKB contract |
Actor model is used to structure the dapp better and make data/state sharing less possible, not to map data on-chain to data off-chain. How to arrange data on-chain and map data on-chain to off-chain will be solved by the
The example will be delivered by @yanguoyu, that's why I posted this design in draft state, the main spec is necessary for the demo and other parts could be discussed later.
I don't get the point
For now |
Developers need to write contracts to verify the state transition in cell's data. But how can they know which cells are included in the transaction? |
IMO, developers don't have to know which cells are going to be packaged in a transaction.
|
OK, but how to write a contract to verify the state transition? |
For now, I don't know It may be solved by the merkle-like solution, or be handled by a feature we set in the plan |
If I will use // file index.ts
import { Actor } from "kuai";
import DomainContract from "./domain/domain.contract";
// actorRoot will be provided by kuai
class RootActor extends Actor {
constructor() {
super()
// kuai will auto collect register contract
this.add(new DomainContract())
}
}
const actorRoot = new RootActor()
export function sequencer() {
// sequencer will be added here
registerDomain({ name: 'kuai.bit', lock: '0x.1...' })
registerDomain({ name: 'kuai.bit', lock: '0x.1...' })
registerDomain({ name: 'kuai1.bit', lock: '0x.1...' })
}
export function registerDomain(params: {
name: string
lock: string
}) {
// Find .bit's actor to handle this action
actorRoot.send('.bit', {
method: 'register',
params
})
}
export function searchDomain(search: string) {
// Find .bit's actor to handle this action
actorRoot.send('.bit', {
method: 'search',
params: { search }
})
}
Then we will achieve // file domain.contract.ts
// contract is created to handle the contract's business
import { Actor, Handle, PatternHandle } from "kuai";
import { Domain } from "./model/domain";
import DomainStore from "./domain.store";
@PatternHandle('.bit')
class DomainContract extends DomainStore {
@Handle('register')
register(domain: Domain, actor: Actor) {
// do something else before creating the domain
actor.send('user_contract', { method: '', params: {}})
this.createDomain(domain)
// do something else after creating the domain
actor.send('user_contract', { method: '', params: {}})
}
@Handle('search')
search(search: string) {
const domains = this.getDomains()
return domains.filter(v => v.name.includes(search))
}
}
export default DomainContract In the end, we will achieve the // file domain.store.ts
// store is created to handle cell data
import { Store } from "kuai";
import { Domain } from "./model/domain";
export default class DomainStore extends Store<Domain> {
pattern: string
getDomains(): Domain[] {
return this.getData('domain')
}
createDomain(domain: Domain) {
const domains = this.getDomains()
if (domains.some(v => v.name === domain.name)) {
throw new Error('domain exists')
}
this.saveAsMerkleTree(domain)
}
saveAsMerkleTree(domain: Domain) {
this.setData(`${domain.lock}.domain`, domain)
// then calculate the Merkle tree and save
}
} |
An actor in actor model is the most basic computing unit to run business logic insulated. It is self-contained that receives messages and processes them sequentially.
Actor runtime is the moderator which decides how, when, where each actor runs, and routes messages transported in the actor system.
Under the control of actor runtime, a large number of actors can perform simultaneously and independently to achieve parallel computation.
Kuai
provides the basic implementation of an actor for developers to extend business logic and dominates these actors with the actor runtime for scalability and reliability.1. Actor Runtime
1.1 Supervision
The main idea delivered by the actor model is
Divide-and-Conquer
. If a heavy task is assigned to actor_a, the task would be split into sub-tasks and delegated to actor_a's child actors, recursively, until sub-tasks are small enough to be handled in one piece.Within the runtime, an actor will be activated(created) or deactivated(destroyed) automatically so developers don't have to pay attention to the lifecycle of a single actor. Once a message is sent to an actor located by identity, the actor runtime will activate one to handle the message. And if an actor has been idle for a while(no messages, no internal state), the actor runtime will deactivate it. In some cases, which we will mention later, an actor should be kept alive, it could send messages to itself periodically as a reminder.
To achieve this, a supervision tree is going to be introduced because actor model has a tree-like hierarchical structure. More about supervision tree could be learned from supervision principles
1.2 Router
Actors communicate with each other exclusively by sending messages to targets while targets are not referenced directly, instead, messages are routed by the runtime. With this, actors are decoupled and their lifecycles could be taken over by the runtime.
To deliver a message, the recipient should have an identity that is transparent to the sender. For simplicity,
address
is used as the identity inKuai
runtime.There're several ways to get a recipient's address. The simplest way is to register the newly activated actor in a registry. A registry is a local, decentralized, and scalable key-value address storage. It allows an actor to look up one or more actors with a given key. The actors registered in the registry will be managed by the runtime under different supervision/monitoring strategies(strategies could be found in supervision principles too)
The other way is more modular, an actor will only send messages to addresses it received, e.g. a parent spawns a child actor and gets a response of the child actor's address, with the response, the parent could start communicating with its child actor.
2. Actor
2.1 State
2.2 Behaviour
The
state
field in the parameters is the state of actor before the action and thestate
field returned by callback is the state of actor after the action(framework will update the internal state of the actor, quite similar touseState
hook in React:useAction(preState => curState)
).2.3 Mailbox
// TODO:
3. Basic Models
3.1 Registry
It's actually a
Store
model we will design later.3.2 Supervisor
3.3 Store
// TODO: Design
Store
model3.4 Contract
// TODO: Design
contract
model3.5 Token
// TODO: Design
token
modelThe text was updated successfully, but these errors were encountered: