diff --git a/TODO.md b/TODO.md index e9d2f61ea..bff7c68fd 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,6 @@ # TODO for rewrite -* Reimplement MultiTx in base - * FeeTx and CheckTx changes logic to estimate, not validate * Add tests for new CheckTx * Test EndBlock validator set changes +* Test Multiplexer diff --git a/handler.go b/handler.go index c15d479fa..0e4e16c8a 100644 --- a/handler.go +++ b/handler.go @@ -87,10 +87,12 @@ type Dataer interface { // CheckResult captures any non-error abci result // to make sure people use error for error cases type CheckResult struct { - Data data.Bytes - Log string + Data data.Bytes + Log string + // GasAllocated is the maximum units of work we allow this tx to perform GasAllocated uint - GasPrice uint + // GasPayment is the total fees for this tx (or other source of payment) + GasPayment uint } var _ Dataer = CheckResult{} diff --git a/modules/base/multiplexer.go b/modules/base/multiplexer.go index f9eac8207..408812901 100644 --- a/modules/base/multiplexer.go +++ b/modules/base/multiplexer.go @@ -1,73 +1,116 @@ package base -// import ( -// "strings" +import ( + "strings" -// wire "github.com/tendermint/go-wire" -// "github.com/tendermint/go-wire/data" + abci "github.com/tendermint/abci/types" + wire "github.com/tendermint/go-wire" + "github.com/tendermint/go-wire/data" -// "github.com/tendermint/basecoin" -// "github.com/tendermint/basecoin/stack" -// "github.com/tendermint/basecoin/state" -// ) + "github.com/tendermint/basecoin" + "github.com/tendermint/basecoin/stack" + "github.com/tendermint/basecoin/state" +) -// //nolint -// const ( -// NameMultiplexer = "mplx" -// ) +//nolint +const ( + NameMultiplexer = "mplx" +) -// // Multiplexer grabs a MultiTx and sends them sequentially down the line -// type Multiplexer struct { -// stack.PassInitState -// } +// Multiplexer grabs a MultiTx and sends them sequentially down the line +type Multiplexer struct { + stack.PassInitState + stack.PassInitValidate +} -// // Name of the module - fulfills Middleware interface -// func (Multiplexer) Name() string { -// return NameMultiplexer -// } +// Name of the module - fulfills Middleware interface +func (Multiplexer) Name() string { + return NameMultiplexer +} -// var _ stack.Middleware = Multiplexer{} +var _ stack.Middleware = Multiplexer{} -// // CheckTx splits the input tx and checks them all - fulfills Middlware interface -// func (Multiplexer) CheckTx(ctx basecoin.Context, store state.SimpleDB, tx basecoin.Tx, next basecoin.Checker) (res basecoin.CheckResult, err error) { -// if mtx, ok := tx.Unwrap().(*MultiTx); ok { -// return runAll(ctx, store, mtx.Txs, next.CheckTx) -// } -// return next.CheckTx(ctx, store, tx) -// } +// CheckTx splits the input tx and checks them all - fulfills Middlware interface +func (Multiplexer) CheckTx(ctx basecoin.Context, store state.SimpleDB, tx basecoin.Tx, next basecoin.Checker) (res basecoin.CheckResult, err error) { + if mtx, ok := tx.Unwrap().(*MultiTx); ok { + return runAllChecks(ctx, store, mtx.Txs, next) + } + return next.CheckTx(ctx, store, tx) +} -// // DeliverTx splits the input tx and checks them all - fulfills Middlware interface -// func (Multiplexer) DeliverTx(ctx basecoin.Context, store state.SimpleDB, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.DeliverResult, err error) { -// if mtx, ok := tx.Unwrap().(*MultiTx); ok { -// return runAll(ctx, store, mtx.Txs, next.DeliverTx) -// } -// return next.DeliverTx(ctx, store, tx) -// } +// DeliverTx splits the input tx and checks them all - fulfills Middlware interface +func (Multiplexer) DeliverTx(ctx basecoin.Context, store state.SimpleDB, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.DeliverResult, err error) { + if mtx, ok := tx.Unwrap().(*MultiTx); ok { + return runAllDelivers(ctx, store, mtx.Txs, next) + } + return next.DeliverTx(ctx, store, tx) +} -// func runAll(ctx basecoin.Context, store state.SimpleDB, txs []basecoin.Tx, next basecoin.CheckerFunc) (res basecoin.Result, err error) { -// // store all results, unless anything errors -// rs := make([]basecoin.Result, len(txs)) -// for i, stx := range txs { -// rs[i], err = next(ctx, store, stx) -// if err != nil { -// return -// } -// } -// // now combine the results into one... -// return combine(rs), nil -// } +func runAllChecks(ctx basecoin.Context, store state.SimpleDB, txs []basecoin.Tx, next basecoin.Checker) (res basecoin.CheckResult, err error) { + // store all results, unless anything errors + rs := make([]basecoin.CheckResult, len(txs)) + for i, stx := range txs { + rs[i], err = next.CheckTx(ctx, store, stx) + if err != nil { + return + } + } + // now combine the results into one... + return combineChecks(rs), nil +} -// // combines all data bytes as a go-wire array. -// // joins all log messages with \n -// func combine(all []basecoin.Result) basecoin.Result { -// datas := make([]data.Bytes, len(all)) -// logs := make([]string, len(all)) -// for i, r := range all { -// datas[i] = r.Data -// logs[i] = r.Log -// } -// return basecoin.Result{ -// Data: wire.BinaryBytes(datas), -// Log: strings.Join(logs, "\n"), -// } -// } +func runAllDelivers(ctx basecoin.Context, store state.SimpleDB, txs []basecoin.Tx, next basecoin.Deliver) (res basecoin.DeliverResult, err error) { + // store all results, unless anything errors + rs := make([]basecoin.DeliverResult, len(txs)) + for i, stx := range txs { + rs[i], err = next.DeliverTx(ctx, store, stx) + if err != nil { + return + } + } + // now combine the results into one... + return combineDelivers(rs), nil +} + +// combines all data bytes as a go-wire array. +// joins all log messages with \n +func combineChecks(all []basecoin.CheckResult) basecoin.CheckResult { + datas := make([]data.Bytes, len(all)) + logs := make([]string, len(all)) + var allocated, payments uint + for i, r := range all { + datas[i] = r.Data + logs[i] = r.Log + allocated += r.GasAllocated + payments += r.GasPayment + } + return basecoin.CheckResult{ + Data: wire.BinaryBytes(datas), + Log: strings.Join(logs, "\n"), + GasAllocated: allocated, + GasPayment: payments, + } +} + +// combines all data bytes as a go-wire array. +// joins all log messages with \n +func combineDelivers(all []basecoin.DeliverResult) basecoin.DeliverResult { + datas := make([]data.Bytes, len(all)) + logs := make([]string, len(all)) + var used uint + var diffs []*abci.Validator + for i, r := range all { + datas[i] = r.Data + logs[i] = r.Log + used += r.GasUsed + if len(r.Diff) > 0 { + diffs = append(diffs, r.Diff...) + } + } + return basecoin.DeliverResult{ + Data: wire.BinaryBytes(datas), + Log: strings.Join(logs, "\n"), + GasUsed: used, + Diff: diffs, + } +}