Browse Source

Merge pull request #967 from tendermint/feature/total-tx

Add TotalTx to block header
pull/975/head
Anton Kaliaev 7 years ago
committed by GitHub
parent
commit
b78606d94f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 132 additions and 24 deletions
  1. +3
    -1
      blockchain/reactor_test.go
  2. +2
    -1
      consensus/mempool_test.go
  3. +3
    -2
      consensus/state.go
  4. +5
    -4
      lite/helpers.go
  5. +2
    -1
      state/execution.go
  6. +4
    -2
      state/execution_test.go
  7. +11
    -6
      state/state.go
  8. +22
    -7
      types/block.go
  9. +80
    -0
      types/block_test.go

+ 3
- 1
blockchain/reactor_test.go View File

@ -106,7 +106,9 @@ func makeBlock(height int64, state *sm.State) *types.Block {
valHash := state.Validators.Hash()
prevBlockID := types.BlockID{prevHash, prevParts}
block, _ := types.MakeBlock(height, "test_chain", makeTxs(height),
new(types.Commit), prevBlockID, valHash, state.AppHash, state.Params.BlockGossipParams.BlockPartSizeBytes)
state.LastBlockTotalTx, new(types.Commit),
prevBlockID, valHash, state.AppHash,
state.Params.BlockGossipParams.BlockPartSizeBytes)
return block
}


+ 2
- 1
consensus/mempool_test.go View File

