prysm-pulse/sharding/simulator/service_test.go
Raul Jordan 2624cd2b3c sharding: Completely Remove Geth, Create a Single Sharding Entry Point That Builds (#238)
Former-commit-id: b853fd1c3ea2284d30d7f3032cf83287c7198c10 [formerly c012daacceec9cb3497f1d066ee3ca2d20aa5b14]
Former-commit-id: 0a5a60c296f878c7057b25fc759dec2487363d30
2018-07-08 21:40:34 -05:00

219 lines
6.2 KiB
Go

package simulator
import (
"context"
"errors"
"fmt"
"math/big"
"testing"
"time"
"github.com/prysmaticlabs/geth-sharding/sharding/mainchain"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
gethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/prysmaticlabs/geth-sharding/sharding/p2p/messages"
"github.com/ethereum/go-ethereum/log"
internal "github.com/prysmaticlabs/geth-sharding/sharding/internal"
"github.com/prysmaticlabs/geth-sharding/sharding/p2p"
"github.com/prysmaticlabs/geth-sharding/sharding/params"
"github.com/prysmaticlabs/geth-sharding/sharding/types"
)
var _ = types.Service(&Simulator{})
type faultyReader struct{}
type goodReader struct{}
type faultySMCCaller struct{}
type goodSMCCaller struct{}
func (f *faultySMCCaller) CollationRecords(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (struct {
ChunkRoot [32]byte
Proposer common.Address
IsElected bool
Signature [32]byte
}, error) {
res := new(struct {
ChunkRoot [32]byte
Proposer common.Address
IsElected bool
Signature [32]byte
})
return *res, errors.New("error fetching collation record")
}
func (g *goodSMCCaller) CollationRecords(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (struct {
ChunkRoot [32]byte
Proposer common.Address
IsElected bool
Signature [32]byte
}, error) {
res := new(struct {
ChunkRoot [32]byte
Proposer common.Address
IsElected bool
Signature [32]byte
})
body := []byte{1, 2, 3, 4, 5}
res.ChunkRoot = [32]byte(gethTypes.DeriveSha(types.Chunks(body)))
res.Proposer = common.BytesToAddress([]byte{})
res.IsElected = false
return *res, nil
}
func (f *faultyReader) BlockByNumber(ctx context.Context, number *big.Int) (*gethTypes.Block, error) {
return nil, fmt.Errorf("cannot fetch block by number")
}
func (f *faultyReader) SubscribeNewHead(ctx context.Context, ch chan<- *gethTypes.Header) (ethereum.Subscription, error) {
return nil, nil
}
func (g *goodReader) BlockByNumber(ctx context.Context, number *big.Int) (*gethTypes.Block, error) {
return gethTypes.NewBlock(&gethTypes.Header{Number: big.NewInt(0)}, nil, nil, nil), nil
}
func (g *goodReader) SubscribeNewHead(ctx context.Context, ch chan<- *gethTypes.Header) (ethereum.Subscription, error) {
return nil, nil
}
func TestStartStop(t *testing.T) {
h := internal.NewLogHandler(t)
log.Root().SetHandler(h)
shardID := 0
server, err := p2p.NewServer()
if err != nil {
t.Fatalf("Unable to setup p2p server: %v", err)
}
simulator, err := NewSimulator(params.DefaultConfig, &mainchain.SMCClient{}, server, shardID, 0)
if err != nil {
t.Fatalf("Unable to setup simulator service: %v", err)
}
if err := simulator.Stop(); err != nil {
t.Fatalf("Unable to stop simulator service: %v", err)
}
h.VerifyLogMsg("Stopping simulator service")
// The context should have been canceled.
if simulator.ctx.Err() == nil {
t.Error("Context was not canceled")
}
}
// This test uses a faulty chain reader in order to trigger an error
// in the simulateNotaryRequests goroutine when reading the block number from
// the mainchain via RPC.
func TestSimulateNotaryRequests_FaultyReader(t *testing.T) {
h := internal.NewLogHandler(t)
log.Root().SetHandler(h)
shardID := 0
server, err := p2p.NewServer()
if err != nil {
t.Fatalf("Unable to setup p2p server: %v", err)
}
simulator, err := NewSimulator(params.DefaultConfig, &mainchain.SMCClient{}, server, shardID, 0)
if err != nil {
t.Fatalf("Unable to setup simulator service: %v", err)
}
simulator.requestFeed = server.Feed(messages.CollationBodyRequest{})
delayChan := make(chan time.Time)
doneChan := make(chan struct{})
exitRoutine := make(chan bool)
go func() {
simulator.simulateNotaryRequests(&goodSMCCaller{}, &faultyReader{}, delayChan, doneChan)
<-exitRoutine
}()
delayChan <- time.Time{}
doneChan <- struct{}{}
h.VerifyLogMsg("Could not fetch current block number: cannot fetch block by number")
exitRoutine <- true
h.VerifyLogMsg("Simulator context closed, exiting goroutine")
}
// This test uses a faulty SMCCaller in order to trigger an error
// in the simulateNotaryRequests goroutine when reading the collation records
// from the SMC.
func TestSimulateNotaryRequests_FaultyCaller(t *testing.T) {
h := internal.NewLogHandler(t)
log.Root().SetHandler(h)
shardID := 0
server, err := p2p.NewServer()
if err != nil {
t.Fatalf("Unable to setup p2p server: %v", err)
}
simulator, err := NewSimulator(params.DefaultConfig, &mainchain.SMCClient{}, server, shardID, 0)
if err != nil {
t.Fatalf("Unable to setup simulator service: %v", err)
}
simulator.requestFeed = server.Feed(messages.CollationBodyRequest{})
delayChan := make(chan time.Time)
doneChan := make(chan struct{})
exitRoutine := make(chan bool)
go func() {
simulator.simulateNotaryRequests(&faultySMCCaller{}, &goodReader{}, delayChan, doneChan)
<-exitRoutine
}()
delayChan <- time.Time{}
doneChan <- struct{}{}
h.VerifyLogMsg("Error constructing collation body request: could not fetch collation record from SMC: error fetching collation record")
exitRoutine <- true
h.VerifyLogMsg("Simulator context closed, exiting goroutine")
}
// This test checks the proper functioning of the simulateNotaryRequests goroutine
// by listening to the requestSent channel which occurs after successful
// construction and sending of a request via p2p.
func TestSimulateNotaryRequests(t *testing.T) {
h := internal.NewLogHandler(t)
log.Root().SetHandler(h)
shardID := 0
server, err := p2p.NewServer()
if err != nil {
t.Fatalf("Unable to setup p2p server: %v", err)
}
simulator, err := NewSimulator(params.DefaultConfig, &mainchain.SMCClient{}, server, shardID, 0)
if err != nil {
t.Fatalf("Unable to setup simulator service: %v", err)
}
simulator.requestFeed = server.Feed(messages.CollationBodyRequest{})
delayChan := make(chan time.Time)
doneChan := make(chan struct{})
exitRoutine := make(chan bool)
go func() {
simulator.simulateNotaryRequests(&goodSMCCaller{}, &goodReader{}, delayChan, doneChan)
<-exitRoutine
}()
delayChan <- time.Time{}
doneChan <- struct{}{}
h.VerifyLogMsg("Sent request for collation body via a shardp2p feed")
exitRoutine <- true
h.VerifyLogMsg("Simulator context closed, exiting goroutine")
}