区块链前置知识可参考其他资料
前言 cosmos-sdk可从simapp开始看起,从入口函数了解如何启动一个链并发送交易
tendermint 整体流程
初始化节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ./simd init demo cosmos-sdk/x/genutil/client/cli/init.go // InitCmd returns a command that initializes all files needed for Tendermint // and the respective application. * 获取context 操作sdk 使用的client * 获取server context 包括 tendermint context viper log * 链id,如果传入使用传入的,没有则随机生成 * 如果传入 --recover 使用传入的seed来恢复助记词 * 创建节点的公私钥 * 生成配置信息并写入到配置文件
生成账号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ./simd keys add joe cosmos-sdk/client/keys/add.go /* input - bip39 mnemonic - bip39 passphrase - bip44 path - local encryption password output - armor encrypted private key (saved to file) --algo 设定签名算法参数 --no-backup 不输出助记词信息 * 获取传入的名称 * 设定签名算法, 默认使用secp256k1 * 从本地钥匙串中查询name是否已经存在, 如果存在提示是否需要覆盖 * 覆盖,从本地钥匙串中把秘钥删除 * 生成一个新的秘钥,如果使用--recover 使用传入的助记词生成 */ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *bufio.Reader) error
查看账号信息 1 2 3 4 5 6 7 8 9 10 11 12 ./simd keys show joee cosmos-sdk/client/keys/show.go /** * 获取参数,长度为1表明只查询一条账户信息,大于1表示查询多条 * 根据name,从本地钥匙串中获取秘钥信息 * 根据几个flag,控制展示不同的信息,仅仅展示address public key * keyring 转成输出的结构 KeyOutput(定义了info的结构信息) * 输出信息 */ func runShowCmd(cmd *cobra.Command, args []string) (err error)
其实就是根据name从本地的钥匙串(mac)中查出来keyinfo然后在转成ko信息进行输出
增加创世账号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ./simd add-genesis-account joee 100000000stake cosmos-sdk/simapp/simd/cmd/genaccount.go // AddGenesisAccountCmd returns add-genesis-account cobra Command. * 读取账号name,读取币信息 * 解析name值如果是Bech32则使用(生成的账户地址),否则从本地查询出私钥信息 * 解析币信息多少币以及单位 * 读取创世文件并解析 * 将创世账号设置到创世配置文件里 * 保存新的文件
账号增加前后,genesis文件对比
生成创世交易 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ./simd gentx joee 70000000stake --chain-id test-chain-hTxGEP cosmos-sdk/x/genutil/client/cli/gentx.go // GenTxCmd builds the application's gentx command. /** * 获取nodeid validator key * 读取genesis.json配置 * 生成TxCreateValidatorConfig * 验证创世账号,检查是否有足够的余额, 判断了创世账号和传入的币数量,进行了对比 * 生成 tx client 方便对交易进行签名等 * 生成 'create-validator' message * 无签名交易, 生成一个 std tx 不带签名的 * 创建 tx builder 依据 std tx * 签名交易, 利用用户的私钥, 签名的消息在 std tx中, tx builder里也有该结构 * 将std tx写入本地的文件中 */
std tx 和 tx builder其都是接口, 都实现了tx.wrapper, 最终文件里写入的也是tx的结构信息
收集创世交易到创世配置文件中 1 2 ./simd collect-gentxs 主要功能就是把gentx/下的创世的tx信息,写入到genesis文件的genutil->gen_txs下
启动链 1 2 3 4 5 6 7 8 9 10 11 12 13 ./simd start cosmos-sdk/server/start.go 核心主要是startInProcess方法, 其大概的流程如下 * simapp, tendermint node 初始化 * db创建 * 初始化链 * 执行各个模块的init * tendermint模块的启动 * 初始化几个db * consensus, mempool, query启动 * 创建eventbus,因为可能需要重放tx,因为可能在上一次索引tx前可能程序崩溃了 * grpc server启动
重放
1 2 3 4 5 6 7 8 从数据库中读取数据, 包含了同步的高度 最后一个hash等 通过proxyapp的query查询数据 query req: req:{Version:0.34.20 BlockVersion:11 P2PVersion:8} rsp:data:"SimApp" last_block_height:876 last_block_app_hash:"\225\002\200\022\210\230m\033\367\270\307\274gf\3015\007\273Ip\004v\345\245\375Q=\036\362\317]\203" 生成默克尔树
执行的大致步骤
查询账户余额 通过命令行查询账户余额信息,query bank balances 发起一个rpc请求,server接收到请求后调用bank模块的查询方法
1 2 3 4 5 6 7 8 9 10 11 ./simd query bank balances cosmos1trspjhj9hela7x3k0jucs93trjlcm0zv0cemtx 该cmd代码在 cosmos-sdk/x/bank/client/cli/query.go里GetBalancesCmd方法 这是是client调用的代码 server端代码在 cosmos-sdk/x/bank/keeper/grpc_query.go里的AllBalances方法
实际查询是调用这里,是一个分页的查询方法,会查询某个prefix的所有value数据。使用了kvstore的迭代器,kv的prefix实际上就是addr iter的key就是addr, value就是用户的余额信息,每一次的迭代的结果都会调用调用者的回调函数,进行数据的进一步处理,看下一张图
接收到的kvstore里的value,在这里进行了unmarshal转成了coin类型的, 之后就是处理下返回的数据,在把数据通过rpc进行返回,client端就可以看到查询到的数据
转账交易 前期准备 首先创建另外一个账户得到需要被转账的账户地址, 创建一个wt的账号,从joee转账到wt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ./simd keys add wt 创建一个账号 - name: wt type: local address: cosmos14a6hsfwvxfsnu4rtshxu2g2qcsj4s985vhflg3 pubkey: cosmospub1addwnpepqvmcswuhleztl4pt2nfw4n32puxfvjwrflmtzedkw0hf68ytagnr6xjhux5 mnemonic: "" threshold: 0 pubkeys: [] **Important** write this mnemonic phrase in a safe place. It is the only way to recover your account if you ever forget your password. sail lady calm ensure repeat cinnamon tilt sponsor thumb glad also nice bright absurd tone rather scissors wasp salad topic pave choice cabin purpose
签名交易 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ./simd tx bank send cosmos1trspjhj9hela7x3k0jucs93trjlcm0zv0cemtx cosmos14a6hsfwvxfsnu4rtshxu2g2qcsj4s985vhflg3 10stake --chain-id test-chain-hTxGEP --home /Users/joe/.simappdebug /cosmos.auth.v1beta1.Query/Account 先查询from账号信息 client拿到账号数据信息 准备构造广播交易 client确实是否广播前签名交易 签名前交易 {"body":{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"cosmos1trspjhj9hela7x3k0jucs93trjlcm0zv0cemtx","to_address":"cosmos14a6hsfwvxfsnu4rtshxu2g2qcsj4s985vhflg3","amount":[{"denom":"stake","amount":"10"}]}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]} 构造http请求, json rpc请求, client会调用链的的接口 以下是一个json rpc请求样例, tx的交易信息大致包括,from和to的address,调用了bank的msgsend,转账的金额,pubkey等信息 {"jsonrpc":"2.0","id":2,"method":"broadcast_tx_sync","params":{"tx":"Co4BCosBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmsKLWNvc21vczF0cnNwamhqOWhlbGE3eDNrMGp1Y3M5M3RyamxjbTB6djBjZW10eBItY29zbW9zMTRhNmhzZnd2eGZzbnU0cnRzaHh1MmcycWNzajRzOTg1dmhmbGczGgsKBXN0YWtlEgIxMBJYClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDT0ZVTObifli0uYI1YWSRv2LI/Ga2n+6WdFnQJDnLYegSBAoCCAEYAxIEEMCaDBpAAP1xjbIPlt5wHwEESFD6rmJr0osa4HUocS5lqPXy/us8CvlXOPrpQm9FlKd9ZRgFCfVXpUInEnHWcHP7RRn44Q=="}} 请求返回样例 { "jsonrpc": "2.0", "id": 2, "result": { "code": 0, "data": "", "log": "[]", "codespace": "", "hash": "5F10702E8E885B8FFD6D530EC6649781BA12810DB78A3392C0F556A0676B3730" } }
交易处理流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 接口接收到tx信息,开始处理交易 检查交易,会判断交易大小 计算tx的hash值,使用了sha256来计算 将交易放入队列 // mapTxCache maintains a LRU cache of transactions. This only stores the hash // of the tx, due to memory concerns. type mapTxCache struct { mtx tmsync.Mutex size int cacheMap map[[TxKeySize]byte]*list.Element list *list.List } 提交共识,节点进行共识操作 执行区块
节点共识流程
执行区块流程
参考文献