This type is allocated on the heap and as such is able to store an amount of text that is unknown to us at compile time.

#![allow(unused_variables)]
fn main() {
let s = String::from("hello");
}
#![allow(unused_variables)]
fn main() {
let mut s = String::from("hello");

s.push_str(", world!"); // push_str() appends a literal to a String

println!("{}", s); // This will print `hello, world!`
}

release memory


#![allow(unused_variables)]
fn main() {
{
let s = String::from("hello"); // s is valid from this point forward

// do stuff with s
} // this scope is now over, and s is no
// longer valid
}

There is a natural point at which we can return the memory our String needs to the operating system: when s goes out of scope. When a variable goes out of scope, Rust calls a special function for us. This function is called drop, and it’s where the author of String can put the code to return the memory. Rust calls drop automatically at the closing curly bracket.

#![allow(unused_variables)]
fn main() {
let s1 = String::from("hello");
let s2 = s1; //Rust considers s1 to no longer be valid
}
6898585a.png 130473ca.png

actually is a move operation
7e400833.png

deep copy use clone

#![allow(unused_variables)]
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone();

println!("s1 = {}, s2 = {}", s1, s2);
}

return value and scope

fn main() {
let s1 = gives_ownership(); // gives_ownership moves its return
// value into s1

let s2 = String::from("hello"); // s2 comes into scope

let s3 = takes_and_gives_back(s2); // s2 is moved into
// takes_and_gives_back, which also
// moves its return value into s3
} // Here, s3 goes out of scope and is dropped. s2 goes out of scope but was
// moved, so nothing happens. s1 goes out of scope and is dropped.

fn gives_ownership() -> String { // gives_ownership will move its
// return value into the function
// that calls it

let some_string = String::from("hello"); // some_string comes into scope

some_string // some_string is returned and
// moves out to the calling
// function
}

// takes_and_gives_back will take a String and return one
fn takes_and_gives_back(a_string: String) -> String { // a_string comes into
// scope

a_string // a_string is returned and moves out to the calling function
}

return multiple value use tuple

fn main() {
let s1 = String::from("hello");

let (s2, len) = calculate_length(s1);

println!("The length of '{}' is {}.", s2, len);
}

fn calculate_length(s: String) -> (String, usize) {
let length = s.len(); // len() returns the length of a String

(s, length)
}

slice

#![allow(unused_variables)]
fn main() {
let s = String::from("hello world");

let hello = &s[0..5];
let world = &s[6..11];
}

The start..end syntax is a range that begins at start and continues up to, but not including, end. If we wanted to include end, we can use ..= instead of ..:

#![allow(unused_variables)]
fn main() {
let s = String::from("hello world");

let hello = &s[0..=4];
let world = &s[6..=10];
}

official Learn Rust

basic concept

trait

variables

by default variables are immutable

let vairable:i32 = 100;

pattern destructure

模式解构声明

Shadowing

变量遮蔽

fn main() {
let x = 5;

let x = x + 1;

let x = x * 2;

println!("The value of x is: {}", x);
}

mutable

following is mutable code use mut indicate

let mut x = 5;
println!("The value of x is: {}", x);
x = 6;
println!("The value of x is: {}", x);

difference with constant

  • Not allowed use mut with constants
  • Declare constants with const keyword, and the type of the value must be annotated
  • Constants can be declared in any scope
  • The last difference is that constants may be set only to a constant expression, not the result of a function call or any other value that could only be computed at runtime.

raw identifiers

Sometimes, you may need to use a name that’s a keyword for another purpose. Maybe you need to call a function named match that is coming from a C library, where ‘match’ is not a keyword. To do this, you can use a “raw identifier.” Raw identifiers start with r#:

let r#fn = "this variable is named 'fn' even though that's a keyword";

// call a function named 'match'
r#match();

Data Types

Scalar Types

A scalar type represents a single value.

Rust has four primary scalar types: integers, floating-point numbers, Booleans, and characters

integers

Length Signed Unsigned
8-bit i8 u8
16-bit i16 u16
32-bit i32 u32
64-bit i64 u64
128-bit i128 u128
arch isize usize

Additionally, the isize and usize types depend on the kind of computer your program is running on: 64 bits if you’re on a 64-bit architecture and 32 bits if you’re on a 32-bit architecture.

