test: TFS-05 add byzantine faulty tests

This commit is contained in:
Yute Lin 2017-08-24 16:09:59 +08:00
parent 22cdc39566
commit be765d7fbe
4 changed files with 185 additions and 0 deletions

View File

@ -72,6 +72,44 @@ func NewDefaultBlockchain(numOfValidators int) (bc *blockchain) {
)
}
func NewDefaultBlockchainWithFaulty(numOfNormal int, numOfFaulty int) (bc *blockchain) {
commonOpts := [...]Option{
DataDir("/data"),
WebSocket(),
WebSocketAddress("0.0.0.0"),
WebSocketAPI("admin,eth,net,web3,personal,miner,istanbul"),
WebSocketOrigin("*"),
NAT("any"),
NoDiscover(),
Etherbase("1a9afb711302c5f83b5902843d1c007a1a137632"),
Mine(),
Logging(false)}
normalOpts := make([]Option, len(commonOpts), len(commonOpts)+2)
copy(normalOpts, commonOpts[:])
normalOpts = append(normalOpts, ImageRepository("quay.io/amis/geth"), ImageTag("istanbul_develop"))
faultyOpts := make([]Option, len(commonOpts), len(commonOpts)+3)
copy(faultyOpts, commonOpts[:])
faultyOpts = append(faultyOpts, ImageRepository("quay.io/amis/geth_faulty"), ImageTag("latest"), FaultyMode(1))
// New env client
bc = &blockchain{}
var err error
bc.dockerClient, err = client.NewEnvClient()
if err != nil {
log.Fatalf("Cannot connect to Docker daemon, err: %v", err)
}
keys, addrs := generateKeys(numOfNormal + numOfFaulty)
bc.setupGenesis(addrs)
// Create normal validators
bc.opts = normalOpts
bc.setupValidators(keys[:numOfNormal], bc.opts...)
// Create faulty validators
bc.opts = faultyOpts
bc.setupValidators(keys[numOfNormal:], bc.opts...)
return bc
}
// ----------------------------------------------------------------------------
type blockchain struct {

View File

@ -73,6 +73,8 @@ type Ethereum interface {
WaitForPeersConnected(int) error
WaitForBlocks(int) error
WaitForBlockHeight(int) error
// Want for block for no more than the given number during the given time duration
WaitForNoBlocks(int, time.Duration) error
AddPeer(string) error
}
@ -495,6 +497,37 @@ func (eth *ethereum) WaitForBlockHeight(num int) error {
return nil
}
func (eth *ethereum) WaitForNoBlocks(num int, duration time.Duration) error {
var first *big.Int
client := eth.NewIstanbulClient()
if client == nil {
return errors.New("failed to retrieve client")
}
timeout := time.After(duration)
tick := time.Tick(time.Millisecond * 500)
for {
select {
case <-timeout:
return nil
case <-tick:
n, err := client.BlockNumber(context.Background())
if err != nil {
return err
}
if first == nil {
first = new(big.Int).Set(n)
continue
}
// Check if new blocks are getting generated
if new(big.Int).Sub(n, first).Int64() > int64(num) {
return errors.New("generated more blocks than expected")
}
}
}
}
func (eth *ethereum) AddPeer(address string) error {
client := eth.NewIstanbulClient()
if client == nil {

View File

@ -238,3 +238,10 @@ func Verbosity(verbosity int) Option {
eth.flags = append(eth.flags, fmt.Sprintf("%d", verbosity))
}
}
func FaultyMode(mode int) Option {
return func(eth *ethereum) {
eth.flags = append(eth.flags, "--istanbul.faultymode")
eth.flags = append(eth.flags, fmt.Sprintf("%d", mode))
}
}

View File

@ -0,0 +1,107 @@
// Copyright 2017 AMIS Technologies
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package tests
import (
"sync"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/getamis/istanbul-tools/container"
)
var _ = Describe("TFS-05: Byzantine Faulty", func() {
Context("TFS-05-01: F faulty validators", func() {
const (
numberOfNormal = 3
numberOfFaulty = 1
)
var (
blockchain container.Blockchain
)
BeforeEach(func() {
blockchain = container.NewDefaultBlockchainWithFaulty(numberOfNormal, numberOfFaulty)
Expect(blockchain.Start(true)).To(BeNil())
})
AfterEach(func() {
Expect(blockchain.Stop(false)).To(BeNil())
blockchain.Finalize()
})
It("Should generate blocks", func(done Done) {
By("Wait for p2p connection", func() {
waitFor(blockchain.Validators(), func(geth container.Ethereum, wg *sync.WaitGroup) {
Expect(geth.WaitForPeersConnected(numberOfNormal + numberOfFaulty - 1)).To(BeNil())
wg.Done()
})
})
By("Wait for blocks", func() {
const targetBlockHeight = 3
waitFor(blockchain.Validators()[:1], func(geth container.Ethereum, wg *sync.WaitGroup) {
Expect(geth.WaitForBlocks(targetBlockHeight)).To(BeNil())
wg.Done()
})
})
close(done)
}, 60)
})
Context("TFS-05-01: F+1 faulty validators", func() {
const (
numberOfNormal = 2
numberOfFaulty = 2
)
var (
blockchain container.Blockchain
)
BeforeEach(func() {
blockchain = container.NewDefaultBlockchainWithFaulty(numberOfNormal, numberOfFaulty)
Expect(blockchain.Start(true)).To(BeNil())
})
AfterEach(func() {
Expect(blockchain.Stop(false)).To(BeNil())
blockchain.Finalize()
})
It("Should not generate blocks", func(done Done) {
By("Wait for p2p connection", func() {
waitFor(blockchain.Validators(), func(geth container.Ethereum, wg *sync.WaitGroup) {
Expect(geth.WaitForPeersConnected(numberOfNormal + numberOfFaulty - 1)).To(BeNil())
wg.Done()
})
})
By("Wait for blocks", func() {
// Only check normal validators
waitFor(blockchain.Validators()[:2], func(geth container.Ethereum, wg *sync.WaitGroup) {
Expect(geth.WaitForNoBlocks(0, time.Second*30)).To(BeNil())
wg.Done()
})
})
close(done)
}, 60)
})
})