Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: Merge PRs from cosmos #808

Merged
merged 7 commits into from
Dec 12, 2018
95 changes: 62 additions & 33 deletions app/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/tmhash"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"

Expand Down Expand Up @@ -65,6 +64,10 @@ type BaseApp struct {
deliverState *state // for DeliverTx
voteInfos []abci.VoteInfo // absent validators from begin block

// consensus params
// TODO move this in the future to baseapp param store on main store.
consensusParams *abci.ConsensusParams

// minimum fees for spam prevention
minimumFees sdk.Coins

Expand Down Expand Up @@ -208,6 +211,10 @@ func (st *state) CacheMultiStore() sdk.CacheMultiStore {
return st.ms.CacheMultiStore()
}

func (st *state) Context() sdk.Context {
return st.ctx
}

func (app *BaseApp) setCheckState(header abci.Header) {
ms := app.cms.CacheMultiStore()
app.checkState = &state{
Expand Down Expand Up @@ -392,6 +399,7 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
return sdk.ErrUnknownRequest(fmt.Sprintf("no custom querier found for route %s", path[1])).QueryResult()
}

// Cache wrap the commit-multistore for safety.
ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger).
WithMinimumFees(app.minimumFees)
// Passes the rest of the path as an argument to the querier.
Expand Down Expand Up @@ -539,13 +547,14 @@ func validateBasicTxMsgs(msgs []sdk.Msg) sdk.Error {
return nil
}

// retrieve the context for the ante handler and store the tx bytes; store
// the vote infos if the tx runs within the deliverTx() state.
func (app *BaseApp) getContextForAnte(mode RunTxMode, txBytes []byte) (ctx sdk.Context) {
// Get the context
ctx = getState(app, mode).ctx.WithTxBytes(txBytes)
if mode == RunTxModeDeliver {
ctx = ctx.WithVoteInfos(app.voteInfos)
// retrieve the context for the tx w/ txBytes and other memoized values.
func (app *BaseApp) getContextForTx(mode RunTxMode, txBytes []byte) (ctx sdk.Context) {
ctx = app.getState(mode).ctx.
WithTxBytes(txBytes).
WithVoteInfos(app.voteInfos).
WithConsensusParams(app.consensusParams)
if mode == RunTxModeSimulate {
ctx, _ = ctx.CacheContext()
}
return
}
Expand Down Expand Up @@ -612,19 +621,31 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode RunTxMode) (re

// Returns the applicantion's deliverState if app is in runTxModeDeliver,
// otherwise it returns the application's checkstate.
func getState(app *BaseApp, mode RunTxMode) *state {
func (app *BaseApp) getState(mode RunTxMode) *state {
if mode == RunTxModeCheck || mode == RunTxModeSimulate {
return app.checkState
}

return app.deliverState
}

func (app *BaseApp) initializeContext(ctx sdk.Context, mode RunTxMode) sdk.Context {
if mode == RunTxModeSimulate {
ctx = ctx.WithMultiStore(getState(app, RunTxModeSimulate).CacheMultiStore())
// cacheTxContext returns a new context based off of the provided context with
// a cache wrapped multi-store.
func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (
sdk.Context, sdk.CacheMultiStore) {
ms := ctx.MultiStore()
// TODO: https://github.com/cosmos/cosmos-sdk/issues/2824
msCache := ms.CacheMultiStore()
if msCache.TracingEnabled() {
msCache = msCache.WithTracingContext(
sdk.TraceContext(
map[string]interface{}{
"txHash": fmt.Sprintf("%X", tmhash.Sum(txBytes)),
},
),
).(sdk.CacheMultiStore)
}
return ctx
return ctx.WithMultiStore(msCache), msCache
}

// runTx processes a transaction. The transactions is proccessed via an
Expand All @@ -636,8 +657,8 @@ func (app *BaseApp) runTx(mode RunTxMode, txBytes []byte, tx sdk.Tx) (result sdk
// meter so we initialize upfront.
var gasWanted uint64
var msCache sdk.CacheMultiStore
ctx := app.getContextForAnte(mode, txBytes)
ctx = app.initializeContext(ctx, mode)
ctx := app.getContextForTx(mode, txBytes)
ms := ctx.MultiStore()
ctxWithNoCache := ctx

defer func() {
Expand Down Expand Up @@ -685,37 +706,45 @@ func (app *BaseApp) runTx(mode RunTxMode, txBytes []byte, tx sdk.Tx) (result sdk
anteHandler := app.Engine.GetCurrent().GetAnteHandler()
// run the ante handler
if anteHandler != nil {
newCtx, result, abort := anteHandler(ctx, tx, (mode == RunTxModeSimulate))
var anteCtx sdk.Context
var msCache sdk.CacheMultiStore
// Cache wrap context before anteHandler call in case it aborts.
// This is required for both CheckTx and DeliverTx.
// https://github.com/cosmos/cosmos-sdk/issues/2772
// NOTE: Alternatively, we could require that anteHandler ensures that
// writes do not happen if aborted/failed. This may have some
// performance benefits, but it'll be more difficult to get right.
anteCtx, msCache = app.cacheTxContext(ctx, txBytes)

newCtx, result, abort := anteHandler(anteCtx, tx, (mode == RunTxModeSimulate))
if abort {
return result
}
if !newCtx.IsZero() {
ctx = newCtx
ctxWithNoCache = newCtx
// At this point, newCtx.MultiStore() is cache wrapped,
// or something else replaced by anteHandler.
// We want the original ms, not one which was cache-wrapped
// for the ante handler.
ctx = newCtx.WithMultiStore(ms)
}

msCache.Write()
gasWanted = result.GasWanted
}

if mode == RunTxModeSimulate {
result = app.runMsgs(ctx, msgs, mode)
result.GasWanted = gasWanted
if mode == RunTxModeCheck {
return
}

// Keep the state in a transient CacheWrap in case processing the messages
// fails.
msCache = getState(app, mode).CacheMultiStore()
if msCache.TracingEnabled() {
msCache = msCache.WithTracingContext(sdk.TraceContext(
map[string]interface{}{"txHash": cmn.HexBytes(tmhash.Sum(txBytes)).String()},
)).(sdk.CacheMultiStore)
}

ctx = ctx.WithMultiStore(msCache)
result = app.runMsgs(ctx, msgs, mode)
// Create a new context based off of the existing context with a cache wrapped
// multi-store in case message processing fails.
runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes)
result = app.runMsgs(runMsgCtx, msgs, mode)
result.GasWanted = gasWanted

if mode == RunTxModeSimulate {
return
}

// only update state if all messages pass
if result.IsOK() {
msCache.Write()
Expand Down
9 changes: 8 additions & 1 deletion modules/distribution/keeper/allocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ func (k Keeper) AllocateTokens(ctx sdk.Context, percentVotes sdk.Dec, proposer s
feesCollected := k.feeCollectionKeeper.GetCollectedFees(ctx)
feesCollectedDec := types.NewDecCoins(feesCollected)

feePool := k.GetFeePool(ctx)
if k.stakeKeeper.GetLastTotalPower(ctx).IsZero() {
feePool.CommunityPool = feePool.CommunityPool.Plus(feesCollectedDec)
k.SetFeePool(ctx, feePool)
k.feeCollectionKeeper.ClearCollectedFees(ctx)
return
}

// allocated rewards to proposer
baseProposerReward := k.GetBaseProposerReward(ctx)
bonusProposerReward := k.GetBonusProposerReward(ctx)
Expand All @@ -33,7 +41,6 @@ func (k Keeper) AllocateTokens(ctx sdk.Context, percentVotes sdk.Dec, proposer s
// allocate community funding
communityTax := k.GetCommunityTax(ctx)
communityFunding := feesCollectedDec.MulDec(communityTax)
feePool := k.GetFeePool(ctx)
feePool.CommunityPool = feePool.CommunityPool.Plus(communityFunding)

// set the global pool within the distribution module
Expand Down
9 changes: 9 additions & 0 deletions modules/stake/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/irisnet/irishub/modules/stake/tags"
"github.com/irisnet/irishub/modules/stake/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/common"
tmtypes "github.com/tendermint/tendermint/types"
)

func NewHandler(k keeper.Keeper) sdk.Handler {
Expand Down Expand Up @@ -103,6 +105,13 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k
return ErrBadDenom(k.Codespace()).Result()
}

if ctx.ConsensusParams() != nil {
tmPubKey := tmtypes.TM2PB.PubKey(msg.PubKey)
if !common.StringInSlice(tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes) {
return ErrValidatorPubKeyTypeUnsupported(k.Codespace(), tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes).Result()
}
}

validator := NewValidator(msg.ValidatorAddr, msg.PubKey, msg.Description)
commission := NewCommissionWithTime(
msg.Commission.Rate, msg.Commission.MaxRate,
Expand Down
18 changes: 18 additions & 0 deletions modules/stake/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import (
sdk "github.com/irisnet/irishub/types"
keep "github.com/irisnet/irishub/modules/stake/keeper"
"github.com/irisnet/irishub/modules/stake/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/secp256k1"
tmtypes "github.com/tendermint/tendermint/types"
)

//______________________________________________________________________
Expand Down Expand Up @@ -157,6 +160,21 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) {
assert.Equal(t, Description{}, validator.Description)
}

func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, sdk.NewIntWithDecimal(1000,18))
addr := sdk.ValAddress(keep.Addrs[0])
invalidPk := secp256k1.GenPrivKey().PubKey()
// invalid pukKey type should not be allowed
msgCreateValidator := NewTestMsgCreateValidator(addr, invalidPk, sdk.NewIntWithDecimal(10,18))
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
require.False(t, got.IsOK(), "%v", got)
ctx = ctx.WithConsensusParams(&abci.ConsensusParams{
Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeSecp256k1}},
})
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
require.True(t, got.IsOK(), "%v", got)
}

func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, sdk.NewIntWithDecimal(1000, 18))

Expand Down
18 changes: 9 additions & 9 deletions modules/stake/keeper/test_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,20 @@ import (
"strconv"
"testing"

"github.com/irisnet/irishub/codec"
"github.com/irisnet/irishub/modules/auth"
"github.com/irisnet/irishub/modules/bank"
"github.com/irisnet/irishub/modules/params"
"github.com/irisnet/irishub/modules/stake/types"
"github.com/irisnet/irishub/store"
sdk "github.com/irisnet/irishub/types"
"github.com/stretchr/testify/require"

abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"

"github.com/irisnet/irishub/codec"
"github.com/irisnet/irishub/store"
sdk "github.com/irisnet/irishub/types"
"github.com/irisnet/irishub/modules/auth"
"github.com/irisnet/irishub/modules/bank"
"github.com/irisnet/irishub/modules/params"
"github.com/irisnet/irishub/modules/stake/types"
tmtypes "github.com/tendermint/tendermint/types"
)

// dummy addresses used for testing
Expand Down Expand Up @@ -94,6 +93,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins sdk.Int) (sdk.Conte
require.Nil(t, err)

ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger())
ctx = ctx.WithConsensusParams(&abci.ConsensusParams{Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}}})
cdc := MakeTestCodec()
accountKeeper := auth.NewAccountKeeper(
cdc, // amino codec
Expand Down
19 changes: 10 additions & 9 deletions modules/stake/stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,16 @@ const (
)

var (
ErrNilValidatorAddr = types.ErrNilValidatorAddr
ErrNoValidatorFound = types.ErrNoValidatorFound
ErrValidatorOwnerExists = types.ErrValidatorOwnerExists
ErrValidatorPubKeyExists = types.ErrValidatorPubKeyExists
ErrValidatorJailed = types.ErrValidatorJailed
ErrBadRemoveValidator = types.ErrBadRemoveValidator
ErrDescriptionLength = types.ErrDescriptionLength
ErrCommissionNegative = types.ErrCommissionNegative
ErrCommissionHuge = types.ErrCommissionHuge
ErrNilValidatorAddr = types.ErrNilValidatorAddr
ErrNoValidatorFound = types.ErrNoValidatorFound
ErrValidatorOwnerExists = types.ErrValidatorOwnerExists
ErrValidatorPubKeyExists = types.ErrValidatorPubKeyExists
ErrValidatorPubKeyTypeUnsupported = types.ErrValidatorPubKeyTypeNotSupported
ErrValidatorJailed = types.ErrValidatorJailed
ErrBadRemoveValidator = types.ErrBadRemoveValidator
ErrDescriptionLength = types.ErrDescriptionLength
ErrCommissionNegative = types.ErrCommissionNegative
ErrCommissionHuge = types.ErrCommissionHuge

ErrNilDelegatorAddr = types.ErrNilDelegatorAddr
ErrBadDenom = types.ErrBadDenom
Expand Down
6 changes: 6 additions & 0 deletions modules/stake/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

sdk "github.com/irisnet/irishub/types"
"strings"
)

type CodeType = sdk.CodeType
Expand Down Expand Up @@ -44,6 +45,11 @@ func ErrValidatorPubKeyExists(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "validator already exist for this pubkey, must use new validator pubkey")
}

func ErrValidatorPubKeyTypeNotSupported(codespace sdk.CodespaceType, keyType string, supportedTypes []string) sdk.Error {
msg := fmt.Sprintf("validator pubkey type %s is not supported, must use %s", keyType, strings.Join(supportedTypes, ","))
return sdk.NewError(codespace, CodeInvalidValidator, msg)
}

func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "validator for this address is currently jailed")
}
Expand Down
19 changes: 8 additions & 11 deletions types/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, logger log.Lo
c = c.WithVoteInfos(nil)
c = c.WithGasMeter(NewInfiniteGasMeter())
c = c.WithMinimumFees(Coins{})
c = c.WithConsensusParams(nil)
return c
}

