版权声明:凡原创系列文章,均笔者的辛勤于中,如转载,请文章顶部注明来源。谢谢配合 https://blog.csdn.net/smilejiasmile/article/details/83094796
接上篇文章
3、钱包及其账号
- 钱包是一个私钥库,里面保存着私钥公钥对, 类似以太坊里的 keystore 信息。里面保存的私钥数据其实是私钥被加密后数据,需要用户输入密码才能还原出真正的私钥。智能合约的action执行都需要钱包来解锁相关的公钥(key).所以钱包可以看成是钥匙箱。
- 一个钱包对应 ~/eosio-wallet/的一个文件,其中的一个文件里面的内容就是私钥被加密后的内容。如;
[chen@ubuntu ~/eosio-wallet]$>cat bob.wallet
{
"cipher_keys": "8d58fbbf7ceb56ede4959108943055d2376c3e908461b3cfc665c8a30530ab001585c3bbfd980ce9f18eb932f5adea04d718fa9eb37d60e680058004d785338ea760b51e8692bbba0345eb04a4734a4f61dc372e6b9721da0f39c214336f4028aa5d74ae56e453e32e550440d77c1fc6c3cf6e9e88bf8cd434b8d3dfed3aa920c661196c3c835f6822b06be9772bbe4bcb700f331fea9aa8f6e3c808adff819cd1f896c5286acccb332746c8a0b963ba414859dccbdb20c6138389ffc14ef96dc1f0a3f4a83b177186718c7dc85a0a68449e477a218950286e8debf58d911ba43c1f616179efc13cf8f511109927a0465d287af10618b70d99b6848f135668cad26e19ffb7b1bbf482503587b2b962d0"
}
- EOS的账号对应以太坊的智能合约地址,它扩展了账号的概念,一个账号由智能合约 + 权限管理构成。
- 权限管理
权限管理模块可以精细的定义一个Account/key或者几个Account/key(比如多重签名机制)对账号数据的访问权限。目前有两个默认的权限类型 - owner权限 : 可以修改任意账号和key的权限
- active : 可转账,DPOS投票,及其它上层定义的权限修改
- 用户也可自定义权限类型。同时引入了权重和阈值的概念,该机制使得多重签名实现非常简单,也更有扩展性。
permission格式如下
{
"threshold": 100,/*An integer that defines cumulative signature weight required for authorization*/
"keys": [], /*An array made up of individual permissions defined with an EOS PUBLIC KEY*/
"accounts": [] /*An array made up of individual permissions defined with an EOS ACCOUNT*/
}
-
组合和自定义权限
-
bob和stacy两个账号一起才能行使owner权限
-
bob, stacy两个账号的任一一个都可以行使active权限
-
bob可以行使publish权限,但是stacy和”EOS7KBTMkU…"没法单独行使publish权限,但是他们一起可以行使publish权限
-
这些权限的检测一般在执行action操作时执行。
-
建账号account
cleos create account [OPTIONS] creator name OwnerKey ActiveKey
-
该命令本身是一个action,会产生一个transaction,最后会保存在链上的,所以该操作依赖nodeos程序,必须启动nodeos程序。上面的OwnerKey,ActiveKey都是公钥。creator必须是一个已经存在的账号,第一次创建账号,我们使用 eosio账号, eosio这个特殊账号是在nodeos启动时自动生成的,且这个账号的private key,和public key是hardcode固定的。
-
查看账号信息
cleos get account newaccount
- 修改权限命令格式
- $ cleos set account permission [OPTIONS] account permission authority [parent]
account,表示要修改的账户
permission 表示要设置的权限(上面的owner,active,publish)
authority 权限内容,JSON字符串
parent 上级权限
- 例如:修改 active 权限
$ cleos set account permission testaccount active '{"threshold" : 1, "keys" : [], "accounts" : [{"permission":{"actor":"bob","permission":"active"},"weight":1}, {"permission":{"actor":"stacy","permission":"active"},"weight":1}]}’ owner
- 例如:新增自定义权限
cleos set account permission testaccount publish '{"threshold" : 2, "keys" : [{"permission":{"key":"EOS8X7Mp7apQWtL6T2sfSZzBcQNUqZB7tARFEm9gA9Tn9nbMdsvBB","permission":"active"},"weight":1}], "accounts" : [{"permission":{"actor":"bob","permission":"active"},"weight":2}, {"permission":{"actor":"stacy","permission":"active"},"weight":1}]}’ active
4、系统智能合约及其相关知识
- 在编写智能合约的源代码中,常常会涉及到 ‘EOSIO_ABI’ 这个宏定义, 它是一个生成智能合约初始化函数 apply 的宏,生成的apply 函数是智能合约的入口,它采用 switch(action) case 的方式调用具体 action 对应的函数。例如(经典的 helloWorld Dapps 合约):
EOSIO_ABI( hello, (hi) )
- 编译生成wast文件
$ eosiocpp -o hello.wast hello.cpp
编译完成后,会生成两个新文件,hello.wast, hello.wasm
- $ ls
hello.cpp hello.wasm hello.wast
.wast文件是wasm的代码文本格式,.wasm是汇编代码二级制格式
- 生成abi文件
- $ eosiocpp -g hello.abi hello.cpp
764454ms thread-0 abi_generator.hpp:68 ricardian_contracts ] Warning, no ricardian clauses found for hello
764454ms thread-0 abi_generator.hpp:75 ricardian_contracts ] Warning, no ricardian contract found for hi
5、区块链开源项目中的 C++ 编程技巧
- 奇异递归模板模式( Curiously Recurring Template Pattern,CRTP), 是 C++ 模板编程时的一种惯用法(idiom):把派生类作为基类的模板参数。更一般地被称作 F-bound polymorphism,是一类 F 界量化。
- 一般形式:
// The Curiously Recurring Template Pattern (CRTP)
template<class T>
class Base
{
// methods within Base can use template to access members of Derived
};
class Derived : public Base<Derived>
{
// ...
};
- 它主要的功能就是可以实现 【 静态多态 】, 这样做的目的是在基类中使用派生类,从基类的角度来看,派生类其实也是基类,通过向下转换[downcast],因此,基类可以通过static_cast把其转换到派生类,从而使用派生类的成员,形式如下:
template <class T>
struct Base
{
void interface()
{
// ...
static_cast<T*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
T::static_sub_func();
// ...
}
};
struct Derived : Base<Derived>
{
void implementation();
static void static_sub_func();
};
- 基类模板利用了其成员函数体(即成员函数的实现)将不被实例化直至声明很久之后(实际上只有被调用的模板类的成员函数才会被实例化), 如上例中,Base::interface(),虽然是在struct Derived之前就被声明了,但未被编译器实例化直至它被实际调用,这发生于Derived声明之后,此时Derived::implementation()的声明是已知的。
- 这种技术获得了类似于虚函数的效果,并避免了动态多态的代价。也有人把CRTP称为“模拟的动态绑定”。这种模式广泛用于Windows ATL与WTL库,以及Boost.Iterator,Boost.Python或者Boost.Serialization等库中。
- 考虑一个基类,没有虚函数,则它的成员函数能够调用的其它成员函数,只能是属于该基类自身。当从这个基类派生其它类时,派生类继承了所有未被覆盖(overridden)的基类的数据成员与成员函数。如果派生类调用了一个被继承的基类的函数,而该函数又调用了其它成员函数,这些成员函数不可能是派生类中的派生或者覆盖的成员函数。也就是说,基类中是看不到派生类的。但是,基类如果使用了CRTP,则在编译时派生类的覆盖的函数可被选中调用。这效果相当于编译时模拟了虚函数调用但避免了虚函数的尺寸与调用开销(VTBL结构与方法查找、多继承机制)等代价。但CRTP的缺点是不能在运行时做出动态绑定。
- 不通过虚函数机制,基类访问派生类的私有或保护成员,需要把基类声明为派生类的友元(friend)。如果一个类有多个基类都出现这种需求,声明多个基类都是友元会很麻烦。一种解决技巧是在派生类之上再派生一个accessor类,显然accessor类有权访问派生类的保护函数;如果基类有权访问accessor类,就可以间接调用派生类的保护成员了。这种方法被boost的多个库使用,如:Boost.Python中的def_visitor_access和Boost.Iterator的iterator_core_access。原理示例代码如下:
template<class DerivedT> class Base
{
private:
struct accessor : DerivedT
{ // accessor类没有数据成员,只有一些静态成员函数
static int foo(DerivedT& derived)
{
int (DerivedT::*fn)() = &DeriveT::do_foo; //获取DerivedT::do_foo的成员函数指针
return (derived.*fn)(); // 通过成员函数指针的函数调用
}
}; // accessor类仅是Base类的成员类型,而没有实例化为Base类的数据成员。
public:
DerivedT& derived() // 该成员函数返回派生类的实例的引用
{
return static_cast<DerivedT&>(*this);
}
int foo()
{ // 该函数具体实现了业务功能
return accessor::foo( this->derived());
}
};
struct Derived : Base<Derived> // 派生类不需要任何特别的友元声明
protected:
int do_foo()
{
// ... 具体实现
return 1;
}
};
6、数据库相关
- 对象模型,一般的大部分的 object 都是继承于在 chainbase.h 中的模板类 object, 使用了 CRTP(奇异递归模板模式的技术), 由下列的基类可知,成员 type_id 被定义为 static 成员变量,则要求其子类在继承模板基类时,就必须给出 TypeNumber 的值,其外,可通过子类的 Derived 的类型多态以处理各自类型的 object id(oid)。
template<uint16_t TypeNumber, typename Derived>
struct object
{
typedef oid<Derived> id_type;
static const uint16_t type_id = TypeNumber;
};
- 索引模型,在 eos 的这一部分底层用的是 boost::multi_index, 索引模型与对象模型的基类在同一层级,也在 chainbase.h 文件中定义。其中在该文件中有这样几个与索引相关的类,generic_index (管理index的类,模板类需要一个索引类型参数 MultiIndexType)、abstract_index (抽象接口)、index_impl(继承于 abstract_index 模板类,需要一个 BaseIndex 的模板参数)、index(继承于 index_impl 模板类,需要一个 IndexType 的模板参数)
- 其中 genertic_index 的核心就是 multi_index_container<>,深入了解一下会发现 multi_index_container<> 的底层实际上是 std::map, 而 std::map 底层实际是红黑树。
7、插件相关
- 推荐博客:插件