Skip to main content

Context-aware Flipper

Our previous example works just like any standard smart-contract on any other blockchain. The logic has some state where it stores user's state (values). Anyone can set, get or flip their own value.

Flipper logic state

But just like on any other blockchain, if multiple users want to modify their value, they need to do it one after another. If a million users try to flip their values, the logic will be locked for each user, the value flipped, then another user's invocation will flip its own value and so again and again. And it will take quite some time to finish.

The core concept of MOI blockchain that resolves the problem above is to remove the data from a central location in the logic into actor's context (users are called actors in MOI, any user or even logic can be an actor). So instead of a Map on a logic, we keep the value on each actor's context. In this manner, logic Flipper doesn't need to be locked and can be used to modify all actor's data in parallel, so in the above case of a million actors wanting to flip their state, they can all do it at once in parallel, gaining massive performance.

Flipper values on actor states

Modified Coco code

Let's write the new code and compare it with the original Flipper with central storage of values. The new module is called ContextFlipper, we can put it in a separate folder with its own coco.nut file and the source in context_flipper.coco:

coco ContextFlipper

state actor:
value Bool

endpoint enlist Init():
mutate true -> ContextFlipper.Sender.value

endpoint dynamic Flip():
mutate value <- ContextFlipper.Sender.value:
value = !value

endpoint Mode() -> (value Bool):
observe value <- ContextFlipper.Sender.value

endpoint dynamic Set(value Bool):
mutate value -> ContextFlipper.Sender.value

Testing the code

First, compile the code and init Cocolab, so you get a compiled logic ContextFlipper and default_user as the Sender.

coco compile
coco lab init

With context-aware logics, state on every actor is not initialized by deploy command, but by enlist. So let's enlist default_user to use the logic and check the results.

enlist ContextFlipper.Init()
observe ContextFlipper.Sender.value

Init has set the value for the logic ContextFlipper on the actor that has made the call (also denoted by Sender). So observing the Sender's value on the logic ContextFlipper returns true.

Sender means default.sender in Cocolab, but you can also use user's name (default_user in our example) or even the identifier. Let's look what identifier has the user and try other options for observing the data:

users
default_user [0x3354b6f98a3920ee671c0982c37439f98995104330a771c9d457372ad8da1a13]

The output should look like this, 32-byte identifier will be unique for everyone. Now, we can try all three options to observe the value and they should all return the same result as Sender is default_user and its identifier is 0x3354b6f98a3920ee671c0982c37439f98995104330a771c9d457372ad8da1a13

observe ContextFlipper.Sender.value
observe ContextFlipper.default_user.value
observe.ContextFlipper.0x3354b6f98a3920ee671c0982c37439f98995104330a771c9d457372ad8da1a13.value

Flip the value and repeat the above commands and they should return the same value again

invoke ContextFlipper.Flip()
observe ContextFlipper.Sender.value
observe ContextFlipper.default_user.value
observe.ContextFlipper.0x3354b6f98a3920ee671c0982c37439f98995104330a771c9d457372ad8da1a13.value

Let's see how this works for a different user. As in our first example, register a new user, make it the default.sender and it should be able to work with its ContextFlipper value - all this while default_user's value remains as it was.

register Robert
wipe default.sender
set default.sender Robert
enlist ContextFlipper.Init()
observe ContextFlipper.Robert.value
observe ContextFlipper.default_user.value

Let's flip Robert's value and observe both his and default_user's value.

invoke ContextFlipper.Flip()
observe ContextFlipper.Robert.value
observe ContextFlipper.default_user.value

Actor's context is the most important concept in MOI, but to fully use Coco, let's explore the language in more detail.