mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-04-04 15:55:23 +00:00 
			
		
		
		
	add commands
This commit is contained in:
		
							parent
							
								
									3ae217e927
								
							
						
					
					
						commit
						3f7bcca487
					
				| @ -8,7 +8,6 @@ Simplifications: | ||||
| 
 | ||||
|  TODO | ||||
|  - in code TODOs | ||||
|  - write basic cmds | ||||
|  - Tidy up - method descriptions, heading comments, remove uneccessary comments, README/docs | ||||
|  - chnge module name to "channel"? | ||||
|  - Find a better name for Queue - clarify distinction between int slice and abstract queue concept | ||||
| @ -16,6 +15,7 @@ Simplifications: | ||||
|  - find nicer name for payout | ||||
|  - add Gas usage | ||||
|  - add tags (return channel id on creation) | ||||
|  - refactor cmds to be able to test them, then test them | ||||
|  - use custom errors instead of using sdk.ErrInternal | ||||
|  - split off signatures from update as with txs/msgs - testing easier, code easier to use, doesn't store sigs unecessarily on chain | ||||
|  - consider removing pubKey from UpdateSignature - instead let channel module access accountMapper | ||||
|  | ||||
| @ -3,6 +3,7 @@ package cli | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 
 | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/spf13/cobra" | ||||
