mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-10 03:31:20 +00:00
268 lines
7.8 KiB
Go
268 lines
7.8 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/prysm/client/contracts"
|
|
shardparams "github.com/prysmaticlabs/prysm/client/params"
|
|
shardingTypes "github.com/prysmaticlabs/prysm/client/types"
|
|
pb "github.com/prysmaticlabs/prysm/proto/sharding/p2p/v1"
|
|
"github.com/prysmaticlabs/prysm/shared/p2p"
|
|
)
|
|
|
|
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) {
|
|
c := shardparams.DefaultConfig()
|
|
for i := 0; i < p*int(c.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 mockCollationFetcher struct{}
|
|
|
|
func (m *mockCollationFetcher) CollationByHeaderHash(headerHash *common.Hash) (*shardingTypes.Collation, error) {
|
|
shardID := big.NewInt(1)
|
|
chunkRoot := common.BytesToHash([]byte{})
|
|
period := big.NewInt(1)
|
|
proposerAddress := common.BytesToAddress([]byte{})
|
|
|
|
header := shardingTypes.NewCollationHeader(shardID, &chunkRoot, period, &proposerAddress, [32]byte{})
|
|
return shardingTypes.NewCollation(header, []byte{}, []*types.Transaction{}), nil
|
|
}
|
|
|
|
func (f *faultyCollationFetcher) CollationByHeaderHash(headerHash *common.Hash) (*shardingTypes.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 := pb.CollationBodyRequest{
|
|
ChunkRoot: chunkRoot.Bytes(),
|
|
ShardId: 1,
|
|
Period: 1,
|
|
ProposerAddress: proposerAddress.Bytes(),
|
|
}
|
|
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 pb.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.")
|
|
}
|
|
|
|
shardID := new(big.Int).SetUint64(goodReq.ShardId)
|
|
chunkRoot = common.BytesToHash(goodReq.ChunkRoot)
|
|
period := new(big.Int).SetUint64(goodReq.Period)
|
|
proposer := common.BytesToAddress(goodReq.ProposerAddress)
|
|
|
|
header := shardingTypes.NewCollationHeader(
|
|
shardID,
|
|
&chunkRoot,
|
|
period,
|
|
&proposer,
|
|
[32]byte{})
|
|
body := []byte{}
|
|
response, err := RespondCollationBody(goodMsg, fetcher)
|
|
if err != nil {
|
|
t.Fatalf("Could not construct collation body response: %v", err)
|
|
}
|
|
|
|
if common.BytesToHash(response.HeaderHash).Hex() != header.Hash().Hex() {
|
|
t.Errorf("Incorrect header hash received. want: %v, received: %v", header.Hash().Hex(), common.BytesToHash(response.HeaderHash).Hex())
|
|
}
|
|
|
|
if !bytes.Equal(response.Body, body) {
|
|
t.Errorf("Incorrect collation body received. want: %v, received: %v", response.Body, body)
|
|
}
|
|
}
|
|
|
|
func TestConstructAttesterRequest(t *testing.T) {
|
|
|
|
backend, smc := setup(t)
|
|
node := &mockNode{smc: smc, t: t, Backend: backend}
|
|
|
|
// Fast forward to next period.
|
|
c := shardparams.DefaultConfig()
|
|
for i := 0; i < int(c.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))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
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("constructAttesterRequest should return nil for an inexistent collation header. got: %v", err)
|
|
}
|
|
|
|
if common.BytesToHash(request.ChunkRoot).Hex() != chunkRoot.Hex() {
|
|
t.Errorf("Chunk root from attester request incorrect. want: %v, got: %v", chunkRoot.Hex(), common.BytesToHash(request.ChunkRoot).Hex())
|
|
}
|
|
|
|
if common.BytesToAddress(request.ProposerAddress).Hex() != proposerAddress.Hex() {
|
|
t.Errorf("Proposer address from attester request incorrect. want: %v, got: %v", proposerAddress.Hex(), common.BytesToAddress(request.ProposerAddress).Hex())
|
|
}
|
|
|
|
if shardID.Uint64() != request.ShardId {
|
|
t.Errorf("ShardID from attester request incorrect. want: %d, got: %d", shardID.Uint64(), request.ShardId)
|
|
}
|
|
|
|
if request.Period != period.Uint64() {
|
|
t.Errorf("Proposer address from attester request incorrect. want: %d, got: %d", period.Uint64(), request.Period)
|
|
}
|
|
}
|