diff --git a/.github/workflows/build-linux-binaries.yml b/.github/workflows/build-linux-binaries.yml index 8e61d5235ed..857ba374a20 100644 --- a/.github/workflows/build-linux-binaries.yml +++ b/.github/workflows/build-linux-binaries.yml @@ -82,7 +82,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v3 with: go-version: ${{ env.go_version }} check-latest: true diff --git a/.github/workflows/build-ubuntu-arm64-release.yml b/.github/workflows/build-ubuntu-arm64-release.yml index 4b907d1ddaa..6c0b37d6924 100644 --- a/.github/workflows/build-ubuntu-arm64-release.yml +++ b/.github/workflows/build-ubuntu-arm64-release.yml @@ -19,7 +19,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v3 with: go-version: ${{ env.go_version }} check-latest: true @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v3 with: go-version: ${{ env.go_version }} check-latest: true diff --git a/message/mock_outbound_message_builder.go b/message/mock_outbound_message_builder.go index ac9a09a51b5..d3ec69a0b0c 100644 --- a/message/mock_outbound_message_builder.go +++ b/message/mock_outbound_message_builder.go @@ -102,6 +102,21 @@ func (mr *MockOutboundMsgBuilderMockRecorder) Ancestors(arg0, arg1, arg2 any) *g return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ancestors", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Ancestors), arg0, arg1, arg2) } +// AppError mocks base method. +func (m *MockOutboundMsgBuilder) AppError(arg0 ids.ID, arg1 uint32, arg2 int32, arg3 string) (OutboundMessage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AppError", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(OutboundMessage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AppError indicates an expected call of AppError. +func (mr *MockOutboundMsgBuilderMockRecorder) AppError(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppError", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).AppError), arg0, arg1, arg2, arg3) +} + // AppGossip mocks base method. func (m *MockOutboundMsgBuilder) AppGossip(arg0 ids.ID, arg1 []byte) (OutboundMessage, error) { m.ctrl.T.Helper() diff --git a/message/ops.go b/message/ops.go index 0c58eb60690..11c69087b5f 100644 --- a/message/ops.go +++ b/message/ops.go @@ -97,6 +97,7 @@ var ( PutOp, ChitsOp, AppResponseOp, + AppErrorOp, } // AppGossip is the only message that is sent unrequested without the // expectation of a response @@ -115,7 +116,6 @@ var ( GetAncestorsFailedOp, GetFailedOp, QueryFailedOp, - AppErrorOp, CrossChainAppRequestOp, CrossChainAppErrorOp, CrossChainAppResponseOp, diff --git a/message/outbound_msg_builder.go b/message/outbound_msg_builder.go index bffd2df3625..f90a5f501b8 100644 --- a/message/outbound_msg_builder.go +++ b/message/outbound_msg_builder.go @@ -177,6 +177,13 @@ type OutboundMsgBuilder interface { msg []byte, ) (OutboundMessage, error) + AppError( + chainID ids.ID, + requestID uint32, + errorCode int32, + errorMessage string, + ) (OutboundMessage, error) + AppGossip( chainID ids.ID, msg []byte, @@ -710,6 +717,23 @@ func (b *outMsgBuilder) AppResponse(chainID ids.ID, requestID uint32, msg []byte ) } +func (b *outMsgBuilder) AppError(chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) (OutboundMessage, error) { + return b.builder.createOutbound( + &p2p.Message{ + Message: &p2p.Message_AppError{ + AppError: &p2p.AppError{ + ChainId: chainID[:], + RequestId: requestID, + ErrorCode: errorCode, + ErrorMessage: errorMessage, + }, + }, + }, + b.compressionType, + false, + ) +} + func (b *outMsgBuilder) AppGossip(chainID ids.ID, msg []byte) (OutboundMessage, error) { return b.builder.createOutbound( &p2p.Message{ diff --git a/proto/appsender/appsender.proto b/proto/appsender/appsender.proto index d021bbb5acc..1d7cdac8992 100644 --- a/proto/appsender/appsender.proto +++ b/proto/appsender/appsender.proto @@ -9,11 +9,13 @@ option go_package = "github.com/ava-labs/avalanchego/proto/pb/appsender"; service AppSender { rpc SendAppRequest(SendAppRequestMsg) returns (google.protobuf.Empty); rpc SendAppResponse(SendAppResponseMsg) returns (google.protobuf.Empty); + rpc SendAppError(SendAppErrorMsg) returns (google.protobuf.Empty); rpc SendAppGossip(SendAppGossipMsg) returns (google.protobuf.Empty); rpc SendAppGossipSpecific(SendAppGossipSpecificMsg) returns (google.protobuf.Empty); rpc SendCrossChainAppRequest(SendCrossChainAppRequestMsg) returns (google.protobuf.Empty); rpc SendCrossChainAppResponse(SendCrossChainAppResponseMsg) returns (google.protobuf.Empty); + rpc SendCrossChainAppError(SendCrossChainAppErrorMsg) returns (google.protobuf.Empty); } message SendAppRequestMsg { @@ -34,6 +36,17 @@ message SendAppResponseMsg { bytes response = 3; } +message SendAppErrorMsg { + // The node to send a response to + bytes node_id = 1; + // ID of this request + uint32 request_id = 2; + // Application-defined error code + sint32 error_code = 3; + // Application-defined error message + string error_message = 4; +} + message SendAppGossipMsg { // The message body bytes msg = 1; @@ -63,3 +76,14 @@ message SendCrossChainAppResponseMsg { // The response body bytes response = 3; } + +message SendCrossChainAppErrorMsg { + // The chain to send a response to + bytes chain_id = 1; + // ID of this request + uint32 request_id = 2; + // Application-defined error code + sint32 error_code = 3; + // Application-defined error message + string error_message = 4; +} diff --git a/proto/pb/appsender/appsender.pb.go b/proto/pb/appsender/appsender.pb.go index 7bae1df845a..416faab9bce 100644 --- a/proto/pb/appsender/appsender.pb.go +++ b/proto/pb/appsender/appsender.pb.go @@ -153,6 +153,81 @@ func (x *SendAppResponseMsg) GetResponse() []byte { return nil } +type SendAppErrorMsg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The node to send a response to + NodeId []byte `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // ID of this request + RequestId uint32 `protobuf:"varint,2,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // Application-defined error code + ErrorCode int32 `protobuf:"zigzag32,3,opt,name=error_code,json=errorCode,proto3" json:"error_code,omitempty"` + // Application-defined error message + ErrorMessage string `protobuf:"bytes,4,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` +} + +func (x *SendAppErrorMsg) Reset() { + *x = SendAppErrorMsg{} + if protoimpl.UnsafeEnabled { + mi := &file_appsender_appsender_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendAppErrorMsg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendAppErrorMsg) ProtoMessage() {} + +func (x *SendAppErrorMsg) ProtoReflect() protoreflect.Message { + mi := &file_appsender_appsender_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendAppErrorMsg.ProtoReflect.Descriptor instead. +func (*SendAppErrorMsg) Descriptor() ([]byte, []int) { + return file_appsender_appsender_proto_rawDescGZIP(), []int{2} +} + +func (x *SendAppErrorMsg) GetNodeId() []byte { + if x != nil { + return x.NodeId + } + return nil +} + +func (x *SendAppErrorMsg) GetRequestId() uint32 { + if x != nil { + return x.RequestId + } + return 0 +} + +func (x *SendAppErrorMsg) GetErrorCode() int32 { + if x != nil { + return x.ErrorCode + } + return 0 +} + +func (x *SendAppErrorMsg) GetErrorMessage() string { + if x != nil { + return x.ErrorMessage + } + return "" +} + type SendAppGossipMsg struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -165,7 +240,7 @@ type SendAppGossipMsg struct { func (x *SendAppGossipMsg) Reset() { *x = SendAppGossipMsg{} if protoimpl.UnsafeEnabled { - mi := &file_appsender_appsender_proto_msgTypes[2] + mi := &file_appsender_appsender_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -178,7 +253,7 @@ func (x *SendAppGossipMsg) String() string { func (*SendAppGossipMsg) ProtoMessage() {} func (x *SendAppGossipMsg) ProtoReflect() protoreflect.Message { - mi := &file_appsender_appsender_proto_msgTypes[2] + mi := &file_appsender_appsender_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -191,7 +266,7 @@ func (x *SendAppGossipMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use SendAppGossipMsg.ProtoReflect.Descriptor instead. func (*SendAppGossipMsg) Descriptor() ([]byte, []int) { - return file_appsender_appsender_proto_rawDescGZIP(), []int{2} + return file_appsender_appsender_proto_rawDescGZIP(), []int{3} } func (x *SendAppGossipMsg) GetMsg() []byte { @@ -215,7 +290,7 @@ type SendAppGossipSpecificMsg struct { func (x *SendAppGossipSpecificMsg) Reset() { *x = SendAppGossipSpecificMsg{} if protoimpl.UnsafeEnabled { - mi := &file_appsender_appsender_proto_msgTypes[3] + mi := &file_appsender_appsender_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -228,7 +303,7 @@ func (x *SendAppGossipSpecificMsg) String() string { func (*SendAppGossipSpecificMsg) ProtoMessage() {} func (x *SendAppGossipSpecificMsg) ProtoReflect() protoreflect.Message { - mi := &file_appsender_appsender_proto_msgTypes[3] + mi := &file_appsender_appsender_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -241,7 +316,7 @@ func (x *SendAppGossipSpecificMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use SendAppGossipSpecificMsg.ProtoReflect.Descriptor instead. func (*SendAppGossipSpecificMsg) Descriptor() ([]byte, []int) { - return file_appsender_appsender_proto_rawDescGZIP(), []int{3} + return file_appsender_appsender_proto_rawDescGZIP(), []int{4} } func (x *SendAppGossipSpecificMsg) GetNodeIds() [][]byte { @@ -274,7 +349,7 @@ type SendCrossChainAppRequestMsg struct { func (x *SendCrossChainAppRequestMsg) Reset() { *x = SendCrossChainAppRequestMsg{} if protoimpl.UnsafeEnabled { - mi := &file_appsender_appsender_proto_msgTypes[4] + mi := &file_appsender_appsender_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -287,7 +362,7 @@ func (x *SendCrossChainAppRequestMsg) String() string { func (*SendCrossChainAppRequestMsg) ProtoMessage() {} func (x *SendCrossChainAppRequestMsg) ProtoReflect() protoreflect.Message { - mi := &file_appsender_appsender_proto_msgTypes[4] + mi := &file_appsender_appsender_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -300,7 +375,7 @@ func (x *SendCrossChainAppRequestMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use SendCrossChainAppRequestMsg.ProtoReflect.Descriptor instead. func (*SendCrossChainAppRequestMsg) Descriptor() ([]byte, []int) { - return file_appsender_appsender_proto_rawDescGZIP(), []int{4} + return file_appsender_appsender_proto_rawDescGZIP(), []int{5} } func (x *SendCrossChainAppRequestMsg) GetChainId() []byte { @@ -340,7 +415,7 @@ type SendCrossChainAppResponseMsg struct { func (x *SendCrossChainAppResponseMsg) Reset() { *x = SendCrossChainAppResponseMsg{} if protoimpl.UnsafeEnabled { - mi := &file_appsender_appsender_proto_msgTypes[5] + mi := &file_appsender_appsender_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -353,7 +428,7 @@ func (x *SendCrossChainAppResponseMsg) String() string { func (*SendCrossChainAppResponseMsg) ProtoMessage() {} func (x *SendCrossChainAppResponseMsg) ProtoReflect() protoreflect.Message { - mi := &file_appsender_appsender_proto_msgTypes[5] + mi := &file_appsender_appsender_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -366,7 +441,7 @@ func (x *SendCrossChainAppResponseMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use SendCrossChainAppResponseMsg.ProtoReflect.Descriptor instead. func (*SendCrossChainAppResponseMsg) Descriptor() ([]byte, []int) { - return file_appsender_appsender_proto_rawDescGZIP(), []int{5} + return file_appsender_appsender_proto_rawDescGZIP(), []int{6} } func (x *SendCrossChainAppResponseMsg) GetChainId() []byte { @@ -390,6 +465,81 @@ func (x *SendCrossChainAppResponseMsg) GetResponse() []byte { return nil } +type SendCrossChainAppErrorMsg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The chain to send a response to + ChainId []byte `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // ID of this request + RequestId uint32 `protobuf:"varint,2,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // Application-defined error code + ErrorCode int32 `protobuf:"zigzag32,3,opt,name=error_code,json=errorCode,proto3" json:"error_code,omitempty"` + // Application-defined error message + ErrorMessage string `protobuf:"bytes,4,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` +} + +func (x *SendCrossChainAppErrorMsg) Reset() { + *x = SendCrossChainAppErrorMsg{} + if protoimpl.UnsafeEnabled { + mi := &file_appsender_appsender_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendCrossChainAppErrorMsg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendCrossChainAppErrorMsg) ProtoMessage() {} + +func (x *SendCrossChainAppErrorMsg) ProtoReflect() protoreflect.Message { + mi := &file_appsender_appsender_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendCrossChainAppErrorMsg.ProtoReflect.Descriptor instead. +func (*SendCrossChainAppErrorMsg) Descriptor() ([]byte, []int) { + return file_appsender_appsender_proto_rawDescGZIP(), []int{7} +} + +func (x *SendCrossChainAppErrorMsg) GetChainId() []byte { + if x != nil { + return x.ChainId + } + return nil +} + +func (x *SendCrossChainAppErrorMsg) GetRequestId() uint32 { + if x != nil { + return x.RequestId + } + return 0 +} + +func (x *SendCrossChainAppErrorMsg) GetErrorCode() int32 { + if x != nil { + return x.ErrorCode + } + return 0 +} + +func (x *SendCrossChainAppErrorMsg) GetErrorMessage() string { + if x != nil { + return x.ErrorMessage + } + return "" +} + var File_appsender_appsender_proto protoreflect.FileDescriptor var file_appsender_appsender_proto_rawDesc = []byte{ @@ -410,7 +560,16 @@ var file_appsender_appsender_proto_rawDesc = []byte{ 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, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8d, 0x01, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, + 0x70, 0x70, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, + 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6e, 0x6f, 0x64, + 0x65, 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, 0x24, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x47, 0x6f, 0x73, 0x73, 0x69, 0x70, 0x4d, 0x73, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0x47, 0x0a, 0x18, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x47, 0x6f, 0x73, 0x73, 0x69, 0x70, 0x53, 0x70, 0x65, @@ -431,16 +590,30 @@ var file_appsender_appsender_proto_rawDesc = []byte{ 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, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xf3, - 0x03, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x46, 0x0a, 0x0e, - 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, - 0x2e, 0x61, 0x70, 0x70, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, - 0x70, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x12, 0x48, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x70, 0x73, 0x65, 0x6e, - 0x64, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x99, + 0x01, 0x0a, 0x19, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x41, 0x70, 0x70, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 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, 0x32, 0x8f, 0x05, 0x0a, 0x09, 0x41, + 0x70, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x46, 0x0a, 0x0e, 0x53, 0x65, 0x6e, 0x64, + 0x41, 0x70, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x70, + 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x12, 0x48, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x70, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x2e, + 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x42, 0x0a, 0x0c, 0x53, 0x65, + 0x6e, 0x64, 0x41, 0x70, 0x70, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x70, + 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x44, 0x0a, 0x0d, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x47, 0x6f, 0x73, 0x73, 0x69, 0x70, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x70, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, @@ -463,11 +636,16 @@ var file_appsender_appsender_proto_rawDesc = []byte{ 0x53, 0x65, 0x6e, 0x64, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x42, 0x34, 0x5a, 0x32, 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, 0x61, 0x70, 0x70, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x56, 0x0a, 0x16, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x72, 0x6f, 0x73, + 0x73, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x41, 0x70, 0x70, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x24, + 0x2e, 0x61, 0x70, 0x70, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, + 0x72, 0x6f, 0x73, 0x73, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x41, 0x70, 0x70, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x34, 0x5a, 0x32, + 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, 0x61, 0x70, 0x70, 0x73, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -482,31 +660,37 @@ func file_appsender_appsender_proto_rawDescGZIP() []byte { return file_appsender_appsender_proto_rawDescData } -var file_appsender_appsender_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_appsender_appsender_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_appsender_appsender_proto_goTypes = []interface{}{ (*SendAppRequestMsg)(nil), // 0: appsender.SendAppRequestMsg (*SendAppResponseMsg)(nil), // 1: appsender.SendAppResponseMsg - (*SendAppGossipMsg)(nil), // 2: appsender.SendAppGossipMsg - (*SendAppGossipSpecificMsg)(nil), // 3: appsender.SendAppGossipSpecificMsg - (*SendCrossChainAppRequestMsg)(nil), // 4: appsender.SendCrossChainAppRequestMsg - (*SendCrossChainAppResponseMsg)(nil), // 5: appsender.SendCrossChainAppResponseMsg - (*emptypb.Empty)(nil), // 6: google.protobuf.Empty + (*SendAppErrorMsg)(nil), // 2: appsender.SendAppErrorMsg + (*SendAppGossipMsg)(nil), // 3: appsender.SendAppGossipMsg + (*SendAppGossipSpecificMsg)(nil), // 4: appsender.SendAppGossipSpecificMsg + (*SendCrossChainAppRequestMsg)(nil), // 5: appsender.SendCrossChainAppRequestMsg + (*SendCrossChainAppResponseMsg)(nil), // 6: appsender.SendCrossChainAppResponseMsg + (*SendCrossChainAppErrorMsg)(nil), // 7: appsender.SendCrossChainAppErrorMsg + (*emptypb.Empty)(nil), // 8: google.protobuf.Empty } var file_appsender_appsender_proto_depIdxs = []int32{ 0, // 0: appsender.AppSender.SendAppRequest:input_type -> appsender.SendAppRequestMsg 1, // 1: appsender.AppSender.SendAppResponse:input_type -> appsender.SendAppResponseMsg - 2, // 2: appsender.AppSender.SendAppGossip:input_type -> appsender.SendAppGossipMsg - 3, // 3: appsender.AppSender.SendAppGossipSpecific:input_type -> appsender.SendAppGossipSpecificMsg - 4, // 4: appsender.AppSender.SendCrossChainAppRequest:input_type -> appsender.SendCrossChainAppRequestMsg - 5, // 5: appsender.AppSender.SendCrossChainAppResponse:input_type -> appsender.SendCrossChainAppResponseMsg - 6, // 6: appsender.AppSender.SendAppRequest:output_type -> google.protobuf.Empty - 6, // 7: appsender.AppSender.SendAppResponse:output_type -> google.protobuf.Empty - 6, // 8: appsender.AppSender.SendAppGossip:output_type -> google.protobuf.Empty - 6, // 9: appsender.AppSender.SendAppGossipSpecific:output_type -> google.protobuf.Empty - 6, // 10: appsender.AppSender.SendCrossChainAppRequest:output_type -> google.protobuf.Empty - 6, // 11: appsender.AppSender.SendCrossChainAppResponse:output_type -> google.protobuf.Empty - 6, // [6:12] is the sub-list for method output_type - 0, // [0:6] is the sub-list for method input_type + 2, // 2: appsender.AppSender.SendAppError:input_type -> appsender.SendAppErrorMsg + 3, // 3: appsender.AppSender.SendAppGossip:input_type -> appsender.SendAppGossipMsg + 4, // 4: appsender.AppSender.SendAppGossipSpecific:input_type -> appsender.SendAppGossipSpecificMsg + 5, // 5: appsender.AppSender.SendCrossChainAppRequest:input_type -> appsender.SendCrossChainAppRequestMsg + 6, // 6: appsender.AppSender.SendCrossChainAppResponse:input_type -> appsender.SendCrossChainAppResponseMsg + 7, // 7: appsender.AppSender.SendCrossChainAppError:input_type -> appsender.SendCrossChainAppErrorMsg + 8, // 8: appsender.AppSender.SendAppRequest:output_type -> google.protobuf.Empty + 8, // 9: appsender.AppSender.SendAppResponse:output_type -> google.protobuf.Empty + 8, // 10: appsender.AppSender.SendAppError:output_type -> google.protobuf.Empty + 8, // 11: appsender.AppSender.SendAppGossip:output_type -> google.protobuf.Empty + 8, // 12: appsender.AppSender.SendAppGossipSpecific:output_type -> google.protobuf.Empty + 8, // 13: appsender.AppSender.SendCrossChainAppRequest:output_type -> google.protobuf.Empty + 8, // 14: appsender.AppSender.SendCrossChainAppResponse:output_type -> google.protobuf.Empty + 8, // 15: appsender.AppSender.SendCrossChainAppError:output_type -> google.protobuf.Empty + 8, // [8:16] is the sub-list for method output_type + 0, // [0:8] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name @@ -543,7 +727,7 @@ func file_appsender_appsender_proto_init() { } } file_appsender_appsender_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SendAppGossipMsg); i { + switch v := v.(*SendAppErrorMsg); i { case 0: return &v.state case 1: @@ -555,7 +739,7 @@ func file_appsender_appsender_proto_init() { } } file_appsender_appsender_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SendAppGossipSpecificMsg); i { + switch v := v.(*SendAppGossipMsg); i { case 0: return &v.state case 1: @@ -567,7 +751,7 @@ func file_appsender_appsender_proto_init() { } } file_appsender_appsender_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SendCrossChainAppRequestMsg); i { + switch v := v.(*SendAppGossipSpecificMsg); i { case 0: return &v.state case 1: @@ -579,6 +763,18 @@ func file_appsender_appsender_proto_init() { } } file_appsender_appsender_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendCrossChainAppRequestMsg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_appsender_appsender_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SendCrossChainAppResponseMsg); i { case 0: return &v.state @@ -590,6 +786,18 @@ func file_appsender_appsender_proto_init() { return nil } } + file_appsender_appsender_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendCrossChainAppErrorMsg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -597,7 +805,7 @@ func file_appsender_appsender_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_appsender_appsender_proto_rawDesc, NumEnums: 0, - NumMessages: 6, + NumMessages: 8, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/pb/appsender/appsender_grpc.pb.go b/proto/pb/appsender/appsender_grpc.pb.go index edfc5d1db86..6873c7768fb 100644 --- a/proto/pb/appsender/appsender_grpc.pb.go +++ b/proto/pb/appsender/appsender_grpc.pb.go @@ -22,10 +22,12 @@ const _ = grpc.SupportPackageIsVersion7 const ( AppSender_SendAppRequest_FullMethodName = "/appsender.AppSender/SendAppRequest" AppSender_SendAppResponse_FullMethodName = "/appsender.AppSender/SendAppResponse" + AppSender_SendAppError_FullMethodName = "/appsender.AppSender/SendAppError" AppSender_SendAppGossip_FullMethodName = "/appsender.AppSender/SendAppGossip" AppSender_SendAppGossipSpecific_FullMethodName = "/appsender.AppSender/SendAppGossipSpecific" AppSender_SendCrossChainAppRequest_FullMethodName = "/appsender.AppSender/SendCrossChainAppRequest" AppSender_SendCrossChainAppResponse_FullMethodName = "/appsender.AppSender/SendCrossChainAppResponse" + AppSender_SendCrossChainAppError_FullMethodName = "/appsender.AppSender/SendCrossChainAppError" ) // AppSenderClient is the client API for AppSender service. @@ -34,10 +36,12 @@ const ( type AppSenderClient interface { SendAppRequest(ctx context.Context, in *SendAppRequestMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) SendAppResponse(ctx context.Context, in *SendAppResponseMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) + SendAppError(ctx context.Context, in *SendAppErrorMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) SendAppGossip(ctx context.Context, in *SendAppGossipMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) SendAppGossipSpecific(ctx context.Context, in *SendAppGossipSpecificMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) SendCrossChainAppRequest(ctx context.Context, in *SendCrossChainAppRequestMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) SendCrossChainAppResponse(ctx context.Context, in *SendCrossChainAppResponseMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) + SendCrossChainAppError(ctx context.Context, in *SendCrossChainAppErrorMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) } type appSenderClient struct { @@ -66,6 +70,15 @@ func (c *appSenderClient) SendAppResponse(ctx context.Context, in *SendAppRespon return out, nil } +func (c *appSenderClient) SendAppError(ctx context.Context, in *SendAppErrorMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, AppSender_SendAppError_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *appSenderClient) SendAppGossip(ctx context.Context, in *SendAppGossipMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) err := c.cc.Invoke(ctx, AppSender_SendAppGossip_FullMethodName, in, out, opts...) @@ -102,16 +115,27 @@ func (c *appSenderClient) SendCrossChainAppResponse(ctx context.Context, in *Sen return out, nil } +func (c *appSenderClient) SendCrossChainAppError(ctx context.Context, in *SendCrossChainAppErrorMsg, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, AppSender_SendCrossChainAppError_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // AppSenderServer is the server API for AppSender service. // All implementations must embed UnimplementedAppSenderServer // for forward compatibility type AppSenderServer interface { SendAppRequest(context.Context, *SendAppRequestMsg) (*emptypb.Empty, error) SendAppResponse(context.Context, *SendAppResponseMsg) (*emptypb.Empty, error) + SendAppError(context.Context, *SendAppErrorMsg) (*emptypb.Empty, error) SendAppGossip(context.Context, *SendAppGossipMsg) (*emptypb.Empty, error) SendAppGossipSpecific(context.Context, *SendAppGossipSpecificMsg) (*emptypb.Empty, error) SendCrossChainAppRequest(context.Context, *SendCrossChainAppRequestMsg) (*emptypb.Empty, error) SendCrossChainAppResponse(context.Context, *SendCrossChainAppResponseMsg) (*emptypb.Empty, error) + SendCrossChainAppError(context.Context, *SendCrossChainAppErrorMsg) (*emptypb.Empty, error) mustEmbedUnimplementedAppSenderServer() } @@ -125,6 +149,9 @@ func (UnimplementedAppSenderServer) SendAppRequest(context.Context, *SendAppRequ func (UnimplementedAppSenderServer) SendAppResponse(context.Context, *SendAppResponseMsg) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method SendAppResponse not implemented") } +func (UnimplementedAppSenderServer) SendAppError(context.Context, *SendAppErrorMsg) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendAppError not implemented") +} func (UnimplementedAppSenderServer) SendAppGossip(context.Context, *SendAppGossipMsg) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method SendAppGossip not implemented") } @@ -137,6 +164,9 @@ func (UnimplementedAppSenderServer) SendCrossChainAppRequest(context.Context, *S func (UnimplementedAppSenderServer) SendCrossChainAppResponse(context.Context, *SendCrossChainAppResponseMsg) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method SendCrossChainAppResponse not implemented") } +func (UnimplementedAppSenderServer) SendCrossChainAppError(context.Context, *SendCrossChainAppErrorMsg) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendCrossChainAppError not implemented") +} func (UnimplementedAppSenderServer) mustEmbedUnimplementedAppSenderServer() {} // UnsafeAppSenderServer may be embedded to opt out of forward compatibility for this service. @@ -186,6 +216,24 @@ func _AppSender_SendAppResponse_Handler(srv interface{}, ctx context.Context, de return interceptor(ctx, in, info, handler) } +func _AppSender_SendAppError_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SendAppErrorMsg) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AppSenderServer).SendAppError(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AppSender_SendAppError_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AppSenderServer).SendAppError(ctx, req.(*SendAppErrorMsg)) + } + return interceptor(ctx, in, info, handler) +} + func _AppSender_SendAppGossip_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SendAppGossipMsg) if err := dec(in); err != nil { @@ -258,6 +306,24 @@ func _AppSender_SendCrossChainAppResponse_Handler(srv interface{}, ctx context.C return interceptor(ctx, in, info, handler) } +func _AppSender_SendCrossChainAppError_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SendCrossChainAppErrorMsg) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AppSenderServer).SendCrossChainAppError(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AppSender_SendCrossChainAppError_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AppSenderServer).SendCrossChainAppError(ctx, req.(*SendCrossChainAppErrorMsg)) + } + return interceptor(ctx, in, info, handler) +} + // AppSender_ServiceDesc is the grpc.ServiceDesc for AppSender service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -273,6 +339,10 @@ var AppSender_ServiceDesc = grpc.ServiceDesc{ MethodName: "SendAppResponse", Handler: _AppSender_SendAppResponse_Handler, }, + { + MethodName: "SendAppError", + Handler: _AppSender_SendAppError_Handler, + }, { MethodName: "SendAppGossip", Handler: _AppSender_SendAppGossip_Handler, @@ -289,6 +359,10 @@ var AppSender_ServiceDesc = grpc.ServiceDesc{ MethodName: "SendCrossChainAppResponse", Handler: _AppSender_SendCrossChainAppResponse_Handler, }, + { + MethodName: "SendCrossChainAppError", + Handler: _AppSender_SendCrossChainAppError_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "appsender/appsender.proto", diff --git a/snow/engine/common/appsender/appsender_client.go b/snow/engine/common/appsender/appsender_client.go index acde7109f75..ed1248d2aac 100644 --- a/snow/engine/common/appsender/appsender_client.go +++ b/snow/engine/common/appsender/appsender_client.go @@ -48,6 +48,20 @@ func (c *Client) SendCrossChainAppResponse(ctx context.Context, chainID ids.ID, return err } +func (c *Client) SendCrossChainAppError(ctx context.Context, chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) error { + _, err := c.client.SendCrossChainAppError( + ctx, + &appsenderpb.SendCrossChainAppErrorMsg{ + ChainId: chainID[:], + RequestId: requestID, + ErrorCode: errorCode, + ErrorMessage: errorMessage, + }, + ) + + return err +} + func (c *Client) SendAppRequest(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, request []byte) error { nodeIDsBytes := make([][]byte, nodeIDs.Len()) i := 0 @@ -78,6 +92,19 @@ func (c *Client) SendAppResponse(ctx context.Context, nodeID ids.NodeID, request return err } +func (c *Client) SendAppError(ctx context.Context, nodeID ids.NodeID, requestID uint32, errorCode int32, errorMessage string) error { + _, err := c.client.SendAppError(ctx, + &appsenderpb.SendAppErrorMsg{ + NodeId: nodeID[:], + RequestId: requestID, + ErrorCode: errorCode, + ErrorMessage: errorMessage, + }, + ) + + return err +} + func (c *Client) SendAppGossip(ctx context.Context, msg []byte) error { _, err := c.client.SendAppGossip( ctx, diff --git a/snow/engine/common/appsender/appsender_server.go b/snow/engine/common/appsender/appsender_server.go index 84763e17bf1..eedce556ce7 100644 --- a/snow/engine/common/appsender/appsender_server.go +++ b/snow/engine/common/appsender/appsender_server.go @@ -45,6 +45,15 @@ func (s *Server) SendCrossChainAppResponse(ctx context.Context, msg *appsenderpb return &emptypb.Empty{}, s.appSender.SendCrossChainAppResponse(ctx, chainID, msg.RequestId, msg.Response) } +func (s *Server) SendCrossChainAppError(ctx context.Context, msg *appsenderpb.SendCrossChainAppErrorMsg) (*emptypb.Empty, error) { + chainID, err := ids.ToID(msg.ChainId) + if err != nil { + return &emptypb.Empty{}, err + } + + return &emptypb.Empty{}, s.appSender.SendCrossChainAppError(ctx, chainID, msg.RequestId, msg.ErrorCode, msg.ErrorMessage) +} + func (s *Server) SendAppRequest(ctx context.Context, req *appsenderpb.SendAppRequestMsg) (*emptypb.Empty, error) { nodeIDs := set.NewSet[ids.NodeID](len(req.NodeIds)) for _, nodeIDBytes := range req.NodeIds { @@ -67,6 +76,16 @@ func (s *Server) SendAppResponse(ctx context.Context, req *appsenderpb.SendAppRe return &emptypb.Empty{}, err } +func (s *Server) SendAppError(ctx context.Context, req *appsenderpb.SendAppErrorMsg) (*emptypb.Empty, error) { + nodeID, err := ids.ToNodeID(req.NodeId) + if err != nil { + return nil, err + } + + err = s.appSender.SendAppError(ctx, nodeID, req.RequestId, req.ErrorCode, req.ErrorMessage) + return &emptypb.Empty{}, err +} + func (s *Server) SendAppGossip(ctx context.Context, req *appsenderpb.SendAppGossipMsg) (*emptypb.Empty, error) { err := s.appSender.SendAppGossip(ctx, req.Msg) return &emptypb.Empty{}, err diff --git a/snow/engine/common/mock_sender.go b/snow/engine/common/mock_sender.go index 6ebeeb63667..c22cfb45bfe 100644 --- a/snow/engine/common/mock_sender.go +++ b/snow/engine/common/mock_sender.go @@ -104,6 +104,20 @@ func (mr *MockSenderMockRecorder) SendAncestors(ctx, nodeID, requestID, containe return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAncestors", reflect.TypeOf((*MockSender)(nil).SendAncestors), ctx, nodeID, requestID, containers) } +// SendAppError mocks base method. +func (m *MockSender) SendAppError(ctx context.Context, nodeID ids.NodeID, requestID uint32, errorCode int32, errorMessage string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendAppError", ctx, nodeID, requestID, errorCode, errorMessage) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendAppError indicates an expected call of SendAppError. +func (mr *MockSenderMockRecorder) SendAppError(ctx, nodeID, requestID, errorCode, errorMessage any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAppError", reflect.TypeOf((*MockSender)(nil).SendAppError), ctx, nodeID, requestID, errorCode, errorMessage) +} + // SendAppGossip mocks base method. func (m *MockSender) SendAppGossip(ctx context.Context, appGossipBytes []byte) error { m.ctrl.T.Helper() @@ -172,6 +186,20 @@ func (mr *MockSenderMockRecorder) SendChits(ctx, nodeID, requestID, preferredID, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendChits", reflect.TypeOf((*MockSender)(nil).SendChits), ctx, nodeID, requestID, preferredID, preferredIDAtHeight, acceptedID) } +// SendCrossChainAppError mocks base method. +func (m *MockSender) SendCrossChainAppError(ctx context.Context, chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendCrossChainAppError", ctx, chainID, requestID, errorCode, errorMessage) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendCrossChainAppError indicates an expected call of SendCrossChainAppError. +func (mr *MockSenderMockRecorder) SendCrossChainAppError(ctx, chainID, requestID, errorCode, errorMessage any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCrossChainAppError", reflect.TypeOf((*MockSender)(nil).SendCrossChainAppError), ctx, chainID, requestID, errorCode, errorMessage) +} + // SendCrossChainAppRequest mocks base method. func (m *MockSender) SendCrossChainAppRequest(ctx context.Context, chainID ids.ID, requestID uint32, appRequestBytes []byte) error { m.ctrl.T.Helper() diff --git a/snow/engine/common/sender.go b/snow/engine/common/sender.go index b40084fc714..d0ba856347a 100644 --- a/snow/engine/common/sender.go +++ b/snow/engine/common/sender.go @@ -180,6 +180,8 @@ type NetworkAppSender interface { // This response must be in response to an AppRequest that the VM corresponding // to this AppSender received from [nodeID] with ID [requestID]. SendAppResponse(ctx context.Context, nodeID ids.NodeID, requestID uint32, appResponseBytes []byte) error + // SendAppError sends an application-level error to an AppRequest + SendAppError(ctx context.Context, nodeID ids.NodeID, requestID uint32, errorCode int32, errorMessage string) error // Gossip an application-level message. SendAppGossip(ctx context.Context, appGossipBytes []byte) error SendAppGossipSpecific(ctx context.Context, nodeIDs set.Set[ids.NodeID], appGossipBytes []byte) error @@ -204,6 +206,8 @@ type CrossChainAppSender interface { // corresponding to this CrossChainAppSender received from [chainID] with ID // [requestID]. SendCrossChainAppResponse(ctx context.Context, chainID ids.ID, requestID uint32, appResponseBytes []byte) error + // SendCrossChainAppError sends an application-level error to a CrossChainAppRequest + SendCrossChainAppError(ctx context.Context, chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) error } // AppSender sends application (VM) level messages. diff --git a/snow/engine/common/test_sender.go b/snow/engine/common/test_sender.go index 32af682838f..ef77fc658a5 100644 --- a/snow/engine/common/test_sender.go +++ b/snow/engine/common/test_sender.go @@ -21,6 +21,7 @@ var ( errAccept = errors.New("unexpectedly called Accept") errSendAppRequest = errors.New("unexpectedly called SendAppRequest") errSendAppResponse = errors.New("unexpectedly called SendAppResponse") + errSendAppError = errors.New("unexpectedly called SendAppError") errSendAppGossip = errors.New("unexpectedly called SendAppGossip") errSendAppGossipSpecific = errors.New("unexpectedly called SendAppGossipSpecific") ) @@ -37,8 +38,9 @@ type SenderTest struct { CantSendGet, CantSendGetAncestors, CantSendPut, CantSendAncestors, CantSendPullQuery, CantSendPushQuery, CantSendChits, CantSendGossip, - CantSendAppRequest, CantSendAppResponse, CantSendAppGossip, CantSendAppGossipSpecific, - CantSendCrossChainAppRequest, CantSendCrossChainAppResponse bool + CantSendAppRequest, CantSendAppResponse, CantSendAppError, + CantSendAppGossip, CantSendAppGossipSpecific, + CantSendCrossChainAppRequest, CantSendCrossChainAppResponse, CantSendCrossChainAppError bool AcceptF func(*snow.ConsensusContext, ids.ID, []byte) error SendGetStateSummaryFrontierF func(context.Context, set.Set[ids.NodeID], uint32) @@ -59,10 +61,12 @@ type SenderTest struct { SendGossipF func(context.Context, []byte) 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 SendAppGossipF func(context.Context, []byte) error SendAppGossipSpecificF func(context.Context, set.Set[ids.NodeID], []byte) error SendCrossChainAppRequestF func(context.Context, ids.ID, uint32, []byte) SendCrossChainAppResponseF func(context.Context, ids.ID, uint32, []byte) + SendCrossChainAppErrorF func(context.Context, ids.ID, uint32, int32, string) } // Default set the default callable value to [cant] @@ -308,6 +312,18 @@ func (s *SenderTest) SendCrossChainAppResponse(ctx context.Context, chainID ids. return nil } +// SendCrossChainAppError calls SendCrossChainAppErrorF 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 *SenderTest) SendCrossChainAppError(ctx context.Context, chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) error { + if s.SendCrossChainAppErrorF != nil { + s.SendCrossChainAppErrorF(ctx, chainID, requestID, errorCode, errorMessage) + } else if s.CantSendCrossChainAppError && s.T != nil { + require.FailNow(s.T, "Unexpectedly called SendCrossChainAppError") + } + return nil +} + // SendAppRequest calls SendAppRequestF if it was initialized. If it wasn't // initialized and this function shouldn't be called and testing was // initialized, then testing will fail. @@ -334,6 +350,19 @@ func (s *SenderTest) SendAppResponse(ctx context.Context, nodeID ids.NodeID, req return errSendAppResponse } +// SendAppError calls SendAppErrorF 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 *SenderTest) SendAppError(ctx context.Context, nodeID ids.NodeID, requestID uint32, code int32, message string) error { + switch { + case s.SendAppErrorF != nil: + return s.SendAppErrorF(ctx, nodeID, requestID, code, message) + case s.CantSendAppError && s.T != nil: + require.FailNow(s.T, errSendAppError.Error()) + } + return errSendAppError +} + // SendAppGossip calls SendAppGossipF if it was initialized. If it wasn't // initialized and this function shouldn't be called and testing was // initialized, then testing will fail. @@ -365,6 +394,8 @@ type FakeSender struct { SentAppRequest, SentAppResponse, SentAppGossip, SentAppGossipSpecific, SentCrossChainAppRequest, SentCrossChainAppResponse chan []byte + + SentAppError, SentCrossChainAppError chan *AppError } func (f FakeSender) SendAppRequest(_ context.Context, _ set.Set[ids.NodeID], _ uint32, bytes []byte) error { @@ -385,6 +416,18 @@ func (f FakeSender) SendAppResponse(_ context.Context, _ ids.NodeID, _ uint32, b return nil } +func (f FakeSender) SendAppError(_ context.Context, _ ids.NodeID, _ uint32, errorCode int32, errorMessage string) error { + if f.SentAppError == nil { + return nil + } + + f.SentAppError <- &AppError{ + Code: errorCode, + Message: errorMessage, + } + return nil +} + func (f FakeSender) SendAppGossip(_ context.Context, bytes []byte) error { if f.SentAppGossip == nil { return nil @@ -420,3 +463,15 @@ func (f FakeSender) SendCrossChainAppResponse(_ context.Context, _ ids.ID, _ uin f.SentCrossChainAppResponse <- bytes return nil } + +func (f FakeSender) SendCrossChainAppError(_ context.Context, _ ids.ID, _ uint32, errorCode int32, errorMessage string) error { + if f.SentCrossChainAppError == nil { + return nil + } + + f.SentCrossChainAppError <- &AppError{ + Code: errorCode, + Message: errorMessage, + } + return nil +} diff --git a/snow/networking/sender/sender.go b/snow/networking/sender/sender.go index 170c4ad4557..a7090e5d0b6 100644 --- a/snow/networking/sender/sender.go +++ b/snow/networking/sender/sender.go @@ -1253,6 +1253,21 @@ func (s *sender) SendCrossChainAppResponse(ctx context.Context, chainID ids.ID, return nil } +func (s *sender) SendCrossChainAppError(ctx context.Context, chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) error { + ctx = context.WithoutCancel(ctx) + + inMsg := message.InternalCrossChainAppError( + s.ctx.NodeID, + s.ctx.ChainID, + chainID, + requestID, + errorCode, + errorMessage, + ) + go s.router.HandleInbound(ctx, inMsg) + return nil +} + func (s *sender) SendAppRequest(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, appRequestBytes []byte) error { ctx = context.WithoutCancel(ctx) @@ -1443,6 +1458,72 @@ func (s *sender) SendAppResponse(ctx context.Context, nodeID ids.NodeID, request return nil } +func (s *sender) SendAppError(ctx context.Context, nodeID ids.NodeID, requestID uint32, errorCode int32, errorMessage string) error { + ctx = context.WithoutCancel(ctx) + + if nodeID == s.ctx.NodeID { + inMsg := message.InboundAppError( + nodeID, + s.ctx.ChainID, + requestID, + errorCode, + errorMessage, + ) + go s.router.HandleInbound(ctx, inMsg) + return nil + } + + // Create the outbound message. + outMsg, err := s.msgCreator.AppError( + s.ctx.ChainID, + requestID, + errorCode, + errorMessage, + ) + if err != nil { + s.ctx.Log.Error("failed to build message", + zap.Stringer("messageOp", message.AppErrorOp), + zap.Stringer("nodeID", nodeID), + zap.Stringer("chainID", s.ctx.ChainID), + zap.Uint32("requestID", requestID), + zap.Int32("errorCode", errorCode), + zap.String("errorMessage", errorMessage), + zap.Error(err), + ) + return nil + } + + // Send the message over the network. + sentTo := s.sender.Send( + outMsg, + set.Of(nodeID), + s.ctx.SubnetID, + s.subnet, + ) + if sentTo.Len() == 0 { + if s.ctx.Log.Enabled(logging.Verbo) { + s.ctx.Log.Verbo("failed to send message", + zap.Stringer("messageOp", message.AppErrorOp), + zap.Stringer("nodeID", nodeID), + zap.Stringer("chainID", s.ctx.ChainID), + zap.Uint32("requestID", requestID), + zap.Int32("errorCode", errorCode), + zap.String("errorMessage", errorMessage), + ) + } else { + s.ctx.Log.Debug("failed to send message", + zap.Stringer("messageOp", message.AppErrorOp), + zap.Stringer("nodeID", nodeID), + zap.Stringer("chainID", s.ctx.ChainID), + zap.Uint32("requestID", requestID), + zap.Int32("errorCode", errorCode), + zap.String("errorMessage", errorMessage), + ) + } + } + return nil +} + func (s *sender) SendAppGossipSpecific(_ context.Context, nodeIDs set.Set[ids.NodeID], appGossipBytes []byte) error { // Create the outbound message. outMsg, err := s.msgCreator.AppGossip(s.ctx.ChainID, appGossipBytes) diff --git a/snow/networking/sender/traced_sender.go b/snow/networking/sender/traced_sender.go index ee5b9abee24..a82264ab325 100644 --- a/snow/networking/sender/traced_sender.go +++ b/snow/networking/sender/traced_sender.go @@ -214,6 +214,18 @@ func (s *tracedSender) SendCrossChainAppResponse(ctx context.Context, chainID id return s.sender.SendCrossChainAppResponse(ctx, chainID, requestID, appResponseBytes) } +func (s *tracedSender) SendCrossChainAppError(ctx context.Context, chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) error { + ctx, span := s.tracer.Start(ctx, "tracedSender.SendCrossChainAppError", oteltrace.WithAttributes( + attribute.Stringer("chainID", chainID), + attribute.Int64("requestID", int64(requestID)), + attribute.Int64("errorCode", int64(errorCode)), + attribute.String("errorMessage", errorMessage), + )) + defer span.End() + + return s.sender.SendCrossChainAppError(ctx, chainID, requestID, errorCode, errorMessage) +} + func (s *tracedSender) SendAppRequest(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, appRequestBytes []byte) error { ctx, span := s.tracer.Start(ctx, "tracedSender.SendAppRequest", oteltrace.WithAttributes( attribute.Int64("requestID", int64(requestID)), @@ -235,6 +247,18 @@ func (s *tracedSender) SendAppResponse(ctx context.Context, nodeID ids.NodeID, r return s.sender.SendAppResponse(ctx, nodeID, requestID, appResponseBytes) } +func (s *tracedSender) SendAppError(ctx context.Context, nodeID ids.NodeID, requestID uint32, errorCode int32, errorMessage string) error { + ctx, span := s.tracer.Start(ctx, "tracedSender.SendAppError", oteltrace.WithAttributes( + attribute.Stringer("nodeID", nodeID), + attribute.Int64("requestID", int64(requestID)), + attribute.Int64("errorCode", int64(errorCode)), + attribute.String("errorMessage", errorMessage), + )) + defer span.End() + + return s.sender.SendAppError(ctx, nodeID, requestID, errorCode, errorMessage) +} + func (s *tracedSender) SendAppGossipSpecific(ctx context.Context, nodeIDs set.Set[ids.NodeID], appGossipBytes []byte) error { _, span := s.tracer.Start(ctx, "tracedSender.SendAppGossipSpecific", oteltrace.WithAttributes( attribute.Int("gossipLen", len(appGossipBytes)), diff --git a/utils/bimap/bimap.go b/utils/bimap/bimap.go index d0651ff36cd..bde60d97b13 100644 --- a/utils/bimap/bimap.go +++ b/utils/bimap/bimap.go @@ -8,6 +8,8 @@ import ( "encoding/json" "errors" + "golang.org/x/exp/maps" + "github.com/ava-labs/avalanchego/utils" ) @@ -110,6 +112,17 @@ func (m *BiMap[K, V]) DeleteValue(val V) (K, bool) { return key, true } +// Keys returns the keys of the map. The keys will be in an indeterminate order. +func (m *BiMap[K, _]) Keys() []K { + return maps.Keys(m.keyToValue) +} + +// Values returns the values of the map. The values will be in an indeterminate +// order. +func (m *BiMap[_, V]) Values() []V { + return maps.Values(m.keyToValue) +} + // Len return the number of entries in this map. func (m *BiMap[K, V]) Len() int { return len(m.keyToValue) diff --git a/utils/bimap/bimap_test.go b/utils/bimap/bimap_test.go index 9b4433a51c7..1792bec9a3d 100644 --- a/utils/bimap/bimap_test.go +++ b/utils/bimap/bimap_test.go @@ -309,23 +309,33 @@ func TestBiMapDeleteValue(t *testing.T) { } } -func TestBiMapLen(t *testing.T) { +func TestBiMapLenAndLists(t *testing.T) { require := require.New(t) m := New[int, int]() require.Zero(m.Len()) + require.Empty(m.Keys()) + require.Empty(m.Values()) m.Put(1, 2) require.Equal(1, m.Len()) + require.ElementsMatch([]int{1}, m.Keys()) + require.ElementsMatch([]int{2}, m.Values()) m.Put(2, 3) require.Equal(2, m.Len()) + require.ElementsMatch([]int{1, 2}, m.Keys()) + require.ElementsMatch([]int{2, 3}, m.Values()) m.Put(1, 3) require.Equal(1, m.Len()) + require.ElementsMatch([]int{1}, m.Keys()) + require.ElementsMatch([]int{3}, m.Values()) m.DeleteKey(1) require.Zero(m.Len()) + require.Empty(m.Keys()) + require.Empty(m.Values()) } func TestBiMapJSON(t *testing.T) { diff --git a/vms/platformvm/block/builder/builder_test.go b/vms/platformvm/block/builder/builder_test.go index 0c463eaf8c4..e3486f96dca 100644 --- a/vms/platformvm/block/builder/builder_test.go +++ b/vms/platformvm/block/builder/builder_test.go @@ -32,7 +32,7 @@ import ( func TestBuildBlockBasic(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, latestFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -75,7 +75,7 @@ func TestBuildBlockBasic(t *testing.T) { func TestBuildBlockDoesNotBuildWithEmptyMempool(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, latestFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -92,7 +92,7 @@ func TestBuildBlockDoesNotBuildWithEmptyMempool(t *testing.T) { func TestBuildBlockShouldReward(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, latestFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -194,7 +194,7 @@ func TestBuildBlockShouldReward(t *testing.T) { func TestBuildBlockAdvanceTime(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, latestFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -227,7 +227,7 @@ func TestBuildBlockAdvanceTime(t *testing.T) { func TestBuildBlockForceAdvanceTime(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, latestFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -282,7 +282,7 @@ func TestBuildBlockForceAdvanceTime(t *testing.T) { func TestBuildBlockDropExpiredStakerTxs(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, latestFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -388,7 +388,7 @@ func TestBuildBlockDropExpiredStakerTxs(t *testing.T) { func TestBuildBlockInvalidStakingDurations(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, latestFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -474,7 +474,7 @@ func TestBuildBlockInvalidStakingDurations(t *testing.T) { func TestPreviouslyDroppedTxsCannotBeReAddedToMempool(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, latestFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -518,7 +518,7 @@ func TestPreviouslyDroppedTxsCannotBeReAddedToMempool(t *testing.T) { func TestNoErrorOnUnexpectedSetPreferenceDuringBootstrapping(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, latestFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index c2c756cb2d0..9190f01e2c6 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -5,6 +5,7 @@ package builder import ( "context" + "fmt" "testing" "time" @@ -57,6 +58,14 @@ import ( const ( defaultWeight = 10000 trackChecksum = false + + apricotPhase3 fork = iota + apricotPhase5 + banff + cortina + durango + + latestFork = durango ) var ( @@ -84,6 +93,8 @@ func init() { } } +type fork uint8 + type mutableSharedMemory struct { atomic.SharedMemory } @@ -110,12 +121,12 @@ type environment struct { backend txexecutor.Backend } -func newEnvironment(t *testing.T) *environment { +func newEnvironment(t *testing.T, f fork) *environment { //nolint:unparam require := require.New(t) res := &environment{ isBootstrapped: &utils.Atomic[bool]{}, - config: defaultConfig(), + config: defaultConfig(t, f), clk: defaultClock(), } res.isBootstrapped.Set(true) @@ -293,7 +304,34 @@ func defaultState( return state } -func defaultConfig() *config.Config { +func defaultConfig(t *testing.T, f fork) *config.Config { + var ( + apricotPhase3Time = mockable.MaxTime + apricotPhase5Time = mockable.MaxTime + banffTime = mockable.MaxTime + cortinaTime = mockable.MaxTime + durangoTime = mockable.MaxTime + ) + + switch f { + case durango: + durangoTime = time.Time{} // neglecting fork ordering for this package's tests + fallthrough + case cortina: + cortinaTime = time.Time{} // neglecting fork ordering for this package's tests + fallthrough + case banff: + banffTime = time.Time{} // neglecting fork ordering for this package's tests + fallthrough + case apricotPhase5: + apricotPhase5Time = defaultValidateEndTime + fallthrough + case apricotPhase3: + apricotPhase3Time = defaultValidateEndTime + default: + require.NoError(t, fmt.Errorf("unhandled fork %d", f)) + } + return &config.Config{ Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), @@ -312,9 +350,11 @@ func defaultConfig() *config.Config { MintingPeriod: 365 * 24 * time.Hour, SupplyCap: 720 * units.MegaAvax, }, - ApricotPhase3Time: defaultValidateEndTime, - ApricotPhase5Time: defaultValidateEndTime, - BanffTime: time.Time{}, // neglecting fork ordering this for package tests + ApricotPhase3Time: apricotPhase3Time, + ApricotPhase5Time: apricotPhase5Time, + BanffTime: banffTime, + CortinaTime: cortinaTime, + DurangoTime: durangoTime, } } diff --git a/vms/platformvm/block/builder/standard_block_test.go b/vms/platformvm/block/builder/standard_block_test.go index 1ae257cdadb..fa1a07fb3f0 100644 --- a/vms/platformvm/block/builder/standard_block_test.go +++ b/vms/platformvm/block/builder/standard_block_test.go @@ -22,7 +22,7 @@ import ( func TestAtomicTxImports(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, latestFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 5fce5c632c2..825625b7c77 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -59,6 +59,12 @@ const ( defaultWeight = 10000 trackChecksum = false + + apricotPhase3 fork = iota + apricotPhase5 + banff + cortina + durango ) var ( @@ -89,6 +95,8 @@ func init() { type stakerStatus uint +type fork uint8 + type staker struct { nodeID ids.NodeID rewardAddress ids.ShortID @@ -124,10 +132,10 @@ type environment struct { backend *executor.Backend } -func newEnvironment(t *testing.T, ctrl *gomock.Controller) *environment { +func newEnvironment(t *testing.T, ctrl *gomock.Controller, f fork) *environment { res := &environment{ isBootstrapped: &utils.Atomic[bool]{}, - config: defaultConfig(), + config: defaultConfig(t, f), clk: defaultClock(), } res.isBootstrapped.Set(true) @@ -320,7 +328,34 @@ func defaultState( return state } -func defaultConfig() *config.Config { +func defaultConfig(t *testing.T, f fork) *config.Config { + var ( + apricotPhase3Time = mockable.MaxTime + apricotPhase5Time = mockable.MaxTime + banffTime = mockable.MaxTime + cortinaTime = mockable.MaxTime + durangoTime = mockable.MaxTime + ) + + switch f { + case durango: + durangoTime = time.Time{} // neglecting fork ordering for this package's tests + fallthrough + case cortina: + cortinaTime = time.Time{} // neglecting fork ordering for this package's tests + fallthrough + case banff: + banffTime = time.Time{} // neglecting fork ordering for this package's tests + fallthrough + case apricotPhase5: + apricotPhase5Time = defaultValidateEndTime + fallthrough + case apricotPhase3: + apricotPhase3Time = defaultValidateEndTime + default: + require.NoError(t, fmt.Errorf("unhandled fork %d", f)) + } + return &config.Config{ Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), @@ -339,9 +374,11 @@ func defaultConfig() *config.Config { MintingPeriod: 365 * 24 * time.Hour, SupplyCap: 720 * units.MegaAvax, }, - ApricotPhase3Time: defaultValidateEndTime, - ApricotPhase5Time: defaultValidateEndTime, - BanffTime: mockable.MaxTime, + ApricotPhase3Time: apricotPhase3Time, + ApricotPhase5Time: apricotPhase5Time, + BanffTime: banffTime, + CortinaTime: cortinaTime, + DurangoTime: durangoTime, } } diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index a4eddbbeb22..984c8081ae4 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -19,7 +19,6 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" - "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/block" "github.com/ava-labs/avalanchego/vms/platformvm/reward" @@ -35,7 +34,7 @@ func TestApricotProposalBlockTimeVerification(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - env := newEnvironment(t, ctrl) + env := newEnvironment(t, ctrl, apricotPhase5) // create apricotParentBlk. It's a standard one for simplicity parentHeight := uint64(2022) @@ -138,10 +137,7 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - env := newEnvironment(t, ctrl) - env.clk.Set(defaultGenesisTime) - env.config.BanffTime = time.Time{} // activate Banff - env.config.DurangoTime = mockable.MaxTime // deactivate Durango + env := newEnvironment(t, ctrl, banff) // create parentBlock. It's a standard one for simplicity parentTime := defaultGenesisTime @@ -549,8 +545,7 @@ func TestBanffProposalBlockUpdateStakers(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff + env := newEnvironment(t, nil, banff) subnetID := testSubnet1.ID() env.config.TrackedSubnets.Add(subnetID) @@ -702,8 +697,7 @@ func TestBanffProposalBlockUpdateStakers(t *testing.T) { func TestBanffProposalBlockRemoveSubnetValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff + env := newEnvironment(t, nil, banff) subnetID := testSubnet1.ID() env.config.TrackedSubnets.Add(subnetID) @@ -845,8 +839,7 @@ func TestBanffProposalBlockTrackedSubnet(t *testing.T) { for _, tracked := range []bool{true, false} { t.Run(fmt.Sprintf("tracked %t", tracked), func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff + env := newEnvironment(t, nil, banff) subnetID := testSubnet1.ID() if tracked { @@ -950,8 +943,7 @@ func TestBanffProposalBlockTrackedSubnet(t *testing.T) { func TestBanffProposalBlockDelegatorStakerWeight(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff + env := newEnvironment(t, nil, banff) // Case: Timestamp is after next validator start time // Add a pending validator @@ -1135,8 +1127,7 @@ func TestBanffProposalBlockDelegatorStakerWeight(t *testing.T) { func TestBanffProposalBlockDelegatorStakers(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff + env := newEnvironment(t, nil, banff) // Case: Timestamp is after next validator start time // Add a pending validator @@ -1320,9 +1311,7 @@ func TestBanffProposalBlockDelegatorStakers(t *testing.T) { func TestAddValidatorProposalBlock(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff - env.config.DurangoTime = time.Time{} // activate Durango + env := newEnvironment(t, nil, durango) now := env.clk.Time() diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index 8d20a718650..b77846351bc 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -29,7 +29,7 @@ func TestApricotStandardBlockTimeVerification(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - env := newEnvironment(t, ctrl) + env := newEnvironment(t, ctrl, apricotPhase5) // setup and store parent block // it's a standard block for simplicity @@ -82,10 +82,9 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - env := newEnvironment(t, ctrl) + env := newEnvironment(t, ctrl, banff) now := env.clk.Time() env.clk.Set(now) - env.config.BanffTime = time.Time{} // activate Banff // setup and store parent block // it's a standard block for simplicity @@ -290,8 +289,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { func TestBanffStandardBlockUpdatePrimaryNetworkStakers(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff + env := newEnvironment(t, nil, banff) // Case: Timestamp is after next validator start time // Add a pending validator @@ -492,8 +490,7 @@ func TestBanffStandardBlockUpdateStakers(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff + env := newEnvironment(t, nil, banff) subnetID := testSubnet1.ID() env.config.TrackedSubnets.Add(subnetID) @@ -592,8 +589,7 @@ func TestBanffStandardBlockUpdateStakers(t *testing.T) { // is after the new timestamp func TestBanffStandardBlockRemoveSubnetValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff + env := newEnvironment(t, nil, banff) subnetID := testSubnet1.ID() env.config.TrackedSubnets.Add(subnetID) @@ -690,8 +686,7 @@ func TestBanffStandardBlockTrackedSubnet(t *testing.T) { for _, tracked := range []bool{true, false} { t.Run(fmt.Sprintf("tracked %t", tracked), func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff + env := newEnvironment(t, nil, banff) subnetID := testSubnet1.ID() if tracked { @@ -751,8 +746,7 @@ func TestBanffStandardBlockTrackedSubnet(t *testing.T) { func TestBanffStandardBlockDelegatorStakerWeight(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) - env.config.BanffTime = time.Time{} // activate Banff + env := newEnvironment(t, nil, banff) // Case: Timestamp is after next validator start time // Add a pending validator diff --git a/vms/platformvm/txs/executor/advance_time_test.go b/vms/platformvm/txs/executor/advance_time_test.go index 167ea5cb8e2..4e106a82de1 100644 --- a/vms/platformvm/txs/executor/advance_time_test.go +++ b/vms/platformvm/txs/executor/advance_time_test.go @@ -34,7 +34,7 @@ func newAdvanceTimeTx(t testing.TB, timestamp time.Time) (*txs.Tx, error) { // for the primary network func TestAdvanceTimeTxUpdatePrimaryNetworkStakers(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() dummyHeight := uint64(1) @@ -97,7 +97,7 @@ func TestAdvanceTimeTxUpdatePrimaryNetworkStakers(t *testing.T) { // Ensure semantic verification fails when proposed timestamp is at or before current timestamp func TestAdvanceTimeTxTimestampTooEarly(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) tx, err := newAdvanceTimeTx(t, env.state.GetTimestamp()) require.NoError(err) @@ -121,7 +121,7 @@ func TestAdvanceTimeTxTimestampTooEarly(t *testing.T) { // Ensure semantic verification fails when proposed timestamp is after next validator set change time func TestAdvanceTimeTxTimestampTooLate(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -154,7 +154,7 @@ func TestAdvanceTimeTxTimestampTooLate(t *testing.T) { } // Case: Timestamp is after next validator end time - env = newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env = newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -354,7 +354,7 @@ func TestAdvanceTimeTxUpdateStakers(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -458,7 +458,7 @@ func TestAdvanceTimeTxUpdateStakers(t *testing.T) { // is after the new timestamp func TestAdvanceTimeTxRemoveSubnetValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -562,7 +562,7 @@ func TestTrackedSubnet(t *testing.T) { for _, tracked := range []bool{true, false} { t.Run(fmt.Sprintf("tracked %t", tracked), func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() dummyHeight := uint64(1) @@ -631,7 +631,7 @@ func TestTrackedSubnet(t *testing.T) { func TestAdvanceTimeTxDelegatorStakerWeight(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() dummyHeight := uint64(1) @@ -737,7 +737,7 @@ func TestAdvanceTimeTxDelegatorStakerWeight(t *testing.T) { func TestAdvanceTimeTxDelegatorStakers(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() dummyHeight := uint64(1) @@ -832,7 +832,7 @@ func TestAdvanceTimeTxDelegatorStakers(t *testing.T) { func TestAdvanceTimeTxAfterBanff(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, durango) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() env.clk.Set(defaultGenesisTime) // VM's clock reads the genesis time @@ -864,7 +864,7 @@ func TestAdvanceTimeTxAfterBanff(t *testing.T) { // Ensure marshaling/unmarshaling works func TestAdvanceTimeTxUnmarshal(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 8da002d2c5c..8209c9756ba 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -25,7 +25,7 @@ import ( // Ensure Execute fails when there are not enough control sigs func TestCreateChainTxInsufficientControlSigs(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banff) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -59,7 +59,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { // Ensure Execute fails when an incorrect control signature is given func TestCreateChainTxWrongControlSig(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banff) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -100,7 +100,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { // its validator set doesn't exist func TestCreateChainTxNoSuchSubnet(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banff) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -133,7 +133,7 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { // Ensure valid tx passes semanticVerify func TestCreateChainTxValid(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banff) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -191,7 +191,7 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { t.Run(test.name, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banff) env.config.ApricotPhase3Time = ap3Time ins, outs, _, signers, err := env.utxosHandler.Spend(env.state, preFundedKeys, 0, test.fee, ids.ShortEmpty) diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 6d968daa4df..259a5596218 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -49,7 +49,7 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { t.Run(test.name, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase3) env.config.ApricotPhase3Time = ap3Time env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/txs/executor/export_test.go b/vms/platformvm/txs/executor/export_test.go index 1194b3319d6..0ee1966e608 100644 --- a/vms/platformvm/txs/executor/export_test.go +++ b/vms/platformvm/txs/executor/export_test.go @@ -15,7 +15,7 @@ import ( ) func TestNewExportTx(t *testing.T) { - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banff) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index afba76a3f95..f319b19826a 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -50,6 +50,12 @@ import ( const ( defaultWeight = 5 * units.MilliAvax trackChecksum = false + + apricotPhase3 fork = iota + apricotPhase5 + banff + cortina + durango ) var ( @@ -78,6 +84,8 @@ func init() { } } +type fork uint8 + type mutableSharedMemory struct { atomic.SharedMemory } @@ -111,12 +119,12 @@ func (e *environment) SetState(blkID ids.ID, chainState state.Chain) { e.states[blkID] = chainState } -func newEnvironment(t *testing.T, postBanff, postCortina, postDurango bool) *environment { +func newEnvironment(t *testing.T, f fork) *environment { var isBootstrapped utils.Atomic[bool] isBootstrapped.Set(true) - config := defaultConfig(postBanff, postCortina, postDurango) - clk := defaultClock(postBanff || postCortina || postDurango) + config := defaultConfig(t, f) + clk := defaultClock(f) baseDB := versiondb.New(memdb.New()) ctx := snowtest.Context(t, snowtest.PChainID) @@ -271,18 +279,32 @@ func defaultState( return state } -func defaultConfig(postBanff, postCortina, postDurango bool) *config.Config { - banffTime := mockable.MaxTime - if postBanff { - banffTime = defaultValidateEndTime.Add(-2 * time.Second) - } - cortinaTime := mockable.MaxTime - if postCortina { - cortinaTime = defaultValidateStartTime.Add(-2 * time.Second) - } - durangoTime := mockable.MaxTime - if postDurango { +func defaultConfig(t *testing.T, f fork) *config.Config { + var ( + apricotPhase3Time = mockable.MaxTime + apricotPhase5Time = mockable.MaxTime + banffTime = mockable.MaxTime + cortinaTime = mockable.MaxTime + durangoTime = mockable.MaxTime + ) + + switch f { + case durango: durangoTime = defaultValidateStartTime.Add(-2 * time.Second) + fallthrough + case cortina: + cortinaTime = defaultValidateStartTime.Add(-2 * time.Second) + fallthrough + case banff: + banffTime = defaultValidateStartTime.Add(-2 * time.Second) + fallthrough + case apricotPhase5: + apricotPhase5Time = defaultValidateEndTime + fallthrough + case apricotPhase3: + apricotPhase3Time = defaultValidateEndTime + default: + require.NoError(t, fmt.Errorf("unhandled fork %d", f)) } return &config.Config{ @@ -303,18 +325,18 @@ func defaultConfig(postBanff, postCortina, postDurango bool) *config.Config { MintingPeriod: 365 * 24 * time.Hour, SupplyCap: 720 * units.MegaAvax, }, - ApricotPhase3Time: defaultValidateEndTime, - ApricotPhase5Time: defaultValidateEndTime, + ApricotPhase3Time: apricotPhase3Time, + ApricotPhase5Time: apricotPhase5Time, BanffTime: banffTime, CortinaTime: cortinaTime, DurangoTime: durangoTime, } } -func defaultClock(postFork bool) *mockable.Clock { +func defaultClock(f fork) *mockable.Clock { now := defaultGenesisTime - if postFork { - // 1 second after Banff fork + if f >= banff { + // 1 second after active fork now = defaultValidateEndTime.Add(-2 * time.Second) } clk := &mockable.Clock{} diff --git a/vms/platformvm/txs/executor/import_test.go b/vms/platformvm/txs/executor/import_test.go index 1b5ae8e8a45..bc52fabc247 100644 --- a/vms/platformvm/txs/executor/import_test.go +++ b/vms/platformvm/txs/executor/import_test.go @@ -24,7 +24,7 @@ import ( var fundedSharedMemoryCalls byte func TestNewImportTx(t *testing.T) { - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) type test struct { description string diff --git a/vms/platformvm/txs/executor/proposal_tx_executor_test.go b/vms/platformvm/txs/executor/proposal_tx_executor_test.go index 3cf61c63e6b..a6ecc21b405 100644 --- a/vms/platformvm/txs/executor/proposal_tx_executor_test.go +++ b/vms/platformvm/txs/executor/proposal_tx_executor_test.go @@ -93,7 +93,7 @@ func TestProposalTxExecuteAddDelegator(t *testing.T) { require.NoError(t, target.state.Commit()) } - dummyH := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + dummyH := newEnvironment(t, apricotPhase5) currentTimestamp := dummyH.state.GetTimestamp() type test struct { @@ -247,7 +247,7 @@ func TestProposalTxExecuteAddDelegator(t *testing.T) { for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { require := require.New(t) - freshTH := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + freshTH := newEnvironment(t, apricotPhase5) freshTH.config.ApricotPhase3Time = tt.AP3Time tx, err := freshTH.txBuilder.NewAddDelegatorTx( @@ -286,7 +286,7 @@ func TestProposalTxExecuteAddDelegator(t *testing.T) { func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -732,7 +732,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { func TestProposalTxExecuteAddValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/txs/executor/reward_validator_test.go b/vms/platformvm/txs/executor/reward_validator_test.go index a7c3da899df..cbd7f7bdf4e 100644 --- a/vms/platformvm/txs/executor/reward_validator_test.go +++ b/vms/platformvm/txs/executor/reward_validator_test.go @@ -35,7 +35,7 @@ func newRewardValidatorTx(t testing.TB, txID ids.ID) (*txs.Tx, error) { func TestRewardValidatorTxExecuteOnCommit(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) dummyHeight := uint64(1) currentStakerIterator, err := env.state.GetCurrentStakerIterator() @@ -135,7 +135,7 @@ func TestRewardValidatorTxExecuteOnCommit(t *testing.T) { func TestRewardValidatorTxExecuteOnAbort(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) dummyHeight := uint64(1) currentStakerIterator, err := env.state.GetCurrentStakerIterator() @@ -229,7 +229,7 @@ func TestRewardValidatorTxExecuteOnAbort(t *testing.T) { func TestRewardDelegatorTxExecuteOnCommitPreDelegateeDeferral(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) dummyHeight := uint64(1) vdrRewardAddress := ids.GenerateTestShortID() @@ -352,7 +352,7 @@ func TestRewardDelegatorTxExecuteOnCommitPreDelegateeDeferral(t *testing.T) { func TestRewardDelegatorTxExecuteOnCommitPostDelegateeDeferral(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, true /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, cortina) dummyHeight := uint64(1) vdrRewardAddress := ids.GenerateTestShortID() @@ -570,7 +570,7 @@ func TestRewardDelegatorTxExecuteOnCommitPostDelegateeDeferral(t *testing.T) { func TestRewardDelegatorTxAndValidatorTxExecuteOnCommitPostDelegateeDeferral(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, true /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, cortina) dummyHeight := uint64(1) vdrRewardAddress := ids.GenerateTestShortID() @@ -731,7 +731,7 @@ func TestRewardDelegatorTxAndValidatorTxExecuteOnCommitPostDelegateeDeferral(t * func TestRewardDelegatorTxExecuteOnAbort(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) dummyHeight := uint64(1) initialSupply, err := env.state.GetCurrentSupply(constants.PrimaryNetworkID) diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 94a3014eadd..69ad018caa1 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -43,7 +43,7 @@ var errTest = errors.New("non-nil error") func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -168,7 +168,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { require.NoError(t, target.state.Commit()) } - dummyH := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + dummyH := newEnvironment(t, apricotPhase5) currentTimestamp := dummyH.state.GetTimestamp() type test struct { @@ -322,7 +322,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { require := require.New(t) - freshTH := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + freshTH := newEnvironment(t, apricotPhase5) freshTH.config.ApricotPhase3Time = tt.AP3Time tx, err := freshTH.txBuilder.NewAddDelegatorTx( @@ -359,7 +359,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -800,7 +800,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { func TestBanffStandardTxExecutorAddValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banff) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -1047,7 +1047,7 @@ func TestDurangoDisabledTransactions(t *testing.T) { t.Run(tt.name, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, true /*=postCortina*/, true /*=postDurango*/) + env := newEnvironment(t, durango) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -1394,7 +1394,7 @@ func TestDurangoMemoField(t *testing.T) { t.Run(tt.name, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, true /*=postCortina*/, true /*=postDurango*/) + env := newEnvironment(t, durango) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/vm_regression_test.go b/vms/platformvm/vm_regression_test.go index bdcb169562f..e612340546f 100644 --- a/vms/platformvm/vm_regression_test.go +++ b/vms/platformvm/vm_regression_test.go @@ -51,7 +51,7 @@ import ( func TestAddDelegatorTxOverDelegatedRegression(t *testing.T) { require := require.New(t) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -495,7 +495,7 @@ func TestUnverifiedParentPanicRegression(t *testing.T) { func TestRejectedStateRegressionInvalidValidatorTimestamp(t *testing.T) { require := require.New(t) - vm, baseDB, mutableSharedMemory := defaultVM(t, cortinaFork) + vm, baseDB, mutableSharedMemory := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -701,7 +701,7 @@ func TestRejectedStateRegressionInvalidValidatorTimestamp(t *testing.T) { func TestRejectedStateRegressionInvalidValidatorReward(t *testing.T) { require := require.New(t) - vm, baseDB, mutableSharedMemory := defaultVM(t, cortinaFork) + vm, baseDB, mutableSharedMemory := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -1015,7 +1015,7 @@ func TestRejectedStateRegressionInvalidValidatorReward(t *testing.T) { func TestValidatorSetAtCacheOverwriteRegression(t *testing.T) { require := require.New(t) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -1152,7 +1152,7 @@ func TestAddDelegatorTxAddBeforeRemove(t *testing.T) { delegator2EndTime := delegator2StartTime.Add(3 * defaultMinStakingDuration) delegator2Stake := defaultMaxValidatorStake - validatorStake - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -1241,7 +1241,7 @@ func TestRemovePermissionedValidatorDuringPendingToCurrentTransitionNotTracked(t validatorStartTime := latestForkTime.Add(executor.SyncBound).Add(1 * time.Second) validatorEndTime := validatorStartTime.Add(360 * 24 * time.Hour) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -1366,7 +1366,7 @@ func TestRemovePermissionedValidatorDuringPendingToCurrentTransitionTracked(t *t validatorStartTime := latestForkTime.Add(executor.SyncBound).Add(1 * time.Second) validatorEndTime := validatorStartTime.Add(360 * 24 * time.Hour) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -1474,7 +1474,7 @@ func TestRemovePermissionedValidatorDuringPendingToCurrentTransitionTracked(t *t func TestSubnetValidatorBLSKeyDiffAfterExpiry(t *testing.T) { // setup require := require.New(t) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -1699,7 +1699,7 @@ func TestPrimaryNetworkValidatorPopulatedToEmptyBLSKeyDiff(t *testing.T) { // setup require := require.New(t) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -1828,7 +1828,7 @@ func TestSubnetValidatorPopulatedToEmptyBLSKeyDiff(t *testing.T) { // setup require := require.New(t) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -2012,7 +2012,7 @@ func TestSubnetValidatorSetAfterPrimaryNetworkValidatorRemoval(t *testing.T) { // setup require := require.New(t) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -2132,7 +2132,7 @@ func TestSubnetValidatorSetAfterPrimaryNetworkValidatorRemoval(t *testing.T) { func TestValidatorSetRaceCondition(t *testing.T) { require := require.New(t) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 2b2bde0c154..1b16e72bf3c 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -71,16 +71,14 @@ import ( txexecutor "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" ) -type activeFork uint8 - const ( - apricotPhase3 activeFork = iota + apricotPhase3 fork = iota apricotPhase5 - banffFork - cortinaFork - durangoFork + banff + cortina + durango - latestFork activeFork = durangoFork + latestFork = durango defaultWeight uint64 = 10000 ) @@ -137,6 +135,8 @@ func init() { } } +type fork uint8 + type mutableSharedMemory struct { atomic.SharedMemory } @@ -201,7 +201,7 @@ func defaultGenesis(t *testing.T, avaxAssetID ids.ID) (*api.BuildGenesisArgs, [] return &buildGenesisArgs, genesisBytes } -func defaultVM(t *testing.T, fork activeFork) (*VM, database.Database, *mutableSharedMemory) { +func defaultVM(t *testing.T, f fork) (*VM, database.Database, *mutableSharedMemory) { require := require.New(t) var ( apricotPhase3Time = mockable.MaxTime @@ -214,14 +214,14 @@ func defaultVM(t *testing.T, fork activeFork) (*VM, database.Database, *mutableS // always reset latestForkTime (a package level variable) // to ensure test independence latestForkTime = defaultGenesisTime.Add(time.Second) - switch fork { - case durangoFork: + switch f { + case durango: durangoTime = latestForkTime fallthrough - case cortinaFork: + case cortina: cortinaTime = latestForkTime fallthrough - case banffFork: + case banff: banffTime = latestForkTime fallthrough case apricotPhase5: @@ -230,7 +230,7 @@ func defaultVM(t *testing.T, fork activeFork) (*VM, database.Database, *mutableS case apricotPhase3: apricotPhase3Time = latestForkTime default: - require.NoError(fmt.Errorf("unhandled fork %d", fork)) + require.NoError(fmt.Errorf("unhandled fork %d", f)) } vm := &VM{Config: config.Config{ @@ -436,7 +436,7 @@ func TestAddValidatorCommit(t *testing.T) { // verify invalid attempt to add validator to primary network func TestInvalidAddValidatorCommit(t *testing.T) { require := require.New(t) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -487,7 +487,7 @@ func TestInvalidAddValidatorCommit(t *testing.T) { // Reject attempt to add validator to primary network func TestAddValidatorReject(t *testing.T) { require := require.New(t) - vm, _, _ := defaultVM(t, cortinaFork) + vm, _, _ := defaultVM(t, cortina) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() diff --git a/wallet/chain/p/builder_test.go b/wallet/chain/p/builder_test.go index 9e880f27f6d..47310314754 100644 --- a/wallet/chain/p/builder_test.go +++ b/wallet/chain/p/builder_test.go @@ -4,7 +4,6 @@ package p import ( - "slices" "testing" "time" @@ -23,8 +22,6 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" - - stdcontext "context" ) var ( @@ -59,7 +56,7 @@ func TestBaseTx(t *testing.T) { // backend utxosKey = testKeys[1] utxos = makeTestUTXOs(utxosKey) - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, }) backend = NewBackend(testCtx, chainUTXOs, nil) @@ -103,7 +100,7 @@ func TestAddSubnetValidatorTx(t *testing.T) { // backend utxosKey = testKeys[1] utxos = makeTestUTXOs(utxosKey) - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, }) @@ -160,7 +157,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { // backend utxosKey = testKeys[1] utxos = makeTestUTXOs(utxosKey) - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, }) @@ -211,7 +208,7 @@ func TestCreateChainTx(t *testing.T) { // backend utxosKey = testKeys[1] utxos = makeTestUTXOs(utxosKey) - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, }) @@ -270,7 +267,7 @@ func TestCreateSubnetTx(t *testing.T) { // backend utxosKey = testKeys[1] utxos = makeTestUTXOs(utxosKey) - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, }) @@ -318,7 +315,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { // backend utxosKey = testKeys[1] utxos = makeTestUTXOs(utxosKey) - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, }) @@ -371,7 +368,7 @@ func TestImportTx(t *testing.T) { utxos = makeTestUTXOs(utxosKey) sourceChainID = ids.GenerateTestID() importedUTXOs = utxos[:1] - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, sourceChainID: importedUTXOs, }) @@ -419,7 +416,7 @@ func TestExportTx(t *testing.T) { // backend utxosKey = testKeys[1] utxos = makeTestUTXOs(utxosKey) - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, }) backend = NewBackend(testCtx, chainUTXOs, nil) @@ -468,7 +465,7 @@ func TestTransformSubnetTx(t *testing.T) { // backend utxosKey = testKeys[1] utxos = makeTestUTXOs(utxosKey) - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, }) @@ -538,7 +535,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { // backend utxosKey = testKeys[1] utxos = makeTestUTXOs(utxosKey) - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, }) backend = NewBackend(testCtx, chainUTXOs, nil) @@ -608,7 +605,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { // backend utxosKey = testKeys[1] utxos = makeTestUTXOs(utxosKey) - chainUTXOs = newChainUTXOs(require, map[ids.ID][]*avax.UTXO{ + chainUTXOs = common.NewDeterministicChainUTXOs(require, map[ids.ID][]*avax.UTXO{ constants.PlatformChainID: utxos, }) backend = NewBackend(testCtx, chainUTXOs, nil) @@ -747,33 +744,3 @@ func makeTestUTXOs(utxosKey *secp256k1.PrivateKey) []*avax.UTXO { }, } } - -func newChainUTXOs(require *require.Assertions, utxoSets map[ids.ID][]*avax.UTXO) common.ChainUTXOs { - globalUTXOs := common.NewUTXOs() - for subnetID, utxos := range utxoSets { - for _, utxo := range utxos { - require.NoError( - globalUTXOs.AddUTXO(stdcontext.Background(), subnetID, constants.PlatformChainID, utxo), - ) - } - } - return &deterministicChainUTXOs{ - ChainUTXOs: common.NewChainUTXOs(constants.PlatformChainID, globalUTXOs), - } -} - -type deterministicChainUTXOs struct { - common.ChainUTXOs -} - -func (c *deterministicChainUTXOs) UTXOs(ctx stdcontext.Context, sourceChainID ids.ID) ([]*avax.UTXO, error) { - utxos, err := c.ChainUTXOs.UTXOs(ctx, sourceChainID) - if err != nil { - return nil, err - } - - slices.SortFunc(utxos, func(a, b *avax.UTXO) int { - return a.Compare(&b.UTXOID) - }) - return utxos, nil -} diff --git a/wallet/chain/x/builder_test.go b/wallet/chain/x/builder_test.go new file mode 100644 index 00000000000..f4eb916b693 --- /dev/null +++ b/wallet/chain/x/builder_test.go @@ -0,0 +1,550 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package x + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/verify" + "github.com/ava-labs/avalanchego/vms/nftfx" + "github.com/ava-labs/avalanchego/vms/propertyfx" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" +) + +var ( + testKeys = secp256k1.TestKeys() + + // We hard-code [avaxAssetID] and [subnetAssetID] to make + // ordering of UTXOs generated by [testUTXOsList] is reproducible + avaxAssetID = ids.Empty.Prefix(1789) + xChainID = ids.Empty.Prefix(2021) + nftAssetID = ids.Empty.Prefix(2022) + propertyAssetID = ids.Empty.Prefix(2023) + + testCtx = NewContext( + constants.UnitTestID, + xChainID, + avaxAssetID, + units.MicroAvax, // BaseTxFee + 99*units.MilliAvax, // CreateAssetTxFee + ) +) + +// These tests create and sign a tx, then verify that utxos included +// in the tx are exactly necessary to pay fees for it + +func TestBaseTx(t *testing.T) { + var ( + require = require.New(t) + + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + genericBackend = common.NewDeterministicChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + }, + ) + backend = NewBackend(testCtx, genericBackend) + + // builder + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + + // data to build the transaction + outputsToMove = []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 7 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxoAddr}, + }, + }, + }} + ) + + utx, err := builder.NewBaseTx( + outputsToMove, + ) + require.NoError(err) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 2) + + expectedConsumed := testCtx.BaseTxFee() + consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() - outs[1].Out.Amount() + require.Equal(expectedConsumed, consumed) + require.Equal(outputsToMove[0], outs[1]) +} + +func TestCreateAssetTx(t *testing.T) { + require := require.New(t) + + var ( + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + genericBackend = common.NewDeterministicChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + }, + ) + backend = NewBackend(testCtx, genericBackend) + + // builder + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + + // data to build the transaction + assetName = "Team Rocket" + symbol = "TR" + denomination uint8 = 0 + initialState = map[uint32][]verify.State{ + 0: { + &secp256k1fx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[0].PublicKey().Address()}, + }, + }, &secp256k1fx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[0].PublicKey().Address()}, + }, + }, + }, + 1: { + &nftfx.MintOutput{ + GroupID: 1, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[1].PublicKey().Address()}, + }, + }, + &nftfx.MintOutput{ + GroupID: 2, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[1].PublicKey().Address()}, + }, + }, + }, + 2: { + &propertyfx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[2].PublicKey().Address()}, + }, + }, + &propertyfx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[2].PublicKey().Address()}, + }, + }, + }, + } + ) + + utx, err := builder.NewCreateAssetTx( + assetName, + symbol, + denomination, + initialState, + ) + require.NoError(err) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 1) + + expectedConsumed := testCtx.CreateAssetTxFee() + consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) +} + +func TestMintNFTOperation(t *testing.T) { + require := require.New(t) + + var ( + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + genericBackend = common.NewDeterministicChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + }, + ) + backend = NewBackend(testCtx, genericBackend) + + // builder + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + + // data to build the transaction + payload = []byte{'h', 'e', 'l', 'l', 'o'} + NFTOwner = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxoAddr}, + } + ) + + utx, err := builder.NewOperationTxMintNFT( + nftAssetID, + payload, + []*secp256k1fx.OutputOwners{NFTOwner}, + ) + require.NoError(err) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 1) + require.Len(outs, 1) + + expectedConsumed := testCtx.BaseTxFee() + consumed := ins[0].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) +} + +func TestMintFTOperation(t *testing.T) { + require := require.New(t) + + var ( + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + genericBackend = common.NewDeterministicChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + }, + ) + backend = NewBackend(testCtx, genericBackend) + + // builder + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + + // data to build the transaction + outputs = map[ids.ID]*secp256k1fx.TransferOutput{ + nftAssetID: { + Amt: 1, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxoAddr}, + }, + }, + } + ) + + utx, err := builder.NewOperationTxMintFT( + outputs, + ) + require.NoError(err) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 1) + require.Len(outs, 1) + + expectedConsumed := testCtx.BaseTxFee() + consumed := ins[0].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) +} + +func TestMintPropertyOperation(t *testing.T) { + require := require.New(t) + + var ( + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + genericBackend = common.NewDeterministicChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + }, + ) + backend = NewBackend(testCtx, genericBackend) + + // builder + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + + // data to build the transaction + propertyOwner = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxoAddr}, + } + ) + + utx, err := builder.NewOperationTxMintProperty( + propertyAssetID, + propertyOwner, + ) + require.NoError(err) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 1) + require.Len(outs, 1) + + expectedConsumed := testCtx.BaseTxFee() + consumed := ins[0].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) +} + +func TestBurnPropertyOperation(t *testing.T) { + require := require.New(t) + + var ( + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + genericBackend = common.NewDeterministicChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + }, + ) + backend = NewBackend(testCtx, genericBackend) + + // builder + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + ) + + utx, err := builder.NewOperationTxBurnProperty( + propertyAssetID, + ) + require.NoError(err) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 1) + require.Len(outs, 1) + + expectedConsumed := testCtx.BaseTxFee() + consumed := ins[0].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) +} + +func TestImportTx(t *testing.T) { + var ( + require = require.New(t) + + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + sourceChainID = ids.GenerateTestID() + importedUTXOs = utxos[:1] + genericBackend = common.NewDeterministicChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + sourceChainID: importedUTXOs, + }, + ) + + backend = NewBackend(testCtx, genericBackend) + + // builder + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + + // data to build the transaction + importKey = testKeys[0] + importTo = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + importKey.Address(), + }, + } + ) + + utx, err := builder.NewImportTx( + sourceChainID, + importTo, + ) + require.NoError(err) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + importedIns := utx.ImportedIns + require.Empty(ins) + require.Len(importedIns, 1) + require.Len(outs, 1) + + expectedConsumed := testCtx.BaseTxFee() + consumed := importedIns[0].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) +} + +func TestExportTx(t *testing.T) { + var ( + require = require.New(t) + + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + genericBackend = common.NewDeterministicChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + }, + ) + backend = NewBackend(testCtx, genericBackend) + + // builder + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + + // data to build the transaction + subnetID = ids.GenerateTestID() + exportedOutputs = []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 7 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxoAddr}, + }, + }, + }} + ) + + utx, err := builder.NewExportTx( + subnetID, + exportedOutputs, + ) + require.NoError(err) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 1) + + expectedConsumed := testCtx.BaseTxFee() + exportedOutputs[0].Out.Amount() + consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) + require.Equal(utx.ExportedOuts, exportedOutputs) +} + +func makeTestUTXOs(utxosKey *secp256k1.PrivateKey) []*avax.UTXO { + // Note: we avoid ids.GenerateTestNodeID here to make sure that UTXO IDs won't change + // run by run. This simplifies checking what utxos are included in the built txs. + const utxosOffset uint64 = 2024 + + return []*avax.UTXO{ // currently, the wallet scans UTXOs in the order provided here + { // a small UTXO first, which should not be enough to pay fees + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset), + OutputIndex: uint32(utxosOffset), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 2 * units.MilliAvax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + { + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 2), + OutputIndex: uint32(utxosOffset + 2), + }, + Asset: avax.Asset{ID: nftAssetID}, + Out: &nftfx.MintOutput{ + GroupID: 1, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }, + { + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 3), + OutputIndex: uint32(utxosOffset + 3), + }, + Asset: avax.Asset{ID: nftAssetID}, + Out: &secp256k1fx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }, + { + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 4), + OutputIndex: uint32(utxosOffset + 4), + }, + Asset: avax.Asset{ID: propertyAssetID}, + Out: &propertyfx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + { + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 5), + OutputIndex: uint32(utxosOffset + 5), + }, + Asset: avax.Asset{ID: propertyAssetID}, + Out: &propertyfx.OwnedOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + { // a large UTXO last, which should be enough to pay any fee by itself + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 6), + OutputIndex: uint32(utxosOffset + 6), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 9 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + } +} diff --git a/wallet/subnet/primary/common/test_utxos.go b/wallet/subnet/primary/common/test_utxos.go new file mode 100644 index 00000000000..094c57d5370 --- /dev/null +++ b/wallet/subnet/primary/common/test_utxos.go @@ -0,0 +1,45 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package common + +import ( + "context" + "slices" + + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/vms/components/avax" +) + +func NewDeterministicChainUTXOs(require *require.Assertions, utxoSets map[ids.ID][]*avax.UTXO) *DeterministicChainUTXOs { + globalUTXOs := NewUTXOs() + for subnetID, utxos := range utxoSets { + for _, utxo := range utxos { + require.NoError( + globalUTXOs.AddUTXO(context.Background(), subnetID, constants.PlatformChainID, utxo), + ) + } + } + return &DeterministicChainUTXOs{ + ChainUTXOs: NewChainUTXOs(constants.PlatformChainID, globalUTXOs), + } +} + +type DeterministicChainUTXOs struct { + ChainUTXOs +} + +func (c *DeterministicChainUTXOs) UTXOs(ctx context.Context, sourceChainID ids.ID) ([]*avax.UTXO, error) { + utxos, err := c.ChainUTXOs.UTXOs(ctx, sourceChainID) + if err != nil { + return nil, err + } + + slices.SortFunc(utxos, func(a, b *avax.UTXO) int { + return a.Compare(&b.UTXOID) + }) + return utxos, nil +}