| @ -21,62 +22,54 @@ import ( | ||||
| // list of functions that return pointers to cobra commands
 | ||||
| // No local storage needed for cli acting as a sender
 | ||||
| 
 | ||||
| // Current minimal set of cli commands:
 | ||||
| // create paychan - create and fund (sender signs tx)
 | ||||
| // generate new update - print a signed update (from sender)
 | ||||
| // submit update - send update to chain (either can sign tx)
 | ||||
| 
 | ||||
| // Future cli commands:
 | ||||
| // create paychan
 | ||||
| // close paychan
 | ||||
| // get paychan(s)
 | ||||
| // send paychan payment
 | ||||
| // get balance from receiver
 | ||||
| 
 | ||||
| /* | ||||
| func CreatePaychanCmd(cdc *wire.Codec) *cobra.Command { | ||||
| func CreateChannelCmd(cdc *wire.Codec) *cobra.Command { | ||||
| 	flagTo := "to" | ||||
| 	flagAmount := "amount" | ||||
| 	flagCoins := "amount" | ||||
| 
 | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:   "create", | ||||
| 		Short: "Create a new payment channel", | ||||
| 		Long:  "Create a new payment channel from a local address to a remote address, funded with some amount of coins. These coins are removed from the sender account and put into the payment channel.", | ||||
| 		Long:  "Create a new unidirectional payment channel from a local address to a remote address, funded with some amount of coins. These coins are removed from the sender account and put into the channel.", | ||||
| 		Args:  cobra.NoArgs, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 
 | ||||
| 			// Create a "client context" stuct populated with info from common flags
 | ||||
| 			ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) | ||||
| 			// ctx.PrintResponse = true TODO is this needed for channelID
 | ||||
| 
 | ||||
| 			// Get sender adress
 | ||||
| 			senderAddress, err := ctx.GetFromAddress() | ||||
| 			sender, err := ctx.GetFromAddress() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// Get receiver address
 | ||||
| 			toStr := viper.GetString(flagTo) | ||||
| 			receiverAddress, err := sdk.GetAccAddressBech32(toStr) | ||||
| 			receiver, err := sdk.GetAccAddressBech32(toStr) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// Get channel funding amount
 | ||||
| 			amountString := viper.GetString(flagAmount) | ||||
| 			amount, err := sdk.ParseCoins(amountString) | ||||
| 			coinsString := viper.GetString(flagCoins) | ||||
| 			coins, err := sdk.ParseCoins(coinsString) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// Create the create channel msg to send
 | ||||
| 			// TODO write NewMsgCreate func?
 | ||||
| 			msg := paychan.MsgCreate{ | ||||
| 				Sender:   senderAddress, | ||||
| 				Receiver: receiverAddress, | ||||
| 				Amount:   amount, | ||||
| 				Participants: []sdk.AccAddress{sender, receiver}, | ||||
| 				Coins:        coins, | ||||
| 			} | ||||
| 			err = msg.ValidateBasic() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// Build and sign the transaction, then broadcast to the blockchain
 | ||||
| 			res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, msg, cdc) | ||||
| 			res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| @ -84,77 +77,180 @@ func CreatePaychanCmd(cdc *wire.Codec) *cobra.Command { | ||||
| 			return nil | ||||
| 		}, | ||||
| 	} | ||||
| 	cmd.Flags().String(flagTo, "", "Recipient address of the payment channel") | ||||
| 	cmd.Flags().String(flagAmount, "", "Amount of coins to fund the paymetn channel with") | ||||
| 	cmd.Flags().String(flagTo, "", "Recipient address of the payment channel.") | ||||
| 	cmd.Flags().String(flagAmount, "", "Amount of coins to fund the payment channel with.") | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| func GenerateNewStateCmd(cdc *wire.Codec) *cobra.Command { | ||||
| 	flagId := "id" | ||||
| 	flagTo := "to" | ||||
| 	flagAmount := "amount" | ||||
| func GeneratePaymentCmd(cdc *wire.Codec) *cobra.Command { | ||||
| 	flagId := "id"                   // ChannelID
 | ||||
| 	flagReceiverAmount := "r-amount" // amount the receiver should received on closing the channel
 | ||||
| 	flagSenderAmount := "s-amount"   //
 | ||||
| 
 | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:   "new-state", | ||||
| 		Short: "Generate a new payment channel state.", | ||||
| 		Long:  "Generate a new state for an existing payment channel and print it out. The new state is represented as a half signed close transaction, signed by the sender.", | ||||
| 		Use:   "pay", | ||||
| 		Short: "Generate a .", // TODO descriptions
 | ||||
| 		Long:  "Generate a new ", | ||||
| 		Args:  cobra.NoArgs, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 
 | ||||
| 			// Create a "client context" stuct populated with info from common flags
 | ||||
| 			ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) | ||||
| 			// ctx.PrintResponse = false TODO is this needed to stop any other output messing up json?
 | ||||
| 
 | ||||
| 			// Get sender adress
 | ||||
| 			senderAddress, err := ctx.GetFromAddress() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			// senderAddress, err := ctx.GetFromAddress()
 | ||||
| 			// if err != nil {
 | ||||
| 			// 	return err
 | ||||
| 			// }
 | ||||
| 
 | ||||
| 			// Get the paychan id
 | ||||
| 			id := viper.GetInt64(flagId) | ||||
| 			id := viper.GetInt64(flagId) // TODO make this default to pulling id from chain
 | ||||
| 
 | ||||
| 			// Get receiver address
 | ||||
| 			toStr := viper.GetString(flagTo) | ||||
| 			receiverAddress, err := sdk.GetAccAddressBech32(toStr) | ||||
| 			// Get channel receiver amount
 | ||||
| 			senderCoins, err := sdk.ParseCoins(viper.GetString(flagSenderAmount)) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// Get channel receiver amount
 | ||||
| 			amountString := viper.GetString(flagAmount) | ||||
| 			amount, err := sdk.ParseCoins(amountString) | ||||
| 			receiverCoins, err := sdk.ParseCoins(viper.GetString(flagReceiverAmount)) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// create close paychan msg
 | ||||
| 			msg := paychan.MsgClose{ | ||||
| 				Sender:         senderAddress, | ||||
| 				Receiver:       receiverAddress, | ||||
| 				Id:             id, | ||||
| 				ReceiverAmount: amount, | ||||
| 			update := paychan.Update{ | ||||
| 				ChannelID: id, | ||||
| 				Payout:    paychan.Payout{senderCoins, receiverCoins}, | ||||
| 				// empty sigs
 | ||||
| 			} | ||||
| 
 | ||||
| 			// Sign the msg as the sender
 | ||||
| 			txBytes, err := EnsureSignBuild(ctx, ctx.FromAddressName, msg, cdc) | ||||
| 			// Sign the update as the sender
 | ||||
| 			keybase, err := keys.GetKeyBase() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			name := ctx.FromAddressName | ||||
| 			passphrase, err := ctx.GetPassphraseFromStdin(name) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			bz := update.GetSignBytes() | ||||
| 
 | ||||
| 			sig, pubKey, err := keybase.Sign(name, passphrase, bz) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			update.Sigs = [1]paychan.UpdateSignature{ | ||||
| 				PubKey:          pubKey, | ||||
| 				CryptoSignature: sig, | ||||
| 			} | ||||
| 
 | ||||
| 			// Print out the update
 | ||||
| 			jsonUpdate := cdc.MarshalJSONIndent(update) | ||||
| 			fmt.Println(string(jsonUpdate)) | ||||
| 
 | ||||
| 			// Print out the signed msg
 | ||||
| 			fmt.Println("txBytes:", txBytes) | ||||
| 			//encodedTxBytes := make([]byte, base64.StdEncoding.EncodedLen(len(txBytes)))
 | ||||
| 			encodedTxBytes := base64.StdEncoding.EncodeToString(txBytes) | ||||
| 			fmt.Println("base64TxBytes:", encodedTxBytes) | ||||
| 			return nil | ||||
| 		}, | ||||
| 	} | ||||
| 	cmd.Flags().Int(flagId, 0, "ID of the payment channel.") | ||||
| 	cmd.Flags().String(flagTo, "", "Recipient address of the payment channel") | ||||
| 	cmd.Flags().String(flagAmount, "", "Amount of coins to fund the paymetn channel with") | ||||
| 	cmd.Flags().String(flagSenderAmount, "", "") | ||||
| 	cmd.Flags().String(flagReceiverAmount, "", "") | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| func VerifyPaymentCmd(cdc *wire.Codec, paychanStoreName, string) *cobra.Command { | ||||
| 
 | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:   "verify", | ||||
| 		Short: "", // TODO
 | ||||
| 		Long:  "", | ||||
| 		Args:  cobra.NoArgs, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 
 | ||||
| 			// read in update
 | ||||
| 			bz, err := ioutil.ReadAll(os.Stdin) | ||||
| 			if err != nil { | ||||
| 				// TODO add nice message about how to feed in stdin
 | ||||
| 				return err | ||||
| 			} | ||||
| 			// decode json
 | ||||
| 			var update paychan.Update | ||||
| 			cdc.UnmarshalJSON(bz, &update) | ||||
| 
 | ||||
| // get the channel from the node
 | ||||
| 			res, err := ctx.QueryStore(paychan.GetChannelKey(update.ChannelID), paychanStoreName) | ||||
| 			if len(res) == 0 || err != nil { | ||||
| 				return errors.Errorf("channel with ID '%d' does not exist", update.ChannelID) | ||||
| 			} | ||||
| 			var channel paychan.Channel | ||||
| 			cdc.MustUnmarshalBinary(res, &channel) | ||||
| 
 | ||||
| 			//verify
 | ||||
| 			updateIsOK := paychan.Keeper.VerifyUpdate(channel ,update) | ||||
| 
 | ||||
| 			// print result
 | ||||
| 			fmt.Println(updateIsOK) | ||||
| 
 | ||||
| 			return nil | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| func SubmitPaymentChannelCmd(cdc *wire.Codec) *cobra.Command { | ||||
| 
 | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:   "submit", | ||||
| 		Short: "", | ||||
| 		Long:  "", | ||||
| 		Args:  cobra.NoArgs, | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 
 | ||||
| 			// Create a "client context" stuct populated with info from common flags
 | ||||
| 			ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) | ||||
| 			// ctx.PrintResponse = true TODO is this needed for channelID
 | ||||
| 
 | ||||
| 			// Get sender adress
 | ||||
| 			submitter, err := ctx.GetFromAddress() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// read in update
 | ||||
| 			bz, err := ioutil.ReadAll(os.Stdin) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			// decode json
 | ||||
| 			var update paychan.Update | ||||
| 			cdc.UnmarshalJSON(bz, &update) | ||||
| 
 | ||||
| 			// Create the create channel msg to send
 | ||||
| 			msg := paychan.MsgSubmitUpdate{ | ||||
| 				Update:    update, | ||||
| 				Submitter: submitter, | ||||
| 			} | ||||
| 			err = msg.ValidateBasic() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// Build and sign the transaction, then broadcast to the blockchain
 | ||||
| 			res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) | ||||
| 			return nil | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| func ClosePaychanCmd(cdc *wire.Codec) *cobra.Command { | ||||
| 	flagState := "state" | ||||
| 
 | ||||
|  | ||||
| @ -45,10 +45,10 @@ func handleMsgSubmitUpdate(ctx sdk.Context, k Keeper, msg MsgSubmitUpdate) sdk.R | ||||
| 	participants := channel.Participants | ||||
| 
 | ||||
| 	// if only sender signed
 | ||||
| 	if reflect.DeepEqual(msg.submitter, participants[0]) { | ||||
| 	if reflect.DeepEqual(msg.Submitter, participants[0]) { | ||||
| 		tags, err = k.InitCloseChannelBySender(ctx, msg.Update) | ||||
| 		// else if receiver signed
 | ||||
| 	} else if reflect.DeepEqual(msg.submitter, participants[len(participants)-1]) { | ||||
| 	} else if reflect.DeepEqual(msg.Submitter, participants[len(participants)-1]) { | ||||
| 		tags, err = k.CloseChannelByReceiver(ctx, msg.Update) | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -74,7 +74,12 @@ func (k Keeper) CreateChannel(ctx sdk.Context, sender sdk.AccAddress, receiver s | ||||
| func (k Keeper) InitCloseChannelBySender(ctx sdk.Context, update Update) (sdk.Tags, sdk.Error) { | ||||
| 	// This is roughly the default path for non unidirectional channels
 | ||||
| 
 | ||||
| 	err := k.validateUpdate(ctx, update) | ||||
| 	// get the channel
 | ||||
| 	channel, found := k.getChannel(ctx, update.ChannelID) | ||||
| 	if !found { | ||||
| 		return nil, sdk.ErrInternal("Channel doesn't exist") | ||||
| 	} | ||||
| 	err := k.VerifyUpdate(channel, update) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @ -113,7 +118,12 @@ func (k Keeper) InitCloseChannelBySender(ctx sdk.Context, update Update) (sdk.Ta | ||||
| 
 | ||||
| func (k Keeper) CloseChannelByReceiver(ctx sdk.Context, update Update) (sdk.Tags, sdk.Error) { | ||||
| 
 | ||||
| 	err := k.validateUpdate(ctx, update) | ||||
| 	// get the channel
 | ||||
| 	channel, found := k.getChannel(ctx, update.ChannelID) | ||||
| 	if !found { | ||||
| 		return nil, sdk.ErrInternal("Channel doesn't exist") | ||||
| 	} | ||||
| 	err := k.VerifyUpdate(channel, update) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @ -152,12 +162,8 @@ func (k Keeper) CloseChannelByReceiver(ctx sdk.Context, update Update) (sdk.Tags | ||||
| // 	return returnUpdate
 | ||||
| // }
 | ||||
| 
 | ||||
| func (k Keeper) validateUpdate(ctx sdk.Context, update Update) sdk.Error { | ||||
| 	// Check that channel exists
 | ||||
| 	channel, found := k.getChannel(ctx, update.ChannelID) | ||||
| 	if !found { | ||||
| 		return sdk.ErrInternal("Channel doesn't exist") | ||||
| 	} | ||||
| func (k Keeper) VerifyUpdate(channel Channel, update Update) sdk.Error { | ||||
| 
 | ||||
| 	// Check the num of payout participants match channel participants
 | ||||
| 	if len(update.Payout) != len(channel.Participants) { | ||||
| 		return sdk.ErrInternal("Payout doesn't match number of channel participants") | ||||
| @ -177,7 +183,7 @@ func (k Keeper) validateUpdate(ctx sdk.Context, update Update) sdk.Error { | ||||
| 		return sdk.ErrInternal("Payout amount doesn't match channel amount") | ||||
| 	} | ||||
| 	// Check sender signature is OK
 | ||||
| 	if !k.verifySignatures(ctx, channel, update) { | ||||
| 	if !k.verifySignatures(channel, update) { | ||||
| 		return sdk.ErrInternal("Signature on update not valid") | ||||
| 	} | ||||
| 	return nil | ||||
| @ -206,7 +212,7 @@ func (k Keeper) closeChannel(ctx sdk.Context, update Update) (sdk.Tags, sdk.Erro | ||||
| 	return tags, nil | ||||
| } | ||||
| 
 | ||||
| func (k Keeper) verifySignatures(ctx sdk.Context, channel Channel, update Update) bool { | ||||
| func (k Keeper) verifySignatures(channel Channel, update Update) bool { | ||||
| 	// In non unidirectional channels there will be more than one signature to check
 | ||||
| 
 | ||||
| 	signBytes := update.GetSignBytes() | ||||
| @ -326,7 +332,7 @@ func (k Keeper) getSubmittedUpdateKey(channelID ChannelID) []byte { | ||||
| func (k Keeper) getChannel(ctx sdk.Context, channelID ChannelID) (Channel, bool) { | ||||
| 	// load from DB
 | ||||
| 	store := ctx.KVStore(k.storeKey) | ||||
| 	bz := store.Get(k.getChannelKey(channelID)) | ||||
| 	bz := store.Get(k.GetChannelKey(channelID)) | ||||
| 
 | ||||
| 	var channel Channel | ||||
| 	if bz == nil { | ||||
| @ -344,13 +350,13 @@ func (k Keeper) setChannel(ctx sdk.Context, channel Channel) { | ||||
| 	// marshal
 | ||||
| 	bz := k.cdc.MustMarshalBinary(channel) // panics if something goes wrong
 | ||||
| 	// write to db
 | ||||
| 	key := k.getChannelKey(channel.ID) | ||||
| 	key := k.GetChannelKey(channel.ID) | ||||
| 	store.Set(key, bz) // panics if something goes wrong
 | ||||
| } | ||||
| 
 | ||||
| func (k Keeper) deleteChannel(ctx sdk.Context, channelID ChannelID) { | ||||
| 	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?
 | ||||
| } | ||||
| 
 | ||||
| @ -373,7 +379,7 @@ func (k Keeper) getNewChannelID(ctx sdk.Context) ChannelID { | ||||
| 	return newID | ||||
| } | ||||
| 
 | ||||
| func (k Keeper) getChannelKey(channelID ChannelID) []byte { | ||||
| func (k Keeper) GetChannelKey(channelID ChannelID) []byte { | ||||
| 	return []byte(fmt.Sprintf("channel:%d", channelID)) | ||||
| } | ||||
| func (k Keeper) getLastChannelIDKey() []byte { | ||||
|  | ||||
| @ -45,7 +45,7 @@ type UpdateSignature struct { | ||||
| 	CryptoSignature crypto.Signature | ||||
| } | ||||
| 
 | ||||
| type Payout []sdk.Coins // a list of coins to be paid to each of Channel.Participants
 | ||||
| type Payout [2]sdk.Coins // a list of coins to be paid to each of Channel.Participants
 | ||||
| func (p Payout) IsNotNegative() bool { | ||||
| 	result := true | ||||
| 	for _, coins := range p { | ||||
| @ -195,7 +195,7 @@ func (msg MsgCreate) GetSigners() []sdk.AccAddress { | ||||
| // A message to close a payment channel.
 | ||||
| type MsgSubmitUpdate struct { | ||||
| 	Update | ||||
| 	submitter sdk.AccAddress | ||||
| 	Submitter sdk.AccAddress | ||||
| } | ||||
| 
 | ||||
| // func (msg MsgSubmitUpdate) NewMsgSubmitUpdate(update Update) MsgSubmitUpdate {
 | ||||
| @ -247,5 +247,5 @@ func (msg MsgSubmitUpdate) ValidateBasic() sdk.Error { | ||||
| func (msg MsgSubmitUpdate) GetSigners() []sdk.AccAddress { | ||||
| 	// Signing not strictly necessary as signatures contained within the channel update.
 | ||||
| 	// TODO add signature by submitting address
 | ||||
| 	return []sdk.AccAddress{msg.submitter} | ||||
| 	return []sdk.AccAddress{msg.Submitter} | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 rhuairahrighairigh
						rhuairahrighairigh