Skip to content

Commit

Permalink
WIP: refactor
Browse files Browse the repository at this point in the history
Refactor

* No more decorators, but rather types.AntiHandler
* No more handlers, but rather types.MsgHandler
* Ability to pass "stores" in NewXYZHandler()
* Coins live in types, and Accounts have coins
* Coinstore -> bank
  • Loading branch information
jaekwon committed Jan 13, 2018
1 parent 620bdf4 commit ba2b4f0
Show file tree
Hide file tree
Showing 28 changed files with 696 additions and 715 deletions.
9 changes: 9 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

* global state dumper.
for developer to list accounts, etc.
e.g. what does the world look like?
cmd cli.

* something that can list transactions ...
make all decorators actually use the logger
so you can see all the txs and see what's going on
141 changes: 85 additions & 56 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ type App struct {
// Main (uncached) state
ms types.CommitMultiStore

// Unmarshal []byte into types.Tx
txDecoder types.TxDecoder

// Ante handler for fee and auth.
defaultAnteHandler types.AnteHandler

// Handle any kind of message.
router Router

//--------------------
// Volatile

// CheckTx state, a cache-wrap of `.ms`.
msCheck types.CacheMultiStore

Expand All @@ -35,49 +47,43 @@ type App struct {
// Current block header
header abci.Header

// Unmarshal []byte into types.Tx
txParser TxParser

// Handler for CheckTx and DeliverTx.
handler types.Handler

// Cached validator changes from DeliverTx
// Cached validator changes from DeliverTx.
valUpdates []abci.Validator
}

var _ abci.Application = &App{}

func NewApp(name string) *App {
func NewApp(name string, ms CommitMultiStore) *App {
return &App{
name: name,
logger: makeDefaultLogger(),
name: name,
ms: ms,
router: NewRouter(),
}
}

func (app *App) Name() string {
return app.name
}

func (app *App) SetCommitMultiStore(ms types.CommitMultiStore) {
app.ms = ms
func (app *App) SetTxDecoder(txDecoder types.TxDecoder) {
app.txDecoder = txDecoder
}

/*
SetBeginBlocker
SetEndBlocker
SetInitStater
*/

type TxParser func(txBytes []byte) (types.Tx, error)

func (app *App) SetTxParser(txParser TxParser) {
app.txParser = txParser
func (app *App) SetDefaultAnteHandler(ah types.AnteHandler) {
app.defaultAnteHandler = ah
}

func (app *App) SetHandler(handler types.Handler) {
app.handler = handler
func (app *App) Router() Router {
return app.router
}

/* TODO consider:
func (app *App) SetBeginBlocker(...) {}
func (app *App) SetEndBlocker(...) {}
func (app *App) SetInitStater(...) {}
*/

func (app *App) LoadLatestVersion() error {
app.ms.LoadLatestVersion()
return app.initFromStore()
Expand Down Expand Up @@ -179,23 +185,8 @@ func (app *App) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBl
// Implements ABCI
func (app *App) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) {

// Initialize arguments to Handler.
var isCheckTx = true
var ctx = types.NewContext(app.header, isCheckTx, txBytes)
var tx types.Tx
result := app.runTx(true, txBytes)

var err error
tx, err = app.txParser(txBytes)
if err != nil {
return abci.ResponseCheckTx{
Code: 1, // TODO
}
}

// Run the handler.
var result = app.handler(ctx, app.msCheck, tx)

// Tell the blockchain engine (i.e. Tendermint).
return abci.ResponseCheckTx{
Code: result.Code,
Data: result.Data,
Expand All @@ -207,33 +198,21 @@ func (app *App) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) {
},
Tags: result.Tags,
}

}

// Implements ABCI
func (app *App) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {

// Initialize arguments to Handler.
var isCheckTx = false
var ctx = types.NewContext(app.header, isCheckTx, txBytes)
var tx types.Tx

var err error
tx, err = app.txParser(txBytes)
if err != nil {
return abci.ResponseDeliverTx{
Code: 1, // TODO
}
}

// Run the handler.
var result = app.handler(ctx, app.msDeliver, tx)
result := app.runTx(false, txBytes)

// After-handler hooks.
if result.Code == abci.CodeTypeOK {
app.valUpdates = append(app.valUpdates, result.ValidatorUpdates...)
} else {
// Even though the Code is not OK, there will be some side effects,
// like those caused by fee deductions or sequence incrementations.
// Even though the Code is not OK, there will be some side
// effects, like those caused by fee deductions or sequence
// incrementations.
}

// Tell the blockchain engine (i.e. Tendermint).
Expand All @@ -247,6 +226,56 @@ func (app *App) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
}
}

func (app *App) runTx(isCheckTx bool, txBytes []byte) (result types.Result) {

// Handle any panics.
defer func() {
if r := recover(); r != nil {
result = types.Result{
Code: 1, // TODO
Log: fmt.Sprintf("Recovered: %v\n", r),
}
}
}()

var store types.MultiStore
if isCheckTx {
store = app.msCheck
} else {
store = app.msDeliver
}

// Initialize arguments to Handler.
var ctx = types.NewContext(
store,
app.header,
isCheckTx,
txBytes,
)

// Decode the Tx.
var err error
tx, err = app.txDecoder(txBytes)
if err != nil {
return types.Result{
Code: 1, // TODO
}
}

// Run the ante handler.
ctx, result, abort := app.defaultAnteHandler(ctx, tx)
if isCheckTx || abort {
return result
}

// Match and run route.
msgType := tx.Type()
handler := app.router.Route(msgType)
result = handler(ctx, tx)

return result
}

// Implements ABCI
func (app *App) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBlock) {
res.ValidatorUpdates = app.valUpdates
Expand Down
40 changes: 40 additions & 0 deletions app/router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package app

type Router interface {
AddRoute(r string, h Handler)
Route(path string) (h Handler)
}

type route struct {
r string
h Handler
}

type router struct {
routes []route
}

func NewRouter() router {
return router{
routes: make([]route),
}
}

var isAlpha = regexp.MustCompile(`^[a-zA-Z]+$`).MatchString

func (rtr router) AddRoute(r string, h Handler) {
if !isAlpha(r) {
panic("route expressions can only contain alphanumeric characters")
}
rtr.routes = append(rtr.routes, route{r, h})
}

// TODO handle expressive matches.
func (rtr router) Route(path string) (h Handler) {
for _, route := range rtr.routes {
if route.r == path {
return route.h
}
}
return nil
}
19 changes: 13 additions & 6 deletions errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (
const (
// ABCI Response Codes
// Base SDK reserves 0 ~ 99.
CodeInternalError uint32 = 1
CodeTxParseError = 2
CodeBadNonce = 3
CodeUnauthorized = 4
CodeInsufficientFunds = 5
CodeUnknownRequest = 6
CodeInternalError uint32 = 1
CodeTxParseError = 2
CodeBadNonce = 3
CodeUnauthorized = 4
CodeInsufficientFunds = 5
CodeUnknownRequest = 6
CodeUnrecognizedAddress = 7
)

// NOTE: Don't stringer this, we'll put better messages in later.
Expand All @@ -30,6 +31,8 @@ func CodeToDefaultLog(code uint32) string {
return "Insufficent funds"
case CodeUnknownRequest:
return "Unknown request"
case CodeUnrecognizeAddress:
return "Unrecognized address"
default:
return fmt.Sprintf("Unknown code %d", code)
}
Expand Down Expand Up @@ -63,6 +66,10 @@ func UnknownRequest(log string) *sdkError {
return newSDKError(CodeUnknownRequest, log)
}

func UnrecognizedAddress(log string) *sdkError {
return newSDKError(CodeUnrecognizedAddress, log)
}

//----------------------------------------
// ABCIError & sdkError

Expand Down
Loading

0 comments on commit ba2b4f0

Please sign in to comment.