{"content":{"title":"Cosmos SDK——从选链到创链的跨越，稳步踏入区块链3.0","body":"Cosmos SDK 是世界上最受欢迎的用于构建面向应用的区块链的框架。\r\n\r\n## Cosmos SDK\r\n\r\nCosmos SDK是一个开源框架，用于构建多资产公共权益证明（PoS）区块链，如Cosmos Hub，以及许可的权威证明区块链。使用Cosmos SDK构建的区块链通常称为**面向应用的区块链**。\r\n\r\nCosmos SDK的目标是允许开发人员从头开始轻松创建自定义区块链，这些区块链可以与其他区块链进行本机互操作。我们将Cosmos SDK设想为类似于npm的框架，用于在[Tendermint](https://github.com/tendermint/tendermint)之上构建安全的区块链应用程序。基于SDK的区块链由可组合模块构建而成，其中大多数是开源的，可供任何开发人员使用。任何人都可以为 Cosmos SDK创建模块，集成已构建的模块就像将它们导入区块链应用程序一样简单。此外，Cosmos SDK是一个基于功能的系统，允许开发人员更好地推理模块之间交互的安全性。\r\n\r\n![微信图片_20230105192013.png](https://img.learnblockchain.cn/attachments/2023/01/oPJdbINk63b8ef42509bf.png)\r\n\r\n## 面向特定应用的区块链\r\n\r\n面向应用的区块链是为操作单个应用程序而定制的区块链。开发人员不是在以太坊等底层区块链之上构建去中心化应用程序，**而是从头开始构建自己的区块链**。这意味着构建一个全节点客户端、一个轻客户端和所有必要的接口（CLI、REST 等）来与节点交互。\r\n\r\n```shell\r\n                ^  +-------------------------------+  ^\r\n                |  |                               |  |   Built with Cosmos SDK\r\n                |  |  State-machine = Application  |  |\r\n                |  |                               |  v\r\n                |  +-------------------------------+\r\n                |  |                               |  ^\r\nBlockchain node |  |           Consensus           |  |\r\n                |  |                               |  |\r\n                |  +-------------------------------+  |   Tendermint Core\r\n                |  |                               |  |\r\n                |  |           Networking          |  |\r\n                |  |                               |  |\r\n                v  +-------------------------------+  v\r\n```\r\n\r\n智能合约的缺点：\r\n\r\n像以太坊这样的虚拟机区块链早在2014年就解决了对更多可编程性的需求。当时，可用于构建去中心化应用程序的选择非常有限。大多数开发人员会建立在复杂且有限的比特币脚本语言之上，或者分叉难以使用和定制的比特币代码库。\r\n\r\n虚拟机区块链带来了新的价值主张。他们的状态机包含一个虚拟机，能够解释称为智能合约的图灵完备程序。这些智能合约非常适合一次性事件（例如ICO）等用例，但它们可能不足以构建复杂的去中心化平台。原因如下：\r\n\r\n- 智能合约通常使用特定的编程语言开发，这些编程语言可以由底层虚拟机解释。这些编程语言通常不成熟，并且受到虚拟机本身约束的固有限制。例如，以太坊虚拟机不允许开发人员实现代码的自动执行。开发人员也仅限于基于帐户的EVM系统，他们只能从一组有限的功能中进行选择以进行加密操作。这些都是例子，但它们暗示了智能合约环境通常缺乏**灵活性**。\r\n\r\n- 智能合约都由同一个虚拟机运行。这意味着它们会争夺资源，这会严重限制**性能**。即使状态机被拆分为多个子集（例如通过分片），智能合约仍然需要由虚拟机解释，与在状态机级别实现的本机应用程序相比，这将限制性能（我们的基准测试显示，当虚拟机被删除时，性能提高了10倍）。\r\n\r\n- 智能合约共享相同底层环境这一事实的另一个问题是由此产生的独立性限制。去中心化应用程序是一个涉及多个参与者的生态系统。如果应用程序构建在通用虚拟机区块链上，则利益相关者对其应用程序的主权非常有限，最终被底层区块链的治理所取代。如果应用程序中存在错误，则几乎无能为力。\r\n\r\n**面向应用的区块链旨在解决这些缺点。**\r\n\r\n## Cosmos区块链核心架构\r\n\r\n### 状态机\r\n\r\n区块链的本质是一个可以被复制的状态机，一个简化了事物因果关系的逻辑模型，可以给定某个条件来更新状态。比如说比特币就是一个可以被所有人下载的账本，新的交易成功后就会被更新到这个所有人都可以看到的账本。在实践中，大量的交易可以被打包并上传到链上修改账本的状态。\r\n\r\n### Tendermint\r\n\r\n![微信图片_20230105193708.png](https://img.learnblockchain.cn/attachments/2023/01/eGho0C5r63b8ef60d2426.png)\r\nCosmos SDK使得开发人员只需要定义状态机，[*Tendermint*](https://docs.tendermint.com/master/introduction/what-is-tendermint.html)将为他们处理网络上的复制。\r\n\r\n[Tendermint](https://docs.tendermint.com/v0.34/introduction/what-is-tendermint.html)是一个与应用程序无关的引擎，负责处理区块链的网络和共识层。实际上，这意味着Tendermint负责传播和排序事务字节。Tendermint Core依靠同名的拜占庭容错（BFT）算法来让交易顺序达成共识。\r\n\r\nTendermint[共识算法](https://docs.tendermint.com/v0.34/introduction/what-is-tendermint.html#consensus-overview)与一组称为验证器的特殊节点一起工作。验证者负责将交易块添加到区块链中。在任何给定的区块中，都有一个验证器集V。算法选择V中的验证者作为下一个区块的提议者。如果超过2/3的V在其上签署了`prevote`和`precommit`，并且它包含的所有交易都有效，则认为此块有效。验证器集可以通过在状态机中编写的规则来更改。\r\n\r\n\r\n![consensus_logic.e9f4ca6f.png](https://img.learnblockchain.cn/attachments/2023/01/ZqNb204S63b8ef793e3f5.png)\r\n\r\n### ABCI\r\n\r\n在Cosmos的区块链网络中，每条区块链都由Tendermint作为底层的通用的网络层和共识层，同时每个应用都能在应用层设计自己的业务逻辑。对于开发者来说，只需要通过ABCI（Application Blockchain Interface）应用程序区块链接口调用，他们可以直接在tendermint提供的共识机制上提供的最终交易上就可以构建应用程序。\r\n\r\n**ABCI 作为一个socket协议是一个调用的接口，不同于其他的区块链要求开发者学习并使用特定的语言，开发人员可以选择他们熟悉的语言进行开发。**\r\n\r\n我们看到的比特币、以太坊在设计区块链网络时都是采用的一体化的思路，每一个技术栈，也就是我们刚刚讲到的区块链的各个层级，都是一个相互链接和依赖的程序，无法单独拆开。\r\n\r\n这种整体的架构在开发时容易遇到2个问题。\r\n\r\n1）代码难以使用。比如说，比特币的一个堆栈里面就包含了待处理的交易池mempool，账户余额，用户权限等，如果想要单独拎出mempool就会变得非常困难，即使分叉也很难维护，变成面条式代码，和面条一样缠绕在一起混乱难以理出头绪。\r\n\r\n2）限制开发语言。在以太坊网络中，EVM 需要通过编译器将智能合约代码编译成字节码再上传到区块链之后才能执行操作，导致开发者只能使用EVM编译器支持的语言，也就是 Serpent 和 Solidity。\r\n\r\n**功能类型**\r\n\r\n主要有3个ABCI连接应用层和Tenderint共识层，包括：\r\n\r\n1）CheckTx：验证交易并提交到mempool交易池中广播交易\r\n\r\n2）DeliverTx：提交给共识引擎处理并更新状态\r\n\r\n3）BeginBlock/EndBlock：查询应用层的状态\r\n\r\nabci协议包括几种不同的消息类型。Tendermint core 会创建3个ABCI连接到应用层：\r\n\r\n![abci.3542de28.png](https://img.learnblockchain.cn/attachments/2023/01/5GAgOhpD63b8ef8f37fbb.png)\r\n\r\n在计算机科学中，通常不认为单体架构通常是一个好的做法。Cosmos把原来的需要从底层开始构建层层堆叠的区块链架构，变成了模块化的可自由组合的结构。就像是组装电脑一样，你可以把内存条，显示器，键盘，鼠标组装成一个电脑需要考虑添加具体的配置就可以开车上路了。而应用层的配置也提供了工具，Cosmos SDK，一个允许开发者为应用场景自定义配置的框架，提供了新的开发范式。\r\n\r\n任何基于Tendermint构建的应用程序都需要实现ABCI接口，以便与底层本地Tendermint引擎进行通信。幸运的是，不必实现 ABCI 接口。Cosmos SDK 以[基本应用](https://docs.cosmos.network/v0.47/intro/sdk-design#baseapp)的形式提供它的样板实现。\r\n\r\n\r\n![tm-transaction-flow.258ca020.png](https://img.learnblockchain.cn/attachments/2023/01/4MheBK0A63b8efa884b9b.png)\r\n\r\n\r\n*开发Keplr钱包的Josh曾经总结过，“使用智能合约是租房，使用CosmosSDK开发才是建造属于自己的房子。”*\r\n\r\n### Cosmos SDK模块设计\r\n\r\n\r\n![微信图片_20230105200240.png](https://img.learnblockchain.cn/attachments/2023/01/rzYJSgJM63b8efc67f909.png)\r\n\r\nCosmos SDK的运行机制：**通过Multistore 的机制来定义和维护应用层的状态，将应用层的状态划分到不同的模块，可以看作是独立的状态机CosmosSDK里内置的底层basepp里有ABCI的接口可以直接调用适应所有应用类型的Tendermint共识机制，经过CheckTX的验证非攻击后提交到mempool交易池，在验证节点达成共识成功出块后交易被打包上链，通过DeliverTx成功修改状态，即交易成功。**\r\n\r\n**通过DeliverTx的功能收到字节形式的交易后，解码提取消息，在验证交易相关的信息后，比如是否有签名，再推送到对应的模块处理，最后更新状态。更新后的状态由SDK里的Multistore的功能保存，并且还可以把信息切割开来对应到不同的模块。**\r\n\r\nCosmos SDK的核心是Golang中[ABCI](https://docs.cosmos.network/v0.47/intro/sdk-app-architecture#abci)的实现。它带有一个用于持久保存数据的[`多存储`](https://docs.cosmos.network/v0.47/core/store#multistore)和一个用于处理事务的[`路由器`](https://docs.cosmos.network/v0.47/core/baseapp#routing)。\r\n\r\n当通过`DeliverTx`方式从Tendermint传输时，基于Cosmos SDK构建的应用程序如何处理事务：\r\n\r\n1. 解码从Tendermint 共识引擎收到的`transactions`（Tendermint 只处理 `[]bytes`）。\r\n2. 从`transactions`中提取`messages`并执行基本的健全性检查。\r\n3. 将每条消息发送到相应的模块，以便对其进行处理。\r\n4. 提交状态更改。\r\n\r\n## Cosmos SDK应用编程\r\n\r\n首先下载Cosmos SDK源代码：\r\n\r\n`git clone https://github.com/cosmos/cosmos-sdk`\r\n\r\n其中app.go作为Cosmos SDK构建应用的核心，代码如下：\r\n\r\n```go\r\n//go:build app_v1\r\npackage simapp\r\n\r\nimport (\r\n\t...\r\n)\r\n\r\nconst appName = \"SimApp\"\r\n\r\nvar (\r\n\t// DefaultNodeHome default home directories for the application daemon\r\n\tDefaultNodeHome string\r\n\r\n\t// ModuleBasics defines the module BasicManager is in charge of setting up basic,\r\n\t// non-dependant module elements, such as codec registration\r\n\t// and genesis verification.\r\n\tModuleBasics = module.NewBasicManager(\r\n\t\tauth.AppModuleBasic{},\r\n\t\tgenutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),\r\n\t\tbank.AppModuleBasic{},\r\n\t\tcapability.AppModuleBasic{},\r\n\t\tstaking.AppModuleBasic{},\r\n\t\tmint.AppModuleBasic{},\r\n\t\tdistr.AppModuleBasic{},\r\n\t\tgov.NewAppModuleBasic(\r\n\t\t\t[]govclient.ProposalHandler{\r\n\t\t\t\tparamsclient.ProposalHandler,\r\n\t\t\t\tupgradeclient.LegacyProposalHandler,\r\n\t\t\t\tupgradeclient.LegacyCancelProposalHandler,\r\n\t\t\t},\r\n\t\t),\r\n\t\tparams.AppModuleBasic{},\r\n\t\tcrisis.AppModuleBasic{},\r\n\t\tslashing.AppModuleBasic{},\r\n\t\tfeegrantmodule.AppModuleBasic{},\r\n\t\tupgrade.AppModuleBasic{},\r\n\t\tevidence.AppModuleBasic{},\r\n\t\tauthzmodule.AppModuleBasic{},\r\n\t\tgroupmodule.AppModuleBasic{},\r\n\t\tvesting.AppModuleBasic{},\r\n\t\tnftmodule.AppModuleBasic{},\r\n\t\tconsensus.AppModuleBasic{},\r\n\t)\r\n\r\n\t// module account permissions\r\n\tmaccPerms = map[string][]string{\r\n\t\tauthtypes.FeeCollectorName:     nil,\r\n\t\tdistrtypes.ModuleName:          nil,\r\n\t\tminttypes.ModuleName:           {authtypes.Minter},\r\n\t\tstakingtypes.BondedPoolName:    {authtypes.Burner, authtypes.Staking},\r\n\t\tstakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},\r\n\t\tgovtypes.ModuleName:            {authtypes.Burner},\r\n\t\tnft.ModuleName:                 nil,\r\n\t}\r\n)\r\n\r\nvar (\r\n\t_ runtime.AppI            = (*SimApp)(nil)\r\n\t_ servertypes.Application = (*SimApp)(nil)\r\n)\r\n\r\n// SimApp extends an ABCI application, but with most of its parameters exported.\r\n// They are exported for convenience in creating helper functions, as object\r\n// capabilities aren't needed for testing.\r\ntype SimApp struct {\r\n\t*baseapp.BaseApp\r\n\tlegacyAmino       *codec.LegacyAmino\r\n\tappCodec          codec.Codec\r\n\ttxConfig          client.TxConfig\r\n\tinterfaceRegistry types.InterfaceRegistry\r\n\r\n\t// keys to access the substores\r\n\tkeys    map[string]*storetypes.KVStoreKey\r\n\ttkeys   map[string]*storetypes.TransientStoreKey\r\n\tmemKeys map[string]*storetypes.MemoryStoreKey\r\n\r\n\t// keepers\r\n\tAccountKeeper         authkeeper.AccountKeeper\r\n\tBankKeeper            bankkeeper.Keeper\r\n\tCapabilityKeeper      *capabilitykeeper.Keeper\r\n\tStakingKeeper         *stakingkeeper.Keeper\r\n\tSlashingKeeper        slashingkeeper.Keeper\r\n\tMintKeeper            mintkeeper.Keeper\r\n\tDistrKeeper           distrkeeper.Keeper\r\n\tGovKeeper             govkeeper.Keeper\r\n\tCrisisKeeper          *crisiskeeper.Keeper\r\n\tUpgradeKeeper         *upgradekeeper.Keeper\r\n\tParamsKeeper          paramskeeper.Keeper\r\n\tAuthzKeeper           authzkeeper.Keeper\r\n\tEvidenceKeeper        evidencekeeper.Keeper\r\n\tFeeGrantKeeper        feegrantkeeper.Keeper\r\n\tGroupKeeper           groupkeeper.Keeper\r\n\tNFTKeeper             nftkeeper.Keeper\r\n\tConsensusParamsKeeper consensusparamkeeper.Keeper\r\n\r\n\t// the module manager\r\n\tModuleManager *module.Manager\r\n\r\n\t// simulation manager\r\n\tsm *module.SimulationManager\r\n\r\n\t// module configurator\r\n\tconfigurator module.Configurator\r\n}\r\n\r\nfunc init() {\r\n\tuserHomeDir, err := os.UserHomeDir()\r\n\tif err != nil {\r\n\t\tpanic(err)\r\n\t}\r\n\r\n\tDefaultNodeHome = filepath.Join(userHomeDir, \".simapp\")\r\n}\r\n\r\n// NewSimApp returns a reference to an initialized SimApp.\r\nfunc NewSimApp(\r\n\tlogger log.Logger,\r\n\tdb dbm.DB,\r\n\ttraceStore io.Writer,\r\n\tloadLatest bool,\r\n\tappOpts servertypes.AppOptions,\r\n\tbaseAppOptions ...func(*baseapp.BaseApp),\r\n) *SimApp {\r\n\tencodingConfig := makeEncodingConfig()\r\n\r\n\tappCodec := encodingConfig.Codec\r\n\tlegacyAmino := encodingConfig.Amino\r\n\tinterfaceRegistry := encodingConfig.InterfaceRegistry\r\n\ttxConfig := encodingConfig.TxConfig\r\n\r\n\tbApp := baseapp.NewBaseApp(appName, logger, db, txConfig.TxDecoder(), baseAppOptions...)\r\n\tbApp.SetCommitMultiStoreTracer(traceStore)\r\n\tbApp.SetVersion(version.Version)\r\n\tbApp.SetInterfaceRegistry(interfaceRegistry)\r\n\tbApp.SetTxEncoder(txConfig.TxEncoder())\r\n\r\n\tkeys := sdk.NewKVStoreKeys(\r\n\t\tauthtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, crisistypes.StoreKey,\r\n\t\tminttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey,\r\n\t\tgovtypes.StoreKey, paramstypes.StoreKey, consensusparamtypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey,\r\n\t\tevidencetypes.StoreKey, capabilitytypes.StoreKey,\r\n\t\tauthzkeeper.StoreKey, nftkeeper.StoreKey, group.StoreKey,\r\n\t)\r\n\r\n\ttkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey)\r\n\t// NOTE: The testingkey is just mounted for testing purposes. Actual applications should\r\n\t// not include this key.\r\n\tmemKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, \"testingkey\")\r\n\r\n\t// register the streaming service with the BaseApp\r\n\tif err := bApp.SetStreamingService(appOpts, appCodec, keys); err != nil {\r\n\t\tlogger.Error(\"failed to load state streaming\", \"err\", err)\r\n\t\tos.Exit(1)\r\n\t}\r\n\r\n\tapp := &SimApp{\r\n\t\tBaseApp:           bApp,\r\n\t\tlegacyAmino:       legacyAmino,\r\n\t\tappCodec:          appCodec,\r\n\t\ttxConfig:          txConfig,\r\n\t\tinterfaceRegistry: interfaceRegistry,\r\n\t\tkeys:              keys,\r\n\t\ttkeys:             tkeys,\r\n\t\tmemKeys:           memKeys,\r\n\t}\r\n\r\n\tapp.ParamsKeeper = initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey])\r\n\r\n\t// set the BaseApp's parameter store\r\n\tapp.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(appCodec, keys[upgradetypes.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String())\r\n\tbApp.SetParamStore(&app.ConsensusParamsKeeper)\r\n\r\n\tapp.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey])\r\n\t// Applications that wish to enforce statically created ScopedKeepers should call `Seal` after creating\r\n\t// their scoped modules in `NewApp` with `ScopeToModule`\r\n\tapp.CapabilityKeeper.Seal()\r\n\r\n\t// add keepers\r\n\tapp.AccountKeeper = authkeeper.NewAccountKeeper(appCodec, keys[authtypes.StoreKey], authtypes.ProtoBaseAccount, maccPerms, sdk.Bech32MainPrefix, authtypes.NewModuleAddress(govtypes.ModuleName).String())\r\n\r\n\tapp.BankKeeper = bankkeeper.NewBaseKeeper(\r\n\t\tappCodec,\r\n\t\tkeys[banktypes.StoreKey],\r\n\t\tapp.AccountKeeper,\r\n\t\tBlockedAddresses(),\r\n\t\tauthtypes.NewModuleAddress(govtypes.ModuleName).String(),\r\n\t)\r\n\tapp.StakingKeeper = stakingkeeper.NewKeeper(\r\n\t\tappCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(),\r\n\t)\r\n\tapp.MintKeeper = mintkeeper.NewKeeper(appCodec, keys[minttypes.StoreKey], app.StakingKeeper, app.AccountKeeper, app.BankKeeper, authtypes.FeeCollectorName, authtypes.NewModuleAddress(govtypes.ModuleName).String())\r\n\r\n\tapp.DistrKeeper = distrkeeper.NewKeeper(appCodec, keys[distrtypes.StoreKey], app.AccountKeeper, app.BankKeeper, app.StakingKeeper, authtypes.FeeCollectorName, authtypes.NewModuleAddress(govtypes.ModuleName).String())\r\n\r\n\tapp.SlashingKeeper = slashingkeeper.NewKeeper(\r\n\t\tappCodec, legacyAmino, keys[slashingtypes.StoreKey], app.StakingKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(),\r\n\t)\r\n\r\n\tinvCheckPeriod := cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod))\r\n\tapp.CrisisKeeper = crisiskeeper.NewKeeper(appCodec, keys[crisistypes.StoreKey], invCheckPeriod,\r\n\t\tapp.BankKeeper, authtypes.FeeCollectorName, authtypes.NewModuleAddress(govtypes.ModuleName).String())\r\n\r\n\tapp.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegrant.StoreKey], app.AccountKeeper)\r\n\r\n\t// register the staking hooks\r\n\t// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks\r\n\tapp.StakingKeeper.SetHooks(\r\n\t\tstakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()),\r\n\t)\r\n\r\n\tapp.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.MsgServiceRouter(), app.AccountKeeper)\r\n\r\n\tgroupConfig := group.DefaultConfig()\r\n\t/*\r\n\t\tExample of setting group params:\r\n\t\tgroupConfig.MaxMetadataLen = 1000\r\n\t*/\r\n\tapp.GroupKeeper = groupkeeper.NewKeeper(keys[group.StoreKey], appCodec, app.MsgServiceRouter(), app.AccountKeeper, groupConfig)\r\n\r\n\t// get skipUpgradeHeights from the app options\r\n\tskipUpgradeHeights := map[int64]bool{}\r\n\tfor _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) {\r\n\t\tskipUpgradeHeights[int64(h)] = true\r\n\t}\r\n\thomePath := cast.ToString(appOpts.Get(flags.FlagHome))\r\n\t// set the governance module account as the authority for conducting upgrades\r\n\tapp.UpgradeKeeper = upgradekeeper.NewKeeper(skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp, authtypes.NewModuleAddress(govtypes.ModuleName).String())\r\n\r\n\t// Register the proposal types\r\n\t// Deprecated: Avoid adding new handlers, instead use the new proposal flow\r\n\t// by granting the governance module the right to execute the message.\r\n\t// See: https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/gov/spec/01_concepts.md#proposal-messages\r\n\tgovRouter := govv1beta1.NewRouter()\r\n\tgovRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).\r\n\t\tAddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).\r\n\t\tAddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper))\r\n\tgovConfig := govtypes.DefaultConfig()\r\n\t/*\r\n\t\tExample of setting gov params:\r\n\t\tgovConfig.MaxMetadataLen = 10000\r\n\t*/\r\n\tgovKeeper := govkeeper.NewKeeper(\r\n\t\tappCodec, keys[govtypes.StoreKey], app.AccountKeeper, app.BankKeeper,\r\n\t\tapp.StakingKeeper, app.MsgServiceRouter(), govConfig, authtypes.NewModuleAddress(govtypes.ModuleName).String(),\r\n\t)\r\n\r\n\t// Set legacy router for backwards compatibility with gov v1beta1\r\n\tgovKeeper.SetLegacyRouter(govRouter)\r\n\r\n\tapp.GovKeeper = *govKeeper.SetHooks(\r\n\t\tgovtypes.NewMultiGovHooks(\r\n\t\t// register the governance hooks\r\n\t\t),\r\n\t)\r\n\r\n\tapp.NFTKeeper = nftkeeper.NewKeeper(keys[nftkeeper.StoreKey], appCodec, app.AccountKeeper, app.BankKeeper)\r\n\r\n\t// create evidence keeper with router\r\n\tevidenceKeeper := evidencekeeper.NewKeeper(\r\n\t\tappCodec, keys[evidencetypes.StoreKey], app.StakingKeeper, app.SlashingKeeper,\r\n\t)\r\n\t// If evidence needs to be handled for the app, set routes in router here and seal\r\n\tapp.EvidenceKeeper = *evidenceKeeper\r\n\r\n\t/****  Module Options ****/\r\n\r\n\t// NOTE: we may consider parsing `appOpts` inside module constructors. For the moment\r\n\t// we prefer to be more strict in what arguments the modules expect.\r\n\tskipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants))\r\n\r\n\t// NOTE: Any module instantiated in the module manager that is later modified\r\n\t// must be passed by reference here.\r\n\tapp.ModuleManager = module.NewManager(\r\n\t\tgenutil.NewAppModule(\r\n\t\t\tapp.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx,\r\n\t\t\tencodingConfig.TxConfig,\r\n\t\t),\r\n\t\tauth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)),\r\n\t\tvesting.NewAppModule(app.AccountKeeper, app.BankKeeper),\r\n\t\tbank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)),\r\n\t\tcapability.NewAppModule(appCodec, *app.CapabilityKeeper, false),\r\n\t\tcrisis.NewAppModule(app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)),\r\n\t\tfeegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),\r\n\t\tgov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)),\r\n\t\tmint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)),\r\n\t\tslashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName)),\r\n\t\tdistr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)),\r\n\t\tstaking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)),\r\n\t\tupgrade.NewAppModule(app.UpgradeKeeper),\r\n\t\tevidence.NewAppModule(app.EvidenceKeeper),\r\n\t\tparams.NewAppModule(app.ParamsKeeper),\r\n\t\tauthzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),\r\n\t\tgroupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),\r\n\t\tnftmodule.NewAppModule(appCodec, app.NFTKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),\r\n\t\tconsensus.NewAppModule(appCodec, app.ConsensusParamsKeeper),\r\n\t)\r\n\r\n\t// During begin block slashing happens after distr.BeginBlocker so that\r\n\t// there is nothing left over in the validator fee pool, so as to keep the\r\n\t// CanWithdrawInvariant invariant.\r\n\t// NOTE: staking module is required if HistoricalEntries param > 0\r\n\t// NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC)\r\n\tapp.ModuleManager.SetOrderBeginBlockers(\r\n\t\tupgradetypes.ModuleName,\r\n\t\tcapabilitytypes.ModuleName,\r\n\t\tminttypes.ModuleName,\r\n\t\tdistrtypes.ModuleName,\r\n\t\tslashingtypes.ModuleName,\r\n\t\tevidencetypes.ModuleName,\r\n\t\tstakingtypes.ModuleName,\r\n\t\tgenutiltypes.ModuleName,\r\n\t\tauthz.ModuleName,\r\n\t)\r\n\tapp.ModuleManager.SetOrderEndBlockers(\r\n\t\tcrisistypes.ModuleName,\r\n\t\tgovtypes.ModuleName,\r\n\t\tstakingtypes.ModuleName,\r\n\t\tgenutiltypes.ModuleName,\r\n\t\tfeegrant.ModuleName,\r\n\t\tgroup.ModuleName,\r\n\t)\r\n\r\n\t// NOTE: The genutils module must occur after staking so that pools are\r\n\t// properly initialized with tokens from genesis accounts.\r\n\t// NOTE: The genutils module must also occur after auth so that it can access the params from auth.\r\n\t// NOTE: Capability module must occur first so that it can initialize any capabilities\r\n\t// so that other modules that want to create or claim capabilities afterwards in InitChain\r\n\t// can do so safely.\r\n\tgenesisModuleOrder := []string{\r\n\t\tcapabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName,\r\n\t\tdistrtypes.ModuleName, stakingtypes.ModuleName, slashingtypes.ModuleName, govtypes.ModuleName,\r\n\t\tminttypes.ModuleName, crisistypes.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName,\r\n\t\tfeegrant.ModuleName, nft.ModuleName, group.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName,\r\n\t\tvestingtypes.ModuleName, consensusparamtypes.ModuleName,\r\n\t}\r\n\tapp.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...)\r\n\tapp.ModuleManager.SetOrderExportGenesis(genesisModuleOrder...)\r\n\r\n\t// Uncomment if you want to set a custom migration order here.\r\n\t// app.ModuleManager.SetOrderMigrations(custom order)\r\n\r\n\tapp.ModuleManager.RegisterInvariants(app.CrisisKeeper)\r\n\tapp.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter())\r\n\tapp.ModuleManager.RegisterServices(app.configurator)\r\n\r\n\t// RegisterUpgradeHandlers is used for registering any on-chain upgrades.\r\n\t// Make sure it's called after `app.ModuleManager` and `app.configurator` are set.\r\n\tapp.RegisterUpgradeHandlers()\r\n\r\n\tautocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.ModuleManager.Modules))\r\n\r\n\treflectionSvc, err := runtimeservices.NewReflectionService()\r\n\tif err != nil {\r\n\t\tpanic(err)\r\n\t}\r\n\treflectionv1.RegisterReflectionServiceServer(app.GRPCQueryRouter(), reflectionSvc)\r\n\r\n\t// add test gRPC service for testing gRPC queries in isolation\r\n\ttestdata_pulsar.RegisterQueryServer(app.GRPCQueryRouter(), testdata_pulsar.QueryImpl{})\r\n\r\n\t// create the simulation manager and define the order of the modules for deterministic simulations\r\n\t//\r\n\t// NOTE: this is not required apps that don't use the simulator for fuzz testing\r\n\t// transactions\r\n\toverrideModules := map[string]module.AppModuleSimulation{\r\n\t\tauthtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)),\r\n\t}\r\n\tapp.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules)\r\n\r\n\tapp.sm.RegisterStoreDecoders()\r\n\r\n\t// initialize stores\r\n\tapp.MountKVStores(keys)\r\n\tapp.MountTransientStores(tkeys)\r\n\tapp.MountMemoryStores(memKeys)\r\n\r\n\t// initialize BaseApp\r\n\tapp.SetInitChainer(app.InitChainer)\r\n\tapp.SetBeginBlocker(app.BeginBlocker)\r\n\tapp.SetEndBlocker(app.EndBlocker)\r\n\tapp.setAnteHandler(encodingConfig.TxConfig)\r\n\tapp.setPostHandler()\r\n\r\n\tif loadLatest {\r\n\t\tif err := app.LoadLatestVersion(); err != nil {\r\n\t\t\tlogger.Error(\"error on loading last version\", \"err\", err)\r\n\t\t\tos.Exit(1)\r\n\t\t}\r\n\t}\r\n\r\n\treturn app\r\n}\r\n\r\nfunc (app *SimApp) setAnteHandler(txConfig client.TxConfig) {\r\n\tanteHandler, err := ante.NewAnteHandler(\r\n\t\tante.HandlerOptions{\r\n\t\t\tAccountKeeper:   app.AccountKeeper,\r\n\t\t\tBankKeeper:      app.BankKeeper,\r\n\t\t\tSignModeHandler: txConfig.SignModeHandler(),\r\n\t\t\tFeegrantKeeper:  app.FeeGrantKeeper,\r\n\t\t\tSigGasConsumer:  ante.DefaultSigVerificationGasConsumer,\r\n\t\t},\r\n\t)\r\n\tif err != nil {\r\n\t\tpanic(err)\r\n\t}\r\n\r\n\tapp.SetAnteHandler(anteHandler)\r\n}\r\n\r\nfunc (app *SimApp) setPostHandler() {\r\n\tpostHandler, err := posthandler.NewPostHandler(\r\n\t\tposthandler.HandlerOptions{},\r\n\t)\r\n\tif err != nil {\r\n\t\tpanic(err)\r\n\t}\r\n\r\n\tapp.SetPostHandler(postHandler)\r\n}\r\n\r\n// Name returns the name of the App\r\nfunc (app *SimApp) Name() string { return app.BaseApp.Name() }\r\n\r\n// BeginBlocker application updates every begin block\r\nfunc (app *SimApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {\r\n\treturn app.ModuleManager.BeginBlock(ctx, req)\r\n}\r\n\r\n// EndBlocker application updates every end block\r\nfunc (app *SimApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {\r\n\treturn app.ModuleManager.EndBlock(ctx, req)\r\n}\r\n\r\nfunc (a *SimApp) Configurator() module.Configurator {\r\n\treturn a.configurator\r\n}\r\n\r\n// InitChainer application update at chain initialization\r\nfunc (app *SimApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {\r\n\tvar genesisState GenesisState\r\n\tif err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil {\r\n\t\tpanic(err)\r\n\t}\r\n\tapp.UpgradeKeeper.SetModuleVersionMap(ctx, app.ModuleManager.GetVersionMap())\r\n\treturn app.ModuleManager.InitGenesis(ctx, app.appCodec, genesisState)\r\n}\r\n\r\n// LoadHeight loads a particular height\r\nfunc (app *SimApp) LoadHeight(height int64) error {\r\n\treturn app.LoadVersion(height)\r\n}\r\n\r\n// LegacyAmino returns SimApp's amino codec.\r\n//\r\n// NOTE: This is solely to be used for testing purposes as it may be desirable\r\n// for modules to register their own custom testing types.\r\nfunc (app *SimApp) LegacyAmino() *codec.LegacyAmino {\r\n\treturn app.legacyAmino\r\n}\r\n\r\n// AppCodec returns SimApp's app codec.\r\n//\r\n// NOTE: This is solely to be used for testing purposes as it may be desirable\r\n// for modules to register their own custom testing types.\r\nfunc (app *SimApp) AppCodec() codec.Codec {\r\n\treturn app.appCodec\r\n}\r\n\r\n// InterfaceRegistry returns SimApp's InterfaceRegistry\r\nfunc (app *SimApp) InterfaceRegistry() types.InterfaceRegistry {\r\n\treturn app.interfaceRegistry\r\n}\r\n\r\n// TxConfig returns SimApp's TxConfig\r\nfunc (app *SimApp) TxConfig() client.TxConfig {\r\n\treturn app.txConfig\r\n}\r\n\r\n// AutoCliOpts returns the autocli options for the app.\r\nfunc (app *SimApp) AutoCliOpts() autocli.AppOptions {\r\n\tmodules := make(map[string]appmodule.AppModule, 0)\r\n\tfor _, m := range app.ModuleManager.Modules {\r\n\t\tif moduleWithName, ok := m.(module.HasName); ok {\r\n\t\t\tmoduleName := moduleWithName.Name()\r\n\t\t\tif appModule, ok := moduleWithName.(appmodule.AppModule); ok {\r\n\t\t\t\tmodules[moduleName] = appModule\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn autocli.AppOptions{Modules: modules}\r\n}\r\n\r\n// DefaultGenesis returns a default genesis from the registered AppModuleBasic's.\r\nfunc (a *SimApp) DefaultGenesis() map[string]json.RawMessage {\r\n\treturn ModuleBasics.DefaultGenesis(a.appCodec)\r\n}\r\n\r\n// GetKey returns the KVStoreKey for the provided store key.\r\n//\r\n// NOTE: This is solely to be used for testing purposes.\r\nfunc (app *SimApp) GetKey(storeKey string) *storetypes.KVStoreKey {\r\n\treturn app.keys[storeKey]\r\n}\r\n\r\n// GetTKey returns the TransientStoreKey for the provided store key.\r\n//\r\n// NOTE: This is solely to be used for testing purposes.\r\nfunc (app *SimApp) GetTKey(storeKey string) *storetypes.TransientStoreKey {\r\n\treturn app.tkeys[storeKey]\r\n}\r\n\r\n// GetMemKey returns the MemStoreKey for the provided mem key.\r\n//\r\n// NOTE: This is solely used for testing purposes.\r\nfunc (app *SimApp) GetMemKey(storeKey string) *storetypes.MemoryStoreKey {\r\n\treturn app.memKeys[storeKey]\r\n}\r\n\r\n// GetSubspace returns a param subspace for a given module name.\r\n//\r\n// NOTE: This is solely to be used for testing purposes.\r\nfunc (app *SimApp) GetSubspace(moduleName string) paramstypes.Subspace {\r\n\tsubspace, _ := app.ParamsKeeper.GetSubspace(moduleName)\r\n\treturn subspace\r\n}\r\n\r\n// SimulationManager implements the SimulationApp interface\r\nfunc (app *SimApp) SimulationManager() *module.SimulationManager {\r\n\treturn app.sm\r\n}\r\n\r\n// RegisterAPIRoutes registers all application module routes with the provided\r\n// API server.\r\nfunc (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {\r\n\tclientCtx := apiSvr.ClientCtx\r\n\t// Register new tx routes from grpc-gateway.\r\n\tauthtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)\r\n\r\n\t// Register new tendermint queries routes from grpc-gateway.\r\n\ttmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)\r\n\r\n\t// Register node gRPC service for grpc-gateway.\r\n\tnodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)\r\n\r\n\t// Register grpc-gateway routes for all modules.\r\n\tModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)\r\n\r\n\t// register swagger API from root so that other applications can override easily\r\n\tif err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil {\r\n\t\tpanic(err)\r\n\t}\r\n}\r\n\r\n// RegisterTxService implements the Application.RegisterTxService method.\r\nfunc (app *SimApp) RegisterTxService(clientCtx client.Context) {\r\n\tauthtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry)\r\n}\r\n\r\n// RegisterTendermintService implements the Application.RegisterTendermintService method.\r\nfunc (app *SimApp) RegisterTendermintService(clientCtx client.Context) {\r\n\ttmservice.RegisterTendermintService(\r\n\t\tclientCtx,\r\n\t\tapp.BaseApp.GRPCQueryRouter(),\r\n\t\tapp.interfaceRegistry,\r\n\t\tapp.Query,\r\n\t)\r\n}\r\n\r\nfunc (app *SimApp) RegisterNodeService(clientCtx client.Context) {\r\n\tnodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter())\r\n}\r\n\r\n// GetMaccPerms returns a copy of the module account permissions\r\n//\r\n// NOTE: This is solely to be used for testing purposes.\r\nfunc GetMaccPerms() map[string][]string {\r\n\tdupMaccPerms := make(map[string][]string)\r\n\tfor k, v := range maccPerms {\r\n\t\tdupMaccPerms[k] = v\r\n\t}\r\n\r\n\treturn dupMaccPerms\r\n}\r\n\r\n// BlockedAddresses returns all the app's blocked account addresses.\r\nfunc BlockedAddresses() map[string]bool {\r\n\tmodAccAddrs := make(map[string]bool)\r\n\tfor acc := range GetMaccPerms() {\r\n\t\tmodAccAddrs[authtypes.NewModuleAddress(acc).String()] = true\r\n\t}\r\n\r\n\t// allow the following addresses to receive funds\r\n\tdelete(modAccAddrs, authtypes.NewModuleAddress(govtypes.ModuleName).String())\r\n\r\n\treturn modAccAddrs\r\n}\r\n\r\n// initParamsKeeper init params keeper and its subspaces\r\nfunc initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper {\r\n\tparamsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey)\r\n\r\n\tparamsKeeper.Subspace(authtypes.ModuleName)\r\n\tparamsKeeper.Subspace(banktypes.ModuleName)\r\n\tparamsKeeper.Subspace(stakingtypes.ModuleName)\r\n\tparamsKeeper.Subspace(minttypes.ModuleName)\r\n\tparamsKeeper.Subspace(distrtypes.ModuleName)\r\n\tparamsKeeper.Subspace(slashingtypes.ModuleName)\r\n\tparamsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1.ParamKeyTable())\r\n\tparamsKeeper.Subspace(crisistypes.ModuleName)\r\n\r\n\treturn paramsKeeper\r\n}\r\n\r\nfunc makeEncodingConfig() simappparams.EncodingConfig {\r\n\tencodingConfig := simappparams.MakeTestEncodingConfig()\r\n\tstd.RegisterLegacyAminoCodec(encodingConfig.Amino)\r\n\tstd.RegisterInterfaces(encodingConfig.InterfaceRegistry)\r\n\tModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino)\r\n\tModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry)\r\n\treturn encodingConfig\r\n}\r\n\r\n```\r\n\r\n`SimApp`是使用 Cosmos SDK生成的用于测试和学习的应用程序，可以通过SimApp的创链过程，了解Cosmos SDK的基础构造和运行过程。\r\n\r\n下面介绍如何运行基于SimApp的simd测试网:\r\n\r\n- 从 Cosmos SDK 存储库的根目录中，运行`make build`。这将在新目录`build`中构建二进制文件。后续指令需要在`build`目录内运行。\r\n\r\n```shell\r\nlinux@linux:~/Cosmos/cosmos-sdk-main$ make build\r\nfatal: 不是 git 仓库（或者任何父目录）：.git\r\nfatal: 不是 git 仓库（或者任何父目录）：.git\r\nmkdir -p /home/linux/Cosmos/cosmos-sdk-main/build/\r\ncd /home/linux/Cosmos/cosmos-sdk-main/simapp && go build -mod=readonly -tags \"netgo ledger\" -ldflags '-X github.com/cosmos/cosmos-sdk/version.Name=sim -X github.com/cosmos/cosmos-sdk/version.AppName=simd -X github.com/cosmos/cosmos-sdk/version.Version= -X github.com/cosmos/cosmos-sdk/version.Commit= -X \"github.com/cosmos/cosmos-sdk/version.BuildTags=netgo,ledger\" -X github.com/tendermint/tendermint/version.TMCoreSemVer=v0.37.0-rc2 -w -s' -trimpath -o /home/linux/Cosmos/cosmos-sdk-main/build/ ./...\r\ngo: downloading cosmossdk.io/math v1.0.0-beta.4\r\ngo: downloading github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32\r\ngo: downloading cosmossdk.io/tools/rosetta v0.2.0\r\ngo: downloading github.com/tendermint/tendermint v0.37.0-rc2\r\ngo: downloading github.com/spf13/cobra v1.6.1\r\ngo: downloading github.com/spf13/viper v1.14.0\r\ngo: downloading github.com/cosmos/gogoproto v1.4.3\r\ngo: downloading github.com/golang/protobuf v1.5.2\r\ngo: downloading github.com/grpc-ecosystem/grpc-gateway v1.16.0\r\ngo: downloading google.golang.org/grpc v1.51.0\r\ngo: downloading google.golang.org/protobuf v1.28.1\r\ngo: downloading cosmossdk.io/api v0.2.6\r\ngo: downloading cosmossdk.io/client/v2 v2.0.0-20230104083136-11f46a0bae58\r\ngo: downloading cosmossdk.io/core v0.4.0\r\ngo: downloading cosmossdk.io/depinject v1.0.0-alpha.3\r\ngo: downloading github.com/stretchr/testify v1.8.1\r\ngo: downloading github.com/tendermint/go-amino v0.16.0\r\ngo: downloading sigs.k8s.io/yaml v1.3.0\r\ngo: downloading github.com/pkg/errors v0.9.1\r\ngo: downloading github.com/cosmos/go-bip39 v1.0.0\r\ngo: downloading github.com/btcsuite/btcd/btcec/v2 v2.3.2\r\ngo: downloading github.com/cosmos/keyring v1.2.0\r\ngo: downloading github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15\r\ngo: downloading cosmossdk.io/errors v1.0.0-beta.7\r\ngo: downloading github.com/gorilla/mux v1.8.0\r\ngo: downloading github.com/rakyll/statik v0.1.7\r\ngo: downloading github.com/spf13/cast v1.5.0\r\ngo: downloading golang.org/x/exp v0.0.0-20221019170559-20944726eadf\r\ngo: downloading github.com/cosmos/cosmos-proto v1.0.0-beta.1\r\ngo: downloading github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d\r\ngo: downloading google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef\r\ngo: downloading github.com/fsnotify/fsnotify v1.6.0\r\ngo: downloading github.com/mitchellh/mapstructure v1.5.0\r\ngo: downloading github.com/spf13/afero v1.9.2\r\ngo: downloading github.com/spf13/jwalterweatherman v1.1.0\r\ngo: downloading github.com/google/btree v1.1.2\r\ngo: downloading github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7\r\ngo: downloading github.com/grpc-ecosystem/go-grpc-middleware v1.3.0\r\ngo: downloading golang.org/x/crypto v0.5.0\r\ngo: downloading github.com/cosmos/gogogateway v1.2.0\r\ngo: downloading github.com/gorilla/handlers v1.5.1\r\ngo: downloading github.com/confio/ics23/go v0.9.0\r\ngo: downloading github.com/golang/mock v1.6.0\r\ngo: downloading github.com/armon/go-metrics v0.4.1\r\ngo: downloading github.com/go-kit/log v0.2.1\r\ngo: downloading github.com/go-logfmt/logfmt v0.5.1\r\ngo: downloading golang.org/x/net v0.5.0\r\ngo: downloading github.com/cosmos/iavl v0.20.0-alpha1\r\ngo: downloading github.com/go-kit/kit v0.12.0\r\ngo: downloading github.com/prometheus/client_golang v1.14.0\r\ngo: downloading github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3\r\ngo: downloading github.com/bgentry/speakeasy v0.1.0\r\ngo: downloading github.com/mattn/go-isatty v0.0.17\r\ngo: downloading github.com/cosmos/ledger-cosmos-go v0.12.2\r\ngo: downloading github.com/tendermint/btcd v0.1.1\r\ngo: downloading github.com/cosmos/btcutil v1.0.5\r\ngo: downloading github.com/prometheus/common v0.39.0\r\ngo: downloading github.com/davecgh/go-spew v1.1.1\r\ngo: downloading github.com/pmezard/go-difflib v1.0.0\r\ngo: downloading gopkg.in/yaml.v3 v3.0.1\r\ngo: downloading github.com/improbable-eng/grpc-web v0.15.0\r\ngo: downloading github.com/lib/pq v1.10.7\r\ngo: downloading github.com/rs/cors v1.8.2\r\ngo: downloading github.com/tendermint/tm-db v0.6.7\r\ngo: downloading pgregory.net/rapid v0.5.3\r\n```\r\n\r\n- 执行`$ ./simd init [moniker] --chain-id [chain-id]`.这将初始化一个新的隐藏工作目录`~/.simapp`在默认位置 。需要提供[moniker]和[chain-id]。两个名称可以是任何名称，但在后续步骤中，需要使用相同值。\r\n\r\n```shell\r\nlinux@linux:~/Cosmos/cosmos-sdk-main/build$  ./simd init monkey --chain-id 3307\r\n{\"app_message\":{\"auth\":{\"accounts\":[],\"params\":{\"max_memo_characters\":\"256\",\"sig_verify_cost_ed25519\":\"590\",\"sig_verify_cost_secp256k1\":\"1000\",\"tx_sig_limit\":\"7\",\"tx_size_cost_per_byte\":\"10\"}},\"authz\":{\"authorization\":[]},\"bank\":{\"balances\":[],\"denom_metadata\":[],\"params\":{\"default_send_enabled\":true,\"send_enabled\":[]},\"send_enabled\":[],\"supply\":[]},\"capability\":{\"index\":\"1\",\"owners\":[]},\"consensus\":null,\"crisis\":{\"constant_fee\":{\"amount\":\"1000\",\"denom\":\"stake\"}},\"distribution\":{\"delegator_starting_infos\":[],\"delegator_withdraw_infos\":[],\"fee_pool\":{\"community_pool\":[]},\"outstanding_rewards\":[],\"params\":{\"base_proposer_reward\":\"0.000000000000000000\",\"bonus_proposer_reward\":\"0.000000000000000000\",\"community_tax\":\"0.020000000000000000\",\"withdraw_addr_enabled\":true},\"previous_proposer\":\"\",\"validator_accumulated_commissions\":[],\"validator_current_rewards\":[],\"validator_historical_rewards\":[],\"validator_slash_events\":[]},\"evidence\":{\"evidence\":[]},\"feegrant\":{\"allowances\":[]},\"genutil\":{\"gen_txs\":[]},\"gov\":{\"deposit_params\":null,\"deposits\":[],\"params\":{\"max_deposit_period\":\"172800s\",\"min_deposit\":[{\"amount\":\"10000000\",\"denom\":\"stake\"}],\"min_initial_deposit_ratio\":\"0.000000000000000000\",\"quorum\":\"0.334000000000000000\",\"threshold\":\"0.500000000000000000\",\"veto_threshold\":\"0.334000000000000000\",\"voting_period\":\"172800s\"},\"proposals\":[],\"starting_proposal_id\":\"1\",\"tally_params\":null,\"votes\":[],\"voting_params\":null},\"group\":{\"group_members\":[],\"group_policies\":[],\"group_policy_seq\":\"0\",\"group_seq\":\"0\",\"groups\":[],\"proposal_seq\":\"0\",\"proposals\":[],\"votes\":[]},\"mint\":{\"minter\":{\"annual_provisions\":\"0.000000000000000000\",\"inflation\":\"0.130000000000000000\"},\"params\":{\"blocks_per_year\":\"6311520\",\"goal_bonded\":\"0.670000000000000000\",\"inflation_max\":\"0.200000000000000000\",\"inflation_min\":\"0.070000000000000000\",\"inflation_rate_change\":\"0.130000000000000000\",\"mint_denom\":\"stake\"}},\"nft\":{\"classes\":[],\"entries\":[]},\"params\":null,\"slashing\":{\"missed_blocks\":[],\"params\":{\"downtime_jail_duration\":\"600s\",\"min_signed_per_window\":\"0.500000000000000000\",\"signed_blocks_window\":\"100\",\"slash_fraction_double_sign\":\"0.050000000000000000\",\"slash_fraction_downtime\":\"0.010000000000000000\"},\"signing_infos\":[]},\"staking\":{\"delegations\":[],\"exported\":false,\"last_total_power\":\"0\",\"last_validator_powers\":[],\"params\":{\"bond_denom\":\"stake\",\"historical_entries\":10000,\"max_entries\":7,\"max_validators\":100,\"min_commission_rate\":\"0.000000000000000000\",\"unbonding_time\":\"1814400s\"},\"redelegations\":[],\"unbonding_delegations\":[],\"validators\":[]},\"upgrade\":{},\"vesting\":{}},\"chain_id\":\"3307\",\"gentxs_dir\":\"\",\"moniker\":\"monkey\",\"node_id\":\"a618eb59133c6a89252e4e7d0f6f2f5c724bcc58\"}\r\nlinux@linux:~/Cosmos/cosmos-sdk-main/build$ \r\n```\r\n\r\n- `$ ./simd keys add [key_name]`.这将创建一个新密钥，其中包含可随意选择的名称[key_name]。执行命令后，终端输出的内容需要保存一下，信息非常重要。\r\n\r\n```shell\r\nlinux@linux:~/Cosmos/cosmos-sdk-main/build$ ./simd keys add keyname\r\n\r\n- address: cosmos1v9x8reez5zkt7h5kcykzgtssdead0mv6jl7k8f\r\n  name: keyname\r\n  pubkey: '{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\",\"key\":\"Ahg+4lFkHp3ylHGbDl0ghDCLLHblmSdhLAUSp8iCL6+9\"}'\r\n  type: local\r\n\r\n\r\n**Important** write this mnemonic phrase in a safe place.\r\nIt is the only way to recover your account if you ever forget your password.\r\n\r\nminor gown melody joy wait mother bright eternal wealth odor orchard habit pluck name image badge ticket aerobic option cross approve foster liberty truck\r\nlinux@linux:~/Cosmos/cosmos-sdk-main/build$ \r\n```\r\n\r\n\r\n![image-20230106200943150.png](https://img.learnblockchain.cn/attachments/2023/01/WZjiKHdK63b8f010023ce.png)\r\n\r\n- `$ ./simd genesis add-genesis-account [key_name] [amount]`，这里的[key_name]与之前保持一致，而[amount]可以填写类似于`10000000000000000000000000stake`的值。\r\n\r\n```shell\r\nlinux@linux:~/Cosmos/cosmos-sdk-main/build$ ./simd genesis add-genesis-account  keyname 10000000000000000000000000stake\r\nlinux@linux:~/Cosmos/cosmos-sdk-main/build$ \r\n```\r\n\r\n注：这里在官方文档中存在错误，官方文档中给出的命令为：\r\n\r\n\r\n![image-20230107102423465.png](https://img.learnblockchain.cn/attachments/2023/01/U99Utvny63b8f0210da98.png)\r\n\r\n- $ `./simd genesis gentx [key_name] [amount] --chain-id [chain-id]`，为新链创造初始交易，这里的[amount]不可过多或过少，至少为`1000000000stake`，否则启动节点时会报错。\r\n\r\n```shell\r\nlinux@linux:~/Cosmos/cosmos-sdk-main/build$ ./simd genesis gentx keyname 10000000000stake --chain-id 3307\r\nGenesis transaction written to \"/home/linux/.simapp/config/gentx/gentx-a618eb59133c6a89252e4e7d0f6f2f5c724bcc58.json\"\r\nlinux@linux:~/Cosmos/cosmos-sdk-main/build$ \r\n```\r\n\r\n- $ `./simd collect-gentxs`生成包含初始交易的json文件，若有多人参与，则可以包含多个json文件。\r\n\r\n\r\n![image-20230106190053392.png](https://img.learnblockchain.cn/attachments/2023/01/VnM5n6Yl63b8f032871a0.png)\r\n\r\n` ./simd start`启动节点。\r\n\r\n```shell\r\nlinux@linux:~/Cosmos/cosmos-sdk-main/build$ ./simd start\r\n```\r\n\r\n\r\n![image-20230106210513119.png](https://img.learnblockchain.cn/attachments/2023/01/oQCobW0D63b8f04165ba9.png)\r\n\r\n![image-20230106210534964.png](https://img.learnblockchain.cn/attachments/2023/01/tqhkdECN63b8f04e8af00.png)\r\n\r\n\r\n![image-20230106210609592.png](https://img.learnblockchain.cn/attachments/2023/01/kH8hCVa463b8f055040ca.png)\r\n\r\n\r\n![image-20230106210642150.png](https://img.learnblockchain.cn/attachments/2023/01/3i05lxoI63b8f05bb1475.png)\r\n\r\n\r\n![image-20230106210711606.png](https://img.learnblockchain.cn/attachments/2023/01/1bh7RuO863b8f061c937f.png)\r\n\r\n现在一个小型测试网构建成功，可以用来尝试对Cosmos SDK或Tendermint的修改。\r\n\r\n## 思考\r\n\r\n其实面向应用场景构建区块链这件事在国内的联盟链中已经有所体现。在FISCO BCOS 3.x中，就已经考虑了根据多样化的场景诉求，对于区块链的底层平台特性进行划归。FISCO BCOS开源社区经过5年发展，生态内的产业角色逐渐丰富，这几年也遇到几类典型用户：一类是落地应用的机构用户，他们基于FISCO BCOS投产落地众多应用，而且应用的业务量越来越大；一类是运营平台的机构用户，他们基于FISCO BCOS构建了BaaS平台对外提供服务；还有一类是以个人开发者为代表的学习型用户。这几类用户诉求存在比较大的差异：有大业务体量上链的机构需要区块链支撑海量计算和存储，可以承担较复杂系统的运维；BaaS平台的用户需要更好地区块链接入、隔离、计费机制等；而学习型用户则最需要简单易用、可快速上手的区块链工具。对于不同用户的诉求，v3.0采用灵活可扩展的开发框架，根据不同场景用户需求专业定制。因此，FISCO BCOS发布了3款不同类型的版本，分别是“轻便Air版”、“专业Pro版”和“大容量Max版”。\r\n\r\n Air版：沿用FISCO BCOS v2.0的all-in-one设计，区块链底层所有能力打包成一个服务，可供学习型用户，在入门、开发、测试、POC验证等场景中快速上手使用。\r\n\r\n Pro版：将接入层单独剥离，区块链核心能力通过多群组方式扩展，适用于常规生产业务，特别适合BaaS平台构建基于群组的区块链底层基础能力。\r\n\r\n Max版：采用前面提到分层扩展微服务模式，适用大容量场景。\r\n\r\n因此，笔者认为FISCO BCOS未来也可以将区块链底层模块进行拆分，在面向具体的应用场景时，能够实现一键化构造更加匹配特定应用场景的专用区块链，缓解纯智能合约编程带来的问题。同时，这样也有利于未来后量子密码算法嵌入区块链。在量子时代，区块链底层密码学算法一定会采用后量子密码方案。而从进入NIST第四轮评估的超奇异椭圆曲线同源密码已经被相关研究证明不再安全来看，将密码学模块设计成可拔插架构更利于区块链后量子安全体系的更新升级。\r\n\r\n## 参考文献\r\n\r\nhttps://docs.cosmos.network/\r\n\r\n[Cosmos: The Internet of Blockchains](https://cosmos.network/)\r\n\r\n[COSMOS (github.com)](https://github.com/cosmos)\r\n\r\nhttps://mp.weixin.qq.com/s/4EBw-hS_cS4H5wJMT-9Cnw\r\n\r\n[Cosmos-SDK/Simapp at v0.47.0-alpha1 ·Cosmos/Cosmos-SDK (github.com)](https://github.com/cosmos/cosmos-sdk/tree/v0.47.0-alpha1/simapp)\r\n\r\n[重磅发布 | FISCO BCOS v3.0核心特性与技术实现](https://www.fisco.org.cn/news_7/401.html)\r\n\r\n南京大学普惠三农金融科技创新研究中心[DigitalFinanceAndWorldSIG-DAO (github.com)](https://github.com/DigitalFinanceAndWorldSIG-DAO)"},"author":{"user":"https://learnblockchain.cn/people/11990","address":null},"history":null,"timestamp":1673064955,"version":1}