Surround detection (#3967)

* min max span update logic

* add comment to exported method

* Update slasher/rpc/update_min_max_span.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/rpc/update_min_max_span.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/rpc/update_min_max_span.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/rpc/update_min_max_span_test.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/rpc/update_min_max_span.go

Co-Authored-By: terence tsao <terence@prysmaticlabs.com>

* Update slasher/rpc/update_min_max_span.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* weak subjectivity error

* add context

* SlasherDb change to SlasherDB

* gaz

* raul feedback

* fix old problem

* gofmt goimports

* gaz

* import fix

* change order

* min max span detection

* added benchmark

* max diff without error

* Update slasher/rpc/detect_update_min_max_span_bench_test.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/db/indexed_attestations.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/rpc/detect_update_min_max_span_bench_test.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/rpc/detect_update_min_max_span_test.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/rpc/detect_update_min_max_span.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/rpc/detect_update_min_max_span_test.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/rpc/detect_update_min_max_span_bench_test.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* raul feedback, benchmark fix

* raul feedback

* gaz

* fix merge

* bench fix

* another bench fix

* comments

* changed names of functions and proto

* name change fix

* name change fix

* fix test

* clarification comment

* change to interface

* Update proto/eth/v1alpha1/slasher.proto

Co-Authored-By: Ivan Martinez <ivanthegreatdev@gmail.com>

* Update slasher/rpc/detect_update_min_max_span.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* Update slasher/rpc/detect_update_min_max_span.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* change order to reduce confusion

* Update proto/eth/v1alpha1/slasher.proto

Co-Authored-By: terence tsao <terence@prysmaticlabs.com>

* Update slasher/rpc/detect_update_min_max_span.go

Co-Authored-By: terence tsao <terence@prysmaticlabs.com>

* Update slasher/rpc/detect_update_min_max_span.go

Co-Authored-By: terence tsao <terence@prysmaticlabs.com>

* Update slasher/rpc/detect_update_min_max_span.go

Co-Authored-By: terence tsao <terence@prysmaticlabs.com>

* Apply suggestions from code review

Co-Authored-By: terence tsao <terence@prysmaticlabs.com>

* Update slasher/rpc/detect_update_min_max_span.go

* Fix some comments

* terence feedback

* preston feedback

* fix test

* fix comments
This commit is contained in:
shayzluf
2019-11-19 01:19:39 +05:30
committed by Raul Jordan
parent 3b18aee181
commit 607f086de9
10 changed files with 615 additions and 399 deletions

View File

@@ -237,26 +237,26 @@ func (m *ProposerSlashingResponse) GetProposerSlashing() []*ProposerSlashing {
return nil
}
type MinMaxSpan struct {
MinSpan uint32 `protobuf:"varint,1,opt,name=min_span,json=minSpan,proto3" json:"min_span,omitempty"`
MaxSpan uint32 `protobuf:"varint,2,opt,name=max_span,json=maxSpan,proto3" json:"max_span,omitempty"`
type MinMaxEpochSpan struct {
MinEpochSpan uint32 `protobuf:"varint,1,opt,name=min_epoch_span,json=minEpochSpan,proto3" json:"min_epoch_span,omitempty"`
MaxEpochSpan uint32 `protobuf:"varint,2,opt,name=max_epoch_span,json=maxEpochSpan,proto3" json:"max_epoch_span,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *MinMaxSpan) Reset() { *m = MinMaxSpan{} }
func (m *MinMaxSpan) String() string { return proto.CompactTextString(m) }
func (*MinMaxSpan) ProtoMessage() {}
func (*MinMaxSpan) Descriptor() ([]byte, []int) {
func (m *MinMaxEpochSpan) Reset() { *m = MinMaxEpochSpan{} }
func (m *MinMaxEpochSpan) String() string { return proto.CompactTextString(m) }
func (*MinMaxEpochSpan) ProtoMessage() {}
func (*MinMaxEpochSpan) Descriptor() ([]byte, []int) {
return fileDescriptor_c3db2cc39857595b, []int{4}
}
func (m *MinMaxSpan) XXX_Unmarshal(b []byte) error {
func (m *MinMaxEpochSpan) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *MinMaxSpan) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
func (m *MinMaxEpochSpan) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_MinMaxSpan.Marshal(b, m, deterministic)
return xxx_messageInfo_MinMaxEpochSpan.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalTo(b)
@@ -266,37 +266,37 @@ func (m *MinMaxSpan) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return b[:n], nil
}
}
func (m *MinMaxSpan) XXX_Merge(src proto.Message) {
xxx_messageInfo_MinMaxSpan.Merge(m, src)
func (m *MinMaxEpochSpan) XXX_Merge(src proto.Message) {
xxx_messageInfo_MinMaxEpochSpan.Merge(m, src)
}
func (m *MinMaxSpan) XXX_Size() int {
func (m *MinMaxEpochSpan) XXX_Size() int {
return m.Size()
}
func (m *MinMaxSpan) XXX_DiscardUnknown() {
xxx_messageInfo_MinMaxSpan.DiscardUnknown(m)
func (m *MinMaxEpochSpan) XXX_DiscardUnknown() {
xxx_messageInfo_MinMaxEpochSpan.DiscardUnknown(m)
}
var xxx_messageInfo_MinMaxSpan proto.InternalMessageInfo
var xxx_messageInfo_MinMaxEpochSpan proto.InternalMessageInfo
func (m *MinMaxSpan) GetMinSpan() uint32 {
func (m *MinMaxEpochSpan) GetMinEpochSpan() uint32 {
if m != nil {
return m.MinSpan
return m.MinEpochSpan
}
return 0
}
func (m *MinMaxSpan) GetMaxSpan() uint32 {
func (m *MinMaxEpochSpan) GetMaxEpochSpan() uint32 {
if m != nil {
return m.MaxSpan
return m.MaxEpochSpan
}
return 0
}
type EpochSpanMap struct {
EpochSpanMap map[uint64]*MinMaxSpan `protobuf:"bytes,1,rep,name=epoch_span_map,json=epochSpanMap,proto3" json:"epoch_span_map,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
EpochSpanMap map[uint64]*MinMaxEpochSpan `protobuf:"bytes,1,rep,name=epoch_span_map,json=epochSpanMap,proto3" json:"epoch_span_map,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EpochSpanMap) Reset() { *m = EpochSpanMap{} }
@@ -332,7 +332,7 @@ func (m *EpochSpanMap) XXX_DiscardUnknown() {
var xxx_messageInfo_EpochSpanMap proto.InternalMessageInfo
func (m *EpochSpanMap) GetEpochSpanMap() map[uint64]*MinMaxSpan {
func (m *EpochSpanMap) GetEpochSpanMap() map[uint64]*MinMaxEpochSpan {
if m != nil {
return m.EpochSpanMap
}
@@ -344,54 +344,54 @@ func init() {
proto.RegisterType((*ValidatorIDToIdxAttList)(nil), "ethereum.eth.v1alpha1.ValidatorIDToIdxAttList")
proto.RegisterType((*ProposerSlashingRequest)(nil), "ethereum.eth.v1alpha1.ProposerSlashingRequest")
proto.RegisterType((*ProposerSlashingResponse)(nil), "ethereum.eth.v1alpha1.ProposerSlashingResponse")
proto.RegisterType((*MinMaxSpan)(nil), "ethereum.eth.v1alpha1.MinMaxSpan")
proto.RegisterType((*MinMaxEpochSpan)(nil), "ethereum.eth.v1alpha1.MinMaxEpochSpan")
proto.RegisterType((*EpochSpanMap)(nil), "ethereum.eth.v1alpha1.EpochSpanMap")
proto.RegisterMapType((map[uint64]*MinMaxSpan)(nil), "ethereum.eth.v1alpha1.EpochSpanMap.EpochSpanMapEntry")
proto.RegisterMapType((map[uint64]*MinMaxEpochSpan)(nil), "ethereum.eth.v1alpha1.EpochSpanMap.EpochSpanMapEntry")
}
func init() { proto.RegisterFile("proto/eth/v1alpha1/slasher.proto", fileDescriptor_c3db2cc39857595b) }
var fileDescriptor_c3db2cc39857595b = []byte{
// 616 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xc1, 0x6e, 0xd3, 0x4c,
0x10, 0xd6, 0x36, 0xfd, 0xff, 0xb6, 0x93, 0x50, 0xda, 0x45, 0x6d, 0x43, 0x8a, 0xaa, 0x60, 0x81,
0x1a, 0x71, 0xb0, 0xdb, 0xa0, 0x0a, 0x04, 0xa7, 0x06, 0x2a, 0x11, 0xd1, 0x4a, 0xc8, 0xad, 0x40,
0x2a, 0x07, 0x6b, 0x9d, 0x0c, 0xf1, 0x52, 0x7b, 0x77, 0xf1, 0x6e, 0xaa, 0xe4, 0x29, 0xb8, 0xf3,
0x44, 0xdc, 0xe0, 0x11, 0x50, 0x9f, 0x04, 0x79, 0xed, 0x34, 0xa1, 0x49, 0x50, 0xb9, 0xf9, 0x9b,
0xf9, 0x66, 0xe6, 0xf3, 0xe7, 0xf1, 0x40, 0x5d, 0xa5, 0xd2, 0x48, 0x0f, 0x4d, 0xe4, 0x5d, 0xee,
0xb3, 0x58, 0x45, 0x6c, 0xdf, 0xd3, 0x31, 0xd3, 0x11, 0xa6, 0xae, 0x4d, 0xd1, 0x0d, 0x34, 0x11,
0xa6, 0xd8, 0x4f, 0x5c, 0x34, 0x91, 0x3b, 0x22, 0xd5, 0xb6, 0x7b, 0x52, 0xf6, 0x62, 0xf4, 0x2c,
0x29, 0xec, 0x7f, 0xf2, 0x30, 0x51, 0x66, 0x98, 0xd7, 0xd4, 0x1e, 0xcf, 0xe8, 0x1a, 0x22, 0xeb,
0x48, 0x11, 0x84, 0xb1, 0xec, 0x5c, 0x14, 0xb4, 0x47, 0x33, 0x68, 0xcc, 0x18, 0xd4, 0x86, 0x19,
0x2e, 0x45, 0xce, 0x72, 0x3e, 0xc3, 0xbd, 0xf7, 0x2c, 0xe6, 0x5d, 0x66, 0x64, 0xda, 0x7e, 0x7d,
0x26, 0xdb, 0xdd, 0xc1, 0xa1, 0x31, 0xb4, 0x0a, 0x4b, 0x5c, 0x74, 0x79, 0x07, 0x75, 0x95, 0xd4,
0x4b, 0x8d, 0x45, 0x7f, 0x04, 0xe9, 0x36, 0xac, 0x74, 0x99, 0x61, 0x41, 0x2a, 0xa5, 0xa9, 0x2e,
0xd4, 0x49, 0xa3, 0xe2, 0x2f, 0x67, 0x01, 0x5f, 0x4a, 0x43, 0x1f, 0xc0, 0x8a, 0xe6, 0x3d, 0xc1,
0x4c, 0x3f, 0xc5, 0x6a, 0xc9, 0x26, 0xc7, 0x01, 0xa7, 0x07, 0x5b, 0x33, 0x66, 0x1d, 0x73, 0x6d,
0xe8, 0x31, 0x94, 0x8b, 0x01, 0x19, 0xb4, 0x33, 0xcb, 0xcd, 0x27, 0xee, 0x4c, 0x77, 0xdc, 0x19,
0x4d, 0xfc, 0xc9, 0x72, 0xe7, 0x2b, 0x81, 0xad, 0x77, 0xa9, 0x54, 0x52, 0x63, 0x7a, 0x9a, 0xf9,
0xcd, 0x45, 0xcf, 0xc7, 0x2f, 0x7d, 0xd4, 0x86, 0xbe, 0x85, 0x8a, 0x75, 0x29, 0x88, 0x90, 0x75,
0x31, 0xad, 0x92, 0x3a, 0x69, 0x94, 0x9b, 0x8d, 0x39, 0xa3, 0x5a, 0xd6, 0xd7, 0x56, 0x56, 0xf0,
0xc6, 0xf2, 0xfd, 0x72, 0x38, 0x06, 0x74, 0x17, 0xee, 0x5e, 0x8e, 0xc4, 0x04, 0x5c, 0x74, 0x71,
0x60, 0x2d, 0x59, 0xf4, 0x57, 0xaf, 0xc3, 0xed, 0x2c, 0xea, 0x28, 0xa8, 0x4e, 0x0b, 0xd2, 0x4a,
0x0a, 0x8d, 0xf4, 0x0c, 0xd6, 0x55, 0x91, 0x0b, 0x74, 0x91, 0x2c, 0x1c, 0xd8, 0x9d, 0x23, 0x6b,
0xaa, 0xd7, 0x9a, 0xba, 0x11, 0x71, 0x5a, 0x00, 0x27, 0x5c, 0x9c, 0xb0, 0xc1, 0xa9, 0x62, 0x82,
0xde, 0x87, 0xe5, 0x84, 0x8b, 0x40, 0x2b, 0x26, 0xec, 0x1b, 0xdf, 0xf1, 0x97, 0x12, 0x2e, 0xae,
0x53, 0x6c, 0x90, 0xa7, 0x16, 0x8a, 0x54, 0x5e, 0xe5, 0xfc, 0x20, 0x50, 0x39, 0x52, 0xb2, 0x13,
0x65, 0xe8, 0x84, 0x29, 0xfa, 0x11, 0x56, 0x31, 0xc3, 0x96, 0x1d, 0x24, 0x4c, 0x15, 0x3a, 0x0f,
0xe6, 0xe8, 0x9c, 0x2c, 0xfe, 0x03, 0x1c, 0x09, 0x93, 0x0e, 0xfd, 0x0a, 0x4e, 0x84, 0x6a, 0x21,
0xac, 0x4f, 0x51, 0xe8, 0x1a, 0x94, 0x2e, 0x70, 0x68, 0x35, 0x2f, 0xfa, 0xd9, 0x23, 0x7d, 0x06,
0xff, 0x5d, 0xb2, 0xb8, 0x8f, 0x56, 0x6c, 0xb9, 0xf9, 0x70, 0xce, 0xe8, 0xf1, 0xcb, 0xfb, 0x39,
0xff, 0xc5, 0xc2, 0x73, 0xd2, 0xfc, 0x56, 0x82, 0xa5, 0xd3, 0xfc, 0x0f, 0xa4, 0x08, 0x9b, 0x6d,
0x6d, 0x01, 0x0b, 0x63, 0x3c, 0x1c, 0xff, 0x1a, 0xd4, 0x99, 0xd3, 0x73, 0x82, 0x53, 0xdb, 0xfd,
0x2b, 0x67, 0xfc, 0x21, 0xa8, 0x86, 0xb5, 0x89, 0x31, 0x76, 0x95, 0xa8, 0x7b, 0xdb, 0xef, 0x9a,
0x2f, 0x6d, 0xcd, 0xbb, 0x35, 0xbf, 0xd8, 0xa9, 0x0f, 0x40, 0xaf, 0x47, 0xe6, 0x24, 0x16, 0x6b,
0xba, 0xe9, 0xe6, 0x77, 0xc5, 0x1d, 0xdd, 0x15, 0xf7, 0x28, 0xbb, 0x2b, 0xb5, 0xdb, 0xae, 0xd9,
0x1e, 0xa1, 0xe7, 0xb0, 0x31, 0xcb, 0xb2, 0x7f, 0xef, 0x7d, 0xd3, 0xa7, 0x3d, 0xd2, 0x7a, 0xf5,
0xfd, 0x6a, 0x87, 0xfc, 0xbc, 0xda, 0x21, 0xbf, 0xae, 0x76, 0xc8, 0xf9, 0x41, 0x8f, 0x9b, 0xa8,
0x1f, 0xba, 0x1d, 0x99, 0x78, 0x2a, 0x1d, 0xea, 0x84, 0x19, 0xde, 0x89, 0x59, 0xa8, 0x73, 0xe4,
0x4d, 0x9f, 0xb7, 0x97, 0x68, 0xa2, 0xf0, 0x7f, 0x1b, 0x7f, 0xfa, 0x3b, 0x00, 0x00, 0xff, 0xff,
0x96, 0x7b, 0xa2, 0x30, 0x7c, 0x05, 0x00, 0x00,
// 621 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xdd, 0x6e, 0xd3, 0x4c,
0x10, 0x95, 0x9b, 0x7e, 0x5f, 0xe9, 0x24, 0xf4, 0x67, 0x51, 0xdb, 0x28, 0x45, 0x55, 0x64, 0x15,
0x1a, 0x71, 0x61, 0xb7, 0x41, 0x95, 0x10, 0x70, 0xd3, 0x42, 0x25, 0x22, 0x5a, 0x09, 0xb9, 0x15,
0x48, 0x45, 0xc8, 0x5a, 0x27, 0x83, 0xbd, 0xd4, 0xde, 0x5d, 0xbc, 0x9b, 0x2a, 0x79, 0x0a, 0xee,
0x79, 0x22, 0x2e, 0xb9, 0xe0, 0x01, 0x50, 0x9f, 0x04, 0x79, 0xed, 0x34, 0x6e, 0x93, 0xa0, 0x72,
0xe7, 0x39, 0x73, 0xe6, 0xef, 0x78, 0x76, 0xa0, 0x29, 0x53, 0xa1, 0x85, 0x8b, 0x3a, 0x72, 0x2f,
0xf7, 0x68, 0x2c, 0x23, 0xba, 0xe7, 0xaa, 0x98, 0xaa, 0x08, 0x53, 0xc7, 0xb8, 0xc8, 0x1a, 0xea,
0x08, 0x53, 0xec, 0x27, 0x0e, 0xea, 0xc8, 0x19, 0x91, 0x1a, 0x9b, 0xa1, 0x10, 0x61, 0x8c, 0xae,
0x21, 0x05, 0xfd, 0xcf, 0x2e, 0x26, 0x52, 0x0f, 0xf3, 0x98, 0xc6, 0xa3, 0x29, 0x59, 0x03, 0xa4,
0x5d, 0xc1, 0xfd, 0x20, 0x16, 0xdd, 0x8b, 0x82, 0xb6, 0x3d, 0x85, 0x46, 0xb5, 0x46, 0xa5, 0xa9,
0x66, 0x82, 0xe7, 0x2c, 0xfb, 0x0b, 0x3c, 0x78, 0x4f, 0x63, 0xd6, 0xa3, 0x5a, 0xa4, 0x9d, 0xd7,
0x67, 0xa2, 0xd3, 0x1b, 0x1c, 0x68, 0x4d, 0xea, 0xb0, 0xc0, 0x78, 0x8f, 0x75, 0x51, 0xd5, 0xad,
0x66, 0xa5, 0x35, 0xef, 0x8d, 0x4c, 0xb2, 0x09, 0x8b, 0x3d, 0xaa, 0xa9, 0x9f, 0x0a, 0xa1, 0xeb,
0x73, 0x4d, 0xab, 0x55, 0xf3, 0xee, 0x65, 0x80, 0x27, 0x84, 0x26, 0x0f, 0x61, 0x51, 0xb1, 0x90,
0x53, 0xdd, 0x4f, 0xb1, 0x5e, 0x31, 0xce, 0x31, 0x60, 0x87, 0xb0, 0x31, 0xa5, 0xd6, 0x31, 0x53,
0x9a, 0x1c, 0x43, 0xb5, 0x28, 0x90, 0x99, 0xa6, 0x66, 0xb5, 0xfd, 0xc4, 0x99, 0xaa, 0x8e, 0x33,
0x25, 0x89, 0x57, 0x0e, 0xb7, 0xbf, 0x59, 0xb0, 0xf1, 0x2e, 0x15, 0x52, 0x28, 0x4c, 0x4f, 0x33,
0xbd, 0x19, 0x0f, 0x3d, 0xfc, 0xda, 0x47, 0xa5, 0xc9, 0x5b, 0xa8, 0x19, 0x95, 0xfc, 0x08, 0x69,
0x0f, 0xd3, 0xba, 0xd5, 0xb4, 0x5a, 0xd5, 0x76, 0x6b, 0x46, 0xa9, 0x43, 0xa3, 0xeb, 0x61, 0x16,
0xf0, 0xc6, 0xf0, 0xbd, 0x6a, 0x30, 0x36, 0xc8, 0x0e, 0x2c, 0x5f, 0x8e, 0x9a, 0xf1, 0x19, 0xef,
0xe1, 0xc0, 0x48, 0x32, 0xef, 0x2d, 0x5d, 0xc3, 0x9d, 0x0c, 0xb5, 0x25, 0xd4, 0x27, 0x1b, 0x52,
0x52, 0x70, 0x85, 0xe4, 0x0c, 0x56, 0x65, 0xe1, 0xf3, 0x55, 0xe1, 0x2c, 0x14, 0xd8, 0x99, 0xd1,
0xd6, 0x44, 0xae, 0x15, 0x79, 0x0b, 0xb1, 0x3f, 0xc1, 0xf2, 0x09, 0xe3, 0x27, 0x74, 0x70, 0x24,
0x45, 0x37, 0x3a, 0x95, 0x94, 0x93, 0x6d, 0x58, 0x4a, 0x18, 0xf7, 0x31, 0x03, 0x7c, 0x25, 0x29,
0x37, 0xc3, 0xdf, 0xf7, 0x6a, 0x09, 0xe3, 0x37, 0x59, 0x74, 0x50, 0x66, 0xcd, 0x15, 0xac, 0x52,
0x2e, 0xfb, 0x97, 0x05, 0xb5, 0x6b, 0xeb, 0x84, 0x4a, 0xf2, 0x11, 0x96, 0xc6, 0x21, 0x7e, 0x42,
0x65, 0x31, 0xc2, 0xfe, 0x8c, 0x11, 0xca, 0xc1, 0x37, 0x8c, 0x23, 0xae, 0xd3, 0xa1, 0x57, 0xc3,
0x12, 0xd4, 0x08, 0x61, 0x75, 0x82, 0x42, 0x56, 0xa0, 0x72, 0x81, 0x43, 0x33, 0xc3, 0xbc, 0x97,
0x7d, 0x92, 0x97, 0xf0, 0xdf, 0x25, 0x8d, 0xfb, 0x68, 0x3a, 0xae, 0xb6, 0x1f, 0xcf, 0x28, 0x7d,
0x4b, 0x17, 0x2f, 0x0f, 0x7a, 0x3e, 0xf7, 0xcc, 0x6a, 0x7f, 0xaf, 0xc0, 0xc2, 0x69, 0xfe, 0x42,
0x09, 0xc2, 0x7a, 0x47, 0x19, 0x83, 0x06, 0x31, 0x1e, 0x8c, 0x9f, 0x0e, 0xb1, 0x67, 0x24, 0x2e,
0x71, 0x1a, 0x3b, 0x7f, 0xe5, 0x8c, 0x7f, 0x14, 0x51, 0xb0, 0x52, 0x2a, 0x63, 0x56, 0x8d, 0x38,
0x77, 0xfd, 0xef, 0xf9, 0x52, 0x37, 0xdc, 0x3b, 0xf3, 0x8b, 0x9d, 0xfb, 0x00, 0xe4, 0xba, 0x64,
0x4e, 0xa2, 0xb1, 0x22, 0xeb, 0x4e, 0x7e, 0x77, 0x9c, 0xd1, 0xdd, 0x71, 0x8e, 0xb2, 0xbb, 0xd3,
0xb8, 0xeb, 0x1a, 0xee, 0x5a, 0xe4, 0x1c, 0xd6, 0xa6, 0x49, 0xf6, 0xef, 0xb9, 0x6f, 0xeb, 0xb4,
0x6b, 0x1d, 0xbe, 0xfa, 0x71, 0xb5, 0x65, 0xfd, 0xbc, 0xda, 0xb2, 0x7e, 0x5f, 0x6d, 0x59, 0xe7,
0xfb, 0x21, 0xd3, 0x51, 0x3f, 0x70, 0xba, 0x22, 0x71, 0x65, 0x3a, 0x54, 0x09, 0xd5, 0xac, 0x1b,
0xd3, 0x40, 0xe5, 0x96, 0x3b, 0x79, 0xfe, 0x5e, 0xa0, 0x8e, 0x82, 0xff, 0x0d, 0xfe, 0xf4, 0x4f,
0x00, 0x00, 0x00, 0xff, 0xff, 0x8c, 0xe8, 0x23, 0xe5, 0x9c, 0x05, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -772,7 +772,7 @@ func (m *ProposerSlashingResponse) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *MinMaxSpan) Marshal() (dAtA []byte, err error) {
func (m *MinMaxEpochSpan) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
@@ -782,20 +782,20 @@ func (m *MinMaxSpan) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
func (m *MinMaxSpan) MarshalTo(dAtA []byte) (int, error) {
func (m *MinMaxEpochSpan) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.MinSpan != 0 {
if m.MinEpochSpan != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintSlasher(dAtA, i, uint64(m.MinSpan))
i = encodeVarintSlasher(dAtA, i, uint64(m.MinEpochSpan))
}
if m.MaxSpan != 0 {
if m.MaxEpochSpan != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintSlasher(dAtA, i, uint64(m.MaxSpan))
i = encodeVarintSlasher(dAtA, i, uint64(m.MaxEpochSpan))
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
@@ -942,17 +942,17 @@ func (m *ProposerSlashingResponse) Size() (n int) {
return n
}
func (m *MinMaxSpan) Size() (n int) {
func (m *MinMaxEpochSpan) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.MinSpan != 0 {
n += 1 + sovSlasher(uint64(m.MinSpan))
if m.MinEpochSpan != 0 {
n += 1 + sovSlasher(uint64(m.MinEpochSpan))
}
if m.MaxSpan != 0 {
n += 1 + sovSlasher(uint64(m.MaxSpan))
if m.MaxEpochSpan != 0 {
n += 1 + sovSlasher(uint64(m.MaxEpochSpan))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
@@ -1481,7 +1481,7 @@ func (m *ProposerSlashingResponse) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *MinMaxSpan) Unmarshal(dAtA []byte) error {
func (m *MinMaxEpochSpan) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -1504,17 +1504,17 @@ func (m *MinMaxSpan) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: MinMaxSpan: wiretype end group for non-group")
return fmt.Errorf("proto: MinMaxEpochSpan: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: MinMaxSpan: illegal tag %d (wire type %d)", fieldNum, wire)
return fmt.Errorf("proto: MinMaxEpochSpan: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field MinSpan", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field MinEpochSpan", wireType)
}
m.MinSpan = 0
m.MinEpochSpan = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSlasher
@@ -1524,16 +1524,16 @@ func (m *MinMaxSpan) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
m.MinSpan |= uint32(b&0x7F) << shift
m.MinEpochSpan |= uint32(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field MaxSpan", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field MaxEpochSpan", wireType)
}
m.MaxSpan = 0
m.MaxEpochSpan = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSlasher
@@ -1543,7 +1543,7 @@ func (m *MinMaxSpan) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
m.MaxSpan |= uint32(b&0x7F) << shift
m.MaxEpochSpan |= uint32(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -1632,10 +1632,10 @@ func (m *EpochSpanMap) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
if m.EpochSpanMap == nil {
m.EpochSpanMap = make(map[uint64]*MinMaxSpan)
m.EpochSpanMap = make(map[uint64]*MinMaxEpochSpan)
}
var mapkey uint64
var mapvalue *MinMaxSpan
var mapvalue *MinMaxEpochSpan
for iNdEx < postIndex {
entryPreIndex := iNdEx
var wire uint64
@@ -1695,7 +1695,7 @@ func (m *EpochSpanMap) Unmarshal(dAtA []byte) error {
if postmsgIndex > l {
return io.ErrUnexpectedEOF
}
mapvalue = &MinMaxSpan{}
mapvalue = &MinMaxEpochSpan{}
if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil {
return err
}

View File

@@ -51,13 +51,15 @@ message ProposerSlashingResponse {
// each attestation source to those spans
// see https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
// for further details.
message MinMaxSpan {
uint32 min_span = 1;
uint32 max_span = 2;
message MinMaxEpochSpan {
uint32 min_epoch_span = 1;
uint32 max_epoch_span = 2;
}
// every validator will have his own spans map containing min and max value for each epoch
// in order to detect slashable attestation as quick as possible.
// Every validator will have their own spans map containing min distance from each epoch
// to the closest target epoch of another attestation (surrounded) and max distance to
// a target attestation (surrounding), in order to detect slashable attestation as quickly
// as possible.
message EpochSpanMap {
// uint64 is for storing the epoch
map<uint64, MinMaxSpan> epoch_span_map = 1;
map<uint64, MinMaxEpochSpan> epoch_span_map = 1;
}

View File

@@ -33,7 +33,7 @@ func (db *Store) ValidatorSpansMap(validatorIdx uint64) (*ethpb.EpochSpanMap, er
return nil
})
if sm.EpochSpanMap == nil {
sm.EpochSpanMap = make(map[uint64]*ethpb.MinMaxSpan)
sm.EpochSpanMap = make(map[uint64]*ethpb.MinMaxEpochSpan)
}
return sm, err
}

View File

@@ -20,30 +20,30 @@ func init() {
{
validatorIdx: 1,
spanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxSpan{
1: {MinSpan: 10, MaxSpan: 20},
2: {MinSpan: 11, MaxSpan: 21},
3: {MinSpan: 12, MaxSpan: 22},
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
1: {MinEpochSpan: 10, MaxEpochSpan: 20},
2: {MinEpochSpan: 11, MaxEpochSpan: 21},
3: {MinEpochSpan: 12, MaxEpochSpan: 22},
},
},
},
{
validatorIdx: 2,
spanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxSpan{
1: {MinSpan: 10, MaxSpan: 20},
2: {MinSpan: 11, MaxSpan: 21},
3: {MinSpan: 12, MaxSpan: 22},
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
1: {MinEpochSpan: 10, MaxEpochSpan: 20},
2: {MinEpochSpan: 11, MaxEpochSpan: 21},
3: {MinEpochSpan: 12, MaxEpochSpan: 22},
},
},
},
{
validatorIdx: 3,
spanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxSpan{
1: {MinSpan: 10, MaxSpan: 20},
2: {MinSpan: 11, MaxSpan: 21},
3: {MinSpan: 12, MaxSpan: 22},
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
1: {MinEpochSpan: 10, MaxEpochSpan: 20},
2: {MinEpochSpan: 11, MaxEpochSpan: 21},
3: {MinEpochSpan: 12, MaxEpochSpan: 22},
},
},
},
@@ -59,7 +59,7 @@ func TestValidatorSpanMap_NilDB(t *testing.T) {
if err != nil {
t.Fatalf("Nil ValidatorSpansMap should not return error: %v", err)
}
if !reflect.DeepEqual(vsm.EpochSpanMap, map[uint64]*ethpb.MinMaxSpan{}) {
if !reflect.DeepEqual(vsm.EpochSpanMap, map[uint64]*ethpb.MinMaxEpochSpan{}) {
t.Fatal("ValidatorSpansMap should return nil")
}
}
@@ -111,7 +111,7 @@ func TestValidatorSpanMap_Delete(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(sm.EpochSpanMap, map[uint64]*ethpb.MinMaxSpan{}) {
if !reflect.DeepEqual(sm.EpochSpanMap, map[uint64]*ethpb.MinMaxEpochSpan{}) {
t.Errorf("Expected validator span map to be deleted, received: %v", sm)
}
}

View File

@@ -3,8 +3,8 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"detect_update_min_max_span.go",
"server.go",
"update_min_max_span.go",
],
importpath = "github.com/prysmaticlabs/prysm/slasher/rpc",
visibility = ["//visibility:public"],
@@ -24,8 +24,8 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"detect_update_min_max_span_test.go",
"server_test.go",
"update_min_max_span_test.go",
],
embed = [":go_default_library"],
deps = [
@@ -35,3 +35,25 @@ go_test(
"@com_github_gogo_protobuf//proto:go_default_library",
],
)
# gazelle:exclude detect_update_min_max_span_bench_test.go
go_test(
name = "go_benchmark_test",
size = "medium",
srcs = ["detect_update_min_max_span_bench_test.go"],
args = [
"-test.bench=.",
"-test.benchmem",
"-test.v",
],
embed = [":go_default_library"],
local = True,
tags = [
"benchmark",
"manual",
"no-cache",
],
deps = [
"//slasher/db:go_default_library",
],
)

View File

@@ -0,0 +1,127 @@
package rpc
import (
"context"
"fmt"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params"
)
// Detector is a function type used to implement the slashable surrounding/surrounded
// vote detection methods.
type detectFn = func(attestationEpochSpan uint64, recorderEpochSpan *ethpb.MinMaxEpochSpan, sourceEpoch uint64) uint64
// detectMax is a function for maxDetector used to detect surrounding attestations.
func detectMax(
attestationEpochSpan uint64,
recorderEpochSpan *ethpb.MinMaxEpochSpan,
attestationSourceEpoch uint64) uint64 {
maxSpan := uint64(recorderEpochSpan.MaxEpochSpan)
if maxSpan > attestationEpochSpan {
return maxSpan + attestationSourceEpoch
}
return 0
}
// detectMin is a function for minDetecter used to detect surrounded attestations.
func detectMin(attestationEpochSpan uint64,
recorderEpochSpan *ethpb.MinMaxEpochSpan,
attestationSourceEpoch uint64) uint64 {
minSpan := uint64(recorderEpochSpan.MinEpochSpan)
if minSpan < attestationEpochSpan {
return minSpan + attestationSourceEpoch
}
return 0
}
// DetectAndUpdateMaxEpochSpan is used to detect and update the max span of an incoming attestation.
// This is used for detecting surrounding votes.
// The max span is the span between the current attestation's source epoch and the furthest attestation's
// target epoch that has a lower (earlier) source epoch.
// Logic for this detection method was designed by https://github.com/protolambda
// Detailed here: https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
func (ss *Server) DetectAndUpdateMaxEpochSpan(ctx context.Context, source uint64, target uint64, validatorIdx uint64) (uint64, error) {
targetEpoch, span, spanMap, err := ss.detectSlashingByEpochSpan(source, target, validatorIdx, detectMax)
if err != nil {
return 0, err
}
if targetEpoch > 0 {
return targetEpoch, nil
}
for i := uint64(1); i < target-source; i++ {
val := uint32(span - i - 1)
if _, ok := spanMap.EpochSpanMap[source+i]; !ok {
spanMap.EpochSpanMap[source+i] = &ethpb.MinMaxEpochSpan{}
}
if spanMap.EpochSpanMap[source+i].MaxEpochSpan < val {
spanMap.EpochSpanMap[source+i].MaxEpochSpan = val
} else {
break
}
}
if err := ss.SlasherDB.SaveValidatorSpansMap(validatorIdx, spanMap); err != nil {
return 0, err
}
return 0, nil
}
// DetectAndUpdateMinEpochSpan is used to detect surrounded votes and update the min epoch span
// of an incoming attestation.
// The min span is the span between the current attestations target epoch and the
// closest attestation's target distance.
//
// Logic is following the detection method designed by https://github.com/protolambda
// Detailed here: https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
func (ss *Server) DetectAndUpdateMinEpochSpan(ctx context.Context, source uint64, target uint64, validatorIdx uint64) (uint64, error) {
targetEpoch, _, spanMap, err := ss.detectSlashingByEpochSpan(source, target, validatorIdx, detectMin)
if err != nil {
return 0, err
}
if targetEpoch > 0 {
return targetEpoch, nil
}
if source == 0 {
return 0, nil
}
for i := source - 1; i > 0; i-- {
val := uint32(target - (i))
if _, ok := spanMap.EpochSpanMap[i]; !ok {
spanMap.EpochSpanMap[i] = &ethpb.MinMaxEpochSpan{}
}
if spanMap.EpochSpanMap[i].MinEpochSpan == 0 || spanMap.EpochSpanMap[i].MinEpochSpan > val {
spanMap.EpochSpanMap[i].MinEpochSpan = val
} else {
break
}
}
if err := ss.SlasherDB.SaveValidatorSpansMap(validatorIdx, spanMap); err != nil {
return 0, errors.Wrap(err, "could not save validator spans")
}
return 0, nil
}
// detectSlashingByEpochSpan is used to detect if a slashable event is present
// in the db by checking either the closest attestation target or the furthest
// attestation target. This method receives a detector function in order to be used
// for both surrounding and surrounded vote cases.
func (ss *Server) detectSlashingByEpochSpan(source, target, validatorIdx uint64, detector detectFn) (uint64, uint64, *ethpb.EpochSpanMap, error) {
span := target - source + 1
if span > params.BeaconConfig().WeakSubjectivityPeriod {
return 0, span, nil, fmt.Errorf("target: %d - source: %d > weakSubjectivityPeriod",
params.BeaconConfig().WeakSubjectivityPeriod,
span,
)
}
spanMap, err := ss.SlasherDB.ValidatorSpansMap(validatorIdx)
if err != nil {
return 0, span, nil, errors.Wrapf(err, "could not retrieve span map for validator index: %d", validatorIdx)
}
if _, ok := spanMap.EpochSpanMap[source]; ok {
return detector(span, spanMap.EpochSpanMap[source], source), span, spanMap, nil
}
return 0, span, spanMap, nil
}

View File

@@ -0,0 +1,81 @@
package rpc
import (
"context"
"fmt"
"testing"
"github.com/prysmaticlabs/prysm/slasher/db"
)
func BenchmarkMinSpan(b *testing.B) {
diffs := []uint64{2, 10, 100, 1000, 10000, 53999}
dbs := db.SetupSlasherDB(b)
defer db.TeardownSlasherDB(b, dbs)
ctx := context.Background()
slasherServer := &Server{
SlasherDB: dbs,
}
for _, diff := range diffs {
b.Run(fmt.Sprintf("MinSpan_diff_%d", diff), func(ib *testing.B) {
for i := uint64(0); i < uint64(ib.N); i++ {
_, err := slasherServer.DetectAndUpdateMinEpochSpan(ctx, i, i+diff, i%10)
if err != nil {
b.Fatal(err)
}
}
})
}
}
func BenchmarkMaxSpan(b *testing.B) {
diffs := []uint64{2, 10, 100, 1000, 10000, 53999}
dbs := db.SetupSlasherDB(b)
defer db.TeardownSlasherDB(b, dbs)
ctx := context.Background()
slasherServer := &Server{
SlasherDB: dbs,
}
for _, diff := range diffs {
b.Run(fmt.Sprintf("MaxSpan_diff_%d", diff), func(ib *testing.B) {
for i := uint64(0); i < uint64(ib.N); i++ {
_, err := slasherServer.DetectAndUpdateMaxEpochSpan(ctx, diff, diff+i, i%10)
if err != nil {
b.Fatal(err)
}
}
})
}
}
func BenchmarkDetectSpan(b *testing.B) {
diffs := []uint64{2, 10, 100, 1000, 10000, 53999}
dbs := db.SetupSlasherDB(b)
defer db.TeardownSlasherDB(b, dbs)
slasherServer := &Server{
SlasherDB: dbs,
}
for _, diff := range diffs {
b.Run(fmt.Sprintf("Detect_MaxSpan_diff_%d", diff), func(ib *testing.B) {
for i := uint64(0); i < uint64(ib.N); i++ {
_, _, _, err := slasherServer.detectSlashingByEpochSpan(i, i+diff, i%10, detectMax)
if err != nil {
b.Fatal(err)
}
}
})
}
for _, diff := range diffs {
b.Run(fmt.Sprintf("Detect_MinSpan_diff_%d", diff), func(ib *testing.B) {
for i := uint64(0); i < uint64(ib.N); i++ {
_, _, _, err := slasherServer.detectSlashingByEpochSpan(i, i+diff, i%10, detectMin)
if err != nil {
b.Fatal(err)
}
}
})
}
}

View File

@@ -0,0 +1,270 @@
package rpc
import (
"context"
"testing"
"github.com/gogo/protobuf/proto"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/slasher/db"
)
type spanMapTestStruct struct {
validatorIdx uint64
sourceEpoch uint64
targetEpoch uint64
slashingTargetEpoch uint64
resultSpanMap *ethpb.EpochSpanMap
}
var spanTestsMax []spanMapTestStruct
var spanTestsMin []spanMapTestStruct
func init() {
// Test data following example of a max span by https://github.com/protolambda
// from here: https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
spanTestsMax = []spanMapTestStruct{
{
validatorIdx: 0,
sourceEpoch: 3,
targetEpoch: 6,
slashingTargetEpoch: 0,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
4: {MinEpochSpan: 0, MaxEpochSpan: 2},
5: {MinEpochSpan: 0, MaxEpochSpan: 1},
},
},
},
{
validatorIdx: 0,
sourceEpoch: 8,
targetEpoch: 18,
slashingTargetEpoch: 0,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
4: {MinEpochSpan: 0, MaxEpochSpan: 2},
5: {MinEpochSpan: 0, MaxEpochSpan: 1},
9: {MinEpochSpan: 0, MaxEpochSpan: 9},
10: {MinEpochSpan: 0, MaxEpochSpan: 8},
11: {MinEpochSpan: 0, MaxEpochSpan: 7},
12: {MinEpochSpan: 0, MaxEpochSpan: 6},
13: {MinEpochSpan: 0, MaxEpochSpan: 5},
14: {MinEpochSpan: 0, MaxEpochSpan: 4},
15: {MinEpochSpan: 0, MaxEpochSpan: 3},
16: {MinEpochSpan: 0, MaxEpochSpan: 2},
17: {MinEpochSpan: 0, MaxEpochSpan: 1},
},
},
},
{
validatorIdx: 0,
sourceEpoch: 4,
targetEpoch: 12,
slashingTargetEpoch: 0,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
4: {MinEpochSpan: 0, MaxEpochSpan: 2},
5: {MinEpochSpan: 0, MaxEpochSpan: 7},
6: {MinEpochSpan: 0, MaxEpochSpan: 6},
7: {MinEpochSpan: 0, MaxEpochSpan: 5},
8: {MinEpochSpan: 0, MaxEpochSpan: 4},
9: {MinEpochSpan: 0, MaxEpochSpan: 9},
10: {MinEpochSpan: 0, MaxEpochSpan: 8},
11: {MinEpochSpan: 0, MaxEpochSpan: 7},
12: {MinEpochSpan: 0, MaxEpochSpan: 6},
13: {MinEpochSpan: 0, MaxEpochSpan: 5},
14: {MinEpochSpan: 0, MaxEpochSpan: 4},
15: {MinEpochSpan: 0, MaxEpochSpan: 3},
16: {MinEpochSpan: 0, MaxEpochSpan: 2},
17: {MinEpochSpan: 0, MaxEpochSpan: 1},
},
},
},
{
validatorIdx: 0,
sourceEpoch: 10,
targetEpoch: 15,
slashingTargetEpoch: 18,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
4: {MinEpochSpan: 0, MaxEpochSpan: 2},
5: {MinEpochSpan: 0, MaxEpochSpan: 7},
6: {MinEpochSpan: 0, MaxEpochSpan: 6},
7: {MinEpochSpan: 0, MaxEpochSpan: 5},
8: {MinEpochSpan: 0, MaxEpochSpan: 4},
9: {MinEpochSpan: 0, MaxEpochSpan: 9},
10: {MinEpochSpan: 0, MaxEpochSpan: 8},
11: {MinEpochSpan: 0, MaxEpochSpan: 7},
12: {MinEpochSpan: 0, MaxEpochSpan: 6},
13: {MinEpochSpan: 0, MaxEpochSpan: 5},
14: {MinEpochSpan: 0, MaxEpochSpan: 4},
15: {MinEpochSpan: 0, MaxEpochSpan: 3},
16: {MinEpochSpan: 0, MaxEpochSpan: 2},
17: {MinEpochSpan: 0, MaxEpochSpan: 1},
},
},
},
}
spanTestsMin = []spanMapTestStruct{
{
validatorIdx: 0,
sourceEpoch: 4,
targetEpoch: 6,
slashingTargetEpoch: 0,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
1: {MinEpochSpan: 5, MaxEpochSpan: 0},
2: {MinEpochSpan: 4, MaxEpochSpan: 0},
3: {MinEpochSpan: 3, MaxEpochSpan: 0},
},
},
},
{
validatorIdx: 0,
sourceEpoch: 13,
targetEpoch: 18,
slashingTargetEpoch: 0,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
1: {MinEpochSpan: 5, MaxEpochSpan: 0},
2: {MinEpochSpan: 4, MaxEpochSpan: 0},
3: {MinEpochSpan: 3, MaxEpochSpan: 0},
4: {MinEpochSpan: 14, MaxEpochSpan: 0},
5: {MinEpochSpan: 13, MaxEpochSpan: 0},
6: {MinEpochSpan: 12, MaxEpochSpan: 0},
7: {MinEpochSpan: 11, MaxEpochSpan: 0},
8: {MinEpochSpan: 10, MaxEpochSpan: 0},
9: {MinEpochSpan: 9, MaxEpochSpan: 0},
10: {MinEpochSpan: 8, MaxEpochSpan: 0},
11: {MinEpochSpan: 7, MaxEpochSpan: 0},
12: {MinEpochSpan: 6, MaxEpochSpan: 0},
},
},
},
{
validatorIdx: 0,
sourceEpoch: 11,
targetEpoch: 15,
slashingTargetEpoch: 0,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
1: {MinEpochSpan: 5, MaxEpochSpan: 0},
2: {MinEpochSpan: 4, MaxEpochSpan: 0},
3: {MinEpochSpan: 3, MaxEpochSpan: 0},
4: {MinEpochSpan: 11, MaxEpochSpan: 0},
5: {MinEpochSpan: 10, MaxEpochSpan: 0},
6: {MinEpochSpan: 9, MaxEpochSpan: 0},
7: {MinEpochSpan: 8, MaxEpochSpan: 0},
8: {MinEpochSpan: 7, MaxEpochSpan: 0},
9: {MinEpochSpan: 6, MaxEpochSpan: 0},
10: {MinEpochSpan: 5, MaxEpochSpan: 0},
11: {MinEpochSpan: 7, MaxEpochSpan: 0},
12: {MinEpochSpan: 6, MaxEpochSpan: 0},
},
},
},
{
validatorIdx: 0,
sourceEpoch: 10,
targetEpoch: 20,
slashingTargetEpoch: 15,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
1: {MinEpochSpan: 5, MaxEpochSpan: 0},
2: {MinEpochSpan: 4, MaxEpochSpan: 0},
3: {MinEpochSpan: 3, MaxEpochSpan: 0},
4: {MinEpochSpan: 11, MaxEpochSpan: 0},
5: {MinEpochSpan: 10, MaxEpochSpan: 0},
6: {MinEpochSpan: 9, MaxEpochSpan: 0},
7: {MinEpochSpan: 8, MaxEpochSpan: 0},
8: {MinEpochSpan: 7, MaxEpochSpan: 0},
9: {MinEpochSpan: 6, MaxEpochSpan: 0},
10: {MinEpochSpan: 5, MaxEpochSpan: 0},
11: {MinEpochSpan: 7, MaxEpochSpan: 0},
12: {MinEpochSpan: 6, MaxEpochSpan: 0},
},
},
},
}
}
func TestServer_UpdateMaxEpochSpan(t *testing.T) {
dbs := db.SetupSlasherDB(t)
defer db.TeardownSlasherDB(t, dbs)
ctx := context.Background()
slasherServer := &Server{
SlasherDB: dbs,
}
for _, tt := range spanTestsMax {
st, err := slasherServer.DetectAndUpdateMaxEpochSpan(ctx, tt.sourceEpoch, tt.targetEpoch, tt.validatorIdx)
if err != nil {
t.Fatalf("Failed to update span: %v", err)
}
if st != tt.slashingTargetEpoch {
t.Fatalf("Expected slashing target: %d got: %v", tt.slashingTargetEpoch, st)
}
sm, err := slasherServer.SlasherDB.ValidatorSpansMap(tt.validatorIdx)
if err != nil {
t.Fatalf("Failed to retrieve span: %v", err)
}
if sm == nil || !proto.Equal(sm, tt.resultSpanMap) {
t.Fatalf("Get should return validator span map: %v got: %v", tt.resultSpanMap, sm)
}
}
}
func TestServer_UpdateMinEpochSpan(t *testing.T) {
dbs := db.SetupSlasherDB(t)
defer db.TeardownSlasherDB(t, dbs)
ctx := context.Background()
slasherServer := &Server{
SlasherDB: dbs,
}
for _, tt := range spanTestsMin {
st, err := slasherServer.DetectAndUpdateMinEpochSpan(ctx, tt.sourceEpoch, tt.targetEpoch, tt.validatorIdx)
if err != nil {
t.Fatalf("Failed to update span: %v", err)
}
if st != tt.slashingTargetEpoch {
t.Fatalf("Expected slashing target: %v got: %v", tt.slashingTargetEpoch, st)
}
sm, err := slasherServer.SlasherDB.ValidatorSpansMap(tt.validatorIdx)
if err != nil {
t.Fatalf("Failed to retrieve span: %v", err)
}
if sm == nil || !proto.Equal(sm, tt.resultSpanMap) {
t.Fatalf("Get should return validator span map: %v got: %v", tt.resultSpanMap, sm)
}
}
}
func TestServer_FailToUpdate(t *testing.T) {
dbs := db.SetupSlasherDB(t)
defer db.TeardownSlasherDB(t, dbs)
ctx := context.Background()
slasherServer := &Server{
SlasherDB: dbs,
}
spanTestsFail := spanMapTestStruct{
validatorIdx: 0,
sourceEpoch: 0,
slashingTargetEpoch: 0,
targetEpoch: params.BeaconConfig().WeakSubjectivityPeriod + 1,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxEpochSpan{
4: {MinEpochSpan: 0, MaxEpochSpan: 2},
5: {MinEpochSpan: 0, MaxEpochSpan: 1},
},
},
}
if _, err := slasherServer.DetectAndUpdateMinEpochSpan(ctx, spanTestsFail.sourceEpoch, spanTestsFail.targetEpoch, spanTestsFail.validatorIdx); err == nil {
t.Fatalf("Update should not support diff greater then weak subjectivity period: %v ", params.BeaconConfig().WeakSubjectivityPeriod)
}
if _, err := slasherServer.DetectAndUpdateMaxEpochSpan(ctx, spanTestsFail.sourceEpoch, spanTestsFail.targetEpoch, spanTestsFail.validatorIdx); err == nil {
t.Fatalf("Update should not support diff greater then weak subjectivity period: %v ", params.BeaconConfig().WeakSubjectivityPeriod)
}
}

View File

@@ -1,74 +0,0 @@
package rpc
import (
"context"
"fmt"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params"
)
// UpdateMaxSpan is used to update the max span of an incoming attestation after the slashing detection phase.
// logic is following the detection method designed by https://github.com/protolambda
// from here: https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
func (ss *Server) UpdateMaxSpan(ctx context.Context, source uint64, target uint64, validatorIdx uint64) error {
diff := target - source
if diff > params.BeaconConfig().WeakSubjectivityPeriod {
return fmt.Errorf("%d target - source: %d > weakSubjectivityPeriod",
params.BeaconConfig().WeakSubjectivityPeriod,
diff,
)
}
spanMap, err := ss.SlasherDB.ValidatorSpansMap(validatorIdx)
if err != nil {
return errors.Wrapf(err, "could not retrieve span map for validatorIdx: %v", validatorIdx)
}
for i := uint64(1); i < target-source; i++ {
val := uint32(diff - i)
if spanMap.EpochSpanMap[source+i] == nil {
spanMap.EpochSpanMap[source+i] = &ethpb.MinMaxSpan{MinSpan: 0, MaxSpan: 0}
}
if spanMap.EpochSpanMap[source+i].MaxSpan < val {
spanMap.EpochSpanMap[source+i].MaxSpan = val
} else {
break
}
}
if err := ss.SlasherDB.SaveValidatorSpansMap(validatorIdx, spanMap); err != nil {
return err
}
return nil
}
// UpdateMinSpan is used to update the min span of an incoming attestation after the slashing detection phase.
// logic is following the detection method designed by https://github.com/protolambda
// from here: https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
func (ss *Server) UpdateMinSpan(ctx context.Context, source uint64, target uint64, validatorIdx uint64) error {
diff := target - source
if diff > params.BeaconConfig().WeakSubjectivityPeriod {
return fmt.Errorf("%d target - source: %d > weakSubjectivityPeriod",
params.BeaconConfig().WeakSubjectivityPeriod,
diff,
)
}
spanMap, err := ss.SlasherDB.ValidatorSpansMap(validatorIdx)
if err != nil {
return errors.Wrapf(err, "could not retrieve span map for validatorIdx: %d", validatorIdx)
}
for i := source - 1; i > 0; i-- {
val := uint32(target - (i))
if spanMap.EpochSpanMap[i] == nil {
spanMap.EpochSpanMap[i] = &ethpb.MinMaxSpan{MinSpan: 0, MaxSpan: 0}
}
if spanMap.EpochSpanMap[i].MinSpan == 0 || spanMap.EpochSpanMap[i].MinSpan > val {
spanMap.EpochSpanMap[i].MinSpan = val
} else {
break
}
}
if err := ss.SlasherDB.SaveValidatorSpansMap(validatorIdx, spanMap); err != nil {
errors.Wrap(err, "could not save validator spans")
}
return nil
}

View File

@@ -1,212 +0,0 @@
package rpc
import (
"context"
"testing"
"github.com/gogo/protobuf/proto"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/slasher/db"
)
type spanMapTestStruct struct {
validatorIdx uint64
sourceEpoch uint64
targetEpoch uint64
resultSpanMap *ethpb.EpochSpanMap
}
var spanTestsMax []spanMapTestStruct
var spanTestsMin []spanMapTestStruct
var spanTestsFail []spanMapTestStruct
func init() {
// Test data following example of a max span by https://github.com/protolambda
// from here: https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
spanTestsMax = []spanMapTestStruct{
{
validatorIdx: 0,
sourceEpoch: 3,
targetEpoch: 6,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxSpan{
4: {MinSpan: 0, MaxSpan: 2},
5: {MinSpan: 0, MaxSpan: 1},
},
},
},
{
validatorIdx: 0,
sourceEpoch: 8,
targetEpoch: 18,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxSpan{
4: {MinSpan: 0, MaxSpan: 2},
5: {MinSpan: 0, MaxSpan: 1},
9: {MinSpan: 0, MaxSpan: 9},
10: {MinSpan: 0, MaxSpan: 8},
11: {MinSpan: 0, MaxSpan: 7},
12: {MinSpan: 0, MaxSpan: 6},
13: {MinSpan: 0, MaxSpan: 5},
14: {MinSpan: 0, MaxSpan: 4},
15: {MinSpan: 0, MaxSpan: 3},
16: {MinSpan: 0, MaxSpan: 2},
17: {MinSpan: 0, MaxSpan: 1},
},
},
},
{
validatorIdx: 0,
sourceEpoch: 4,
targetEpoch: 12,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxSpan{
4: {MinSpan: 0, MaxSpan: 2},
5: {MinSpan: 0, MaxSpan: 7},
6: {MinSpan: 0, MaxSpan: 6},
7: {MinSpan: 0, MaxSpan: 5},
8: {MinSpan: 0, MaxSpan: 4},
9: {MinSpan: 0, MaxSpan: 9},
10: {MinSpan: 0, MaxSpan: 8},
11: {MinSpan: 0, MaxSpan: 7},
12: {MinSpan: 0, MaxSpan: 6},
13: {MinSpan: 0, MaxSpan: 5},
14: {MinSpan: 0, MaxSpan: 4},
15: {MinSpan: 0, MaxSpan: 3},
16: {MinSpan: 0, MaxSpan: 2},
17: {MinSpan: 0, MaxSpan: 1},
},
},
},
}
spanTestsMin = []spanMapTestStruct{
{
validatorIdx: 0,
sourceEpoch: 4,
targetEpoch: 6,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxSpan{
1: {MinSpan: 5, MaxSpan: 0},
2: {MinSpan: 4, MaxSpan: 0},
3: {MinSpan: 3, MaxSpan: 0},
},
},
},
{
validatorIdx: 0,
sourceEpoch: 13,
targetEpoch: 18,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxSpan{
1: {MinSpan: 5, MaxSpan: 0},
2: {MinSpan: 4, MaxSpan: 0},
3: {MinSpan: 3, MaxSpan: 0},
4: {MinSpan: 14, MaxSpan: 0},
5: {MinSpan: 13, MaxSpan: 0},
6: {MinSpan: 12, MaxSpan: 0},
7: {MinSpan: 11, MaxSpan: 0},
8: {MinSpan: 10, MaxSpan: 0},
9: {MinSpan: 9, MaxSpan: 0},
10: {MinSpan: 8, MaxSpan: 0},
11: {MinSpan: 7, MaxSpan: 0},
12: {MinSpan: 6, MaxSpan: 0},
},
},
},
{
validatorIdx: 0,
sourceEpoch: 11,
targetEpoch: 15,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxSpan{
1: {MinSpan: 5, MaxSpan: 0},
2: {MinSpan: 4, MaxSpan: 0},
3: {MinSpan: 3, MaxSpan: 0},
4: {MinSpan: 11, MaxSpan: 0},
5: {MinSpan: 10, MaxSpan: 0},
6: {MinSpan: 9, MaxSpan: 0},
7: {MinSpan: 8, MaxSpan: 0},
8: {MinSpan: 7, MaxSpan: 0},
9: {MinSpan: 6, MaxSpan: 0},
10: {MinSpan: 5, MaxSpan: 0},
11: {MinSpan: 7, MaxSpan: 0},
12: {MinSpan: 6, MaxSpan: 0},
},
},
},
}
}
func TestServer_UpdateMaxSpan(t *testing.T) {
dbs := db.SetupSlasherDB(t)
defer db.TeardownSlasherDB(t, dbs)
ctx := context.Background()
slasherServer := &Server{
SlasherDB: dbs,
}
for _, tt := range spanTestsMax {
if err := slasherServer.UpdateMaxSpan(ctx, tt.sourceEpoch, tt.targetEpoch, tt.validatorIdx); err != nil {
t.Fatalf("Failed to update span: %v", err)
}
sm, err := slasherServer.SlasherDB.ValidatorSpansMap(tt.validatorIdx)
if err != nil {
t.Fatalf("Failed to retrieve span: %v", err)
}
if sm == nil || !proto.Equal(sm, tt.resultSpanMap) {
t.Fatalf("Get should return validator span map: %v got: %v", tt.resultSpanMap, sm)
}
}
}
func TestServer_UpdateMinSpan(t *testing.T) {
dbs := db.SetupSlasherDB(t)
defer db.TeardownSlasherDB(t, dbs)
ctx := context.Background()
slasherServer := &Server{
SlasherDB: dbs,
}
for _, tt := range spanTestsMin {
if err := slasherServer.UpdateMinSpan(ctx, tt.sourceEpoch, tt.targetEpoch, tt.validatorIdx); err != nil {
t.Fatalf("Failed to update span: %v", err)
}
sm, err := slasherServer.SlasherDB.ValidatorSpansMap(tt.validatorIdx)
if err != nil {
t.Fatalf("Failed to retrieve span: %v", err)
}
if sm == nil || !proto.Equal(sm, tt.resultSpanMap) {
t.Fatalf("Get should return validator span map: %v got: %v", tt.resultSpanMap, sm)
}
}
}
func TestServer_FailToUpdate(t *testing.T) {
dbs := db.SetupSlasherDB(t)
defer db.TeardownSlasherDB(t, dbs)
ctx := context.Background()
slasherServer := &Server{
SlasherDB: dbs,
}
spanTestsFail := spanMapTestStruct{
validatorIdx: 0,
sourceEpoch: 0,
targetEpoch: params.BeaconConfig().WeakSubjectivityPeriod + 1,
resultSpanMap: &ethpb.EpochSpanMap{
EpochSpanMap: map[uint64]*ethpb.MinMaxSpan{
4: {MinSpan: 0, MaxSpan: 2},
5: {MinSpan: 0, MaxSpan: 1},
},
},
}
if err := slasherServer.UpdateMinSpan(ctx, spanTestsFail.sourceEpoch, spanTestsFail.targetEpoch, spanTestsFail.validatorIdx); err == nil {
t.Fatalf("Update should not support diff greater then weak subjectivity period: %v ", params.BeaconConfig().WeakSubjectivityPeriod)
}
if err := slasherServer.UpdateMaxSpan(ctx, spanTestsFail.sourceEpoch, spanTestsFail.targetEpoch, spanTestsFail.validatorIdx); err == nil {
t.Fatalf("Update should not support diff greater then weak subjectivity period: %v ", params.BeaconConfig().WeakSubjectivityPeriod)
}
}