mirror of
https://github.com/0glabs/0g-chain.git
synced 2025-01-12 16:25:17 +00:00
add error handling and fix compile errors
This commit is contained in:
parent
a4baa34ee0
commit
c268088260
@ -7,7 +7,10 @@ Simplifications:
|
|||||||
|
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
- error handling (getter setter return values? and what happens in failures)
|
|
||||||
- chnge module name to "channel"?
|
- chnge module name to "channel"?
|
||||||
- Find a better name for Queue - clarify distinction between int slice and abstract queue concept
|
- Find a better name for Queue - clarify distinction between int slice and abstract queue concept
|
||||||
- Do all the small functions need to be methods on the keeper or can they just be floating around?
|
- Do all the small functions need to be methods on the keeper or can they just be floating around?
|
||||||
|
- Tidy up - standardise var names, comments and method descriptions
|
||||||
|
- is having all the get functions return a bool if not found reasonable?
|
||||||
|
- any problem in signing your own address?
|
||||||
|
- Gas
|
||||||
|
@ -1,22 +1,36 @@
|
|||||||
package paychan
|
package paychan
|
||||||
|
|
||||||
import ()
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
func EndBlocker(ctx sdk.Context, k Keeper) sdk.Tags {
|
func EndBlocker(ctx sdk.Context, k Keeper) sdk.Tags {
|
||||||
|
var err sdk.Error
|
||||||
|
var channelTags sdk.Tags
|
||||||
|
tags := sdk.EmptyTags()
|
||||||
|
|
||||||
// Iterate through submittedUpdatesQueue
|
// Iterate through submittedUpdatesQueue
|
||||||
// TODO optimise so it doesn't pull every update from DB every block
|
// TODO optimise so it doesn't pull every update from DB every block
|
||||||
var sUpdate SubmittedUpdate
|
var sUpdate SubmittedUpdate
|
||||||
q := k.getSubmittedUpdatesQueue(ctx)
|
q, found := k.getSubmittedUpdatesQueue(ctx)
|
||||||
|
if !found {
|
||||||
|
panic("SubmittedUpdatesQueue not found.")
|
||||||
|
}
|
||||||
for _, id := range q {
|
for _, id := range q {
|
||||||
// close the channel if the update has reached its execution time.
|
// close the channel if the update has reached its execution time.
|
||||||
// Using >= in case some are somehow missed.
|
// Using >= in case some are somehow missed.
|
||||||
sUpdate = k.getSubmittedUpdate(ctx, id)
|
sUpdate, found = k.getSubmittedUpdate(ctx, id)
|
||||||
|
if !found {
|
||||||
|
panic("can't find element in queue that should exist")
|
||||||
|
}
|
||||||
if ctx.BlockHeight() >= sUpdate.ExecutionTime {
|
if ctx.BlockHeight() >= sUpdate.ExecutionTime {
|
||||||
k.closeChannel(ctx, sUpdate.Update)
|
channelTags, err = k.closeChannel(ctx, sUpdate.Update)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
tags.AppendTags(channelTags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := sdk.NewTags()
|
|
||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
@ -37,15 +37,19 @@ func handleMsgCreate(ctx sdk.Context, k Keeper, msg MsgCreate) sdk.Result {
|
|||||||
// Handle MsgSubmitUpdate
|
// Handle MsgSubmitUpdate
|
||||||
// Leaves validation to the keeper methods.
|
// Leaves validation to the keeper methods.
|
||||||
func handleMsgSubmitUpdate(ctx sdk.Context, k Keeper, msg MsgSubmitUpdate) sdk.Result {
|
func handleMsgSubmitUpdate(ctx sdk.Context, k Keeper, msg MsgSubmitUpdate) sdk.Result {
|
||||||
|
var err sdk.Error
|
||||||
|
tags := sdk.EmptyTags()
|
||||||
|
|
||||||
participants := k.getChannel(ctx, msg.Update.ChannelID).Participants
|
// TODO refactor signer detection - move to keeper or find nicer setup
|
||||||
|
channel, _ := k.getChannel(ctx, msg.Update.ChannelID)
|
||||||
|
participants := channel.Participants
|
||||||
|
|
||||||
// if only sender signed
|
// if only sender signed
|
||||||
if msg.submitter == participants[0] {
|
if reflect.DeepEqual(msg.submitter, participants[0]) {
|
||||||
tags, err := k.InitCloseChannelBySender()
|
tags, err = k.InitCloseChannelBySender(ctx, msg.Update)
|
||||||
// else if receiver signed
|
// else if receiver signed
|
||||||
} else if msg.submitter == participants[len(participants)-1] {
|
} else if reflect.DeepEqual(msg.submitter, participants[len(participants)-1]) {
|
||||||
tags, err := k.CloseChannelByReceiver()
|
tags, err = k.CloseChannelByReceiver(ctx, msg.Update)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package paychan
|
package paychan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"fmt"
|
||||||
|
|
||||||
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/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
@ -33,9 +32,8 @@ func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper) Keeper {
|
|||||||
|
|
||||||
// ============================================== Main Business Logic
|
// ============================================== Main Business Logic
|
||||||
|
|
||||||
|
|
||||||
// Create a new payment channel and lock up sender funds.
|
// Create a new payment channel and lock up sender funds.
|
||||||
func (k Keeper) CreateChannel(ctx sdk.Context, sender sdk.Address, receiver sdk.Address, coins sdk.Coins) (sdk.Tags, sdk.Error) {
|
func (k Keeper) CreateChannel(ctx sdk.Context, sender sdk.AccAddress, receiver sdk.AccAddress, coins sdk.Coins) (sdk.Tags, sdk.Error) {
|
||||||
// TODO do validation and maybe move somewhere nicer
|
// TODO do validation and maybe move somewhere nicer
|
||||||
/*
|
/*
|
||||||
// args present
|
// args present
|
||||||
@ -67,18 +65,18 @@ func (k Keeper) CreateChannel(ctx sdk.Context, sender sdk.Address, receiver sdk.
|
|||||||
// TODO check if sender and receiver different?
|
// TODO check if sender and receiver different?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Calculate next id
|
|
||||||
id := k.getNewChannelID(ctx)
|
|
||||||
// subtract coins from sender
|
// subtract coins from sender
|
||||||
_, tags, err := k.coinKeeper.SubtractCoins(ctx, sender, coins)
|
_, tags, err := k.coinKeeper.SubtractCoins(ctx, sender, coins)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// Calculate next id
|
||||||
|
id := k.getNewChannelID(ctx)
|
||||||
// create new Paychan struct
|
// create new Paychan struct
|
||||||
channel := Channel{
|
channel := Channel{
|
||||||
ID: id
|
ID: id,
|
||||||
Participants: [2]sdk.AccAddress{sender, receiver},
|
Participants: [2]sdk.AccAddress{sender, receiver},
|
||||||
Coins: coins,
|
Coins: coins,
|
||||||
}
|
}
|
||||||
// save to db
|
// save to db
|
||||||
k.setChannel(ctx, channel)
|
k.setChannel(ctx, channel)
|
||||||
@ -88,51 +86,64 @@ func (k Keeper) CreateChannel(ctx sdk.Context, sender sdk.Address, receiver sdk.
|
|||||||
return tags, err
|
return tags, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k Keeper) InitCloseChannelBySender(ctx sdk.Context, update Update) (sdk.Tags, sdk.Error) {
|
||||||
|
|
||||||
func (k Keeper) InitCloseChannelBySender(update Update) {
|
|
||||||
// This is roughly the default path for non unidirectional channels
|
// This is roughly the default path for non unidirectional channels
|
||||||
|
|
||||||
// TODO Validate update - e.g. check signed by sender
|
// TODO Validate update - e.g. check signed by sender
|
||||||
|
|
||||||
q := k.getSubmittedUpdateQueue(ctx)
|
q, found := k.getSubmittedUpdatesQueue(ctx)
|
||||||
|
if !found {
|
||||||
|
panic("SubmittedUpdatesQueue not found.") // TODO nicer custom errors
|
||||||
|
}
|
||||||
if q.Contains(update.ChannelID) {
|
if q.Contains(update.ChannelID) {
|
||||||
// Someone has previously tried to update channel
|
// Someone has previously tried to update channel
|
||||||
existingSUpdate := k.getSubmittedUpdate(ctx, update.ChannelID)
|
existingSUpdate, found := k.getSubmittedUpdate(ctx, update.ChannelID)
|
||||||
k.addToSubmittedUpdateQueue(ctx, k.applyNewUpdate(existingSUpdate, update))
|
if !found {
|
||||||
} else {
|
panic("can't find element in queue that should exist")
|
||||||
// No one has tried to update channel.
|
|
||||||
submittedUpdate := SubmittedUpdate{
|
|
||||||
Update: update
|
|
||||||
executionTime: ctx.BlockHeight()+ChannelDisputeTime //TODO check what exactly BlockHeight refers to
|
|
||||||
}
|
}
|
||||||
k.addToSubmittedUpdateQueue(ctx, submittedUpdate)
|
k.addToSubmittedUpdatesQueue(ctx, k.applyNewUpdate(existingSUpdate, update))
|
||||||
|
} else {
|
||||||
|
// No one has tried to update channel
|
||||||
|
submittedUpdate := SubmittedUpdate{
|
||||||
|
Update: update,
|
||||||
|
ExecutionTime: ctx.BlockHeight() + ChannelDisputeTime, //TODO check what exactly BlockHeight refers to
|
||||||
|
}
|
||||||
|
k.addToSubmittedUpdatesQueue(ctx, submittedUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tags := sdk.EmptyTags() // TODO tags
|
||||||
|
|
||||||
|
return tags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k Keeper) CloseChannelByReceiver(update Update) () {
|
func (k Keeper) CloseChannelByReceiver(ctx sdk.Context, update Update) (sdk.Tags, sdk.Error) {
|
||||||
// TODO Validate update
|
// TODO Validate update
|
||||||
|
|
||||||
// Check if there is an update in the queue already
|
// Check if there is an update in the queue already
|
||||||
q := k.getSubmittedUpdateQueue(ctx)
|
q, found := k.getSubmittedUpdatesQueue(ctx)
|
||||||
|
if !found {
|
||||||
|
panic("SubmittedUpdatesQueue not found.") // TODO nicer custom errors
|
||||||
|
}
|
||||||
if q.Contains(update.ChannelID) {
|
if q.Contains(update.ChannelID) {
|
||||||
// Someone has previously tried to update channel but receiver has final say
|
// Someone has previously tried to update channel but receiver has final say
|
||||||
k.removeFromSubmittedUpdateQueue(ctx, update.ChannelID)
|
k.removeFromSubmittedUpdatesQueue(ctx, update.ChannelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
k.closeChannel(ctx, update)
|
tags, err := k.closeChannel(ctx, update)
|
||||||
|
|
||||||
|
return tags, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main function that compare updates against each other.
|
// Main function that compare updates against each other.
|
||||||
// Pure function
|
// Pure function
|
||||||
func (k Keeper) applyNewUpdate(existingSUpdate, proposedUpdate) SubmittedUpdate {
|
func (k Keeper) applyNewUpdate(existingSUpdate SubmittedUpdate, proposedUpdate Update) SubmittedUpdate {
|
||||||
var returnUpdate SubmittedUpdate
|
var returnUpdate SubmittedUpdate
|
||||||
|
|
||||||
if existingSUpdate.sequence > proposedUpdate.sequence {
|
if existingSUpdate.Sequence > proposedUpdate.Sequence {
|
||||||
// update accepted
|
// update accepted
|
||||||
returnUpdate = SubmittedUpdate{
|
returnUpdate = SubmittedUpdate{
|
||||||
Update: proposedUpdate
|
Update: proposedUpdate,
|
||||||
ExecutionTime: existingSUpdate.ExecutionTime
|
ExecutionTime: existingSUpdate.ExecutionTime,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// update rejected
|
// update rejected
|
||||||
@ -141,62 +152,79 @@ func (k Keeper) applyNewUpdate(existingSUpdate, proposedUpdate) SubmittedUpdate
|
|||||||
return returnUpdate
|
return returnUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k Keeper) closeChannel(ctx sdk.Context, update Update) {
|
// unsafe close channel - doesn't check if update matches existing channel TODO make safer?
|
||||||
channel := k.getChannel(ctx, update.ChannelID)
|
func (k Keeper) closeChannel(ctx sdk.Context, update Update) (sdk.Tags, sdk.Error) {
|
||||||
|
var err error
|
||||||
|
var sdkErr sdk.Error
|
||||||
|
var tags sdk.Tags
|
||||||
|
|
||||||
// Add coins to sender and receiver
|
// Add coins to sender and receiver
|
||||||
for address, coins := range update.CoinsUpdate {
|
// TODO check for possible errors first to avoid coins being half paid out?
|
||||||
|
var address sdk.AccAddress
|
||||||
|
for bech32Address, coins := range update.CoinsUpdate {
|
||||||
|
address, err = sdk.AccAddressFromBech32(bech32Address)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
// TODO check somewhere if coins are not negative?
|
// TODO check somewhere if coins are not negative?
|
||||||
k.ck.AddCoins(ctx, address, coins)
|
_, tags, sdkErr = k.coinKeeper.AddCoins(ctx, address, coins)
|
||||||
|
if sdkErr != nil {
|
||||||
|
panic(sdkErr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
k.deleteChannel(ctx, update.ChannelID)
|
k.deleteChannel(ctx, update.ChannelID)
|
||||||
|
|
||||||
|
return tags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =========================================== QUEUE
|
// =========================================== QUEUE
|
||||||
|
|
||||||
|
|
||||||
func (k Keeper) addToSubmittedUpdatesQueue(ctx sdk.Context, sUpdate SubmittedUpdate) {
|
func (k Keeper) addToSubmittedUpdatesQueue(ctx sdk.Context, sUpdate SubmittedUpdate) {
|
||||||
// always overwrite prexisting values - leave paychan logic to higher levels
|
// always overwrite prexisting values - leave paychan logic to higher levels
|
||||||
// get current queue
|
// get current queue
|
||||||
q := k.getSubmittedUpdateQueue(ctx)
|
q, found := k.getSubmittedUpdatesQueue(ctx)
|
||||||
|
if !found {
|
||||||
|
panic("SubmittedUpdatesQueue not found.")
|
||||||
|
}
|
||||||
// append ID to queue
|
// append ID to queue
|
||||||
if q.Contains(sUpdate.ChannelID)! {
|
if !q.Contains(sUpdate.ChannelID) {
|
||||||
q = append(q, sUpdate.ChannelID)
|
q = append(q, sUpdate.ChannelID)
|
||||||
}
|
}
|
||||||
// set queue
|
// set queue
|
||||||
k.setSubmittedUpdateQueue(ctx, q)
|
k.setSubmittedUpdatesQueue(ctx, q)
|
||||||
// store submittedUpdate
|
// store submittedUpdate
|
||||||
k.setSubmittedUpdate(ctx, sUpdate)
|
k.setSubmittedUpdate(ctx, sUpdate)
|
||||||
}
|
}
|
||||||
func (k Keeper) removeFromSubmittdUpdatesQueue(ctx sdk.Context, channelID) {
|
func (k Keeper) removeFromSubmittedUpdatesQueue(ctx sdk.Context, channelID ChannelID) {
|
||||||
// get current queue
|
// get current queue
|
||||||
q := k.getSubmittedUpdateQueue(ctx)
|
q, found := k.getSubmittedUpdatesQueue(ctx)
|
||||||
|
if !found {
|
||||||
|
panic("SubmittedUpdatesQueue not found.")
|
||||||
|
}
|
||||||
// remove id
|
// remove id
|
||||||
q.RemoveMatchingElements(channelID)
|
q.RemoveMatchingElements(channelID)
|
||||||
// set queue
|
// set queue
|
||||||
k.setSubmittedUpdateQueue(ctx, q)
|
k.setSubmittedUpdatesQueue(ctx, q)
|
||||||
// delete submittedUpdate
|
// delete submittedUpdate
|
||||||
k.deleteSubmittedUpdate(ctx, channelID)
|
k.deleteSubmittedUpdate(ctx, channelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k Keeper) getSubmittedUpdatesQueue(ctx sdk.Context) (Queue, bool) {
|
func (k Keeper) getSubmittedUpdatesQueue(ctx sdk.Context) (SubmittedUpdatesQueue, bool) {
|
||||||
// load from DB
|
// load from DB
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
bz := store.Get(k.getSubmittedUpdatesQueueKey())
|
bz := store.Get(k.getSubmittedUpdatesQueueKey())
|
||||||
|
|
||||||
var q Queue
|
var suq SubmittedUpdatesQueue
|
||||||
if bz == nil {
|
if bz == nil {
|
||||||
return q, false
|
return suq, false // TODO maybe create custom error to pass up here
|
||||||
}
|
}
|
||||||
// unmarshal
|
// unmarshal
|
||||||
k.cdc.MustUnmarshalBinary(bz, &q)
|
k.cdc.MustUnmarshalBinary(bz, &suq)
|
||||||
// return
|
// return
|
||||||
return q, true
|
return suq, true
|
||||||
}
|
}
|
||||||
func (k Keeper) setSubmittedUpdatesQueue(ctx sdk.Context, q Queue) {
|
func (k Keeper) setSubmittedUpdatesQueue(ctx sdk.Context, q SubmittedUpdatesQueue) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
// marshal
|
// marshal
|
||||||
bz := k.cdc.MustMarshalBinary(q)
|
bz := k.cdc.MustMarshalBinary(q)
|
||||||
@ -213,7 +241,7 @@ func (k Keeper) getSubmittedUpdatesQueueKey() []byte {
|
|||||||
// This section deals with only setting and getting
|
// This section deals with only setting and getting
|
||||||
|
|
||||||
func (k Keeper) getSubmittedUpdate(ctx sdk.Context, channelID ChannelID) (SubmittedUpdate, bool) {
|
func (k Keeper) getSubmittedUpdate(ctx sdk.Context, channelID ChannelID) (SubmittedUpdate, bool) {
|
||||||
|
|
||||||
// load from DB
|
// load from DB
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
bz := store.Get(k.getSubmittedUpdateKey(channelID))
|
bz := store.Get(k.getSubmittedUpdateKey(channelID))
|
||||||
@ -234,11 +262,11 @@ func (k Keeper) setSubmittedUpdate(ctx sdk.Context, sUpdate SubmittedUpdate) {
|
|||||||
// marshal
|
// marshal
|
||||||
bz := k.cdc.MustMarshalBinary(sUpdate) // panics if something goes wrong
|
bz := k.cdc.MustMarshalBinary(sUpdate) // panics if something goes wrong
|
||||||
// write to db
|
// write to db
|
||||||
key := k.getSubmittedUpdateKey(sUpdate.channelID)
|
key := k.getSubmittedUpdateKey(sUpdate.ChannelID)
|
||||||
store.Set(key, bz) // panics if something goes wrong
|
store.Set(key, bz) // panics if something goes wrong
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k Keeper) deleteSubmittedUpdate(ctx sdk.Context, channelID ) {
|
func (k Keeper) deleteSubmittedUpdate(ctx sdk.Context, channelID ChannelID) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
store.Delete(k.getSubmittedUpdateKey(channelID))
|
store.Delete(k.getSubmittedUpdateKey(channelID))
|
||||||
// TODO does this have return values? What happens when key doesn't exist?
|
// TODO does this have return values? What happens when key doesn't exist?
|
||||||
@ -247,12 +275,10 @@ func (k Keeper) getSubmittedUpdateKey(channelID ChannelID) []byte {
|
|||||||
return []byte(fmt.Sprintf("submittedUpdate:%d", channelID))
|
return []byte(fmt.Sprintf("submittedUpdate:%d", channelID))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ========================================== CHANNELS
|
// ========================================== CHANNELS
|
||||||
|
|
||||||
// Reteive a payment channel struct from the blockchain store.
|
// Reteive a payment channel struct from the blockchain store.
|
||||||
func (k Keeper) getChannel(ctx sdk.Context, channelID ChannelID) (Channel, bool) {
|
func (k Keeper) getChannel(ctx sdk.Context, channelID ChannelID) (Channel, bool) {
|
||||||
|
|
||||||
// load from DB
|
// load from DB
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
bz := store.Get(k.getChannelKey(channelID))
|
bz := store.Get(k.getChannelKey(channelID))
|
||||||
@ -273,27 +299,28 @@ func (k Keeper) setChannel(ctx sdk.Context, channel Channel) {
|
|||||||
// marshal
|
// marshal
|
||||||
bz := k.cdc.MustMarshalBinary(channel) // panics if something goes wrong
|
bz := k.cdc.MustMarshalBinary(channel) // panics if something goes wrong
|
||||||
// write to db
|
// write to db
|
||||||
key := sdk.getChannelKey(channel.ID)
|
key := k.getChannelKey(channel.ID)
|
||||||
store.Set(key, bz) // panics if something goes wrong
|
store.Set(key, bz) // panics if something goes wrong
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k Keeper) deleteChannel(ctx sdk.Context, channelID ) {
|
func (k Keeper) deleteChannel(ctx sdk.Context, channelID ChannelID) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
store.Delete(k.getChannelKey(channelID))
|
store.Delete(k.getChannelKey(channelID))
|
||||||
// TODO does this have return values? What happens when key doesn't exist?
|
// TODO does this have return values? What happens when key doesn't exist?
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k Keeper) getNewChannelID(ctx sdk.Context) (int64, error) {
|
func (k Keeper) getNewChannelID(ctx sdk.Context) ChannelID {
|
||||||
// get last channel ID
|
// get last channel ID
|
||||||
store := k.KVStore(k.storeKey)
|
var lastID ChannelID
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
bz := store.Get(k.getLastChannelIDKey())
|
bz := store.Get(k.getLastChannelIDKey())
|
||||||
if bz == nil {
|
if bz == nil {
|
||||||
return nil, // TODO throw some error (assumes this has been initialized elsewhere) or just set to zero here
|
lastID = -1 // TODO is just setting to zero if uninitialized ok?
|
||||||
|
} else {
|
||||||
|
k.cdc.MustUnmarshalBinary(bz, &lastID)
|
||||||
}
|
}
|
||||||
var lastID ChannelID
|
|
||||||
k.cdc.MustUnmarshalBinary(bz, &lastID)
|
|
||||||
// increment to create new one
|
// increment to create new one
|
||||||
newID := lastID+1
|
newID := lastID + 1
|
||||||
bz = k.cdc.MustMarshalBinary(newID)
|
bz = k.cdc.MustMarshalBinary(newID)
|
||||||
// set last channel id again
|
// set last channel id again
|
||||||
store.Set(k.getLastChannelIDKey(), bz)
|
store.Set(k.getLastChannelIDKey(), bz)
|
||||||
@ -302,11 +329,12 @@ func (k Keeper) getNewChannelID(ctx sdk.Context) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (k Keeper) getChannelKey(channelID ChannelID) []byte {
|
func (k Keeper) getChannelKey(channelID ChannelID) []byte {
|
||||||
return []bytes(fmt.Sprintf("channel:%d", channelID))
|
return []byte(fmt.Sprintf("channel:%d", channelID))
|
||||||
}
|
}
|
||||||
func (k Keeper) getLastChannelIDKey() []byte {
|
func (k Keeper) getLastChannelIDKey() []byte {
|
||||||
return []bytes("lastChannelID")
|
return []byte("lastChannelID")
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Close a payment channel and distribute funds to participants.
|
// Close a payment channel and distribute funds to participants.
|
||||||
func (k Keeper) ClosePaychan(ctx sdk.Context, sender sdk.Address, receiver sdk.Address, id int64, receiverAmount sdk.Coins) (sdk.Tags, sdk.Error) {
|
func (k Keeper) ClosePaychan(ctx sdk.Context, sender sdk.Address, receiver sdk.Address, id int64, receiverAmount sdk.Coins) (sdk.Tags, sdk.Error) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package paychan
|
package paychan
|
||||||
|
|
||||||
|
/*
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
//"github.com/stretchr/testify/assert"
|
//"github.com/stretchr/testify/assert"
|
||||||
@ -139,3 +140,4 @@ func TestKeeper(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -2,7 +2,7 @@ package paychan
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"strconv"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
/* CHANNEL TYPES */
|
/* CHANNEL TYPES */
|
||||||
@ -11,32 +11,35 @@ import (
|
|||||||
// Participants is limited to two as currently these are unidirectional channels.
|
// Participants is limited to two as currently these are unidirectional channels.
|
||||||
// Last participant is designated as receiver.
|
// Last participant is designated as receiver.
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
ID ChannelID
|
ID ChannelID
|
||||||
Participants [2]sdk.AccAddress
|
Participants [2]sdk.AccAddress // [senderAddr, receiverAddr]
|
||||||
Coins sdk.Coins
|
Coins sdk.Coins
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelID int64 // TODO should this be positive only
|
type ChannelID int64 // TODO should this be positive only
|
||||||
|
|
||||||
// The data that is passed between participants as payments, and submitted to the blockchain to close a channel.
|
// The data that is passed between participants as payments, and submitted to the blockchain to close a channel.
|
||||||
type Update struct {
|
type Update struct {
|
||||||
ChannelID int64
|
ChannelID ChannelID
|
||||||
CoinsUpdate map[sdk.AccAddress]sdk.Coins
|
CoinsUpdate map[string]sdk.Coins // map of bech32 addresses to coins
|
||||||
Sequence int64
|
Sequence int64
|
||||||
sig // TODO type, only sender needs to sign
|
Sigs [1]{crypto.Signature} // only sender needs to sign
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ChannelDisputeTime = int64(2000) // measured in blocks TODO pick reasonable time
|
||||||
|
|
||||||
// An update that has been submitted to the blockchain, but not yet acted on.
|
// An update that has been submitted to the blockchain, but not yet acted on.
|
||||||
type SubmittedUpdate {
|
type SubmittedUpdate struct {
|
||||||
Update
|
Update
|
||||||
executionTime int64 // BlockHeight
|
ExecutionTime int64 // BlockHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubmittedUpdateQueue []ChannelID
|
type SubmittedUpdatesQueue []ChannelID
|
||||||
|
|
||||||
// Check if value is in queue
|
// Check if value is in queue
|
||||||
func (suq SubmittedChannelID) Contains(channelID ChannelID) bool {
|
func (suq SubmittedUpdatesQueue) Contains(channelID ChannelID) bool {
|
||||||
found := false
|
found := false
|
||||||
for _, id := range(suq) {
|
for _, id := range suq {
|
||||||
if id == channelID {
|
if id == channelID {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
@ -44,11 +47,12 @@ func (suq SubmittedChannelID) Contains(channelID ChannelID) bool {
|
|||||||
}
|
}
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
// Remove all values from queue that match argument
|
|
||||||
func (suq SubmittedUpdateQueue) RemoveMatchingElements(channelID ChannelID) {
|
|
||||||
newSUQ := SubmittedUpdateQueue{}
|
|
||||||
|
|
||||||
for _, id := range(suq) {
|
// Remove all values from queue that match argument
|
||||||
|
func (suq SubmittedUpdatesQueue) RemoveMatchingElements(channelID ChannelID) {
|
||||||
|
newSUQ := SubmittedUpdatesQueue{}
|
||||||
|
|
||||||
|
for _, id := range suq {
|
||||||
if id != channelID {
|
if id != channelID {
|
||||||
newSUQ = append(newSUQ, id)
|
newSUQ = append(newSUQ, id)
|
||||||
}
|
}
|
||||||
@ -56,8 +60,6 @@ func (suq SubmittedUpdateQueue) RemoveMatchingElements(channelID ChannelID) {
|
|||||||
suq = newSUQ
|
suq = newSUQ
|
||||||
}
|
}
|
||||||
|
|
||||||
var ChannelDisputeTime = 2000 // measured in blocks
|
|
||||||
|
|
||||||
/* MESSAGE TYPES */
|
/* MESSAGE TYPES */
|
||||||
/*
|
/*
|
||||||
Message implement the sdk.Msg interface:
|
Message implement the sdk.Msg interface:
|
||||||
@ -77,14 +79,14 @@ type Msg interface {
|
|||||||
// Signers returns the addrs of signers that must sign.
|
// Signers returns the addrs of signers that must sign.
|
||||||
// CONTRACT: All signatures must be present to be valid.
|
// CONTRACT: All signatures must be present to be valid.
|
||||||
// CONTRACT: Returns addrs in some deterministic order.
|
// CONTRACT: Returns addrs in some deterministic order.
|
||||||
GetSigners() []Address
|
GetSigners() []AccAddress
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// A message to create a payment channel.
|
// A message to create a payment channel.
|
||||||
type MsgCreate struct {
|
type MsgCreate struct {
|
||||||
Participants [2]sdk.AccAddress
|
Participants [2]sdk.AccAddress
|
||||||
Coins sdk.Coins
|
Coins sdk.Coins
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create a new message.
|
//Create a new message.
|
||||||
@ -103,12 +105,11 @@ func (msg CreatMsg) NewMsgCreate(sender sdk.Address, receiver sdk.Address, amoun
|
|||||||
func (msg MsgCreate) Type() string { return "paychan" }
|
func (msg MsgCreate) Type() string { return "paychan" }
|
||||||
|
|
||||||
func (msg MsgCreate) GetSignBytes() []byte {
|
func (msg MsgCreate) GetSignBytes() []byte {
|
||||||
// TODO create msgCdc in wire.go
|
bz, err := msgCdc.MarshalJSON(msg)
|
||||||
bz, err := msgCdc.Marshal(msg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return MustSortJSON(bz)
|
return sdk.MustSortJSON(bz)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg MsgCreate) ValidateBasic() sdk.Error {
|
func (msg MsgCreate) ValidateBasic() sdk.Error {
|
||||||
@ -118,29 +119,29 @@ func (msg MsgCreate) ValidateBasic() sdk.Error {
|
|||||||
//TODO implement
|
//TODO implement
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// check if all fields present / not 0 valued
|
// check if all fields present / not 0 valued
|
||||||
if len(msg.Sender) == 0 {
|
if len(msg.Sender) == 0 {
|
||||||
return sdk.ErrInvalidAddress(msg.Sender.String())
|
return sdk.ErrInvalidAddress(msg.Sender.String())
|
||||||
}
|
}
|
||||||
if len(msg.Receiver) == 0 {
|
if len(msg.Receiver) == 0 {
|
||||||
return sdk.ErrInvalidAddress(msg.Receiver.String())
|
return sdk.ErrInvalidAddress(msg.Receiver.String())
|
||||||
}
|
}
|
||||||
if len(msg.Amount) == 0 {
|
if len(msg.Amount) == 0 {
|
||||||
return sdk.ErrInvalidCoins(msg.Amount.String())
|
return sdk.ErrInvalidCoins(msg.Amount.String())
|
||||||
}
|
}
|
||||||
// Check if coins are sorted, non zero, non negative
|
// Check if coins are sorted, non zero, non negative
|
||||||
if !msg.Amount.IsValid() {
|
if !msg.Amount.IsValid() {
|
||||||
return sdk.ErrInvalidCoins(msg.Amount.String())
|
return sdk.ErrInvalidCoins(msg.Amount.String())
|
||||||
}
|
}
|
||||||
if !msg.Amount.IsPositive() {
|
if !msg.Amount.IsPositive() {
|
||||||
return sdk.ErrInvalidCoins(msg.Amount.String())
|
return sdk.ErrInvalidCoins(msg.Amount.String())
|
||||||
}
|
}
|
||||||
// TODO check if Address valid?
|
// TODO check if Address valid?
|
||||||
*/
|
*/
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg MsgCreate) GetSigners() []sdk.Address {
|
func (msg MsgCreate) GetSigners() []sdk.AccAddress {
|
||||||
// Only sender must sign to create a paychan
|
// Only sender must sign to create a paychan
|
||||||
return []sdk.AccAddress{msg.Participants[0]} // select sender address
|
return []sdk.AccAddress{msg.Participants[0]} // select sender address
|
||||||
}
|
}
|
||||||
@ -160,46 +161,45 @@ type MsgSubmitUpdate struct {
|
|||||||
func (msg MsgSubmitUpdate) Type() string { return "paychan" }
|
func (msg MsgSubmitUpdate) Type() string { return "paychan" }
|
||||||
|
|
||||||
func (msg MsgSubmitUpdate) GetSignBytes() []byte {
|
func (msg MsgSubmitUpdate) GetSignBytes() []byte {
|
||||||
// TODO create msgCdc in wire.go
|
bz, err := msgCdc.MarshalJSON(msg)
|
||||||
bz, err := msgCdc.Marshal(msg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return MustSortJSON(bz)
|
return sdk.MustSortJSON(bz)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg MsgSubmitUpdate) ValidateBasic() sdk.Error {
|
func (msg MsgSubmitUpdate) ValidateBasic() sdk.Error {
|
||||||
|
|
||||||
// TODO implement
|
// TODO implement
|
||||||
/*
|
/*
|
||||||
// check if all fields present / not 0 valued
|
// check if all fields present / not 0 valued
|
||||||
if len(msg.Sender) == 0 {
|
if len(msg.Sender) == 0 {
|
||||||
return sdk.ErrInvalidAddress(msg.Sender.String())
|
return sdk.ErrInvalidAddress(msg.Sender.String())
|
||||||
}
|
}
|
||||||
if len(msg.Receiver) == 0 {
|
if len(msg.Receiver) == 0 {
|
||||||
return sdk.ErrInvalidAddress(msg.Receiver.String())
|
return sdk.ErrInvalidAddress(msg.Receiver.String())
|
||||||
}
|
}
|
||||||
if len(msg.ReceiverAmount) == 0 {
|
if len(msg.ReceiverAmount) == 0 {
|
||||||
return sdk.ErrInvalidCoins(msg.ReceiverAmount.String())
|
return sdk.ErrInvalidCoins(msg.ReceiverAmount.String())
|
||||||
}
|
}
|
||||||
// check id ≥ 0
|
// check id ≥ 0
|
||||||
if msg.Id < 0 {
|
if msg.Id < 0 {
|
||||||
return sdk.ErrInvalidAddress(strconv.Itoa(int(msg.Id))) // TODO implement custom errors
|
return sdk.ErrInvalidAddress(strconv.Itoa(int(msg.Id))) // TODO implement custom errors
|
||||||
}
|
}
|
||||||
// Check if coins are sorted, non zero, non negative
|
// Check if coins are sorted, non zero, non negative
|
||||||
if !msg.ReceiverAmount.IsValid() {
|
if !msg.ReceiverAmount.IsValid() {
|
||||||
return sdk.ErrInvalidCoins(msg.ReceiverAmount.String())
|
return sdk.ErrInvalidCoins(msg.ReceiverAmount.String())
|
||||||
}
|
}
|
||||||
if !msg.ReceiverAmount.IsPositive() {
|
if !msg.ReceiverAmount.IsPositive() {
|
||||||
return sdk.ErrInvalidCoins(msg.ReceiverAmount.String())
|
return sdk.ErrInvalidCoins(msg.ReceiverAmount.String())
|
||||||
}
|
}
|
||||||
// TODO check if Address valid?
|
// TODO check if Address valid?
|
||||||
*/
|
*/
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg MsgSubmitUpdate) GetSigners() []sdk.Address {
|
func (msg MsgSubmitUpdate) GetSigners() []sdk.AccAddress {
|
||||||
// Signing not strictly necessary as signatures contained within the channel update.
|
// Signing not strictly necessary as signatures contained within the channel update.
|
||||||
// TODO add signature by submitting address
|
// TODO add signature by submitting address
|
||||||
return []sdk.Address{}
|
return []sdk.AccAddress{msg.submitter}
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,14 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
func RegisterWire(cdc *wire.Codec) {
|
func RegisterWire(cdc *wire.Codec) {
|
||||||
cdc.RegisterConcrete(MsgCreate{}, "paychan/MsgCreate", nil)
|
cdc.RegisterConcrete(MsgCreate{}, "paychan/MsgCreate", nil)
|
||||||
cdc.RegisterConcrete(MsgClose{}, "paychan/MsgClose", nil)
|
cdc.RegisterConcrete(MsgSubmitUpdate{}, "paychan/MsgSubmitUpdate", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var msgCdc = wire.NewCodec()
|
var msgCdc = wire.NewCodec()
|
||||||
|
|
||||||
|
/*
|
||||||
func init() {
|
func init() {
|
||||||
RegisterWire(msgCdc)
|
RegisterWire(msgCdc)
|
||||||
// TODO is this needed?
|
// TODO is this needed?
|
||||||
|
Loading…
Reference in New Issue
Block a user