diff --git a/gen/lumera/action/types/codec.go b/gen/lumera/action/types/codec.go new file mode 100644 index 00000000..98e1bf63 --- /dev/null +++ b/gen/lumera/action/types/codec.go @@ -0,0 +1,26 @@ +package types + +import ( + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + // this line is used by starport scaffolding # 1 +) + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgRequestAction{}, + ) + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgFinalizeAction{}, + ) + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgApproveAction{}, + ) + // this line is used by starport scaffolding # 3 + + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgUpdateParams{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} diff --git a/p2p/kademlia/bootstrap.go b/p2p/kademlia/bootstrap.go index 065a4c1f..833350b4 100644 --- a/p2p/kademlia/bootstrap.go +++ b/p2p/kademlia/bootstrap.go @@ -9,6 +9,7 @@ import ( "time" "github.com/LumeraProtocol/supernode/pkg/errors" + "github.com/LumeraProtocol/supernode/pkg/utils" "github.com/LumeraProtocol/supernode/pkg/log" ltc "github.com/LumeraProtocol/supernode/pkg/net/credentials" @@ -20,10 +21,10 @@ const ( ) func (s *DHT) skipBadBootstrapAddrs() { - skipAddress1 := fmt.Sprintf("%s:%d", "127.0.0.1", s.options.Port) - skipAddress2 := fmt.Sprintf("%s:%d", "localhost", s.options.Port) - s.cache.Set(skipAddress1, []byte("true")) - s.cache.Set(skipAddress2, []byte("true")) + //skipAddress1 := fmt.Sprintf("%s:%d", "127.0.0.1", s.options.Port) + //skipAddress2 := fmt.Sprintf("%s:%d", "localhost", s.options.Port) + //s.cache.Set(skipAddress1, []byte("true")) + //s.cache.Set(skipAddress2, []byte("true")) } func (s *DHT) parseNode(extP2P string, selfAddr string) (*Node, error) { @@ -31,9 +32,10 @@ func (s *DHT) parseNode(extP2P string, selfAddr string) (*Node, error) { return nil, errors.New("empty address") } - if strings.Contains(extP2P, "0.0.0.0") { + /*if strings.Contains(extP2P, "0.0.0.0") { + fmt.Println("skippping node") return nil, errors.New("invalid address") - } + }*/ if extP2P == selfAddr { return nil, errors.New("self address") @@ -151,6 +153,10 @@ func (s *DHT) ConfigureBootstrapNodes(ctx context.Context, bootstrapNodes string // Convert the map to a slice for _, node := range mapNodes { + node.Port = node.Port + 1 + hID, _ := utils.Sha3256hash(node.ID) + node.HashedID = hID + fmt.Println("node adding", node.String(), "hashed id", string(node.HashedID)) boostrapNodes = append(boostrapNodes, node) } } diff --git a/p2p/kademlia/dht.go b/p2p/kademlia/dht.go index 853b912f..229ac5d7 100644 --- a/p2p/kademlia/dht.go +++ b/p2p/kademlia/dht.go @@ -147,6 +147,10 @@ func NewDHT(ctx context.Context, store Store, metaStore MetaStore, options *Opti return s, nil } +func (s *DHT) NodesLen() int { + return len(s.ht.nodes()) +} + func (s *DHT) getExternalIP() (string, error) { s.mtx.Lock() defer s.mtx.Unlock() diff --git a/pkg/log/context.go b/pkg/log/context.go index e6aa91f0..175ea0bd 100644 --- a/pkg/log/context.go +++ b/pkg/log/context.go @@ -45,3 +45,29 @@ func init() { return msg, fields })) } + +// GetExternalIPAddress returns external IP address +func GetExternalIPAddress() (externalIP string, err error) { + return "localhost", nil + /*if ip != "" { + return ip, nil + } + + resp, err := http.Get("https://api.ipify.org") + if err != nil { + return "", err + } + + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + if net.ParseIP(string(body)) == nil { + return "", errors.Errorf("invalid IP response from %s", "ipconf.ip") + } + + return string(body), nil*/ +} diff --git a/pkg/lumera/client.go b/pkg/lumera/client.go index 9f7cbf7e..89c993ed 100644 --- a/pkg/lumera/client.go +++ b/pkg/lumera/client.go @@ -4,6 +4,7 @@ import ( "context" "github.com/LumeraProtocol/supernode/pkg/lumera/modules/action" + "github.com/LumeraProtocol/supernode/pkg/lumera/modules/action_msg" "github.com/LumeraProtocol/supernode/pkg/lumera/modules/auth" "github.com/LumeraProtocol/supernode/pkg/lumera/modules/node" "github.com/LumeraProtocol/supernode/pkg/lumera/modules/supernode" @@ -15,6 +16,7 @@ type lumeraClient struct { cfg *Config authMod auth.Module actionMod action.Module + actionMsgMod action_msg.Module supernodeMod supernode.Module txMod tx.Module nodeMod node.Module @@ -49,6 +51,17 @@ func newClient(ctx context.Context, opts ...Option) (Client, error) { return nil, err } + actionMsgModule, err := action_msg.NewModule( + conn.GetConn(), + cfg.keyring, + cfg.KeyName, + cfg.ChainID, + ) + if err != nil { + conn.Close() + return nil, err + } + supernodeModule, err := supernode.NewModule(conn.GetConn()) if err != nil { conn.Close() @@ -71,6 +84,7 @@ func newClient(ctx context.Context, opts ...Option) (Client, error) { cfg: cfg, authMod: authModule, actionMod: actionModule, + actionMsgMod: actionMsgModule, supernodeMod: supernodeModule, txMod: txModule, nodeMod: nodeModule, @@ -88,6 +102,11 @@ 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 diff --git a/pkg/lumera/config.go b/pkg/lumera/config.go index 52343727..ab557de2 100644 --- a/pkg/lumera/config.go +++ b/pkg/lumera/config.go @@ -19,6 +19,9 @@ type Config struct { // keyring is the keyring conf for the node sign & verify keyring keyring.Keyring + + // KeyName is the name of the key to use for signing + KeyName string } // DefaultConfig returns a default configuration @@ -26,6 +29,7 @@ func DefaultConfig() *Config { return &Config{ GRPCAddr: "localhost:9090", ChainID: "lumera", - Timeout: 10, + Timeout: 30, + KeyName: "", } } diff --git a/pkg/lumera/interface.go b/pkg/lumera/interface.go index 940d4ab1..37495129 100644 --- a/pkg/lumera/interface.go +++ b/pkg/lumera/interface.go @@ -5,6 +5,7 @@ import ( "context" "github.com/LumeraProtocol/supernode/pkg/lumera/modules/action" + "github.com/LumeraProtocol/supernode/pkg/lumera/modules/action_msg" "github.com/LumeraProtocol/supernode/pkg/lumera/modules/auth" "github.com/LumeraProtocol/supernode/pkg/lumera/modules/node" "github.com/LumeraProtocol/supernode/pkg/lumera/modules/supernode" @@ -15,6 +16,7 @@ import ( type Client interface { Auth() auth.Module Action() action.Module + ActionMsg() action_msg.Module SuperNode() supernode.Module Tx() tx.Module Node() node.Module diff --git a/pkg/lumera/modules/action/impl.go b/pkg/lumera/modules/action/impl.go index 358aa07c..affa8b91 100644 --- a/pkg/lumera/modules/action/impl.go +++ b/pkg/lumera/modules/action/impl.go @@ -47,3 +47,13 @@ func (m *module) GetActionFee(ctx context.Context, dataSize string) (*types.Quer return resp, nil } + +// GetParams fetches the action module parameters +func (m *module) GetParams(ctx context.Context) (*types.QueryParamsResponse, error) { + resp, err := m.client.Params(ctx, &types.QueryParamsRequest{}) + if err != nil { + return nil, fmt.Errorf("failed to get action params: %w", err) + } + + return resp, nil +} diff --git a/pkg/lumera/modules/action/interface.go b/pkg/lumera/modules/action/interface.go index 329d7889..84746f26 100644 --- a/pkg/lumera/modules/action/interface.go +++ b/pkg/lumera/modules/action/interface.go @@ -12,6 +12,7 @@ import ( type Module interface { GetAction(ctx context.Context, actionID string) (*types.QueryGetActionResponse, error) GetActionFee(ctx context.Context, dataSize string) (*types.QueryGetActionFeeResponse, error) + GetParams(ctx context.Context) (*types.QueryParamsResponse, error) } // NewModule creates a new Action module client diff --git a/pkg/lumera/modules/action/tx/impl.go b/pkg/lumera/modules/action/tx/impl.go deleted file mode 100644 index 485f6f1f..00000000 --- a/pkg/lumera/modules/action/tx/impl.go +++ /dev/null @@ -1,141 +0,0 @@ -package tx - -import ( - "context" - "fmt" - "time" - - txmodule "github.com/LumeraProtocol/supernode/pkg/lumera/modules/tx" - - "github.com/LumeraProtocol/supernode/gen/lumera/action/types" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/tx" - cKeyring "github.com/cosmos/cosmos-sdk/crypto/keyring" - sdk "github.com/cosmos/cosmos-sdk/types" - sdktx "github.com/cosmos/cosmos-sdk/types/tx" - "google.golang.org/grpc" -) - -// module implements the Module interface -type module struct { - client types.MsgClient - txModule txmodule.Module -} - -// newModule creates a new Action tx module client -func newModule(conn *grpc.ClientConn) (Module, error) { - if conn == nil { - return nil, fmt.Errorf("connection cannot be nil") - } - - txMod, err := txmodule.NewModule(conn) - if err != nil { - return nil, fmt.Errorf("failed to create tx module: %w", err) - } - - return &module{ - client: types.NewMsgClient(conn), - txModule: txMod, - }, nil -} - -// FinalizeAction finalizes the given action -func (m *module) FinalizeAction( - ctx context.Context, - txConfig client.TxConfig, - keyRing cKeyring.Keyring, - actionID, creator, actionType, metadata, rpcURL, chainID string, -) (*types.MsgFinalizeActionResponse, error) { - fromName := creator // assuming `creator` is the key name in keyring - info, err := keyRing.Key(fromName) - if err != nil { - return nil, fmt.Errorf("failed to get key info: %w", err) - } - fromAddr, err := info.GetAddress() - if err != nil { - return nil, fmt.Errorf("failed to get address from key: %w", err) - } - - _ = client.Context{}. - WithNodeURI(rpcURL). - WithChainID(chainID). - WithKeyring(keyRing). - WithFromName(fromName). - WithFromAddress(fromAddr). - WithTxConfig(txConfig) - - msg := &types.MsgFinalizeAction{ - ActionId: actionID, - Creator: creator, - ActionType: actionType, - Metadata: metadata, - } - - txf := tx.Factory{}. - WithChainID(chainID). - WithKeybase(keyRing). - WithTxConfig(txConfig). - WithGasAdjustment(1.2). - WithGasPrices("0.025stake") - - builder := txConfig.NewTxBuilder() - if err := builder.SetMsgs(msg); err != nil { - return nil, fmt.Errorf("failed to set message: %w", err) - } - builder.SetGasLimit(0) // zero for simulation - - gasCtx, cancel := context.WithTimeout(ctx, 10*time.Second) - defer cancel() - - txf = txf.WithGas(0) - - simBuilder := txConfig.NewTxBuilder() - if err := simBuilder.SetMsgs(msg); err != nil { - return nil, fmt.Errorf("failed to set messages for simulation: %w", err) - } - - if err := tx.Sign(gasCtx, txf, fromName, simBuilder, true); err != nil { - return nil, fmt.Errorf("failed to sign transaction for simulation: %w", err) - } - - simBytes, err := txConfig.TxEncoder()(simBuilder.GetTx()) - if err != nil { - return nil, fmt.Errorf("failed to encode tx for simulation: %w", err) - } - - simRes, err := m.txModule.SimulateTx(gasCtx, simBytes) - if err != nil { - return nil, fmt.Errorf("failed to simulate transaction: %w", err) - } - - estimatedGas := simRes.GasInfo.GasUsed - builder.SetGasLimit(uint64(float64(estimatedGas) * txf.GasAdjustment())) - - gasPrices := txf.GasPrices() - if len(gasPrices) > 0 { - var fees sdk.Coins - for _, gasPrice := range gasPrices { - feeAmount := gasPrice.Amount.MulInt64(int64(builder.GetTx().GetGas())) - fees = append(fees, sdk.NewCoin(gasPrice.Denom, feeAmount.TruncateInt())) - } - - builder.SetFeeAmount(fees) - } - - if err := tx.Sign(ctx, txf, fromName, builder, true); err != nil { - return nil, fmt.Errorf("failed to sign transaction: %w", err) - } - - txBytes, err := txConfig.TxEncoder()(builder.GetTx()) - if err != nil { - return nil, fmt.Errorf("failed to encode tx: %w", err) - } - - _, err = m.txModule.BroadcastTx(ctx, txBytes, sdktx.BroadcastMode_BROADCAST_MODE_BLOCK) - if err != nil { - return nil, fmt.Errorf("failed to broadcast tx: %w", err) - } - - return &types.MsgFinalizeActionResponse{}, nil -} diff --git a/pkg/lumera/modules/action/tx/interface.go b/pkg/lumera/modules/action/tx/interface.go deleted file mode 100644 index a2627ae2..00000000 --- a/pkg/lumera/modules/action/tx/interface.go +++ /dev/null @@ -1,22 +0,0 @@ -//go:generate mockgen -destination=tx_mock.go -package=tx -source=interface.go -package tx - -import ( - "context" - - "github.com/LumeraProtocol/supernode/gen/lumera/action/types" - - "github.com/cosmos/cosmos-sdk/client" - cKeyring "github.com/cosmos/cosmos-sdk/crypto/keyring" - "google.golang.org/grpc" -) - -// Module defines the interface for interacting with the action tx module -type Module interface { - FinalizeAction(ctx context.Context, txConfig client.TxConfig, keyRing cKeyring.Keyring, actionID, creator, actionType, metadata, rpcURL, chainID string) (*types.MsgFinalizeActionResponse, error) -} - -// NewModule creates a new Action tx module client -func NewModule(conn *grpc.ClientConn) (Module, error) { - return newModule(conn) -} diff --git a/pkg/lumera/modules/action_msg/impl.go b/pkg/lumera/modules/action_msg/impl.go new file mode 100644 index 00000000..1e32be43 --- /dev/null +++ b/pkg/lumera/modules/action_msg/impl.go @@ -0,0 +1,397 @@ +package action_msg + +import ( + "context" + "encoding/json" + "fmt" + + actiontypes "github.com/LumeraProtocol/supernode/gen/lumera/action/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/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" + "google.golang.org/grpc" +) + +// Default gas parameters +const ( + defaultGasLimit = uint64(200000) + defaultMinGasLimit = uint64(100000) + defaultMaxGasLimit = uint64(1000000) + defaultGasAdjustment = float64(3.0) + defaultGasPadding = uint64(50000) +) + +// module implements the Module interface +type module struct { + conn *grpc.ClientConn + client actiontypes.MsgClient + kr keyring.Keyring + keyName string + chainID string + gasLimit uint64 + minGasLimit uint64 + maxGasLimit uint64 + gasAdjustment float64 + gasPadding uint64 +} + +// newModule creates a new ActionMsg module client +func newModule(conn *grpc.ClientConn, kr keyring.Keyring, keyName string, chainID string) (Module, error) { + if conn == nil { + return nil, fmt.Errorf("connection 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, + minGasLimit: defaultMinGasLimit, + maxGasLimit: defaultMaxGasLimit, + gasAdjustment: defaultGasAdjustment, + gasPadding: defaultGasPadding, + }, nil +} + +// FinalizeCascadeAction finalizes a CASCADE action with the given parameters +func (m *module) FinalizeCascadeAction( + ctx context.Context, + actionId string, + rqIdsIds []string, + rqIdsOti []byte, +) (*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") + } + if len(rqIdsOti) == 0 { + return nil, fmt.Errorf("rq_ids_oti 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 + metadata := map[string]interface{}{ + "rq_ids_ids": rqIdsIds, + "rq_ids_oti": rqIdsOti, + } + + // Convert metadata to JSON + metadataJSON, err := json.Marshal(metadata) + if err != nil { + return nil, fmt.Errorf("failed to marshal metadata: %w", err) + } + + // Create the message + msg := &actiontypes.MsgFinalizeAction{ + Creator: creator, + ActionId: actionId, + ActionType: "CASCADE", + Metadata: string(metadataJSON), + } + + // 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") + + // 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). + 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, // your signing 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) + } + + adjustedGas := uint64(float64(simulatedGas) * m.gasAdjustment) + gasToUse := adjustedGas + m.gasPadding + + // Apply gas bounds + if gasToUse > m.maxGasLimit { + gasToUse = m.maxGasLimit + } + + logtrace.Info(ctx, "using simulated gas", logtrace.Fields{"simulatedGas": simulatedGas, "adjustedGas": gasToUse}) + + // Create transaction factory with final gas + 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) + + // 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, + } + + // Check if we have the tx in the request too + if simReq.Tx != nil { + logtrace.Info(ctx, "simulation request has tx field", logtrace.Fields{ + "txFieldPresent": true, + }) + } + + 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) + } + + logtrace.Info(ctx, "simulation response", logtrace.Fields{ + "gasUsed": simRes.GasInfo.GasUsed, + "gasWanted": simRes.GasInfo.GasWanted, + }) + + 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 +} + +// TxResponse holds transaction response information +type TxResponse struct { + TxHash string + Code uint32 + RawLog string +} diff --git a/pkg/lumera/modules/action_msg/interface.go b/pkg/lumera/modules/action_msg/interface.go new file mode 100644 index 00000000..210cf8f8 --- /dev/null +++ b/pkg/lumera/modules/action_msg/interface.go @@ -0,0 +1,37 @@ +//go:generate mockgen -destination=action_msg_mock.go -package=action_msg -source=interface.go +package action_msg + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "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, + rqIdsOti []byte, + ) (*FinalizeActionResult, 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) +} diff --git a/pkg/lumera/modules/supernode/impl.go b/pkg/lumera/modules/supernode/impl.go index 6761ab6d..8e14b5a7 100644 --- a/pkg/lumera/modules/supernode/impl.go +++ b/pkg/lumera/modules/supernode/impl.go @@ -56,12 +56,22 @@ func (m *module) GetSupernodeBySupernodeAddress(ctx context.Context, address str SupernodeAddress: address, }) if err != nil { - fmt.Errorf("failed to get supernode: %w", err) + return nil, fmt.Errorf("failed to get supernode: %w", err) } return resp.Supernode, nil } +// GetParams fetches the supernode module parameters +func (m *module) GetParams(ctx context.Context) (*types.QueryParamsResponse, error) { + resp, err := m.client.Params(ctx, &types.QueryParamsRequest{}) + if err != nil { + return nil, fmt.Errorf("failed to get supernode params: %w", err) + } + + return resp, nil +} + func Exists(nodes []*types.SuperNode, snAccAddress string) bool { for _, sn := range nodes { if sn.SupernodeAccount == snAccAddress { diff --git a/pkg/lumera/modules/supernode/interface.go b/pkg/lumera/modules/supernode/interface.go index 6fa6546c..1602e86c 100644 --- a/pkg/lumera/modules/supernode/interface.go +++ b/pkg/lumera/modules/supernode/interface.go @@ -13,6 +13,7 @@ type Module interface { GetTopSuperNodesForBlock(ctx context.Context, blockHeight uint64) (*types.QueryGetTopSuperNodesForBlockResponse, error) GetSuperNode(ctx context.Context, address string) (*types.QueryGetSuperNodeResponse, error) GetSupernodeBySupernodeAddress(ctx context.Context, address string) (*types.SuperNode, error) + GetParams(ctx context.Context) (*types.QueryParamsResponse, error) } // NewModule creates a new SuperNode module client diff --git a/pkg/lumera/options.go b/pkg/lumera/options.go index c8ccacb9..d6d843f9 100644 --- a/pkg/lumera/options.go +++ b/pkg/lumera/options.go @@ -36,3 +36,10 @@ func WithKeyring(k keyring.Keyring) Option { c.keyring = k } } + +// WithKeyName sets the key name to use for signing +func WithKeyName(keyName string) Option { + return func(c *Config) { + c.KeyName = keyName + } +} diff --git a/pkg/net/credentials/alts/conn/register.go b/pkg/net/credentials/alts/conn/register.go index 24bae62e..eb43410f 100644 --- a/pkg/net/credentials/alts/conn/register.go +++ b/pkg/net/credentials/alts/conn/register.go @@ -4,6 +4,10 @@ import ( . "github.com/LumeraProtocol/supernode/pkg/net/credentials/alts/common" ) +func init() { + RegisterALTSRecordProtocols() +} + var ( // ALTS record protocol names. ALTSRecordProtocols = make([]string, 0) @@ -32,4 +36,4 @@ func RegisterALTSRecordProtocols() { func UnregisterALTSRecordProtocols() { ALTSRecordProtocols = make([]string, 0) -} \ No newline at end of file +} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 8b3d8b12..4a8c4c06 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -15,7 +15,6 @@ import ( "math" "math/big" "net" - "net/http" "os" "os/exec" "path/filepath" @@ -46,31 +45,31 @@ var ipEndpoints = []string{ // GetExternalIPAddress returns the first valid public IP obtained // from a list of providers, or an error if none work. -func GetExternalIPAddress() (string, error) { - client := &http.Client{Timeout: 4 * time.Second} +// func GetExternalIPAddress() (string, error) { +// client := &http.Client{Timeout: 4 * time.Second} - for _, url := range ipEndpoints { - req, _ := http.NewRequest(http.MethodGet, url, nil) +// for _, url := range ipEndpoints { +// req, _ := http.NewRequest(http.MethodGet, url, nil) - resp, err := client.Do(req) - if err != nil { - continue // provider down? try next - } +// resp, err := client.Do(req) +// if err != nil { +// continue // provider down? try next +// } - body, err := io.ReadAll(resp.Body) - resp.Body.Close() - if err != nil { - continue - } +// body, err := io.ReadAll(resp.Body) +// resp.Body.Close() +// if err != nil { +// continue +// } - ip := strings.TrimSpace(string(body)) - if net.ParseIP(ip) != nil { - return ip, nil - } - } +// ip := strings.TrimSpace(string(body)) +// if net.ParseIP(ip) != nil { +// return ip, nil +// } +// } - return "", errors.New("unable to determine external IP address from any provider") -} +// return "", errors.New("unable to determine external IP address from any provider") +// } var sem = semaphore.NewWeighted(maxParallelHighCompressCalls) @@ -132,6 +131,29 @@ func IsContextErr(err error) bool { return false } +// GetExternalIPAddress returns external IP address +func GetExternalIPAddress() (externalIP string, err error) { + return "localhost", nil + /* + resp, err := http.Get("https://api.ipify.org") + if err != nil { + return "", err + } + + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + if net.ParseIP(string(body)) == nil { + return "", errors.Errorf("invalid IP response from %s", "ipconf.ip") + } + + return string(body), nil */ +} + // B64Encode base64 encodes func B64Encode(in []byte) (out []byte) { out = make([]byte, base64.StdEncoding.EncodedLen(len(in))) diff --git a/sdk/action/client.go b/sdk/action/client.go index b2a5092f..060a8f2d 100644 --- a/sdk/action/client.go +++ b/sdk/action/client.go @@ -3,7 +3,6 @@ package action import ( "context" "fmt" - "os" "github.com/LumeraProtocol/supernode/sdk/config" "github.com/LumeraProtocol/supernode/sdk/event" @@ -15,7 +14,7 @@ import ( // Client defines the interface for action operations type Client interface { - StartCascade(ctx context.Context, fileHash string, actionID string, filePath string, signedData string) (string, error) + StartCascade(ctx context.Context, data []byte, actionID string) (string, error) DeleteTask(ctx context.Context, taskID string) error GetTask(ctx context.Context, taskID string) (*task.TaskEntry, bool) SubscribeToEvents(ctx context.Context, eventType event.EventType, handler event.Handler) error @@ -53,26 +52,21 @@ func NewClient(ctx context.Context, config config.Config, logger log.Logger, key } // StartCascade initiates a cascade operation -func (c *ClientImpl) StartCascade(ctx context.Context, fileHash string, actionID string, filePath string, signedData string) (string, error) { - if fileHash == "" { - c.logger.Error(ctx, "Empty file hash provided") - return "", ErrEmptyFileHash - } +func (c *ClientImpl) StartCascade(ctx context.Context, + data []byte, + actionID string, +) (string, error) { + if actionID == "" { c.logger.Error(ctx, "Empty action ID provided") return "", ErrEmptyActionID } - if filePath == "" { - c.logger.Error(ctx, "Empty file path provided") - return "", ErrEmptyFilePath - } - _, err := os.Stat(filePath) - if err != nil { - c.logger.Error(ctx, "File not found", "filePath", filePath) - return "", ErrEmptyFileNotFound + if len(data) == 0 { + c.logger.Error(ctx, "Empty data provided") + return "", ErrEmptyData } - taskID, err := c.taskManager.CreateCascadeTask(ctx, actionID, filePath) + taskID, err := c.taskManager.CreateCascadeTask(ctx, data, actionID) if err != nil { c.logger.Error(ctx, "Failed to create cascade task", "error", err) return "", fmt.Errorf("failed to create cascade task: %w", err) diff --git a/sdk/action/errors.go b/sdk/action/errors.go index b6af6969..77a017e1 100644 --- a/sdk/action/errors.go +++ b/sdk/action/errors.go @@ -6,15 +6,14 @@ import ( ) var ( - ErrEmptyFileHash = errors.New("file hash cannot be empty") - ErrEmptyActionID = errors.New("action ID cannot be empty") - ErrEmptyFilePath = errors.New("file path cannot be empty") - ErrEmptyFileNotFound = errors.New("file not found at the specified path") - ErrNoValidAction = errors.New("no action found with the specified ID") - ErrInvalidAction = errors.New("action is not in a valid state") - ErrNoSupernodes = errors.New("no valid supernodes available") - ErrTaskCreation = errors.New("failed to create task") - ErrCommunication = errors.New("communication with supernode failed") + ErrEmptyData = errors.New("data cannot be empty") + ErrEmptyActionID = errors.New("action ID cannot be empty") + ErrEmptyFileName = errors.New("file name cannot be empty") + ErrNoValidAction = errors.New("no action found with the specified ID") + ErrInvalidAction = errors.New("action is not in a valid state") + ErrNoSupernodes = errors.New("no valid supernodes available") + ErrTaskCreation = errors.New("failed to create task") + ErrCommunication = errors.New("communication with supernode failed") ) // SupernodeError represents an error related to supernode operations diff --git a/sdk/adapters/lumera/adapter.go b/sdk/adapters/lumera/adapter.go index 953cee37..266b0491 100644 --- a/sdk/adapters/lumera/adapter.go +++ b/sdk/adapters/lumera/adapter.go @@ -3,7 +3,6 @@ package lumera import ( "context" "fmt" - "strconv" "time" "github.com/LumeraProtocol/supernode/sdk/log" @@ -25,6 +24,7 @@ type ConfigParams struct { GRPCAddr string ChainID string Timeout time.Duration + KeyName string } type Adapter struct { @@ -66,6 +66,10 @@ func NewAdapter( options = append(options, lumeraclient.WithKeyring(kr)) } + if config.KeyName != "" { + options = append(options, lumeraclient.WithKeyName(config.KeyName)) + } + // Initialize the client client, err := lumeraclient.NewClient(ctx, options...) if err != nil { @@ -90,6 +94,15 @@ func (a *Adapter) GetAction(ctx context.Context, actionID string) (Action, error return Action{}, fmt.Errorf("failed to get action: %w", err) } + // Add validation + if resp == nil { + return Action{}, fmt.Errorf("received nil response for action %s", actionID) + } + + if resp.Action == nil { + return Action{}, fmt.Errorf("action %s not found", actionID) + } + action := toSdkAction(resp) a.logger.Debug(ctx, "Successfully retrieved action", "actionID", action.ID, @@ -102,7 +115,14 @@ func (a *Adapter) GetAction(ctx context.Context, actionID string) (Action, error func (a *Adapter) GetSupernodes(ctx context.Context, height int64) ([]Supernode, error) { a.logger.Debug(ctx, "Getting top supernodes for block", "height", height) - resp, err := a.client.SuperNode().GetTopSuperNodesForBlock(ctx, uint64(height)) + // Safely convert int64 to uint64 + var blockHeight uint64 + if height < 0 { + return nil, fmt.Errorf("invalid block height: %d", height) + } + blockHeight = uint64(height) + + resp, err := a.client.SuperNode().GetTopSuperNodesForBlock(ctx, blockHeight) if err != nil { a.logger.Error(ctx, "Failed to get supernodes", "height", height, "error", err) return nil, fmt.Errorf("failed to get supernodes: %w", err) @@ -113,12 +133,14 @@ func (a *Adapter) GetSupernodes(ctx context.Context, height int64) ([]Supernode, return supernodes, nil } + func toSdkAction(resp *actiontypes.QueryGetActionResponse) Action { + return Action{ ID: resp.Action.ActionID, State: ACTION_STATE(resp.Action.State.String()), - Height: int64(resp.Action.BlockHeight), - ExpirationTime: strconv.FormatInt(resp.Action.ExpirationTime, 10), + Height: resp.Action.BlockHeight, + ExpirationTime: resp.Action.ExpirationTime, } } @@ -134,10 +156,12 @@ func toSdkSupernodes(resp *sntypes.QueryGetTopSuperNodesForBlockResponse) []Supe continue } + // Check if States slice has at least one element if len(sn.States) == 0 { continue } + // Check if the first state is active if sn.States[0].State.String() != string(SUPERNODE_STATE_ACTIVE) { continue } @@ -156,9 +180,15 @@ func getLatestIP(supernode *sntypes.SuperNode) (string, error) { return "", fmt.Errorf("supernode is nil") } + // Check if the slice has elements before accessing it if len(supernode.PrevIpAddresses) == 0 { return "", fmt.Errorf("no ip history exists for the supernode") } + // Access the first element safely + if supernode.PrevIpAddresses[0] == nil { + return "", fmt.Errorf("first IP address in history is nil") + } + return supernode.PrevIpAddresses[0].Address, nil } diff --git a/sdk/adapters/lumera/types.go b/sdk/adapters/lumera/types.go index 236cb76b..429cf1f5 100644 --- a/sdk/adapters/lumera/types.go +++ b/sdk/adapters/lumera/types.go @@ -28,7 +28,7 @@ type Action struct { ID string State ACTION_STATE Height int64 - ExpirationTime string + ExpirationTime int64 } type Supernodes []Supernode diff --git a/sdk/adapters/supernodeservice/adapter.go b/sdk/adapters/supernodeservice/adapter.go index 9f51d5f5..24871fa9 100644 --- a/sdk/adapters/supernodeservice/adapter.go +++ b/sdk/adapters/supernodeservice/adapter.go @@ -3,8 +3,6 @@ package supernodeservice import ( "context" "fmt" - "io" - "os" "github.com/LumeraProtocol/supernode/sdk/log" @@ -30,64 +28,39 @@ func NewCascadeAdapter(ctx context.Context, client cascade.CascadeServiceClient, } } -func (a *cascadeAdapter) RegisterCascade(ctx context.Context, in *RegisterCascadeRequest, opts ...grpc.CallOption) (*RegisterCascadeResponse, error) { - a.logger.Debug(ctx, "RegisterCascade through adapter", "task_id", in.TaskID, "actionID", in.ActionID, "filePath", in.FilePath) - - // Open the file for reading - file, err := os.Open(in.FilePath) - if err != nil { - a.logger.Error(ctx, "Failed to open file for reading", - "error", err) - return nil, fmt.Errorf("failed to open file: %w", err) - } - defer file.Close() - - // Get file size for logging and progress tracking - fileInfo, err := file.Stat() - if err != nil { - a.logger.Error(ctx, "Failed to get file stats", - "error", err) - return nil, fmt.Errorf("failed to get file stats: %w", err) - } - - fileSize := fileInfo.Size() - a.logger.Debug(ctx, "File opened for streaming", - "fileSize", fileSize) - +func (a *cascadeAdapter) CascadeSupernodeRegister(ctx context.Context, in *CascadeSupernodeRegisterRequest, opts ...grpc.CallOption) (*CascadeSupernodeRegisterResponse, error) { // Create the client stream stream, err := a.client.Register(ctx, opts...) if err != nil { - a.logger.Error(ctx, "Failed to create upload stream", + a.logger.Error(ctx, "Failed to create register stream", "error", err) return nil, err } - // Define chunk size (could be configurable) - const chunkSize = 1024 // 1 KB - buffer := make([]byte, chunkSize) + // Define chunk size + const chunkSize = 1024 // 1 KB - // Track progress + // Keep track of how much data we've processed bytesRead := int64(0) + totalBytes := int64(len(in.Data)) chunkIndex := 0 - // Read and send file in chunks - for { - n, err := file.Read(buffer) - if err == io.EOF { - break // End of file - } - if err != nil { - a.logger.Error(ctx, "Error reading file chunk", - "chunkIndex", chunkIndex, - "error", err) - return nil, fmt.Errorf("error reading file: %w", err) + // Read and send data in chunks + for bytesRead < totalBytes { + // Determine size of the next chunk + end := bytesRead + chunkSize + if end > totalBytes { + end = totalBytes } - // Only send what was actually read + // Prepare the chunk data + chunkData := in.Data[bytesRead:end] + + // Create the chunk request chunk := &cascade.RegisterRequest{ RequestType: &cascade.RegisterRequest_Chunk{ Chunk: &cascade.DataChunk{ - Data: buffer[:n], + Data: chunkData, }, }, } @@ -97,10 +70,10 @@ func (a *cascadeAdapter) RegisterCascade(ctx context.Context, in *RegisterCascad return nil, fmt.Errorf("failed to send chunk: %w", err) } - bytesRead += int64(n) - progress := float64(bytesRead) / float64(fileSize) * 100 + bytesRead += int64(len(chunkData)) + progress := float64(bytesRead) / float64(totalBytes) * 100 - a.logger.Debug(ctx, "Sent data chunk", "chunkIndex", chunkIndex, "chunkSize", n, "progress", fmt.Sprintf("%.1f%%", progress)) + a.logger.Debug(ctx, "Sent data chunk", "chunkIndex", chunkIndex, "chunkSize", len(chunkData), "progress", fmt.Sprintf("%.1f%%", progress)) chunkIndex++ } @@ -109,30 +82,31 @@ func (a *cascadeAdapter) RegisterCascade(ctx context.Context, in *RegisterCascad metadata := &cascade.RegisterRequest{ RequestType: &cascade.RegisterRequest_Metadata{ Metadata: &cascade.Metadata{ - TaskId: in.TaskID, + TaskId: in.TaskId, ActionId: in.ActionID, }, }, } if err := stream.Send(metadata); err != nil { - a.logger.Error(ctx, "Failed to send metadata", "task_id", in.TaskID, "actionID", in.ActionID, "error", err) + a.logger.Error(ctx, "Failed to send metadata", "TaskId", in.TaskId, "ActionID", in.ActionID, "error", err) return nil, fmt.Errorf("failed to send metadata: %w", err) } + a.logger.Debug(ctx, "Sent metadata", "TaskId", in.TaskId, "ActionID", in.ActionID) + resp, err := stream.CloseAndRecv() if err != nil { - a.logger.Error(ctx, "Failed to close stream and receive response", "task_id", in.TaskID, "actionID", in.ActionID, "error", err) + a.logger.Error(ctx, "Failed to close stream and receive response", "TaskId", in.TaskId, "ActionID", in.ActionID, "error", err) return nil, fmt.Errorf("failed to receive response: %w", err) } - response := &RegisterCascadeResponse{ + response := &CascadeSupernodeRegisterResponse{ Success: resp.Success, Message: resp.Message, } - a.logger.Info(ctx, "Successfully Registered with Supernode", "task_id", in.TaskID, "actionID", in.ActionID, "fileSize", fileSize, - "success", resp.Success, "message", resp.Message) + a.logger.Info(ctx, "Successfully registered supernode data", "TaskId", in.TaskId, "ActionID", in.ActionID, "dataSize", totalBytes, "success", resp.Success, "message", resp.Message) return response, nil } diff --git a/sdk/adapters/supernodeservice/types.go b/sdk/adapters/supernodeservice/types.go index 1fb04870..cc0eb839 100644 --- a/sdk/adapters/supernodeservice/types.go +++ b/sdk/adapters/supernodeservice/types.go @@ -6,17 +6,17 @@ import ( "google.golang.org/grpc" ) -type RegisterCascadeRequest struct { +type CascadeSupernodeRegisterRequest struct { + Data []byte ActionID string - TaskID string - FilePath string + TaskId string } -type RegisterCascadeResponse struct { +type CascadeSupernodeRegisterResponse struct { Success bool Message string } type CascadeServiceClient interface { - RegisterCascade(ctx context.Context, in *RegisterCascadeRequest, opts ...grpc.CallOption) (*RegisterCascadeResponse, error) + CascadeSupernodeRegister(ctx context.Context, in *CascadeSupernodeRegisterRequest, opts ...grpc.CallOption) (*CascadeSupernodeRegisterResponse, error) } diff --git a/sdk/config/config.go b/sdk/config/config.go index 556a2dbc..2a353525 100644 --- a/sdk/config/config.go +++ b/sdk/config/config.go @@ -9,7 +9,7 @@ const ( DefaultLocalCosmosAddress = "lumera1qv3" // Example address - replace with actual DefaultChainID = "lumera-testnet" // Example chain ID - replace with actual DefaultGRPCAddr = "127.0.0.1:9090" - DefaultTimeout = 10 * time.Second + DefaultTimeout = 10 ) // AccountConfig holds peer-to-peer addresses, ports, etc. @@ -22,6 +22,7 @@ type LumeraConfig struct { GRPCAddr string // REQUIRED – e.g. "127.0.0.1:9090" ChainID string // REQUIRED – e.g. "lumera-mainnet" Timeout time.Duration // OPTIONAL – defaults to DefaultTimeout + KeyName string } type Config struct { diff --git a/sdk/net/client.go b/sdk/net/client.go index 23a8cddd..431b14e6 100644 --- a/sdk/net/client.go +++ b/sdk/net/client.go @@ -4,15 +4,14 @@ import ( "context" "github.com/LumeraProtocol/supernode/sdk/adapters/supernodeservice" - "google.golang.org/grpc" "google.golang.org/grpc/health/grpc_health_v1" ) // SupernodeClient defines the interface for communicating with supernodes type SupernodeClient interface { - //RegisterCascade uploads input data to Supernode for processing cascade request - RegisterCascade(ctx context.Context, in *supernodeservice.RegisterCascadeRequest, opts ...grpc.CallOption) (*supernodeservice.RegisterCascadeResponse, error) + // UploadInputData uploads input data for cascade processing + UploadInputData(ctx context.Context, in *supernodeservice.CascadeSupernodeRegisterRequest, opts ...grpc.CallOption) (*supernodeservice.CascadeSupernodeRegisterResponse, error) // HealthCheck performs a health check on the supernode HealthCheck(ctx context.Context) (*grpc_health_v1.HealthCheckResponse, error) diff --git a/sdk/net/impl.go b/sdk/net/impl.go index 726a4fd8..24638408 100644 --- a/sdk/net/impl.go +++ b/sdk/net/impl.go @@ -104,18 +104,16 @@ func NewSupernodeClient(ctx context.Context, logger log.Logger, keyring keyring. }, nil } -// RegisterCascade sends data to the supernode for cascade processing -func (c *supernodeClient) RegisterCascade(ctx context.Context, - in *supernodeservice.RegisterCascadeRequest, opts ...grpc.CallOption, -) (*supernodeservice.RegisterCascadeResponse, error) { +// UploadInputData sends data to the supernode for cascade processing +func (c *supernodeClient) UploadInputData(ctx context.Context, in *supernodeservice.CascadeSupernodeRegisterRequest, opts ...grpc.CallOption) (*supernodeservice.CascadeSupernodeRegisterResponse, error) { - resp, err := c.cascadeClient.RegisterCascade(ctx, in, opts...) + resp, err := c.cascadeClient.CascadeSupernodeRegister(ctx, in, opts...) if err != nil { return nil, fmt.Errorf("upload input data failed: %w", err) } c.logger.Info(ctx, "Input data uploaded successfully", - "actionID", in.ActionID, "filePath", in.FilePath) + "actionID", in.ActionID, "taskId", in.TaskId) return resp, nil } diff --git a/sdk/task/cascade.go b/sdk/task/cascade.go index 01f4a674..fc98f363 100644 --- a/sdk/task/cascade.go +++ b/sdk/task/cascade.go @@ -23,14 +23,20 @@ const ( type CascadeTask struct { BaseTask - FilePath string + data []byte + actionId string } // NewCascadeTask creates a new CascadeTask using a BaseTask plus cascade-specific parameters -func NewCascadeTask(base BaseTask, filePath string) *CascadeTask { +func NewCascadeTask( + base BaseTask, + data []byte, + actionId string, + +) *CascadeTask { return &CascadeTask{ BaseTask: base, - FilePath: filePath, + data: data, } } @@ -145,10 +151,10 @@ func (t *CascadeTask) registerWithSupernodes(ctx context.Context, supernodes lum } clientFactory := net.NewClientFactory(ctx, t.logger, t.keyring, factoryCfg) - req := &supernodeservice.RegisterCascadeRequest{ + req := &supernodeservice.CascadeSupernodeRegisterRequest{ + Data: t.data, ActionID: t.ActionID, - FilePath: t.FilePath, - TaskID: t.TaskID, + TaskId: t.TaskID, } var lastErr error @@ -162,8 +168,7 @@ func (t *CascadeTask) registerWithSupernodes(ctx context.Context, supernodes lum return fmt.Errorf("failed to upload to all supernodes: %w", lastErr) } -func (t *CascadeTask) attemptRegistration(ctx context.Context, index int, sn lumera.Supernode, - factory *net.ClientFactory, req *supernodeservice.RegisterCascadeRequest) error { +func (t *CascadeTask) attemptRegistration(ctx context.Context, index int, sn lumera.Supernode, factory *net.ClientFactory, req *supernodeservice.CascadeSupernodeRegisterRequest) error { t.logEvent(ctx, event.TaskProgressRegistrationInProgress, "attempting registration with supernode", map[string]interface{}{ "supernode": sn.GrpcEndpoint, "sn-address": sn.CosmosAddress, "iteration": index + 1}) diff --git a/sdk/task/manager.go b/sdk/task/manager.go index 32e025f8..be7c0fba 100644 --- a/sdk/task/manager.go +++ b/sdk/task/manager.go @@ -17,7 +17,7 @@ const MAX_EVENT_WORKERS = 100 // Manager handles task creation and management type Manager interface { - CreateCascadeTask(ctx context.Context, actionID, filePath string) (string, error) + CreateCascadeTask(ctx context.Context, data []byte, actionID string) (string, error) GetTask(ctx context.Context, taskID string) (*TaskEntry, bool) DeleteTask(ctx context.Context, taskID string) error SubscribeToEvents(ctx context.Context, eventType event.EventType, handler event.Handler) @@ -56,10 +56,15 @@ func NewManager( GRPCAddr: config.Lumera.GRPCAddr, ChainID: config.Lumera.ChainID, Timeout: config.Lumera.Timeout, + KeyName: config.Lumera.KeyName, }, kr, logger) + if err != nil { + panic(fmt.Sprintf("Failed to create Lumera client: %v", err)) + } + taskCache, err := NewTaskCache(ctx, logger) if err != nil { logger.Error(ctx, "Failed to create task cache", "error", err) @@ -77,8 +82,11 @@ func NewManager( } // CreateCascadeTask creates and starts a Cascade task using the new pattern -func (m *ManagerImpl) CreateCascadeTask(ctx context.Context, actionID string, filePath string) (string, error) { - m.logger.Info(ctx, "Creating cascade task", "filePath", filePath, "actionID", actionID) +func (m *ManagerImpl) CreateCascadeTask( + ctx context.Context, + data []byte, + actionID string, +) (string, error) { // Generate task ID // slice this to 8 bytes @@ -97,7 +105,7 @@ func (m *ManagerImpl) CreateCascadeTask(ctx context.Context, actionID string, fi logger: m.logger, } // Create cascade-specific task - task := NewCascadeTask(baseTask, filePath) + task := NewCascadeTask(baseTask, data, actionID) // Store task in cache m.taskCache.Set(ctx, taskID, task, TaskTypeCascade) diff --git a/sdk/task/task.go b/sdk/task/task.go index 9259658a..060eb620 100644 --- a/sdk/task/task.go +++ b/sdk/task/task.go @@ -29,7 +29,6 @@ const ( ) // EventCallback is a function that processes events from tasks -// Now includes context parameter for proper context propagation type EventCallback func(ctx context.Context, e event.Event) // Task is the interface that all task types must implement diff --git a/supernode/cmd/start.go b/supernode/cmd/start.go index 87c9eb74..d4b2446f 100644 --- a/supernode/cmd/start.go +++ b/supernode/cmd/start.go @@ -60,7 +60,7 @@ The supernode will connect to the Lumera network and begin participating in the } // Initialize Lumera client - lumeraClient, err := initLumeraClient(ctx, appConfig) + lumeraClient, err := initLumeraClient(ctx, appConfig, kr) if err != nil { return fmt.Errorf("failed to initialize Lumera client: %w", err) } diff --git a/supernode/cmd/supernode.go b/supernode/cmd/supernode.go index b188bee5..e9c6e75f 100644 --- a/supernode/cmd/supernode.go +++ b/supernode/cmd/supernode.go @@ -127,7 +127,7 @@ func (s *Supernode) Stop(ctx context.Context) error { } // initLumeraClient initializes the Lumera client based on configuration -func initLumeraClient(ctx context.Context, config *config.Config) (lumera.Client, error) { +func initLumeraClient(ctx context.Context, config *config.Config, kr keyring.Keyring) (lumera.Client, error) { if config == nil { return nil, fmt.Errorf("config is nil") } @@ -143,6 +143,8 @@ func initLumeraClient(ctx context.Context, config *config.Config) (lumera.Client lumera.WithGRPCAddr(config.LumeraClientConfig.GRPCAddr), lumera.WithChainID(config.LumeraClientConfig.ChainID), lumera.WithTimeout(time.Duration(config.LumeraClientConfig.Timeout)*time.Second), + lumera.WithKeyring(kr), + lumera.WithKeyName(config.SupernodeConfig.KeyName), ) } diff --git a/supernode/config.test-2.yml b/supernode/config.test-2.yml index 08bdabdd..eadea42f 100644 --- a/supernode/config.test-2.yml +++ b/supernode/config.test-2.yml @@ -2,7 +2,7 @@ # Supernode Configuration supernode: key_name: "testkey2" - identity: "lumera1ae37km54w88f783cktmpyd3fny0ycdn69ftt6e" + identity: "lumera1cf0ms9ttgdvz6zwlqfty4tjcawhuaq69p40w0c" ip_address: "0.0.0.0" port: 4446 diff --git a/tests/system/cli.go b/tests/system/cli.go index de35b5a1..351156c1 100644 --- a/tests/system/cli.go +++ b/tests/system/cli.go @@ -290,6 +290,15 @@ func (c LumeradCli) GetKeyAddr(name string) string { const defaultSrcAddr = "node0" +func (c LumeradCli) FundAddressWithNode(destAddr, amount string, nodeAddr string) string { + require.NotEmpty(c.t, destAddr) + require.NotEmpty(c.t, amount) + cmd := []string{"tx", "bank", "send", nodeAddr, destAddr, amount} + rsp := c.CustomCommand(cmd...) + RequireTxSuccess(c.t, rsp) + return rsp +} + // FundAddress sends the token amount to the destination address func (c LumeradCli) FundAddress(destAddr, amount string) string { require.NotEmpty(c.t, destAddr) diff --git a/tests/system/e2e_cascade_test.go b/tests/system/e2e_cascade_test.go index 688564a5..c7054d34 100644 --- a/tests/system/e2e_cascade_test.go +++ b/tests/system/e2e_cascade_test.go @@ -1,8 +1,8 @@ package system import ( + "bytes" "context" - "crypto/sha3" "encoding/base64" "encoding/json" "fmt" @@ -14,9 +14,9 @@ import ( "testing" "time" + "github.com/LumeraProtocol/supernode/pkg/codec" "github.com/LumeraProtocol/supernode/pkg/keyring" - "github.com/LumeraProtocol/supernode/pkg/lumera" - "github.com/LumeraProtocol/supernode/pkg/raptorq" + "lukechampine.com/blake3" "github.com/LumeraProtocol/supernode/sdk/action" "github.com/LumeraProtocol/supernode/sdk/event" @@ -79,7 +79,7 @@ func TestCascadeE2E(t *testing.T) { t.Log("Registering multiple supernodes to process requests") // Helper function to register a supernode - registerSupernode := func(nodeKey string, port string) { + registerSupernode := func(nodeKey string, port string, addr string) { // Get account and validator addresses for registration accountAddr := cli.GetKeyAddr(nodeKey) valAddrOutput := cli.Keys("keys", "show", nodeKey, "--bech", "val", "-a") @@ -93,7 +93,7 @@ func TestCascadeE2E(t *testing.T) { valAddr, // validator address "localhost:" + port, // IP address with unique port "1.0.0", // version - accountAddr, // supernode account + addr, // supernode account "--from", nodeKey, } @@ -105,20 +105,19 @@ func TestCascadeE2E(t *testing.T) { } // Register three supernodes with different ports - registerSupernode("node0", "4444") - registerSupernode("node1", "4446") - registerSupernode("node2", "4448") + registerSupernode("node0", "4444", "lumera1em87kgrvgttrkvuamtetyaagjrhnu3vjy44at4") + registerSupernode("node1", "4446", "lumera1cf0ms9ttgdvz6zwlqfty4tjcawhuaq69p40w0c") + registerSupernode("node2", "4448", "lumera1cjyc4ruq739e2lakuhargejjkr0q5vg6x3d7kp") + cli.FundAddress("lumera1em87kgrvgttrkvuamtetyaagjrhnu3vjy44at4", "100000ulume") + cli.FundAddressWithNode("lumera1cf0ms9ttgdvz6zwlqfty4tjcawhuaq69p40w0c", "100000ulume", "node1") + cli.FundAddressWithNode("lumera1cjyc4ruq739e2lakuhargejjkr0q5vg6x3d7kp", "100000ulume", "node2") t.Log("Successfully registered three supernodes") // --------------------------------------- // Step 1: Start all required services // --------------------------------------- - // // Start the RaptorQ service for encoding/decoding with fountain codes - rq_cmd := StartRQService(t) - defer StopRQService(rq_cmd) // Ensure service is stopped after test - // Start the supernode service to process cascade requests cmds := StartAllSupernodes(t) defer StopAllSupernodes(cmds) // Ensure service is stopped after test @@ -161,7 +160,7 @@ func TestCascadeE2E(t *testing.T) { keplrKeyring, err := keyring.InitKeyring("memory", "") require.NoError(t, err, "Failed to initialize in-memory keyring") - // Add the same key to the in-memory keyring for consistency + // Add the same key to the in-memory keyring record, err := keyring.RecoverAccountFromMnemonic(keplrKeyring, testKeyName, testMnemonic) require.NoError(t, err, "Failed to recover account from mnemonic in local keyring") @@ -178,55 +177,26 @@ func TestCascadeE2E(t *testing.T) { require.Contains(t, balanceOutput, fundAmount[:len(fundAmount)-5], "Account should have the funded amount") - // --------------------------------------- - // Step 3: Set up RaptorQ service and clients - // --------------------------------------- - t.Log("Step 3: Setting up RaptorQ service and initializing clients") - - // Create directory for RaptorQ files if it doesn't exist - err = os.MkdirAll(raptorQFilesDir, 0755) - require.NoError(t, err, "Failed to create RaptorQ files directory") - - // Create context with timeout for service operations - ctx, cancel := context.WithTimeout(context.Background(), 1200*time.Second) - defer cancel() - - // Initialize RaptorQ configuration with host, port and file directory - rqConfig := raptorq.NewConfig() - rqConfig.Host = raptorQHost - rqConfig.Port = raptorQPort - rqConfig.RqFilesDir = raptorQFilesDir - - // Create RaptorQ client and establish connection - client := raptorq.NewClient() - address := fmt.Sprintf("%s:%d", raptorQHost, raptorQPort) - t.Logf("Connecting to RaptorQ server at %s", address) - connection, err := client.Connect(ctx, address) - require.NoError(t, err, "Failed to connect to RaptorQ server") - defer connection.Close() - // Initialize Lumera blockchain client for interactions t.Log("Initializing Lumera client") - lumeraClient, err := lumera.NewClient( - ctx, - lumera.WithGRPCAddr(lumeraGRPCAddr), - lumera.WithChainID(lumeraChainID), - ) + // require.NoError(t, err, "Failed to initialize Lumera client") // --------------------------------------- - // Step 4: Create and prepare test file + // Step 4: Create and prepare layout file for RaptorQ encoding // --------------------------------------- t.Log("Step 4: Creating test file for RaptorQ encoding") // Create a test file with sample data in a temporary directory - testFileName := filepath.Join(t.TempDir(), "testfile.data") + + testFileName := "testfile.data" + testFileFullpath := filepath.Join(t.TempDir(), testFileName) testData := []byte("This is test data for RaptorQ encoding in the Lumera network") - err = os.WriteFile(testFileName, testData, 0644) + err = os.WriteFile(testFileFullpath, testData, 0644) require.NoError(t, err, "Failed to write test file") // Read the file into memory for processing - file, err := os.Open(testFileName) + file, err := os.Open(testFileFullpath) require.NoError(t, err, "Failed to open test file") defer file.Close() @@ -238,85 +208,47 @@ func TestCascadeE2E(t *testing.T) { require.NoError(t, err, "Failed to read file contents") t.Logf("Read %d bytes from test file", len(data)) - // Calculate SHA3-256 hash of the file data for identification - // This hash is used in metadata and for CASCADE operation - hash := sha3.New256() - hash.Write(data) - hashBytes := hash.Sum(nil) - hashHex := fmt.Sprintf("%X", hashBytes) - t.Logf("File hash: %s", hashHex) - time.Sleep(1 * time.Minute) - // --------------------------------------- - // Step 5: Sign data and generate RaptorQ identifiers - // --------------------------------------- - t.Log("Step 5: Signing data and generating RaptorQ identifiers") - - // Sign the original file data for verification purposes - // This signature proves the data came from this account - signedData, err := keyring.SignBytes(keplrKeyring, testKeyName, data) - base64EncodedData := base64.StdEncoding.EncodeToString(signedData) - require.NoError(t, err, "Failed to sign data") - t.Logf("Signed data length: %d bytes", len(signedData)) - - // Initialize RaptorQ client for fountain code processing - rq := connection.RaptorQ(rqConfig, lumeraClient) - - // Get current block hash or use file hash as fallback - // Block hash adds randomness to the fountain code generation - // blockHash := hashHex // Default to file hash - // latestBlock, err := lumeraClient.Node().GetLatestBlock(ctx) - // if err == nil && latestBlock != nil && len(latestBlock.BlockId.Hash) > 0 { - // blockHash = fmt.Sprintf("%X", latestBlock.BlockId.Hash) - // } - // t.Logf("Using block hash: %s", blockHash) - - t.Log("Generating RQ identifiers") - genRqIdsResp, err := rq.GenRQIdentifiersFiles(ctx, raptorq.GenRQIdentifiersFilesRequest{ - - RqMax: 50, - Data: data, - CreatorSNAddress: localAddr.String(), - SignedData: base64EncodedData, - }) - require.NoError(t, err, "Failed to generate RQ identifiers") + rqCodec := codec.NewRaptorQCodec(raptorQFilesDir) - t.Logf("RQ identifiers generated successfully with RQ_IDs_IC: %d", genRqIdsResp.RQIDsIc) + ctx := context.Background() + encodeRes, err := rqCodec.Encode(ctx, codec.EncodeRequest{ + Data: data, + TaskID: "1", + }) - // --------------------------------------- - // Step 6: Sign the RQ IDs file for verification - // --------------------------------------- - t.Log("Step 6: Signing the RQ IDs file for the action request") + metadataFile := encodeRes.Metadata - // Base64 encode the RQIDsFile for consistent transmission - // IMPORTANT: We sign the encoded version, not the raw bytes - rqIdsFileBase64 := base64.StdEncoding.EncodeToString(genRqIdsResp.RQIDsFile) - t.Logf("Base64 encoded RQ IDs file length: %d", len(rqIdsFileBase64)) + // Marshal metadata to JSON and convert to bytes + me, err := json.Marshal(metadataFile) + require.NoError(t, err, "Failed to marshal metadata to JSON") - // Sign the Base64-encoded RQ IDs file - // This critical step creates a signature that proves ownership - rqIdsSignature, err := keyring.SignBytes(keplrKeyring, testKeyName, []byte(rqIdsFileBase64)) - require.NoError(t, err, "Failed to sign Base64-encoded RQIDsFile") + // regular + regularbase64EncodedData := base64.StdEncoding.EncodeToString(me) + t.Logf("Base64 encoded RQ IDs file length: %d", len(regularbase64EncodedData)) - // Encode the signature itself to base64 for consistent format - rqIdsSignatureBase64 := base64.StdEncoding.EncodeToString(rqIdsSignature) + //signed + signedMetaData, err := keyring.SignBytes(keplrKeyring, testKeyName, me) + signedbase64EncodedData := base64.StdEncoding.EncodeToString(signedMetaData) + t.Logf("Base64 signed RQ IDs file length: %d", len(signedbase64EncodedData)) // Format according to expected verification pattern: Base64(rq_ids).signature - // This format allows verification of both the data and the signature - signatureFormat := fmt.Sprintf("%s.%s", rqIdsFileBase64, rqIdsSignatureBase64) + + signatureFormat := fmt.Sprintf("%s.%s", regularbase64EncodedData, signedbase64EncodedData) t.Logf("Signature format prepared with length: %d bytes", len(signatureFormat)) - // --------------------------------------- - // Step 7: Create metadata and submit action request + // Data hash with blake3 + hash, err := Blake3Hash(data) + require.NoError(t, err, "Failed to compute Blake3 hash") // --------------------------------------- t.Log("Step 7: Creating metadata and submitting action request") // Create CascadeMetadata struct with all required fields // This structured approach ensures all required fields are included cascadeMetadata := types.CascadeMetadata{ - DataHash: hashHex, // Hash of the original file - FileName: filepath.Base(testFileName), // Original filename - RqIdsIc: uint64(genRqIdsResp.RQIDsIc), // Count of RQ identifiers - Signatures: signatureFormat, // Combined signature format + DataHash: string(hash), // Hash of the original file + FileName: filepath.Base(testFileFullpath), // Original filename + RqIdsIc: uint64(121), // Count of RQ identifiers + Signatures: signatureFormat, // Combined signature format } // Marshal the struct to JSON for the blockchain transaction @@ -392,23 +324,20 @@ func TestCascadeE2E(t *testing.T) { // Set up action client configuration // This defines how to connect to network services + + accConfig := sdkconfig.AccountConfig{ + LocalCosmosAddress: recoveredAddress, + } + + lumraConfig := sdkconfig.LumeraConfig{ + GRPCAddr: lumeraGRPCAddr, + ChainID: lumeraChainID, + Timeout: 300, // 30 seconds timeout + KeyName: testKeyName, + } actionConfig := sdkconfig.Config{ - Network: struct { - DefaultSupernodePort int - LocalCosmosAddress string - }{ - DefaultSupernodePort: 4444, // Default supernode gRPC port - LocalCosmosAddress: recoveredAddress, // Account address - }, - Lumera: struct { - GRPCAddr string - ChainID string - Timeout int - }{ - GRPCAddr: lumeraGRPCAddr, - ChainID: lumeraChainID, - Timeout: 300, // 30 seconds timeout - }, + Account: accConfig, + Lumera: lumraConfig, } // Initialize action client for cascade operations @@ -421,18 +350,13 @@ func TestCascadeE2E(t *testing.T) { require.NoError(t, err, "Failed to create action client") // Start cascade operation with all required parameters - // INPUTS: - // - hashHex: File hash for identification - // - actionID: The blockchain action ID - // - testFileName: Path to the original file - // - signedData: Proof of data ownership + t.Logf("Starting cascade operation with action ID: %s", actionID) taskID, err := actionClient.StartCascade( ctx, - hashHex, // File hash - actionID, // Action ID from the events - testFileName, // Path to the test file - base64EncodedData, // Signed data + data, // data []byte + actionID, // Action ID from the transaction + ) require.NoError(t, err, "Failed to start cascade operation") require.NotEmpty(t, taskID, "Task ID should not be empty") @@ -499,6 +423,24 @@ func TestCascadeE2E(t *testing.T) { } } } + + time.Sleep(10 * time.Minute) // Wait for supernode processing require.NotEmpty(t, successfulSupernode, "Should have a successful supernode in events") t.Logf("Cascade successfully processed by supernode: %s", successfulSupernode) } + +// lumeraClient, err := lumera.NewClient( +// ctx, +// lumera.WithGRPCAddr(lumeraGRPCAddr), +// lumera.WithChainID(lumeraChainID), +// lumera.WithKeyring(keplrKeyring), +// lumera.WithKeyName(testKeyName), +// ) + +func Blake3Hash(msg []byte) ([]byte, error) { + hasher := blake3.New(32, nil) + if _, err := io.Copy(hasher, bytes.NewReader(msg)); err != nil { + return nil, err + } + return hasher.Sum(nil), nil +} diff --git a/tests/system/go.mod b/tests/system/go.mod index 35cdb808..6f6c0cd4 100644 --- a/tests/system/go.mod +++ b/tests/system/go.mod @@ -35,6 +35,7 @@ require ( github.com/tidwall/gjson v1.14.2 github.com/tidwall/sjson v1.2.5 golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 + lukechampine.com/blake3 v1.4.0 ) require ( @@ -52,6 +53,7 @@ require ( github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.5 // indirect github.com/LumeraProtocol/lumera v0.4.3 // indirect + github.com/LumeraProtocol/rq-go v0.2.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect @@ -117,9 +119,8 @@ require ( github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/jmoiron/sqlx v1.4.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect @@ -127,13 +128,10 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-sqlite3 v1.14.24 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect diff --git a/tests/system/go.sum b/tests/system/go.sum index be649589..1974a409 100644 --- a/tests/system/go.sum +++ b/tests/system/go.sum @@ -63,6 +63,8 @@ github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwS github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/LumeraProtocol/lumera v0.4.3 h1:q/FuT+JOLIpYdlunczRUr6K85r9Sn0lKvGltSrj4r6s= github.com/LumeraProtocol/lumera v0.4.3/go.mod h1:MRqVY+f8edEBkDvpr4z2nJpglp3Qj1OUvjeWvrvIUSM= +github.com/LumeraProtocol/rq-go v0.2.1 h1:8B3UzRChLsGMmvZ+UVbJsJj6JZzL9P9iYxbdUwGsQI4= +github.com/LumeraProtocol/rq-go v0.2.1/go.mod h1:APnKCZRh1Es2Vtrd2w4kCLgAyaL5Bqrkz/BURoRJ+O8= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -292,8 +294,6 @@ github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXS github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= -github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= @@ -478,8 +478,6 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= -github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= -github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -500,6 +498,8 @@ github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -541,9 +541,6 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= -github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= @@ -1106,6 +1103,8 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w= +lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0= lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= diff --git a/tests/system/main_test.go b/tests/system/main_test.go index 14ea2e8c..67c97efa 100644 --- a/tests/system/main_test.go +++ b/tests/system/main_test.go @@ -1,5 +1,3 @@ -//go:build system_test - package system import ( diff --git a/tests/system/rq-utils.go b/tests/system/rq-utils.go index e20f0755..4fa14695 100644 --- a/tests/system/rq-utils.go +++ b/tests/system/rq-utils.go @@ -1,5 +1,3 @@ -//go:build system_test - package system import (