mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-10 11:41:21 +00:00
b6cd890a67
Former-commit-id: f7344b7d3fb2fa07f0fd421c5ed3721f6c7a9258 [formerly e678ab2f1681d9492c0e1b142cd06ee08a462fdb] Former-commit-id: d942da3d5cfcde921bebb149c26edd5c4ed178dd
276 lines
7.3 KiB
Go
276 lines
7.3 KiB
Go
package simulator
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"math/big"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"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/prysm/client/mainchain"
|
|
"github.com/prysmaticlabs/prysm/client/p2p"
|
|
"github.com/prysmaticlabs/prysm/client/params"
|
|
"github.com/prysmaticlabs/prysm/client/types"
|
|
"github.com/sirupsen/logrus"
|
|
logTest "github.com/sirupsen/logrus/hooks/test"
|
|
)
|
|
|
|
func init() {
|
|
logrus.SetLevel(logrus.DebugLevel)
|
|
logrus.SetOutput(ioutil.Discard)
|
|
}
|
|
|
|
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) {
|
|
hook := logTest.NewGlobal()
|
|
|
|
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, 1*time.Second)
|
|
if err != nil {
|
|
t.Fatalf("Unable to setup simulator service: %v", err)
|
|
}
|
|
|
|
simulator.Start()
|
|
msg := hook.LastEntry().Message
|
|
if msg != "Starting simulator service" {
|
|
t.Errorf("incorrect log, expected %s, got %s", "Starting simulator service", msg)
|
|
}
|
|
|
|
if err := simulator.Stop(); err != nil {
|
|
t.Fatalf("Unable to stop simulator service: %v", err)
|
|
}
|
|
|
|
msg = hook.LastEntry().Message
|
|
if msg != "Stopping simulator service" {
|
|
t.Errorf("incorrect log, expected %s, got %s", "Stopping simulator service", msg)
|
|
}
|
|
|
|
// The context should have been canceled.
|
|
if simulator.ctx.Err() == nil {
|
|
t.Error("Context was not canceled")
|
|
}
|
|
hook.Reset()
|
|
}
|
|
|
|
// 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) {
|
|
hook := logTest.NewGlobal()
|
|
|
|
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)
|
|
}
|
|
|
|
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{}{}
|
|
|
|
msg := hook.LastEntry().Message
|
|
want := "Could not fetch current block number: cannot fetch block by number"
|
|
if msg != want {
|
|
t.Errorf("incorrect log, expected %s, got %s", want, msg)
|
|
}
|
|
|
|
exitRoutine <- true
|
|
hook.Reset()
|
|
}
|
|
|
|
// 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) {
|
|
hook := logTest.NewGlobal()
|
|
|
|
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)
|
|
}
|
|
|
|
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{}{}
|
|
|
|
msg := hook.AllEntries()[0].Message
|
|
want := "Error constructing collation body request: could not fetch collation record from SMC: error fetching collation record"
|
|
if msg != want {
|
|
t.Errorf("incorrect log, expected %s, got %s", want, msg)
|
|
}
|
|
|
|
exitRoutine <- true
|
|
hook.Reset()
|
|
}
|
|
|
|
// 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) {
|
|
hook := logTest.NewGlobal()
|
|
|
|
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)
|
|
}
|
|
|
|
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{}{}
|
|
|
|
msg := hook.Entries[1].Message
|
|
want := "Sent request for collation body via a shardp2p broadcast"
|
|
if msg != want {
|
|
t.Errorf("incorrect log, expected %s, got %s", want, msg)
|
|
}
|
|
|
|
exitRoutine <- true
|
|
hook.Reset()
|
|
}
|
|
|
|
// This test verifies actor simulator can successfully broadcast
|
|
// transactions to rest of the peers.
|
|
func TestBroadcastTransactions(t *testing.T) {
|
|
hook := logTest.NewGlobal()
|
|
|
|
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, 1*time.Second)
|
|
if err != nil {
|
|
t.Fatalf("Unable to setup simulator service: %v", err)
|
|
}
|
|
|
|
delayChan := make(chan time.Time)
|
|
doneChan := make(chan struct{})
|
|
exitRoutine := make(chan bool)
|
|
|
|
go func() {
|
|
simulator.broadcastTransactions(delayChan, doneChan)
|
|
<-exitRoutine
|
|
}()
|
|
|
|
delayChan <- time.Time{}
|
|
doneChan <- struct{}{}
|
|
|
|
msg := hook.Entries[1].Message
|
|
want := "Transaction broadcasted"
|
|
if !strings.Contains(msg, want) {
|
|
t.Errorf("incorrect log, expected %s, got %s", want, msg)
|
|
}
|
|
|
|
exitRoutine <- true
|
|
hook.Reset()
|
|
}
|