buckyos / documents Goto Github PK
View Code? Open in Web Editor NEWLicense: BSD 3-Clause "New" or "Revised" License
License: BSD 3-Clause "New" or "Revised" License
Any Data is named with it's hash, any modification will change its name. This is a key design, it will ensure that the data you reference has not been tampered with.
Any data named in this way is called Named Data
.
Data is divided into structured data and unstructured data, and structured data is called Object
, Any Object
named in this way is called Named Object
.
In principle, Object is immutable, if you need to change it, create a new object.
But for convenience, there is a design to modify it:
The content of Object
is split into two parts:
ObjectId
is calculate with this part.the size is limmited at 64KBytes.ObjectId
. We can update the body without modify the ObjectId
. Therefore, developers must consider how to ensure that the Body is the version we need.Every object should belong to a different Area
, and accept the legal supervision of the corresponding Area
.
Any Object requires a field that explicitly specifies its type, it's ObjectType.
All types are divided into 4 categories:
cyfs-base
. Collected in the module cyfs-base
.cyfs-core
.The name of a Named Object
is ObjectId
.
The main component of ObjectId
is the SHA256
of ObjectDesc
, It also contains the type and area information.The total length is 32Bytes(256bits).
The structure is as follow:
ObjectId = Catgory(2bits) + DataContent(38bits) | CommonObjectId(38bits)
Catgory = Standuard(1) | Core(2) | DecAppObject(3) | Data(0)
if Catgory = Data(0) {
DataContent = 0b_000000 + ImmediateValue(248bits)
} else {
CommonObjectId = TypeDetail(4bits) + Area(34bits) + SHA256(`ObjectDesc`)[5..]
TypeDetail = ObjectTypeCode | FieldFlags
if Catgory = Standuard(1) {
ObjectTypeCode = Device(1) | People(2) | Group(3) | AppGroup(5) | UnionAccount(6) | Chunk(7) | File(8) | Dir(9) | Diff(10) |
ProofOfService(11) | Tx(12) | Action(13) | ObjectMap(14) | Contract(15)
} else {
FieldFlags = is_area_exist(1bit) + is_single_exist(1bit) + is_mult_key_exist(1bit) + is_owner_exist(1bit)
is_area_exist = 1 | 0
is_single_exist = 1 | 0
is_mult_key_exist = 1 | 0
is_owner_exist = 1 | 0
}
Area = country(9bits) + carrier(4bits) + city(13bits) + inner(8bits)
* if the Area is not set the bits shoud be set to 0.
}
An object is said to be entitled object
if it can provide proof of the authenticity of another object.It can be the owner of an object to own it.A common method of proof is the signature, so, most entitled object
contains a key-pair,for example:People
and Device
.but a Group
contains many People
as the members
, Its proof requires the signature of a majority of members.
An object is said to be owned object
if it's created with a owner, most public object is owned object
,Any object of external origin without owner and signature is untrusted.
Owner
is contained in the ObjectDesc
, it's immutable field, it's always the creator.
The Owner
is immutable, but there are many tradable objects(for example: NFT). the updated property is the Right to profit
, that usually occurs on the chain. The immutable Owner
strongly protects the copyright
of the objects.
R
LinkIt's like below:
cyfs://$target_zone.r/$dec_id/$inner_path[?mode=json&mime=txt]
The R
Link read the specified field mounted on the RootState
of a DECApp
. it's usually used to access the mutable Object
s.
Object
saved on RootState.Different from O
link, the content specified by R
link can be modified by the owner, It behaves much like http, and we can always use it instead of the http
.
R
LinkDifferent from O
link, the domain of R
link is depend on the DecApp
. So, there are cross domain issues and defense. We must open the permissions to the target DecApp
to allow it's access.
duplicate with #4
The method of developing DECApp
needs to be introduced systematically, which is too long. It is recommended that you read the tutorial document provided by the offical. If you encounter any problems, please leave a message for discussion.
Let's look at the readme in official repository first.
The above is the overall architecture diagram of CYFS, which can help to establish a macro understanding of the design of CYFS. The core design of CYFS can be decomposed into the following parts
There are also two auxiliary connectivity devices that are not mentioned:
SN: Super Node
.It's service that assists devices deployed in NAT to communicate with each other. In CYFS, anyone can deploy a SN server, and anyone can freely choose the appropriate SN server.Both parties complete the transaction through SN service contract and service certificate.
PN: Proxy Node
. They are used as proxies to transfer data when both communication devices cannot complete a direct connection. As the SN service, anyone can deploy a PN server, and anyone can freely choose the appropriate PN server.Both parties complete the transaction through PN service contract and service certificate.
Explain some new words:
Zone: The devices owned by the same owner. It can be represented by its owner. Unowned devices are allowed, it will form a zone that include it only. All devices can connect each other directly.
OOD: Owner Online Device
, The central device of a zone, it builds a star network with other devices, it assists other devices in the same zone to communicate with the other zones. And it is the centralized storage of data in the zone, running as a service(gateway) in http. It's the most important device for a zone in CYFS
, it's the personal server
for the user.
MetaChain: It is a blockchain system that maintains the consensus of each node in the CYFS network.Its implementation is not yet complete, just a conceptual version?
I will introduce the distribution of project source code files, and then introduce the main core modules one by one.
The CYFS project directory is expanded as follows:
/--CYFS
|--doc // formal design documents
|--scripts // some scripts for build/publish...
|--src // the source code, We will specifically introduce the source code directory
|--... // other files for solution: .gitignore, .eslintrc, package.json, .etc
All modules are divided into several categories and collected into corresponding directories in src
:
3rd
The main code comes from an external project, but with a few custom modifications.
component
Basic functional modules, most of which belong to this type, each implements its own functions, is referenced by other runnable instances, and has interdependence internally.
If your module will be depended on by other modules, it should be collect in component
. If part of your module will be depended on, you should split the part into a separate module.
As examples:
cyfs-base
: It's the most basic module,Almost all modules depend on it.
cyfs-core
: It defines all normalized objects
cyfs-util
: Some auxiliary modules
I will introduce them in other issues.
meta
The modules for MetaChain
, it's just a conceptual version?
I haven't dabbled in this part yet, I will introduce it in future.
service
Services in CYFS
system, They run as independent processes on various CYFS
devices.
I will introduce them in other issues.
tests
Some test cases and sample programs. We can help to supplement and improve, it's a good entrance to enter the CYFS
world, and contribute to the cause of Web3.
tools
Some tools to help users/developers to use the CYFS
. We can design more useful tools.
misc
Others.
As introduced here, there are 2 types of devices in CYFS for users and developers. They are OOD(gateway) and runtime.The relationship is as follow:
Zone A | <--> | Zone Other | ||||
---|---|---|---|---|---|---|
runtime A1 | <--> | OOD(gateway) A | OOD(gateway) O | <--> | runtime O1 | |
runtime A2 | <--> | <--> | runtime O2 | |||
runtime ... | <--> | <--> | runtime ... | |||
runtime An | <--> |
In a zone, several services is running on the OOD always. These services are running depend on the gateway
, the gateway
is also a service, It is equivalent to nginx for http, receive and forward the requests to the target services.
gateway | <--> | app-manager |
<--> | chunk-manager | |
<--> | file-manager | |
<--> | ... |
By the way, the server of a DECApp
is also running as the services on OOD. They listen to requests from clients through the gateway and respond.
Thanks @weiqiushi for the correction
cyfs-base
This is the most basic component, and almost all other components depend on it.
It implement the follow functions:
AccessString: Structures for ACL.It refers to the design of file system permission in linux.It divides users into 6 groups:
These groups can be combined arbitrarily to get the target group that the user wants to configure permissions.
And we can configure 3 permissions:
Base36: Transform the BLOB with A human-readable string ignoring case. The string will be used case-insensitively, .eg:
channel: This name is used in many occasions. Here it defines the operating environment of the CYFS system. Currently, the CYFS system has 3 operating environments:
endpoint: Encapsulation of IpAddr, It's used to connect into the network.
BuckyError: Define the Results for CYFS.
Name: As the domain for http, we can register a readable nick name for any object.
paths: The req-path(similar as the URI for http) or the path in RootState
ports: The listening ports when the CYFS
running.
protocol_fields: The HTTP
header fields, HTTP
is used at RPC
between the stack
(runtime/gateway) and the other services or DECApp
.
time: Defines various standard timestamps, and the methods to convert between them
Hash
of the content is included in the Object system
without the content itself.Body
.The Device
will be publish on the MetaChain
, Therefore,we should query the latest version from MetaChain
when we realized that it was no longer effective.desc
if the size is little enough, otherwise the content(file/chunk list) will be included in the body or in another file.If the content is not saved in desc
, there should be a hash to verify the authenticity of the content.desc
desc
body
, So,we must verify the file hash instead of the chunkids.MetaChain
or other synchronization methods.There is a issue for it.MetaChain
.blockchain
, describing a transaction itself, the main field includes:
MetaChain
.Both parties are free to withdraw their share of coins.The UionAccount
object only describes the account itself, not the current state of the account. It has 3 fields only:
MetaChain
ProofOfService
signed by the other party and submits it to MetaChain
for arbitration, and the transaction can be completed according to the contract.ObjectId
is calculate with all items, it will change when any item is updated, and we can regard the two versions before and after modification as two different objects.The ObjectMap
can express three structures:
ObjectMap
, it can be stored in a file
.Area
, and accept the legal supervision of the corresponding Area
. The Area
field is set when the object is generate, and is encoded in header 40 bits of the ObjectId
.Object
.TypelessObject
.Dir
,File
,Diff
)Object
.Desc
and Body
respectively.I think there will be some risk,You are welcome to join the discussion.ObjectDesc
with the random UniqueId
when we need to distinguish the object with same fields in ObjectDesc
:
ObjectDesc
ObjectDesc
is same, but the ObjectBody
will be update in different time.They are 2 different objects.cyfs-base-derive
Some usefull macro is implement in this crate:
cyfs-base-meta
The basic structures for MetaChain
.
cyfs-core
I mentioned 4 object categories in previous part. The Core
object is collected in the crate cyfs-core
.Many object types have been collected, most of those support the functions of the current CYFS
system.
Text
It's a common Object
to describe a String
.You can save a short(<=31Bytes) string in the ObjectId
immediately building with the ObjectIdDataBuilder
.Otherwise, you can use the Text
object.
It contains 3 fields:
Text
,fill the id
with key, and file the value
with the content, header
for other immutable annotation.Text
,fill the id
with the content, header
for immutable annotation, and value
for mutable annotation.Desc
) Text
, fill the value
with the content, and fill the id
with the hash of content to verify the value
, header
for immutable annotation.Storage
It's a common Object
to describe a binary buffer(Vec),it can describe both the immutable and mutable buffer.
It contains 3 fields:
None
if the buffer is mutable to avoid the ObjectId
is changed when the buffer is changed.app
It supports the running of the system service AppManager
,Various related entity objects and behavior objects are defined here.
Local
mean?Local
mean?There is a issue for it.The core objects for group
is implemented in cyfs-core
.
We use the blockchain structure to record the state evolution process of the Group
.The consensus algorithm is Hotstuff
.
DECApp
3 questions:
rpath
the blockchain is running on.there is a blockchain is running for each rpath
of the group
.DECApp
,it will be called with the proposal
.DECApp
.MetaChain
currently,Indicates that this proposal was made after the block on MetaChain
.DECApp
, the DECApp
guarantees its correctness. It's usefull when the params is large.blocks
for Hotstuff
.It has 2 types:
QC
.
QC
.GroupConsensusBlock
is used to describe the content of each block.rpath
the blockchain is running on.there is a blockchain is running for each rpath
of the group
.GroupConsensusBlock
, is used to verify the body
.ObjectId
of the result calculated by the DECApp
,MetaChain
currently,Indicates that this block was constructed after the block on MetaChain.Hotstuff
.Group
the block is depend on.body
, verify by body_hash
,the set of the proposals(proposal/result/receipt/context) collected by the block.body
, verify by body_hash
,the quorum certificate for the previous block.body
, verify by body_hash
,the timeout certificate for last round.nft
NFT is a popular application scenario in recent years.CYFS collect and defined its own NFT objects.In theory,any named data
is NFT
in CYFS
,but most NFTs are files in fact.So NFT is limited to file types.
trans
I don't know this part?
Body
?CyfsStack
(cyfs-stack/cyfs-stack-loader/cyfs-lib)CyfsStack integrates all functional modules provided by the CYFS system.Any service or DECApp
will call the CyfsStack
to use the CYFS
.
There are 2 solutions:
DECApp
are executed as plugins in the same process as CyfsStack.DECApp
s will be affected by exceptions thrown by any DECApp
, that is a disaster.DECApp
can easily access the memory of another.DECApp
is executed in a new process, they call the CyfsStack
through the RPC
.DECApp
with their familiar technology.DECApp
s can run independently in separate processes without interfering with each other.They can even run in separate docker
s to keep resources isolated.RPC
in different programming languages is needed.but we can use it immediatly while anyone has complete it.RPC
.RPC
RPC
HTTP
based on WebSocket
or BDT
.cyfs-base/src/base/protocol_fields.rs
.RPC
There are client and service for RPC
, the service is CyfsStack
, and the client is SharedCyfsStack
.
client | service |
---|---|
Implement in SharedCyfsStack | Implement in CyfsStack |
Multiple instances | Only one instance for one device |
Open in any DECApp process | Start with gateway(for OOD) or cyfs-runtime(for other devices) |
Public for developers of DECApp | Invisible for developers of DECApp |
Module named by cyfs-${function-name}-lib | Module named by cyfs-${function-name} |
The data will flow from the DECApp
to the processor in service.
${function-name}InputProcessor
,and the parameter with data
is named in ${function-name}InputRequest
.${function-name}OutputProcessor
,and the parameter with data
is named in ${function-name}OutputRequest
.${function-name}InputTransformer
or ${function-name}OutputTransformer
.It's flow as follow:
graph TB
subgraph DECApp
User-->Interface[SharedCyfsStack: function with FunctionOutputRequest]
end
Interface-->FindTheTarget
subgraph SharedCyfsStack
FindTheTarget[find target device]-->RPC.send[RPC.send]
end
RPC.send.->RPC.recv
RPC.send.->OtherDevice
subgraph CyfsStack
RPC.recv-->ObjectHttpListener
ObjectHttpListener-->FunctionRequestHandlerEndpoint[FunctionRequestHandlerEndpoint.call]
FunctionRequestHandlerEndpoint-->FunctionInputProcessor[FunctionInputProcessor.call_function]
FunctionInputProcessor-->FindNextProcessor[output_processor = get_forward]
FindNextProcessor-->InputOfOtherModule[input_processor]
InputOfOtherModule-->NextN[next...]
NextN-->Ending[ending_input_processor.call_function]
end
FindNextProcessor.->OtherDevice
subgraph OtherDevice.CyfsStack
OtherDevice[Other CyfsStack in different device]
end
OtherDevice.CyfsStack-.eq.-CyfsStack
We can integrate our own modules into the CYFS protocol stack according to the above framework.and you can also do it follow the issue step by step.
It implements the CyfsStack
and all processor
s to route the data for each module.It's inaccessable immediatly for DECApp
, so it will never be depended on by any DECApp
.There are some directories named in ${function-name}
or ${function-name}_api
.They are implemented with the function module:
${function-name}
: implement some basic structure, it's accessable for other modules.${function-name}_api
: it is the specific call routing logic of the function module.It implements the SharedCyfsStack
and some interface for the default function modules.It's the entry interface for DECApp
to call the CyfsStack
.So,most DECApp
will depend on this crate.
If you are extending new functionality to CYFS,It's suggested to make a new crate named in cyfs-${function-name}-lib
to instead of implement in cyfs-lib
,you can export a interface to initialize your module with the SharedCyfsStack
.
There are so many parameters to initialize the CyfsStack
, You are suggested to initialize the CyfsStack
with cyfs-stack-loader
if you want to initialize yourself, for example:
zone-simulator
.CyfsSharedStack
if you are making a DECApp
based on CYFS
. it will connect to your CyfsStack
initialized by cyfs-runtime
or gateway
.Our goal is to become http 3.0 (to be discussed).
http://192.168.100.188/path => cyfs://$wallet_addr/path
CYFS
anytime if you want.cyfs://
Now, we know some basic concepts in the CYFS
protocol, how to exchange information between the client and server, and some internal implementation principles. But there is still a little difference from http://
, that is how to use cyfs://
in browsers and html
pages.
In CYFS
, all information is an object, and cyfs://
provides a variety of ways to manipulate objects:
ObjectId
.RootState
.DECApp
.O
LinkIt's like below:
cyfs://o/$target_zone/$obj_id[?mode=json&mime=txt]
cyfs://o/$target_zone/$dir_id/$inner_path[?mode=json&mime=txt]
This protocol is the simplest and most used cyfs protocol. Since the obj_id is included in the request, the result must be credible. Since it is used the most, default parameters are used in most times to construct requests, and the FastResp mechanism of BDT is used as much as possible.
ObjectId
of the directory which we want to read.If the mode is not specified, there are different default Response Body for different types of objid. The Body of FileObject is the most special, which is a continuous binary file
.
O
LinkBatch: When requesting objB, objC..., if you know that the request is initiated after requesting objA to the same zone (Learning the source grouping of HTTP requests), unless the relevant URL has special configuration, you can ignore objB, objC O Link target_zone, but uniformly initiate batch obj requests to target_zone_A.
Client load balancing: There are CacheNodes configuration in the target_zone, the client will request CacheA, CacheB, OOD in order of distance from itself to try to get the Object.
O
LinkFor browsers, the second segment of the URL is the domain, so all O
Links are in the same domain.It means there are no cross domain issues and defense. It's a static content, and the defense is not needed.
O
LinkObjectId
to others if it's confidential.O
Link with namecyfs://eips/index.html
We can register a name for Object
to simplify the access link to Object
, and we can publish a static website like above.
zone-simulator
The zone-simulator
is a useful tool in coding. It can simulate two zones in a single process, with two built-in oods, and each ood has two devices. It is very convenient to use this tool to run multiple DECApp
instances on the local machine at the same time during the development and debugging phase. Just configure different RPC
ports to connect to different devices when each instance opens SharedCyfsStack
to access the emulator environment.
Zone1 | <--> | Zone2 | ||||
---|---|---|---|---|---|---|
People1 | People2 | |||||
Device1 | <--> | ood1 | ood2 | <--> | Device1 | |
Device2 | <--> | <--> | Device2 |
The usage is as follows(Excerpted from a previous document on the official website):
zone-simulator
derives all people and device information from mnemonics through the bip
protocol, so the same set of mnemonics generates the same zone configuration information every time.zone-simulator
is started first time, and saved in {cyfs-root}/etc/zone-simulator/mnemonic
; this configuration will be loaded each startup, if you need to create new zone desc information, then delete this configuration file.zone contains follow infomation:
zone
s respectively.zone
s respectively.zone
, and the ood in same zone constitutes an independent zone
.When the zone-simulator is started, the above information will be written into the {cyfs-root}/etc/zone-simulator/desc_list
directory, which corresponds to the mnemonic one-to-one, and the desc list generated by the same set of mnemonics will are the same, and development and testing can directly rely on this information.
For example, the mnemonic is below:
million used drastic castle during top category wood street visa steak bachelor
The generated desc list is as follows:
zone1 as follows:
people:5r4MYfFFQetBPDyeuBuDxPT7zowk9497SbpMQsZK2G19
ood:5aSixgLq9LVWbPByjRYgyjGicXtCN5S1nF1DMKZygLRE
device1:5aSixgPFg7R48VSo2b9PXcSHofK3TUFUcHnHbtmB7fJr
device2:5aSixgRaonSm1qWeCh8kNNrPGaB6pbETsqoN4Zb5Ev3H
zone2 as follows:
people:5r4MYfFGppKJXEjLvsgbKsibmTVLFZhL5cuZdEcXSr68
ood:5aSixgM12wHBfJBW1Q9n4xv1c5cu5g8hSxbrkhAQoojq
device1:5aSixgPdH5stj9pHrRVGXPNKiyrPsy8932BEr3zwFhXF
device2:5aSixgRx45jDU4Fg4ijYo3Yfo6RajtKSHgnGCVJUnk65
The above device_id and people_id can be directly used as the target of router and other interfaces to interact with the corresponding protocol stack.
For example, put_object to ood1
:
const ood1 = DeviceId.from_base_58('5aSixgLq9LVWbPByjRYgyjGicXtCN5S1nF1DMKZygLRE').unwrap();
const target = ood1.object_id;
stack.put_object({
...,
target
})
You can directly use the people_id of zone1 as the target:
const people1 = PeopleId.from_base_58('5r4MYfFFQetBPDyeuBuDxPT7zowk9497SbpMQsZK2G19').unwrap();
const target = people1.object_id;
stack.put_object({
...,
target
})
RPC
2 zones, each zone contains 1 ood + 2 devices, so there are six stacks in total. In order to facilitate external sdk calls, fixed ports are used, and the allocation is as follows:
device | bdt-port | http-port | ws-port |
---|---|---|---|
zone1-ood1 | 20001 | 21000 | 21001 |
zone1-device1 | 20002 | 21002 | 21003 |
zone1-device2 | 20003 | 21004 | 21005 |
zone2-ood1 | 20010 | 21010 | 21011 |
zone2-device1 | 20011 | 21012 | 21013 |
zone2-device2 | 20012 | 21014 | 21015 |
The http-port
and ws-port
can be used as the service interface of the local SharedObjectStack, we can open SharedObjectStack
directly with them, and pass it to the corresponding interface.
For example, if you want to use the protocol stack of zone1-device2, you can open SharedCyfsStack
as follow:
const param = SharedObjectStackParam.new_with_ws_event_ports(21004, 21005).unwrap();
const stack = SharedObjectStack.open(param);
await stack.online();
The above two zones can simulate most of the interaction scenarios in cyfs:
zone
(zone1 or zone2).There are 2 commands, and some auxiliary information can be generated:
shell> zone-simulator.exe --random
random mnemonic as follows:
side act dilemma super open tonight shallow wrong brother various potato punch
people/ood/device
generated by the current mnemonic, and save it in the default directory {cyfs}/etc/zone-simulator/
, user1 indicates the information related to zone1, and user2 indicates the information related to zone2. These information can be placed under {cyfs}/etc/desc
for direct use by gateway
, runtime
or zone-stack etc.After solving most of the errors in the zone-simulator
environment, We can deploy the project to the test environment and start testing:
nightly
and beta
, and the stable environment has not yet been launched. The target environment for deployment depends on the environment of cyfs-tool
, cyfs-runtime
and OOD
, they must be the same environment, either nightly
or beta
.cyfs deploy
command is used to deploy a project, It should run in the same directory as the project file cyfs.config.json
, it will take a long time. Here we introduce the contents of the cyfs.config.json
file in detail:{
"app_name": "your project name",
"version": "1.0.0", // version with 3 fields
"description": "descript your project",
"icon": "url for your icon that has published.cyfs://",
"service": { // configuration for service
"pack": ["directory1", "directory2", "..."], // A list of directories for source code in server-side, which will be packaged together using same relative paths
"type": "node", // type of your project: nodejs or native
"dist_targets": ["x86_64-pc-windows-msvc", "x86_64-unknown-linux-gnu"], // target os
"app_config": {
"default": "service_package.cfg" // configuration for service, introduce later
},
"app_dependent_config": {
"default": "dependent.cfg" // Dependent configuration, which may depend on other `DECApp`
},
"app_acl_config": {
"default": "acl.cfg" // The permissions required by `DECApp`, and the permissions configuration opened to others
}
},
"web": { // configuration for web
"folder": "src/www/dist", // Directory of the source code for web
"entry": "index.html" // Entry webpage
},
"dist": "dist", // The directory for the packaged resources
"owner_config": ".cyfs\\owner.json", // Owner of `DECApp`, which will be generated when using `cyfs-tool` to build the project, usually configures the identity file exported by the developer environment. It can be modified with the `cyfs modify` command, but it will become a new project after the change, and all information including `DecAppId` and historical versions will be changed, pay attention to synchronously modify related configurations.
"ext_info": {
"cyfs-app-store": { // Configuration displayed on `AppStore`
"tag": ["tag1", "tag2", "..."], // Add some tags
"community": ["your community name"],
"releasedate": {
"1.2.20": "2022-11-14" // the version history
}
}
},
"app_id": "9tGpLNna8UVtPYCfV1LbRN2Bqa5G9vRBKhDhZxxxxxxx", // your `DecAppId`
"config_version": 1 // version of the format used by the config file?
}
Fields of service_package.cfg
as follow:
{
"id": "your readable project name", // unique?
"version": "1.0.0", // verison with 3 fields
"install": ["cmd1", "cmd2", "..."], // Commands in order for install the `DECApp`
"start": "command", // Command to start the `DECApp`
"stop": "command", // Command to stop the `DECApp`
"status": "command", // Command to query the status the `DECApp`
"executable": [] // ?
}
You can execute cyfs deploy
to publish your DECApp
after the above information is configured correctly. The URL
to install DECApp
will show in the last line. Now others can also get your latest version. **If you are not ready for others, you can separate the development People
from the publish People
, and use the People
environment to deploy your DECApp
. **
AppStore
on the browser, and install the DECApp
with the URL
generated by cyfs deploy
. Now you can use and check that your DECApp
works correctly.In the personal property rights environment, all calculations are completed on the user's personal server (OOD
), it is still a centralized system, and we can optimize concurrency and throughput like the central server of Web2
. However, personal servers are only used to process self
information. and the workload in central server of Web2
has been distributed actually to many personal servers of Web3
, and the problems have been naturally alleviated.
Shared property rights are based on blockchain technology, and the process of blockchain consensus is serial; it is difficult to meet the high concurrency requirements in many Web2
application scenarios.
We can use multiple chains to improve the concurrent processing capability of shared property rights. In other words, we can optimize the design to disperse information in multiple rpath
.
For example: a DAO
organization manages the information of all its users.
Its structure based on RootState
should be as follows:
/--users
|--user1
| |--...
|--user2
| |--...
|--...
|--userN
All information of every user must be updated serially if there is only one chain. In fact, users are not related to each other in most time, we can update B
without waiting for A
.
Then, we try to start a chain for each user, manage the branch of each subpath with a consensus chain (rpath
):
/users/user1
/users/user2
...
/users/userN
There is a small problem here. We also need to manage the user list jointly. In fact, the status of each user has reached a consensus, the rpath
list maintained by this organization can express the current user list in most time. However, there is no strict consensus chain to maintain it, the rpath
list in each node may be inconsistent for some abnormalities, and there is no historical record of updates. If your application is very sensitive to these issues, you need to design another rpath
(/users/list) to maintain the user list, and you need to design carefully for the consistency between its content and the rpath
list.
Now, does it feel familiar to server engineers in the Web2
era? Yes, it is actually similar to the divide-table
and divide-database
that are often used in Web2
, but the form has changed. I will not go into specific details for lack of experience.
Every one needs to protect secret information from being accessed, and CYFS
is an open platform, and anyone has the opportunity to read the information stored on it. The best way to protect privacy is not to deal with other people, and sensitive information is not shown to others. In CYFS
, it is necessary to protect the ObjectId
of sensitive information. Once someone else gets your ObjectId
, it is possible to get the object content itself. This is very important, and it should be regarded as a principle for using CYFS
. Information can be leaked in many ways:
DECApp
s may deliver it on purpose or accidentally. Therefore, We should try our best to install DECApp
from a reliable source, and even read the source code and build DECApp
by ourselves.It's too difficult to distinguish and prevent dangerous behaviors by users themselves. Therefore, CYFS
provides a permission system to help users manage private data. The user can prohibit all DECApp
except the system DECApp
from accessing an object, and can also prohibit any other user from actively accessing an object. No one can read the object content without permissions even if the ObjectId
is leaked. As a basic system, CYFS
provides a flexible methods to config the permissions, which can only open partial access permissions for specific trusted users or DECApp
; of course, the author cannot prevent Object
from continuing to propagate after it has been displayed to others, It's also unpreventable in real world.
Let me emphasize again that users should try their best to abide by the confidentiality principle mentioned above. The system can only provide auxiliary management capabilities and cannot be used as the final guarantee.
I will describe the design of the CYFS
permissions (hereafter referred to as ACL
) system as follow.
If no permissions are configured for an Object
, the default permissions are effective as follows:
If the Owner
of Object
is not itself, anyone has the full permissions.
If the request is from the current Zone
or a friend Zone
, and the source DECApp
is same as the DECApp
that constructs Object
, the request will be granted.
It's important to add friends cautiously!
Otherwise the request will be prevented.
Currently, CYFS
already supports several ways to configure ACL
:
req_path
field of the request:
DECApp
.RootState
subtree, and its lower-level subtrees also apply the same permission configuration, unless the lower-level subtrees are configured otherwise.rmeta
).The rules are hit one by one in above order, and the permission configuration with the highest matching degree is found and applied. If you still remember the architectural design of CyfsStack
, the ACL
system is a Processor
in it, and the implementation code is in src\cyfs-stack\src\non_api\acl
.
ACL
can be statically configured by app-manager
to read the acl
configuration in the installation package when DECApp
is installed. For the specific configuration method, refer to the app_acl_config
field of the cyfs.config.json
file.
The file is used to configure the permissions that the app needs and awarded to others by the app. This file will be read by app-manager
when the app is installed, and the corresponding permissions will be registered with the system according to the configured values.
A complete permission configuration file is shown as follows:
[self]
[self.access] // Grant permissions to your own data by path
// /test3 by each alone group
"/test3" = [{group = "OthersDec", access = "-wx"}, {group = "CurrentDevice", access = "---"}]
// complete string, set/clear each bits for each group
"/test2" = "rwxrwxrwx---rwx---"
"/test1" = "rwxrwxrwx---rwx--x"
[self.specified] // Authorize your own data to the specified DECApp or user
"/test3" = {access = "--x", dec_id = "9tGpLNnDpa8deXEk2NaWGccEu4yFQ2DrTZJPLYLTxxxx"} // The specified DECApp running on any zone can call the specified path.
"/test2" = {access = "--x", zone_category = "current-zone", dec_id = "9tGpLNnDpa8deXEk2NaWGccEu4yFQ2DrTZJPLYLTxxxx"} // The specified DECApp running on the specified zone can call the specified path.
"/test1" = {access = "--x", zone = "5aSixgLwnWbmcDKwBtTBd7p9U4bmqwNU2C6h6SCvxxxx"} // Any DECApp running on the specified zone can call the specified path.
// Request authorization from a specified DECApp(DECID_A)
[DECID_A.specified]
// The `dec_id` field in SpecifiedGroup will never be set, otherwise the rule will be discarded.
"/test3" = {access = "--x"} // Apply for the permission to call the specified path.
"/test2" = {access = "--x", zone_category = "current-zone"} // Apply for the permission to call the specified path limited in the specified zone("current-zone").
"/test1" = {access = "--x", zone = "5aSixgLwnWbmcDKwBtTBd7p9U4bmqwNU2C6h6SCvxxxx"} // Apply for the permission to call the specified path limited in the specified zone("5aSixgLwnWbmcDKwBtTBd7p9U4bmqwNU2C6h6SCvxxxx").
[DECID_A.config] // **None currently?**
This file is structured in toml
format, where each section represents authorization in the same direction, and the section name rules are as follows:
${SectionName} = ${dec_id}[.access|specified|config]
DecAppId
that needs to provide permissions. If it is the current DecAppId
(can be replaced by self
), it means that the permission is open to others, otherwise, it means that the current DECApp
needs the permissions from the specified DECApp
.DECApp
, Zone
, etc.), key
is the request path, which can be the path of RootState
, or the value of req_path
in the request. It can manage permissions more granularly than access
The content of each line is as follows:
${SectionRow} = ${key} = ${AccessString} | ${SpecifiedGroup}
${key}: request path, which can be the path of RootState
, or the value of req_path
in the request.
AccessString
: Indicates the complete permission corresponding to a path. Refer to the file system permission in linux. A set of specific permissions is represented by 3 bits. A total of 6 groups of 18 bits represent a complete permission, and each bit represents the authorization of the corresponding group.
There are 3 permissions currently: Read/Write/Call:
pub enum AccessPermission {
Call = 0b001, // 用`x`表示
Write = 0b010, // 用`w`表示
Read = 0b100, // 用`r`表示
}
And there are 6 groups divided according to device and DECApp
:
pub enum AccessGroup {
CurrentDevice = 0,
CurrentZone = 3,
FriendZone = 6,
OthersZone = 9,
OwnerDec = 12,
OthersDec = 15,
}
Now, there are 2 methods to represent an AccessString
in a configuration file:
Example: Full permissions for
OwnerDec
inCurrentDevice | CurrentZone
,read | write
permissions forOwnerDec
inFriendZone
, and read permission forOthersDec
inOthersZone
. We can express it as "rwxrwxrw-r--rwxr--"; it is equivalent to "rwx rwx rw- r-- rwx r--" or "rwx_rwx_rw-_r--_rwx_r--".
{group, access}
, group
is the enumeration name of AccessGroup
, and access
is a 3-chats "rwx-" string.
- Default
AccessString
permission: "rwxrwxrwx---rwx"- Still take the above permissions as an example, expressed as
[{group = "FriendZone", access = "rw-"}, {group = "OthersZone", access = "r--"}, {group = "OthersDec" , access = "r--"}]
SpecifiedGroup
: The permissions of a specific DECApp
, Zone
, or zone_category
, the difference from AccessString
is that AccessString
can only configure permissions for each group, and SpecifiedGroup
can limit permissions into a specific DECApp
or Zone
.
There are 4 fields:
access
: Permission configuration, which is a 3-chats "rwx-" string
zone
: ZoneId
of the Zone
which the permission is applied to. Here, it is usually filled with the PeopleId
of Zone
. You can also fill in a DeviceId
, indicating that it is limited to a specific Device
. We can remove the field to match any device.
zone_category
: The group of zone
this permission will be applied to, if not filled, it means for any devices. Can take one of the following values:
I found that the zone_category is words with hyphen
, it's different with it in AccessGroup
for AccessString
. can we use the same style?
dec_id
: DECApp
which this permission applies to, if not filled, it means for any DECApp
s.
Among the 4 fields, access
is required, and zone
, zone_category
, and dec_id
must be filled in at least one. The permission will be passed when all the three conditions of zone
, zone_category
, and dec_id
are matched.
We can config the ACL
statically by app-manager
to read the acl
configuration in the installation package when DECApp
is installed. And we can also config it dynamically by calling SharedCyfsStack
when the DECApp
is running. The entry point of the dynamic configuration interface is:
let meta: GlobalStateMetaStub = SharedCyfsStack.root_state_meta_stub();
GlobalStateMetaStub
provides different interfaces for various configuration methods. I will introduce as follow.
req_path
constraintsreq_path
, the core structure is designed as follows:pub struct GlobalStatePathAccessItem {
// GlobalState path, must end with /
pub path: String,
// Access value, it's a `AccessString` as uint32, or a SpecifiedGroup
pub access: GlobalStatePathGroupAccess,
}
path
as key
to delete the parameter specified permission.rmeta
constraintspub struct GlobalStateObjectMetaItem {
// Object dynamic selector: `${key} ${operator} ${value}`
pub selector: String,
// Access value
pub access: GlobalStatePathGroupAccess,
// Object referer's depth, default is 1
pub depth: Option<u8>,
}
We can use the following operators in selector
:
`==`, `!=`, `<=`, `>=`, `<`, `>`, `&&`, `||`, `&`, `^`, `|`, `!`.
The key
and corresponding value
are as follows:
key | type | value |
---|---|---|
obj_type_code | u16 | ObjectTypeCode enum int values |
object_category | string | ObjectCategory enum values |
obj_type | u16 | value of obj_type |
object.dec_id | string | ObjectId |
object.author | string | ObjectId |
object.owner | string | ObjectId |
object.create_time | u64 | bucky time |
object.update_time | u64 | bucky time |
object.expired_time | u64 | bucky time |
insert_time | u64 | bucky time |
update_time | u64 | bucky time |
selector
as key
, delete the permission specified by the parameter.object_id
constraintsaccess
parameter directly when put_object
is called, if you want to change it, call put_object
again.How to choose a method to config the permission, I suggest as follow:
You should write it clearly in the static configuration file if you want to grant permissions to the others (other DECApp
or Zone
); dynamic configuration in the program is more difficult to maintain. You can use dynamic configuration
if the static configuration file can not do it.
You must write it in this configuration file and let app-manager
register during installation, if you want to request permissions from other DECApp
. There is no way to register dynamically in code.
You must use the specified
section to request permissions from other DECApp
, anything in the access
field is ignored.
There is no way to request permissions from other zone
.
There are many entities in the world other than people,family,club,company,country,etc.They are organizations made up of many people,the people are related, or they have the same purpose or hobby.They have common assets and often have to make resolutions on matters.They also have personal positions and interests.
There are many solutions for web2:
Github
Discord
The data stored in the IT
system by these organizations should be owned by themself. Members of these organizations share the property rights of these data, and they jointly manage the data status (addition, update, deletion and query).
In the web3 era, we need a decentralized solution to make sure the users to obtain more autonomy and more certain rights and interests. Blockchain provides us with a good idea.We can make these applications run on a Consortium Blockchain
.
A
LinkIt's like below:
cyfs://$version_name.$dec_id.a/$inner_path[?mode=json&mime=txt]
We can send a request to the specified DECApp
with specified version in current Zone
.
.
included) registered on MetaChain for a product, It's also can be a hash.R
LinkThe domain of A Link
is related to $version_name
and $dec_id
, similarly as R Link
, there are cross domain issues and defense, we need to open relevant permissions to the clients of DECApp
.
From the previous introduction to the scenario of Shared Property Rights
, it is not difficult to see that the key issues is:
Consortium Blockchain
simply and cheaply?Define standard Object
s for CYFS
users to ensure they representing in the same way.
Use the BDT
protocol to ensure the interconnection between CYFS
users, even users under NAT, and protect privacy through protocol encryption.
Provide a basic consensus framework to ensure that all proposals are received, executed and verified in a unified order.The DECApp
developers only need to define the implementation and verification methods of proposals according to their needs,it's a Smart Contract
.
For the ending user,They only need to complete the operation following the guidance of DECApp
:
Group
.proposal
.proposal
.proposal
as a vote.DECApp
.The follow sequence diagram will show a common flow for a proposal.
%% 时序图例子,-> 直线,-->虚线,->>实线箭头
sequenceDiagram
participant User
participant CYFS
participant DECApp
User->>CYFS: post(proposal)
CYFS->>DECApp: on_execute(proposal,last_result)
DECApp->>DECApp: result=execute(proposal,last_result)
DECApp-->>CYFS: result
CYFS->>CYFS: broadcast(proposal,result) to other members
CYFS->>DECApp: on_verify(proposal,last_result)
DECApp->>DECApp: is_ok=verify(proposal,last_result)
DECApp-->>CYFS: is_ok
CYFS-->>User: finish(result,is_ok)
A vote on a proposal is a proposal that depends on the original proposal,and its execution process is exactly the same as the general proposal.
A proposal that requires voting, from the original proposal to the formation of the final resolution, the implementation process is as follows.
%% 时序图例子,-> 直线,-->虚线,->>实线箭头
sequenceDiagram
participant User
participant CYFS
participant DECApp
User-->>DECApp: post(proposal)
DECApp->>DECApp: result_proposal_list=add(proposal,last_proposal_list)
DECApp-->>CYFS: result_proposal_list
User->>CYFS: proposal_list = get_voting_proposals()
CYFS-->>User: proposal_list
User->>User: vote=make_vote(proposal_list.select(),voter=self)
User-->>DECApp: post(vote)
DECApp->>DECApp: all_votes=collect_votes(vote)
DECApp->>DECApp: is_enough=check(all_votes)
DECApp->>DECApp: if is_enough {result=decide()}
DECApp->>DECApp: if !is_enough {result=add(vote,last_vote_list)}
DECApp-->>CYFS: result
We can find that the working mode for users and developers hasn't changed substantially against Web2
, there are only some differences in form:
Web2
era, the database is directly updated when the proposal is executed after the user has been authenticated.CYFS
, there is an additional verification stage before the proposal execution results take effect. Usually, each node executes it once to compare whether the respective calculation results are the same.And, all cyfs://
protocols will support the Group
as a Zone
,the same interface will be provided as People
,so,it will work in the same way for People
zone.
Hotstuff
I will introduce Hotstuff
briefly. Please refer to the professional literature if you want to learn more about it.
Hotstuff
is a type of BFT
consensus algorithm:
f
;N
.v
;n
, in the worst case, all malicious nodes also participated in the vote, n > f
;N - v
, n > N - v
;$$
\begin{cases}
\ v >= n + f; => min(v) = n + f => min(v) = min(n) + f \
\ n > f; => min(n) = f + 1 \
\ n > N - v; => max(N) = n + v - 1 \
\end{cases}
=>
\begin{cases}
\ min(v) >= 2f + 1; \
\ n + v > N; => min(n) + min(v) > N \
\end{cases}
=> N < f + 1 + 2f + 1 = 3f + 2; \
=> N <= 3f + 1
From the above calculations, we can prevent malicious nodes accounting for up to 1/3(excluding) of the total when we collect signatures from more than 2/3(excluding) nodes.
PBFT
PBFT
is the first available BFT
algorithm, and its basic process is:
sorting
, executing
, packaging
, blocking
for all proposals;2f+1
signatures are collected, and broadcasts the vote to all other nodes again;2f+1
2nd signatures are collected;2f+1
2nd signatures are collected.** Here, it is required to collect 2f+1
signatures twice, because each node must ensure that 2f+1
nodes have received votes, so that they can recover in the event of a failure. **
View change:
There should be a mechanism to change the master when the master node does evil or fails, otherwise the activity of the system cannot be guaranteed.
The current running state of all nodes is a view
, and the process of changing the master node is view change
:
view change
request;view change
, and attach the block vote with the highest signature height of 2f+1
; then broadcast to other nodes;view change
again;Hotstuff
Hotstuff
optimizes PBFT
in several pionts:
Pipelining: the vote for each block is also the confirmation of the next state of the previous block, and the whole process only has two broadcasts per block on average (2*n, block broadcast and voting);
Simplify the state machine: the view change process is subtly integrated into the block consensus process, and the view change process only changes the node responsible for collecting votes for the next block;
All information based on CYFS
can choose one of the following three encoding methods. Both Protobuf
and JSON
have their standard encoding specifications. I won’t go into details here. We only introduce the binary encoding format.
Binary
Binary format encoding, usually used for standardized fixed encoding, the most space-saving, but not easy to expand.
When binary encoding is selected, the type designer needs to fill all fields into a Buffer
one by one in a certain order.
Protobuf
Using Protobuf
encoding, while taking into account certain space efficiency and scalability, this is the encoding method selected by most complex types.
When using Protobuf
encoding, the type designer only needs to assign each field of the object to the corresponding Protobuf
type, and then use the Protobuf
method to encode and decode. Compatibility processing needs to refer to the Protobuf
specification.
** Note: The Protobuf
specification we chose is Proto3
, considering backward compatibility, the Protobuf
version is unlikely to be upgraded. Of course, other versions can be selected for the type of new design, but different versions need to be carefully introduced. **
JSON
Encoded in JSON
, which is less space efficient but more readable.
Because of its low space efficiency, the JSON
method is usually not selected to encode and decode information. JSON
encoding usually appears in the scene of human-computer interaction.
** No matter which encoding method you choose, you must pay attention to the stability of the encoding when you use it for object encoding (for example: Set
and Map
should pay attention to the order of each element), otherwise the ObjectId
obtained by calculating the same content multiple times may be different. **
I want to collect and organize various information encoding formats in the CYFS
protocol in this document. By reading this article, you can gain the ability to:
In the web2
era, any information is read from a central server, you can trust any information from it as you trust the source server. It is very simple.
But in the web3
era, for decentralization, all information comes from servers provided by someone. For single owned information, we can trust it with the signature from owner as proof of accountability. As for shared property rights information, we can only obtain information from one of the members, and these members are likely to falsify information for their interests. Therefore, we need a verification method for the shared property rights information.
As mentioned in the previous article, we use Hotstuff
as the consensus algorithm for sharing property rights. Naturally, we also adopt the corresponding verification strategy with 2f+1
signature rate.
block
Every block
on the chain can be verified by any node. We use the BFT
consensus algorithm. Each valid block
holds the voting signatures of 2f+1
nodes naturally, so all the fields contained in the block
are recognized, the field result_state_id
is the ObjectId
of the state of property rights information.
ObjectId
We known earlier that result_state_id
is a tree structure object implemented by ObjectMap
; result_state_id
is obtained by computing Hash
from all branches and leaf node values in this tree.
Therefore, all branch and leaf node values of result_state_id
are trusted.
However, we must read the full Desc
(immutable part) of the Object
to verify if an Object
is matched with the ObjectId
, in other words: we must read all elements of ObjectMap
and compare their Hash
with result_state_id
to verify that one of the elements is correct.
Now, it's clear that we must verify ObjectMapId
of a branch in each level to verify the sub-field in a tree specified by a path. A flowchart is as follow:
flowchart TB
Init(path, state_id) --> IsEmptyPath{path is empty}
IsEmptyPath --no--> Read["obj_map = get(state_id)"]
IsEmptyPath --yes--> Found(return state_id)
Read --> Verify["state_id = ObjectId(obj_map)"]
Verify --> NextPath["sub_paths=split(path,'/');\nnext_path=sub_paths[0];\npath=sub_paths[1..].join('/');"]
NextPath --> NextState["state_id = obj_map.get(next_path)"]
NextState --> IsExistState{state_id == None}
IsExistState --yes--> None(return None)
IsExistState --no--> IsEmptyPath
We can see that we must read the full content of the first-level subdirectory contained in each level of directory to verify a child node specified by the path in the tree:
flowchart TB
Root --> P_1_1[p.1.1]
Root --> P_1_2[p.1.2]
Root --> P_1_3[p.1.3]
Root --> P_1_x[...]
Root --> P_1_f1[folder.1]
Root --> P_1_x1[...]
P_1_f1 --> P_2_1[p.2.1]
P_1_f1 --> P_2_x[...]
P_1_f1 --> P_2_f2[folder.2]
P_1_f1 --> p_2_x[...]
P_2_f2 --> P_x_x[...]
P_x_x --> P_n_fn[folder.n]
We stated a complete state verification scheme above, but there is a problem that we must read a large amount of redundant data for a specified field of a shared property right information. It is an impossible task in a scenario with a large data.
I think there are several solutions:
Design each rpath
(representing a consensus unit in a shared property rights) carefully so that its capacity is small, and divide the large container structures into segments for management (for example: every 16 is a segment).
Add 2f+1
signatures to the result of each request. The server returns only the specified field(0 redundancy) for each status request, but servers owned by members of the organization must sign on the field. Of course, the burden on the service node will be increased for signatures, the more queries, the more signatures.
I want to finish the documents to introduct CYFS
for developers. you can develop your own DECApp, or join the team to improve the CYFS
protocol.
I have create a repository for it. Anyone can raise an issue in the repository to help me to complete it.
Following is the table of contents:
cyfs-base
cyfs-core
CyfsStack
Group
cyfs://
Protocolcyfs://o/
cyfs://r/
cyfs://a/
I want to finish the documents to introduct CYFS
for developers. you can develop your own DECApp, or join the team to improve the CYFS
protocol.
I have create a repository for it. Anyone can raise an issue in the repository to help me to complete it.
Following is the table of contents:
cyfs-base
cyfs-core
CyfsStack
Group
cyfs://
ProtocolA declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.