Number literals Example
Decimal 98_222
Hex 0xff
Octal 0o77
Binary 0b1111_0000
Byte (u8 only) b’A’

floating-point numbers

fn main() {
let x = 2.0; // f64

let y: f32 = 3.0; // f32
}

boolean

true or false that’s a question

characters

Rust’s char type represents a Unicode Scalar Value, which means it can represent a lot more than just ASCII.
Accented letters; Chinese, Japanese, and Korean characters; emoji; and zero-width spaces are all valid char values in Rust. Unicode Scalar Values range from U+0000 to U+D7FF and U+E000 to U+10FFFF inclusive.

fn main() {
let c = 'z';
let z = 'ℤ';
let heart_eyed_cat = '😻';
}

compound types

Compound types can group multiple values into one type. Rust has two primitive compound types: tuples and arrays.

Tuples

A tuple is a general way of grouping together some number of other values with a variety of types into one compound type. Tuples have a fixed length: once declared, they cannot grow or shrink in size.

fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
}

access data

fn main() {
let tup = (500, 6.4, 1);

let (x, y, z) = tup;

println!("The value of y is: {}", y);
}
fn main() {
let x: (i32, f64, u8) = (500, 6.4, 1);

let five_hundred = x.0;

let six_point_four = x.1;

let one = x.2;
}

Array Type

arrays in Rust have a fixed length, like tuples.
Arrays are useful when you want your data allocated on the stack rather than the heap

fn main() {
let a = [1, 2, 3, 4, 5];
}

Arrays have an interesting type; it looks like this: [type; number]. For example:

#![allow(unused_variables)]
fn main() {
let a: [i32; 5] = [1, 2, 3, 4, 5];
}

invalide element access

fn main() {
let a = [1, 2, 3, 4, 5];
let index = 10;

let element = a[index];

println!("The value of element is: {}", element);
}

The compilation didn’t produce any errors, but the program resulted in a runtime error and didn’t exit successfully. When you attempt to access an element using indexing, Rust will check that the index you’ve specified is less than the array length. If the index is greater than the length, Rust will panic.

functions

Rust code uses snake case as the conventional style for function and variable names.

fn main() {
another_function(5, 6);
}

fn another_function(x: i32, y: i32) {
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}

return value use ->

fn main() {
let x = plus_one(5);

println!("The value of x is: {}", x);
}

fn plus_one(x: i32) -> i32 {
x + 1
}

comments

same to c language.

// one line comment
/*
block Comments
block Comments
*/

Doc comments which are parsed into HTML library


control flow

if

fn main() {
let number = 3;

if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}

fn main() {
let number = 6;

if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else if number % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
}

using with let
Because if is an expression, we can use it on the right side of a let statement

fn main() {
let condition = true;
let number = if condition {
5
} else {
6
};

println!("The value of number is: {}", number);
}

loops

loop

The loop keyword tells Rust to execute a block of code over and over again forever or until you explicitly tell it to stop.

fn main() {
let mut counter = 0;

let result = loop {
counter += 1;

if counter == 10 {
break counter * 2;
}
};

assert_eq!(result, 20);
}

while

fn main() {
let mut number = 3;

while number != 0 {
println!("{}!", number);

number = number - 1;
}

println!("LIFTOFF!!!");
}

for

fn main() {
let a = [10, 20, 30, 40, 50];

for element in a.iter() {
println!("the value is: {}", element);
}
}
fn main() {
for number in (1..4).rev() {
println!("{}!", number);
}
println!("LIFTOFF!!!");
}

macro system

macros look like functions, except that their name ends with a bang !
Rust macros are expanded into abstract syntax trees, rather than string preprocessing, so you don’t get unexpected precedence bugs.

// This is a simple macro named `say_hello`.
macro_rules! say_hello {
// `()` indicates that the macro takes no argument.
() => (
// The macro will expand into the contents of this block.
println!("Hello!");
)
}

fn main() {
// This call will expand into `println!("Hello");`
say_hello!()
}

naming convention

Constants

use all uppercase with underscores between words

#![allow(unused_variables)]
fn main() {
const MAX_POINTS: u32 = 100_000;
}

引用依赖库

packages from crate.io

Cargo.toml 里面添加

[dependencies]
webbrowser = "0.2.2"

在rust源文件中引入 crate。

extern crate webbrowser;

