cosmos-sdk/x/bank/tx.go

220 lines
5.0 KiB
Go
Raw Normal View History

package bank
import (
"encoding/json"
"fmt"
crypto "github.com/tendermint/go-crypto"
2018-01-26 04:19:33 -08:00
sdk "github.com/cosmos/cosmos-sdk/types"
)
// SendMsg - high level transaction of the coin module
type SendMsg struct {
Inputs []Input `json:"inputs"`
Outputs []Output `json:"outputs"`
}
// NewSendMsg - construct arbitrary multi-in, multi-out send msg.
2018-01-12 14:30:02 -08:00
func NewSendMsg(in []Input, out []Output) SendMsg {
return SendMsg{Inputs: in, Outputs: out}
}
// Implements Msg.
func (msg SendMsg) Type() string { return "bank" } // TODO: "bank/send"
// Implements Msg.
2018-01-26 04:19:33 -08:00
func (msg SendMsg) ValidateBasic() sdk.Error {
// this just makes sure all the inputs and outputs are properly formatted,
// not that they actually have the money inside
if len(msg.Inputs) == 0 {
2018-01-26 04:19:33 -08:00
return ErrNoInputs().Trace("")
}
if len(msg.Outputs) == 0 {
2018-01-26 04:19:33 -08:00
return ErrNoOutputs().Trace("")
}
// make sure all inputs and outputs are individually valid
2018-01-26 04:19:33 -08:00
var totalIn, totalOut sdk.Coins
for _, in := range msg.Inputs {
if err := in.ValidateBasic(); err != nil {
2018-01-26 04:19:33 -08:00
return err.Trace("")
}
totalIn = totalIn.Plus(in.Coins)
}
for _, out := range msg.Outputs {
if err := out.ValidateBasic(); err != nil {
2018-01-26 04:19:33 -08:00
return err.Trace("")
}
totalOut = totalOut.Plus(out.Coins)
}
// make sure inputs and outputs match
if !totalIn.IsEqual(totalOut) {
2018-01-26 04:19:33 -08:00
return ErrInvalidCoins(totalIn.String()).Trace("inputs and outputs don't match")
}
return nil
}
func (msg SendMsg) String() string {
return fmt.Sprintf("SendMsg{%v->%v}", msg.Inputs, msg.Outputs)
}
// Implements Msg.
func (msg SendMsg) Get(key interface{}) (value interface{}) {
return nil
}
// Implements Msg.
func (msg SendMsg) GetSignBytes() []byte {
b, err := json.Marshal(msg) // XXX: ensure some canonical form
if err != nil {
panic(err)
}
return b
}
// Implements Msg.
2018-03-01 23:49:07 -08:00
func (msg SendMsg) GetSigners() []sdk.Address {
addrs := make([]sdk.Address, len(msg.Inputs))
for i, in := range msg.Inputs {
addrs[i] = in.Address
}
return addrs
}
//----------------------------------------
// IssueMsg
// IssueMsg - high level transaction of the coin module
type IssueMsg struct {
2018-03-01 23:49:07 -08:00
Banker sdk.Address `json:"banker"`
Outputs []Output `json:"outputs"`
}
// NewIssueMsg - construct arbitrary multi-in, multi-out send msg.
2018-03-01 23:49:07 -08:00
func NewIssueMsg(banker sdk.Address, out []Output) IssueMsg {
return IssueMsg{Banker: banker, Outputs: out}
}
// Implements Msg.
func (msg IssueMsg) Type() string { return "bank" } // TODO: "bank/send"
// Implements Msg.
2018-01-26 04:19:33 -08:00
func (msg IssueMsg) ValidateBasic() sdk.Error {
// XXX
if len(msg.Outputs) == 0 {
2018-01-26 04:19:33 -08:00
return ErrNoOutputs().Trace("")
}
for _, out := range msg.Outputs {
if err := out.ValidateBasic(); err != nil {
2018-01-26 04:19:33 -08:00
return err.Trace("")
}
}
return nil
}
func (msg IssueMsg) String() string {
return fmt.Sprintf("IssueMsg{%v#%v}", msg.Banker, msg.Outputs)
}
// Implements Msg.
func (msg IssueMsg) Get(key interface{}) (value interface{}) {
return nil
}
// Implements Msg.
func (msg IssueMsg) GetSignBytes() []byte {
b, err := json.Marshal(msg) // XXX: ensure some canonical form
if err != nil {
panic(err)
}
return b
}
// Implements Msg.
2018-03-01 23:49:07 -08:00
func (msg IssueMsg) GetSigners() []sdk.Address {
return []sdk.Address{msg.Banker}
}
//----------------------------------------
// Input
type Input struct {
2018-03-01 23:49:07 -08:00
Address sdk.Address `json:"address"`
2018-01-26 04:19:33 -08:00
Coins sdk.Coins `json:"coins"`
Sequence int64 `json:"sequence"`
signature crypto.Signature
}
// ValidateBasic - validate transaction input
2018-01-26 04:19:33 -08:00
func (in Input) ValidateBasic() sdk.Error {
if len(in.Address) == 0 {
return ErrInvalidAddress(in.Address.String())
}
if in.Sequence < 0 {
2018-01-26 04:19:33 -08:00
return ErrInvalidSequence("negative sequence")
}
if !in.Coins.IsValid() {
return ErrInvalidCoins(in.Coins.String())
}
if !in.Coins.IsPositive() {
return ErrInvalidCoins(in.Coins.String())
}
return nil
}
func (in Input) String() string {
return fmt.Sprintf("Input{%v,%v}", in.Address, in.Coins)
}
// NewInput - create a transaction input, used with SendMsg
2018-03-01 23:49:07 -08:00
func NewInput(addr sdk.Address, coins sdk.Coins) Input {
input := Input{
Address: addr,
Coins: coins,
}
return input
}
// NewInputWithSequence - create a transaction input, used with SendMsg
2018-03-01 23:49:07 -08:00
func NewInputWithSequence(addr sdk.Address, coins sdk.Coins, seq int64) Input {
input := NewInput(addr, coins)
input.Sequence = seq
return input
}
//----------------------------------------
// Output
type Output struct {
2018-03-01 23:49:07 -08:00
Address sdk.Address `json:"address"`
2018-01-26 04:19:33 -08:00
Coins sdk.Coins `json:"coins"`
}
// ValidateBasic - validate transaction output
2018-01-26 04:19:33 -08:00
func (out Output) ValidateBasic() sdk.Error {
if len(out.Address) == 0 {
return ErrInvalidAddress(out.Address.String())
}
if !out.Coins.IsValid() {
return ErrInvalidCoins(out.Coins.String())
}
if !out.Coins.IsPositive() {
return ErrInvalidCoins(out.Coins.String())
}
return nil
}
func (out Output) String() string {
return fmt.Sprintf("Output{%X,%v}", out.Address, out.Coins)
}
// NewOutput - create a transaction output, used with SendMsg
2018-03-01 23:49:07 -08:00
func NewOutput(addr sdk.Address, coins sdk.Coins) Output {
output := Output{
Address: addr,
Coins: coins,
}
return output
}