Skip to content

Commit

Permalink
Merge PR cosmos#1266: Multiple messages
Browse files Browse the repository at this point in the history
* Started work on multiple msgs, types and x/auth tests pass
* Fix issues in x, examples, and baseapp
* Added baseapp tests for multiple msgs
* Documentation fixes
* Fix baseapp tests with sdk.Int
* Modify test
* Transaction handling is now atomic
* Fix test comment
* Minor doc fixes and code cleanup
* Added baseapp result changes
* Use address in validator update accumulation
* Started work on multiple msgs, types and x/auth tests pass
* Fix issues in x, examples, and baseapp
* Added baseapp tests for multiple msgs
* Documentation fixes
* Fix baseapp tests with sdk.Int
* Modify test
* Transaction handling is now atomic
* Fix test comment
* Minor doc fixes and code cleanup
* Added baseapp result changes
* Use address in validator update accumulation
* Added ante tests for multisigner
* Remove validatorUpdates from tx result
* Better error logs
* Put Memo in StdSignBytes and formatting
* Updated changelog
  • Loading branch information
AdityaSripal authored and cwgoes committed Jun 21, 2018
1 parent 3fa6824 commit f049a56
Show file tree
Hide file tree
Showing 35 changed files with 657 additions and 232 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
BREAKING CHANGES
* Change default ports from 466xx to 266xx
* AltBytes renamed to Memo, now a string, max 100 characters, costs a bit of gas
* Transactions now take a list of Messages
* Signers of a transaction now only sign over their account and sequence number

FEATURES
* [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag
Expand Down
84 changes: 52 additions & 32 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,8 @@ type BaseApp struct {
// checkState is set on initialization and reset on Commit.
// deliverState is set in InitChain and BeginBlock and cleared on Commit.
// See methods setCheckState and setDeliverState.
// .valUpdates accumulate in DeliverTx and are reset in BeginBlock.
// QUESTION: should we put valUpdates in the deliverState.ctx?
checkState *state // for CheckTx
deliverState *state // for DeliverTx
valUpdates []abci.Validator // cached validator changes from DeliverTx
signedValidators []abci.SigningValidator // absent validators from begin block
}

Expand Down Expand Up @@ -387,7 +384,6 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
if app.deliverState == nil {
app.setDeliverState(req.Header)
}
app.valUpdates = nil
if app.beginBlocker != nil {
res = app.beginBlocker(app.deliverState.ctx, req)
}
Expand Down Expand Up @@ -432,13 +428,8 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
result = app.runTx(runTxModeDeliver, txBytes, tx)
}

// After-handler hooks.
if result.IsOK() {
app.valUpdates = append(app.valUpdates, result.ValidatorUpdates...)
} else {
// Even though the Result.Code is not OK, there are still effects,
// namely fee deductions and sequence incrementing.
}
// Even though the Result.Code is not OK, there are still effects,
// namely fee deductions and sequence incrementing.

// Tell the blockchain engine (i.e. Tendermint).
return abci.ResponseDeliverTx{
Expand Down Expand Up @@ -484,16 +475,18 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
}()

// Get the Msg.
var msg = tx.GetMsg()
if msg == nil {
return sdk.ErrInternal("Tx.GetMsg() returned nil").Result()
var msgs = tx.GetMsgs()
if msgs == nil || len(msgs) == 0 {
return sdk.ErrInternal("Tx.GetMsgs() must return at least one message in list").Result()
}

// Validate the Msg.
err := msg.ValidateBasic()
if err != nil {
err = err.WithDefaultCodespace(sdk.CodespaceRoot)
return err.Result()
for _, msg := range msgs {
// Validate the Msg
err := msg.ValidateBasic()
if err != nil {
err = err.WithDefaultCodespace(sdk.CodespaceRoot)
return err.Result()
}
}

// Get the context
Expand Down Expand Up @@ -521,13 +514,6 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
}
}

// Match route.
msgType := msg.Type()
handler := app.router.Route(msgType)
if handler == nil {
return sdk.ErrUnknownRequest("Unrecognized Msg type: " + msgType).Result()
}

// Get the correct cache
var msCache sdk.CacheMultiStore
if mode == runTxModeCheck || mode == runTxModeSimulate {
Expand All @@ -540,25 +526,59 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
ctx = ctx.WithMultiStore(msCache)
}

result = handler(ctx, msg)
finalResult := sdk.Result{}
var logs []string
for i, msg := range msgs {
// Match route.
msgType := msg.Type()
handler := app.router.Route(msgType)
if handler == nil {
return sdk.ErrUnknownRequest("Unrecognized Msg type: " + msgType).Result()
}

result = handler(ctx, msg)

// Set gas utilized
finalResult.GasUsed += ctx.GasMeter().GasConsumed()
finalResult.GasWanted += result.GasWanted

// Set gas utilized
result.GasUsed = ctx.GasMeter().GasConsumed()
// Append Data and Tags
finalResult.Data = append(finalResult.Data, result.Data...)
finalResult.Tags = append(finalResult.Tags, result.Tags...)

// Construct usable logs in multi-message transactions. Messages are 1-indexed in logs.
logs = append(logs, fmt.Sprintf("Msg %d: %s", i+1, finalResult.Log))

// Stop execution and return on first failed message.
if !result.IsOK() {
if len(msgs) == 1 {
return result
}
result.GasUsed = finalResult.GasUsed
if i == 0 {
result.Log = fmt.Sprintf("Msg 1 failed: %s", result.Log)
} else {
result.Log = fmt.Sprintf("Msg 1-%d Passed. Msg %d failed: %s", i, i+1, result.Log)
}
return result
}
}

// If not a simulated run and result was successful, write to app.checkState.ms or app.deliverState.ms
// Only update state if all messages pass.
if mode != runTxModeSimulate && result.IsOK() {
msCache.Write()
}

return result
finalResult.Log = strings.Join(logs, "\n")

return finalResult
}

// Implements ABCI
func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBlock) {
if app.endBlocker != nil {
res = app.endBlocker(app.deliverState.ctx, req)
} else {
res.ValidatorUpdates = app.valUpdates
}
return
}
Expand Down
Loading

0 comments on commit f049a56

Please sign in to comment.