Merge pull request #42 from getamis/test/byzantine-faulty-behavior-testing
test: TFS-05 add byzantine faulty tests
This commit is contained in:
commit
d4591be74d
|
@ -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 {
|
||||
|
|
|
@ -74,6 +74,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
|
||||
}
|
||||
|
@ -523,6 +525,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 {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
||||
})
|
Loading…
Reference in New Issue