mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-24 18:21:38 +00:00
tx indexing (Refs #237)
save transactions to blockstore move to a separate module benchmark KVIndexer batch write transactions Benchmarks: ``` BenchmarkKVIndexerIndex-2 100000 516300 ns/op PASS ok github.com/tendermint/tendermint/blockchain/tx 56.506s 5,16 s for 10000 transactions 1 s for 2000 transactions ``` ``` BenchmarkKVIndexerIndex-2 h 3000000 8622 ns/op PASS ok github.com/tendermint/tendermint/blockchain/tx 34.210s 86 ms for 10000 transactions 16 ms for 2000 transactions ``` ``` BenchmarkKVIndexerIndex1-2 5000000 7160 ns/op BenchmarkKVIndexerIndex500-2 20000 1750411 ns/op BenchmarkKVIndexerIndex1000-2 10000 3573973 ns/op BenchmarkKVIndexerIndex2000-2 5000 7836851 ns/op BenchmarkKVIndexerIndex10000-2 1000 33438980 ns/op PASS ok github.com/tendermint/tendermint/blockchain/tx 209.482s 7,8 ms for 2000 transactions ``` [state] write test for ApplyBlock review comments - move txindexer to state - fix type save Tx Index as well do not store tx itself in the result
This commit is contained in:
@ -2,26 +2,26 @@ package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ebuchman/fail-test"
|
||||
|
||||
fail "github.com/ebuchman/fail-test"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
. "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/go-crypto"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
txindexer "github.com/tendermint/tendermint/state/tx/indexer"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
//--------------------------------------------------
|
||||
// Execute the block
|
||||
|
||||
// Execute the block to mutate State.
|
||||
// Validates block and then executes Data.Txs in the block.
|
||||
func (s *State) ExecBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus, block *types.Block, blockPartsHeader types.PartSetHeader) error {
|
||||
|
||||
// ExecBlock executes the block to mutate State.
|
||||
// + validates the block
|
||||
// + executes block.Txs on the proxyAppConn
|
||||
// + updates validator sets
|
||||
// + returns block.Txs results
|
||||
func (s *State) ExecBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus, block *types.Block, blockPartsHeader types.PartSetHeader) ([]*types.TxResult, error) {
|
||||
// Validate the block.
|
||||
if err := s.validateBlock(block); err != nil {
|
||||
return ErrInvalidBlock(err)
|
||||
return nil, ErrInvalidBlock(err)
|
||||
}
|
||||
|
||||
// compute bitarray of validators that signed
|
||||
@ -33,11 +33,11 @@ func (s *State) ExecBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnC
|
||||
nextValSet := valSet.Copy()
|
||||
|
||||
// Execute the block txs
|
||||
changedValidators, err := execBlockOnProxyApp(eventCache, proxyAppConn, block)
|
||||
txResults, changedValidators, err := execBlockOnProxyApp(eventCache, proxyAppConn, block)
|
||||
if err != nil {
|
||||
// There was some error in proxyApp
|
||||
// TODO Report error and wait for proxyApp to be available.
|
||||
return ErrProxyAppConn(err)
|
||||
return nil, ErrProxyAppConn(err)
|
||||
}
|
||||
|
||||
// update the validator set
|
||||
@ -54,16 +54,22 @@ func (s *State) ExecBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnC
|
||||
|
||||
fail.Fail() // XXX
|
||||
|
||||
return nil
|
||||
return txResults, nil
|
||||
}
|
||||
|
||||
// Executes block's transactions on proxyAppConn.
|
||||
// Returns a list of updates to the validator set
|
||||
// Returns a list of transaction results and updates to the validator set
|
||||
// TODO: Generate a bitmap or otherwise store tx validity in state.
|
||||
func execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus, block *types.Block) ([]*abci.Validator, error) {
|
||||
|
||||
func execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus, block *types.Block) ([]*types.TxResult, []*abci.Validator, error) {
|
||||
var validTxs, invalidTxs = 0, 0
|
||||
|
||||
txResults := make([]*types.TxResult, len(block.Txs))
|
||||
|
||||
txHashToIndexMap := make(map[string]int)
|
||||
for index, tx := range block.Txs {
|
||||
txHashToIndexMap[string(tx.Hash())] = index
|
||||
}
|
||||
|
||||
// Execute transactions and get hash
|
||||
proxyCb := func(req *abci.Request, res *abci.Response) {
|
||||
switch r := res.Value.(type) {
|
||||
@ -73,21 +79,28 @@ func execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnCo
|
||||
// Blocks may include invalid txs.
|
||||
// reqDeliverTx := req.(abci.RequestDeliverTx)
|
||||
txError := ""
|
||||
apTx := r.DeliverTx
|
||||
if apTx.Code == abci.CodeType_OK {
|
||||
validTxs += 1
|
||||
txResult := r.DeliverTx
|
||||
if txResult.Code == abci.CodeType_OK {
|
||||
validTxs++
|
||||
} else {
|
||||
log.Debug("Invalid tx", "code", r.DeliverTx.Code, "log", r.DeliverTx.Log)
|
||||
invalidTxs += 1
|
||||
txError = apTx.Code.String()
|
||||
log.Debug("Invalid tx", "code", txResult.Code, "log", txResult.Log)
|
||||
invalidTxs++
|
||||
txError = txResult.Code.String()
|
||||
}
|
||||
|
||||
tx := types.Tx(req.GetDeliverTx().Tx)
|
||||
index, ok := txHashToIndexMap[string(tx.Hash())]
|
||||
if ok {
|
||||
txResults[index] = &types.TxResult{uint64(block.Height), uint32(index), *txResult}
|
||||
}
|
||||
|
||||
// NOTE: if we count we can access the tx from the block instead of
|
||||
// pulling it from the req
|
||||
event := types.EventDataTx{
|
||||
Tx: req.GetDeliverTx().Tx,
|
||||
Data: apTx.Data,
|
||||
Code: apTx.Code,
|
||||
Log: apTx.Log,
|
||||
Tx: tx,
|
||||
Data: txResult.Data,
|
||||
Code: txResult.Code,
|
||||
Log: txResult.Log,
|
||||
Error: txError,
|
||||
}
|
||||
types.FireEventTx(eventCache, event)
|
||||
@ -99,7 +112,7 @@ func execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnCo
|
||||
err := proxyAppConn.BeginBlockSync(block.Hash(), types.TM2PB.Header(block.Header))
|
||||
if err != nil {
|
||||
log.Warn("Error in proxyAppConn.BeginBlock", "error", err)
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fail.Fail() // XXX
|
||||
@ -109,7 +122,7 @@ func execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnCo
|
||||
fail.FailRand(len(block.Txs)) // XXX
|
||||
proxyAppConn.DeliverTxAsync(tx)
|
||||
if err := proxyAppConn.Error(); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +132,7 @@ func execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnCo
|
||||
respEndBlock, err := proxyAppConn.EndBlockSync(uint64(block.Height))
|
||||
if err != nil {
|
||||
log.Warn("Error in proxyAppConn.EndBlock", "error", err)
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fail.Fail() // XXX
|
||||
@ -128,7 +141,7 @@ func execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnCo
|
||||
if len(respEndBlock.Diffs) > 0 {
|
||||
log.Info("Update to validator set", "updates", abci.ValidatorsString(respEndBlock.Diffs))
|
||||
}
|
||||
return respEndBlock.Diffs, nil
|
||||
return txResults, respEndBlock.Diffs, nil
|
||||
}
|
||||
|
||||
func updateValidators(validators *types.ValidatorSet, changedValidators []*abci.Validator) error {
|
||||
@ -218,26 +231,31 @@ func (s *State) validateBlock(block *types.Block) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ApplyBlock executes the block, then commits and updates the mempool atomically
|
||||
|
||||
// Execute and commit block against app, save block and state
|
||||
// ApplyBlock executes the block, then commits and updates the mempool
|
||||
// atomically, optionally indexing transaction results.
|
||||
func (s *State) ApplyBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus,
|
||||
block *types.Block, partsHeader types.PartSetHeader, mempool types.Mempool) error {
|
||||
|
||||
// Run the block on the State:
|
||||
// + update validator sets
|
||||
// + run txs on the proxyAppConn
|
||||
err := s.ExecBlock(eventCache, proxyAppConn, block, partsHeader)
|
||||
txResults, err := s.ExecBlock(eventCache, proxyAppConn, block, partsHeader)
|
||||
if err != nil {
|
||||
return errors.New(Fmt("Exec failed for application: %v", err))
|
||||
return fmt.Errorf("Exec failed for application: %v", err)
|
||||
}
|
||||
|
||||
// lock mempool, commit state, update mempoool
|
||||
err = s.CommitStateUpdateMempool(proxyAppConn, block, mempool)
|
||||
if err != nil {
|
||||
return errors.New(Fmt("Commit failed for application: %v", err))
|
||||
return fmt.Errorf("Commit failed for application: %v", err)
|
||||
}
|
||||
|
||||
batch := txindexer.NewBatch()
|
||||
for i, r := range txResults {
|
||||
if r != nil {
|
||||
tx := block.Txs[i]
|
||||
batch.Index(string(tx.Hash()), *r)
|
||||
}
|
||||
}
|
||||
s.TxIndexer.Batch(batch)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -272,7 +290,7 @@ func (s *State) CommitStateUpdateMempool(proxyAppConn proxy.AppConnConsensus, bl
|
||||
// Returns the application root hash (result of abci.Commit)
|
||||
func ApplyBlock(appConnConsensus proxy.AppConnConsensus, block *types.Block) ([]byte, error) {
|
||||
var eventCache types.Fireable // nil
|
||||
_, err := execBlockOnProxyApp(eventCache, appConnConsensus, block)
|
||||
_, _, err := execBlockOnProxyApp(eventCache, appConnConsensus, block)
|
||||
if err != nil {
|
||||
log.Warn("Error executing block on proxy app", "height", block.Height, "err", err)
|
||||
return nil, err
|
||||
|
Reference in New Issue
Block a user