prysm-pulse/sharding/syncer/handlers_test.go
Preston Van Loon 68eba02cc2 Remove most of the remaining geth code and set up bazel (#235)
* Remove most of the remaining geth code and set up bazel for this

* chmod +x

* Add flake check

* better flake detection


Former-commit-id: 5c332ecbf2923943f646f1fe40befa95be883329 [formerly 99590fc354514584700e5ce8d7d30a8a7d541f29]
Former-commit-id: e5f919b553fe698e98090965d34eb721990b5693
2018-07-07 13:23:19 -04:00

258 lines
7.5 KiB
Go

package syncer
import (
"bytes"
"context"
"errors"
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/prysmaticlabs/geth-sharding/sharding"
"github.com/prysmaticlabs/geth-sharding/sharding/contracts"
"github.com/prysmaticlabs/geth-sharding/sharding/p2p"
"github.com/prysmaticlabs/geth-sharding/sharding/p2p/messages"
shardparams "github.com/prysmaticlabs/geth-sharding/sharding/params"
)
var (
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr = crypto.PubkeyToAddress(key.PublicKey)
accountBalance, _ = new(big.Int).SetString("1001000000000000000000", 10)
)
// Mock client for testing proposer.
type mockNode struct {
smc *contracts.SMC
t *testing.T
depositFlag bool
Backend *backends.SimulatedBackend
BlockNumber int64
}
type faultySMCCaller 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 (m *mockNode) CreateTXOpts(value *big.Int) (*bind.TransactOpts, error) {
txOpts := transactOpts()
txOpts.Value = value
return txOpts, nil
}
func (m *mockNode) SMCTransactor() *contracts.SMCTransactor {
return &m.smc.SMCTransactor
}
func (m *mockNode) SMCCaller() *contracts.SMCCaller {
return &m.smc.SMCCaller
}
func (m *mockNode) GetShardCount() (int64, error) {
shardCount, err := m.SMCCaller().ShardCount(&bind.CallOpts{})
if err != nil {
return 0, err
}
return shardCount.Int64(), nil
}
func (m *mockNode) Account() *accounts.Account {
return &accounts.Account{Address: addr}
}
func (m *mockNode) WaitForTransaction(ctx context.Context, hash common.Hash, durationInSeconds time.Duration) error {
m.CommitWithBlock()
m.FastForward(1)
return nil
}
func (m *mockNode) TransactionReceipt(hash common.Hash) (*types.Receipt, error) {
return m.Backend.TransactionReceipt(context.Background(), hash)
}
func (m *mockNode) DepositFlag() bool {
return m.depositFlag
}
func (m *mockNode) FastForward(p int) {
for i := 0; i < p*int(shardparams.DefaultConfig.PeriodLength); i++ {
m.CommitWithBlock()
}
}
func (m *mockNode) CommitWithBlock() {
m.Backend.Commit()
m.BlockNumber = m.BlockNumber + 1
}
func (m *mockNode) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
return types.NewBlockWithHeader(&types.Header{Number: big.NewInt(m.BlockNumber)}), nil
}
type faultyRequest struct{}
type faultyCollationFetcher struct{}
type mockSigner struct{}
type mockCollationFetcher struct{}
func (m *mockSigner) Sign(hash common.Hash) ([]byte, error) {
return []byte{}, nil
}
func (m *mockCollationFetcher) CollationByHeaderHash(headerHash *common.Hash) (*sharding.Collation, error) {
shardID := big.NewInt(1)
chunkRoot := common.BytesToHash([]byte{})
period := big.NewInt(1)
proposerAddress := common.BytesToAddress([]byte{})
header := sharding.NewCollationHeader(shardID, &chunkRoot, period, &proposerAddress, [32]byte{})
return sharding.NewCollation(header, []byte{}, []*types.Transaction{}), nil
}
func (f *faultyCollationFetcher) CollationByHeaderHash(headerHash *common.Hash) (*sharding.Collation, error) {
return nil, errors.New("could not fetch collation")
}
func transactOpts() *bind.TransactOpts {
return bind.NewKeyedTransactor(key)
}
func setup(t *testing.T) (*backends.SimulatedBackend, *contracts.SMC) {
backend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: accountBalance}})
_, _, smc, err := contracts.DeploySMC(transactOpts(), backend)
if err != nil {
t.Fatalf("Failed to deploy SMC contract: %v", err)
}
backend.Commit()
return backend, smc
}
func TestCollationBodyResponse(t *testing.T) {
proposerAddress := common.BytesToAddress([]byte{})
chunkRoot := common.BytesToHash([]byte{})
goodReq := messages.CollationBodyRequest{
ChunkRoot: &chunkRoot,
ShardID: big.NewInt(1),
Period: big.NewInt(1),
Proposer: &proposerAddress,
}
incorrectReq := faultyRequest{}
fetcher := &mockCollationFetcher{}
faultyFetcher := &faultyCollationFetcher{}
badMsg := p2p.Message{
Peer: p2p.Peer{},
Data: incorrectReq,
}
goodMsg := p2p.Message{
Peer: p2p.Peer{},
Data: goodReq,
}
if _, err := RespondCollationBody(badMsg, fetcher); err == nil {
t.Errorf("Incorrect request should throw error. Expecting messages.CollationBodyRequest{}, received: %v", incorrectReq)
}
if _, err := RespondCollationBody(goodMsg, faultyFetcher); err == nil {
t.Error("Faulty collatiom fetcher should cause function to throw error. no error thrown.")
}
header := sharding.NewCollationHeader(goodReq.ShardID, goodReq.ChunkRoot, goodReq.Period, goodReq.Proposer, [32]byte{})
body := []byte{}
response, err := RespondCollationBody(goodMsg, fetcher)
if err != nil {
t.Fatalf("Could not construct collation body response: %v", err)
}
if response.HeaderHash.Hex() != header.Hash().Hex() {
t.Errorf("Incorrect header hash received. want: %v, received: %v", header.Hash().Hex(), response.HeaderHash.Hex())
}
if !bytes.Equal(response.Body, body) {
t.Errorf("Incorrect collation body received. want: %v, received: %v", response.Body, body)
}
}
func TestConstructNotaryRequest(t *testing.T) {
backend, smc := setup(t)
node := &mockNode{smc: smc, t: t, Backend: backend}
// Fast forward to next period.
for i := 0; i < int(shardparams.DefaultConfig.PeriodLength); i++ {
backend.Commit()
}
shardID := big.NewInt(0)
period := big.NewInt(1)
// We set the proposer address to the address used to setup the backend.
proposerAddress := addr
chunkRoot := common.BytesToHash([]byte("chunkroottest"))
// Adds the header to the SMC.
opt, err := node.CreateTXOpts(big.NewInt(0))
smc.AddHeader(opt, shardID, period, chunkRoot, [32]byte{})
backend.Commit()
if _, err := RequestCollationBody(&faultySMCCaller{}, shardID, period); err == nil {
t.Errorf("Expected error from RequestCollationBody when using faulty SMCCaller, got nil")
}
request, err := RequestCollationBody(node.SMCCaller(), shardID, period)
if err != nil {
t.Fatalf("Could not construct request: %v", err)
}
// fetching an inexistent shardID, period pair from the SMC will return a nil request.
nilRequest, err := RequestCollationBody(node.SMCCaller(), big.NewInt(20), big.NewInt(20))
if err != nil {
t.Fatalf("Could not construct request: %v", err)
}
if nilRequest != nil {
t.Errorf("constructNotaryRequest should return nil for an inexistent collation header. got: %v", err)
}
if request.ChunkRoot.Hex() != chunkRoot.Hex() {
t.Errorf("Chunk root from notary request incorrect. want: %v, got: %v", chunkRoot.Hex(), request.ChunkRoot.Hex())
}
if request.Proposer.Hex() != proposerAddress.Hex() {
t.Errorf("Proposer address from notary request incorrect. want: %v, got: %v", proposerAddress.Hex(), request.Proposer.Hex())
}
if request.ShardID.Cmp(shardID) != 0 {
t.Errorf("ShardID from notary request incorrect. want: %s, got: %s", shardID, request.ShardID)
}
if request.Period.Cmp(period) != 0 {
t.Errorf("Proposer address from notary request incorrect. want: %s, got: %s", period, request.Period)
}
}