Skip to content

Commit

Permalink
Merge PR #1332: benchmarks: Add benchmark for block time to bank module
Browse files Browse the repository at this point in the history
* benchmarks: Add benchmark folder, and single benchmark for block time
* Move benchmark into module
* Fix merge conflict errors
* Fix spelling
* Add instructions to run benchmark
* Update auth_app_test.go
  • Loading branch information
ValarDragon authored and Adrian Brink committed Jul 2, 2018
1 parent b730ba6 commit 05608d4
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 12 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ FEATURES
* Supported proposal types: just binary (pass/fail) TextProposals for now
* Proposals need deposits to be votable; deposits are burned if proposal fails
* Delegators delegate votes to validator by default but can override (for their stake)
* Add benchmarks for signing and delivering a block with a single bank transaction
* Run with `cd x/bank && go test --bench=.`
* [tools] make get_tools installs tendermint's linter, and gometalinter
* [tools] Switch gometalinter to the stable version
* [tools] Add checking for misspellings and for incorrectly formatted files in circle CI
Expand Down
2 changes: 1 addition & 1 deletion baseapp/baseapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package baseapp
import (
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/x/bank"
"os"
"testing"

Expand All @@ -20,6 +19,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
)

func defaultLogger() log.Logger {
Expand Down
71 changes: 63 additions & 8 deletions x/auth/mock/auth_app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,38 @@ package mock
import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/auth"

abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
)

// A mock transaction that has a validation which can fail.
type testMsg struct {
signers []sdk.Address
positiveNum int64
}

// TODO: Clean this up, make it public
const msgType = "testMsg"

func (tx testMsg) Type() string { return msgType }
func (tx testMsg) GetMsg() sdk.Msg { return tx }
func (tx testMsg) GetMemo() string { return "" }
func (tx testMsg) GetSignBytes() []byte { return nil }
func (tx testMsg) GetSigners() []sdk.Address { return tx.signers }
func (tx testMsg) GetSignatures() []auth.StdSignature { return nil }
func (tx testMsg) ValidateBasic() sdk.Error {
if tx.positiveNum >= 0 {
return nil
}
return sdk.ErrTxDecode("positiveNum should be a non-negative integer.")
}

// test auth module messages

var (
Expand All @@ -20,19 +44,50 @@ var (
addr2 = priv2.PubKey().Address()

coins = sdk.Coins{sdk.NewCoin("foocoin", 10)}
sendMsg1 = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
}
testMsg1 = testMsg{signers: []sdk.Address{addr1}, positiveNum: 1}
)

// initialize the mock application for this module
func getMockApp(t *testing.T) *App {
mapp := NewApp()

coinKeeper := bank.NewKeeper(mapp.AccountMapper)
mapp.Router().AddRoute("bank", bank.NewHandler(coinKeeper))

mapp.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return })
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{}))
return mapp
}

func TestMsgPrivKeys(t *testing.T) {
mapp := getMockApp(t)
mapp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil)

// Construct some genesis bytes to reflect basecoin/types/AppAccount
// Give 77 foocoin to the first key
coins := sdk.Coins{sdk.NewCoin("foocoin", 77)}
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: coins,
}
accs := []auth.Account{acc1}

// Construct genesis state
SetGenesis(mapp, accs)

// A checkTx context (true)
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, acc1, res1.(*auth.BaseAccount))

// Run a CheckDeliver
SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{testMsg1}, []int64{0}, []int64{0}, true, priv1)

// signing a SendMsg with the wrong privKey should be an auth error
mapp.BeginBlock(abci.RequestBeginBlock{})
tx := GenTx([]sdk.Msg{testMsg1}, []int64{0}, []int64{1}, priv2)
res := mapp.Deliver(tx)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)

// resigning the tx with the correct priv key should still work
res = SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{testMsg1}, []int64{0}, []int64{1}, true, priv1)

assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), res.Code, res.Log)
}
20 changes: 19 additions & 1 deletion x/auth/mock/simulate_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@ func GenTx(msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyE
return auth.NewStdTx(msgs, fee, sigs, memo)
}

// generate a set of signed transactions a msg, that differ only by having the
// sequence numbers incremented between every transaction.
func GenSequenceOfTxs(msgs []sdk.Msg, accnums []int64, initSeqNums []int64, numToGenerate int, priv ...crypto.PrivKeyEd25519) []auth.StdTx {
txs := make([]auth.StdTx, numToGenerate, numToGenerate)
for i := 0; i < numToGenerate; i++ {
txs[i] = GenTx(msgs, accnums, initSeqNums, priv...)
incrementAllSequenceNumbers(initSeqNums)
}
return txs
}

func incrementAllSequenceNumbers(initSeqNums []int64) {
for i := 0; i < len(initSeqNums); i++ {
initSeqNums[i]++
}
}

// check a transaction result
func SignCheck(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.Result {
tx := GenTx(msgs, accnums, seq, priv...)
Expand All @@ -62,7 +79,7 @@ func SignCheck(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int
}

// simulate a block
func SignCheckDeliver(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
func SignCheckDeliver(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) sdk.Result {

// Sign the tx
tx := GenTx(msgs, accnums, seq, priv...)
Expand All @@ -86,4 +103,5 @@ func SignCheckDeliver(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnum
app.EndBlock(abci.RequestEndBlock{})

app.Commit()
return res
}
12 changes: 10 additions & 2 deletions x/bank/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,22 @@ var (

// initialize the mock application for this module
func getMockApp(t *testing.T) *mock.App {
mapp, err := getBenchmarkMockApp()
require.NoError(t, err)
return mapp
}

// getBenchmarkMockApp initializes a mock application for this module, for purposes of benchmarking
// Any long term API support commitments do not apply to this function.
func getBenchmarkMockApp() (*mock.App, error) {
mapp := mock.NewApp()

RegisterWire(mapp.Cdc)
coinKeeper := NewKeeper(mapp.AccountMapper)
mapp.Router().AddRoute("bank", NewHandler(coinKeeper))

require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{}))
return mapp
err := mapp.CompleteSetup([]*sdk.KVStoreKey{})
return mapp, err
}

func TestMsgSendWithAccounts(t *testing.T) {
Expand Down
41 changes: 41 additions & 0 deletions x/bank/bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package bank

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock"

abci "github.com/tendermint/abci/types"
)

func BenchmarkOneBankSendTxPerBlock(b *testing.B) {
benchmarkApp, _ := getBenchmarkMockApp()

// Add an account at genesis
acc := &auth.BaseAccount{
Address: addr1,
// Some value conceivably higher than the benchmarks would ever go
Coins: sdk.Coins{sdk.NewCoin("foocoin", 100000000000)},
}
accs := []auth.Account{acc}

// Construct genesis state
mock.SetGenesis(benchmarkApp, accs)
// Precompute all txs
txs := mock.GenSequenceOfTxs([]sdk.Msg{sendMsg1}, []int64{0}, []int64{int64(0)}, b.N, priv1)
b.ResetTimer()
// Run this with a profiler, so its easy to distinguish what time comes from
// Committing, and what time comes from Check/Deliver Tx.
for i := 0; i < b.N; i++ {
benchmarkApp.BeginBlock(abci.RequestBeginBlock{})
x := benchmarkApp.Check(txs[i])
if !x.IsOK() {
panic("something is broken in checking transaction")
}
benchmarkApp.Deliver(txs[i])
benchmarkApp.EndBlock(abci.RequestEndBlock{})
benchmarkApp.Commit()
}
}

0 comments on commit 05608d4

Please sign in to comment.