@ -108,7 +108,8 @@ func TestTxConcurrentWithCommit(t *testing.T) {
for nTxs := 0; nTxs < NTxs; {
select {
case b := <-newBlockCh:
nTxs += b.(types.TMEventData).Unwrap().(types.EventDataNewBlock).Block.Header.NumTxs
evt := b.(types.TMEventData).Unwrap().(types.EventDataNewBlock)
nTxs += int(evt.Block.Header.NumTxs)
case <-ticker.C:
panic("Timed out waiting to commit blocks with transactions")
}


+ 3
- 2
consensus/state.go View File

@ -863,7 +863,8 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts
// Mempool validated transactions
txs := cs.mempool.Reap(cs.config.MaxBlockSizeTxs)
return types.MakeBlock(cs.Height, cs.state.ChainID, txs, commit,
return types.MakeBlock(cs.Height, cs.state.ChainID, txs,
cs.state.LastBlockTotalTx, commit,
cs.state.LastBlockID, cs.state.Validators.Hash(),
cs.state.AppHash, cs.state.Params.BlockPartSizeBytes)
}
@ -1200,7 +1201,7 @@ func (cs *ConsensusState) finalizeCommit(height int64) {
// Create a copy of the state for staging
// and an event cache for txs
stateCopy := cs.state.Copy()
txEventBuffer := types.NewTxEventBuffer(cs.eventBus, block.NumTxs)
txEventBuffer := types.NewTxEventBuffer(cs.eventBus, int(block.NumTxs))
// Execute and commit the block, update and save the state, and update the mempool.
// All calls to the proxyAppConn come here.


+ 5
- 4
lite/helpers.go View File

@ -113,10 +113,11 @@ func genHeader(chainID string, height int64, txs types.Txs,
vals *types.ValidatorSet, appHash []byte) *types.Header {
return &types.Header{
ChainID: chainID,
Height: height,
Time: time.Now(),
NumTxs: len(txs),
ChainID: chainID,
Height: height,
Time: time.Now(),
NumTxs: int64(len(txs)),
TotalTxs: int64(len(txs)),
// LastBlockID
// LastCommitHash
ValidatorsHash: vals.Hash(),


+ 2
- 1
state/execution.go View File

@ -178,7 +178,8 @@ func (s *State) ValidateBlock(block *types.Block) error {
func (s *State) validateBlock(block *types.Block) error {
// Basic block validation.
err := block.ValidateBasic(s.ChainID, s.LastBlockHeight, s.LastBlockID, s.LastBlockTime, s.AppHash)
err := block.ValidateBasic(s.ChainID, s.LastBlockHeight,
s.LastBlockTotalTx, s.LastBlockID, s.LastBlockTime, s.AppHash)
if err != nil {
return err
}


+ 4
- 2
state/execution_test.go View File

@ -66,7 +66,9 @@ func makeBlock(height int64, state *State) *types.Block {
prevParts := types.PartSetHeader{}
valHash := state.Validators.Hash()
prevBlockID := types.BlockID{prevHash, prevParts}
block, _ := types.MakeBlock(height, chainID, makeTxs(height), new(types.Commit),
prevBlockID, valHash, state.AppHash, testPartSize)
block, _ := types.MakeBlock(height, chainID,
makeTxs(height), state.LastBlockTotalTx,
new(types.Commit), prevBlockID, valHash,
state.AppHash, testPartSize)
return block
}

+ 11
- 6
state/state.go View File

@ -45,11 +45,12 @@ type State struct {
// These fields are updated by SetBlockAndValidators.
// LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
// LastValidators is used to validate block.LastCommit.
LastBlockHeight int64
LastBlockID types.BlockID
LastBlockTime time.Time
Validators *types.ValidatorSet
LastValidators *types.ValidatorSet
LastBlockHeight int64
LastBlockTotalTx int64
LastBlockID types.BlockID
LastBlockTime time.Time
Validators *types.ValidatorSet
LastValidators *types.ValidatorSet
// When a block returns a validator set change via EndBlock,
// the change only applies to the next block.
// So, if s.LastBlockHeight causes a valset change,
@ -113,6 +114,7 @@ func (s *State) Copy() *State {
return &State{
db: s.db,
LastBlockHeight: s.LastBlockHeight,
LastBlockTotalTx: s.LastBlockTotalTx,
LastBlockID: s.LastBlockID,
LastBlockTime: s.LastBlockTime,
Validators: s.Validators.Copy(),
@ -250,16 +252,19 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ
nextValSet.IncrementAccum(1)
s.setBlockAndValidators(header.Height,
header.NumTxs,
types.BlockID{header.Hash(), blockPartsHeader},
header.Time,
prevValSet, nextValSet)
}
func (s *State) setBlockAndValidators(height int64, blockID types.BlockID, blockTime time.Time,
func (s *State) setBlockAndValidators(height int64,
newTxs int64, blockID types.BlockID, blockTime time.Time,
prevValSet, nextValSet *types.ValidatorSet) {
s.LastBlockHeight = height
s.LastBlockTotalTx += newTxs
s.LastBlockID = blockID
s.LastBlockTime = blockTime
s.Validators = nextValSet


+ 22
- 7
types/block.go View File

@ -23,14 +23,19 @@ type Block struct {
// MakeBlock returns a new block and corresponding partset from the given information.
// TODO: Add version information to the Block struct.
func MakeBlock(height int64, chainID string, txs []Tx, commit *Commit,
prevBlockID BlockID, valHash, appHash []byte, partSize int) (*Block, *PartSet) {
func MakeBlock(height int64, chainID string, txs []Tx,
totalTxs int64, commit *Commit,
prevBlockID BlockID, valHash, appHash []byte,
partSize int) (*Block, *PartSet) {
newTxs := int64(len(txs))
block := &Block{
Header: &Header{
ChainID: chainID,
Height: height,
Time: time.Now(),
NumTxs: len(txs),
NumTxs: newTxs,
TotalTxs: totalTxs + newTxs,
LastBlockID: prevBlockID,
ValidatorsHash: valHash,
AppHash: appHash, // state merkle root of txs from the previous block.
@ -45,8 +50,10 @@ func MakeBlock(height int64, chainID string, txs []Tx, commit *Commit,
}
// ValidateBasic performs basic validation that doesn't involve state data.
func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64, lastBlockID BlockID,
func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64,
lastBlockTotalTx int64, lastBlockID BlockID,
lastBlockTime time.Time, appHash []byte) error {
if b.ChainID != chainID {
return errors.New(cmn.Fmt("Wrong Block.Header.ChainID. Expected %v, got %v", chainID, b.ChainID))
}
@ -60,8 +67,12 @@ func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64, lastBlockID
return errors.New("Invalid Block.Header.Time")
}
*/
if b.NumTxs != len(b.Data.Txs) {
return errors.New(cmn.Fmt("Wrong Block.Header.NumTxs. Expected %v, got %v", len(b.Data.Txs), b.NumTxs))
newTxs := int64(len(b.Data.Txs))
if b.NumTxs != newTxs {
return errors.New(cmn.Fmt("Wrong Block.Header.NumTxs. Expected %v, got %v", newTxs, b.NumTxs))
}
if b.TotalTxs != lastBlockTotalTx+newTxs {
return errors.New(cmn.Fmt("Wrong Block.Header.TotalTxs. Expected %v, got %v", lastBlockTotalTx+newTxs, b.TotalTxs))
}
if !b.LastBlockID.Equals(lastBlockID) {
return errors.New(cmn.Fmt("Wrong Block.Header.LastBlockID. Expected %v, got %v", lastBlockID, b.LastBlockID))
@ -160,7 +171,8 @@ type Header struct {
ChainID string `json:"chain_id"`
Height int64 `json:"height"`
Time time.Time `json:"time"`
NumTxs int `json:"num_txs"` // XXX: Can we get rid of this?
NumTxs int64 `json:"num_txs"` // XXX: Can we get rid of this?
TotalTxs int64 `json:"total_txs"`
LastBlockID BlockID `json:"last_block_id"`
LastCommitHash data.Bytes `json:"last_commit_hash"` // commit from validators from the last block
DataHash data.Bytes `json:"data_hash"` // transactions
@ -179,6 +191,7 @@ func (h *Header) Hash() data.Bytes {
"Height": h.Height,
"Time": h.Time,
"NumTxs": h.NumTxs,
"TotalTxs": h.TotalTxs,
"LastBlockID": h.LastBlockID,
"LastCommit": h.LastCommitHash,
"Data": h.DataHash,
@ -197,6 +210,7 @@ func (h *Header) StringIndented(indent string) string {
%s Height: %v
%s Time: %v
%s NumTxs: %v
%s TotalTxs: %v
%s LastBlockID: %v
%s LastCommit: %v
%s Data: %v
@ -207,6 +221,7 @@ func (h *Header) StringIndented(indent string) string {
indent, h.Height,
indent, h.Time,
indent, h.NumTxs,
indent, h.TotalTxs,
indent, h.LastBlockID,
indent, h.LastCommitHash,
indent, h.DataHash,


+ 80
- 0
types/block_test.go View File

@ -0,0 +1,80 @@
package types
import (
"testing"
"github.com/stretchr/testify/require"
crypto "github.com/tendermint/go-crypto"
)
func TestValidateBlock(t *testing.T) {
txs := []Tx{Tx("foo"), Tx("bar")}
lastID := makeBlockID()
valHash := []byte("val")
appHash := []byte("app")
h := int64(3)
voteSet, _, vals := randVoteSet(h-1, 1, VoteTypePrecommit,
10, 1)
commit, err := makeCommit(lastID, h-1, 1, voteSet, vals)
require.NoError(t, err)
block, _ := MakeBlock(h, "hello", txs, 10, commit,
lastID, valHash, appHash, 2)
require.NotNil(t, block)
// proper block must pass
err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, appHash)
require.NoError(t, err)
// wrong chain fails
err = block.ValidateBasic("other", h-1, 10, lastID, block.Time, appHash)
require.Error(t, err)
// wrong height fails
err = block.ValidateBasic("hello", h+4, 10, lastID, block.Time, appHash)
require.Error(t, err)
// wrong total tx fails
err = block.ValidateBasic("hello", h-1, 15, lastID, block.Time, appHash)
require.Error(t, err)
// wrong blockid fails
err = block.ValidateBasic("hello", h-1, 10, makeBlockID(), block.Time, appHash)
require.Error(t, err)
// wrong app hash fails
err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, []byte("bad-hash"))
require.Error(t, err)
}
func makeBlockID() BlockID {
blockHash, blockPartsHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)}
return BlockID{blockHash, blockPartsHeader}
}
func makeCommit(blockID BlockID, height int64, round int,
voteSet *VoteSet,
validators []*PrivValidatorFS) (*Commit, error) {
voteProto := &Vote{
ValidatorAddress: nil,
ValidatorIndex: -1,
Height: height,
Round: round,
Type: VoteTypePrecommit,
BlockID: blockID,
}
// all sign
for i := 0; i < len(validators); i++ {
vote := withValidator(voteProto, validators[i].GetAddress(), i)
_, err := signAddVote(validators[i], vote, voteSet)
if err != nil {
return nil, err
}
}
return voteSet.MakeCommit(), nil
}

Loading…
Cancel
Save