Implement initial ABCI logic
This commit is contained in:
parent
50e0602923
commit
f93135f0f8
152
app/ethermint.go
152
app/ethermint.go
@ -5,12 +5,19 @@ import (
|
|||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/cosmos/ethermint/handlers"
|
"github.com/cosmos/ethermint/handlers"
|
||||||
"github.com/cosmos/ethermint/types"
|
"github.com/cosmos/ethermint/types"
|
||||||
|
|
||||||
ethparams "github.com/ethereum/go-ethereum/params"
|
ethparams "github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
tmcmn "github.com/tendermint/tendermint/libs/common"
|
tmcmn "github.com/tendermint/tendermint/libs/common"
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
tmlog "github.com/tendermint/tendermint/libs/log"
|
tmlog "github.com/tendermint/tendermint/libs/log"
|
||||||
@ -28,51 +35,145 @@ type (
|
|||||||
*bam.BaseApp
|
*bam.BaseApp
|
||||||
|
|
||||||
codec *wire.Codec
|
codec *wire.Codec
|
||||||
sealed bool
|
|
||||||
|
|
||||||
accountKey *sdk.KVStoreKey
|
accountKey *sdk.KVStoreKey
|
||||||
accountMapper auth.AccountMapper
|
mainKey *sdk.KVStoreKey
|
||||||
// TODO: keys, stores, mappers, and keepers
|
stakeKey *sdk.KVStoreKey
|
||||||
}
|
slashingKey *sdk.KVStoreKey
|
||||||
|
govKey *sdk.KVStoreKey
|
||||||
|
feeCollKey *sdk.KVStoreKey
|
||||||
|
paramsKey *sdk.KVStoreKey
|
||||||
|
tParamsKey *sdk.TransientStoreKey
|
||||||
|
|
||||||
// Options is a function signature that provides the ability to modify
|
accountMapper auth.AccountMapper
|
||||||
// options of an EthermintApp during initialization.
|
feeCollKeeper auth.FeeCollectionKeeper
|
||||||
Options func(*EthermintApp)
|
coinKeeper bank.Keeper
|
||||||
|
stakeKeeper stake.Keeper
|
||||||
|
slashingKeeper slashing.Keeper
|
||||||
|
govKeeper gov.Keeper
|
||||||
|
paramsKeeper params.Keeper
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewEthermintApp returns a reference to a new initialized Ethermint
|
// NewEthermintApp returns a reference to a new initialized Ethermint
|
||||||
// application.
|
// application.
|
||||||
func NewEthermintApp(logger tmlog.Logger, db dbm.DB, ethChainCfg *ethparams.ChainConfig, opts ...Options,
|
func NewEthermintApp(
|
||||||
|
logger tmlog.Logger, db dbm.DB, ethChainCfg *ethparams.ChainConfig, baseAppOptions ...func(*bam.BaseApp),
|
||||||
) *EthermintApp {
|
) *EthermintApp {
|
||||||
|
|
||||||
codec := CreateCodec()
|
codec := CreateCodec()
|
||||||
app := &EthermintApp{
|
app := &EthermintApp{
|
||||||
BaseApp: bam.NewBaseApp(appName, logger, db, types.TxDecoder(codec)),
|
BaseApp: bam.NewBaseApp(appName, logger, db, types.TxDecoder(codec), baseAppOptions...),
|
||||||
codec: codec,
|
codec: codec,
|
||||||
accountKey: sdk.NewKVStoreKey("accounts"),
|
accountKey: sdk.NewKVStoreKey("acc"),
|
||||||
|
mainKey: sdk.NewKVStoreKey("main"),
|
||||||
|
stakeKey: sdk.NewKVStoreKey("stake"),
|
||||||
|
slashingKey: sdk.NewKVStoreKey("slashing"),
|
||||||
|
govKey: sdk.NewKVStoreKey("gov"),
|
||||||
|
feeCollKey: sdk.NewKVStoreKey("fee"),
|
||||||
|
paramsKey: sdk.NewKVStoreKey("params"),
|
||||||
|
tParamsKey: sdk.NewTransientStoreKey("transient_params"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set application keepers and mappers
|
||||||
app.accountMapper = auth.NewAccountMapper(codec, app.accountKey, auth.ProtoBaseAccount)
|
app.accountMapper = auth.NewAccountMapper(codec, app.accountKey, auth.ProtoBaseAccount)
|
||||||
|
app.coinKeeper = bank.NewKeeper(app.accountMapper)
|
||||||
|
app.paramsKeeper = params.NewKeeper(app.codec, app.paramsKey)
|
||||||
|
app.feeCollKeeper = auth.NewFeeCollectionKeeper(app.codec, app.feeCollKey)
|
||||||
|
app.stakeKeeper = stake.NewKeeper(
|
||||||
|
app.codec, app.stakeKey, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace),
|
||||||
|
)
|
||||||
|
app.govKeeper = gov.NewKeeper(
|
||||||
|
app.codec, app.govKey, app.paramsKeeper.Setter(), app.coinKeeper,
|
||||||
|
app.stakeKeeper, app.RegisterCodespace(gov.DefaultCodespace),
|
||||||
|
)
|
||||||
|
app.slashingKeeper = slashing.NewKeeper(
|
||||||
|
app.codec, app.slashingKey, app.stakeKeeper,
|
||||||
|
app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace),
|
||||||
|
)
|
||||||
|
|
||||||
app.SetAnteHandler(handlers.AnteHandler(app.accountMapper))
|
// register message handlers
|
||||||
app.MountStoresIAVL(app.accountKey)
|
app.Router().
|
||||||
|
// TODO: Do we need to mount bank and IBC handlers? Should be handled
|
||||||
|
// directly in the EVM.
|
||||||
|
AddRoute("stake", stake.NewHandler(app.stakeKeeper)).
|
||||||
|
AddRoute("slashing", slashing.NewHandler(app.slashingKeeper)).
|
||||||
|
AddRoute("gov", gov.NewHandler(app.govKeeper))
|
||||||
|
|
||||||
for _, opt := range opts {
|
// initialize the underlying ABCI BaseApp
|
||||||
opt(app)
|
app.SetInitChainer(app.initChainer)
|
||||||
}
|
app.SetBeginBlocker(app.BeginBlocker)
|
||||||
|
app.SetEndBlocker(app.EndBlocker)
|
||||||
|
app.SetAnteHandler(handlers.AnteHandler(app.accountMapper, app.feeCollKeeper))
|
||||||
|
|
||||||
err := app.LoadLatestVersion(app.accountKey)
|
app.MountStoresIAVL(
|
||||||
if err != nil {
|
app.mainKey, app.accountKey, app.stakeKey, app.slashingKey,
|
||||||
|
app.govKey, app.feeCollKey, app.paramsKey,
|
||||||
|
)
|
||||||
|
app.MountStore(app.tParamsKey, sdk.StoreTypeTransient)
|
||||||
|
|
||||||
|
if err := app.LoadLatestVersion(app.accountKey); err != nil {
|
||||||
tmcmn.Exit(err.Error())
|
tmcmn.Exit(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
app.seal()
|
app.BaseApp.Seal()
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
// seal seals the Ethermint application and prohibits any future modifications
|
// BeginBlocker signals the beginning of a block. It performs application
|
||||||
// that change critical components.
|
// updates on the start of every block.
|
||||||
func (app *EthermintApp) seal() {
|
func (app *EthermintApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
||||||
app.sealed = true
|
tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper)
|
||||||
|
|
||||||
|
return abci.ResponseBeginBlock{
|
||||||
|
Tags: tags.ToKVPairs(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndBlocker signals the end of a block. It performs application updates on
|
||||||
|
// the end of every block.
|
||||||
|
func (app *EthermintApp) EndBlocker(ctx sdk.Context, _ abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||||
|
tags := gov.EndBlocker(ctx, app.govKeeper)
|
||||||
|
validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper)
|
||||||
|
|
||||||
|
app.slashingKeeper.AddValidators(ctx, validatorUpdates)
|
||||||
|
|
||||||
|
return abci.ResponseEndBlock{
|
||||||
|
ValidatorUpdates: validatorUpdates,
|
||||||
|
Tags: tags,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initChainer initializes the application blockchain with validators and other
|
||||||
|
// state data from TendermintCore.
|
||||||
|
func (app *EthermintApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||||
|
var genesisState GenesisState
|
||||||
|
stateJSON := req.AppStateBytes
|
||||||
|
|
||||||
|
err := app.codec.UnmarshalJSON(stateJSON, &genesisState)
|
||||||
|
if err != nil {
|
||||||
|
panic(errors.Wrap(err, "failed to parse application genesis state"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the genesis accounts
|
||||||
|
for _, genAcc := range genesisState.Accounts {
|
||||||
|
acc := genAcc.ToAccount()
|
||||||
|
acc.AccountNumber = app.accountMapper.GetNextAccountNumber(ctx)
|
||||||
|
app.accountMapper.SetAccount(ctx, acc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the genesis stake information
|
||||||
|
validators, err := stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
|
||||||
|
if err != nil {
|
||||||
|
panic(errors.Wrap(err, "failed to initialize genesis validators"))
|
||||||
|
}
|
||||||
|
|
||||||
|
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.StakeData)
|
||||||
|
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
||||||
|
|
||||||
|
return abci.ResponseInitChain{
|
||||||
|
Validators: validators,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateCodec creates a new amino wire codec and registers all the necessary
|
// CreateCodec creates a new amino wire codec and registers all the necessary
|
||||||
@ -80,7 +181,12 @@ func (app *EthermintApp) seal() {
|
|||||||
func CreateCodec() *wire.Codec {
|
func CreateCodec() *wire.Codec {
|
||||||
codec := wire.NewCodec()
|
codec := wire.NewCodec()
|
||||||
|
|
||||||
// Register other modules, types, and messages...
|
|
||||||
types.RegisterWire(codec)
|
types.RegisterWire(codec)
|
||||||
|
auth.RegisterWire(codec)
|
||||||
|
gov.RegisterWire(codec)
|
||||||
|
slashing.RegisterWire(codec)
|
||||||
|
stake.RegisterWire(codec)
|
||||||
|
wire.RegisterCrypto(codec)
|
||||||
|
|
||||||
return codec
|
return codec
|
||||||
}
|
}
|
||||||
|
47
app/genesis.go
Normal file
47
app/genesis.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
"github.com/cosmos/ethermint/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// GenesisState defines the application's genesis state. It contains all the
|
||||||
|
// information required and accounts to initialize the blockchain.
|
||||||
|
GenesisState struct {
|
||||||
|
Accounts []GenesisAccount `json:"accounts"`
|
||||||
|
StakeData stake.GenesisState `json:"stake"`
|
||||||
|
GovData gov.GenesisState `json:"gov"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenesisAccount defines an account to be initialized in the genesis state.
|
||||||
|
GenesisAccount struct {
|
||||||
|
Address sdk.AccAddress `json:"address"`
|
||||||
|
Coins sdk.Coins `json:"coins"`
|
||||||
|
Code []byte `json:"code,omitempty"`
|
||||||
|
Storage types.Storage `json:"storage,omitempty"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewGenesisAccount returns a reference to a new initialized genesis account.
|
||||||
|
func NewGenesisAccount(acc *types.Account) GenesisAccount {
|
||||||
|
return GenesisAccount{
|
||||||
|
Address: acc.GetAddress(),
|
||||||
|
Coins: acc.GetCoins(),
|
||||||
|
Code: acc.Code,
|
||||||
|
Storage: acc.Storage,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToAccount converts a genesis account to an initialized Ethermint account.
|
||||||
|
func (ga *GenesisAccount) ToAccount() (acc *types.Account) {
|
||||||
|
base := auth.BaseAccount{
|
||||||
|
Address: ga.Address,
|
||||||
|
Coins: ga.Coins.Sort(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewAccount(base, ga.Code, ga.Storage)
|
||||||
|
}
|
@ -30,7 +30,7 @@ type internalAnteHandler func(
|
|||||||
// transaction to an internal ante handler for performing transaction-level
|
// transaction to an internal ante handler for performing transaction-level
|
||||||
// processing (e.g. fee payment, signature verification) before being passed
|
// processing (e.g. fee payment, signature verification) before being passed
|
||||||
// onto it's respective handler.
|
// onto it's respective handler.
|
||||||
func AnteHandler(am auth.AccountMapper) sdk.AnteHandler {
|
func AnteHandler(am auth.AccountMapper, _ auth.FeeCollectionKeeper) sdk.AnteHandler {
|
||||||
return func(sdkCtx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
return func(sdkCtx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
||||||
var (
|
var (
|
||||||
gasLimit int64
|
gasLimit int64
|
||||||
|
53
types/account.go
Normal file
53
types/account.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
|
||||||
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ auth.Account = (*Account)(nil)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Storage defines account storage
|
||||||
|
Storage map[ethcmn.Hash]ethcmn.Hash
|
||||||
|
|
||||||
|
// Account defines an auth.BaseAccount extension for Ethermint. It is
|
||||||
|
// compatible with the auth.AccountMapper.
|
||||||
|
Account struct {
|
||||||
|
auth.BaseAccount
|
||||||
|
|
||||||
|
Code []byte
|
||||||
|
Storage Storage
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewAccount returns a reference to a new initialized account.
|
||||||
|
func NewAccount(base auth.BaseAccount, code []byte, storage Storage) *Account {
|
||||||
|
return &Account{
|
||||||
|
BaseAccount: base,
|
||||||
|
Code: code,
|
||||||
|
Storage: storage,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccountDecoder returns the auth.AccountDecoder function for the custom
|
||||||
|
// Account type.
|
||||||
|
func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder {
|
||||||
|
return func(accBytes []byte) (auth.Account, error) {
|
||||||
|
if len(accBytes) == 0 {
|
||||||
|
return nil, sdk.ErrTxDecode("account bytes are empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
acc := new(Account)
|
||||||
|
|
||||||
|
err := cdc.UnmarshalBinaryBare(accBytes, &acc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, sdk.ErrTxDecode("failed to decode account bytes")
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc, err
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,8 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ sdk.Tx = (*Transaction)(nil)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TypeTxEthereum reflects an Ethereum Transaction type.
|
// TypeTxEthereum reflects an Ethereum Transaction type.
|
||||||
TypeTxEthereum = "Ethereum"
|
TypeTxEthereum = "Ethereum"
|
||||||
|
@ -15,6 +15,7 @@ func init() {
|
|||||||
// codec.
|
// codec.
|
||||||
func RegisterWire(codec *wire.Codec) {
|
func RegisterWire(codec *wire.Codec) {
|
||||||
sdk.RegisterWire(codec)
|
sdk.RegisterWire(codec)
|
||||||
|
codec.RegisterConcrete(&Account{}, "types/Account", nil)
|
||||||
codec.RegisterConcrete(&EthSignature{}, "types/EthSignature", nil)
|
codec.RegisterConcrete(&EthSignature{}, "types/EthSignature", nil)
|
||||||
codec.RegisterConcrete(TxData{}, "types/TxData", nil)
|
codec.RegisterConcrete(TxData{}, "types/TxData", nil)
|
||||||
codec.RegisterConcrete(Transaction{}, "types/Transaction", nil)
|
codec.RegisterConcrete(Transaction{}, "types/Transaction", nil)
|
||||||
|
Loading…
Reference in New Issue
Block a user