diff --git a/errors/common.go b/errors/common.go index 8c152c4493..8eb05045d3 100644 --- a/errors/common.go +++ b/errors/common.go @@ -8,6 +8,7 @@ import ( "fmt" abci "github.com/tendermint/abci/types" + "github.com/tendermint/basecoin" ) const ( @@ -26,8 +27,14 @@ const ( msgTooManySignatures = "Too many signatures" msgNoChain = "No chain id provided" msgWrongChain = "Tx belongs to different chain - %s" + msgUnknownTxType = "We cannot handle this tx - %v" ) +func UnknownTxType(tx basecoin.Tx) TMError { + msg := fmt.Sprintf(msgUnknownTxType, tx) + return New(msg, abci.CodeType_UnknownRequest) +} + func InternalError(msg string) TMError { return New(msg, abci.CodeType_InternalError) } diff --git a/modules/coin/handler.go b/modules/coin/handler.go new file mode 100644 index 0000000000..de66c434a6 --- /dev/null +++ b/modules/coin/handler.go @@ -0,0 +1,64 @@ +package coin + +import ( + "github.com/tendermint/basecoin" + "github.com/tendermint/basecoin/errors" + "github.com/tendermint/basecoin/types" +) + +const ( + NameCoin = "coin" +) + +// Handler writes +type Handler struct{} + +var _ basecoin.Handler = Handler{} + +func (_ Handler) Name() string { + return NameCoin +} + +// CheckTx checks if there is enough money in the account +func (h Handler) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) { + _, err = checkTx(ctx, tx) + if err != nil { + return res, err + } + + // now make sure there is money + + // otherwise, we are good + return res, nil +} + +// DeliverTx moves the money +func (h Handler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) { + _, err = checkTx(ctx, tx) + if err != nil { + return res, err + } + + // now move the money + return basecoin.Result{}, nil +} + +func checkTx(ctx basecoin.Context, tx basecoin.Tx) (*SendTx, error) { + // check if the tx is proper type and valid + send, ok := tx.Unwrap().(*SendTx) + if !ok { + return nil, errors.UnknownTxType(tx) + } + err := send.ValidateBasic() + if err != nil { + return nil, err + } + + // check if all inputs have permission + for _, in := range send.Inputs { + if !ctx.HasPermission(in.Address) { + return nil, errors.Unauthorized() + } + } + return send, nil +} diff --git a/modules/coin/tx.go b/modules/coin/tx.go index 1c3b2efb17..935b34bc84 100644 --- a/modules/coin/tx.go +++ b/modules/coin/tx.go @@ -98,15 +98,23 @@ func (tx SendTx) ValidateBasic() error { if len(tx.Outputs) == 0 { return errors.NoOutputs() } + // make sure all inputs and outputs are individually valid + var totalIn, totalOut types.Coins for _, in := range tx.Inputs { if err := in.ValidateBasic(); err != nil { return err } + totalIn.Plus(in.Coins) } for _, out := range tx.Outputs { if err := out.ValidateBasic(); err != nil { return err } + totalOut.Plus(out.Coins) + } + // make sure inputs and outputs match + if !totalIn.IsEqual(totalOut) { + return errors.InvalidCoins() } return nil } diff --git a/stack/multiplexer.go b/stack/multiplexer.go index 7788fbdd1a..b0cddfc98e 100644 --- a/stack/multiplexer.go +++ b/stack/multiplexer.go @@ -1,9 +1,13 @@ package stack import ( + "strings" + "github.com/tendermint/basecoin" "github.com/tendermint/basecoin/txs" "github.com/tendermint/basecoin/types" + wire "github.com/tendermint/go-wire" + "github.com/tendermint/go-wire/data" ) const ( @@ -45,7 +49,17 @@ func runAll(ctx basecoin.Context, store types.KVStore, txs []basecoin.Tx, next b return combine(rs), nil } -func combine(res []basecoin.Result) basecoin.Result { - // TODO: how to combine??? - return res[0] +// combines all data bytes as a go-wire array. +// joins all log messages with \n +func combine(all []basecoin.Result) basecoin.Result { + datas := make([]data.Bytes, len(all)) + logs := make([]string, len(all)) + for i, r := range all { + datas[i] = r.Data + logs[i] = r.Log + } + return basecoin.Result{ + Data: wire.BinaryBytes(datas), + Log: strings.Join(logs, "\n"), + } }