|
|
@ -0,0 +1,158 @@ |
|
|
|
package blockchain |
|
|
|
|
|
|
|
import ( |
|
|
|
"bytes" |
|
|
|
"testing" |
|
|
|
|
|
|
|
wire "github.com/tendermint/go-wire" |
|
|
|
cmn "github.com/tendermint/tmlibs/common" |
|
|
|
"github.com/tendermint/tmlibs/db" |
|
|
|
"github.com/tendermint/tmlibs/log" |
|
|
|
|
|
|
|
cfg "github.com/tendermint/tendermint/config" |
|
|
|
"github.com/tendermint/tendermint/p2p" |
|
|
|
sm "github.com/tendermint/tendermint/state" |
|
|
|
"github.com/tendermint/tendermint/types" |
|
|
|
) |
|
|
|
|
|
|
|
func newBlockchainReactor(logger log.Logger, maxBlockHeight int) *BlockchainReactor { |
|
|
|
config := cfg.ResetTestRoot("node_node_test") |
|
|
|
|
|
|
|
blockStoreDB := db.NewDB("blockstore", config.DBBackend, config.DBDir()) |
|
|
|
blockStore := NewBlockStore(blockStoreDB) |
|
|
|
|
|
|
|
stateLogger := logger.With("module", "state") |
|
|
|
|
|
|
|
// Get State
|
|
|
|
stateDB := db.NewDB("state", config.DBBackend, config.DBDir()) |
|
|
|
state, _ := sm.GetState(stateDB, config.GenesisFile()) |
|
|
|
|
|
|
|
state.SetLogger(stateLogger) |
|
|
|
state.Save() |
|
|
|
|
|
|
|
// Make the blockchainReactor itself
|
|
|
|
fastSync := true |
|
|
|
bcReactor := NewBlockchainReactor(state.Copy(), nil, blockStore, fastSync) |
|
|
|
|
|
|
|
// Next: we need to set a switch in order for peers to be added in
|
|
|
|
bcReactor.Switch = p2p.NewSwitch(cfg.DefaultP2PConfig()) |
|
|
|
bcReactor.SetLogger(logger.With("module", "blockchain")) |
|
|
|
|
|
|
|
// Lastly: let's add some blocks in
|
|
|
|
for blockHeight := 1; blockHeight <= maxBlockHeight; blockHeight++ { |
|
|
|
firstBlock := makeBlock(blockHeight, state) |
|
|
|
secondBlock := makeBlock(blockHeight+1, state) |
|
|
|
firstParts := firstBlock.MakePartSet(state.Params().BlockGossipParams.BlockPartSizeBytes) |
|
|
|
blockStore.SaveBlock(firstBlock, firstParts, secondBlock.LastCommit) |
|
|
|
} |
|
|
|
|
|
|
|
return bcReactor |
|
|
|
} |
|
|
|
|
|
|
|
func TestNoBlockMessageResponse(t *testing.T) { |
|
|
|
logBuf := new(bytes.Buffer) |
|
|
|
logger := log.NewTMLogger(logBuf) |
|
|
|
maxBlockHeight := 20 |
|
|
|
|
|
|
|
bcr := newBlockchainReactor(logger, maxBlockHeight) |
|
|
|
go bcr.OnStart() |
|
|
|
defer bcr.Stop() |
|
|
|
|
|
|
|
// Add some peers in
|
|
|
|
peer := newbcrTestPeer(cmn.RandStr(12)) |
|
|
|
bcr.AddPeer(peer) |
|
|
|
|
|
|
|
chID := byte(0x01) |
|
|
|
|
|
|
|
tests := []struct { |
|
|
|
height int |
|
|
|
existent bool |
|
|
|
}{ |
|
|
|
{maxBlockHeight + 2, false}, |
|
|
|
{10, true}, |
|
|
|
{1, true}, |
|
|
|
{100, false}, |
|
|
|
} |
|
|
|
|
|
|
|
for _, tt := range tests { |
|
|
|
reqBlockMsg := &bcBlockRequestMessage{tt.height} |
|
|
|
reqBlockBytes := wire.BinaryBytes(struct{ BlockchainMessage }{reqBlockMsg}) |
|
|
|
bcr.Receive(chID, peer, reqBlockBytes) |
|
|
|
value := peer.lastValue() |
|
|
|
msg := value.(struct{ BlockchainMessage }).BlockchainMessage |
|
|
|
|
|
|
|
if tt.existent { |
|
|
|
if blockMsg, ok := msg.(*bcBlockResponseMessage); !ok { |
|
|
|
t.Fatalf("Expected to receive a block response for height %d", tt.height) |
|
|
|
} else if blockMsg.Block.Height != tt.height { |
|
|
|
t.Fatalf("Expected response to be for height %d, got %d", tt.height, blockMsg.Block.Height) |
|
|
|
} |
|
|
|
} else { |
|
|
|
if noBlockMsg, ok := msg.(*bcNoBlockResponseMessage); !ok { |
|
|
|
t.Fatalf("Expected to receive a no block response for height %d", tt.height) |
|
|
|
} else if noBlockMsg.Height != tt.height { |
|
|
|
t.Fatalf("Expected response to be for height %d, got %d", tt.height, noBlockMsg.Height) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//----------------------------------------------
|
|
|
|
// utility funcs
|
|
|
|
|
|
|
|
func makeTxs(blockNumber int) (txs []types.Tx) { |
|
|
|
for i := 0; i < 10; i++ { |
|
|
|
txs = append(txs, types.Tx([]byte{byte(blockNumber), byte(i)})) |
|
|
|
} |
|
|
|
return txs |
|
|
|
} |
|
|
|
|
|
|
|
func makeBlock(blockNumber int, state *sm.State) *types.Block { |
|
|
|
prevHash := state.LastBlockID.Hash |
|
|
|
prevParts := types.PartSetHeader{} |
|
|
|
valHash := state.Validators.Hash() |
|
|
|
prevBlockID := types.BlockID{prevHash, prevParts} |
|
|
|
block, _ := types.MakeBlock(blockNumber, "test_chain", makeTxs(blockNumber), |
|
|
|
new(types.Commit), prevBlockID, valHash, state.AppHash, state.Params().BlockGossipParams.BlockPartSizeBytes) |
|
|
|
return block |
|
|
|
} |
|
|
|
|
|
|
|
// The Test peer
|
|
|
|
type bcrTestPeer struct { |
|
|
|
cmn.Service |
|
|
|
key string |
|
|
|
ch chan interface{} |
|
|
|
} |
|
|
|
|
|
|
|
var _ p2p.Peer = (*bcrTestPeer)(nil) |
|
|
|
|
|
|
|
func newbcrTestPeer(key string) *bcrTestPeer { |
|
|
|
return &bcrTestPeer{ |
|
|
|
Service: cmn.NewBaseService(nil, "bcrTestPeer", nil), |
|
|
|
key: key, |
|
|
|
ch: make(chan interface{}, 2), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func (tp *bcrTestPeer) lastValue() interface{} { return <-tp.ch } |
|
|
|
|
|
|
|
func (tp *bcrTestPeer) TrySend(chID byte, value interface{}) bool { |
|
|
|
if _, ok := value.(struct{ BlockchainMessage }).BlockchainMessage.(*bcStatusResponseMessage); ok { |
|
|
|
// Discard status response messages since they skew our results
|
|
|
|
// We only want to deal with:
|
|
|
|
// + bcBlockResponseMessage
|
|
|
|
// + bcNoBlockResponseMessage
|
|
|
|
} else { |
|
|
|
tp.ch <- value |
|
|
|
} |
|
|
|
return true |
|
|
|
} |
|
|
|
|
|
|
|
func (tp *bcrTestPeer) Send(chID byte, data interface{}) bool { return tp.TrySend(chID, data) } |
|
|
|
func (tp *bcrTestPeer) NodeInfo() *p2p.NodeInfo { return nil } |
|
|
|
func (tp *bcrTestPeer) Status() p2p.ConnectionStatus { return p2p.ConnectionStatus{} } |
|
|
|
func (tp *bcrTestPeer) Key() string { return tp.key } |
|
|
|
func (tp *bcrTestPeer) IsOutbound() bool { return false } |
|
|
|
func (tp *bcrTestPeer) IsPersistent() bool { return true } |
|
|
|
func (tp *bcrTestPeer) Get(s string) interface{} { return s } |
|
|
|
func (tp *bcrTestPeer) Set(string, interface{}) {} |