func (k Keeper) deleteChannel(ctx sdk.Context, channelID types.ChannelID) {
	store := ctx.KVStore(k.storeKey)
	store.Delete(types.GetChannelKey(channelID))
}
deleteChannel removes a channel struct from the blockchain store.
package paychan
import (
	"bytes"
	"github.com/cosmos/cosmos-sdk/codec"
	sdk "github.com/cosmos/cosmos-sdk/types"
	"github.com/cosmos/cosmos-sdk/x/bank"
	"github.com/kava-labs/cosmos-paychan/paychan/types"
)
type Keeper struct {
	storeKey   sdk.StoreKey
	cdc        *codec.Codec
	bankKeeper bank.Keeper
}
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, bk bank.Keeper) Keeper {
	keeper := Keeper{
		storeKey:   key,
		cdc:        cdc,
		bankKeeper: bk,
	}
	return keeper
}
func (k Keeper) CreateChannel(ctx sdk.Context, sender sdk.AccAddress, receiver sdk.AccAddress, coins sdk.Coins) (sdk.Tags, sdk.Error) {
	if sender.Empty() {
		return nil, sdk.ErrInvalidAddress(sender.String())
	}
	if receiver.Empty() {
		return nil, sdk.ErrInvalidAddress(receiver.String())
	}
	if !coins.IsValid() {
		return nil, sdk.ErrInvalidCoins(coins.String())
	}
	if !coins.IsAllPositive() {
		return nil, sdk.ErrInvalidCoins(coins.String())
	}
	_, err := k.bankKeeper.SubtractCoins(ctx, sender, coins)
	if err != nil {
		return nil, err
	}
	id := k.getNewChannelID(ctx)
	channel := types.Channel{
		ID:           id,
		Participants: [2]sdk.AccAddress{sender, receiver},
		Coins:        coins,
	}
	k.setChannel(ctx, channel)
	return sdk.EmptyTags(), err
}
func (k Keeper) InitCloseChannelBySender(ctx sdk.Context, update types.Update) (sdk.Tags, sdk.Error) {
	channel, found := k.getChannel(ctx, update.ChannelID)
	if !found {
		return nil, sdk.ErrInternal("Channel doesn't exist")
	}
	err := VerifyUpdate(channel, update)
	if err != nil {
		return nil, err
	}
	q := k.getSubmittedUpdatesQueue(ctx)
	if q.Contains(update.ChannelID) {
		return nil, sdk.ErrInternal("Sender can't submit an update for channel if one has already been submitted.")
	} else {
		submittedUpdate := types.SubmittedUpdate{
			Update:        update,
			ExecutionTime: ctx.BlockHeight() + types.ChannelDisputeTime,
		}
		k.addToSubmittedUpdatesQueue(ctx, submittedUpdate)
	}
	return sdk.EmptyTags(), nil
}
func (k Keeper) CloseChannelByReceiver(ctx sdk.Context, update types.Update) (sdk.Tags, sdk.Error) {
	channel, found := k.getChannel(ctx, update.ChannelID)
	if !found {
		return nil, sdk.ErrInternal("Channel doesn't exist")
	}
	err := VerifyUpdate(channel, update)
	if err != nil {
		return nil, err
	}
	q := k.getSubmittedUpdatesQueue(ctx)
	if q.Contains(update.ChannelID) {
		k.removeFromSubmittedUpdatesQueue(ctx, update.ChannelID)
	}
	tags, err := k.closeChannel(ctx, update)
	return tags, err
}
func VerifyUpdate(channel types.Channel, update types.Update) sdk.Error {
	if len(update.Payout) != len(channel.Participants) {
		return sdk.ErrInternal("Payout doesn't match number of channel participants")
	}
	for _, coins := range update.Payout {
		if !coins.IsValid() {
			return sdk.ErrInternal("Payout coins aren't formatted correctly")
		}
	}
	if update.Payout.IsAnyNegative() {
		return sdk.ErrInternal("Payout cannot be negative")
	}
	if !channel.Coins.IsEqual(update.Payout.Sum()) {
		return sdk.ErrInternal("Payout amount doesn't match channel amount")
	}
	if !verifySignatures(channel, update) {
		return sdk.ErrInternal("Signature on update not valid")
	}
	return nil
}
func (k Keeper) closeChannel(ctx sdk.Context, update types.Update) (sdk.Tags, sdk.Error) {
	var err sdk.Error
	channel, _ := k.getChannel(ctx, update.ChannelID)
	for i, coins := range update.Payout {
		_, err = k.bankKeeper.AddCoins(ctx, channel.Participants[i], coins)
		if err != nil {
			panic(err)
		}
	}
	k.deleteChannel(ctx, update.ChannelID)
	return sdk.EmptyTags(), nil
}
func verifySignatures(channel types.Channel, update types.Update) bool {
	signBytes := update.GetSignBytes()
	address := channel.Participants[0]  
	pubKey := update.Sigs[0].PubKey
	cryptoSig := update.Sigs[0].CryptoSignature
	valid := bytes.Equal(pubKey.Address(), address) &&
		pubKey.VerifyBytes(signBytes, cryptoSig)
	return valid
}
func (k Keeper) addToSubmittedUpdatesQueue(ctx sdk.Context, sUpdate types.SubmittedUpdate) {
	q := k.getSubmittedUpdatesQueue(ctx)
	if !q.Contains(sUpdate.ChannelID) {
		q = append(q, sUpdate.ChannelID)
	}
	k.setSubmittedUpdatesQueue(ctx, q)
	k.setSubmittedUpdate(ctx, sUpdate)
}
func (k Keeper) removeFromSubmittedUpdatesQueue(ctx sdk.Context, channelID types.ChannelID) {
	q := k.getSubmittedUpdatesQueue(ctx)
	q.RemoveMatchingElements(channelID)
	k.setSubmittedUpdatesQueue(ctx, q)
	k.deleteSubmittedUpdate(ctx, channelID)
}
func (k Keeper) getSubmittedUpdatesQueue(ctx sdk.Context) types.SubmittedUpdatesQueue {
	store := ctx.KVStore(k.storeKey)
	bz := store.Get(k.getSubmittedUpdatesQueueKey())
	var suq types.SubmittedUpdatesQueue  
	if bz != nil {
		k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &suq)
	}
	return suq
}
func (k Keeper) setSubmittedUpdatesQueue(ctx sdk.Context, suq types.SubmittedUpdatesQueue) {
	store := ctx.KVStore(k.storeKey)
	bz := k.cdc.MustMarshalBinaryLengthPrefixed(suq)
	key := k.getSubmittedUpdatesQueueKey()
	store.Set(key, bz)
}
func (k Keeper) getSubmittedUpdatesQueueKey() []byte {
	return []byte("submittedUpdatesQueue")
}
func (k Keeper) getSubmittedUpdate(ctx sdk.Context, channelID types.ChannelID) (types.SubmittedUpdate, bool) {
	store := ctx.KVStore(k.storeKey)
	bz := store.Get(types.GetSubmittedUpdateKey(channelID))
	var sUpdate types.SubmittedUpdate
	if bz == nil {
		return sUpdate, false
	}
	k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &sUpdate)
	return sUpdate, true
}
func (k Keeper) setSubmittedUpdate(ctx sdk.Context, sUpdate types.SubmittedUpdate) {
	store := ctx.KVStore(k.storeKey)
	bz := k.cdc.MustMarshalBinaryLengthPrefixed(sUpdate)  
	key := types.GetSubmittedUpdateKey(sUpdate.ChannelID)
	store.Set(key, bz)  
}
func (k Keeper) deleteSubmittedUpdate(ctx sdk.Context, channelID types.ChannelID) {
	store := ctx.KVStore(k.storeKey)
	store.Delete(types.GetSubmittedUpdateKey(channelID))
}
func (k Keeper) getChannel(ctx sdk.Context, channelID types.ChannelID) (types.Channel, bool) {
	store := ctx.KVStore(k.storeKey)
	bz := store.Get(types.GetChannelKey(channelID))
	var channel types.Channel
	if bz == nil {
		return channel, false
	}
	k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &channel)
	return channel, true
}
func (k Keeper) setChannel(ctx sdk.Context, channel types.Channel) {
	store := ctx.KVStore(k.storeKey)
	bz := k.cdc.MustMarshalBinaryLengthPrefixed(channel)  
	key := types.GetChannelKey(channel.ID)
	store.Set(key, bz)  
}