diff --git a/errors/errors.go b/errors/errors.go index d2b9f15b299a..eca3cf6187b6 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -1,15 +1,19 @@ package errors -import "fmt" +import ( + "fmt" + + "github.com/pkg/errors" +) const ( // ABCI Response Codes - CodeInternalError = 1 - CodeTxParseError = 2 - CodeBadNonce = 3 - CodeUnauthorized = 4 - CodeInsufficientFunds = 5 - CodeUnknownRequest = 6 + CodeInternalError uint32 = 1 + CodeTxParseError = 2 + CodeBadNonce = 3 + CodeUnauthorized = 4 + CodeInsufficientFunds = 5 + CodeUnknownRequest = 6 ) // NOTE: Don't stringer this, we'll put better messages in later. @@ -65,6 +69,8 @@ func UnknownRequest(log string) sdkError { type ABCIError interface { ABCICode() uint32 ABCILog() string + + Error() string } /* @@ -132,3 +138,24 @@ func (err sdkError) WithCause(cause error) sdkError { copy.cause = cause return copy } + +// HasErrorCode checks if this error would return the named error code +func HasErrorCode(err error, code uint32) bool { + // XXX Get the cause if not ABCIError + if abciErr, ok := err.(ABCIError); ok { + return abciErr.ABCICode() == code + } + return code == CodeInternalError +} + +func IsSameError(pattern error, err error) bool { + return err != nil && (errors.Cause(err) == errors.Cause(pattern)) +} + +func WithCode(err error, code uint32) sdkError { + return sdkError{ + code: code, + cause: err, + log: "", + } +} diff --git a/exports.go b/exports.go index c2a1ca0cecc8..ea2ab91a01d7 100644 --- a/exports.go +++ b/exports.go @@ -14,5 +14,5 @@ type ( Decorator = types.Decorator // Type aliases for other modules. - MultiStore = store.MultiStore modules. + MultiStore = store.MultiStore ) diff --git a/glide.lock b/glide.lock index ab1cc58af6e9..956fbaa6927b 100644 --- a/glide.lock +++ b/glide.lock @@ -112,7 +112,7 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/abci - version: bb9bb4aa465a31fd6a272765be381888e6898c74 + version: e4b9f1abe794a2117a59738a1294e09b46d0fa00 subpackages: - client - example/dummy diff --git a/types/context.go b/types/context.go index 46bbf4dfd81b..d0730748f3f6 100644 --- a/types/context.go +++ b/types/context.go @@ -2,6 +2,7 @@ package types import ( "context" + abci "github.com/tendermint/abci/types" ) @@ -11,12 +12,12 @@ type Context struct { // it's probably not what you want to do. } -func NewContext(header tm.Header, isCheckTx bool, txBytes []byte) Context { +func NewContext(header abci.Header, isCheckTx bool, txBytes []byte) Context { c := Context{ Context: context.Background(), } c = c.setBlockHeader(header) - c = c.setBlockHeight(int64(header.Height)) + c = c.setBlockHeight(header.Height) c = c.setChainID(header.ChainID) c = c.setIsCheckTx(isCheckTx) c = c.setTxBytes(txBytes) @@ -48,8 +49,8 @@ const ( contextKeyTxBytes ) -func (c Context) BlockHeader() tm.Header { - return c.Value(contextKeyBlockHeader).(tm.Header) +func (c Context) BlockHeader() abci.Header { + return c.Value(contextKeyBlockHeader).(abci.Header) } func (c Context) BlockHeight() int64 { @@ -69,18 +70,18 @@ func (c Context) TxBytes() []byte { } // Unexposed to prevent overriding. -func (c Context) setBlockHeader(header tm.Header) Context { +func (c Context) setBlockHeader(header abci.Header) Context { return c.WithValueSDK(contextKeyBlockHeader, header) } // Unexposed to prevent overriding. func (c Context) setBlockHeight(height int64) Context { - return c.WithValueSDK(contextKeyBlockHeight, header) + return c.WithValueSDK(contextKeyBlockHeight, height) } // Unexposed to prevent overriding. func (c Context) setChainID(chainID string) Context { - return c.WithValueSDK(contextKeyChainID, header) + return c.WithValueSDK(contextKeyChainID, chainID) } // Unexposed to prevent overriding. diff --git a/types/decorators.go b/types/decorators.go index 06469a61e99f..c3b77364807a 100644 --- a/types/decorators.go +++ b/types/decorators.go @@ -1,11 +1,15 @@ package types +import ( + "github.com/cosmos/cosmos-sdk/store" +) + // A Decorator executes before/during/after a handler to enhance functionality. -type Decorator func(ctx Context, ms MultiStore, tx Tx, next Handler) Result +type Decorator func(ctx Context, ms store.MultiStore, tx Tx, next Handler) Result // Return a decorated handler func Decorate(dec Decorator, next Handler) Handler { - return func(ctx Context, ms MultiStore, tx Tx) Result { + return func(ctx Context, ms store.MultiStore, tx Tx) Result { return dec(ctx, ms, tx, next) } } diff --git a/types/decorators_test.go b/types/decorators_test.go new file mode 100644 index 000000000000..9af091ac3b17 --- /dev/null +++ b/types/decorators_test.go @@ -0,0 +1,39 @@ +package types + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/store" + "github.com/stretchr/testify/assert" +) + +func TestDecorate(t *testing.T) { + + var calledDec1, calledDec2, calledHandler bool + dec1 := func(ctx Context, ms store.MultiStore, tx Tx, next Handler) Result { + calledDec1 = true + next(ctx, ms, tx) + return Result{} + } + + dec2 := func(ctx Context, ms store.MultiStore, tx Tx, next Handler) Result { + calledDec2 = true + next(ctx, ms, tx) + return Result{} + } + + handler := func(ctx Context, ms store.MultiStore, tx Tx) Result { + calledHandler = true + return Result{} + } + + decoratedHandler := ChainDecorators(dec1, dec2).WithHandler(handler) + + var ctx Context + var ms store.MultiStore + var tx Tx + decoratedHandler(ctx, ms, tx) + assert.True(t, calledDec1) + assert.True(t, calledDec2) + assert.True(t, calledHandler) +} diff --git a/types/handler.go b/types/handler.go index ff9bcee4f983..58a2e6f0812d 100644 --- a/types/handler.go +++ b/types/handler.go @@ -1,9 +1,9 @@ package types import ( - "github.com/cosmos/cosmos-sdk" + "github.com/cosmos/cosmos-sdk/store" ) // Handler handles both ABCI DeliverTx and CheckTx requests. // Iff ABCI.CheckTx, ctx.IsCheckTx() returns true. -type Handler func(ctx Context, ms MultiStore, tx Tx) +type Handler func(ctx Context, ms store.MultiStore, tx Tx) Result diff --git a/types/signature.go b/types/signature.go index a13dffb19d9f..02c059e58b22 100644 --- a/types/signature.go +++ b/types/signature.go @@ -2,22 +2,7 @@ package types import crypto "github.com/tendermint/go-crypto" -type Signature interface { - CryptoSig() crypto.Signature - Sequence() int -} - -// StdSignature is a simple way to prevent replay attacks. -// There must be better strategies, but this is simplest. type StdSignature struct { crypto.Signature - Sequence int -} - -func (ss StdSignature) CryptoSig() crypto.Signature { - return ss.Signature -} - -func (ss StdSignature) Sequence() int { - return ss.Sequence + Sequence int64 } diff --git a/types/tx_msg.go b/types/tx_msg.go index dce71bff49e7..c704cc41fdaf 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -32,5 +32,5 @@ type Tx interface { // CONTRACT: If the signature is missing (ie the Msg is // invalid), then the corresponding signature is // .Empty(). - Signatures() []Signature + Signatures() []StdSignature } diff --git a/x/auth/context.go b/x/auth/context.go index 26960b5ac2a3..dd585f20513e 100644 --- a/x/auth/context.go +++ b/x/auth/context.go @@ -1,7 +1,7 @@ package auth import ( - sdk "github.com/cosmos/cosmos-sdk" + "github.com/cosmos/cosmos-sdk/types" ) /* @@ -13,7 +13,7 @@ import ( var acc accounts.Account accounts.SetAccount(ctx, acc) - acc2, ok := accounts.GetAccount(ctx) + acc2 := accounts.GetAccount(ctx) */ @@ -24,10 +24,10 @@ const ( contextKeyAccount contextKey = iota ) -func SetAccount(ctx sdk.Context, account Account) sdk.Context { - return ctx.WithValue(contextKeyAccount, account) +func SetAccount(ctx types.Context, account Account) types.Context { + return ctx.WithValueSDK(contextKeyAccount, account) } -func GetAccount(ctx sdk.Context) (Account, bool) { +func GetAccount(ctx types.Context) Account { return ctx.Value(contextKeyAccount).(Account) } diff --git a/x/auth/decorator.go b/x/auth/decorator.go deleted file mode 100644 index f7b1eec1eb4c..000000000000 --- a/x/auth/decorator.go +++ /dev/null @@ -1,35 +0,0 @@ -package auth - -import ( - sdk "github.com/cosmos/cosmos-sdk" -) - -type CheckSignatures struct{} - -var _ sdk.Decorator = CheckSignatures{} - -// CheckTx verifies the signatures are correct - fulfills Middlware interface -func (Signatures) CheckTx(ctx sdk.Context, store sdk.SimpleDB, - tx interface{}, next sdk.Checker) (res sdk.CheckResult, err error) { - - // Check that signatures match - // TODO - - // Add info to context - // TODO - - return next.CheckTx(ctx2, store, tx) -} - -// DeliverTx verifies the signatures are correct - fulfills Middlware interface -func (Signatures) DeliverTx(ctx sdk.Context, store sdk.SimpleDB, - tx interface{}, next sdk.Deliverer) (res sdk.DeliverResult, err error) { - - // Check that signatures match - // TODO - - // Add info to context - // TODO - - return next.DeliverTx(ctx2, store, tx) -} diff --git a/x/coin/bench_test.go b/x/coin/_attic/bench_test.go similarity index 100% rename from x/coin/bench_test.go rename to x/coin/_attic/bench_test.go diff --git a/x/coin/handler.go b/x/coin/_attic/handler.go similarity index 82% rename from x/coin/handler.go rename to x/coin/_attic/handler.go index da98d97dc141..a51cb4320a29 100644 --- a/x/coin/handler.go +++ b/x/coin/_attic/handler.go @@ -6,10 +6,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk" "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/modules/ibc" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" + "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + // "github.com/cosmos/cosmos-sdk/x/ibc" + // "github.com/cosmos/cosmos-sdk/stack" ) const ( @@ -23,10 +24,10 @@ const ( // Handler includes an accountant type Handler struct { - stack.PassInitValidate + // stack.PassInitValidate } -var _ stack.Dispatchable = Handler{} +// var _ stack.Dispatchable = Handler{} // NewHandler - new accountant handler for the coin module func NewHandler() Handler { @@ -42,8 +43,8 @@ func (Handler) Name() string { func (Handler) AssertDispatcher() {} // CheckTx checks if there is enough money in the account -func (h Handler) CheckTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, _ sdk.Checker) (res sdk.CheckResult, err error) { +func (h Handler) CheckTx(ctx types.Context, store store.MultiStore, + tx types.Tx, _ sdk.Checker) (res sdk.CheckResult, err error) { err = tx.ValidateBasic() if err != nil { @@ -63,8 +64,8 @@ func (h Handler) CheckTx(ctx sdk.Context, store state.SimpleDB, } // DeliverTx moves the money -func (h Handler) DeliverTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, cb sdk.Deliver) (res sdk.DeliverResult, err error) { +func (h Handler) DeliverTx(ctx types.Context, store store.MultiStore, + tx types.Tx, cb sdk.Deliver) (res sdk.DeliverResult, err error) { err = tx.ValidateBasic() if err != nil { @@ -81,7 +82,7 @@ func (h Handler) DeliverTx(ctx sdk.Context, store state.SimpleDB, } // InitState - sets the genesis account balance -func (h Handler) InitState(l log.Logger, store state.SimpleDB, +func (h Handler) InitState(l log.Logger, store store.MultiStore, module, key, value string, cb sdk.InitStater) (log string, err error) { if module != NameCoin { return "", errors.ErrUnknownModule(module) @@ -95,7 +96,7 @@ func (h Handler) InitState(l log.Logger, store state.SimpleDB, return "", errors.ErrUnknownKey(key) } -func (h Handler) sendTx(ctx sdk.Context, store state.SimpleDB, +func (h Handler) sendTx(ctx types.Context, store store.MultiStore, send SendTx, cb sdk.Deliver) error { err := checkTx(ctx, send) @@ -136,6 +137,8 @@ func (h Handler) sendTx(ctx sdk.Context, store state.SimpleDB, } outTx := NewSendTx(inputs, []TxOutput{out}) + _ = outTx + /* TODO packet := ibc.CreatePacketTx{ DestChain: out.Address.ChainID, Permissions: senders, @@ -146,6 +149,7 @@ func (h Handler) sendTx(ctx sdk.Context, store state.SimpleDB, if err != nil { return err } + */ } } @@ -153,7 +157,7 @@ func (h Handler) sendTx(ctx sdk.Context, store state.SimpleDB, return nil } -func (h Handler) creditTx(ctx sdk.Context, store state.SimpleDB, +func (h Handler) creditTx(ctx types.Context, store store.MultiStore, credit CreditTx) error { // first check permissions!! @@ -186,7 +190,7 @@ func (h Handler) creditTx(ctx sdk.Context, store state.SimpleDB, return err } -func checkTx(ctx sdk.Context, send SendTx) error { +func checkTx(ctx types.Context, send SendTx) error { // check if all inputs have permission for _, in := range send.Inputs { if !ctx.HasPermission(in.Address) { @@ -196,7 +200,7 @@ func checkTx(ctx sdk.Context, send SendTx) error { return nil } -func (Handler) checkSendTx(ctx sdk.Context, store state.SimpleDB, send SendTx) error { +func (Handler) checkSendTx(ctx types.Context, store store.MultiStore, send SendTx) error { err := checkTx(ctx, send) if err != nil { return err @@ -211,7 +215,7 @@ func (Handler) checkSendTx(ctx sdk.Context, store state.SimpleDB, send SendTx) e return nil } -func setAccount(store state.SimpleDB, value string) (log string, err error) { +func setAccount(store store.MultiStore, value string) (log string, err error) { var acc GenesisAccount err = data.FromJSON([]byte(value), &acc) if err != nil { @@ -233,7 +237,7 @@ func setAccount(store state.SimpleDB, value string) (log string, err error) { // setIssuer sets a permission for some super-powerful account to // mint money -func setIssuer(store state.SimpleDB, value string) (log string, err error) { +func setIssuer(store store.MultiStore, value string) (log string, err error) { var issuer sdk.Actor err = data.FromJSON([]byte(value), &issuer) if err != nil { diff --git a/x/coin/handler_test.go b/x/coin/_attic/handler_test.go similarity index 99% rename from x/coin/handler_test.go rename to x/coin/_attic/handler_test.go index 20941a860402..c8a8eb0937f1 100644 --- a/x/coin/handler_test.go +++ b/x/coin/_attic/handler_test.go @@ -12,7 +12,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk" "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/modules/auth" + "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/stack" "github.com/cosmos/cosmos-sdk/state" ) diff --git a/x/coin/helper.go b/x/coin/_attic/helper.go similarity index 96% rename from x/coin/helper.go rename to x/coin/_attic/helper.go index a885c78b05c7..10ec3aad42c2 100644 --- a/x/coin/helper.go +++ b/x/coin/_attic/helper.go @@ -5,7 +5,7 @@ import ( "github.com/tendermint/go-wire/data" sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/modules/auth" + "github.com/cosmos/cosmos-sdk/x/auth" ) // AccountWithKey is a helper for tests, that includes and account diff --git a/x/coin/ibc_test.go b/x/coin/_attic/ibc_test.go similarity index 98% rename from x/coin/ibc_test.go rename to x/coin/_attic/ibc_test.go index a51b5359d893..4b2af16cf625 100644 --- a/x/coin/ibc_test.go +++ b/x/coin/_attic/ibc_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk" "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/modules/ibc" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/ibc" "github.com/cosmos/cosmos-sdk/stack" "github.com/cosmos/cosmos-sdk/state" wire "github.com/tendermint/go-wire" diff --git a/x/coin/_attic/store.go b/x/coin/_attic/store.go new file mode 100644 index 000000000000..fd7c8ea06903 --- /dev/null +++ b/x/coin/_attic/store.go @@ -0,0 +1,145 @@ +package coin + +import ( + "fmt" + + wire "github.com/tendermint/go-wire" + + sdk "github.com/cosmos/cosmos-sdk" + "github.com/cosmos/cosmos-sdk/errors" + "github.com/cosmos/cosmos-sdk/store" +) + +// GetAccount - Get account from store and address +func GetAccount(store store.MultiStore, addr sdk.Actor) (Account, error) { + // if the actor is another chain, we use one address for the chain.... + addr = ChainAddr(addr) + acct, err := loadAccount(store, addr.Bytes()) + + // for empty accounts, don't return an error, but rather an empty account + if IsNoAccountErr(err) { + err = nil + } + return acct, err +} + +// CheckCoins makes sure there are funds, but doesn't change anything +func CheckCoins(store store.MultiStore, addr sdk.Actor, coins Coins) (Coins, error) { + // if the actor is another chain, we use one address for the chain.... + addr = ChainAddr(addr) + + acct, err := updateCoins(store, addr, coins) + return acct.Coins, err +} + +// ChangeCoins changes the money, returns error if it would be negative +func ChangeCoins(store store.MultiStore, addr sdk.Actor, coins Coins) (Coins, error) { + // if the actor is another chain, we use one address for the chain.... + addr = ChainAddr(addr) + + acct, err := updateCoins(store, addr, coins) + if err != nil { + return acct.Coins, err + } + + err = storeAccount(store, addr.Bytes(), acct) + return acct.Coins, err +} + +// ChainAddr collapses all addresses from another chain into one, so we can +// keep an over-all balance +// +// TODO: is there a better way to do this? +func ChainAddr(addr sdk.Actor) sdk.Actor { + if addr.ChainID == "" { + return addr + } + addr.App = "" + addr.Address = nil + return addr +} + +// updateCoins will load the account, make all checks, and return the updated account. +// +// it doesn't save anything, that is up to you to decide (Check/Change Coins) +func updateCoins(store store.MultiStore, addr sdk.Actor, coins Coins) (acct Account, err error) { + acct, err = loadAccount(store, addr.Bytes()) + // we can increase an empty account... + if IsNoAccountErr(err) && coins.IsPositive() { + err = nil + } + if err != nil { + return acct, err + } + + // check amount + final := acct.Coins.Plus(coins) + if !final.IsNonnegative() { + return acct, ErrInsufficientFunds() + } + + acct.Coins = final + return acct, nil +} + +// Account - coin account structure +type Account struct { + // Coins is how much is on the account + Coins Coins `json:"coins"` + // Credit is how much has been "fronted" to the account + // (this is usually 0 except for trusted chains) + Credit Coins `json:"credit"` +} + +func loadAccount(store store.MultiStore, key []byte) (acct Account, err error) { + // fmt.Printf("load: %X\n", key) + data := store.Get(key) + if len(data) == 0 { + return acct, ErrNoAccount() + } + err = wire.ReadBinaryBytes(data, &acct) + if err != nil { + msg := fmt.Sprintf("Error reading account %X", key) + return acct, errors.ErrInternal(msg) + } + return acct, nil +} + +func storeAccount(store store.MultiStore, key []byte, acct Account) error { + // fmt.Printf("store: %X\n", key) + bin := wire.BinaryBytes(acct) + store.Set(key, bin) + return nil // real stores can return error... +} + +// HandlerInfo - this is global info on the coin handler +type HandlerInfo struct { + Issuer sdk.Actor `json:"issuer"` +} + +// TODO: where to store these special pieces?? +var handlerKey = []byte{12, 34} + +func loadHandlerInfo(store store.KVStore) (info HandlerInfo, err error) { + data := store.Get(handlerKey) + if len(data) == 0 { + return info, nil + } + err = wire.ReadBinaryBytes(data, &info) + if err != nil { + msg := "Error reading handler info" + return info, errors.ErrInternal(msg) + } + return info, nil +} + +func storeIssuer(store store.KVStore, issuer sdk.Actor) error { + info, err := loadHandlerInfo(store) + if err != nil { + return err + } + info.Issuer = issuer + d := wire.BinaryBytes(info) + store.Set(handlerKey, d) + return nil // real stores can return error... +} diff --git a/x/coin/commands/query.go b/x/coin/commands/query.go index 1b13bdd2ac06..25c8b55705bf 100644 --- a/x/coin/commands/query.go +++ b/x/coin/commands/query.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/commands" "github.com/cosmos/cosmos-sdk/client/commands/query" - "github.com/cosmos/cosmos-sdk/modules/coin" + "github.com/cosmos/cosmos-sdk/x/coin" "github.com/cosmos/cosmos-sdk/stack" ) diff --git a/x/coin/commands/tx.go b/x/coin/commands/tx.go index 6459f602e41a..452bf89eba25 100644 --- a/x/coin/commands/tx.go +++ b/x/coin/commands/tx.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk" "github.com/cosmos/cosmos-sdk/client/commands" txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - "github.com/cosmos/cosmos-sdk/modules/coin" + "github.com/cosmos/cosmos-sdk/x/coin" ) // SendTxCmd is CLI command to send tokens between basecoin accounts diff --git a/x/coin/errors.go b/x/coin/errors.go index caf7d4c9b975..e53f2625690a 100644 --- a/x/coin/errors.go +++ b/x/coin/errors.go @@ -4,8 +4,6 @@ package coin import ( "fmt" - abci "github.com/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/errors" ) @@ -17,73 +15,39 @@ var ( errNoOutputs = fmt.Errorf("No output coins") errInvalidAddress = fmt.Errorf("Invalid address") errInvalidCoins = fmt.Errorf("Invalid coins") - - invalidInput = abci.CodeType_BaseInvalidInput - invalidOutput = abci.CodeType_BaseInvalidOutput - unknownAddress = abci.CodeType_BaseUnknownAddress - unknownRequest = abci.CodeType_UnknownRequest ) -// here are some generic handlers to grab classes of errors based on code -func IsInputErr(err error) bool { - return errors.HasErrorCode(err, invalidInput) -} -func IsOutputErr(err error) bool { - return errors.HasErrorCode(err, invalidOutput) -} -func IsAddressErr(err error) bool { - return errors.HasErrorCode(err, unknownAddress) -} -func IsCoinErr(err error) bool { - return err != nil && (IsInputErr(err) || IsOutputErr(err) || IsAddressErr(err)) -} - -func ErrNoAccount() errors.TMError { - return errors.WithCode(errNoAccount, unknownAddress) -} +const ( + CodeInvalidInput uint32 = 101 + CodeInvalidOutput uint32 = 102 + CodeUnknownAddress uint32 = 103 + CodeUnknownRequest uint32 = errors.CodeUnknownRequest +) -func IsNoAccountErr(err error) bool { - return errors.IsSameError(errNoAccount, err) +func ErrNoAccount() errors.ABCIError { + return errors.WithCode(errNoAccount, CodeUnknownAddress) } -func ErrInvalidAddress() errors.TMError { - return errors.WithCode(errInvalidAddress, invalidInput) -} -func IsInvalidAddressErr(err error) bool { - return errors.IsSameError(errInvalidAddress, err) +func ErrInvalidAddress() errors.ABCIError { + return errors.WithCode(errInvalidAddress, CodeInvalidInput) } -func ErrInvalidCoins() errors.TMError { - return errors.WithCode(errInvalidCoins, invalidInput) -} -func IsInvalidCoinsErr(err error) bool { - return errors.IsSameError(errInvalidCoins, err) +func ErrInvalidCoins() errors.ABCIError { + return errors.WithCode(errInvalidCoins, CodeInvalidInput) } -func ErrInsufficientFunds() errors.TMError { - return errors.WithCode(errInsufficientFunds, invalidInput) -} -func IsInsufficientFundsErr(err error) bool { - return errors.IsSameError(errInsufficientFunds, err) +func ErrInsufficientFunds() errors.ABCIError { + return errors.WithCode(errInsufficientFunds, CodeInvalidInput) } -func ErrInsufficientCredit() errors.TMError { - return errors.WithCode(errInsufficientCredit, invalidInput) -} -func IsInsufficientCreditErr(err error) bool { - return errors.IsSameError(errInsufficientCredit, err) +func ErrInsufficientCredit() errors.ABCIError { + return errors.WithCode(errInsufficientCredit, CodeInvalidInput) } -func ErrNoInputs() errors.TMError { - return errors.WithCode(errNoInputs, invalidInput) -} -func IsNoInputsErr(err error) bool { - return errors.IsSameError(errNoInputs, err) +func ErrNoInputs() errors.ABCIError { + return errors.WithCode(errNoInputs, CodeInvalidInput) } -func ErrNoOutputs() errors.TMError { - return errors.WithCode(errNoOutputs, invalidOutput) -} -func IsNoOutputsErr(err error) bool { - return errors.IsSameError(errNoOutputs, err) +func ErrNoOutputs() errors.ABCIError { + return errors.WithCode(errNoOutputs, CodeInvalidOutput) } diff --git a/x/coin/rest/handlers.go b/x/coin/rest/handlers.go index a7362c706dcc..f6a9f18b3248 100644 --- a/x/coin/rest/handlers.go +++ b/x/coin/rest/handlers.go @@ -13,11 +13,11 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/commands" "github.com/cosmos/cosmos-sdk/client/commands/query" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/modules/base" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/modules/fee" - "github.com/cosmos/cosmos-sdk/modules/nonce" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/base" + "github.com/cosmos/cosmos-sdk/x/coin" + "github.com/cosmos/cosmos-sdk/x/fee" + "github.com/cosmos/cosmos-sdk/x/nonce" "github.com/cosmos/cosmos-sdk/stack" "github.com/tendermint/tmlibs/common" ) diff --git a/x/coin/store.go b/x/coin/store.go index 7b0edbaad2fa..8a8dc9e448d2 100644 --- a/x/coin/store.go +++ b/x/coin/store.go @@ -1,85 +1,13 @@ package coin -import ( - "fmt" +import "github.com/tendermint/go-wire/data" - wire "github.com/tendermint/go-wire" +// TEMP - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/state" -) - -// GetAccount - Get account from store and address -func GetAccount(store state.SimpleDB, addr sdk.Actor) (Account, error) { - // if the actor is another chain, we use one address for the chain.... - addr = ChainAddr(addr) - acct, err := loadAccount(store, addr.Bytes()) - - // for empty accounts, don't return an error, but rather an empty account - if IsNoAccountErr(err) { - err = nil - } - return acct, err -} - -// CheckCoins makes sure there are funds, but doesn't change anything -func CheckCoins(store state.SimpleDB, addr sdk.Actor, coins Coins) (Coins, error) { - // if the actor is another chain, we use one address for the chain.... - addr = ChainAddr(addr) - - acct, err := updateCoins(store, addr, coins) - return acct.Coins, err -} - -// ChangeCoins changes the money, returns error if it would be negative -func ChangeCoins(store state.SimpleDB, addr sdk.Actor, coins Coins) (Coins, error) { - // if the actor is another chain, we use one address for the chain.... - addr = ChainAddr(addr) - - acct, err := updateCoins(store, addr, coins) - if err != nil { - return acct.Coins, err - } - - err = storeAccount(store, addr.Bytes(), acct) - return acct.Coins, err -} - -// ChainAddr collapses all addresses from another chain into one, so we can -// keep an over-all balance -// -// TODO: is there a better way to do this? -func ChainAddr(addr sdk.Actor) sdk.Actor { - if addr.ChainID == "" { - return addr - } - addr.App = "" - addr.Address = nil - return addr -} - -// updateCoins will load the account, make all checks, and return the updated account. -// -// it doesn't save anything, that is up to you to decide (Check/Change Coins) -func updateCoins(store state.SimpleDB, addr sdk.Actor, coins Coins) (acct Account, err error) { - acct, err = loadAccount(store, addr.Bytes()) - // we can increase an empty account... - if IsNoAccountErr(err) && coins.IsPositive() { - err = nil - } - if err != nil { - return acct, err - } - - // check amount - final := acct.Coins.Plus(coins) - if !final.IsNonnegative() { - return acct, ErrInsufficientFunds() - } - - acct.Coins = final - return acct, nil +type Actor struct { + ChainID string + App string + Address data.Bytes } // Account - coin account structure @@ -90,56 +18,3 @@ type Account struct { // (this is usually 0 except for trusted chains) Credit Coins `json:"credit"` } - -func loadAccount(store state.SimpleDB, key []byte) (acct Account, err error) { - // fmt.Printf("load: %X\n", key) - data := store.Get(key) - if len(data) == 0 { - return acct, ErrNoAccount() - } - err = wire.ReadBinaryBytes(data, &acct) - if err != nil { - msg := fmt.Sprintf("Error reading account %X", key) - return acct, errors.ErrInternal(msg) - } - return acct, nil -} - -func storeAccount(store state.SimpleDB, key []byte, acct Account) error { - // fmt.Printf("store: %X\n", key) - bin := wire.BinaryBytes(acct) - store.Set(key, bin) - return nil // real stores can return error... -} - -// HandlerInfo - this is global info on the coin handler -type HandlerInfo struct { - Issuer sdk.Actor `json:"issuer"` -} - -// TODO: where to store these special pieces?? -var handlerKey = []byte{12, 34} - -func loadHandlerInfo(store state.KVStore) (info HandlerInfo, err error) { - data := store.Get(handlerKey) - if len(data) == 0 { - return info, nil - } - err = wire.ReadBinaryBytes(data, &info) - if err != nil { - msg := "Error reading handler info" - return info, errors.ErrInternal(msg) - } - return info, nil -} - -func storeIssuer(store state.KVStore, issuer sdk.Actor) error { - info, err := loadHandlerInfo(store) - if err != nil { - return err - } - info.Issuer = issuer - d := wire.BinaryBytes(info) - store.Set(handlerKey, d) - return nil // real stores can return error... -} diff --git a/x/coin/tx.go b/x/coin/tx.go index 09a25abeefe8..73c10f687bbf 100644 --- a/x/coin/tx.go +++ b/x/coin/tx.go @@ -2,18 +2,18 @@ package coin import ( "fmt" - - sdk "github.com/cosmos/cosmos-sdk" ) -func init() { +/*func init() { sdk.TxMapper. RegisterImplementation(SendTx{}, TypeSend, ByteSend). RegisterImplementation(CreditTx{}, TypeCredit, ByteCredit) -} +}*/ // we reserve the 0x20-0x3f range for standard modules const ( + NameCoin = "coin" + ByteSend = 0x20 TypeSend = NameCoin + "/send" ByteCredit = 0x21 @@ -24,8 +24,8 @@ const ( // TxInput - expected coin movement outputs, used with SendTx type TxInput struct { - Address sdk.Actor `json:"address"` - Coins Coins `json:"coins"` + Address Actor `json:"address"` + Coins Coins `json:"coins"` } // ValidateBasic - validate transaction input @@ -51,7 +51,7 @@ func (txIn TxInput) String() string { } // NewTxInput - create a transaction input, used with SendTx -func NewTxInput(addr sdk.Actor, coins Coins) TxInput { +func NewTxInput(addr Actor, coins Coins) TxInput { input := TxInput{ Address: addr, Coins: coins, @@ -63,8 +63,8 @@ func NewTxInput(addr sdk.Actor, coins Coins) TxInput { // TxOutput - expected coin movement output, used with SendTx type TxOutput struct { - Address sdk.Actor `json:"address"` - Coins Coins `json:"coins"` + Address Actor `json:"address"` + Coins Coins `json:"coins"` } // ValidateBasic - validate transaction output @@ -90,7 +90,7 @@ func (txOut TxOutput) String() string { } // NewTxOutput - create a transaction output, used with SendTx -func NewTxOutput(addr sdk.Actor, coins Coins) TxOutput { +func NewTxOutput(addr Actor, coins Coins) TxOutput { output := TxOutput{ Address: addr, Coins: coins, @@ -107,19 +107,19 @@ type SendTx struct { Outputs []TxOutput `json:"outputs"` } -var _ sdk.Tx = NewSendTx(nil, nil) +// var _ types.Tx = NewSendTx(nil, nil) // NewSendTx - construct arbitrary multi-in, multi-out sendtx -func NewSendTx(in []TxInput, out []TxOutput) sdk.Tx { - return SendTx{Inputs: in, Outputs: out}.Wrap() +func NewSendTx(in []TxInput, out []TxOutput) SendTx { // types.Tx { + return SendTx{Inputs: in, Outputs: out} } // NewSendOneTx is a helper for the standard (?) case where there is exactly // one sender and one recipient -func NewSendOneTx(sender, recipient sdk.Actor, amount Coins) sdk.Tx { +func NewSendOneTx(sender, recipient Actor, amount Coins) SendTx { in := []TxInput{{Address: sender, Coins: amount}} out := []TxOutput{{Address: recipient, Coins: amount}} - return SendTx{Inputs: in, Outputs: out}.Wrap() + return SendTx{Inputs: in, Outputs: out} } // ValidateBasic - validate the send transaction @@ -157,17 +157,12 @@ func (tx SendTx) String() string { return fmt.Sprintf("SendTx{%v->%v}", tx.Inputs, tx.Outputs) } -// Wrap - used to satisfy TxInner -func (tx SendTx) Wrap() sdk.Tx { - return sdk.Tx{tx} -} - //----------------------------------------------------------------------------- // CreditTx - this allows a special issuer to give an account credit // Satisfies: TxInner type CreditTx struct { - Debitor sdk.Actor `json:"debitor"` + Debitor Actor `json:"debitor"` // Credit is the amount to change the credit... // This may be negative to remove some over-issued credit, // but can never bring the credit or the balance to negative @@ -175,13 +170,8 @@ type CreditTx struct { } // NewCreditTx - modify the credit granted to a given account -func NewCreditTx(debitor sdk.Actor, credit Coins) sdk.Tx { - return CreditTx{Debitor: debitor, Credit: credit}.Wrap() -} - -// Wrap - used to satisfy TxInner -func (tx CreditTx) Wrap() sdk.Tx { - return sdk.Tx{tx} +func NewCreditTx(debitor Actor, credit Coins) CreditTx { + return CreditTx{Debitor: debitor, Credit: credit} } // ValidateBasic - used to satisfy TxInner