diff --git a/message/messagemock/outbound_message_builder.go b/message/messagemock/outbound_message_builder.go index 0ba02d0b9a5..3f2c4f27dd2 100644 --- a/message/messagemock/outbound_message_builder.go +++ b/message/messagemock/outbound_message_builder.go @@ -165,18 +165,18 @@ func (mr *OutboundMsgBuilderMockRecorder) AppResponse(arg0, arg1, arg2 any) *gom } // Chits mocks base method. -func (m *OutboundMsgBuilder) Chits(arg0 ids.ID, arg1 uint32, arg2, arg3, arg4 ids.ID) (message.OutboundMessage, error) { +func (m *OutboundMsgBuilder) Chits(arg0 ids.ID, arg1 uint32, arg2, arg3, arg4 ids.ID, arg5 uint64) (message.OutboundMessage, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Chits", arg0, arg1, arg2, arg3, arg4) + ret := m.ctrl.Call(m, "Chits", arg0, arg1, arg2, arg3, arg4, arg5) ret0, _ := ret[0].(message.OutboundMessage) ret1, _ := ret[1].(error) return ret0, ret1 } // Chits indicates an expected call of Chits. -func (mr *OutboundMsgBuilderMockRecorder) Chits(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { +func (mr *OutboundMsgBuilderMockRecorder) Chits(arg0, arg1, arg2, arg3, arg4, arg5 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chits", reflect.TypeOf((*OutboundMsgBuilder)(nil).Chits), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chits", reflect.TypeOf((*OutboundMsgBuilder)(nil).Chits), arg0, arg1, arg2, arg3, arg4, arg5) } // Get mocks base method. diff --git a/message/outbound_msg_builder.go b/message/outbound_msg_builder.go index 00314ad9108..46bee1dd5f7 100644 --- a/message/outbound_msg_builder.go +++ b/message/outbound_msg_builder.go @@ -154,6 +154,7 @@ type OutboundMsgBuilder interface { preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, + acceptedHeight uint64, ) (OutboundMessage, error) AppRequest( @@ -639,6 +640,7 @@ func (b *outMsgBuilder) Chits( preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, + acceptedHeight uint64, ) (OutboundMessage, error) { return b.builder.createOutbound( &p2p.Message{ @@ -649,6 +651,7 @@ func (b *outMsgBuilder) Chits( PreferredId: preferredID[:], PreferredIdAtHeight: preferredIDAtHeight[:], AcceptedId: acceptedID[:], + AcceptedHeight: acceptedHeight, }, }, }, diff --git a/proto/p2p/p2p.proto b/proto/p2p/p2p.proto index 43f1a880950..a6a2a0c2eb1 100644 --- a/proto/p2p/p2p.proto +++ b/proto/p2p/p2p.proto @@ -371,6 +371,8 @@ message Chits { bytes accepted_id = 4; // Currently preferred block at the requested height bytes preferred_id_at_height = 5; + // Last accepted block's height + uint64 accepted_height = 6; } // AppRequest is a VM-defined request. diff --git a/proto/pb/p2p/p2p.pb.go b/proto/pb/p2p/p2p.pb.go index 9e5ba7727b8..e3d4b05e393 100644 --- a/proto/pb/p2p/p2p.pb.go +++ b/proto/pb/p2p/p2p.pb.go @@ -2140,6 +2140,8 @@ type Chits struct { AcceptedId []byte `protobuf:"bytes,4,opt,name=accepted_id,json=acceptedId,proto3" json:"accepted_id,omitempty"` // Currently preferred block at the requested height PreferredIdAtHeight []byte `protobuf:"bytes,5,opt,name=preferred_id_at_height,json=preferredIdAtHeight,proto3" json:"preferred_id_at_height,omitempty"` + // Last accepted block's height + AcceptedHeight uint64 `protobuf:"varint,6,opt,name=accepted_height,json=acceptedHeight,proto3" json:"accepted_height,omitempty"` } func (x *Chits) Reset() { @@ -2209,6 +2211,13 @@ func (x *Chits) GetPreferredIdAtHeight() []byte { return nil } +func (x *Chits) GetAcceptedHeight() uint64 { + if x != nil { + return x.AcceptedHeight + } + return 0 +} + // AppRequest is a VM-defined request. // // Remote peers must respond to AppRequest with a corresponding AppResponse or @@ -2761,7 +2770,7 @@ var file_p2p_p2p_proto_rawDesc = []byte{ 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4a, 0x04, 0x08, - 0x05, 0x10, 0x06, 0x22, 0xba, 0x01, 0x0a, 0x05, 0x43, 0x68, 0x69, 0x74, 0x73, 0x12, 0x19, 0x0a, + 0x05, 0x10, 0x06, 0x22, 0xe3, 0x01, 0x0a, 0x05, 0x43, 0x68, 0x69, 0x74, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, @@ -2773,43 +2782,46 @@ var file_p2p_p2p_proto_rawDesc = []byte{ 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x5f, 0x69, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x49, 0x64, 0x41, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x22, 0x7f, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, - 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x61, 0x64, - 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x61, 0x64, - 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x70, 0x70, 0x5f, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x70, 0x70, 0x42, 0x79, 0x74, 0x65, - 0x73, 0x22, 0x64, 0x0a, 0x0b, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x70, - 0x70, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, - 0x70, 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x88, 0x01, 0x0a, 0x08, 0x41, 0x70, 0x70, 0x45, - 0x72, 0x72, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, - 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1d, - 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x11, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, - 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x43, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x47, 0x6f, 0x73, 0x73, 0x69, 0x70, 0x12, - 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x70, - 0x70, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, - 0x70, 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, 0x2a, 0x5d, 0x0a, 0x0a, 0x45, 0x6e, 0x67, 0x69, 0x6e, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x4e, 0x47, 0x49, 0x4e, 0x45, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x4e, 0x47, 0x49, 0x4e, 0x45, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x41, 0x56, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x48, 0x45, 0x10, 0x01, 0x12, 0x17, 0x0a, - 0x13, 0x45, 0x4e, 0x47, 0x49, 0x4e, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4e, 0x4f, - 0x57, 0x4d, 0x41, 0x4e, 0x10, 0x02, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x61, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x61, 0x76, - 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x70, 0x62, 0x2f, 0x70, 0x32, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x65, 0x64, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x7f, 0x0a, 0x0a, 0x41, 0x70, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x1b, 0x0a, + 0x09, 0x61, 0x70, 0x70, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x08, 0x61, 0x70, 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x64, 0x0a, 0x0b, 0x41, 0x70, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x70, 0x70, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x70, 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x22, 0x88, 0x01, 0x0a, 0x08, 0x41, 0x70, 0x70, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x19, 0x0a, + 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x11, 0x52, 0x09, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x43, 0x0a, 0x09, 0x41, + 0x70, 0x70, 0x47, 0x6f, 0x73, 0x73, 0x69, 0x70, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x70, 0x70, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x70, 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x2a, 0x5d, 0x0a, 0x0a, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, + 0x0a, 0x17, 0x45, 0x4e, 0x47, 0x49, 0x4e, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x45, + 0x4e, 0x47, 0x49, 0x4e, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x56, 0x41, 0x4c, 0x41, + 0x4e, 0x43, 0x48, 0x45, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x4e, 0x47, 0x49, 0x4e, 0x45, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4e, 0x4f, 0x57, 0x4d, 0x41, 0x4e, 0x10, 0x02, 0x42, + 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, + 0x61, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x61, 0x76, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x68, 0x65, + 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x2f, 0x70, 0x32, 0x70, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/snow/engine/common/engine.go b/snow/engine/common/engine.go index b99b586f131..dc39504dc76 100644 --- a/snow/engine/common/engine.go +++ b/snow/engine/common/engine.go @@ -330,6 +330,7 @@ type ChitsHandler interface { preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, + acceptedHeight uint64, ) error // Notify this engine that a Query request it issued has failed. diff --git a/snow/engine/common/no_ops_handlers.go b/snow/engine/common/no_ops_handlers.go index 33ea424c968..d728e101eb1 100644 --- a/snow/engine/common/no_ops_handlers.go +++ b/snow/engine/common/no_ops_handlers.go @@ -237,7 +237,7 @@ func NewNoOpChitsHandler(log logging.Logger) ChitsHandler { return &noOpChitsHandler{log: log} } -func (nop *noOpChitsHandler) Chits(_ context.Context, nodeID ids.NodeID, requestID uint32, preferredID, preferredIDAtHeight, acceptedID ids.ID) error { +func (nop *noOpChitsHandler) Chits(_ context.Context, nodeID ids.NodeID, requestID uint32, preferredID, preferredIDAtHeight, acceptedID ids.ID, acceptedHeight uint64) error { nop.log.Debug("dropping request", zap.String("reason", "unhandled by this gear"), zap.Stringer("messageOp", message.ChitsOp), @@ -246,6 +246,7 @@ func (nop *noOpChitsHandler) Chits(_ context.Context, nodeID ids.NodeID, request zap.Stringer("preferredID", preferredID), zap.Stringer("preferredIDAtHeight", preferredIDAtHeight), zap.Stringer("acceptedID", acceptedID), + zap.Uint64("acceptedHeight", acceptedHeight), ) return nil } diff --git a/snow/engine/common/sender.go b/snow/engine/common/sender.go index 58365375385..e4dd19807d6 100644 --- a/snow/engine/common/sender.go +++ b/snow/engine/common/sender.go @@ -161,6 +161,7 @@ type QuerySender interface { preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, + acceptedHeight uint64, ) } diff --git a/snow/engine/common/traced_engine.go b/snow/engine/common/traced_engine.go index a1ca48ad829..a6ab2dee187 100644 --- a/snow/engine/common/traced_engine.go +++ b/snow/engine/common/traced_engine.go @@ -245,7 +245,7 @@ func (e *tracedEngine) PushQuery(ctx context.Context, nodeID ids.NodeID, request return e.engine.PushQuery(ctx, nodeID, requestID, container, requestedHeight) } -func (e *tracedEngine) Chits(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID) error { +func (e *tracedEngine) Chits(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, acceptedHeight uint64) error { ctx, span := e.tracer.Start(ctx, "tracedEngine.Chits", oteltrace.WithAttributes( attribute.Stringer("nodeID", nodeID), attribute.Int64("requestID", int64(requestID)), @@ -255,7 +255,7 @@ func (e *tracedEngine) Chits(ctx context.Context, nodeID ids.NodeID, requestID u )) defer span.End() - return e.engine.Chits(ctx, nodeID, requestID, preferredID, preferredIDAtHeight, acceptedID) + return e.engine.Chits(ctx, nodeID, requestID, preferredID, preferredIDAtHeight, acceptedID, acceptedHeight) } func (e *tracedEngine) QueryFailed(ctx context.Context, nodeID ids.NodeID, requestID uint32) error { diff --git a/snow/engine/common/tracker/accepted.go b/snow/engine/common/tracker/accepted.go index f6c63e3ff28..201cf7430f9 100644 --- a/snow/engine/common/tracker/accepted.go +++ b/snow/engine/common/tracker/accepted.go @@ -18,22 +18,28 @@ type Accepted interface { validators.SetCallbackListener // SetLastAccepted updates the latest accepted block for [nodeID] to - // [blockID]. If [nodeID] is not currently a validator, this is a noop. - SetLastAccepted(nodeID ids.NodeID, blockID ids.ID) + // [blockID], with a corresponding height. + // If [nodeID] is not currently a validator, this is a noop. + SetLastAccepted(nodeID ids.NodeID, blockID ids.ID, height uint64) // LastAccepted returns the latest known accepted block of [nodeID]. If // [nodeID]'s last accepted block was never unknown, false will be returned. - LastAccepted(nodeID ids.NodeID) (ids.ID, bool) + LastAccepted(nodeID ids.NodeID) (ids.ID, uint64, bool) +} + +type idHeight struct { + id ids.ID + height uint64 } type accepted struct { lock sync.RWMutex validators set.Set[ids.NodeID] - frontier map[ids.NodeID]ids.ID + frontier map[ids.NodeID]idHeight } func NewAccepted() Accepted { return &accepted{ - frontier: make(map[ids.NodeID]ids.ID), + frontier: make(map[ids.NodeID]idHeight), } } @@ -54,19 +60,22 @@ func (a *accepted) OnValidatorRemoved(nodeID ids.NodeID, _ uint64) { func (*accepted) OnValidatorWeightChanged(_ ids.NodeID, _, _ uint64) {} -func (a *accepted) SetLastAccepted(nodeID ids.NodeID, frontier ids.ID) { +func (a *accepted) SetLastAccepted(nodeID ids.NodeID, frontier ids.ID, height uint64) { a.lock.Lock() defer a.lock.Unlock() if a.validators.Contains(nodeID) { - a.frontier[nodeID] = frontier + a.frontier[nodeID] = idHeight{ + id: frontier, + height: height, + } } } -func (a *accepted) LastAccepted(nodeID ids.NodeID) (ids.ID, bool) { +func (a *accepted) LastAccepted(nodeID ids.NodeID) (ids.ID, uint64, bool) { a.lock.RLock() defer a.lock.RUnlock() - acceptedID, ok := a.frontier[nodeID] - return acceptedID, ok + acceptedAndHeight, ok := a.frontier[nodeID] + return acceptedAndHeight.id, acceptedAndHeight.height, ok } diff --git a/snow/engine/common/tracker/accepted_test.go b/snow/engine/common/tracker/accepted_test.go index 8ff489f51ae..78a4be69f9d 100644 --- a/snow/engine/common/tracker/accepted_test.go +++ b/snow/engine/common/tracker/accepted_test.go @@ -20,30 +20,32 @@ func TestAccepted(t *testing.T) { a := NewAccepted() - _, ok := a.LastAccepted(nodeID) + _, _, ok := a.LastAccepted(nodeID) require.False(ok) - a.SetLastAccepted(nodeID, blkID0) - _, ok = a.LastAccepted(nodeID) + a.SetLastAccepted(nodeID, blkID0, 13) + _, _, ok = a.LastAccepted(nodeID) require.False(ok) a.OnValidatorAdded(nodeID, nil, ids.GenerateTestID(), 1) - _, ok = a.LastAccepted(nodeID) + _, _, ok = a.LastAccepted(nodeID) require.False(ok) - a.SetLastAccepted(nodeID, blkID0) - blkID, ok := a.LastAccepted(nodeID) + a.SetLastAccepted(nodeID, blkID0, 11) + blkID, height, ok := a.LastAccepted(nodeID) require.True(ok) require.Equal(blkID0, blkID) + require.Equal(uint64(11), height) - a.SetLastAccepted(nodeID, blkID1) - blkID, ok = a.LastAccepted(nodeID) + a.SetLastAccepted(nodeID, blkID1, 12) + blkID, height, ok = a.LastAccepted(nodeID) require.True(ok) require.Equal(blkID1, blkID) + require.Equal(uint64(12), height) a.OnValidatorRemoved(nodeID, 1) - _, ok = a.LastAccepted(nodeID) + _, _, ok = a.LastAccepted(nodeID) require.False(ok) } diff --git a/snow/engine/enginetest/engine.go b/snow/engine/enginetest/engine.go index 1ee1b720659..4bafbfd27b8 100644 --- a/snow/engine/enginetest/engine.go +++ b/snow/engine/enginetest/engine.go @@ -118,7 +118,7 @@ type Engine struct { AncestorsF func(ctx context.Context, nodeID ids.NodeID, requestID uint32, containers [][]byte) error AcceptedFrontierF func(ctx context.Context, nodeID ids.NodeID, requestID uint32, containerID ids.ID) error GetAcceptedF, AcceptedF func(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredIDs set.Set[ids.ID]) error - ChitsF func(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID) error + ChitsF func(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, acceptedHeight uint64) error GetStateSummaryFrontierF, GetStateSummaryFrontierFailedF, GetAcceptedStateSummaryFailedF, GetAcceptedFrontierF, GetFailedF, GetAncestorsFailedF, QueryFailedF, GetAcceptedFrontierFailedF, GetAcceptedFailedF func(ctx context.Context, nodeID ids.NodeID, requestID uint32) error @@ -566,9 +566,9 @@ func (e *Engine) AppGossip(ctx context.Context, nodeID ids.NodeID, msg []byte) e return errAppGossip } -func (e *Engine) Chits(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID) error { +func (e *Engine) Chits(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, acceptedHeight uint64) error { if e.ChitsF != nil { - return e.ChitsF(ctx, nodeID, requestID, preferredID, preferredIDAtHeight, acceptedID) + return e.ChitsF(ctx, nodeID, requestID, preferredID, preferredIDAtHeight, acceptedID, acceptedHeight) } if !e.CantChits { return nil diff --git a/snow/engine/enginetest/sender.go b/snow/engine/enginetest/sender.go index 5bc7f100c05..5d5e1ed6b20 100644 --- a/snow/engine/enginetest/sender.go +++ b/snow/engine/enginetest/sender.go @@ -52,7 +52,7 @@ type Sender struct { SendAncestorsF func(context.Context, ids.NodeID, uint32, [][]byte) SendPushQueryF func(context.Context, set.Set[ids.NodeID], uint32, []byte, uint64) SendPullQueryF func(context.Context, set.Set[ids.NodeID], uint32, ids.ID, uint64) - SendChitsF func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) + SendChitsF func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID, uint64) SendAppRequestF func(context.Context, set.Set[ids.NodeID], uint32, []byte) error SendAppResponseF func(context.Context, ids.NodeID, uint32, []byte) error SendAppErrorF func(context.Context, ids.NodeID, uint32, int32, string) error @@ -238,9 +238,9 @@ func (s *Sender) SendPullQuery(ctx context.Context, vdrs set.Set[ids.NodeID], re // SendChits calls SendChitsF if it was initialized. If it wasn't initialized // and this function shouldn't be called and testing was initialized, then // testing will fail. -func (s *Sender) SendChits(ctx context.Context, vdr ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID) { +func (s *Sender) SendChits(ctx context.Context, vdr ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, acceptedHeight uint64) { if s.SendChitsF != nil { - s.SendChitsF(ctx, vdr, requestID, preferredID, preferredIDAtHeight, acceptedID) + s.SendChitsF(ctx, vdr, requestID, preferredID, preferredIDAtHeight, acceptedID, acceptedHeight) } else if s.CantSendChits && s.T != nil { require.FailNow(s.T, "Unexpectedly called SendChits") } diff --git a/snow/engine/snowman/engine.go b/snow/engine/snowman/engine.go index 0998a9e9f56..b1c1698b53d 100644 --- a/snow/engine/snowman/engine.go +++ b/snow/engine/snowman/engine.go @@ -356,8 +356,8 @@ func (e *Engine) PushQuery(ctx context.Context, nodeID ids.NodeID, requestID uin return e.executeDeferredWork(ctx) } -func (e *Engine) Chits(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID) error { - e.acceptedFrontiers.SetLastAccepted(nodeID, acceptedID) +func (e *Engine) Chits(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, acceptedHeight uint64) error { + e.acceptedFrontiers.SetLastAccepted(nodeID, acceptedID, acceptedHeight) e.Ctx.Log.Verbo("called Chits for the block", zap.Stringer("nodeID", nodeID), @@ -365,6 +365,7 @@ func (e *Engine) Chits(ctx context.Context, nodeID ids.NodeID, requestID uint32, zap.Stringer("preferredID", preferredID), zap.Stringer("preferredIDAtHeight", preferredIDAtHeight), zap.Stringer("acceptedID", acceptedID), + zap.Uint64("acceptedHeight", acceptedHeight), ) issuedMetric := e.metrics.issued.WithLabelValues(pullGossipSource) @@ -414,9 +415,9 @@ func (e *Engine) Chits(ctx context.Context, nodeID ids.NodeID, requestID uint32, } func (e *Engine) QueryFailed(ctx context.Context, nodeID ids.NodeID, requestID uint32) error { - lastAccepted, ok := e.acceptedFrontiers.LastAccepted(nodeID) + lastAcceptedID, lastAcceptedHeight, ok := e.acceptedFrontiers.LastAccepted(nodeID) if ok { - return e.Chits(ctx, nodeID, requestID, lastAccepted, lastAccepted, lastAccepted) + return e.Chits(ctx, nodeID, requestID, lastAcceptedID, lastAcceptedID, lastAcceptedID, lastAcceptedHeight) } v := &voter{ @@ -597,7 +598,7 @@ func (e *Engine) sendChits(ctx context.Context, nodeID ids.NodeID, requestID uin ) acceptedAtHeight = lastAcceptedID } - e.Sender.SendChits(ctx, nodeID, requestID, lastAcceptedID, acceptedAtHeight, lastAcceptedID) + e.Sender.SendChits(ctx, nodeID, requestID, lastAcceptedID, acceptedAtHeight, lastAcceptedID, lastAcceptedHeight) return } @@ -642,7 +643,7 @@ func (e *Engine) sendChits(ctx context.Context, nodeID ids.NodeID, requestID uin preferenceAtHeight = preference } } - e.Sender.SendChits(ctx, nodeID, requestID, preference, preferenceAtHeight, lastAcceptedID) + e.Sender.SendChits(ctx, nodeID, requestID, preference, preferenceAtHeight, lastAcceptedID, lastAcceptedHeight) } // Build blocks if they have been requested and the number of processing blocks diff --git a/snow/engine/snowman/engine_test.go b/snow/engine/snowman/engine_test.go index c7fa4f45bbe..baa47212079 100644 --- a/snow/engine/snowman/engine_test.go +++ b/snow/engine/snowman/engine_test.go @@ -177,13 +177,14 @@ func TestEngineQuery(t *testing.T) { child := snowmantest.BuildChild(parent) var sendChitsCalled bool - sender.SendChitsF = func(_ context.Context, _ ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDByHeight ids.ID, accepted ids.ID) { + sender.SendChitsF = func(_ context.Context, _ ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDByHeight ids.ID, accepted ids.ID, acceptedHeight uint64) { require.False(sendChitsCalled) sendChitsCalled = true require.Equal(uint32(15), requestID) require.Equal(snowmantest.GenesisID, preferredID) require.Equal(snowmantest.GenesisID, preferredIDByHeight) require.Equal(snowmantest.GenesisID, accepted) + require.Equal(uint64(0), acceptedHeight) } var getBlockCalled bool @@ -264,7 +265,7 @@ func TestEngineQuery(t *testing.T) { // Handling chits for [child] register a voter job blocking on [child]'s // issuance and send a request for [child]. - require.NoError(engine.Chits(context.Background(), queryRequest.NodeID, queryRequest.RequestID, child.ID(), child.ID(), child.ID())) + require.NoError(engine.Chits(context.Background(), queryRequest.NodeID, queryRequest.RequestID, child.ID(), child.ID(), child.ID(), 42)) queryRequest = nil sender.SendPullQueryF = func(_ context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, blockID ids.ID, requestedHeight uint64) { @@ -412,8 +413,8 @@ func TestEngineMultipleQuery(t *testing.T) { require.Equal(vdr0, inVdr) require.Equal(blk1.ID(), blkID) } - require.NoError(te.Chits(context.Background(), vdr0, *queryRequestID, blk1.ID(), blk1.ID(), blk1.ID())) - require.NoError(te.Chits(context.Background(), vdr1, *queryRequestID, blk1.ID(), blk1.ID(), blk1.ID())) + require.NoError(te.Chits(context.Background(), vdr0, *queryRequestID, blk1.ID(), blk1.ID(), blk1.ID(), 42)) + require.NoError(te.Chits(context.Background(), vdr1, *queryRequestID, blk1.ID(), blk1.ID(), blk1.ID(), 42)) vm.ParseBlockF = func(context.Context, []byte) (snowman.Block, error) { vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { @@ -444,7 +445,7 @@ func TestEngineMultipleQuery(t *testing.T) { require.NoError(te.Put(context.Background(), vdr0, *getRequestID, blk1.Bytes())) // Should be dropped because the query was already filled - require.NoError(te.Chits(context.Background(), vdr2, *queryRequestID, blk0.ID(), blk0.ID(), blk0.ID())) + require.NoError(te.Chits(context.Background(), vdr2, *queryRequestID, blk0.ID(), blk0.ID(), blk0.ID(), 42)) require.Equal(snowtest.Accepted, blk1.Status) require.Zero(te.blocked.NumDependencies()) @@ -520,32 +521,43 @@ func TestEngineRespondsToGetRequest(t *testing.T) { func TestEnginePushQuery(t *testing.T) { require := require.New(t) - vdr, _, sender, vm, te := setup(t, DefaultConfig(t)) + conf := DefaultConfig(t) + vdr, _, sender, vm, te := setup(t, conf) + + vm.LastAcceptedF = snowmantest.MakeLastAcceptedBlockF( + []*snowmantest.Block{{HeightV: 41}}, + ) + vm.GetBlockF = func(_ context.Context, _ ids.ID) (snowman.Block, error) { + return &snowmantest.Block{HeightV: 41}, nil + } sender.Default(true) blk := snowmantest.BuildChild(snowmantest.Genesis) - vm.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { - if bytes.Equal(b, blk.Bytes()) { - return blk, nil - } - return nil, errUnknownBytes + snowCtx := snowtest.Context(t, snowtest.CChainID) + ctx := snowtest.ConsensusContext(snowCtx) + + params := snowball.Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + Beta: 3, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, } - vm.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { - switch blkID { - case snowmantest.GenesisID: - return snowmantest.Genesis, nil - case blk.ID(): - return blk, nil - default: - return nil, errUnknownBlock - } + err := te.Consensus.Initialize(ctx, params, snowmantest.GenesisID, 41, time.Now()) + require.NoError(err) + + vm.ParseBlockF = func(_ context.Context, _ []byte) (snowman.Block, error) { + return &snowmantest.Block{HeightV: 41}, nil } chitted := new(bool) - sender.SendChitsF = func(_ context.Context, inVdr ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDByHeight ids.ID, acceptedID ids.ID) { + sender.SendChitsF = func(_ context.Context, inVdr ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDByHeight ids.ID, acceptedID ids.ID, acceptedHeight uint64) { require.False(*chitted) *chitted = true require.Equal(vdr, inVdr) @@ -553,22 +565,12 @@ func TestEnginePushQuery(t *testing.T) { require.Equal(snowmantest.GenesisID, preferredID) require.Equal(snowmantest.GenesisID, preferredIDByHeight) require.Equal(snowmantest.GenesisID, acceptedID) + require.Equal(uint64(41), acceptedHeight) } - queried := new(bool) - sender.SendPullQueryF = func(_ context.Context, inVdrs set.Set[ids.NodeID], _ uint32, blkID ids.ID, requestedHeight uint64) { - require.False(*queried) - *queried = true - vdrSet := set.Of(vdr) - require.True(inVdrs.Equals(vdrSet)) - require.Equal(blk.ID(), blkID) - require.Equal(uint64(1), requestedHeight) - } - - require.NoError(te.PushQuery(context.Background(), vdr, 20, blk.Bytes(), 1)) + require.NoError(te.PushQuery(context.Background(), vdr, 20, blk.Bytes(), 42)) require.True(*chitted) - require.True(*queried) } func TestEngineBuildBlock(t *testing.T) { @@ -864,7 +866,7 @@ func TestEngineAbandonChit(t *testing.T) { } // Register a voter dependency on an unknown block. - require.NoError(te.Chits(context.Background(), vdr, reqID, fakeBlkID, fakeBlkID, fakeBlkID)) + require.NoError(te.Chits(context.Background(), vdr, reqID, fakeBlkID, fakeBlkID, fakeBlkID, 42)) require.Equal(1, te.blocked.NumDependencies()) sender.CantSendPullQuery = false @@ -917,7 +919,7 @@ func TestEngineAbandonChitWithUnexpectedPutBlock(t *testing.T) { } // Register a voter dependency on an unknown block. - require.NoError(te.Chits(context.Background(), vdr, reqID, fakeBlkID, fakeBlkID, fakeBlkID)) + require.NoError(te.Chits(context.Background(), vdr, reqID, fakeBlkID, fakeBlkID, fakeBlkID, 42)) require.Equal(1, te.blocked.NumDependencies()) sender.CantSendPullQuery = false @@ -1083,6 +1085,7 @@ func TestEngineBlockingChitResponse(t *testing.T) { blockingBlk.ID(), missingBlk.ID(), blockingBlk.ID(), + 42, )) require.Equal(2, te.blocked.NumDependencies()) @@ -1210,7 +1213,7 @@ func TestEngineUndeclaredDependencyDeadlock(t *testing.T) { false, te.metrics.issued.WithLabelValues(unknownSource), )) - require.NoError(te.Chits(context.Background(), vdr, *reqID, invalidBlkID, invalidBlkID, invalidBlkID)) + require.NoError(te.Chits(context.Background(), vdr, *reqID, invalidBlkID, invalidBlkID, invalidBlkID, 42)) require.Equal(snowtest.Accepted, validBlk.Status) } @@ -1553,13 +1556,13 @@ func TestEngineDoubleChit(t *testing.T) { require.Equal(snowtest.Undecided, blk.Status) - require.NoError(te.Chits(context.Background(), vdr0, *queryRequestID, blk.ID(), blk.ID(), blk.ID())) + require.NoError(te.Chits(context.Background(), vdr0, *queryRequestID, blk.ID(), blk.ID(), blk.ID(), 42)) require.Equal(snowtest.Undecided, blk.Status) - require.NoError(te.Chits(context.Background(), vdr0, *queryRequestID, blk.ID(), blk.ID(), blk.ID())) + require.NoError(te.Chits(context.Background(), vdr0, *queryRequestID, blk.ID(), blk.ID(), blk.ID(), 42)) require.Equal(snowtest.Undecided, blk.Status) - require.NoError(te.Chits(context.Background(), vdr1, *queryRequestID, blk.ID(), blk.ID(), blk.ID())) + require.NoError(te.Chits(context.Background(), vdr1, *queryRequestID, blk.ID(), blk.ID(), blk.ID(), 42)) require.Equal(snowtest.Accepted, blk.Status) } @@ -1657,7 +1660,7 @@ func TestEngineBuildBlockLimit(t *testing.T) { } } - require.NoError(te.Chits(context.Background(), vdr, reqID, blk0.ID(), blk0.ID(), blk0.ID())) + require.NoError(te.Chits(context.Background(), vdr, reqID, blk0.ID(), blk0.ID(), blk0.ID(), 42)) require.True(queried) } @@ -1668,7 +1671,7 @@ func TestEngineDropRejectedBlockOnReceipt(t *testing.T) { nodeID, _, sender, vm, te := setup(t, DefaultConfig(t)) // Ignore outbound chits - sender.SendChitsF = func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) {} + sender.SendChitsF = func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID, uint64) {} acceptedBlk := snowmantest.BuildChild(snowmantest.Genesis) rejectedChain := snowmantest.BuildDescendants(snowmantest.Genesis, 2) @@ -1696,7 +1699,7 @@ func TestEngineDropRejectedBlockOnReceipt(t *testing.T) { require.Len(queryRequestIDs, 1) // Vote for [acceptedBlk] and cause it to be accepted. - require.NoError(te.Chits(context.Background(), nodeID, queryRequestIDs[0], acceptedBlk.ID(), acceptedBlk.ID(), acceptedBlk.ID())) + require.NoError(te.Chits(context.Background(), nodeID, queryRequestIDs[0], acceptedBlk.ID(), acceptedBlk.ID(), acceptedBlk.ID(), 42)) require.Len(queryRequestIDs, 1) // Shouldn't have caused another query require.Equal(snowtest.Accepted, acceptedBlk.Status) @@ -1862,7 +1865,7 @@ func TestEngineBubbleVotesThroughInvalidBlock(t *testing.T) { // Now we are expecting a Chits message, and we receive it for [blk2] // instead of [blk1]. This will cause the node to again request [blk2]. - require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk2.ID(), blk1.ID(), blk2.ID())) + require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk2.ID(), blk1.ID(), blk2.ID(), 42)) // The votes should be bubbled through [blk2] despite the fact that it is // failing verification. @@ -1902,7 +1905,7 @@ func TestEngineBubbleVotesThroughInvalidBlock(t *testing.T) { require.True(*queried) // After a single vote for [blk2], it should be marked as accepted. - require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk2.ID(), blk1.ID(), blk2.ID())) + require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk2.ID(), blk1.ID(), blk2.ID(), 42)) require.Equal(snowtest.Accepted, blk2.Status) } @@ -2017,7 +2020,7 @@ func TestEngineBubbleVotesThroughInvalidChain(t *testing.T) { // Now we are expecting a Chits message and we receive it for [blk3]. // This will cause the node to again request [blk3]. - require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk3.ID(), blk1.ID(), blk3.ID())) + require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk3.ID(), blk1.ID(), blk3.ID(), 42)) // Drop the re-request for [blk3] to cause the poll to terminate. The votes // should be bubbled through [blk3] despite the fact that it hasn't been @@ -2119,8 +2122,8 @@ func TestEngineBuildBlockWithCachedNonVerifiedParent(t *testing.T) { require.NoError(te.Put(context.Background(), vdr, 0, parentBlkA.BytesV)) // Give 2 chits for [parentBlkA]/[parentBlkB] - require.NoError(te.Chits(context.Background(), vdr, *queryRequestAID, parentBlkB.IDV, grandParentBlk.IDV, parentBlkB.IDV)) - require.NoError(te.Chits(context.Background(), vdr, *queryRequestGPID, parentBlkB.IDV, grandParentBlk.IDV, parentBlkB.IDV)) + require.NoError(te.Chits(context.Background(), vdr, *queryRequestAID, parentBlkB.IDV, grandParentBlk.IDV, parentBlkB.IDV, 42)) + require.NoError(te.Chits(context.Background(), vdr, *queryRequestGPID, parentBlkB.IDV, grandParentBlk.IDV, parentBlkB.IDV, 42)) // Assert that the blocks' statuses are correct. // The evicted [parentBlkA] shouldn't be changed. @@ -2227,7 +2230,7 @@ func TestEngineApplyAcceptedFrontierInQueryFailed(t *testing.T) { require.Equal(uint64(1), requestedHeight) } - require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk.ID(), blk.ID(), blk.ID())) + require.NoError(te.Chits(context.Background(), vdr, *queryRequestID, blk.ID(), blk.ID(), blk.ID(), 42)) require.Equal(snowtest.Undecided, blk.Status) @@ -2332,7 +2335,7 @@ func TestEngineRepollsMisconfiguredSubnet(t *testing.T) { // Voting for the block that was issued during the period when the validator // set was misconfigured should result in it being accepted successfully. - require.NoError(te.Chits(context.Background(), vdr, queryRequestID, blk.ID(), blk.ID(), blk.ID())) + require.NoError(te.Chits(context.Background(), vdr, queryRequestID, blk.ID(), blk.ID(), blk.ID(), 42)) require.Equal(snowtest.Accepted, blk.Status) } @@ -2397,7 +2400,7 @@ func TestEngineVoteStallRegression(t *testing.T) { sender := &enginetest.Sender{ T: t, - SendChitsF: func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) {}, + SendChitsF: func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID, uint64) {}, } sender.Default(true) config.Sender = sender @@ -2493,6 +2496,7 @@ func TestEngineVoteStallRegression(t *testing.T) { acceptedChain[1].ID(), acceptedChain[1].ID(), acceptedChain[1].ID(), + 42, )) require.NoError(engine.Chits( context.Background(), @@ -2501,6 +2505,7 @@ func TestEngineVoteStallRegression(t *testing.T) { acceptedChain[2].ID(), acceptedChain[2].ID(), acceptedChain[2].ID(), + 42, )) // Attempt to apply votes in poll 0 for block 3. This will send a Get @@ -2523,6 +2528,7 @@ func TestEngineVoteStallRegression(t *testing.T) { rejectedChain[0].ID(), rejectedChain[0].ID(), rejectedChain[0].ID(), + 42, )) require.NotNil(getBlock3Request) @@ -2546,6 +2552,7 @@ func TestEngineVoteStallRegression(t *testing.T) { acceptedChain[1].ID(), acceptedChain[1].ID(), acceptedChain[1].ID(), + 42, )) require.NoError(engine.Chits( context.Background(), @@ -2554,6 +2561,7 @@ func TestEngineVoteStallRegression(t *testing.T) { acceptedChain[2].ID(), acceptedChain[2].ID(), acceptedChain[2].ID(), + 42, )) require.NoError(engine.Chits( context.Background(), @@ -2562,6 +2570,7 @@ func TestEngineVoteStallRegression(t *testing.T) { rejectedChain[1].ID(), rejectedChain[1].ID(), rejectedChain[1].ID(), + 42, )) // Provide block 3. @@ -2596,6 +2605,7 @@ func TestEngineVoteStallRegression(t *testing.T) { acceptedChain[2].ID(), acceptedChain[2].ID(), acceptedChain[2].ID(), + 42, )) } } @@ -2617,7 +2627,7 @@ func TestEngineEarlyTerminateVoterRegression(t *testing.T) { sender := &enginetest.Sender{ T: t, - SendChitsF: func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) {}, + SendChitsF: func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID, uint64) {}, } sender.Default(true) config.Sender = sender @@ -2704,6 +2714,7 @@ func TestEngineEarlyTerminateVoterRegression(t *testing.T) { chain[2].ID(), chain[1].ID(), snowmantest.GenesisID, + 42, )) require.Len(pollRequestIDs, 1) require.Contains(getRequestIDs, chain[1].ID()) @@ -2762,7 +2773,7 @@ func TestEngineRegistersInvalidVoterDependencyRegression(t *testing.T) { sender := &enginetest.Sender{ T: t, - SendChitsF: func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) {}, + SendChitsF: func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID, uint64) {}, } sender.Default(true) config.Sender = sender @@ -2882,6 +2893,7 @@ func TestEngineRegistersInvalidVoterDependencyRegression(t *testing.T) { acceptedChain[0].ID(), acceptedChain[0].ID(), snowmantest.GenesisID, + 42, )) // There are no processing blocks, so no new poll should be created. require.Len(pollRequestIDs, 1) @@ -2907,6 +2919,7 @@ func TestEngineRegistersInvalidVoterDependencyRegression(t *testing.T) { rejectedChain[1].ID(), rejectedChain[1].ID(), snowmantest.GenesisID, + 42, )) require.Len(pollRequestIDs, 3) @@ -2926,6 +2939,7 @@ func TestEngineRegistersInvalidVoterDependencyRegression(t *testing.T) { acceptedChain[1].ID(), acceptedChain[1].ID(), snowmantest.GenesisID, + 42, )) require.Len(pollRequestIDs, 3) require.Equal(snowtest.Accepted, acceptedChain[1].Status) @@ -3221,3 +3235,72 @@ func TestEngineAbortQueryWhenInPartition(t *testing.T) { require.Contains(buff.String(), errInsufficientStake) } + +func TestEngineAcceptedHeight(t *testing.T) { + require := require.New(t) + + engCfg := DefaultConfig(t) + engCfg.Params = snowball.Parameters{ + K: 2, + AlphaPreference: 2, + AlphaConfidence: 2, + Beta: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + } + + vals := validators.NewManager() + engCfg.Validators = vals + + _, _, _, vm, te := setup(t, engCfg) + + vdr0 := ids.GenerateTestNodeID() + vdr1 := ids.GenerateTestNodeID() + + require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr0, nil, ids.Empty, 1)) + require.NoError(vals.AddStaker(engCfg.Ctx.SubnetID, vdr1, nil, ids.Empty, 1)) + + blk1 := snowmantest.BuildChild(snowmantest.Genesis) + + blk2 := snowmantest.BuildChild(blk1) + + vm.LastAcceptedF = func(context.Context) (ids.ID, error) { + return blk1.ID(), nil + } + + vm.GetBlockF = func(context.Context, ids.ID) (snowman.Block, error) { + return blk1, nil + } + + snowCtx := snowtest.Context(t, snowtest.CChainID) + ctx := snowtest.ConsensusContext(snowCtx) + params := snowball.Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + Beta: 3, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + } + + err := engCfg.Consensus.Initialize(ctx, params, blk1.ID(), 42, time.Now()) + require.NoError(err) + + require.NoError(te.Chits(context.Background(), vdr0, 1, blk1.ID(), blk1.ID(), blk1.ID(), 42)) + require.NoError(te.Chits(context.Background(), vdr1, 2, blk2.ID(), blk2.ID(), blk2.ID(), 43)) + + eBlk1, h1, ok := te.acceptedFrontiers.LastAccepted(vdr0) + require.True(ok) + + eBlk2, h2, ok := te.acceptedFrontiers.LastAccepted(vdr1) + require.True(ok) + + require.Equal(blk1.ID(), eBlk1) + require.Equal(blk2.ID(), eBlk2) + require.Equal(uint64(42), h1) + require.Equal(uint64(43), h2) +} diff --git a/snow/networking/handler/handler.go b/snow/networking/handler/handler.go index 9ab6c614c58..224e0abc51b 100644 --- a/snow/networking/handler/handler.go +++ b/snow/networking/handler/handler.go @@ -736,7 +736,7 @@ func (h *handler) handleSyncMsg(ctx context.Context, msg Message) error { return engine.QueryFailed(ctx, nodeID, msg.RequestId) } - return engine.Chits(ctx, nodeID, msg.RequestId, preferredID, preferredIDAtHeight, acceptedID) + return engine.Chits(ctx, nodeID, msg.RequestId, preferredID, preferredIDAtHeight, acceptedID, msg.AcceptedHeight) case *message.QueryFailed: return engine.QueryFailed(ctx, nodeID, msg.RequestID) diff --git a/snow/networking/handler/handler_test.go b/snow/networking/handler/handler_test.go index 661ba17300f..39947a0c950 100644 --- a/snow/networking/handler/handler_test.go +++ b/snow/networking/handler/handler_test.go @@ -570,7 +570,7 @@ func TestDynamicEngineTypeDispatch(t *testing.T) { engine.ContextF = func() *snow.ConsensusContext { return ctx } - engine.ChitsF = func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID) error { + engine.ChitsF = func(context.Context, ids.NodeID, uint32, ids.ID, ids.ID, ids.ID, uint64) error { close(messageReceived) return nil } diff --git a/snow/networking/sender/sender.go b/snow/networking/sender/sender.go index 7db929517a7..02fe8d82e52 100644 --- a/snow/networking/sender/sender.go +++ b/snow/networking/sender/sender.go @@ -1148,6 +1148,7 @@ func (s *sender) SendChits( preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, + acceptedHeight uint64, ) { ctx = context.WithoutCancel(ctx) @@ -1167,7 +1168,7 @@ func (s *sender) SendChits( } // Create the outbound message. - outMsg, err := s.msgCreator.Chits(s.ctx.ChainID, requestID, preferredID, preferredIDAtHeight, acceptedID) + outMsg, err := s.msgCreator.Chits(s.ctx.ChainID, requestID, preferredID, preferredIDAtHeight, acceptedID, acceptedHeight) if err != nil { s.ctx.Log.Error("failed to build message", zap.Stringer("messageOp", message.ChitsOp), diff --git a/snow/networking/sender/traced_sender.go b/snow/networking/sender/traced_sender.go index 6fadee7f909..2eb445f9927 100644 --- a/snow/networking/sender/traced_sender.go +++ b/snow/networking/sender/traced_sender.go @@ -178,17 +178,18 @@ func (s *tracedSender) SendPullQuery(ctx context.Context, nodeIDs set.Set[ids.No s.sender.SendPullQuery(ctx, nodeIDs, requestID, containerID, requestedHeight) } -func (s *tracedSender) SendChits(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID) { +func (s *tracedSender) SendChits(ctx context.Context, nodeID ids.NodeID, requestID uint32, preferredID ids.ID, preferredIDAtHeight ids.ID, acceptedID ids.ID, acceptedHeight uint64) { ctx, span := s.tracer.Start(ctx, "tracedSender.SendChits", oteltrace.WithAttributes( attribute.Stringer("recipients", nodeID), attribute.Int64("requestID", int64(requestID)), attribute.Stringer("preferredID", preferredID), attribute.Stringer("preferredIDAtHeight", preferredIDAtHeight), attribute.Stringer("acceptedID", acceptedID), + attribute.Int("acceptedHeight", int(acceptedHeight)), )) defer span.End() - s.sender.SendChits(ctx, nodeID, requestID, preferredID, preferredIDAtHeight, acceptedID) + s.sender.SendChits(ctx, nodeID, requestID, preferredID, preferredIDAtHeight, acceptedID, acceptedHeight) } func (s *tracedSender) SendAppRequest(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, appRequestBytes []byte) error {