code.vegaprotocol.io/vega@v0.79.0/wallet/api/admin_send_raw_transaction.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package api 17 18 import ( 19 "context" 20 "encoding/base64" 21 "fmt" 22 "time" 23 24 "code.vegaprotocol.io/vega/libs/jsonrpc" 25 "code.vegaprotocol.io/vega/libs/proto" 26 apipb "code.vegaprotocol.io/vega/protos/vega/api/v1" 27 commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" 28 29 "github.com/mitchellh/mapstructure" 30 ) 31 32 type AdminSendRawTransactionParams struct { 33 Network string `json:"network"` 34 NodeAddress string `json:"nodeAddress"` 35 Retries uint64 `json:"retries"` 36 MaximumRequestDuration time.Duration `json:"maximumRequestDuration"` 37 SendingMode string `json:"sendingMode"` 38 EncodedTransaction string `json:"encodedTransaction"` 39 } 40 41 type ParsedAdminSendRawTransactionParams struct { 42 Network string 43 NodeAddress string 44 Retries uint64 45 MaximumRequestDuration time.Duration 46 SendingMode apipb.SubmitTransactionRequest_Type 47 RawTransaction string 48 } 49 50 type AdminSendRawTransactionResult struct { 51 ReceivedAt time.Time `json:"receivedAt"` 52 SentAt time.Time `json:"sentAt"` 53 TransactionHash string `json:"transactionHash"` 54 Transaction *commandspb.Transaction `json:"transaction"` 55 Node AdminSendRawTransactionNodeResult `json:"node"` 56 } 57 58 type AdminSendRawTransactionNodeResult struct { 59 Host string `json:"host"` 60 } 61 62 type AdminSendRawTransaction struct { 63 networkStore NetworkStore 64 nodeSelectorBuilder NodeSelectorBuilder 65 } 66 67 func (h *AdminSendRawTransaction) Handle(ctx context.Context, rawParams jsonrpc.Params) (jsonrpc.Result, *jsonrpc.ErrorDetails) { 68 receivedAt := time.Now() 69 70 params, err := validateAdminSendRawTransactionParams(rawParams) 71 if err != nil { 72 return nil, InvalidParams(err) 73 } 74 75 tx := &commandspb.Transaction{} 76 if err := proto.Unmarshal([]byte(params.RawTransaction), tx); err != nil { 77 return nil, InvalidParams(ErrRawTransactionIsNotValidVegaTransaction) 78 } 79 80 hosts := []string{params.NodeAddress} 81 if len(params.Network) != 0 { 82 exists, err := h.networkStore.NetworkExists(params.Network) 83 if err != nil { 84 return nil, InternalError(fmt.Errorf("could not determine if the network exists: %w", err)) 85 } else if !exists { 86 return nil, InvalidParams(ErrNetworkDoesNotExist) 87 } 88 89 n, err := h.networkStore.GetNetwork(params.Network) 90 if err != nil { 91 return nil, InternalError(fmt.Errorf("could not retrieve the network configuration: %w", err)) 92 } 93 94 if err := n.EnsureCanConnectGRPCNode(); err != nil { 95 return nil, InternalError(ErrNetworkConfigurationDoesNotHaveGRPCNodes) 96 } 97 hosts = n.API.GRPC.Hosts 98 } 99 100 nodeSelector, err := h.nodeSelectorBuilder(hosts, params.Retries, params.MaximumRequestDuration) 101 if err != nil { 102 return nil, InternalError(fmt.Errorf("could not initialize the node selector: %w", err)) 103 } 104 105 currentNode, err := nodeSelector.Node(ctx, noNodeSelectionReporting) 106 if err != nil { 107 return nil, NodeCommunicationError(ErrNoHealthyNodeAvailable) 108 } 109 110 sentAt := time.Now() 111 txHash, err := currentNode.SendTransaction(ctx, tx, params.SendingMode) 112 if err != nil { 113 return nil, NetworkErrorFromTransactionError(err) 114 } 115 116 return AdminSendRawTransactionResult{ 117 ReceivedAt: receivedAt, 118 SentAt: sentAt, 119 TransactionHash: txHash, 120 Transaction: tx, 121 Node: AdminSendRawTransactionNodeResult{ 122 Host: currentNode.Host(), 123 }, 124 }, nil 125 } 126 127 func NewAdminSendRawTransaction(networkStore NetworkStore, nodeSelectorBuilder NodeSelectorBuilder) *AdminSendRawTransaction { 128 return &AdminSendRawTransaction{ 129 networkStore: networkStore, 130 nodeSelectorBuilder: nodeSelectorBuilder, 131 } 132 } 133 134 func validateAdminSendRawTransactionParams(rawParams jsonrpc.Params) (ParsedAdminSendRawTransactionParams, error) { 135 if rawParams == nil { 136 return ParsedAdminSendRawTransactionParams{}, ErrParamsRequired 137 } 138 139 params := AdminSendRawTransactionParams{} 140 if err := mapstructure.Decode(rawParams, ¶ms); err != nil { 141 return ParsedAdminSendRawTransactionParams{}, ErrParamsDoNotMatch 142 } 143 144 if params.Network == "" && params.NodeAddress == "" { 145 return ParsedAdminSendRawTransactionParams{}, ErrNetworkOrNodeAddressIsRequired 146 } 147 148 if params.Network != "" && params.NodeAddress != "" { 149 return ParsedAdminSendRawTransactionParams{}, ErrSpecifyingNetworkAndNodeAddressIsNotSupported 150 } 151 152 if params.SendingMode == "" { 153 return ParsedAdminSendRawTransactionParams{}, ErrSendingModeIsRequired 154 } 155 156 isValidSendingMode := false 157 var sendingMode apipb.SubmitTransactionRequest_Type 158 for tp, sm := range apipb.SubmitTransactionRequest_Type_value { 159 if tp == params.SendingMode { 160 isValidSendingMode = true 161 sendingMode = apipb.SubmitTransactionRequest_Type(sm) 162 } 163 } 164 if !isValidSendingMode { 165 return ParsedAdminSendRawTransactionParams{}, fmt.Errorf("the sending mode %q is not a valid one", params.SendingMode) 166 } 167 168 if sendingMode == apipb.SubmitTransactionRequest_TYPE_UNSPECIFIED { 169 return ParsedAdminSendRawTransactionParams{}, ErrSendingModeCannotBeTypeUnspecified 170 } 171 172 if params.EncodedTransaction == "" { 173 return ParsedAdminSendRawTransactionParams{}, ErrEncodedTransactionIsRequired 174 } 175 176 tx, err := base64.StdEncoding.DecodeString(params.EncodedTransaction) 177 if err != nil { 178 return ParsedAdminSendRawTransactionParams{}, ErrEncodedTransactionIsNotValidBase64String 179 } 180 181 return ParsedAdminSendRawTransactionParams{ 182 Network: params.Network, 183 NodeAddress: params.NodeAddress, 184 RawTransaction: string(tx), 185 SendingMode: sendingMode, 186 Retries: params.Retries, 187 MaximumRequestDuration: params.MaximumRequestDuration, 188 }, nil 189 }