mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-08 02:31:19 +00:00
86a8ec035c
* aggregation helper * lint
270 lines
7.7 KiB
Go
270 lines
7.7 KiB
Go
package helpers_test
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/prysmaticlabs/go-bitfield"
|
|
"github.com/prysmaticlabs/go-ssz"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
|
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
|
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
|
"github.com/prysmaticlabs/prysm/shared/bls"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
"github.com/prysmaticlabs/prysm/shared/testutil"
|
|
)
|
|
|
|
func TestAttestationDataSlot_OK(t *testing.T) {
|
|
deposits, _, _ := testutil.SetupInitialDeposits(t, 100)
|
|
beaconState, err := state.GenesisBeaconState(deposits, uint64(0), ðpb.Eth1Data{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
offset := uint64(0)
|
|
committeeCount, _ := helpers.CommitteeCount(beaconState, 0)
|
|
expect := offset / (committeeCount / params.BeaconConfig().SlotsPerEpoch)
|
|
attSlot, err := helpers.AttestationDataSlot(beaconState, ðpb.AttestationData{
|
|
Target: ðpb.Checkpoint{Epoch: 0},
|
|
Crosslink: ðpb.Crosslink{
|
|
Shard: 0,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if attSlot != expect {
|
|
t.Errorf("Expected %d, received %d", expect, attSlot)
|
|
}
|
|
}
|
|
|
|
func TestAttestationDataSlot_ReturnsErrorWithNilState(t *testing.T) {
|
|
s, err := helpers.AttestationDataSlot(nil /*state*/, ðpb.AttestationData{
|
|
Target: ðpb.Checkpoint{Epoch: 0},
|
|
Crosslink: ðpb.Crosslink{
|
|
Shard: 0,
|
|
},
|
|
})
|
|
if err != helpers.ErrAttestationDataSlotNilState {
|
|
t.Errorf("Expected an error, but received %v", err)
|
|
t.Logf("attestation slot=%v", s)
|
|
}
|
|
}
|
|
|
|
func TestAttestationDataSlot_ReturnsErrorWithNilData(t *testing.T) {
|
|
s, err := helpers.AttestationDataSlot(&pb.BeaconState{}, nil /*data*/)
|
|
if err != helpers.ErrAttestationDataSlotNilData {
|
|
t.Errorf("Expected an error, but received %v", err)
|
|
t.Logf("attestation slot=%v", s)
|
|
}
|
|
}
|
|
|
|
func TestAttestationDataSlot_ReturnsErrorWithErroneousTargetEpoch(t *testing.T) {
|
|
deposits, _, _ := testutil.SetupInitialDeposits(t, 100)
|
|
beaconState, err := state.GenesisBeaconState(deposits, uint64(0), ðpb.Eth1Data{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s, err := helpers.AttestationDataSlot(beaconState, ðpb.AttestationData{
|
|
Target: ðpb.Checkpoint{Epoch: 1<<63 - 1 /* Far future epoch */},
|
|
})
|
|
if err == nil {
|
|
t.Error("Expected an error, but received nil")
|
|
t.Logf("attestation slot=%v", s)
|
|
}
|
|
}
|
|
|
|
func TestAttestationDataSlot_ReturnsErrorWhenTargetEpochLessThanCurrentEpoch(t *testing.T) {
|
|
deposits, _, _ := testutil.SetupInitialDeposits(t, 100)
|
|
beaconState, err := state.GenesisBeaconState(deposits, uint64(0), ðpb.Eth1Data{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s, err := helpers.AttestationDataSlot(beaconState, ðpb.AttestationData{
|
|
Target: ðpb.Checkpoint{Epoch: 2},
|
|
})
|
|
if err == nil {
|
|
t.Error("Expected an error, but received nil")
|
|
t.Logf("attestation slot=%v", s)
|
|
}
|
|
}
|
|
|
|
func TestAggregateAttestation(t *testing.T) {
|
|
tests := []struct {
|
|
a1 *ethpb.Attestation
|
|
a2 *ethpb.Attestation
|
|
want *ethpb.Attestation
|
|
}{
|
|
{a1: ðpb.Attestation{AggregationBits: []byte{}},
|
|
a2: ðpb.Attestation{AggregationBits: []byte{}},
|
|
want: ðpb.Attestation{AggregationBits: []byte{}}},
|
|
{a1: ðpb.Attestation{AggregationBits: bitfield.Bitlist{0x03}},
|
|
a2: ðpb.Attestation{AggregationBits: bitfield.Bitlist{0x02}},
|
|
want: ðpb.Attestation{AggregationBits: []byte{0x03}}},
|
|
{a1: ðpb.Attestation{AggregationBits: bitfield.Bitlist{0x02}},
|
|
a2: ðpb.Attestation{AggregationBits: bitfield.Bitlist{0x03}},
|
|
want: ðpb.Attestation{AggregationBits: []byte{0x03}}},
|
|
}
|
|
for _, tt := range tests {
|
|
got, err := helpers.AggregateAttestation(tt.a1, tt.a2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !ssz.DeepEqual(got, tt.want) {
|
|
t.Errorf("AggregateAttestation() = %v, want %v", got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func bitlistWithAllBitsSet(length uint64) bitfield.Bitlist {
|
|
b := bitfield.NewBitlist(length)
|
|
for i := uint64(0); i < length; i++ {
|
|
b.SetBitAt(i, true)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func bitlistsWithSingleBitSet(length uint64) []bitfield.Bitlist {
|
|
lists := make([]bitfield.Bitlist, length)
|
|
for i := uint64(0); i < length; i++ {
|
|
b := bitfield.NewBitlist(length)
|
|
b.SetBitAt(i, true)
|
|
lists[i] = b
|
|
}
|
|
return lists
|
|
}
|
|
|
|
func TestAggregateAttestations(t *testing.T) {
|
|
// Each test defines the aggregation bitfield inputs and the wanted output result.
|
|
tests := []struct {
|
|
name string
|
|
inputs []bitfield.Bitlist
|
|
want []bitfield.Bitlist
|
|
}{
|
|
{
|
|
name: "two attestations with no overlap",
|
|
inputs: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00000001, 0b1},
|
|
bitfield.Bitlist{0b00000010, 0b1},
|
|
},
|
|
want: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00000011, 0b1},
|
|
},
|
|
},
|
|
{
|
|
name: "256 attestations with single bit set",
|
|
inputs: bitlistsWithSingleBitSet(256),
|
|
want: []bitfield.Bitlist{
|
|
bitlistWithAllBitsSet(256),
|
|
},
|
|
},
|
|
{
|
|
name: "1024 attestations with single bit set",
|
|
inputs: bitlistsWithSingleBitSet(1024),
|
|
want: []bitfield.Bitlist{
|
|
bitlistWithAllBitsSet(1024),
|
|
},
|
|
},
|
|
{
|
|
name: "two attestations with overlap",
|
|
inputs: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00000101, 0b1},
|
|
bitfield.Bitlist{0b00000110, 0b1},
|
|
},
|
|
want: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00000101, 0b1},
|
|
bitfield.Bitlist{0b00000110, 0b1},
|
|
},
|
|
},
|
|
{
|
|
name: "some attestations overlap",
|
|
inputs: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00001001, 0b1},
|
|
bitfield.Bitlist{0b00010110, 0b1},
|
|
bitfield.Bitlist{0b00001010, 0b1},
|
|
bitfield.Bitlist{0b00110001, 0b1},
|
|
},
|
|
want: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00111011, 0b1},
|
|
bitfield.Bitlist{0b00011111, 0b1},
|
|
},
|
|
},
|
|
{
|
|
name: "some attestations produce duplicates which are removed",
|
|
inputs: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00000101, 0b1},
|
|
bitfield.Bitlist{0b00000110, 0b1},
|
|
bitfield.Bitlist{0b00001010, 0b1},
|
|
bitfield.Bitlist{0b00001001, 0b1},
|
|
},
|
|
want: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00001111, 0b1}, // both 0&1 and 2&3 produce this bitlist
|
|
},
|
|
},
|
|
{
|
|
name: "two attestations where one is fully contained within the other",
|
|
inputs: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00000001, 0b1},
|
|
bitfield.Bitlist{0b00000011, 0b1},
|
|
},
|
|
want: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00000011, 0b1},
|
|
},
|
|
},
|
|
{
|
|
name: "two attestations where one is fully contained within the other reversed",
|
|
inputs: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00000011, 0b1},
|
|
bitfield.Bitlist{0b00000001, 0b1},
|
|
},
|
|
want: []bitfield.Bitlist{
|
|
bitfield.Bitlist{0b00000011, 0b1},
|
|
},
|
|
},
|
|
}
|
|
|
|
var makeAttestationsFromBitlists = func(bl []bitfield.Bitlist) []*ethpb.Attestation {
|
|
atts := make([]*ethpb.Attestation, len(bl))
|
|
for i, b := range bl {
|
|
sk, err := bls.RandKey(rand.Reader)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
sig := sk.Sign([]byte("dummy_test_data"), 0 /*domain*/)
|
|
atts[i] = ðpb.Attestation{
|
|
AggregationBits: b,
|
|
Data: nil,
|
|
CustodyBits: nil,
|
|
Signature: sig.Marshal(),
|
|
}
|
|
}
|
|
return atts
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := helpers.AggregateAttestations(makeAttestationsFromBitlists(tt.inputs))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sort.Slice(got, func(i, j int) bool {
|
|
return got[i].AggregationBits.Bytes()[0] < got[j].AggregationBits.Bytes()[0]
|
|
})
|
|
sort.Slice(tt.want, func(i, j int) bool {
|
|
return tt.want[i].Bytes()[0] < tt.want[j].Bytes()[0]
|
|
})
|
|
if len(got) != len(tt.want) {
|
|
t.Logf("got=%v", got)
|
|
t.Fatalf("Wrong number of responses. Got %d, wanted %d", len(got), len(tt.want))
|
|
}
|
|
for i, w := range tt.want {
|
|
if !bytes.Equal(got[i].AggregationBits.Bytes(), w.Bytes()) {
|
|
t.Errorf("Unexpected bitlist at index %d, got %b, wanted %b", i, got[i].AggregationBits.Bytes(), w.Bytes())
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|