diff --git a/x/coin/_attic/bench_test.go b/_attic/coins/bench_test.go similarity index 100% rename from x/coin/_attic/bench_test.go rename to _attic/coins/bench_test.go diff --git a/x/coin/_attic/commands/query.go b/_attic/coins/commands/query.go similarity index 100% rename from x/coin/_attic/commands/query.go rename to _attic/coins/commands/query.go diff --git a/x/coin/_attic/commands/tx.go b/_attic/coins/commands/tx.go similarity index 100% rename from x/coin/_attic/commands/tx.go rename to _attic/coins/commands/tx.go diff --git a/x/coin/_attic/genesis.go b/_attic/coins/genesis.go similarity index 100% rename from x/coin/_attic/genesis.go rename to _attic/coins/genesis.go diff --git a/x/coin/_attic/handler.go b/_attic/coins/handler.go similarity index 100% rename from x/coin/_attic/handler.go rename to _attic/coins/handler.go diff --git a/x/coin/_attic/handler_test.go b/_attic/coins/handler_test.go similarity index 100% rename from x/coin/_attic/handler_test.go rename to _attic/coins/handler_test.go diff --git a/x/coin/_attic/helper.go b/_attic/coins/helper.go similarity index 100% rename from x/coin/_attic/helper.go rename to _attic/coins/helper.go diff --git a/x/coin/_attic/ibc_test.go b/_attic/coins/ibc_test.go similarity index 100% rename from x/coin/_attic/ibc_test.go rename to _attic/coins/ibc_test.go diff --git a/x/coin/_attic/rest/handlers.go b/_attic/coins/rest/handlers.go similarity index 100% rename from x/coin/_attic/rest/handlers.go rename to _attic/coins/rest/handlers.go diff --git a/x/coin/_attic/store.go b/_attic/coins/store.go similarity index 100% rename from x/coin/_attic/store.go rename to _attic/coins/store.go diff --git a/app/app.go b/app/app.go index a082e93f45..4581f95007 100644 --- a/app/app.go +++ b/app/app.go @@ -193,7 +193,7 @@ func (app *App) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) { } // Run the handler. - var result = app.handler(ctx, app.ms, tx) + var result = app.handler(ctx, app.msCheck, tx) // Tell the blockchain engine (i.e. Tendermint). return abci.ResponseCheckTx{ @@ -226,7 +226,7 @@ func (app *App) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) { } // Run the handler. - var result = app.handler(ctx, app.ms, tx) + var result = app.handler(ctx, app.msDeliver, tx) // After-handler hooks. if result.Code == abci.CodeTypeOK { diff --git a/examples/basecoin/main.go b/examples/basecoin/main.go index 879010cc93..a96cf9bafc 100644 --- a/examples/basecoin/main.go +++ b/examples/basecoin/main.go @@ -30,20 +30,40 @@ func main() { // create CommitStoreLoader cacheSize := 10000 numHistory := int64(100) - loader := store.NewIAVLStoreLoader(db, cacheSize, numHistory) + mainLoader := store.NewIAVLStoreLoader(db, cacheSize, numHistory) + ibcLoader := store.NewIAVLStoreLoader(db, cacheSize, numHistory) + + // The key to access the main KVStore. + var mainKey = storeKey("main") + var ibcKey = storeKey("ibc") // Create MultiStore multiStore := store.NewCommitMultiStore(db) - multiStore.SetSubstoreLoader("main", loader) + multiStore.SetSubstoreLoader(mainKey, mainLoader) + multiStore.SetSubstoreLoader(ibcKey, ibcLoader) + + // XXX + var appAccountCodec AccountCodec = nil // Create Handler handler := types.ChainDecorators( - // recover.Decorator(), - // logger.Decorator(), - auth.DecoratorFn(acm.NewAccountStore), - ).WithHandler( - coinstore.TransferHandlerFn(acm.NewAccountStore), - ) + recover.Decorator(), + logger.Decorator(), + auth.Decorator(appAccountCodec), + fees.Decorator(mainKey), + rollbackDecorator(), // XXX define. + ibc.Decorator(ibcKey), // Handle IBC messages. + pos.Decorator(mainKey), // Handle staking messages. + gov.Decorator(mainKey), // Handle governance messages. + coins.Decorator(mainKey), // Handle coinstore messages. + ).WithHandler(func(ctx types.context, tx Tx) Result { + /* + switch tx.(type) { + case CustomTx1: ... + case CustomTx2: ... + } + */ + }) // TODO: load genesis // TODO: InitChain with validators @@ -75,10 +95,25 @@ func main() { return } +//---------------------------------------- +// Misc. + func txParser(txBytes []byte) (types.Tx, error) { var tx coinstore.SendTx err := json.Unmarshal(txBytes, &tx) return tx, err } -//----------------------------------------------------------------------------- +// an unexported (private) key which no module could know of unless +// it was passed in from the app. +type storeKey struct { + writeable bool + name string +} + +func newStoreKey(name string) storeKey { + return storeKey{true, name} +} +func (s storeKey) ReadOnly() storeKey { + return storeKey{false, s.name} +} diff --git a/types/account.go b/types/account.go index 0175abd40e..0addded4a8 100644 --- a/types/account.go +++ b/types/account.go @@ -4,19 +4,12 @@ import ( crypto "github.com/tendermint/go-crypto" ) -// AccountStore indexes accounts by address. -type AccountStore interface { - NewAccountWithAddress(addr crypto.Address) Account - GetAccount(addr crypto.Address) Account - SetAccount(acc Account) -} - // Account is a standard account using a sequence number for replay protection // and a pubkey for authentication. type Account interface { Address() crypto.Address - GetPubKey() crypto.PubKey + GetPubKey() crypto.PubKey // can return nil. SetPubKey(crypto.PubKey) error GetSequence() int64 @@ -25,3 +18,10 @@ type Account interface { Get(key interface{}) (value interface{}, err error) Set(key interface{}, value interface{}) error } + +// AccountStore indexes accounts by address. +type AccountStore interface { + NewAccountWithAddress(addr crypto.Address) Account + GetAccount(addr crypto.Address) Account + SetAccount(acc Account) +} diff --git a/x/coin/coin.go b/types/coin.go similarity index 97% rename from x/coin/coin.go rename to types/coin.go index 99ffc553d5..62cd0b1e91 100644 --- a/x/coin/coin.go +++ b/types/coin.go @@ -1,4 +1,4 @@ -package coin +package types import ( "fmt" @@ -6,8 +6,6 @@ import ( "sort" "strconv" "strings" - - "github.com/pkg/errors" ) // Coin hold some amount of one currency @@ -220,7 +218,7 @@ func ParseCoin(coinStr string) (coin Coin, err error) { matches := reCoin.FindStringSubmatch(coinStr) if matches == nil { - err = errors.Errorf("Invalid coin expression: %s", coinStr) + err = fmt.Errorf("Invalid coin expression: %s", coinStr) return } denomStr, amountStr := matches[2], matches[1] @@ -256,7 +254,7 @@ func ParseCoins(coinsStr string) (coins Coins, err error) { // Validate coins before returning. if !coins.IsValid() { - return nil, errors.Errorf("ParseCoins invalid: %#v", coins) + return nil, fmt.Errorf("ParseCoins invalid: %#v", coins) } return coins, nil diff --git a/x/coin/coin_test.go b/types/coin_test.go similarity index 99% rename from x/coin/coin_test.go rename to types/coin_test.go index 0cb2b4f21b..bf651c50de 100644 --- a/x/coin/coin_test.go +++ b/types/coin_test.go @@ -1,4 +1,4 @@ -package coin +package types import ( "testing" diff --git a/types/context.go b/types/context.go index 037535c285..beaeaadd03 100644 --- a/types/context.go +++ b/types/context.go @@ -34,7 +34,7 @@ func Decorator(ctx Context, ms MultiStore, tx Tx, next Handler) Result { } ``` -While well-written decorators wouldn't mutate any mutable context values, a malicious or buggy plugin can create unwanted side-effects, so it is highly advised for users of Context to only set immutable values. To help enforce this contract, we require values to be certain primitive types, or a Cloner. +While well-written decorators wouldn't mutate any mutable context values, a malicious or buggy plugin can create unwanted side-effects, so it is highly advised for users of Context to only set immutable values. To help enforce this contract, we require values to be certain primitive types, a Cloner, or a CacheWrapper. */ @@ -60,6 +60,7 @@ func NewContext(header abci.Header, isCheckTx bool, txBytes []byte) Context { func (c Context) Value(key interface{}) interface{} { value := c.Context.Value(key) + // XXX Cachewrap? Probably not? if cloner, ok := value.(Cloner); ok { return cloner.Clone() } @@ -69,34 +70,38 @@ func (c Context) Value(key interface{}) interface{} { return value } -func (c Context) WithValue(key interface{}, value Cloner) Context { - return c.withValue(key, value) -} - -func (c Context) WithValueProto(key interface{}, value proto.Message) Context { - return c.withValue(key, value) -} - -func (c Context) WithValueString(key interface{}, value string) Context { - return c.withValue(key, value) -} - -func (c Context) WithValueInt32(key interface{}, value int32) Context { - return c.withValue(key, value) -} - -func (c Context) WithValueUint32(key interface{}, value uint32) Context { - return c.withValue(key, value) -} - -func (c Context) WithValueUint64(key interface{}, value uint64) Context { - return c.withValue(key, value) -} - func (c Context) WithValueUnsafe(key interface{}, value interface{}) Context { return c.withValue(key, value) } +func (c Context) WithCloner(key interface{}, value Cloner) Context { + return c.withValue(key, value) +} + +func (c Context) WithCacheWrapper(key interface{}, value CacheWrapper) Context { + return c.withValue(key, value) +} + +func (c Context) WithProtoMsg(key interface{}, value proto.Message) Context { + return c.withValue(key, value) +} + +func (c Context) WithString(key interface{}, value string) Context { + return c.withValue(key, value) +} + +func (c Context) WithInt32(key interface{}, value int32) Context { + return c.withValue(key, value) +} + +func (c Context) WithUint32(key interface{}, value uint32) Context { + return c.withValue(key, value) +} + +func (c Context) WithUint64(key interface{}, value uint64) Context { + return c.withValue(key, value) +} + func (c Context) withValue(key interface{}, value interface{}) Context { return Context{context.WithValue(c.Context, key, value)} } @@ -134,6 +139,10 @@ func (c Context) TxBytes() []byte { return c.Value(contextKeyTxBytes).([]byte) } +func (c Context) KVStore(key interface{}) KVStore { + return c.Value(key).(KVStore) +} + // Unexposed to prevent overriding. func (c Context) setBlockHeader(header abci.Header) Context { var _ proto.Message = &header // for cloning. diff --git a/types/decorators.go b/types/decorators.go index 06469a61e9..e2bcb806ba 100644 --- a/types/decorators.go +++ b/types/decorators.go @@ -1,12 +1,12 @@ package types // 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, 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 dec(ctx, ms, tx, next) + return func(ctx Context, tx Tx) Result { + return dec(ctx, tx, next) } } diff --git a/types/handler.go b/types/handler.go index bf95d6323a..5825a34e41 100644 --- a/types/handler.go +++ b/types/handler.go @@ -2,4 +2,4 @@ package types // Handler handles both ABCI DeliverTx and CheckTx requests. // Iff ABCI.CheckTx, ctx.IsCheckTx() returns true. -type Handler func(ctx Context, ms MultiStore, tx Tx) Result +type Handler func(ctx Context, tx Tx) Result diff --git a/types/store.go b/types/store.go index adeba6f445..11d75c128f 100644 --- a/types/store.go +++ b/types/store.go @@ -80,6 +80,12 @@ type CommitStoreLoader func(id CommitID) (CommitStore, error) // KVStore is a simple interface to get/set data type KVStore interface { + // TODO Not yet implemented. + // CreateSubKVStore(key *storeKey) (KVStore, error) + + // TODO Not yet implemented. + // GetSubKVStore(key *storeKey) KVStore + // Get returns nil iff key doesn't exist. Panics on nil key. Get(key []byte) []byte diff --git a/types/tx_msg.go b/types/tx_msg.go index b6d35d1377..e9549abe83 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -8,7 +8,7 @@ type Msg interface { Get(key interface{}) (value interface{}) // Get the canonical byte representation of the Msg. - SignBytes() []byte + GetSignBytes() []byte // ValidateBasic does a simple validation check that // doesn't require access to any other information. diff --git a/x/account/store.go b/x/account/store.go deleted file mode 100644 index ec9030afdd..0000000000 --- a/x/account/store.go +++ /dev/null @@ -1,54 +0,0 @@ -package account - -import ( - "encoding/json" - "path" - - "github.com/cosmos/cosmos-sdk/types" - crypto "github.com/tendermint/go-crypto" -) - -type AccountStore struct { - kvStore types.KVStore -} - -func NewAccountStore(kvStore types.KVStore) types.AccountStore { - return AccountStore{kvStore} -} - -func (accStore AccountStore) NewAccountWithAddress(addr crypto.Address) types.Account { - return NewBaseAccountWithAddress(addr) -} - -func (accStore AccountStore) GetAccount(addr crypto.Address) types.Account { - v := accStore.kvStore.Get(keyAccount(addr)) - - if len(v) == 0 { - return nil - } - - acc := new(BaseAccount) - if err := json.Unmarshal(v, acc); err != nil { - panic(err) - } - - return acc -} - -func (accStore AccountStore) SetAccount(acc types.Account) { - b, err := json.Marshal(acc) - if err != nil { - panic(err) - } - - appAcc, ok := acc.(*BaseAccount) - if !ok { - panic("acc is not *BaseAccount") // XXX - } - - accStore.kvStore.Set(keyAccount(appAcc.Address()), b) -} - -func keyAccount(addr crypto.Address) []byte { - return []byte(path.Join("account", string(addr))) -} diff --git a/x/account/account.go b/x/auth/account.go similarity index 99% rename from x/account/account.go rename to x/auth/account.go index e990f5dfb1..cf0c54549d 100644 --- a/x/account/account.go +++ b/x/auth/account.go @@ -1,4 +1,4 @@ -package account +package auth import ( "encoding/json" diff --git a/x/account/account_test.go b/x/auth/account_test.go similarity index 98% rename from x/account/account_test.go rename to x/auth/account_test.go index 96aff7f620..b947bee275 100644 --- a/x/account/account_test.go +++ b/x/auth/account_test.go @@ -1,4 +1,4 @@ -package account +package auth import ( "testing" diff --git a/x/coinstore/tx.go b/x/coinstore/tx.go index 7bead83d6a..399f2fc09f 100644 --- a/x/coinstore/tx.go +++ b/x/coinstore/tx.go @@ -7,7 +7,6 @@ import ( crypto "github.com/tendermint/go-crypto" "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/coin" ) //----------------------------------------------------------------------------- @@ -15,7 +14,7 @@ import ( // TxInput type TxInput struct { Address crypto.Address `json:"address"` - Coins Coins `json:"coins"` + Coins types.Coins `json:"coins"` Sequence int64 `json:"sequence"` signature crypto.Signature @@ -43,7 +42,7 @@ func (txIn TxInput) String() string { } // NewTxInput - create a transaction input, used with SendTx -func NewTxInput(addr crypto.Address, coins Coins) TxInput { +func NewTxInput(addr crypto.Address, coins types.Coins) TxInput { input := TxInput{ Address: addr, Coins: coins, @@ -52,7 +51,7 @@ func NewTxInput(addr crypto.Address, coins Coins) TxInput { } // NewTxInputWithSequence - create a transaction input, used with SendTx -func NewTxInputWithSequence(addr crypto.Address, coins Coins, seq int64) TxInput { +func NewTxInputWithSequence(addr crypto.Address, coins types.Coins, seq int64) TxInput { input := NewTxInput(addr, coins) input.Sequence = seq return input @@ -63,7 +62,7 @@ func NewTxInputWithSequence(addr crypto.Address, coins Coins, seq int64) TxInput // TxOutput - expected coin movement output, used with SendTx type TxOutput struct { Address crypto.Address `json:"address"` - Coins Coins `json:"coins"` + Coins types.Coins `json:"coins"` } // ValidateBasic - validate transaction output @@ -85,7 +84,7 @@ func (txOut TxOutput) String() string { } // NewTxOutput - create a transaction output, used with SendTx -func NewTxOutput(addr crypto.Address, coins Coins) TxOutput { +func NewTxOutput(addr crypto.Address, coins types.Coins) TxOutput { output := TxOutput{ Address: addr, Coins: coins, @@ -95,7 +94,12 @@ func NewTxOutput(addr crypto.Address, coins Coins) TxOutput { //----------------------------------------------------------------------------- -var _ types.Tx = (*SendTx)(nil) +type CoinstoreTx interface { + Tx + AssertIsCoinstoreTx() +} + +var _ CoinstoreTx = (*SendTx)(nil) // SendTx - high level transaction of the coin module type SendTx struct { @@ -103,6 +107,9 @@ type SendTx struct { Outputs []TxOutput `json:"outputs"` } +// Used to switch in the decorator to process all Coinstore txs. +func (tx SendTx) AssertIsCoinstoreTx() {} + // ValidateBasic - validate the send transaction func (tx SendTx) ValidateBasic() error { // this just makes sure all the inputs and outputs are properly formatted, @@ -114,7 +121,7 @@ func (tx SendTx) ValidateBasic() error { return ErrNoOutputs() } // make sure all inputs and outputs are individually valid - var totalIn, totalOut Coins + var totalIn, totalOut types.Coins for _, in := range tx.Inputs { if err := in.ValidateBasic(); err != nil { return err