diff --git a/.gitignore b/.gitignore index c6a92936..edda115f 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,4 @@ go.work.sum .env /data /tests/system/data -tests/system/supernode-data1 -tests/system/supernode-data2 -tests/system/supernode-data3 \ No newline at end of file +tests/system/**/supernode-data* diff --git a/Makefile b/Makefile index cd508a86..fbebcefe 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,6 @@ system-test-setup: install-lumera setup-supernodes @if [ -f claims.csv ]; then cp claims.csv ~/; echo "Copied claims.csv to home directory."; fi # Run system tests with complete setup -test-system-full: +test-e2e: @echo "Running system tests..." @cd tests/system && go test -tags=system_test -v . \ No newline at end of file diff --git a/gen/supernode/tests/integration/securegrpc/grpc_test_service.pb.go b/gen/supernode/tests/integration/securegrpc/grpc_test_service.pb.go index d48fd6df..e6d0e91c 100644 --- a/gen/supernode/tests/integration/securegrpc/grpc_test_service.pb.go +++ b/gen/supernode/tests/integration/securegrpc/grpc_test_service.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v3.21.4 +// protoc-gen-go v1.35.2 +// protoc v3.21.12 // source: grpc_test_service.proto package securegrpc diff --git a/gen/supernode/tests/integration/securegrpc/grpc_test_service_grpc.pb.go b/gen/supernode/tests/integration/securegrpc/grpc_test_service_grpc.pb.go index 23387ed4..3fda4df5 100644 --- a/gen/supernode/tests/integration/securegrpc/grpc_test_service_grpc.pb.go +++ b/gen/supernode/tests/integration/securegrpc/grpc_test_service_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v3.21.4 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.21.12 // source: grpc_test_service.proto package securegrpc @@ -15,8 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( TestService_TestMethod_FullMethodName = "/securegrpc.TestService/TestMethod" @@ -38,8 +38,9 @@ func NewTestServiceClient(cc grpc.ClientConnInterface) TestServiceClient { } func (c *testServiceClient) TestMethod(ctx context.Context, in *TestRequest, opts ...grpc.CallOption) (*TestResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(TestResponse) - err := c.cc.Invoke(ctx, TestService_TestMethod_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, TestService_TestMethod_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -48,20 +49,24 @@ func (c *testServiceClient) TestMethod(ctx context.Context, in *TestRequest, opt // TestServiceServer is the server API for TestService service. // All implementations must embed UnimplementedTestServiceServer -// for forward compatibility +// for forward compatibility. type TestServiceServer interface { TestMethod(context.Context, *TestRequest) (*TestResponse, error) mustEmbedUnimplementedTestServiceServer() } -// UnimplementedTestServiceServer must be embedded to have forward compatible implementations. -type UnimplementedTestServiceServer struct { -} +// UnimplementedTestServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedTestServiceServer struct{} func (UnimplementedTestServiceServer) TestMethod(context.Context, *TestRequest) (*TestResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method TestMethod not implemented") } func (UnimplementedTestServiceServer) mustEmbedUnimplementedTestServiceServer() {} +func (UnimplementedTestServiceServer) testEmbeddedByValue() {} // UnsafeTestServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to TestServiceServer will @@ -71,6 +76,13 @@ type UnsafeTestServiceServer interface { } func RegisterTestServiceServer(s grpc.ServiceRegistrar, srv TestServiceServer) { + // If the following call pancis, it indicates UnimplementedTestServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&TestService_ServiceDesc, srv) } diff --git a/go.mod b/go.mod index a34b74ee..c0c82a4a 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 github.com/x-cray/logrus-prefixed-formatter v0.5.2 + go.uber.org/mock v0.5.2 go.uber.org/ratelimit v0.3.1 golang.org/x/crypto v0.36.0 golang.org/x/sync v0.12.0 diff --git a/go.sum b/go.sum index 2ec021fc..7254e1e0 100644 --- a/go.sum +++ b/go.sum @@ -825,6 +825,8 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= diff --git a/pkg/codec/codec_mock.go b/pkg/codec/codec_mock.go new file mode 100644 index 00000000..cb7ed36a --- /dev/null +++ b/pkg/codec/codec_mock.go @@ -0,0 +1,56 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: codec.go +// +// Generated by this command: +// +// mockgen -destination=codec_mock.go -package=codec -source=codec.go +// + +// Package codec is a generated GoMock package. +package codec + +import ( + context "context" + reflect "reflect" + + gomock "go.uber.org/mock/gomock" +) + +// MockCodec is a mock of Codec interface. +type MockCodec struct { + ctrl *gomock.Controller + recorder *MockCodecMockRecorder + isgomock struct{} +} + +// MockCodecMockRecorder is the mock recorder for MockCodec. +type MockCodecMockRecorder struct { + mock *MockCodec +} + +// NewMockCodec creates a new mock instance. +func NewMockCodec(ctrl *gomock.Controller) *MockCodec { + mock := &MockCodec{ctrl: ctrl} + mock.recorder = &MockCodecMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockCodec) EXPECT() *MockCodecMockRecorder { + return m.recorder +} + +// Encode mocks base method. +func (m *MockCodec) Encode(ctx context.Context, req EncodeRequest) (EncodeResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Encode", ctx, req) + ret0, _ := ret[0].(EncodeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Encode indicates an expected call of Encode. +func (mr *MockCodecMockRecorder) Encode(ctx, req any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Encode", reflect.TypeOf((*MockCodec)(nil).Encode), ctx, req) +} diff --git a/pkg/dd/dd_mock.go b/pkg/dd/dd_mock.go index 454443a0..224831c6 100644 --- a/pkg/dd/dd_mock.go +++ b/pkg/dd/dd_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: interfaces.go +// +// Generated by this command: +// +// mockgen -destination=dd_mock.go -package=dd -source=interfaces.go +// // Package dd is a generated GoMock package. package dd @@ -8,13 +13,14 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockClientInterface is a mock of ClientInterface interface. type MockClientInterface struct { ctrl *gomock.Controller recorder *MockClientInterfaceMockRecorder + isgomock struct{} } // MockClientInterfaceMockRecorder is the mock recorder for MockClientInterface. @@ -44,7 +50,7 @@ func (m *MockClientInterface) Connect(ctx context.Context, address string) (Conn } // Connect indicates an expected call of Connect. -func (mr *MockClientInterfaceMockRecorder) Connect(ctx, address interface{}) *gomock.Call { +func (mr *MockClientInterfaceMockRecorder) Connect(ctx, address any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connect", reflect.TypeOf((*MockClientInterface)(nil).Connect), ctx, address) } @@ -53,6 +59,7 @@ func (mr *MockClientInterfaceMockRecorder) Connect(ctx, address interface{}) *go type MockConnection struct { ctrl *gomock.Controller recorder *MockConnectionMockRecorder + isgomock struct{} } // MockConnectionMockRecorder is the mock recorder for MockConnection. @@ -95,7 +102,7 @@ func (m *MockConnection) DDService(config *Config) DDService { } // DDService indicates an expected call of DDService. -func (mr *MockConnectionMockRecorder) DDService(config interface{}) *gomock.Call { +func (mr *MockConnectionMockRecorder) DDService(config any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DDService", reflect.TypeOf((*MockConnection)(nil).DDService), config) } @@ -104,6 +111,7 @@ func (mr *MockConnectionMockRecorder) DDService(config interface{}) *gomock.Call type MockDDService struct { ctrl *gomock.Controller recorder *MockDDServiceMockRecorder + isgomock struct{} } // MockDDServiceMockRecorder is the mock recorder for MockDDService. @@ -133,7 +141,7 @@ func (m *MockDDService) GetStatus(ctx context.Context, req GetStatusRequest) (Ge } // GetStatus indicates an expected call of GetStatus. -func (mr *MockDDServiceMockRecorder) GetStatus(ctx, req interface{}) *gomock.Call { +func (mr *MockDDServiceMockRecorder) GetStatus(ctx, req any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStatus", reflect.TypeOf((*MockDDService)(nil).GetStatus), ctx, req) } @@ -148,7 +156,7 @@ func (m *MockDDService) ImageRarenessScore(ctx context.Context, req RarenessScor } // ImageRarenessScore indicates an expected call of ImageRarenessScore. -func (mr *MockDDServiceMockRecorder) ImageRarenessScore(ctx, req interface{}) *gomock.Call { +func (mr *MockDDServiceMockRecorder) ImageRarenessScore(ctx, req any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ImageRarenessScore", reflect.TypeOf((*MockDDService)(nil).ImageRarenessScore), ctx, req) } diff --git a/pkg/lumera/client.go b/pkg/lumera/client.go index f07d5f08..7f684ffe 100644 --- a/pkg/lumera/client.go +++ b/pkg/lumera/client.go @@ -11,7 +11,6 @@ import ( "github.com/LumeraProtocol/supernode/pkg/lumera/modules/tx" ) -// lumeraClient implements the Client interface type lumeraClient struct { cfg *Config authMod auth.Module @@ -23,34 +22,26 @@ type lumeraClient struct { conn Connection } -// newClient creates a new Lumera client with provided options func newClient(ctx context.Context, cfg *Config) (Client, error) { - // Create a single gRPC connection to be shared by all modules conn, err := newGRPCConnection(ctx, cfg.GRPCAddr) if err != nil { return nil, err } - // Initialize all module clients with the shared connection - authModule, err := auth.NewModule(conn.GetConn()) + txModule, err := tx.NewModule(conn.GetConn()) if err != nil { conn.Close() return nil, err } - actionModule, err := action.NewModule(conn.GetConn()) + authModule, err := auth.NewModule(conn.GetConn()) if err != nil { conn.Close() return nil, err } - actionMsgModule, err := action_msg.NewModule( - conn.GetConn(), - cfg.keyring, - cfg.KeyName, - cfg.ChainID, - ) + actionModule, err := action.NewModule(conn.GetConn()) if err != nil { conn.Close() return nil, err @@ -62,13 +53,20 @@ func newClient(ctx context.Context, cfg *Config) (Client, error) { return nil, err } - txModule, err := tx.NewModule(conn.GetConn()) + nodeModule, err := node.NewModule(conn.GetConn(), cfg.keyring) if err != nil { conn.Close() return nil, err } - nodeModule, err := node.NewModule(conn.GetConn(), cfg.keyring) + actionMsgModule, err := action_msg.NewModule( + conn.GetConn(), + authModule, // For account info + txModule, // For transaction operations + cfg.keyring, // For signing + cfg.KeyName, // Key to use + cfg.ChainID, // Chain configuration + ) if err != nil { conn.Close() return nil, err @@ -86,37 +84,30 @@ func newClient(ctx context.Context, cfg *Config) (Client, error) { }, nil } -// Auth returns the Auth module client func (c *lumeraClient) Auth() auth.Module { return c.authMod } -// Action returns the Action module client func (c *lumeraClient) Action() action.Module { return c.actionMod } -// ActionMsg returns the ActionMsg module client func (c *lumeraClient) ActionMsg() action_msg.Module { return c.actionMsgMod } -// SuperNode returns the SuperNode module client func (c *lumeraClient) SuperNode() supernode.Module { return c.supernodeMod } -// Tx returns the Transaction module client func (c *lumeraClient) Tx() tx.Module { return c.txMod } -// Node returns the Node module client func (c *lumeraClient) Node() node.Module { return c.nodeMod } -// Close closes all connections func (c *lumeraClient) Close() error { if c.conn != nil { return c.conn.Close() diff --git a/pkg/lumera/codec/encoding.go b/pkg/lumera/codec/encoding.go new file mode 100644 index 00000000..04a66710 --- /dev/null +++ b/pkg/lumera/codec/encoding.go @@ -0,0 +1,51 @@ +package codec + +import ( + actiontypes "github.com/LumeraProtocol/lumera/x/action/v1/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// EncodingConfig specifies the concrete encoding types to use for Lumera client +type EncodingConfig struct { + InterfaceRegistry codectypes.InterfaceRegistry + Codec codec.Codec + TxConfig client.TxConfig + Amino *codec.LegacyAmino +} + +// NewEncodingConfig creates a new EncodingConfig with all required interfaces registered +func NewEncodingConfig() EncodingConfig { + amino := codec.NewLegacyAmino() + interfaceRegistry := codectypes.NewInterfaceRegistry() + + // Register all required interfaces + RegisterInterfaces(interfaceRegistry) + + marshaler := codec.NewProtoCodec(interfaceRegistry) + txConfig := authtx.NewTxConfig(marshaler, authtx.DefaultSignModes) + + return EncodingConfig{ + InterfaceRegistry: interfaceRegistry, + Codec: marshaler, + TxConfig: txConfig, + Amino: amino, + } +} + +// RegisterInterfaces registers all interface types with the interface registry +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + cryptocodec.RegisterInterfaces(registry) + authtypes.RegisterInterfaces(registry) + actiontypes.RegisterInterfaces(registry) + // Add more interface registrations here as you add more modules +} + +// GetEncodingConfig returns the standard encoding config for Lumera client +func GetEncodingConfig() EncodingConfig { + return NewEncodingConfig() +} diff --git a/pkg/lumera/lumera_mock.go b/pkg/lumera/lumera_mock.go index 3bdeba5e..93cf0724 100644 --- a/pkg/lumera/lumera_mock.go +++ b/pkg/lumera/lumera_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: interface.go +// +// Generated by this command: +// +// mockgen -destination=lumera_mock.go -package=lumera -source=interface.go +// // Package lumera is a generated GoMock package. package lumera @@ -13,13 +18,14 @@ import ( node "github.com/LumeraProtocol/supernode/pkg/lumera/modules/node" supernode "github.com/LumeraProtocol/supernode/pkg/lumera/modules/supernode" tx "github.com/LumeraProtocol/supernode/pkg/lumera/modules/tx" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockClient is a mock of Client interface. type MockClient struct { ctrl *gomock.Controller recorder *MockClientMockRecorder + isgomock struct{} } // MockClientMockRecorder is the mock recorder for MockClient. diff --git a/pkg/lumera/modules/action/action_mock.go b/pkg/lumera/modules/action/action_mock.go index 12ccdf7a..a4524fa3 100644 --- a/pkg/lumera/modules/action/action_mock.go +++ b/pkg/lumera/modules/action/action_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: interface.go +// +// Generated by this command: +// +// mockgen -destination=action_mock.go -package=action -source=interface.go +// // Package action is a generated GoMock package. package action @@ -9,13 +14,14 @@ import ( reflect "reflect" types "github.com/LumeraProtocol/lumera/x/action/v1/types" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockModule is a mock of Module interface. type MockModule struct { ctrl *gomock.Controller recorder *MockModuleMockRecorder + isgomock struct{} } // MockModuleMockRecorder is the mock recorder for MockModule. @@ -45,7 +51,7 @@ func (m *MockModule) GetAction(ctx context.Context, actionID string) (*types.Que } // GetAction indicates an expected call of GetAction. -func (mr *MockModuleMockRecorder) GetAction(ctx, actionID interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetAction(ctx, actionID any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAction", reflect.TypeOf((*MockModule)(nil).GetAction), ctx, actionID) } @@ -60,7 +66,7 @@ func (m *MockModule) GetActionFee(ctx context.Context, dataSize string) (*types. } // GetActionFee indicates an expected call of GetActionFee. -func (mr *MockModuleMockRecorder) GetActionFee(ctx, dataSize interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetActionFee(ctx, dataSize any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActionFee", reflect.TypeOf((*MockModule)(nil).GetActionFee), ctx, dataSize) } @@ -75,7 +81,7 @@ func (m *MockModule) GetParams(ctx context.Context) (*types.QueryParamsResponse, } // GetParams indicates an expected call of GetParams. -func (mr *MockModuleMockRecorder) GetParams(ctx interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetParams(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParams", reflect.TypeOf((*MockModule)(nil).GetParams), ctx) } diff --git a/pkg/lumera/modules/action_msg/action_msg_mock.go b/pkg/lumera/modules/action_msg/action_msg_mock.go index 481aedb6..0ac0368f 100644 --- a/pkg/lumera/modules/action_msg/action_msg_mock.go +++ b/pkg/lumera/modules/action_msg/action_msg_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: interface.go +// +// Generated by this command: +// +// mockgen -destination=action_msg_mock.go -package=action_msg -source=interface.go +// // Package action_msg is a generated GoMock package. package action_msg @@ -8,13 +13,15 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" + tx "github.com/cosmos/cosmos-sdk/types/tx" + gomock "go.uber.org/mock/gomock" ) // MockModule is a mock of Module interface. type MockModule struct { ctrl *gomock.Controller recorder *MockModuleMockRecorder + isgomock struct{} } // MockModuleMockRecorder is the mock recorder for MockModule. @@ -35,16 +42,16 @@ func (m *MockModule) EXPECT() *MockModuleMockRecorder { } // FinalizeCascadeAction mocks base method. -func (m *MockModule) FinalizeCascadeAction(ctx context.Context, actionId string, rqIdsIds []string) (*FinalizeActionResult, error) { +func (m *MockModule) FinalizeCascadeAction(ctx context.Context, actionId string, rqIdsIds []string) (*tx.BroadcastTxResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "FinalizeCascadeAction", ctx, actionId, rqIdsIds) - ret0, _ := ret[0].(*FinalizeActionResult) + ret0, _ := ret[0].(*tx.BroadcastTxResponse) ret1, _ := ret[1].(error) return ret0, ret1 } // FinalizeCascadeAction indicates an expected call of FinalizeCascadeAction. -func (mr *MockModuleMockRecorder) FinalizeCascadeAction(ctx, actionId, rqIdsIds interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) FinalizeCascadeAction(ctx, actionId, rqIdsIds any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FinalizeCascadeAction", reflect.TypeOf((*MockModule)(nil).FinalizeCascadeAction), ctx, actionId, rqIdsIds) } diff --git a/pkg/lumera/modules/action_msg/helpers.go b/pkg/lumera/modules/action_msg/helpers.go new file mode 100644 index 00000000..ce958ce5 --- /dev/null +++ b/pkg/lumera/modules/action_msg/helpers.go @@ -0,0 +1,63 @@ +package action_msg + +import ( + "fmt" + + actionapi "github.com/LumeraProtocol/lumera/api/lumera/action" + actiontypes "github.com/LumeraProtocol/lumera/x/action/v1/types" + "google.golang.org/protobuf/encoding/protojson" +) + +func validateRequestActionParams(actionType, metadata, price, expirationTime string) error { + if actionType == "" { + return fmt.Errorf("action type cannot be empty") + } + if metadata == "" { + return fmt.Errorf("metadata cannot be empty") + } + if price == "" { + return fmt.Errorf("price cannot be empty") + } + if expirationTime == "" { + return fmt.Errorf("expiration time cannot be empty") + } + return nil +} + +func validateFinalizeActionParams(actionId string, rqIdsIds []string) error { + if actionId == "" { + return fmt.Errorf("action ID cannot be empty") + } + if len(rqIdsIds) == 0 { + return fmt.Errorf("rq_ids_ids cannot be empty for cascade action") + } + return nil +} + +func createRequestActionMessage(creator, actionType, metadata, price, expirationTime string) *actiontypes.MsgRequestAction { + return &actiontypes.MsgRequestAction{ + Creator: creator, + ActionType: actionType, + Metadata: metadata, + Price: price, + ExpirationTime: expirationTime, + } +} + +func createFinalizeActionMessage(creator, actionId string, rqIdsIds []string) (*actiontypes.MsgFinalizeAction, error) { + cascadeMeta := actionapi.CascadeMetadata{ + RqIdsIds: rqIdsIds, + } + + metadataBytes, err := protojson.Marshal(&cascadeMeta) + if err != nil { + return nil, fmt.Errorf("failed to marshal cascade metadata: %w", err) + } + + return &actiontypes.MsgFinalizeAction{ + Creator: creator, + ActionId: actionId, + ActionType: "CASCADE", + Metadata: string(metadataBytes), + }, nil +} diff --git a/pkg/lumera/modules/action_msg/impl.go b/pkg/lumera/modules/action_msg/impl.go index af970529..44a07b83 100644 --- a/pkg/lumera/modules/action_msg/impl.go +++ b/pkg/lumera/modules/action_msg/impl.go @@ -3,408 +3,71 @@ package action_msg import ( "context" "fmt" - "strconv" - actionapi "github.com/LumeraProtocol/lumera/api/lumera/action" actiontypes "github.com/LumeraProtocol/lumera/x/action/v1/types" - "github.com/LumeraProtocol/supernode/pkg/logtrace" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/LumeraProtocol/supernode/pkg/lumera/modules/auth" + txmod "github.com/LumeraProtocol/supernode/pkg/lumera/modules/tx" "github.com/cosmos/cosmos-sdk/crypto/keyring" - txtypes "github.com/cosmos/cosmos-sdk/types/tx" - signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" - authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/types" + sdktx "github.com/cosmos/cosmos-sdk/types/tx" "google.golang.org/grpc" - "google.golang.org/protobuf/encoding/protojson" ) -// Default parameters -const ( - defaultGasLimit = uint64(200000) - defaultGasAdjustment = float64(1.5) - defaultGasPadding = uint64(50000) - defaultFeeDenom = "ulume" - defaultGasPrice = "0.000001" // Price per unit of gas -) - -// module implements the Module interface type module struct { - conn *grpc.ClientConn - client actiontypes.MsgClient - kr keyring.Keyring - keyName string - chainID string - gasLimit uint64 - gasAdjustment float64 - gasPadding uint64 - feeDenom string - gasPrice string + client actiontypes.MsgClient + txHelper *txmod.TxHelper } -// newModule creates a new ActionMsg module client -func newModule(conn *grpc.ClientConn, kr keyring.Keyring, keyName string, chainID string) (Module, error) { +func newModule(conn *grpc.ClientConn, authmodule auth.Module, txmodule txmod.Module, kr keyring.Keyring, keyName string, chainID string) (Module, error) { if conn == nil { return nil, fmt.Errorf("connection cannot be nil") } - + if authmodule == nil { + return nil, fmt.Errorf("auth module cannot be nil") + } + if txmodule == nil { + return nil, fmt.Errorf("tx module cannot be nil") + } if kr == nil { return nil, fmt.Errorf("keyring cannot be nil") } - if keyName == "" { return nil, fmt.Errorf("key name cannot be empty") } - if chainID == "" { return nil, fmt.Errorf("chain ID cannot be empty") } return &module{ - conn: conn, - client: actiontypes.NewMsgClient(conn), - kr: kr, - keyName: keyName, - chainID: chainID, - gasLimit: defaultGasLimit, - gasAdjustment: defaultGasAdjustment, - gasPadding: defaultGasPadding, - feeDenom: defaultFeeDenom, - gasPrice: defaultGasPrice, + client: actiontypes.NewMsgClient(conn), + txHelper: txmod.NewTxHelperWithDefaults(authmodule, txmodule, chainID, keyName, kr), }, nil } -// calculateFee calculates the transaction fee based on gas usage -func (m *module) calculateFee(gasAmount uint64) string { - gasPrice, _ := strconv.ParseFloat(m.gasPrice, 64) - feeAmount := gasPrice * float64(gasAmount) - - // Ensure we have at least 1 token as fee to meet minimum requirements - if feeAmount < 1 { - feeAmount = 1 - } - - return fmt.Sprintf("%.0f%s", feeAmount, m.feeDenom) -} - -// FinalizeCascadeAction finalizes a CASCADE action with the given parameters -func (m *module) FinalizeCascadeAction( - ctx context.Context, - actionId string, - rqIdsIds []string, -) (*FinalizeActionResult, error) { - // Basic validation - if actionId == "" { - return nil, fmt.Errorf("action ID cannot be empty") - } - if len(rqIdsIds) == 0 { - return nil, fmt.Errorf("rq_ids_ids cannot be empty for cascade action") - } - - // Get creator address from keyring - key, err := m.kr.Key(m.keyName) - if err != nil { - return nil, fmt.Errorf("failed to get key from keyring: %w", err) - } - - addr, err := key.GetAddress() - if err != nil { - return nil, fmt.Errorf("failed to get address from key: %w", err) - } - creator := addr.String() - - logtrace.Info(ctx, "finalize action started", logtrace.Fields{"creator": creator}) - - // Create CASCADE metadata - cascadeMeta := actionapi.CascadeMetadata{ - RqIdsIds: rqIdsIds, - } - - // Convert metadata to JSON instead of binary protobuf - metadataBytes, err := protojson.Marshal(&cascadeMeta) - if err != nil { - return nil, fmt.Errorf("failed to marshal metadata to JSON: %w", err) - } - - // Create the message - msg := &actiontypes.MsgFinalizeAction{ - Creator: creator, - ActionId: actionId, - ActionType: "CASCADE", - Metadata: string(metadataBytes), +func (m *module) RequesAction(ctx context.Context, actionType, metadata, price, expirationTime string) (*sdktx.BroadcastTxResponse, error) { + if err := validateRequestActionParams(actionType, metadata, price, expirationTime); err != nil { + return nil, err } - // Create encoding config - encCfg := makeEncodingConfig() - - // Get account info for signing - accInfo, err := m.getAccountInfo(ctx, creator) - if err != nil { - return nil, fmt.Errorf("failed to get account info: %w", err) - } - - logtrace.Info(ctx, "account info retrieved", logtrace.Fields{"accountNumber": accInfo.AccountNumber}) - - // Create client context with keyring - clientCtx := client.Context{}. - WithCodec(encCfg.Codec). - WithTxConfig(encCfg.TxConfig). - WithKeyring(m.kr). - WithBroadcastMode("sync") - - // Use a minimal fee for simulation - minFee := fmt.Sprintf("1%s", m.feeDenom) - - // Simulate transaction to get gas estimate - txBuilder, err := tx.Factory{}. - WithTxConfig(clientCtx.TxConfig). - WithKeybase(m.kr). - WithAccountNumber(accInfo.AccountNumber). - WithSequence(accInfo.Sequence). - WithChainID(m.chainID). - WithGas(m.gasLimit). - WithGasAdjustment(m.gasAdjustment). - WithSignMode(signingtypes.SignMode_SIGN_MODE_DIRECT). - WithFees(minFee). - BuildUnsignedTx(msg) - if err != nil { - return nil, fmt.Errorf("failed to build unsigned tx for simulation: %w", err) - } - - pubKey, err := key.GetPubKey() - if err != nil { - return nil, fmt.Errorf("failed to get public key: %w", err) - } - - txBuilder.SetSignatures(signingtypes.SignatureV2{ - PubKey: pubKey, - Data: &signingtypes.SingleSignatureData{SignMode: signingtypes.SignMode_SIGN_MODE_DIRECT, Signature: nil}, - Sequence: accInfo.Sequence, - }) - - simulatedGas, err := m.simulateTx(ctx, clientCtx, txBuilder) - if err != nil { - return nil, fmt.Errorf("simulation failed: %w", err) - } - - // Calculate gas with adjustment and padding - adjustedGas := uint64(float64(simulatedGas) * m.gasAdjustment) - gasToUse := adjustedGas + m.gasPadding - - // Calculate fee based on adjusted gas - fee := m.calculateFee(gasToUse) - logtrace.Info(ctx, "using simulated gas and calculated fee", logtrace.Fields{ - "simulatedGas": simulatedGas, - "adjustedGas": gasToUse, - "fee": fee, + return m.txHelper.ExecuteTransaction(ctx, func(creator string) (types.Msg, error) { + return createRequestActionMessage(creator, actionType, metadata, price, expirationTime), nil }) - - // Create transaction factory with final gas and calculated fee - factory := tx.Factory{}. - WithTxConfig(clientCtx.TxConfig). - WithKeybase(m.kr). - WithAccountNumber(accInfo.AccountNumber). - WithSequence(accInfo.Sequence). - WithChainID(m.chainID). - WithGas(gasToUse). - WithGasAdjustment(m.gasAdjustment). - WithSignMode(signingtypes.SignMode_SIGN_MODE_DIRECT). - WithFees(fee) - - // Build and sign transaction - txBuilder, err = factory.BuildUnsignedTx(msg) - if err != nil { - return nil, fmt.Errorf("failed to build unsigned tx: %w", err) - } - - err = tx.Sign(ctx, factory, m.keyName, txBuilder, true) - if err != nil { - return nil, fmt.Errorf("failed to sign transaction: %w", err) - } - - logtrace.Info(ctx, "transaction signed successfully", nil) - - // Broadcast transaction - txBytes, err := clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) - if err != nil { - return nil, fmt.Errorf("failed to encode transaction: %w", err) - } - - resp, err := m.broadcastTx(ctx, txBytes) - if err != nil { - return &FinalizeActionResult{ - Success: false, - TxHash: "", - }, fmt.Errorf("failed to broadcast transaction: %w", err) - } - - logtrace.Info(ctx, "transaction broadcast success", logtrace.Fields{"txHash": resp.TxHash}) - - return &FinalizeActionResult{ - TxHash: resp.TxHash, - Code: resp.Code, - Success: true, - }, nil } -// Helper function to simulate transaction and return gas used -func (m *module) simulateTx(ctx context.Context, clientCtx client.Context, txBuilder client.TxBuilder) (uint64, error) { - // First, let's see what's in the txBuilder - tx := txBuilder.GetTx() - logtrace.Info(ctx, "transaction for simulation", logtrace.Fields{ - "messages": fmt.Sprintf("%v", tx.GetMsgs()), - "fee": fmt.Sprintf("%v", tx.GetFee()), - "gas": tx.GetGas(), - }) - - txBytes, err := clientCtx.TxConfig.TxEncoder()(tx) - if err != nil { - return 0, fmt.Errorf("failed to encode transaction for simulation: %w", err) - } - - logtrace.Info(ctx, "transaction encoded for simulation", logtrace.Fields{ - "bytesLength": len(txBytes), - }) - - // Create gRPC client for tx service - txClient := txtypes.NewServiceClient(m.conn) - - // Simulate transaction - simReq := &txtypes.SimulateRequest{ - TxBytes: txBytes, - } - - logtrace.Info(ctx, "sending simulation request", logtrace.Fields{ - "requestBytes": len(simReq.TxBytes), - "requestType": fmt.Sprintf("%T", simReq), - }) - - simRes, err := txClient.Simulate(ctx, simReq) - if err != nil { - logtrace.Error(ctx, "simulation error details", logtrace.Fields{ - "error": err.Error(), - "errorType": fmt.Sprintf("%T", err), - "requestBytes": len(simReq.TxBytes), - }) - return 0, fmt.Errorf("simulation error: %w", err) +func (m *module) FinalizeCascadeAction(ctx context.Context, actionId string, rqIdsIds []string) (*sdktx.BroadcastTxResponse, error) { + if err := validateFinalizeActionParams(actionId, rqIdsIds); err != nil { + return nil, err } - logtrace.Info(ctx, "simulation response", logtrace.Fields{ - "gasUsed": simRes.GasInfo.GasUsed, - "gasWanted": simRes.GasInfo.GasWanted, + return m.txHelper.ExecuteTransaction(ctx, func(creator string) (types.Msg, error) { + return createFinalizeActionMessage(creator, actionId, rqIdsIds) }) - - return simRes.GasInfo.GasUsed, nil -} - -// Helper function to broadcast transaction -func (m *module) broadcastTx(ctx context.Context, txBytes []byte) (*TxResponse, error) { - // Create gRPC client for tx service - txClient := txtypes.NewServiceClient(m.conn) - - // Broadcast transaction - req := &txtypes.BroadcastTxRequest{ - TxBytes: txBytes, - Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC, - } - - resp, err := txClient.BroadcastTx(ctx, req) - if err != nil { - return nil, fmt.Errorf("broadcast failed: %w", err) - } - - if resp.TxResponse.Code != 0 { - return nil, fmt.Errorf("transaction failed (code %d): %s", - resp.TxResponse.Code, resp.TxResponse.RawLog) - } - - return &TxResponse{ - TxHash: resp.TxResponse.TxHash, - Code: resp.TxResponse.Code, - RawLog: resp.TxResponse.RawLog, - }, nil -} - -// Helper function to get account info -func (m *module) getAccountInfo(ctx context.Context, address string) (*AccountInfo, error) { - // Create gRPC client for auth service - authClient := authtypes.NewQueryClient(m.conn) - - // Query account info - req := &authtypes.QueryAccountRequest{ - Address: address, - } - - resp, err := authClient.Account(ctx, req) - if err != nil { - return nil, fmt.Errorf("failed to get account info: %w", err) - } - - // Unmarshal account - var account authtypes.AccountI - err = m.getEncodingConfig().InterfaceRegistry.UnpackAny(resp.Account, &account) - if err != nil { - return nil, fmt.Errorf("failed to unpack account: %w", err) - } - - // Convert to BaseAccount - baseAcc, ok := account.(*authtypes.BaseAccount) - if !ok { - return nil, fmt.Errorf("received account is not a BaseAccount") - } - - return &AccountInfo{ - AccountNumber: baseAcc.AccountNumber, - Sequence: baseAcc.Sequence, - }, nil -} - -// makeEncodingConfig creates an EncodingConfig for transaction handling -func makeEncodingConfig() EncodingConfig { - amino := codec.NewLegacyAmino() - - interfaceRegistry := codectypes.NewInterfaceRegistry() - cryptocodec.RegisterInterfaces(interfaceRegistry) - authtypes.RegisterInterfaces(interfaceRegistry) - actiontypes.RegisterInterfaces(interfaceRegistry) - - marshaler := codec.NewProtoCodec(interfaceRegistry) - txConfig := authtx.NewTxConfig(marshaler, authtx.DefaultSignModes) - - return EncodingConfig{ - InterfaceRegistry: interfaceRegistry, - Codec: marshaler, - TxConfig: txConfig, - Amino: amino, - } -} - -// getEncodingConfig returns the module's encoding config -func (m *module) getEncodingConfig() EncodingConfig { - return makeEncodingConfig() -} - -// EncodingConfig specifies the concrete encoding types to use -type EncodingConfig struct { - InterfaceRegistry types.InterfaceRegistry - Codec codec.Codec - TxConfig client.TxConfig - Amino *codec.LegacyAmino } -// AccountInfo holds account information for transaction signing -type AccountInfo struct { - AccountNumber uint64 - Sequence uint64 +func (m *module) SetTxHelperConfig(config *txmod.TxHelperConfig) { + m.txHelper.UpdateConfig(config) } -// TxResponse holds transaction response information -type TxResponse struct { - TxHash string - Code uint32 - RawLog string +func (m *module) GetTxHelper() *txmod.TxHelper { + return m.txHelper } diff --git a/pkg/lumera/modules/action_msg/interface.go b/pkg/lumera/modules/action_msg/interface.go index 6fec08aa..8dae1a45 100644 --- a/pkg/lumera/modules/action_msg/interface.go +++ b/pkg/lumera/modules/action_msg/interface.go @@ -4,24 +4,19 @@ package action_msg import ( "context" + "github.com/LumeraProtocol/supernode/pkg/lumera/modules/auth" + "github.com/LumeraProtocol/supernode/pkg/lumera/modules/tx" "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdktx "github.com/cosmos/cosmos-sdk/types/tx" "google.golang.org/grpc" ) -// FinalizeActionResult represents the result of a finalized action -type FinalizeActionResult struct { - TxHash string // Transaction hash - Code uint32 // Code of the transaction - Success bool // Whether the transaction was successful -} - -// Module defines the interface for action messages operations type Module interface { // FinalizeCascadeAction finalizes a CASCADE action with the given parameters - FinalizeCascadeAction(ctx context.Context, actionId string, rqIdsIds []string) (*FinalizeActionResult, error) + RequesAction(ctx context.Context, actionType, metadata, price, expirationTime string) (*sdktx.BroadcastTxResponse, error) + FinalizeCascadeAction(ctx context.Context, actionId string, rqIdsIds []string) (*sdktx.BroadcastTxResponse, error) } -// NewModule creates a new ActionMsg module client -func NewModule(conn *grpc.ClientConn, kr keyring.Keyring, keyName string, chainID string) (Module, error) { - return newModule(conn, kr, keyName, chainID) +func NewModule(conn *grpc.ClientConn, authmod auth.Module, txmodule tx.Module, kr keyring.Keyring, keyName string, chainID string) (Module, error) { + return newModule(conn, authmod, txmodule, kr, keyName, chainID) } diff --git a/pkg/lumera/modules/auth/auth_mock.go b/pkg/lumera/modules/auth/auth_mock.go index 92269fdf..0873da7b 100644 --- a/pkg/lumera/modules/auth/auth_mock.go +++ b/pkg/lumera/modules/auth/auth_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: interface.go +// +// Generated by this command: +// +// mockgen -destination=auth_mock.go -package=auth -source=interface.go +// // Package auth is a generated GoMock package. package auth @@ -9,13 +14,14 @@ import ( reflect "reflect" types "github.com/cosmos/cosmos-sdk/x/auth/types" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockModule is a mock of Module interface. type MockModule struct { ctrl *gomock.Controller recorder *MockModuleMockRecorder + isgomock struct{} } // MockModuleMockRecorder is the mock recorder for MockModule. @@ -45,7 +51,7 @@ func (m *MockModule) AccountInfoByAddress(ctx context.Context, addr string) (*ty } // AccountInfoByAddress indicates an expected call of AccountInfoByAddress. -func (mr *MockModuleMockRecorder) AccountInfoByAddress(ctx, addr interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) AccountInfoByAddress(ctx, addr any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccountInfoByAddress", reflect.TypeOf((*MockModule)(nil).AccountInfoByAddress), ctx, addr) } @@ -59,7 +65,7 @@ func (m *MockModule) Verify(ctx context.Context, accAddress string, data, signat } // Verify indicates an expected call of Verify. -func (mr *MockModuleMockRecorder) Verify(ctx, accAddress, data, signature interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) Verify(ctx, accAddress, data, signature any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Verify", reflect.TypeOf((*MockModule)(nil).Verify), ctx, accAddress, data, signature) } diff --git a/pkg/lumera/modules/auth/impl.go b/pkg/lumera/modules/auth/impl.go index caa40fcf..3eb2e18b 100644 --- a/pkg/lumera/modules/auth/impl.go +++ b/pkg/lumera/modules/auth/impl.go @@ -5,9 +5,7 @@ import ( "fmt" "github.com/LumeraProtocol/supernode/pkg/logtrace" - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + lumeracodec "github.com/LumeraProtocol/supernode/pkg/lumera/codec" "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "google.golang.org/grpc" @@ -60,7 +58,7 @@ func (m *module) Verify(ctx context.Context, accAddress string, data, signature // Unpack the account from Any type var account types.AccountI - if err := m.getEncodingConfig().InterfaceRegistry.UnpackAny(accResp.Account, &account); err != nil { + if err := lumeracodec.GetEncodingConfig().InterfaceRegistry.UnpackAny(accResp.Account, &account); err != nil { return fmt.Errorf("failed to unpack account: %w", err) } @@ -75,27 +73,3 @@ func (m *module) Verify(ctx context.Context, accAddress string, data, signature return nil } - -// getEncodingConfig returns the module's encoding config -func (m *module) getEncodingConfig() EncodingConfig { - amino := codec.NewLegacyAmino() - - interfaceRegistry := codectypes.NewInterfaceRegistry() - cryptocodec.RegisterInterfaces(interfaceRegistry) - authtypes.RegisterInterfaces(interfaceRegistry) - - marshaler := codec.NewProtoCodec(interfaceRegistry) - - return EncodingConfig{ - InterfaceRegistry: interfaceRegistry, - Codec: marshaler, - Amino: amino, - } -} - -// EncodingConfig specifies the concrete encoding types to use -type EncodingConfig struct { - InterfaceRegistry codectypes.InterfaceRegistry - Codec codec.Codec - Amino *codec.LegacyAmino -} diff --git a/pkg/lumera/modules/node/node_mock.go b/pkg/lumera/modules/node/node_mock.go index e95d7b38..b5cfc728 100644 --- a/pkg/lumera/modules/node/node_mock.go +++ b/pkg/lumera/modules/node/node_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: interface.go +// +// Generated by this command: +// +// mockgen -destination=node_mock.go -package=node -source=interface.go +// // Package node is a generated GoMock package. package node @@ -9,13 +14,14 @@ import ( reflect "reflect" cmtservice "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockModule is a mock of Module interface. type MockModule struct { ctrl *gomock.Controller recorder *MockModuleMockRecorder + isgomock struct{} } // MockModuleMockRecorder is the mock recorder for MockModule. @@ -45,7 +51,7 @@ func (m *MockModule) GetBlockByHeight(ctx context.Context, height int64) (*cmtse } // GetBlockByHeight indicates an expected call of GetBlockByHeight. -func (mr *MockModuleMockRecorder) GetBlockByHeight(ctx, height interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetBlockByHeight(ctx, height any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockByHeight", reflect.TypeOf((*MockModule)(nil).GetBlockByHeight), ctx, height) } @@ -60,7 +66,7 @@ func (m *MockModule) GetLatestBlock(ctx context.Context) (*cmtservice.GetLatestB } // GetLatestBlock indicates an expected call of GetLatestBlock. -func (mr *MockModuleMockRecorder) GetLatestBlock(ctx interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetLatestBlock(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestBlock", reflect.TypeOf((*MockModule)(nil).GetLatestBlock), ctx) } @@ -75,7 +81,7 @@ func (m *MockModule) GetLatestValidatorSet(ctx context.Context) (*cmtservice.Get } // GetLatestValidatorSet indicates an expected call of GetLatestValidatorSet. -func (mr *MockModuleMockRecorder) GetLatestValidatorSet(ctx interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetLatestValidatorSet(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestValidatorSet", reflect.TypeOf((*MockModule)(nil).GetLatestValidatorSet), ctx) } @@ -90,7 +96,7 @@ func (m *MockModule) GetNodeInfo(ctx context.Context) (*cmtservice.GetNodeInfoRe } // GetNodeInfo indicates an expected call of GetNodeInfo. -func (mr *MockModuleMockRecorder) GetNodeInfo(ctx interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetNodeInfo(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNodeInfo", reflect.TypeOf((*MockModule)(nil).GetNodeInfo), ctx) } @@ -105,7 +111,7 @@ func (m *MockModule) GetSyncing(ctx context.Context) (*cmtservice.GetSyncingResp } // GetSyncing indicates an expected call of GetSyncing. -func (mr *MockModuleMockRecorder) GetSyncing(ctx interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetSyncing(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSyncing", reflect.TypeOf((*MockModule)(nil).GetSyncing), ctx) } @@ -120,7 +126,7 @@ func (m *MockModule) GetValidatorSetByHeight(ctx context.Context, height int64) } // GetValidatorSetByHeight indicates an expected call of GetValidatorSetByHeight. -func (mr *MockModuleMockRecorder) GetValidatorSetByHeight(ctx, height interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetValidatorSetByHeight(ctx, height any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidatorSetByHeight", reflect.TypeOf((*MockModule)(nil).GetValidatorSetByHeight), ctx, height) } @@ -135,7 +141,7 @@ func (m *MockModule) Sign(snAccAddress string, data []byte) ([]byte, error) { } // Sign indicates an expected call of Sign. -func (mr *MockModuleMockRecorder) Sign(snAccAddress, data interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) Sign(snAccAddress, data any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sign", reflect.TypeOf((*MockModule)(nil).Sign), snAccAddress, data) } diff --git a/pkg/lumera/modules/supernode/supernode_mock.go b/pkg/lumera/modules/supernode/supernode_mock.go index 819eaa25..6f443e06 100644 --- a/pkg/lumera/modules/supernode/supernode_mock.go +++ b/pkg/lumera/modules/supernode/supernode_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: interface.go +// +// Generated by this command: +// +// mockgen -destination=supernode_mock.go -package=supernode -source=interface.go +// // Package supernode is a generated GoMock package. package supernode @@ -9,13 +14,14 @@ import ( reflect "reflect" types "github.com/LumeraProtocol/lumera/x/supernode/v1/types" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockModule is a mock of Module interface. type MockModule struct { ctrl *gomock.Controller recorder *MockModuleMockRecorder + isgomock struct{} } // MockModuleMockRecorder is the mock recorder for MockModule. @@ -45,7 +51,7 @@ func (m *MockModule) GetParams(ctx context.Context) (*types.QueryParamsResponse, } // GetParams indicates an expected call of GetParams. -func (mr *MockModuleMockRecorder) GetParams(ctx interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetParams(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParams", reflect.TypeOf((*MockModule)(nil).GetParams), ctx) } @@ -60,7 +66,7 @@ func (m *MockModule) GetSuperNode(ctx context.Context, address string) (*types.Q } // GetSuperNode indicates an expected call of GetSuperNode. -func (mr *MockModuleMockRecorder) GetSuperNode(ctx, address interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetSuperNode(ctx, address any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSuperNode", reflect.TypeOf((*MockModule)(nil).GetSuperNode), ctx, address) } @@ -75,7 +81,7 @@ func (m *MockModule) GetSupernodeBySupernodeAddress(ctx context.Context, address } // GetSupernodeBySupernodeAddress indicates an expected call of GetSupernodeBySupernodeAddress. -func (mr *MockModuleMockRecorder) GetSupernodeBySupernodeAddress(ctx, address interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetSupernodeBySupernodeAddress(ctx, address any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSupernodeBySupernodeAddress", reflect.TypeOf((*MockModule)(nil).GetSupernodeBySupernodeAddress), ctx, address) } @@ -90,7 +96,7 @@ func (m *MockModule) GetTopSuperNodesForBlock(ctx context.Context, blockHeight u } // GetTopSuperNodesForBlock indicates an expected call of GetTopSuperNodesForBlock. -func (mr *MockModuleMockRecorder) GetTopSuperNodesForBlock(ctx, blockHeight interface{}) *gomock.Call { +func (mr *MockModuleMockRecorder) GetTopSuperNodesForBlock(ctx, blockHeight any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTopSuperNodesForBlock", reflect.TypeOf((*MockModule)(nil).GetTopSuperNodesForBlock), ctx, blockHeight) } diff --git a/pkg/lumera/modules/tx/helper.go b/pkg/lumera/modules/tx/helper.go new file mode 100644 index 00000000..8249ffbd --- /dev/null +++ b/pkg/lumera/modules/tx/helper.go @@ -0,0 +1,153 @@ +package tx + +import ( + "context" + "fmt" + + "github.com/LumeraProtocol/supernode/pkg/lumera/modules/auth" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/types" + sdktx "github.com/cosmos/cosmos-sdk/types/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// TxHelper provides a simplified interface for modules to handle transactions +// This helper encapsulates common transaction patterns and reduces boilerplate +type TxHelper struct { + authmod auth.Module + txmod Module + config *TxConfig +} + +// TxHelperConfig holds configuration for creating a TxHelper +type TxHelperConfig struct { + ChainID string + Keyring keyring.Keyring + KeyName string + GasLimit uint64 + GasAdjustment float64 + GasPadding uint64 + FeeDenom string + GasPrice string +} + +// NewTxHelper creates a new transaction helper with the given configuration +func NewTxHelper(authmod auth.Module, txmod Module, config *TxHelperConfig) *TxHelper { + txConfig := &TxConfig{ + ChainID: config.ChainID, + Keyring: config.Keyring, + KeyName: config.KeyName, + GasLimit: config.GasLimit, + GasAdjustment: config.GasAdjustment, + GasPadding: config.GasPadding, + FeeDenom: config.FeeDenom, + GasPrice: config.GasPrice, + } + + return &TxHelper{ + authmod: authmod, + txmod: txmod, + config: txConfig, + } +} + +// NewTxHelperWithDefaults creates a new transaction helper with default configuration +func NewTxHelperWithDefaults(authmod auth.Module, txmod Module, chainID, keyName string, kr keyring.Keyring) *TxHelper { + config := &TxHelperConfig{ + ChainID: chainID, + Keyring: kr, + KeyName: keyName, + GasLimit: DefaultGasLimit, + GasAdjustment: DefaultGasAdjustment, + GasPadding: DefaultGasPadding, + FeeDenom: DefaultFeeDenom, + GasPrice: DefaultGasPrice, + } + + return NewTxHelper(authmod, txmod, config) +} + +// ExecuteTransaction is a convenience method that handles the complete transaction flow +// for a single message. It gets account info, creates the message, and processes the transaction. +func (h *TxHelper) ExecuteTransaction(ctx context.Context, msgCreator func(creator string) (types.Msg, error)) (*sdktx.BroadcastTxResponse, error) { + // Step 1: Get creator address from keyring + key, err := h.config.Keyring.Key(h.config.KeyName) + if err != nil { + return nil, fmt.Errorf("failed to get key from keyring: %w", err) + } + + addr, err := key.GetAddress() + if err != nil { + return nil, fmt.Errorf("failed to get address from key: %w", err) + } + creator := addr.String() + + // Step 2: Get account info + accInfoRes, err := h.authmod.AccountInfoByAddress(ctx, creator) + if err != nil { + return nil, fmt.Errorf("failed to get account info: %w", err) + } + + // Step 3: Create the message using the provided creator function + msg, err := msgCreator(creator) + if err != nil { + return nil, fmt.Errorf("failed to create message: %w", err) + } + + // Step 4: Process transaction + return h.ExecuteTransactionWithMsgs(ctx, []types.Msg{msg}, accInfoRes.Info) +} + +// ExecuteTransactionWithMsgs processes a transaction with pre-created messages and account info +func (h *TxHelper) ExecuteTransactionWithMsgs(ctx context.Context, msgs []types.Msg, accountInfo *authtypes.BaseAccount) (*sdktx.BroadcastTxResponse, error) { + return h.txmod.ProcessTransaction(ctx, msgs, accountInfo, h.config) +} + +// GetCreatorAddress returns the creator address for the configured key +func (h *TxHelper) GetCreatorAddress() (string, error) { + key, err := h.config.Keyring.Key(h.config.KeyName) + if err != nil { + return "", fmt.Errorf("failed to get key from keyring: %w", err) + } + + addr, err := key.GetAddress() + if err != nil { + return "", fmt.Errorf("failed to get address from key: %w", err) + } + + return addr.String(), nil +} + +// GetAccountInfo gets account information for the configured key +func (h *TxHelper) GetAccountInfo(ctx context.Context) (*authtypes.BaseAccount, error) { + creator, err := h.GetCreatorAddress() + if err != nil { + return nil, err + } + + accInfoRes, err := h.authmod.AccountInfoByAddress(ctx, creator) + if err != nil { + return nil, fmt.Errorf("failed to get account info: %w", err) + } + + return accInfoRes.Info, nil +} + +// UpdateConfig allows updating the transaction configuration +func (h *TxHelper) UpdateConfig(config *TxHelperConfig) { + h.config = &TxConfig{ + ChainID: config.ChainID, + Keyring: config.Keyring, + KeyName: config.KeyName, + GasLimit: config.GasLimit, + GasAdjustment: config.GasAdjustment, + GasPadding: config.GasPadding, + FeeDenom: config.FeeDenom, + GasPrice: config.GasPrice, + } +} + +// GetConfig returns the current transaction configuration +func (h *TxHelper) GetConfig() *TxConfig { + return h.config +} diff --git a/pkg/lumera/modules/tx/impl.go b/pkg/lumera/modules/tx/impl.go index caca4889..c96c27dc 100644 --- a/pkg/lumera/modules/tx/impl.go +++ b/pkg/lumera/modules/tx/impl.go @@ -3,11 +3,29 @@ package tx import ( "context" "fmt" + "strconv" + "github.com/LumeraProtocol/supernode/pkg/logtrace" + lumeracodec "github.com/LumeraProtocol/supernode/pkg/lumera/codec" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/types" sdktx "github.com/cosmos/cosmos-sdk/types/tx" + signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "google.golang.org/grpc" ) +// Default parameters +const ( + DefaultGasLimit = uint64(200000) + DefaultGasAdjustment = float64(1.5) + DefaultGasPadding = uint64(50000) + DefaultFeeDenom = "ulume" + DefaultGasPrice = "0.000001" // Price per unit of gas +) + // module implements the Module interface type module struct { client sdktx.ServiceClient @@ -24,45 +42,201 @@ func newModule(conn *grpc.ClientConn) (Module, error) { }, nil } -// BroadcastTx broadcasts a signed transaction -func (m *module) BroadcastTx(ctx context.Context, txBytes []byte, mode sdktx.BroadcastMode) (*sdktx.BroadcastTxResponse, error) { +// SimulateTransaction simulates a transaction with given messages and returns gas used +func (m *module) SimulateTransaction(ctx context.Context, msgs []types.Msg, accountInfo *authtypes.BaseAccount, config *TxConfig) (*sdktx.SimulateResponse, error) { + // Create encoding config + encCfg := lumeracodec.GetEncodingConfig() + + // Create client context + clientCtx := client.Context{}. + WithCodec(encCfg.Codec). + WithTxConfig(encCfg.TxConfig). + WithKeyring(config.Keyring). + WithBroadcastMode("sync") + + // Get the key for public key + key, err := config.Keyring.Key(config.KeyName) + if err != nil { + return nil, fmt.Errorf("failed to get key from keyring: %w", err) + } + + pubKey, err := key.GetPubKey() + if err != nil { + return nil, fmt.Errorf("failed to get public key: %w", err) + } + + // Use a minimal fee for simulation, just to avoid errors related to fees + minFee := fmt.Sprintf("1%s", config.FeeDenom) + + // Build unsigned transaction for simulation + txBuilder, err := tx.Factory{}. + WithTxConfig(clientCtx.TxConfig). + WithKeybase(config.Keyring). + WithAccountNumber(accountInfo.AccountNumber). + WithSequence(accountInfo.Sequence). + WithChainID(config.ChainID). + WithGas(config.GasLimit). + WithGasAdjustment(config.GasAdjustment). + WithSignMode(signingtypes.SignMode_SIGN_MODE_DIRECT). + WithFees(minFee). + BuildUnsignedTx(msgs...) + if err != nil { + return nil, fmt.Errorf("failed to build unsigned tx for simulation: %w", err) + } + + // Set empty signature for simulation + txBuilder.SetSignatures(signingtypes.SignatureV2{ + PubKey: pubKey, + Data: &signingtypes.SingleSignatureData{SignMode: signingtypes.SignMode_SIGN_MODE_DIRECT, Signature: nil}, + Sequence: accountInfo.Sequence, + }) + + // Encode transaction for simulation + txBytes, err := clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) + if err != nil { + return nil, fmt.Errorf("failed to encode transaction for simulation: %w", err) + } + + logtrace.Info(ctx, "transaction encoded for simulation", logtrace.Fields{ + "bytesLength": len(txBytes), + }) + + // Simulate transaction + simReq := &sdktx.SimulateRequest{ + TxBytes: txBytes, + } + + simRes, err := m.client.Simulate(ctx, simReq) + if err != nil { + logtrace.Error(ctx, "simulation error details", logtrace.Fields{ + "error": err.Error(), + "errorType": fmt.Sprintf("%T", err), + "requestBytes": len(simReq.TxBytes), + }) + return nil, fmt.Errorf("simulation error: %w", err) + } + + logtrace.Info(ctx, "simulation response", logtrace.Fields{ + "gasUsed": simRes.GasInfo.GasUsed, + "gasWanted": simRes.GasInfo.GasWanted, + }) + + return simRes, nil +} + +// BuildAndSignTransaction builds and signs a transaction with the given parameters +func (m *module) BuildAndSignTransaction(ctx context.Context, msgs []types.Msg, accountInfo *authtypes.BaseAccount, gasLimit uint64, fee string, config *TxConfig) ([]byte, error) { + // Create encoding config + encCfg := lumeracodec.GetEncodingConfig() + + // Create client context + clientCtx := client.Context{}. + WithCodec(encCfg.Codec). + WithTxConfig(encCfg.TxConfig). + WithKeyring(config.Keyring). + WithBroadcastMode("sync") + + // Create transaction factory + factory := tx.Factory{}. + WithTxConfig(clientCtx.TxConfig). + WithKeybase(config.Keyring). + WithAccountNumber(accountInfo.AccountNumber). + WithSequence(accountInfo.Sequence). + WithChainID(config.ChainID). + WithGas(gasLimit). + WithGasAdjustment(config.GasAdjustment). + WithSignMode(signingtypes.SignMode_SIGN_MODE_DIRECT). + WithFees(fee) + + // Build unsigned transaction + txBuilder, err := factory.BuildUnsignedTx(msgs...) + if err != nil { + return nil, fmt.Errorf("failed to build unsigned tx: %w", err) + } + + // Sign transaction + err = tx.Sign(ctx, factory, config.KeyName, txBuilder, true) + if err != nil { + return nil, fmt.Errorf("failed to sign transaction: %w", err) + } + + logtrace.Info(ctx, "transaction signed successfully", nil) + + // Encode signed transaction + txBytes, err := clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) + if err != nil { + return nil, fmt.Errorf("failed to encode transaction: %w", err) + } + + return txBytes, nil +} + +// BroadcastTransaction broadcasts a signed transaction and returns the result +func (m *module) BroadcastTransaction(ctx context.Context, txBytes []byte) (*sdktx.BroadcastTxResponse, error) { + // Broadcast transaction req := &sdktx.BroadcastTxRequest{ TxBytes: txBytes, - Mode: mode, + Mode: sdktx.BroadcastMode_BROADCAST_MODE_SYNC, } resp, err := m.client.BroadcastTx(ctx, req) + if err != nil { + logtrace.Error(ctx, "broadcast transaction error", logtrace.Fields{ + "error": err.Error(), + }) return nil, fmt.Errorf("failed to broadcast transaction: %w", err) } return resp, nil } -// SimulateTx simulates a transaction -func (m *module) SimulateTx(ctx context.Context, txBytes []byte) (*sdktx.SimulateResponse, error) { - req := &sdktx.SimulateRequest{ - TxBytes: txBytes, +// CalculateFee calculates the transaction fee based on gas usage and config +func (m *module) CalculateFee(gasAmount uint64, config *TxConfig) string { + gasPrice, _ := strconv.ParseFloat(config.GasPrice, 64) + feeAmount := gasPrice * float64(gasAmount) + + // Ensure we have at least 1 token as fee to meet minimum requirements + if feeAmount < 1 { + feeAmount = 1 } - resp, err := m.client.Simulate(ctx, req) + return fmt.Sprintf("%.0f%s", feeAmount, config.FeeDenom) +} + +// ProcessTransaction handles the complete flow: simulate, build, sign, and broadcast +func (m *module) ProcessTransaction(ctx context.Context, msgs []types.Msg, accountInfo *authtypes.BaseAccount, config *TxConfig) (*sdktx.BroadcastTxResponse, error) { + // Step 1: Simulate transaction to get gas estimate + simulatedGas, err := m.SimulateTransaction(ctx, msgs, accountInfo, config) if err != nil { - return nil, fmt.Errorf("failed to simulate transaction: %w", err) + return nil, fmt.Errorf("simulation failed: %w", err) } - return resp, nil -} + // Step 2: Calculate gas with adjustment and padding + simulatedGasUsed := simulatedGas.GasInfo.GasUsed + adjustedGas := uint64(float64(simulatedGasUsed) * config.GasAdjustment) + gasToUse := adjustedGas + config.GasPadding + + // Step 3: Calculate fee based on adjusted gas + fee := m.CalculateFee(gasToUse, config) -// GetTx gets transaction by hash -func (m *module) GetTx(ctx context.Context, hash string) (*sdktx.GetTxResponse, error) { - req := &sdktx.GetTxRequest{ - Hash: hash, + logtrace.Info(ctx, "using simulated gas and calculated fee", logtrace.Fields{ + "simulatedGas": simulatedGasUsed, + "adjustedGas": gasToUse, + "fee": fee, + }) + + // Step 4: Build and sign transaction + txBytes, err := m.BuildAndSignTransaction(ctx, msgs, accountInfo, gasToUse, fee, config) + if err != nil { + return nil, fmt.Errorf("failed to build and sign transaction: %w", err) } - resp, err := m.client.GetTx(ctx, req) + // Step 5: Broadcast transaction + result, err := m.BroadcastTransaction(ctx, txBytes) if err != nil { - return nil, fmt.Errorf("failed to get transaction: %w", err) + return result, fmt.Errorf("failed to broadcast transaction: %w", err) } - return resp, nil + return result, nil } diff --git a/pkg/lumera/modules/tx/interface.go b/pkg/lumera/modules/tx/interface.go index 26df9ba8..23d184ea 100644 --- a/pkg/lumera/modules/tx/interface.go +++ b/pkg/lumera/modules/tx/interface.go @@ -4,20 +4,42 @@ package tx import ( "context" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/types" sdktx "github.com/cosmos/cosmos-sdk/types/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "google.golang.org/grpc" ) +// TxConfig holds configuration for transaction operations +type TxConfig struct { + ChainID string + Keyring keyring.Keyring + KeyName string // Name of the key to use for signing + GasLimit uint64 + GasAdjustment float64 + GasPadding uint64 + FeeDenom string + GasPrice string +} + // Module defines the interface for transaction-related operations type Module interface { - // BroadcastTx broadcasts a signed transaction - BroadcastTx(ctx context.Context, txBytes []byte, mode sdktx.BroadcastMode) (*sdktx.BroadcastTxResponse, error) - // SimulateTx simulates a transaction - SimulateTx(ctx context.Context, txBytes []byte) (*sdktx.SimulateResponse, error) + // SimulateTransaction simulates a transaction with given messages and returns gas used + SimulateTransaction(ctx context.Context, msgs []types.Msg, accountInfo *authtypes.BaseAccount, config *TxConfig) (*sdktx.SimulateResponse, error) + + // BuildAndSignTransaction builds and signs a transaction with the given parameters + BuildAndSignTransaction(ctx context.Context, msgs []types.Msg, accountInfo *authtypes.BaseAccount, gasLimit uint64, fee string, config *TxConfig) ([]byte, error) + + // BroadcastTransaction broadcasts a signed transaction and returns the result + BroadcastTransaction(ctx context.Context, txBytes []byte) (*sdktx.BroadcastTxResponse, error) + + // CalculateFee calculates the transaction fee based on gas usage and config + CalculateFee(gasAmount uint64, config *TxConfig) string - // GetTx gets transaction by hash - GetTx(ctx context.Context, hash string) (*sdktx.GetTxResponse, error) + // ProcessTransaction handles the complete flow: simulate, build, sign, and broadcast + ProcessTransaction(ctx context.Context, msgs []types.Msg, accountInfo *authtypes.BaseAccount, config *TxConfig) (*sdktx.BroadcastTxResponse, error) } // NewModule creates a new Transaction module client diff --git a/pkg/lumera/modules/tx/tx_mock.go b/pkg/lumera/modules/tx/tx_mock.go index 353b4150..c0eac536 100644 --- a/pkg/lumera/modules/tx/tx_mock.go +++ b/pkg/lumera/modules/tx/tx_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: interface.go +// +// Generated by this command: +// +// mockgen -destination=tx_mock.go -package=tx -source=interface.go +// // Package tx is a generated GoMock package. package tx @@ -8,14 +13,17 @@ import ( context "context" reflect "reflect" + types "github.com/cosmos/cosmos-sdk/types" tx "github.com/cosmos/cosmos-sdk/types/tx" - gomock "github.com/golang/mock/gomock" + types0 "github.com/cosmos/cosmos-sdk/x/auth/types" + gomock "go.uber.org/mock/gomock" ) // MockModule is a mock of Module interface. type MockModule struct { ctrl *gomock.Controller recorder *MockModuleMockRecorder + isgomock struct{} } // MockModuleMockRecorder is the mock recorder for MockModule. @@ -35,47 +43,76 @@ func (m *MockModule) EXPECT() *MockModuleMockRecorder { return m.recorder } -// BroadcastTx mocks base method. -func (m *MockModule) BroadcastTx(ctx context.Context, txBytes []byte, mode tx.BroadcastMode) (*tx.BroadcastTxResponse, error) { +// BroadcastTransaction mocks base method. +func (m *MockModule) BroadcastTransaction(ctx context.Context, txBytes []byte) (*tx.BroadcastTxResponse, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BroadcastTx", ctx, txBytes, mode) + ret := m.ctrl.Call(m, "BroadcastTransaction", ctx, txBytes) ret0, _ := ret[0].(*tx.BroadcastTxResponse) ret1, _ := ret[1].(error) return ret0, ret1 } -// BroadcastTx indicates an expected call of BroadcastTx. -func (mr *MockModuleMockRecorder) BroadcastTx(ctx, txBytes, mode interface{}) *gomock.Call { +// BroadcastTransaction indicates an expected call of BroadcastTransaction. +func (mr *MockModuleMockRecorder) BroadcastTransaction(ctx, txBytes any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastTx", reflect.TypeOf((*MockModule)(nil).BroadcastTx), ctx, txBytes, mode) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastTransaction", reflect.TypeOf((*MockModule)(nil).BroadcastTransaction), ctx, txBytes) } -// GetTx mocks base method. -func (m *MockModule) GetTx(ctx context.Context, hash string) (*tx.GetTxResponse, error) { +// BuildAndSignTransaction mocks base method. +func (m *MockModule) BuildAndSignTransaction(ctx context.Context, msgs []types.Msg, accountInfo *types0.BaseAccount, gasLimit uint64, fee string, config *TxConfig) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTx", ctx, hash) - ret0, _ := ret[0].(*tx.GetTxResponse) + ret := m.ctrl.Call(m, "BuildAndSignTransaction", ctx, msgs, accountInfo, gasLimit, fee, config) + ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetTx indicates an expected call of GetTx. -func (mr *MockModuleMockRecorder) GetTx(ctx, hash interface{}) *gomock.Call { +// BuildAndSignTransaction indicates an expected call of BuildAndSignTransaction. +func (mr *MockModuleMockRecorder) BuildAndSignTransaction(ctx, msgs, accountInfo, gasLimit, fee, config any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTx", reflect.TypeOf((*MockModule)(nil).GetTx), ctx, hash) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildAndSignTransaction", reflect.TypeOf((*MockModule)(nil).BuildAndSignTransaction), ctx, msgs, accountInfo, gasLimit, fee, config) } -// SimulateTx mocks base method. -func (m *MockModule) SimulateTx(ctx context.Context, txBytes []byte) (*tx.SimulateResponse, error) { +// CalculateFee mocks base method. +func (m *MockModule) CalculateFee(gasAmount uint64, config *TxConfig) string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SimulateTx", ctx, txBytes) + ret := m.ctrl.Call(m, "CalculateFee", gasAmount, config) + ret0, _ := ret[0].(string) + return ret0 +} + +// CalculateFee indicates an expected call of CalculateFee. +func (mr *MockModuleMockRecorder) CalculateFee(gasAmount, config any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CalculateFee", reflect.TypeOf((*MockModule)(nil).CalculateFee), gasAmount, config) +} + +// ProcessTransaction mocks base method. +func (m *MockModule) ProcessTransaction(ctx context.Context, msgs []types.Msg, accountInfo *types0.BaseAccount, config *TxConfig) (*tx.BroadcastTxResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ProcessTransaction", ctx, msgs, accountInfo, config) + ret0, _ := ret[0].(*tx.BroadcastTxResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ProcessTransaction indicates an expected call of ProcessTransaction. +func (mr *MockModuleMockRecorder) ProcessTransaction(ctx, msgs, accountInfo, config any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessTransaction", reflect.TypeOf((*MockModule)(nil).ProcessTransaction), ctx, msgs, accountInfo, config) +} + +// SimulateTransaction mocks base method. +func (m *MockModule) SimulateTransaction(ctx context.Context, msgs []types.Msg, accountInfo *types0.BaseAccount, config *TxConfig) (*tx.SimulateResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SimulateTransaction", ctx, msgs, accountInfo, config) ret0, _ := ret[0].(*tx.SimulateResponse) ret1, _ := ret[1].(error) return ret0, ret1 } -// SimulateTx indicates an expected call of SimulateTx. -func (mr *MockModuleMockRecorder) SimulateTx(ctx, txBytes interface{}) *gomock.Call { +// SimulateTransaction indicates an expected call of SimulateTransaction. +func (mr *MockModuleMockRecorder) SimulateTransaction(ctx, msgs, accountInfo, config any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SimulateTx", reflect.TypeOf((*MockModule)(nil).SimulateTx), ctx, txBytes) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SimulateTransaction", reflect.TypeOf((*MockModule)(nil).SimulateTransaction), ctx, msgs, accountInfo, config) } diff --git a/pkg/net/grpc/client/client_mock.go b/pkg/net/grpc/client/client_mock.go index ccc51b35..6c404138 100644 --- a/pkg/net/grpc/client/client_mock.go +++ b/pkg/net/grpc/client/client_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: rq_server_client.go +// Source: client.go +// +// Generated by this command: +// +// mockgen -destination=client_mock.go -package=client -source=client.go +// // Package client is a generated GoMock package. package client @@ -8,7 +13,7 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" grpc "google.golang.org/grpc" connectivity "google.golang.org/grpc/connectivity" keepalive "google.golang.org/grpc/keepalive" @@ -18,6 +23,7 @@ import ( type MockgrpcClient struct { ctrl *gomock.Controller recorder *MockgrpcClientMockRecorder + isgomock struct{} } // MockgrpcClientMockRecorder is the mock recorder for MockgrpcClient. @@ -46,7 +52,7 @@ func (m *MockgrpcClient) BuildDialOptions(opts *ClientOptions) []grpc.DialOption } // BuildDialOptions indicates an expected call of BuildDialOptions. -func (mr *MockgrpcClientMockRecorder) BuildDialOptions(opts interface{}) *gomock.Call { +func (mr *MockgrpcClientMockRecorder) BuildDialOptions(opts any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildDialOptions", reflect.TypeOf((*MockgrpcClient)(nil).BuildDialOptions), opts) } @@ -61,7 +67,7 @@ func (m *MockgrpcClient) Connect(ctx context.Context, address string, opts *Clie } // Connect indicates an expected call of Connect. -func (mr *MockgrpcClientMockRecorder) Connect(ctx, address, opts interface{}) *gomock.Call { +func (mr *MockgrpcClientMockRecorder) Connect(ctx, address, opts any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connect", reflect.TypeOf((*MockgrpcClient)(nil).Connect), ctx, address, opts) } @@ -75,7 +81,7 @@ func (m *MockgrpcClient) GetState(conn *grpc.ClientConn) connectivity.State { } // GetState indicates an expected call of GetState. -func (mr *MockgrpcClientMockRecorder) GetState(conn interface{}) *gomock.Call { +func (mr *MockgrpcClientMockRecorder) GetState(conn any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetState", reflect.TypeOf((*MockgrpcClient)(nil).GetState), conn) } @@ -87,7 +93,7 @@ func (m *MockgrpcClient) MonitorConnectionState(ctx context.Context, conn *grpc. } // MonitorConnectionState indicates an expected call of MonitorConnectionState. -func (mr *MockgrpcClientMockRecorder) MonitorConnectionState(ctx, conn, callback interface{}) *gomock.Call { +func (mr *MockgrpcClientMockRecorder) MonitorConnectionState(ctx, conn, callback any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MonitorConnectionState", reflect.TypeOf((*MockgrpcClient)(nil).MonitorConnectionState), ctx, conn, callback) } @@ -99,7 +105,7 @@ func (m *MockgrpcClient) ResetConnectBackoff(conn *grpc.ClientConn) { } // ResetConnectBackoff indicates an expected call of ResetConnectBackoff. -func (mr *MockgrpcClientMockRecorder) ResetConnectBackoff(conn interface{}) *gomock.Call { +func (mr *MockgrpcClientMockRecorder) ResetConnectBackoff(conn any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetConnectBackoff", reflect.TypeOf((*MockgrpcClient)(nil).ResetConnectBackoff), conn) } @@ -113,7 +119,7 @@ func (m *MockgrpcClient) WaitForStateChange(ctx context.Context, conn *grpc.Clie } // WaitForStateChange indicates an expected call of WaitForStateChange. -func (mr *MockgrpcClientMockRecorder) WaitForStateChange(ctx, conn, sourceState interface{}) *gomock.Call { +func (mr *MockgrpcClientMockRecorder) WaitForStateChange(ctx, conn, sourceState any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForStateChange", reflect.TypeOf((*MockgrpcClient)(nil).WaitForStateChange), ctx, conn, sourceState) } @@ -122,6 +128,7 @@ func (mr *MockgrpcClientMockRecorder) WaitForStateChange(ctx, conn, sourceState type MockDialOptionBuilder struct { ctrl *gomock.Controller recorder *MockDialOptionBuilderMockRecorder + isgomock struct{} } // MockDialOptionBuilderMockRecorder is the mock recorder for MockDialOptionBuilder. @@ -150,7 +157,7 @@ func (m *MockDialOptionBuilder) buildCallOptions(opts *ClientOptions) []grpc.Cal } // buildCallOptions indicates an expected call of buildCallOptions. -func (mr *MockDialOptionBuilderMockRecorder) buildCallOptions(opts interface{}) *gomock.Call { +func (mr *MockDialOptionBuilderMockRecorder) buildCallOptions(opts any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "buildCallOptions", reflect.TypeOf((*MockDialOptionBuilder)(nil).buildCallOptions), opts) } @@ -164,7 +171,7 @@ func (m *MockDialOptionBuilder) buildConnectParams(opts *ClientOptions) grpc.Con } // buildConnectParams indicates an expected call of buildConnectParams. -func (mr *MockDialOptionBuilderMockRecorder) buildConnectParams(opts interface{}) *gomock.Call { +func (mr *MockDialOptionBuilderMockRecorder) buildConnectParams(opts any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "buildConnectParams", reflect.TypeOf((*MockDialOptionBuilder)(nil).buildConnectParams), opts) } @@ -178,7 +185,7 @@ func (m *MockDialOptionBuilder) buildKeepAliveParams(opts *ClientOptions) keepal } // buildKeepAliveParams indicates an expected call of buildKeepAliveParams. -func (mr *MockDialOptionBuilderMockRecorder) buildKeepAliveParams(opts interface{}) *gomock.Call { +func (mr *MockDialOptionBuilderMockRecorder) buildKeepAliveParams(opts any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "buildKeepAliveParams", reflect.TypeOf((*MockDialOptionBuilder)(nil).buildKeepAliveParams), opts) } @@ -187,6 +194,7 @@ func (mr *MockDialOptionBuilderMockRecorder) buildKeepAliveParams(opts interface type MockConnectionHandler struct { ctrl *gomock.Controller recorder *MockConnectionHandlerMockRecorder + isgomock struct{} } // MockConnectionHandlerMockRecorder is the mock recorder for MockConnectionHandler. @@ -216,7 +224,7 @@ func (m *MockConnectionHandler) attemptConnection(ctx context.Context, target st } // attemptConnection indicates an expected call of attemptConnection. -func (mr *MockConnectionHandlerMockRecorder) attemptConnection(ctx, target, opts interface{}) *gomock.Call { +func (mr *MockConnectionHandlerMockRecorder) attemptConnection(ctx, target, opts any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "attemptConnection", reflect.TypeOf((*MockConnectionHandler)(nil).attemptConnection), ctx, target, opts) } @@ -231,7 +239,7 @@ func (m *MockConnectionHandler) configureContext(ctx context.Context) (context.C } // configureContext indicates an expected call of configureContext. -func (mr *MockConnectionHandlerMockRecorder) configureContext(ctx interface{}) *gomock.Call { +func (mr *MockConnectionHandlerMockRecorder) configureContext(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "configureContext", reflect.TypeOf((*MockConnectionHandler)(nil).configureContext), ctx) } @@ -246,7 +254,7 @@ func (m *MockConnectionHandler) retryConnection(ctx context.Context, address str } // retryConnection indicates an expected call of retryConnection. -func (mr *MockConnectionHandlerMockRecorder) retryConnection(ctx, address, opts interface{}) *gomock.Call { +func (mr *MockConnectionHandlerMockRecorder) retryConnection(ctx, address, opts any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "retryConnection", reflect.TypeOf((*MockConnectionHandler)(nil).retryConnection), ctx, address, opts) } @@ -255,6 +263,7 @@ func (mr *MockConnectionHandlerMockRecorder) retryConnection(ctx, address, opts type MockClientConn struct { ctrl *gomock.Controller recorder *MockClientConnMockRecorder + isgomock struct{} } // MockClientConnMockRecorder is the mock recorder for MockClientConn. @@ -309,7 +318,7 @@ func (m *MockClientConn) WaitForStateChange(ctx context.Context, sourceState con } // WaitForStateChange indicates an expected call of WaitForStateChange. -func (mr *MockClientConnMockRecorder) WaitForStateChange(ctx, sourceState interface{}) *gomock.Call { +func (mr *MockClientConnMockRecorder) WaitForStateChange(ctx, sourceState any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForStateChange", reflect.TypeOf((*MockClientConn)(nil).WaitForStateChange), ctx, sourceState) } diff --git a/pkg/net/grpc/client/client_test.go b/pkg/net/grpc/client/client_test.go index d438732b..12b196fa 100644 --- a/pkg/net/grpc/client/client_test.go +++ b/pkg/net/grpc/client/client_test.go @@ -2,18 +2,18 @@ package client import ( "context" - "os" "net" + "os" "testing" "time" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" "google.golang.org/grpc" + "google.golang.org/grpc/backoff" + "google.golang.org/grpc/connectivity" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/connectivity" - "google.golang.org/grpc/backoff" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/test/bufconn" ) @@ -84,10 +84,10 @@ func TestNewClient(t *testing.T) { func TestDefaultClientOptions(t *testing.T) { opts := DefaultClientOptions() assert.NotNil(t, opts, "ClientOptions should be initialized") - assert.Equal(t, 100 * MB, opts.MaxRecvMsgSize, "MaxRecvMsgSize should be 100 MB") - assert.Equal(t, 100 * MB, opts.MaxSendMsgSize, "MaxSendMsgSize should be 100 MB") - assert.Equal(t, int32(1 * MB), opts.InitialWindowSize, "InitialWindowSize should be 1 MB") - assert.Equal(t, int32(1 * MB), opts.InitialConnWindowSize, "InitialConnWindowSize should be 1 MB") + assert.Equal(t, 100*MB, opts.MaxRecvMsgSize, "MaxRecvMsgSize should be 100 MB") + assert.Equal(t, 100*MB, opts.MaxSendMsgSize, "MaxSendMsgSize should be 100 MB") + assert.Equal(t, int32(1*MB), opts.InitialWindowSize, "InitialWindowSize should be 1 MB") + assert.Equal(t, int32(1*MB), opts.InitialConnWindowSize, "InitialConnWindowSize should be 1 MB") assert.Equal(t, defaultConnWaitTime, opts.ConnWaitTime, "ConnWaitTime should be 10 seconds") assert.True(t, opts.EnableRetries, "EnableRetries should be true") assert.Equal(t, maxRetries, opts.MaxRetries, "MaxRetries should be 5") @@ -114,8 +114,8 @@ func TestBuildDialOptions(t *testing.T) { { name: "with user agent and authority", opts: &ClientOptions{ - UserAgent: "test-agent", - Authority: "test-authority", + UserAgent: "test-agent", + Authority: "test-authority", MaxRecvMsgSize: 1024, MaxSendMsgSize: 1024, }, @@ -211,27 +211,27 @@ func TestWaitForConnection(t *testing.T) { expectError: false, }, { - name: "connection shutdown", - initialState: connectivity.Connecting, - finalState: connectivity.Shutdown, - timeout: 2 * time.Second, - expectError: true, + name: "connection shutdown", + initialState: connectivity.Connecting, + finalState: connectivity.Shutdown, + timeout: 2 * time.Second, + expectError: true, expectedError: "grpc connection is shutdown", }, { - name: "transient failure", - initialState: connectivity.Connecting, - finalState: connectivity.TransientFailure, - timeout: 2 * time.Second, - expectError: true, + name: "transient failure", + initialState: connectivity.Connecting, + finalState: connectivity.TransientFailure, + timeout: 2 * time.Second, + expectError: true, expectedError: "grpc connection is in transient failure", }, { - name: "timeout waiting for connection", - initialState: connectivity.Connecting, - finalState: connectivity.Connecting, // Never changes - timeout: 500 * time.Millisecond, - expectError: true, + name: "timeout waiting for connection", + initialState: connectivity.Connecting, + finalState: connectivity.Connecting, // Never changes + timeout: 500 * time.Millisecond, + expectError: true, expectedError: "timeout waiting for grpc connection state change", }, } diff --git a/pkg/net/grpc/server/server_mock.go b/pkg/net/grpc/server/server_mock.go index b40a1c1c..9c89fcd2 100644 --- a/pkg/net/grpc/server/server_mock.go +++ b/pkg/net/grpc/server/server_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: server.go +// +// Generated by this command: +// +// mockgen -destination=server_mock.go -package=server -source=server.go +// // Package server is a generated GoMock package. package server @@ -8,7 +13,7 @@ import ( net "net" reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" grpc "google.golang.org/grpc" keepalive "google.golang.org/grpc/keepalive" ) @@ -17,6 +22,7 @@ import ( type MockgrpcServer struct { ctrl *gomock.Controller recorder *MockgrpcServerMockRecorder + isgomock struct{} } // MockgrpcServerMockRecorder is the mock recorder for MockgrpcServer. @@ -63,13 +69,13 @@ func (mr *MockgrpcServerMockRecorder) GracefulStop() *gomock.Call { } // RegisterService mocks base method. -func (m *MockgrpcServer) RegisterService(arg0 *grpc.ServiceDesc, arg1 interface{}) { +func (m *MockgrpcServer) RegisterService(arg0 *grpc.ServiceDesc, arg1 any) { m.ctrl.T.Helper() m.ctrl.Call(m, "RegisterService", arg0, arg1) } // RegisterService indicates an expected call of RegisterService. -func (mr *MockgrpcServerMockRecorder) RegisterService(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockgrpcServerMockRecorder) RegisterService(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterService", reflect.TypeOf((*MockgrpcServer)(nil).RegisterService), arg0, arg1) } @@ -83,7 +89,7 @@ func (m *MockgrpcServer) Serve(arg0 net.Listener) error { } // Serve indicates an expected call of Serve. -func (mr *MockgrpcServerMockRecorder) Serve(arg0 interface{}) *gomock.Call { +func (mr *MockgrpcServerMockRecorder) Serve(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Serve", reflect.TypeOf((*MockgrpcServer)(nil).Serve), arg0) } @@ -104,6 +110,7 @@ func (mr *MockgrpcServerMockRecorder) Stop() *gomock.Call { type MockServerOptionBuilder struct { ctrl *gomock.Controller recorder *MockServerOptionBuilderMockRecorder + isgomock struct{} } // MockServerOptionBuilderMockRecorder is the mock recorder for MockServerOptionBuilder. @@ -132,7 +139,7 @@ func (m *MockServerOptionBuilder) buildKeepAliveParams(opts *ServerOptions) keep } // buildKeepAliveParams indicates an expected call of buildKeepAliveParams. -func (mr *MockServerOptionBuilderMockRecorder) buildKeepAliveParams(opts interface{}) *gomock.Call { +func (mr *MockServerOptionBuilderMockRecorder) buildKeepAliveParams(opts any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "buildKeepAliveParams", reflect.TypeOf((*MockServerOptionBuilder)(nil).buildKeepAliveParams), opts) } @@ -146,7 +153,7 @@ func (m *MockServerOptionBuilder) buildKeepAlivePolicy(opts *ServerOptions) keep } // buildKeepAlivePolicy indicates an expected call of buildKeepAlivePolicy. -func (mr *MockServerOptionBuilderMockRecorder) buildKeepAlivePolicy(opts interface{}) *gomock.Call { +func (mr *MockServerOptionBuilderMockRecorder) buildKeepAlivePolicy(opts any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "buildKeepAlivePolicy", reflect.TypeOf((*MockServerOptionBuilder)(nil).buildKeepAlivePolicy), opts) } diff --git a/pkg/net/grpc/server/server_test.go b/pkg/net/grpc/server/server_test.go index 0d5fa2ef..8a75e013 100644 --- a/pkg/net/grpc/server/server_test.go +++ b/pkg/net/grpc/server/server_test.go @@ -3,16 +3,16 @@ package server import ( "context" "fmt" - "os" "net" + "os" "reflect" "testing" "time" "github.com/LumeraProtocol/supernode/pkg/testutil" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) @@ -53,22 +53,22 @@ func TestRegisterService(t *testing.T) { func TestDefaultServerOptions(t *testing.T) { opts := DefaultServerOptions() assert.NotNil(t, opts, "Server options should be initialized") - assert.Equal(t, 100 * MB, opts.MaxRecvMsgSize, "MaxRecvMsgSize should be 100 MB") - assert.Equal(t, 100 * MB, opts.MaxSendMsgSize, "MaxSendMsgSize should be 100 MB") - assert.Equal(t, int32(1 * MB), opts.InitialWindowSize, "InitialWindowSize should be 1 MB") - assert.Equal(t, int32(1 * MB), opts.InitialConnWindowSize, "InitialConnWindowSize should be 1 MB") + assert.Equal(t, 100*MB, opts.MaxRecvMsgSize, "MaxRecvMsgSize should be 100 MB") + assert.Equal(t, 100*MB, opts.MaxSendMsgSize, "MaxSendMsgSize should be 100 MB") + assert.Equal(t, int32(1*MB), opts.InitialWindowSize, "InitialWindowSize should be 1 MB") + assert.Equal(t, int32(1*MB), opts.InitialConnWindowSize, "InitialConnWindowSize should be 1 MB") assert.Equal(t, uint32(1000), opts.MaxConcurrentStreams, "MaxConcurrentStreams should be 1000") - assert.Equal(t, defaultGracefulShutdownTimeout, opts.GracefulShutdownTime, + assert.Equal(t, defaultGracefulShutdownTimeout, opts.GracefulShutdownTime, fmt.Sprintf("GracefulShutdownTimeout should be %v", defaultGracefulShutdownTimeout)) assert.Equal(t, uint32(0), opts.NumServerWorkers, "NumServerWorkers should be 0") - assert.Equal(t, 32 * KB, opts.WriteBufferSize, "WriteBufferSize should be 32 KB") - assert.Equal(t, 32 * KB, opts.ReadBufferSize, "ReadBufferSize should be 32 KB") - assert.Equal(t, 2 * time.Hour, opts.MaxConnectionIdle, "MaxConnectionIdle should be 2 hours") - assert.Equal(t, 2 * time.Hour, opts.MaxConnectionAge, "MaxConnectionAge should be 2 hours") - assert.Equal(t, 1 * time.Hour, opts.MaxConnectionAgeGrace, "MaxConnectionAgeGrace should be 1 hour") - assert.Equal(t, 1 * time.Hour, opts.Time, "Time should be 1 hour") - assert.Equal(t, 30 * time.Minute, opts.Timeout, "Timeout should be 30 minutes") - assert.Equal(t, 5 * time.Minute, opts.MinTime, "MinTime should be 5 minutes") + assert.Equal(t, 32*KB, opts.WriteBufferSize, "WriteBufferSize should be 32 KB") + assert.Equal(t, 32*KB, opts.ReadBufferSize, "ReadBufferSize should be 32 KB") + assert.Equal(t, 2*time.Hour, opts.MaxConnectionIdle, "MaxConnectionIdle should be 2 hours") + assert.Equal(t, 2*time.Hour, opts.MaxConnectionAge, "MaxConnectionAge should be 2 hours") + assert.Equal(t, 1*time.Hour, opts.MaxConnectionAgeGrace, "MaxConnectionAgeGrace should be 1 hour") + assert.Equal(t, 1*time.Hour, opts.Time, "Time should be 1 hour") + assert.Equal(t, 30*time.Minute, opts.Timeout, "Timeout should be 30 minutes") + assert.Equal(t, 5*time.Minute, opts.MinTime, "MinTime should be 5 minutes") assert.True(t, opts.PermitWithoutStream, "PermitWithoutStream should be true") } @@ -153,7 +153,7 @@ func TestBuildServerOptionsWithWorkers(t *testing.T) { serverOpts := server.buildServerOptions(opts) assert.NotNil(t, serverOpts, "Server options should be built") - + // Check function signature rather than value comparison found := false for _, opt := range serverOpts { @@ -222,7 +222,7 @@ type TestServiceInterface interface { } type TestService struct{} - + func (TestService) TestMethod(ctx context.Context, req interface{}) (interface{}, error) { return nil, nil } diff --git a/pkg/storage/rqstore/rq_mock.go b/pkg/storage/rqstore/rq_mock.go new file mode 100644 index 00000000..a460d74c --- /dev/null +++ b/pkg/storage/rqstore/rq_mock.go @@ -0,0 +1,126 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: store.go +// +// Generated by this command: +// +// mockgen -destination=rq_mock.go -package=rqstore -source=store.go +// + +// Package rqstore is a generated GoMock package. +package rqstore + +import ( + reflect "reflect" + + gomock "go.uber.org/mock/gomock" +) + +// MockStore is a mock of Store interface. +type MockStore struct { + ctrl *gomock.Controller + recorder *MockStoreMockRecorder + isgomock struct{} +} + +// MockStoreMockRecorder is the mock recorder for MockStore. +type MockStoreMockRecorder struct { + mock *MockStore +} + +// NewMockStore creates a new mock instance. +func NewMockStore(ctrl *gomock.Controller) *MockStore { + mock := &MockStore{ctrl: ctrl} + mock.recorder = &MockStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockStore) EXPECT() *MockStoreMockRecorder { + return m.recorder +} + +// DeleteSymbolsByTxID mocks base method. +func (m *MockStore) DeleteSymbolsByTxID(txid string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteSymbolsByTxID", txid) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteSymbolsByTxID indicates an expected call of DeleteSymbolsByTxID. +func (mr *MockStoreMockRecorder) DeleteSymbolsByTxID(txid any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSymbolsByTxID", reflect.TypeOf((*MockStore)(nil).DeleteSymbolsByTxID), txid) +} + +// GetDirectoryByTxID mocks base method. +func (m *MockStore) GetDirectoryByTxID(txid string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDirectoryByTxID", txid) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDirectoryByTxID indicates an expected call of GetDirectoryByTxID. +func (mr *MockStoreMockRecorder) GetDirectoryByTxID(txid any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDirectoryByTxID", reflect.TypeOf((*MockStore)(nil).GetDirectoryByTxID), txid) +} + +// GetToDoStoreSymbolDirs mocks base method. +func (m *MockStore) GetToDoStoreSymbolDirs() ([]SymbolDir, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetToDoStoreSymbolDirs") + ret0, _ := ret[0].([]SymbolDir) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetToDoStoreSymbolDirs indicates an expected call of GetToDoStoreSymbolDirs. +func (mr *MockStoreMockRecorder) GetToDoStoreSymbolDirs() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetToDoStoreSymbolDirs", reflect.TypeOf((*MockStore)(nil).GetToDoStoreSymbolDirs)) +} + +// SetIsCompleted mocks base method. +func (m *MockStore) SetIsCompleted(txid string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIsCompleted", txid) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetIsCompleted indicates an expected call of SetIsCompleted. +func (mr *MockStoreMockRecorder) SetIsCompleted(txid any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIsCompleted", reflect.TypeOf((*MockStore)(nil).SetIsCompleted), txid) +} + +// StoreSymbolDirectory mocks base method. +func (m *MockStore) StoreSymbolDirectory(txid, dir string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StoreSymbolDirectory", txid, dir) + ret0, _ := ret[0].(error) + return ret0 +} + +// StoreSymbolDirectory indicates an expected call of StoreSymbolDirectory. +func (mr *MockStoreMockRecorder) StoreSymbolDirectory(txid, dir any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreSymbolDirectory", reflect.TypeOf((*MockStore)(nil).StoreSymbolDirectory), txid, dir) +} + +// UpdateIsFirstBatchStored mocks base method. +func (m *MockStore) UpdateIsFirstBatchStored(txid string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateIsFirstBatchStored", txid) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateIsFirstBatchStored indicates an expected call of UpdateIsFirstBatchStored. +func (mr *MockStoreMockRecorder) UpdateIsFirstBatchStored(txid any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateIsFirstBatchStored", reflect.TypeOf((*MockStore)(nil).UpdateIsFirstBatchStored), txid) +} diff --git a/pkg/testutil/lumera.go b/pkg/testutil/lumera.go index 223be49e..d56ecc49 100644 --- a/pkg/testutil/lumera.go +++ b/pkg/testutil/lumera.go @@ -15,6 +15,7 @@ import ( cmtservice "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdktypes "github.com/cosmos/cosmos-sdk/types" sdktx "github.com/cosmos/cosmos-sdk/types/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -121,13 +122,23 @@ func (m *MockActionModule) GetParams(ctx context.Context) (*types.QueryParamsRes // MockActionMsgModule implements the action_msg.Module interface for testing type MockActionMsgModule struct{} -// Add methods as needed based on the actual action_msg.Module interface -// For now, this is a placeholder implementation +// RequestAction mocks the behavior of requesting an action. +// Adjust the signature and return values as needed to match the actual interface. +func (m *MockActionMsgModule) RequestAction(ctx context.Context, req *types.MsgRequestAction) (*sdktx.BroadcastTxResponse, error) { + // Mock implementation returns success with empty result + return &sdktx.BroadcastTxResponse{}, nil +} + +// RequesAction is a stub to satisfy the action_msg.Module interface in case of typo in interface definition. +func (m *MockActionMsgModule) RequesAction(ctx context.Context, arg1, arg2, arg3, arg4 string) (*sdktx.BroadcastTxResponse, error) { + // Mock implementation returns success with empty result + return &sdktx.BroadcastTxResponse{}, nil +} // FinalizeCascadeAction implements the required method from action_msg.Module interface -func (m *MockActionMsgModule) FinalizeCascadeAction(ctx context.Context, actionId string, signatures []string) (*action_msg.FinalizeActionResult, error) { +func (m *MockActionMsgModule) FinalizeCascadeAction(ctx context.Context, actionId string, signatures []string) (*sdktx.BroadcastTxResponse, error) { // Mock implementation returns success with empty result - return &action_msg.FinalizeActionResult{}, nil + return &sdktx.BroadcastTxResponse{}, nil } // MockSupernodeModule implements the supernode.Module interface for testing @@ -156,16 +167,34 @@ func (m *MockSupernodeModule) GetParams(ctx context.Context) (*supernodeTypes.Qu // MockTxModule implements the tx.Module interface for testing type MockTxModule struct{} -func (m *MockTxModule) BroadcastTx(ctx context.Context, txBytes []byte, mode sdktx.BroadcastMode) (*sdktx.BroadcastTxResponse, error) { +// SimulateTransaction simulates a transaction with given messages and returns gas used +func (m *MockTxModule) SimulateTransaction(ctx context.Context, msgs []sdktypes.Msg, accountInfo *authtypes.BaseAccount, config *tx.TxConfig) (*sdktx.SimulateResponse, error) { + // Mock implementation returns empty simulation response + return &sdktx.SimulateResponse{}, nil +} + +// BuildAndSignTransaction builds and signs a transaction with the given parameters +func (m *MockTxModule) BuildAndSignTransaction(ctx context.Context, msgs []sdktypes.Msg, accountInfo *authtypes.BaseAccount, gasLimit uint64, fee string, config *tx.TxConfig) ([]byte, error) { + // Mock implementation returns empty tx bytes + return []byte{}, nil +} + +// BroadcastTransaction mocks the behavior of broadcasting a transaction +func (m *MockTxModule) BroadcastTransaction(ctx context.Context, txBytes []byte) (*sdktx.BroadcastTxResponse, error) { + // Mock implementation returns an empty response for testing return &sdktx.BroadcastTxResponse{}, nil } -func (m *MockTxModule) SimulateTx(ctx context.Context, txBytes []byte) (*sdktx.SimulateResponse, error) { - return &sdktx.SimulateResponse{}, nil +// CalculateFee calculates the transaction fee based on gas usage and config +func (m *MockTxModule) CalculateFee(gasAmount uint64, config *tx.TxConfig) string { + // Mock implementation returns empty fee string + return "" } -func (m *MockTxModule) GetTx(ctx context.Context, hash string) (*sdktx.GetTxResponse, error) { - return &sdktx.GetTxResponse{}, nil +// ProcessTransaction handles the complete flow: simulate, build, sign, and broadcast +func (m *MockTxModule) ProcessTransaction(ctx context.Context, msgs []sdktypes.Msg, accountInfo *authtypes.BaseAccount, config *tx.TxConfig) (*sdktx.BroadcastTxResponse, error) { + // Mock implementation returns empty broadcast response + return &sdktx.BroadcastTxResponse{}, nil } // MockNodeModule implements the node.Module interface for testing diff --git a/supernode/node/action/server/cascade/cascade_action_server_test.go b/supernode/node/action/server/cascade/cascade_action_server_test.go index aa36a6cc..46405ef4 100644 --- a/supernode/node/action/server/cascade/cascade_action_server_test.go +++ b/supernode/node/action/server/cascade/cascade_action_server_test.go @@ -9,8 +9,8 @@ import ( "github.com/LumeraProtocol/supernode/supernode/services/cascade" cascademocks "github.com/LumeraProtocol/supernode/supernode/services/cascade/mocks" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" ) func TestRegister_Success(t *testing.T) { diff --git a/supernode/node/supernode/server/mock_keyring.go b/supernode/node/supernode/server/mock_keyring.go index 2ecea380..8e97e51d 100644 --- a/supernode/node/supernode/server/mock_keyring.go +++ b/supernode/node/supernode/server/mock_keyring.go @@ -11,7 +11,8 @@ import ( types "github.com/cosmos/cosmos-sdk/crypto/types" types0 "github.com/cosmos/cosmos-sdk/types" signing "github.com/cosmos/cosmos-sdk/types/tx/signing" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" + ) // MockKeyring is a mock of Keyring interface. diff --git a/supernode/node/supernode/server/server_test.go b/supernode/node/supernode/server/server_test.go index da2b2b43..e2a86e4c 100644 --- a/supernode/node/supernode/server/server_test.go +++ b/supernode/node/supernode/server/server_test.go @@ -1,12 +1,14 @@ package server import ( - "github.com/golang/mock/gomock" + "testing" + + "github.com/LumeraProtocol/supernode/pkg/lumera" "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" + "google.golang.org/grpc" "google.golang.org/grpc/health/grpc_health_v1" - "testing" - "github.com/LumeraProtocol/supernode/pkg/lumera" ) // --- Mock service implementing server.service --- @@ -49,7 +51,7 @@ func TestNewServer_WithNilConfig(t *testing.T) { func TestSetServiceStatusAndClose(t *testing.T) { ctl := gomock.NewController(t) defer ctl.Finish() - + mockKeyring := NewMockKeyring(ctl) mockLumeraClient := lumera.NewMockClient(ctl) diff --git a/supernode/services/cascade/adaptors/lumera.go b/supernode/services/cascade/adaptors/lumera.go index 83a6e9e8..fa6d95c4 100644 --- a/supernode/services/cascade/adaptors/lumera.go +++ b/supernode/services/cascade/adaptors/lumera.go @@ -6,7 +6,7 @@ import ( actiontypes "github.com/LumeraProtocol/lumera/x/action/v1/types" sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types" "github.com/LumeraProtocol/supernode/pkg/lumera" - "github.com/LumeraProtocol/supernode/pkg/lumera/modules/action_msg" + sdktx "github.com/cosmos/cosmos-sdk/types/tx" ) //go:generate mockgen -destination=mocks/lumera_mock.go -package=cascadeadaptormocks -source=lumera.go @@ -18,7 +18,7 @@ type LumeraClient interface { // Action Module GetAction(ctx context.Context, actionID string) (*actiontypes.QueryGetActionResponse, error) - FinalizeAction(ctx context.Context, actionID string, rqids []string) (*action_msg.FinalizeActionResult, error) + FinalizeAction(ctx context.Context, actionID string, rqids []string) (*sdktx.BroadcastTxResponse, error) GetActionFee(ctx context.Context, dataSize string) (*actiontypes.QueryGetActionFeeResponse, error) // Auth Verify(ctx context.Context, creator string, file []byte, sigBytes []byte) error @@ -43,7 +43,7 @@ func (c *Client) GetActionFee(ctx context.Context, dataSize string) (*actiontype return c.lc.Action().GetActionFee(ctx, dataSize) } -func (c *Client) FinalizeAction(ctx context.Context, actionID string, rqids []string) (*action_msg.FinalizeActionResult, error) { +func (c *Client) FinalizeAction(ctx context.Context, actionID string, rqids []string) (*sdktx.BroadcastTxResponse, error) { return c.lc.ActionMsg().FinalizeCascadeAction(ctx, actionID, rqids) } diff --git a/supernode/services/cascade/adaptors/mocks/lumera_mock.go b/supernode/services/cascade/adaptors/mocks/lumera_mock.go index f24c757f..84ead7ac 100644 --- a/supernode/services/cascade/adaptors/mocks/lumera_mock.go +++ b/supernode/services/cascade/adaptors/mocks/lumera_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: lumera.go +// +// Generated by this command: +// +// mockgen -destination=mocks/lumera_mock.go -package=cascadeadaptormocks -source=lumera.go +// // Package cascadeadaptormocks is a generated GoMock package. package cascadeadaptormocks @@ -10,14 +15,15 @@ import ( types "github.com/LumeraProtocol/lumera/x/action/v1/types" types0 "github.com/LumeraProtocol/lumera/x/supernode/v1/types" - action_msg "github.com/LumeraProtocol/supernode/pkg/lumera/modules/action_msg" - gomock "github.com/golang/mock/gomock" + tx "github.com/cosmos/cosmos-sdk/types/tx" + gomock "go.uber.org/mock/gomock" ) // MockLumeraClient is a mock of LumeraClient interface. type MockLumeraClient struct { ctrl *gomock.Controller recorder *MockLumeraClientMockRecorder + isgomock struct{} } // MockLumeraClientMockRecorder is the mock recorder for MockLumeraClient. @@ -38,16 +44,16 @@ func (m *MockLumeraClient) EXPECT() *MockLumeraClientMockRecorder { } // FinalizeAction mocks base method. -func (m *MockLumeraClient) FinalizeAction(ctx context.Context, actionID string, rqids []string) (*action_msg.FinalizeActionResult, error) { +func (m *MockLumeraClient) FinalizeAction(ctx context.Context, actionID string, rqids []string) (*tx.BroadcastTxResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "FinalizeAction", ctx, actionID, rqids) - ret0, _ := ret[0].(*action_msg.FinalizeActionResult) + ret0, _ := ret[0].(*tx.BroadcastTxResponse) ret1, _ := ret[1].(error) return ret0, ret1 } // FinalizeAction indicates an expected call of FinalizeAction. -func (mr *MockLumeraClientMockRecorder) FinalizeAction(ctx, actionID, rqids interface{}) *gomock.Call { +func (mr *MockLumeraClientMockRecorder) FinalizeAction(ctx, actionID, rqids any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FinalizeAction", reflect.TypeOf((*MockLumeraClient)(nil).FinalizeAction), ctx, actionID, rqids) } @@ -62,7 +68,7 @@ func (m *MockLumeraClient) GetAction(ctx context.Context, actionID string) (*typ } // GetAction indicates an expected call of GetAction. -func (mr *MockLumeraClientMockRecorder) GetAction(ctx, actionID interface{}) *gomock.Call { +func (mr *MockLumeraClientMockRecorder) GetAction(ctx, actionID any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAction", reflect.TypeOf((*MockLumeraClient)(nil).GetAction), ctx, actionID) } @@ -77,7 +83,7 @@ func (m *MockLumeraClient) GetActionFee(ctx context.Context, dataSize string) (* } // GetActionFee indicates an expected call of GetActionFee. -func (mr *MockLumeraClientMockRecorder) GetActionFee(ctx, dataSize interface{}) *gomock.Call { +func (mr *MockLumeraClientMockRecorder) GetActionFee(ctx, dataSize any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActionFee", reflect.TypeOf((*MockLumeraClient)(nil).GetActionFee), ctx, dataSize) } @@ -92,7 +98,7 @@ func (m *MockLumeraClient) GetTopSupernodes(ctx context.Context, height uint64) } // GetTopSupernodes indicates an expected call of GetTopSupernodes. -func (mr *MockLumeraClientMockRecorder) GetTopSupernodes(ctx, height interface{}) *gomock.Call { +func (mr *MockLumeraClientMockRecorder) GetTopSupernodes(ctx, height any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTopSupernodes", reflect.TypeOf((*MockLumeraClient)(nil).GetTopSupernodes), ctx, height) } @@ -106,7 +112,7 @@ func (m *MockLumeraClient) Verify(ctx context.Context, creator string, file, sig } // Verify indicates an expected call of Verify. -func (mr *MockLumeraClientMockRecorder) Verify(ctx, creator, file, sigBytes interface{}) *gomock.Call { +func (mr *MockLumeraClientMockRecorder) Verify(ctx, creator, file, sigBytes any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Verify", reflect.TypeOf((*MockLumeraClient)(nil).Verify), ctx, creator, file, sigBytes) } diff --git a/supernode/services/cascade/adaptors/mocks/p2p_mock.go b/supernode/services/cascade/adaptors/mocks/p2p_mock.go index 344647ee..2b60d881 100644 --- a/supernode/services/cascade/adaptors/mocks/p2p_mock.go +++ b/supernode/services/cascade/adaptors/mocks/p2p_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: p2p.go +// +// Generated by this command: +// +// mockgen -destination=mocks/p2p_mock.go -package=cascadeadaptormocks -source=p2p.go +// // Package cascadeadaptormocks is a generated GoMock package. package cascadeadaptormocks @@ -10,13 +15,14 @@ import ( logtrace "github.com/LumeraProtocol/supernode/pkg/logtrace" adaptors "github.com/LumeraProtocol/supernode/supernode/services/cascade/adaptors" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockP2PService is a mock of P2PService interface. type MockP2PService struct { ctrl *gomock.Controller recorder *MockP2PServiceMockRecorder + isgomock struct{} } // MockP2PServiceMockRecorder is the mock recorder for MockP2PService. @@ -45,7 +51,7 @@ func (m *MockP2PService) StoreArtefacts(ctx context.Context, req adaptors.StoreA } // StoreArtefacts indicates an expected call of StoreArtefacts. -func (mr *MockP2PServiceMockRecorder) StoreArtefacts(ctx, req, f interface{}) *gomock.Call { +func (mr *MockP2PServiceMockRecorder) StoreArtefacts(ctx, req, f any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreArtefacts", reflect.TypeOf((*MockP2PService)(nil).StoreArtefacts), ctx, req, f) } diff --git a/supernode/services/cascade/adaptors/mocks/rq_mock.go b/supernode/services/cascade/adaptors/mocks/rq_mock.go index 648d9615..34b73ee1 100644 --- a/supernode/services/cascade/adaptors/mocks/rq_mock.go +++ b/supernode/services/cascade/adaptors/mocks/rq_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: rq.go +// +// Generated by this command: +// +// mockgen -destination=mocks/rq_mock.go -package=cascadeadaptormocks -source=rq.go +// // Package cascadeadaptormocks is a generated GoMock package. package cascadeadaptormocks @@ -9,13 +14,14 @@ import ( reflect "reflect" adaptors "github.com/LumeraProtocol/supernode/supernode/services/cascade/adaptors" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockCodecService is a mock of CodecService interface. type MockCodecService struct { ctrl *gomock.Controller recorder *MockCodecServiceMockRecorder + isgomock struct{} } // MockCodecServiceMockRecorder is the mock recorder for MockCodecService. @@ -45,7 +51,7 @@ func (m *MockCodecService) EncodeInput(ctx context.Context, taskID, path string, } // EncodeInput indicates an expected call of EncodeInput. -func (mr *MockCodecServiceMockRecorder) EncodeInput(ctx, taskID, path, dataSize interface{}) *gomock.Call { +func (mr *MockCodecServiceMockRecorder) EncodeInput(ctx, taskID, path, dataSize any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EncodeInput", reflect.TypeOf((*MockCodecService)(nil).EncodeInput), ctx, taskID, path, dataSize) } diff --git a/supernode/services/cascade/mocks/cascade_interfaces_mock.go b/supernode/services/cascade/mocks/cascade_interfaces_mock.go index 3b0bb625..ac7a60e5 100644 --- a/supernode/services/cascade/mocks/cascade_interfaces_mock.go +++ b/supernode/services/cascade/mocks/cascade_interfaces_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: interfaces.go +// +// Generated by this command: +// +// mockgen -destination=mocks/cascade_interfaces_mock.go -package=cascademocks -source=interfaces.go +// // Package cascademocks is a generated GoMock package. package cascademocks @@ -9,13 +14,14 @@ import ( reflect "reflect" cascade "github.com/LumeraProtocol/supernode/supernode/services/cascade" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockTaskFactory is a mock of TaskFactory interface. type MockTaskFactory struct { ctrl *gomock.Controller recorder *MockTaskFactoryMockRecorder + isgomock struct{} } // MockTaskFactoryMockRecorder is the mock recorder for MockTaskFactory. @@ -53,6 +59,7 @@ func (mr *MockTaskFactoryMockRecorder) NewCascadeRegistrationTask() *gomock.Call type MockRegistrationTaskService struct { ctrl *gomock.Controller recorder *MockRegistrationTaskServiceMockRecorder + isgomock struct{} } // MockRegistrationTaskServiceMockRecorder is the mock recorder for MockRegistrationTaskService. @@ -81,7 +88,7 @@ func (m *MockRegistrationTaskService) Register(ctx context.Context, req *cascade } // Register indicates an expected call of Register. -func (mr *MockRegistrationTaskServiceMockRecorder) Register(ctx, req, send interface{}) *gomock.Call { +func (mr *MockRegistrationTaskServiceMockRecorder) Register(ctx, req, send any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Register", reflect.TypeOf((*MockRegistrationTaskService)(nil).Register), ctx, req, send) } diff --git a/supernode/services/cascade/register.go b/supernode/services/cascade/register.go index d5c5b2c9..a0cccba5 100644 --- a/supernode/services/cascade/register.go +++ b/supernode/services/cascade/register.go @@ -135,9 +135,10 @@ func (task *CascadeRegistrationTask) Register( logtrace.Info(ctx, "Finalize Action Error", fields) return task.wrapErr(ctx, "failed to finalize action", err, fields) } - fields[logtrace.FieldTxHash] = resp.TxHash + txHash := resp.TxResponse.TxHash + fields[logtrace.FieldTxHash] = txHash logtrace.Info(ctx, "action has been finalized", fields) - task.streamEvent(SupernodeEventTypeActionFinalized, "action has been finalized", resp.TxHash, send) + task.streamEvent(SupernodeEventTypeActionFinalized, "action has been finalized", txHash, send) err = os.RemoveAll(req.FilePath) if err != nil { diff --git a/supernode/services/cascade/register_test.go b/supernode/services/cascade/register_test.go index 6d65d909..2fe64359 100644 --- a/supernode/services/cascade/register_test.go +++ b/supernode/services/cascade/register_test.go @@ -2,25 +2,26 @@ package cascade_test import ( "context" - sdkmath "cosmossdk.io/math" "encoding/base64" "encoding/hex" + "os" + "testing" + + sdkmath "cosmossdk.io/math" actiontypes "github.com/LumeraProtocol/lumera/x/action/v1/types" sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types" codecpkg "github.com/LumeraProtocol/supernode/pkg/codec" - "github.com/LumeraProtocol/supernode/pkg/lumera/modules/action_msg" "github.com/LumeraProtocol/supernode/supernode/services/cascade" "github.com/LumeraProtocol/supernode/supernode/services/cascade/adaptors" cascadeadaptormocks "github.com/LumeraProtocol/supernode/supernode/services/cascade/adaptors/mocks" "github.com/LumeraProtocol/supernode/supernode/services/common" sdk "github.com/cosmos/cosmos-sdk/types" + sdktx "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/gogoproto/proto" "lukechampine.com/blake3" - "os" - "testing" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" ) func TestCascadeRegistrationTask_Register(t *testing.T) { @@ -82,7 +83,7 @@ func TestCascadeRegistrationTask_Register(t *testing.T) { // 4. Finalize lc.EXPECT(). FinalizeAction(gomock.Any(), "action123", gomock.Any()). - Return(&action_msg.FinalizeActionResult{TxHash: "tx123"}, nil) + Return(&sdktx.BroadcastTxResponse{TxResponse: &sdk.TxResponse{TxHash: "tx123"}}, nil) // 5. Params (if used in fee check) lc.EXPECT().GetActionFee(gomock.Any(), "10").Return(&actiontypes.QueryGetActionFeeResponse{Amount: "1000"}, nil) diff --git a/supernode/services/cascade/service_test.go b/supernode/services/cascade/service_test.go index f8859bc1..b4ae93ac 100644 --- a/supernode/services/cascade/service_test.go +++ b/supernode/services/cascade/service_test.go @@ -8,8 +8,8 @@ import ( "github.com/LumeraProtocol/supernode/supernode/services/cascade" cascadeadaptormocks "github.com/LumeraProtocol/supernode/supernode/services/cascade/adaptors/mocks" "github.com/LumeraProtocol/supernode/supernode/services/common" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" ) func TestNewCascadeService(t *testing.T) { diff --git a/tests/system/e2e_cascade_test.go b/tests/system/e2e_cascade_test.go index 6db5ff00..7b52b5c3 100644 --- a/tests/system/e2e_cascade_test.go +++ b/tests/system/e2e_cascade_test.go @@ -16,6 +16,7 @@ import ( "github.com/LumeraProtocol/supernode/pkg/codec" "github.com/LumeraProtocol/supernode/pkg/keyring" + "github.com/LumeraProtocol/supernode/pkg/lumera" "lukechampine.com/blake3" "github.com/LumeraProtocol/supernode/sdk/action" @@ -229,7 +230,17 @@ func TestCascadeE2E(t *testing.T) { // Initialize Lumera blockchain client for interactions - // + ctx := context.Background() + + lumeraCfg, err := lumera.NewConfig( + lumeraGRPCAddr, + lumeraChainID, + userKeyName, + keplrKeyring, + ) + require.NoError(t, err, "Failed to create Lumera client configuration") + + lumeraClinet, err := lumera.NewClient(ctx, lumeraCfg) require.NoError(t, err, "Failed to initialize Lumera client") // --------------------------------------- @@ -260,7 +271,6 @@ func TestCascadeE2E(t *testing.T) { rqCodec := codec.NewRaptorQCodec(raptorQFilesDir) - ctx := context.Background() encodeRes, err := rqCodec.Encode(ctx, codec.EncodeRequest{ Path: testFileFullpath, DataSize: int(fileInfo.Size()), @@ -332,20 +342,23 @@ func TestCascadeE2E(t *testing.T) { // Submit the action request transaction to the blockchain using user key // This registers the request with metadata for supernodes to process - actionRequestResp := cli.CustomCommand( - "tx", "action", "request-action", - actionType, // CASCADE action type - metadata, // JSON metadata with all required fields - price, // Price in ulume tokens - expirationTime, // Unix timestamp for expiration - "--from", userKeyName, // Use user key for transaction submission - "--gas", "auto", - "--gas-adjustment", "1.5", - ) + // actionRequestResp := cli.CustomCommand( + // "tx", "action", "request-action", + // actionType, // CASCADE action type + // metadata, // JSON metadata with all required fields + // price, // Price in ulume tokens + // expirationTime, // Unix timestamp for expiration + // "--from", userKeyName, // Use user key for transaction submission + // "--gas", "auto", + // "--gas-adjustment", "1.5", + // ) + + response, err := lumeraClinet.ActionMsg().RequesAction(ctx, actionType, metadata, price, expirationTime) + + txresp := response.TxResponse // Verify the transaction was successful - RequireTxSuccess(t, actionRequestResp) - t.Logf("Action request successful: %s", actionRequestResp) + require.Zero(t, txresp.Code, "Transaction should have success code 0") // Wait for transaction to be included in a block sut.AwaitNextBlock(t) @@ -355,7 +368,7 @@ func TestCascadeE2E(t *testing.T) { require.Contains(t, accountResp, "public_key", "User account public key should be available") // Extract transaction hash from response for verification - txHash := gjson.Get(actionRequestResp, "txhash").String() + txHash := txresp.TxHash require.NotEmpty(t, txHash, "Transaction hash should not be empty") t.Logf("Transaction hash: %s", txHash) diff --git a/tests/system/go.mod b/tests/system/go.mod index 1d71a2a7..cc6de30f 100644 --- a/tests/system/go.mod +++ b/tests/system/go.mod @@ -94,7 +94,6 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v1.2.4 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/mock v1.6.0 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.3 // indirect github.com/google/flatbuffers v1.12.1 // indirect @@ -159,6 +158,7 @@ require ( github.com/zondax/ledger-go v0.14.3 // indirect go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect go.opencensus.io v0.24.0 // indirect + go.uber.org/mock v0.5.2 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.15.0 // indirect golang.org/x/crypto v0.37.0 // indirect diff --git a/tests/system/go.sum b/tests/system/go.sum index ccdefd44..a52293ef 100644 --- a/tests/system/go.sum +++ b/tests/system/go.sum @@ -807,7 +807,6 @@ github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7V github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= @@ -889,7 +888,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -935,7 +933,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1029,7 +1026,6 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=