packages from git repository

如果不加branch=”next”,则默认获取最新的commit,当然可以用rev、tag、branch来指定不同的版本。

[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand", branch = "next" }

packages from local path

如果不加version=”0.1.0”,则不会进行版本检查。

[dependencies]
my_crate_name = { path = "../my-crate-directory", version = "0.1.0" }

package version

版本号还可以有另外一种crate格式,这种格式^x.y.z允许升级到与要求版本号兼容的最新版本上。

^1.2.3 := >=1.2.3 <2.0.0
^1.2 := >=1.2.0 <2.0.0

版本号还支持另一种Tilde格式,这种格式~x.y.z指定了最低版本号要求。

~1.2.3 := >=1.2.3 <1.3.0
~1.2 := >=1.2.0 <1.3.0
~1 := >=1.0.0 <2.0.0

版本号支持通配符。

* := >=0.0.0
1.* := >=1.0.0 <2.0.0
1.2.* := >=1.2.0 <1.3.0

update a project with dependencies

cargo update

prepare development environment

use vscode 1.63.0 rust 1.57.0
rust

# 大写的 V
rustc -V
cargo -V
  1. create a new project cargo new hello-rust
    This will generate a new directory called hello-rust
    use cargo run compile and run project

use cargo check check code but not generate binary
build for release cargo build --release

making a binary program
cargo new hello_world --bin
making a library
cargo new hello_world --lib

  1. Adding dependencies

You can find all sorts of libraries on crates

in Cargo.toml add

[dependencies]
ferris-says = "0.1"

run cargo build

EOS(Graphene)

解决了哪些问题:

  1. 应用性能低 (石墨烯技术)
  2. 安全性差 (DPOS 共识算法)
  3. 开发难度高
  4. 手续费高

EOS(Graphene) vs Ethereum

Ethereum Design

Design philosophy

3e7b4345.png

Ethereum has no common functions. It’s a common platform
EOS has build-in common functions like crypto, database save development time and effort

Consensus & Governance

6cb6e98b.png

Scalability

7846457c.png

Dos attack

c82330bb.png

Graphene

Graphene has been designed especially for transactions (token transfer) and high-throughput in order to compete with Visa and Mastercard.

However, the more we’ve drilled down the Graphene core source code, the more we’ve understood why Dan Larimer left the project and completely switched to EOS. Here are some main issues we’ve found:

Substrate & Polkadot

Governance
Scalability
Future-proofing
Developability
Interoperability
efficiency

Polkadot的主要目的是将现在各自独立的区块链连接起来,通过Polkadot,不同区块链之间可以进行通信和数据的传递,智能合约的调用。

解决扩展性:平行链宇宙
解决跨链:转接桥+中继链

Polkadot是如何解决扩展性的?

① 一个主链可以挂各种平行链,平行链通过转接桥可以接进来。不要求是以太系。btc,EOS通过桥也可以接进来。
②平行链的安全性可以集中到主链中,形成一个安全池。
③各个平行链之间可以通过中继链互相连通,包括智能合约的调用。
791bbc60.png
因此,Polkadot可以让dapp跑自己的平行链,并且具有主链的安全性,这可以解决 one platform for all 的问题,但是如果这个dapp本身对吞吐量要求就特别高的话,那还是得平行链自己来解决,比如EOS。

website
crates
Version 1.33

提供了内存安全和可靠的并发

这一杀手级的特性就是 ownership, moves, and borrows

IDE 目前使用 Clion + rust plugin

Why Rust

Rust is a modern systems programming language focusing on safety, speed, and concurrency. It accomplishes these goals by being memory safe without using garbage collection.

Performance

Rust is blazingly fast and memory-efficient: with no runtime or garbage collector, it can power performance-critical services, run on embedded devices, and easily integrate with other languages.

Reliability

Rust’s rich type system and ownership model guarantee memory-safety and thread-safety — and enable you to eliminate many classes of bugs at compile-time.

Productivity

Rust has great documentation, a friendly compiler with useful error messages, and top-notch tooling — an integrated package manager and build tool, smart multi-editor support with auto-completion and type inspections, an auto-formatter, and more.

some tools

  • cargo: Rust’s compilation manager, package manager, and general-purpose tool
  • rustc:Rust compiler. Usually we let Cargo invoke the compiler for us
  • rustdoc:rustdoc can build nicely formatted HTML for us.

install development environment

rustup

https://rustup.rs/

windows

命令行执行以下命令

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

下载win-builds 安装 gnu toolchain

查看
rustup show

目前不支持msvc rust toolchain,使用gun
rustup install stable-gnu
rustup default stable-gnu

encountered this error.

curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to sh.rustup.rs:443

solution:
take a rest, buy a cup of coffee. and try again a few hours later.
maybe 18.00 is ok

add the following line to your ~/.bash_profile:

export PATH="$HOME/.cargo/bin:$PATH"

Cargo: the Rust build tool and package manager

  • build your project with cargo build
  • run your project with cargo run
  • test your project with cargo test
  • build documentation for your project with cargo doc
  • publish a library to crates.io with cargo publish

To test that you have Rust and Cargo installed, you can run this in your terminal of choice:
cargo --version

You can install a code formatting tool (Rustfmt) with rustup component add rustfmt,
and a linting tool (Clippy) with rustup component add clippy.

need update rustup update
need uninstall rustup self uninstall

Ownership

Ownership is Rust’s most unique feature, and it enables Rust to make memory safety guarantees without needing a garbage collector.
related features: borrowing, slices
Rust uses a third approach: memory is managed through a system of ownership with a set of rules that the compiler checks at compile time. None of the ownership features slow down your program while it’s running.

Rules

  • Each value in Rust has a variable that’s called its owner.
  • There can only be one owner at a time.
  • When the owner goes out of scope, the value will be dropped.

github

和同事聊天的时候听他提到的一个区块链技术,据说可以一键发链(当然有点夸张),不过确实在 15 分钟之内就可以搭建一个全新的区块链出来。
很牛的设计。参考了 Web 框架类似的想法,把通用的部分抽象出来了。
看了之后很兴奋,这个就是我想要的东西。

使用 Rust 语言开发的。

由 Gavin Wood 带领的 parity 团队打造,Gavin Wood 是前以太坊 CTO

https://polkadot.network/#cover

What’s included in Substrate

many tools come working out-of-the-box, including:

  • Polkadot connectivity
  • Hot-swappable, pluggable Consensus
  • Hot-upgradeable, pluggable STF
  • Flexible and general sync
  • Pub/Sub WebSocket JSON-RPC
  • Light client
  • Transaction queue
  • Pervasive, secure networking
  • JavaScript implementation
  • Substrate Runtime Module Library (SRML)

Because of Substrate’s novel on-chain upgrade mechanism, you will be able “hot-swap” consensus algorithms or upgrade STFs without the need to hard fork. The latter, a forkless upgrade mechanism was first publicly demonstrated on the Polkadot “Krumme Lanke” testnet on July 17th, 2018, and continues as the PoC-2 testnet at the time of this article’s release.

Several consensus algorithms are supported in the 1.0-beta, with more are coming soon, including:

  • Rhododendron (instant finality)
  • SHAFT/GRANDPA (progressive, adaptive finality)
  • Aurand (probabilistic finality, constant blocktime)
  • Ouroboros (live, probabilistic finality) (planned)
  • PoW (e.g., Ethash) (planned)
  • Parachain (PoV, Polkadot consensus) (planned)
    Your can also design your own consensus algorithm with Substrate’s API.

特点

提供如下特性,开箱即用。

  • 共识机制,不可逆性,出块投票逻辑,拜占庭容错机制。
  • p2p 网络。比如 p2p 节点的搜索,同步等等。
  • 运行时的 WebAssembly 虚拟机。可以运行智能合约,或者其他基于 Substrate 开发的项目。
  • 在浏览器中运行一个节点,并与其他节点通信
  • 跨平台的数据库 / 文件存储系统,还支持浏览器环境
  • 客户端平滑更新。对于可能影响共识的更新,会将代码编译成 WebAssembly 的执行文件,然后部署时作为网络上的一条消息。 这样的机制提供了这种可能,就是你还可以本地保有多个版本的共识代码,并在本地执行一个与部署环境不同版本的共识,Substrate 会去处理本机环境与部署环境的差异。因为 WebAssembly 有回退机制,所以保证不会有不受控制的硬分叉或其他难以解决的共识导致的问题。
  • Polkadot 发布时立即接入你的项目。可以共享 Polkadot 的安全性和链之间的互操作性。

启动并运行一个完整的区块链需要做什么

  1. 初始化块的函数。该函数根据前一个块的头创建一个新的块。
    块的头包括:1. 块高度 ; 2. 块状态的加密索引,主要用于轻客户端验证块是否正确。 加密索引类似于 hash; 3. 块中二进制 BLOB 的加密索引 ; 4. 父块的 hash 值 ;
  2. 块头的自定义数据。轻客户端仅同步块头,更新轻客户端时,注意处理块头中自定义的数据。
  3. 将交易写入块的函数。 这个函数也更新链的状态(例如,账户余额);
  4. 生成块的函数。生成一个写好头、写好 BLOB 数据的块。这个块就可以广播出去了。
  5. 校验块的函数。 全节点运行这个函数,确认接收到的块在接受之前是有效的。 例如,在资产链中,你可以检查是否有人人花费超过其自身余额的钱。

模块

Substrate combines three new technologies: Rust, WebAssembly and Libp2p in order to create a framework that makes building upgradable, efficient and innovative blockchains easy. In short, Substrate helps you build the best blockchain you can.

AfG is an internal codename “Al’s Finality Gadget” due to @AlistairStewart who invented it

libp2p

f4e27cee.png
  • Transports:传输层,TCP,uTP,QUIC,SCTP……
  • Discovery:网络发现层,mDNS,bootstrap,DNS,Kad……
  • Peer Routing: 节点路由,mDNS, KadDHT……
  • NAT Traversal: NAT穿越层……
  • Content Routing: 内容寻址……

libp2p的主要功能是:

  • 发现节点
  • 连接节点
  • 发现数据
  • 传输数据

libp2p 规范及其实现的目标是:
允许使用各种:
传输协议: TCP、UDP、SCTP、UDT、UTP、QIC、SSH等
认证传输协议:TLS,DTLS,CurveCP,SSH等
高效使用套接字(连接重用)
使对等体之间的通信在一个套接字上复用(避免握手开销)
使用协商过程使多种协议和不同协议版本在对等体之间使用
向后兼容
能在现有系统中工作
利用当前网络技术的全部能力
有 NAT 穿透功能
允许中继连接
启用加密通道
有效利用底层传输(例如本地流复用、本地AUTH等)。

Substrate gives blockchain innovators the framework for maximum freedom with minimal effort. It is highly customisable, adaptable, and made by blockchain developers for blockchain developers. It allows developers to focus their effort on the thing they care most about—the state transition function—while providing them with the networking, consensus and security as well as an upgrade path to interoperability with Polkadot.

Substrate’s revolutionary generality and developability is evidenced through it being used to build four wildly different blockchains including Polkadot and Ethereum 2.0 simultaneously and in a fraction of the time it would otherwise take (an early version of Ethereum 2.0 was prototyped in a few weeks).

relative chapter
https://medium.com/polkadot-network/polkadot-poc-2-is-here-parachains-runtime-upgrades-and-libp2p-networking-7035bb141c25

module

Substrate is separated into Substrate Core and Substrate Runtime Module Library (SRML) and comes with a pre-assembled Substrate Node that is simple to configure.

Substrate Core

is the minimal Substrate base for building blockchains. Substrate Core gives you a foundation that is far easier than building a blockchain from scratch, though you don’t get a finished blockchain. It includes:

  • Pervasive and secure networking via libp2p
  • Storage
  • Telemetry
  • Light client
  • Block synchronisation
  • Extensible JSON-RPC API endpoints
  • Low-level JavaScript utils
  • Transaction queue and block production mechanism
  • Sandboxed WebAssembly interpreter
  • Interchain connectivity via the Polkadot protocol
  • Crypto primitives library
  • Chain specification and versioning
  • Pluggable consensus

Substrate Runtime Module Library (SRML)

The core architecture of Substrate separates the basic functionality of a network blockchain node and the chain-specific implementations by executing the latter in a separate WebAssembly environment. You have absolute freedom to write the chain logic in any language that can compile down to WebAssembly (Rust, C/C++, C#, Go, etc). You can add modules from the Substrate Runtime Module Library, or SRML. With SRML, you can take off-the-shelf components, plug them together, and build a blockchain that does what you want it to do. Modules include:

  • Accounts & Balances – basic cryptocurrency, including account management and viewing
  • Assets – simple, secure additional on-chain fungible assets
  • Consensus – setting and modifying runtime code and storage (i.e. the set of authorities as a list of session keys on-chain), and reporting offline or misbehaving validators
  • Contracts – turbo-charged Wasm-based smart contracts
  • Council – council election and proposals
  • Democracy – public proposals and referendums
  • Sessions – key rotation for authorities
  • Staking – Proof-of-Stake logic, including both staking and nominating of validator accounts
  • Timestamp – have your chain know about time
  • Treasury – decentralised grants, similar to a DAO

So, for example, if you want to create a Proof-of-Stake smart contract blockchain, you would take Substrate Core and plug in the Accounts & Balances, Staking, and Contracts modules. Once Polkadot launches, you could also make it interoperable by plugging it into Polkadot.

Substrate Node

Finally, Substrate Node allows you to deploy a blockchain with maximum ease. Soon you will be able to configure Substrate Node with a JSON file.

不推荐阅读,顺便鄙视。

新的一年,第一天就看了本假书,我真佩服这家公司的勇气,文不对题,分明就是他们公司区块链的说明书,讲了一堆 API 调用接口。玩这个文字游戏有意思么,故意隐藏内容使用通用的标题骗人看。

dee87dc5.png

今年累计备了 7037 个单词,坚持打卡 281 天,超过 2,998 万人。
算上就饭吃的单词,应该在 6000 左右,看英文文档感觉比以前轻松了,查字典的次数也越来越少了。
下一个难点应该是语法了。单词继续巩固,把语法放到前面。

8eb6cb4c.png 2681384c.png
9790c985.png c1f42f61.png
985fe48e.png 3f635387.png
4e01ee51.png

参考

C++11引入了右值引用,用 && 表示右值引用,如 int &&a = add(1,2)
什么是左值和右值

int a = 10;

等号 “=” 左边的 a 为左值,右边的 10 为右值;具体地说就是较难获取到具体地址的值,大多数都是临时变量。地址是不确定的。

1. 硬编码的字面量,如int a =10中的10,char *s = "hello world"中的“hello world”都是右值
2. 函数的返回值,如add(1,2)的返回值3也是右值,这里的3是临时值
3. 表达式的计算值,如int a =1,b =2;int c = a+b;中的a+b的值也是右值,这里a+b的值也是临时值

移动构造函数:转移类成员的所有权

std::move:把一个左值引用“强制转换”为右值引用。

emplace_back

template< class... Args >
void emplace_back( Args&&... args );

从函数声明中,我们看到其参数是右值引用,右值引用可以用来干什么?移动元素的所有权!

vector<A> vec;
A a(10);
vec.emplace_back(std::move(a));
//输出结果为:
constructor
move constructor

e1aee8e0.png
  • 应用层Executables:最下层的可执行程序有见证节点witness_node,独立钱包cli_wallet和构造创世区块的工具genesis_util。应用层是对插件库、核心API库以及通用工具库的调用组合,实现其业务功能。
  • 插件层Plugin-Ins:插件对核心API进行封装以提供较为完整独立的服务,譬如区块链查询,交易验证执行,打包区块,P2P网络通信等服务。
  • 核心API层API/Core: 实现了基础核心业务功能组件,譬如网络、数据库,钱包相关功能(签名,私钥生成,验证),区块打包计算。
  • 通用工具库FC utilities:提供业务无关的基础功能工具。

石墨烯的关键技术之一就是高度模块化,将内部节点间的分布式通信能力封装成插件(plugins),由上层的应用程序(DAPP)动态加载调用,使得应用开发者无需关注区块链底层细节,极大降低了开发难度,同时更具可扩展性。

石墨烯架构采用DPoS(Delegated proof of stake)共识算法,使得处理性能可以媲美传统的中心化架构。

对象 ID 类型

object 类中还有三个重要的属性:
每个对象的标识都有三部分组成: space_id, type_id, 和 sequence_id
Graphene 中的对象 ID 总共 64 位, space id 占最高 8 位, type id 占中间 8 位, 最低 48 位是 sequence_id.
在 bitshares 钱包或者区块链浏览器看到过 1.2.12376 这样的标识, 这里 type_id 是 2, 代表的就是对象类型, 12376 代表这个账户是链上的第几个被创建的账户