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