Expand All @@ -73,12 +74,12 @@ func (c Context) Value(key interface{}) interface{} {

// KVStore fetches a KVStore from the MultiStore.
func (c Context) KVStore(key StoreKey) KVStore {
return c.multiStore().GetKVStore(key).Gas(c.GasMeter(), cachedKVGasConfig)
return c.MultiStore().GetKVStore(key).Gas(c.GasMeter(), cachedKVGasConfig)
}

// TransientStore fetches a TransientStore from the MultiStore.
func (c Context) TransientStore(key StoreKey) KVStore {
return c.multiStore().GetKVStore(key).Gas(c.GasMeter(), cachedTransientGasConfig)
return c.MultiStore().GetKVStore(key).Gas(c.GasMeter(), cachedTransientGasConfig)
}

//----------------------------------------
Expand Down Expand Up @@ -146,16 +147,16 @@ const (
// NOTE: Do not expose MultiStore.
// MultiStore exposes all the keys.
// Instead, pass the context and the store key.
func (c Context) multiStore() MultiStore {
func (c Context) MultiStore() MultiStore {
return c.Value(contextKeyMultiStore).(MultiStore)
}

func (c Context) BlockHeader() abci.Header { return c.Value(contextKeyBlockHeader).(abci.Header) }

func (c Context) BlockHeight() int64 { return c.Value(contextKeyBlockHeight).(int64) }

func (c Context) ConsensusParams() abci.ConsensusParams {
return c.Value(contextKeyConsensusParams).(abci.ConsensusParams)
func (c Context) ConsensusParams() *abci.ConsensusParams {
return c.Value(contextKeyConsensusParams).(*abci.ConsensusParams)
}

func (c Context) ChainID() string { return c.Value(contextKeyChainID).(string) }
Expand Down Expand Up @@ -200,11 +201,7 @@ func (c Context) WithBlockHeight(height int64) Context {
}

func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context {
if params == nil {
return c
}
return c.withValue(contextKeyConsensusParams, params).
WithGasMeter(NewGasMeter(uint64(params.BlockSize.MaxGas)))
return c.withValue(contextKeyConsensusParams, params)
}

func (c Context) WithChainID(chainID string) Context { return c.withValue(contextKeyChainID, chainID) }
Expand All @@ -230,7 +227,7 @@ func (c Context) WithMinimumFees(minFees Coins) Context {
// Cache the multistore and return a new cached context. The cached context is
// written to the context when writeCache is called.
func (c Context) CacheContext() (cc Context, writeCache func()) {
cms := c.multiStore().CacheMultiStore()
cms := c.MultiStore().CacheMultiStore()
cc = c.WithMultiStore(cms)
return cc, cms.Write
}
Expand Down