Commit 7915e316 authored by caopingcp's avatar caopingcp

tendermint unit test

parent 6904435a
......@@ -83,13 +83,13 @@ powLimitBits = "0x1f2fffff"
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
genesisBlockTime=1514533394
timeoutTxAvail=1000
timeoutPropose=3000
timeoutPropose=1000
timeoutProposeDelta=500
timeoutPrevote=1000
timeoutPrevoteDelta=500
timeoutPrecommit=1000
timeoutPrecommitDelta=500
timeoutCommit=1000
timeoutCommit=500
skipTimeoutCommit=false
createEmptyBlocks=false
createEmptyBlocksInterval=0
......
......@@ -269,11 +269,11 @@ func (cs *ConsensusState) reconstructLastCommit(state State) {
precommit := &ttypes.Vote{Vote: item}
added, err := lastPrecommits.AddVote(precommit)
if !added || err != nil {
panic(fmt.Sprintf("Panicked on a Crisis: %v", fmt.Sprintf("Failed to reconstruct LastCommit: %v", err)))
panic(fmt.Sprintf("Failed to reconstruct LastCommit: %v", err))
}
}
if !lastPrecommits.HasTwoThirdsMajority() {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", "Failed to reconstruct LastCommit: Does not have +2/3 maj"))
panic("Failed to reconstruct LastCommit: Does not have +2/3 maj")
}
cs.LastCommit = lastPrecommits
}
......@@ -282,14 +282,12 @@ func (cs *ConsensusState) reconstructLastCommit(state State) {
// The round becomes 0 and cs.Step becomes ttypes.RoundStepNewHeight.
func (cs *ConsensusState) updateToState(state State) {
if cs.CommitRound > -1 && 0 < cs.Height && cs.Height != state.LastBlockHeight {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("updateToState() expected state height of %v but found %v",
cs.Height, state.LastBlockHeight)))
panic(fmt.Sprintf("updateToState expected state height of %v but found %v", cs.Height, state.LastBlockHeight))
}
if !cs.state.IsEmpty() && cs.state.LastBlockHeight+1 != cs.Height {
// This might happen when someone else is mutating cs.state.
// Someone forgot to pass in state.Copy() somewhere?!
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v",
cs.state.LastBlockHeight+1, cs.Height)))
panic(fmt.Sprintf("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v", cs.state.LastBlockHeight+1, cs.Height))
}
// If state isn't further out than cs.state, just ignore.
......@@ -305,7 +303,7 @@ func (cs *ConsensusState) updateToState(state State) {
lastPrecommits := (*ttypes.VoteSet)(nil)
if cs.CommitRound > -1 && cs.Votes != nil {
if !cs.Votes.Precommits(cs.CommitRound).HasTwoThirdsMajority() {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", "updateToState(state) called but last Precommit round didn't have +2/3"))
panic("updateToState called but last Precommit round didn't have +2/3")
}
lastPrecommits = cs.Votes.Precommits(cs.CommitRound)
}
......@@ -556,6 +554,9 @@ func (cs *ConsensusState) enterNewRound(height int64, round int) {
// We've already reset these upon new height,
// and meanwhile we might have received a proposal
// for round 0.
if cs.begCons.IsZero() {
cs.begCons = time.Now()
}
} else {
tendermintlog.Info("Resetting Proposal info")
cs.Proposal = nil
......@@ -616,7 +617,7 @@ func (cs *ConsensusState) proposalHeartbeat(height int64, round int) {
// Enter (!CreateEmptyBlocks) : after enterNewRound(height,round), once txs are in the mempool
func (cs *ConsensusState) enterPropose(height int64, round int) {
if cs.Height != height || round < cs.Round || (cs.Round == round && ttypes.RoundStepPropose <= cs.Step) {
tendermintlog.Info(fmt.Sprintf("enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
tendermintlog.Debug(fmt.Sprintf("enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
return
}
tendermintlog.Info(fmt.Sprintf("enterPropose(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
......@@ -730,7 +731,7 @@ func (cs *ConsensusState) createProposalBlock() (block *ttypes.TendermintBlock)
} else {
// This shouldn't happen.
tendermintlog.Error("enterPropose: Cannot propose anything: No commit for the previous block.")
return
return nil
}
// Mempool validated transactions
......@@ -741,7 +742,7 @@ func (cs *ConsensusState) createProposalBlock() (block *ttypes.TendermintBlock)
if pblock.Height != cs.Height {
tendermintlog.Error("pblock.Height is not equal to cs.Height")
return
return nil
}
proposerAddr := cs.privValidator.GetAddress()
......@@ -752,7 +753,7 @@ func (cs *ConsensusState) createProposalBlock() (block *ttypes.TendermintBlock)
pblockNew := cs.client.ExecBlock(block.Data)
if pblockNew == nil {
tendermintlog.Error("createProposalBlock ExecBlock fail")
return
return nil
}
block.Data = pblockNew
evidence := cs.evpool.PendingEvidence()
......@@ -825,6 +826,20 @@ func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
return
}
// Exec proposal block
blockCopy := *cs.ProposalBlock.Data
blockNew := cs.client.ExecBlock(&blockCopy)
if blockNew == nil {
tendermintlog.Error("enterPrevote: Exec ProposalBlock fail")
cs.signAddVote(ttypes.VoteTypePrevote, nil)
return
}
if !bytes.Equal(blockNew.Hash(), cs.ProposalBlock.Data.Hash()) {
tendermintlog.Error("enterPrevote: Exec ProposalBlock has change")
cs.signAddVote(ttypes.VoteTypePrevote, nil)
return
}
// Prevote cs.ProposalBlock
// NOTE: the proposal signature is validated when it is received,
// and the proposal block parts are validated as they are received (against the merkle hash in the proposal)
......@@ -839,7 +854,7 @@ func (cs *ConsensusState) enterPrevoteWait(height int64, round int) {
return
}
if !cs.Votes.Prevotes(round).HasTwoThirdsAny() {
panic(fmt.Sprintf("Panicked on a Sanity Check: %v", fmt.Sprintf("enterPrevoteWait(%v/%v), but Prevotes does not have any +2/3 votes", height, round)))
panic(fmt.Sprintf("enterPrevoteWait(%v/%v), but Prevotes does not have any +2/3 votes", height, round))
}
tendermintlog.Info(fmt.Sprintf("enterPrevoteWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
......@@ -920,7 +935,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
tendermintlog.Info("enterPrecommit: +2/3 prevoted proposal block. Locking", "hash", fmt.Sprintf("%X", blockID.Hash))
// Validate the block.
if err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock); err != nil {
panic(fmt.Sprintf("Panicked on a Consensus Failure: %v", fmt.Sprintf("enterPrecommit: +2/3 prevoted for an invalid block: %v", err)))
panic(fmt.Sprintf("enterPrecommit: +2/3 prevoted for an invalid block: %v", err))
}
cs.LockedRound = round
cs.LockedBlock = cs.ProposalBlock
......
......@@ -191,7 +191,10 @@ func changeInVotingPowerMoreOrEqualToOneThird(currentSet *ttypes.ValidatorSet, u
}
func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error {
newTxs := b.Header.NumTxs
// Validate internal consistency.
if err := b.ValidateBasic(); err != nil {
return err
}
// validate basic info
if b.Header.ChainID != s.ChainID {
......@@ -206,6 +209,7 @@ func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error
return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", s.LastBlockID, b.Header.LastBlockID)
}
newTxs := b.Header.NumTxs
if b.Header.TotalTxs != s.LastBlockTotalTx+newTxs {
return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", s.LastBlockTotalTx+newTxs, b.Header.TotalTxs)
}
......
package tendermint
import (
"encoding/hex"
"fmt"
"github.com/33cn/chain33/types"
"sync"
"testing"
"github.com/33cn/chain33/common/crypto"
"github.com/stretchr/testify/assert"
)
var (
secureConnCrypto crypto.Crypto
sum = 0
mutx sync.Mutex
privKey = "B3DC4C0725884EBB7264B92F1D8D37584A64ADE1799D997EC64B4FE3973E08DE220ACBE680DF2473A0CB48987A00FCC1812F106A7390BE6B8E2D31122C992A19"
expectAddress = "02A13174B92727C4902DB099E51A3339F48BD45E"
)
func init() {
cr2, err := crypto.New(types.GetSignName("", types.ED25519))
if err != nil {
fmt.Println("crypto.New failed for types.ED25519")
return
}
secureConnCrypto = cr2
}
func TestParallel(t *testing.T) {
Parallel(
func() {
mutx.Lock()
sum++
mutx.Unlock()
},
func() {
mutx.Lock()
sum += 2
mutx.Unlock()
},
func() {
mutx.Lock()
sum += 3
mutx.Unlock()
},
)
fmt.Println("TestParallel ok")
assert.Equal(t, 6, sum)
}
func TestGenAddressByPubKey(t *testing.T) {
tmp, err := hex.DecodeString(privKey)
assert.Nil(t, err)
priv, err := secureConnCrypto.PrivKeyFromBytes(tmp)
assert.Nil(t, err)
addr := GenAddressByPubKey(priv.PubKey())
strAddr := fmt.Sprintf("%X", addr)
assert.Equal(t, expectAddress, strAddr)
fmt.Println("TestGenAddressByPubKey ok")
}
func TestIP2IPPort(t *testing.T) {
testMap := NewMutexMap()
assert.Equal(t, false, testMap.Has("1.1.1.1"))
testMap.Set("1.1.1.1", "1.1.1.1:80")
assert.Equal(t, true, testMap.Has("1.1.1.1"))
testMap.Set("1.1.1.2", "1.1.1.2:80")
assert.Equal(t, true, testMap.Has("1.1.1.2"))
testMap.Delete("1.1.1.1")
assert.Equal(t, false, testMap.Has("1.1.1.1"))
fmt.Println("TestIP2IPPort ok")
}
func TestPeerSet(t *testing.T) {
testSet := NewPeerSet()
assert.Equal(t, false, testSet.Has("1"))
peer1 := &peerConn{id: "1", ip: []byte("1.1.1.1")}
testSet.Add(peer1)
assert.Equal(t, true, testSet.Has("1"))
assert.Equal(t, true, testSet.HasIP([]byte("1.1.1.1")))
err := testSet.Add(peer1)
assert.NotNil(t, err)
peer2 := &peerConn{id: "2", ip: []byte("1.1.1.2")}
testSet.Add(peer2)
assert.Equal(t, true, testSet.Has("2"))
assert.Equal(t, 2, testSet.Size())
testSet.Remove(peer1)
assert.Equal(t, 1, testSet.Size())
assert.Equal(t, false, testSet.Has("1"))
assert.Equal(t, false, testSet.HasIP([]byte("1.1.1.1")))
fmt.Println("TestPeerSet ok")
}
......@@ -361,7 +361,7 @@ func (client *Client) getBlockInfoTx(current *types.Block) (*tmtypes.ValNodeActi
return &valAction, nil
}
// CheckBlock 暂不检查任何的交易
// CheckBlock 检查区块
func (client *Client) CheckBlock(parent *types.Block, current *types.BlockDetail) error {
if current.Block.Difficulty != types.GetP(0).PowLimitBits {
return types.ErrBlockHeaderDifficulty
......@@ -385,7 +385,6 @@ func (client *Client) CheckBlock(parent *types.Block, current *types.BlockDetail
}
lastInfo := lastValAction.GetBlockInfo()
lastProposalBlock := &ttypes.TendermintBlock{TendermintBlock: lastInfo.GetBlock()}
lastProposalBlock.Data = parent
if !lastProposalBlock.HashesTo(info.Block.Header.LastBlockID.Hash) {
return ttypes.ErrLastBlockID
}
......
......@@ -7,6 +7,7 @@ package tendermint
import (
"context"
"encoding/binary"
"encoding/hex"
"errors"
"flag"
"fmt"
......@@ -27,6 +28,7 @@ import (
"github.com/33cn/chain33/store"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/norm/types"
ty "github.com/33cn/plugin/plugin/dapp/valnode/types"
"google.golang.org/grpc"
_ "github.com/33cn/chain33/system"
......@@ -36,7 +38,7 @@ import (
var (
random *rand.Rand
loopCount = 10
loopCount = 3
conn *grpc.ClientConn
c types.Chain33Client
)
......@@ -73,6 +75,11 @@ func TendermintPerf() {
NormPut()
time.Sleep(time.Second)
}
AddNode()
for i := 0; i < loopCount*3; i++ {
NormPut()
time.Sleep(time.Second)
}
time.Sleep(2 * time.Second)
}
......@@ -177,3 +184,28 @@ func NormPut() {
return
}
}
func AddNode() {
pubkey := "788657125A5A547B499F8B74239092EBB6466E8A205348D9EA645D510235A671"
pubkeybyte, err := hex.DecodeString(pubkey)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
nput := &ty.ValNodeAction_Node{Node: &ty.ValNode{PubKey: pubkeybyte, Power: int64(2)}}
action := &ty.ValNodeAction{Value: nput, Ty: ty.ValNodeActionUpdate}
tx := &types.Transaction{Execer: []byte("valnode"), Payload: types.Encode(action), Fee: fee}
tx.To = address.ExecAddress("valnode")
tx.Nonce = r.Int63()
tx.Sign(types.SECP256K1, getprivkey("CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944"))
reply, err := c.SendTransaction(context.Background(), tx)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
if !reply.IsOk {
fmt.Fprintln(os.Stderr, errors.New(string(reply.GetMsg())))
return
}
}
......@@ -97,29 +97,47 @@ func (b *TendermintBlock) AddEvidence(evidence []Evidence) {
// ValidateBasic performs basic validation that doesn't involve state data.
// It checks the internal consistency of the block.
func (b *TendermintBlock) ValidateBasic() (int64, error) {
newTxs := int64(len(b.Data.Txs))
// Further validation is done using state#ValidateBlock.
func (b *TendermintBlock) ValidateBasic() error {
if b == nil {
return errors.New("nil block")
}
if b.Header.Height < 0 {
return errors.New("Negative Header.Height")
} else if b.Header.Height == 0 {
return errors.New("Zero Header.Height")
}
newTxs := int64(len(b.Data.Txs))
if b.Header.NumTxs != newTxs {
return 0, fmt.Errorf("Wrong Block.Header.NumTxs. Expected %v, got %v", newTxs, b.Header.NumTxs)
return fmt.Errorf("Wrong Header.NumTxs. Expected %v, got %v", newTxs, b.Header.NumTxs)
}
if b.Header.TotalTxs < 0 {
return errors.New("Negative Header.TotalTxs")
}
lastCommit := Commit{
TendermintCommit: b.LastCommit,
}
if !bytes.Equal(b.Header.LastCommitHash, lastCommit.Hash()) {
return 0, fmt.Errorf("Wrong Block.Header.LastCommitHash. Expected %v, got %v", b.Header.LastCommitHash, lastCommit.Hash())
}
if b.Header.Height != 1 {
if b.Header.Height > 1 {
if b.LastCommit == nil {
return errors.New("nil LastCommit")
}
if err := lastCommit.ValidateBasic(); err != nil {
return 0, err
return err
}
}
if !bytes.Equal(b.Header.LastCommitHash, lastCommit.Hash()) {
return fmt.Errorf("Wrong Header.LastCommitHash. Expected %v, got %v", b.Header.LastCommitHash, lastCommit.Hash())
}
evidence := &EvidenceData{EvidenceData: b.Evidence}
if !bytes.Equal(b.Header.EvidenceHash, evidence.Hash()) {
return 0, errors.New(Fmt("Wrong Block.Header.EvidenceHash. Expected %v, got %v", b.Header.EvidenceHash, evidence.Hash()))
return errors.New(Fmt("Wrong Header.EvidenceHash. Expected %v, got %v", b.Header.EvidenceHash, evidence.Hash()))
}
return newTxs, nil
return nil
}
// FillHeader fills in any remaining header fields that are a function of the block data
......@@ -331,13 +349,14 @@ func (commit *Commit) ValidateBasic() error {
height, round := commit.Height(), commit.Round()
// validate the precommits
for _, precommit := range commit.Precommits {
// It's OK for precommits to be missing.
if precommit == nil {
for _, item := range commit.Precommits {
// may be nil if validator skipped.
if item == nil || len(item.Signature) == 0 {
continue
}
precommit := &Vote{Vote: item}
// Ensure that all votes are precommits
if byte(precommit.Type) != VoteTypePrecommit {
if precommit.Type != uint32(VoteTypePrecommit) {
return fmt.Errorf("Invalid commit vote. Expected precommit, got %v",
precommit.Type)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment