基于上面标准货币体系,我们可以看到在EOS上面的token的经济模型,这是一个很有竞争力的模型,可以保证每个token的价值稳定,而不是狂涨狂跌,真正使EOS上的经济生态健康稳定运转起来。下面来研究exchange智能合约的主要功能。
CMakeLists首先来看CMake设置,上文《【精解】EOS智能合约演练》中也有CMake的应用,但并没有搞太清楚,这里在讨论exchange的CMakeLists配置之前,我们先来搞定cmake本身。
cmakeCMake于C++ 类似maven于java的存在,它可以用来对软件进行构建、测试以及打包等工作。我们在研究C++ 项目的时候,CMake是很好的构建工具,一定要熟悉掌握。
正如maven的配置文件主要是通过pom.xml一样,CMake的工作是通过CMakeLists.txt文件来描述的。所以掌握CMakeLists.txt文件的配置方法是必要的。
cmake_minimum_required,这个配置位于第一行,指定了项目构建所需的CMake的最低版本。
project(banner),括号内填写当前项目名。
set(MY_VAR "hello"),CMake可以通过set关键字来设置文本变量。(相当于全局变量)
set (OTHER_VAR "${MY_VAR} world!"),可以通过“${}”引用上面定义过的变量内容。
我们在IDE中,也可以像直接通过项目中的pom文件导入maven项目那样,通过项目中的CMakelists.txt文件导入CMake项目。
像以上这种设置命令有很多,我们可以参照《CMake官方文档:命令解释》来查阅相关命令的含义以及使用。
exchange cmake file(GLOB ABI_FILES "*.abi") add_wast_executable(TARGET exchange INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" LIBRARIES libc++ libc eosiolib DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} ) configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) add_dependencies( exchange currency ) add_executable(test_exchange test_exchange.cpp ) #bfp/lib/pack.c bfp/lib/posit.cpp bfp/lib/util.c bfp/lib/op2.c) target_link_libraries( test_exchange fc ) target_include_directories( test_exchange PUBLIC fixed_point/include )file是文件操作命令,它的参数:
GLOB,通过文件匹配找到文件列表然后将他们存入变量中。
ABI_FILES,变量名,会将匹配到的文件内容存储在该变量中。
"*.abi",globbing expressions,文件名匹配表达式。例如 “*.vt?”,“f[3-5].txt”
add_wast_executable,cmake的自定义module。
我们在源码位置eos/CMakeModules中可以找到wasm.cmake文件,进去以后可以发现
macro(add_wast_executable)自定义module也是以宏(命令集对外为单一命令)的形式(Excel中我之前写过宏脚本,也是同一个词macro)。这一段add_wast_executable内容很多,我就不粘贴了,主要内容是为了wasm环境构建代码,包括对打包内容的描述,对状态的判断处理等各种命令的集合,其中又包含了很多module宏。
configure_file,复制一个文件到另一个位置,并修改其内容。COPYONLY只复制不修改。
add_executable,增加依赖。
add_executable,添加一个可执行的项目使用指定的源文件。
target_link_libraries,link一个库到target(target是第一个参数)。
target_include_directories,include目录添加到target。
exchange.abiabi文件是通过eosiocpp工具通过exchange.cpp生成的,具体可参照《EOS智能合约演练》。
exchange_accounts从这里开始我们来详细分析exchange合约的源码内容,exchange.cpp需要引用exchange_accounts, exchange_state以及market_state这三个库。其中market_state又依赖两外两个库,因此我们先从比较独立的exchange_accounts入手。
exchange_accounts.hpp
#pragma once #include <eosiolib/asset.hpp> #include <eosiolib/multi_index.hpp> namespace eosio { using boost::container::flat_map;// 相当于java中的import,下面可以直接使用flat_map方法。 /** * 每个用户都有他们自己的账户,并且这个账户是带有exchange合约的。这可以让他们保持跟踪一个用户是如何抵押各种扩展资产类型的。假定存储一个独立的flat_map,包含一个特定用户的所有余额,这个用户比起打破使用扩展标识来排序的多重索引表,将更加实际的 */ struct exaccount { account_name owner;// uint64_t类型,64位无符号整型 flat_map<extended_symbol, int64_t> balances;// extended_symbol是asset.hpp中定义的 uint64_t primary_key() const { return owner; }// 结构体包含一个primary_key方法是不可变的,const,实现也有了,直接是返回owner。 EOSLIB_SERIALIZE( exaccount, (owner)(balances) )// EOSLIB_SERIALIZE这是一种自定义的模板,是一种反射机制,可以给结构体赋值,第一个参数为结构体名字,后面的参数用括号分别括起来,传入当前两个成员变量。 }; typedef eosio::multi_index<N(exaccounts), exaccount> exaccounts;// multi_index是一个类,这行定义了一个变量exaccounts,它的类型是一种多重索引。 /** * 提供一个抽象接口,为用户的余额排序。这个类缓存了数据表,以提供高效地多重访问。 */ struct exchange_accounts { exchange_accounts( account_name code ):_this_contract(code){}// 给私有成员赋值 void adjust_balance( account_name owner, extended_asset delta, const string& reason = string() );//调整余额,传入owner、扩展资产,reason。exchange\_accounts.cpp会实现该函数。 private: account_name _this_contract;// 私有成员 \_this\_contract /** * 保留一个缓存,用来存储我们访问的所有用户表 */ flat_map<account_name, exaccounts> exaccounts_cache;// flat_map类型的缓存exaccounts_cache,存储的是账户名和以上结构体exaccounts。 }; } /// namespace eosiomulti_index这里再简单介绍一下。它的模板定义是
template<uint64_t TableName, typename T, typename... Indices>泛型中第一个参数是表名,第二个是多重索引。