From 3b09a3033a0551bf46447949eae5e328339952d4 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sun, 28 Jan 2018 15:17:59 -0800 Subject: [PATCH] Review feedback from Adrian --- docs/guide.md | 166 ++++++++++++++++++++++++---------------------- x/bank/handler.go | 1 + 2 files changed, 89 insertions(+), 78 deletions(-) diff --git a/docs/guide.md b/docs/guide.md index 74bfb9265e..6f4cfc1daf 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -47,28 +47,26 @@ type Msg interface { ``` -Messages must specify their type via the `Type()` method. The -type should correspond to the messages handler, so there can be -many messages with the same type. +Messages must specify their type via the `Type()` method. The type should +correspond to the messages handler, so there can be many messages with the same +type. -Messages must also specify how they are to be authenticated. The -`GetSigners()` method return a list of addresses that must sign -the message, while the `GetSignBytes()` method returns the bytes -that must be signed for a signature to be valid. +Messages must also specify how they are to be authenticated. The `GetSigners()` +method return a list of addresses that must sign the message, while the +`GetSignBytes()` method returns the bytes that must be signed for a signature +to be valid. -Addresses in the SDK are arbitrary byte arrays that are -hex-encoded when displayed as a string or rendered in JSON. +Addresses in the SDK are arbitrary byte arrays that are hex-encoded when +displayed as a string or rendered in JSON. -Messages can specify basic self-consistency checks using the -`ValidateBasic()` method to enforce that message contents are -well formed before any actual logic begins. +Messages can specify basic self-consistency checks using the `ValidateBasic()` +method to enforce that message contents are well formed before any actual logic +begins. -Finally, messages can provide generic access to their contents -via `Get(key)`, but this is mostly for convenience and not -type-safe. +Finally, messages can provide generic access to their contents via `Get(key)`, +but this is mostly for convenience and not type-safe. -For instance, the `Basecoin` message types are defined in -`x/bank/tx.go`: +For instance, the `Basecoin` message types are defined in `x/bank/tx.go`: ```golang type SendMsg struct { @@ -100,8 +98,7 @@ func (msg IssueMsg) GetSigners() []crypto.Address { ### Transactions -A transaction is a message with additional information for -authentication: +A transaction is a message with additional information for authentication: ```golang type Tx interface { @@ -127,9 +124,9 @@ type Tx interface { } ``` -The `tx.GetSignatures()` method returns a list of signatures, -which must match the list of addresses returned by -`tx.Msg.GetSigners()`. The signatures come in a standard form: +The `tx.GetSignatures()` method returns a list of signatures, which must match +the list of addresses returned by `tx.Msg.GetSigners()`. The signatures come in +a standard form: ```golang type StdSignature struct { @@ -139,25 +136,22 @@ type StdSignature struct { } ``` -It contains the signature itself, as well as the corresponding -account's sequence number. The sequence number is expected to -increment every time a message is signed by a given account. -This prevents "replay attacks", where the same message could be -executed over and over again. +It contains the signature itself, as well as the corresponding account's +sequence number. The sequence number is expected to increment every time a +message is signed by a given account. This prevents "replay attacks", where +the same message could be executed over and over again. -The `StdSignature` can also optionally include the public key for -verifying the signature. An application can store the public key -for each address it knows about, making it optional to include -the public key in the transaction. In the case of Basecoin, the -public key only needs to be included in the first transaction -send by a given account - after that, the public key is forever +The `StdSignature` can also optionally include the public key for verifying the +signature. An application can store the public key for each address it knows +about, making it optional to include the public key in the transaction. In the +case of Basecoin, the public key only needs to be included in the first +transaction send by a given account - after that, the public key is forever stored by the application and can be left out of transactions. -Transactions can also specify the address responsible for paying -the transaction's fees using the `tx.GetFeePayer()` method. +Transactions can also specify the address responsible for paying the +transaction's fees using the `tx.GetFeePayer()` method. -The standard way to create a transaction from a message is to use -the `StdTx`: +The standard way to create a transaction from a message is to use the `StdTx`: ```golang type StdTx struct { @@ -168,28 +162,27 @@ type StdTx struct { ### Encoding and Decoding Transactions -Messages and transactions are designed to be generic enough for -developers to specify their own encoding schemes. This enables -the SDK to be used as the framwork for constructing already -specified cryptocurrency state machines, for instance Ethereum. +Messages and transactions are designed to be generic enough for developers to +specify their own encoding schemes. This enables the SDK to be used as the +framwork for constructing already specified cryptocurrency state machines, for +instance Ethereum. -When initializing an application, a developer must specify a -`TxDecoder` function which determines how an arbitrary byte array -should be unmarshalled into a `Tx`: +When initializing an application, a developer must specify a `TxDecoder` +function which determines how an arbitrary byte array should be unmarshalled +into a `Tx`: ```golang type TxDecoder func(txBytes []byte) (Tx, error) ``` -In `Basecoin`, we use the Tendermint wire format and the -`go-wire` library for encoding and decoding all message types. -The `go-wire` library has the nice property that it can unmarshal -into interface types, but it requires the relevant types to be -registered ahead of type. Registration happens on a `Codec` -object, so as not to taint the global name space. +In `Basecoin`, we use the Tendermint wire format and the `go-wire` library for +encoding and decoding all message types. The `go-wire` library has the nice +property that it can unmarshal into interface types, but it requires the +relevant types to be registered ahead of type. Registration happens on a +`Codec` object, so as not to taint the global name space. -For instance, in `Basecoin`, we wish to register the `SendMsg` -and `IssueMsg` types: +For instance, in `Basecoin`, we wish to register the `SendMsg` and `IssueMsg` +types: ```golang cdc.RegisterInterface((*sdk.Msg)(nil), nil) @@ -197,11 +190,10 @@ cdc.RegisterConcrete(bank.SendMsg{}, "cosmos-sdk/SendMsg", nil) cdc.RegisterConcrete(bank.IssueMsg{}, "cosmos-sdk/IssueMsg", nil) ``` -Note how each concrete type is given a name - these name -determines the types unique "prefix bytes" during encoding. A -registered type will always use the same prefix-bytes, regardless -of what interface it is satisfying. For more details, see the -[go-wire documentation](). +Note how each concrete type is given a name - these name determine the type's +unique "prefix bytes" during encoding. A registered type will always use the +same prefix-bytes, regardless of what interface it is satisfying. For more +details, see the [go-wire documentation](https://github.com/tendermint/go-wire/blob/develop). ## MultiStore @@ -222,38 +214,56 @@ TODO: ## Context -The SDK uses a `Context` to propogate common information across -functions. The `Context` is modelled off of the Golang -`context.Context` object, which has become ubiquitous in -networking middleware and routing applications as a means to -easily propogate request context through handler functions. +The SDK uses a `Context` to propogate common information across functions. The +`Context` is modeled after the Golang `context.Context` object, which has +become ubiquitous in networking middleware and routing applications as a means +to easily propogate request context through handler functions. -The main information stored in the `Context` includes the -application MultiStore (see below), the last block header, and -the transaction bytes. Effectively, the context contains all data -that may be necessary for processing a transaction. +The main information stored in the `Context` includes the application +MultiStore (see below), the last block header, and the transaction bytes. +Effectively, the context contains all data that may be necessary for processing +a transaction. -Many methods on SDK objects receive a context as the first -argument. +Many methods on SDK objects receive a context as the first argument. ## Handler -Transaction processing in the SDK is defined through `Handler` -functions: +Transaction processing in the SDK is defined through `Handler` functions: ```golang type Handler func(ctx Context, tx Tx) Result ``` -A handler takes a context and a transaction and returns a result. -All information necessary for processing a transaction should be -available in the context. +A handler takes a context and a transaction and returns a result. All +information necessary for processing a transaction should be available in the +context. -While the context holds the entire application store, a -particular handler may only need some subset of the store. Access -to substores is managed using capabilities - when a handler is -initialized, it is passed capability keys that determine which -parts of the store it can access. +While the context holds the entire application state (all referenced from the +root MultiStore), a particular handler only needs a particular kind of access +to a particular store (or two or more). Access to stores is managed using +capabilities keys and mappers. When a handler is initialized, it is passed a +key or mapper that gives it access to the relevant stores. + +```golang +// File: cosmos-sdk/examples/basecoin/app/init_stores.go +app.BaseApp.MountStore(app.capKeyMainStore, sdk.StoreTypeIAVL) +app.accountMapper = auth.NewAccountMapper( + app.capKeyMainStore, // target store + &types.AppAccount{}, // prototype +) + +// File: cosmos-sdk/examples/basecoin/app/init_handlers.go +app.router.AddRoute("bank", bank.NewHandler(app.accountMapper)) + +// File: cosmos-sdk/x/bank/handler.go +// NOTE: Technically, NewHandler only needs a CoinMapper +func NewHandler(am sdk.AccountMapper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + cm := CoinMapper{am} + ... + } +} +``` ## AnteHandler diff --git a/x/bank/handler.go b/x/bank/handler.go index faa69df40a..47d6eb2103 100644 --- a/x/bank/handler.go +++ b/x/bank/handler.go @@ -7,6 +7,7 @@ import ( ) // Handle all "bank" type messages. +// NOTE: Technically, NewHandler only needs a CoinMapper func NewHandler(am sdk.AccountMapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {