github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/transaction_receipt_query.go (about) 1 package hedera 2 3 /*- 4 * 5 * Hedera Go SDK 6 * 7 * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 */ 22 23 import ( 24 "time" 25 26 "github.com/hashgraph/hedera-protobufs-go/services" 27 ) 28 29 // TransactionReceiptQuery 30 // Get the receipt of a transaction, given its transaction ID. Once a transaction reaches consensus, 31 // then information about whether it succeeded or failed will be available until the end of the 32 // receipt period. Before and after the receipt period, and for a transaction that was never 33 // submitted, the receipt is unknown. This query is free (the payment field is left empty). No 34 // State proof is available for this response 35 type TransactionReceiptQuery struct { 36 Query 37 transactionID *TransactionID 38 childReceipts *bool 39 duplicates *bool 40 } 41 42 // NewTransactionReceiptQuery creates TransactionReceiptQuery which 43 // gets the receipt of a transaction, given its transaction ID. Once a transaction reaches consensus, 44 // then information about whether it succeeded or failed will be available until the end of the 45 // receipt period. Before and after the receipt period, and for a transaction that was never 46 // submitted, the receipt is unknown. This query is free (the payment field is left empty). No 47 // State proof is available for this response 48 func NewTransactionReceiptQuery() *TransactionReceiptQuery { 49 header := services.QueryHeader{} 50 return &TransactionReceiptQuery{ 51 Query: _NewQuery(false, &header), 52 } 53 } 54 55 // When execution is attempted, a single attempt will timeout when this deadline is reached. (The SDK may subsequently retry the execution.) 56 func (q *TransactionReceiptQuery) SetGrpcDeadline(deadline *time.Duration) *TransactionReceiptQuery { 57 q.Query.SetGrpcDeadline(deadline) 58 return q 59 } 60 61 // SetIncludeChildren Sets whether the response should include the receipts of any child transactions spawned by the 62 // top-level transaction with the given transactionID. 63 func (q *TransactionReceiptQuery) SetIncludeChildren(includeChildReceipts bool) *TransactionReceiptQuery { 64 q.childReceipts = &includeChildReceipts 65 return q 66 } 67 68 // GetIncludeChildren returns whether the response should include the receipts of any child transactions spawned by the 69 // top-level transaction with the given transactionID. 70 func (q *TransactionReceiptQuery) GetIncludeChildren() bool { 71 if q.childReceipts != nil { 72 return *q.childReceipts 73 } 74 75 return false 76 } 77 78 // SetIncludeDuplicates Sets whether receipts of processing duplicate transactions should be returned along with the 79 // receipt of processing the first consensus transaction with the given id whose status was 80 // neither INVALID_NODE_ACCOUNT nor INVALID_PAYER_SIGNATURE; or, if no 81 // such receipt exists, the receipt of processing the first transaction to reach consensus with 82 // the given transaction id. 83 func (q *TransactionReceiptQuery) SetIncludeDuplicates(includeDuplicates bool) *TransactionReceiptQuery { 84 q.duplicates = &includeDuplicates 85 return q 86 } 87 88 // GetIncludeDuplicates returns whether receipts of processing duplicate transactions should be returned along with the 89 // receipt of processing the first consensus transaction with the given id 90 func (q *TransactionReceiptQuery) GetIncludeDuplicates() bool { 91 if q.duplicates != nil { 92 return *q.duplicates 93 } 94 95 return false 96 } 97 98 func (q *TransactionReceiptQuery) GetCost(client *Client) (Hbar, error) { 99 return q.Query.getCost(client, q) 100 } 101 102 // Execute executes the Query with the provided client 103 func (q *TransactionReceiptQuery) Execute(client *Client) (TransactionReceipt, error) { 104 resp, err := q.Query.execute(client, q) 105 106 if err, ok := err.(ErrHederaPreCheckStatus); ok { 107 if resp.GetTransactionGetReceipt() != nil { 108 return _TransactionReceiptFromProtobuf(resp.GetTransactionGetReceipt(), q.transactionID), err 109 } 110 // Manually add the receipt status, because an empty receipt has no status and no status defaults to 0, which means success 111 return TransactionReceipt{Status: err.Status}, err 112 } 113 114 return _TransactionReceiptFromProtobuf(resp.GetTransactionGetReceipt(), q.transactionID), nil 115 } 116 117 // SetTransactionID sets the TransactionID for which the receipt is being requested. 118 func (q *TransactionReceiptQuery) SetTransactionID(transactionID TransactionID) *TransactionReceiptQuery { 119 q.transactionID = &transactionID 120 return q 121 } 122 123 // GetTransactionID returns the TransactionID for which the receipt is being requested. 124 func (q *TransactionReceiptQuery) GetTransactionID() TransactionID { 125 if q.transactionID == nil { 126 return TransactionID{} 127 } 128 129 return *q.transactionID 130 } 131 132 // SetNodeAccountIDs sets the _Node AccountID for this TransactionReceiptQuery. 133 func (q *TransactionReceiptQuery) SetNodeAccountIDs(accountID []AccountID) *TransactionReceiptQuery { 134 q.Query.SetNodeAccountIDs(accountID) 135 return q 136 } 137 138 // SetQueryPayment sets the Hbar payment to pay the _Node a fee for handling this query 139 func (q *TransactionReceiptQuery) SetQueryPayment(queryPayment Hbar) *TransactionReceiptQuery { 140 q.Query.SetQueryPayment(queryPayment) 141 return q 142 } 143 144 // SetMaxQueryPayment sets the maximum payment allowed for this Query. 145 func (q *TransactionReceiptQuery) SetMaxQueryPayment(queryMaxPayment Hbar) *TransactionReceiptQuery { 146 q.Query.SetMaxQueryPayment(queryMaxPayment) 147 return q 148 } 149 150 // SetMaxRetry sets the max number of errors before execution will fail. 151 func (q *TransactionReceiptQuery) SetMaxRetry(count int) *TransactionReceiptQuery { 152 q.Query.SetMaxRetry(count) 153 return q 154 } 155 156 // SetMaxBackoff The maximum amount of time to wait between retries. 157 // Every retry attempt will increase the wait time exponentially until it reaches this time. 158 func (q *TransactionReceiptQuery) SetMaxBackoff(max time.Duration) *TransactionReceiptQuery { 159 q.Query.SetMaxBackoff(max) 160 return q 161 } 162 163 // SetMinBackoff sets the minimum amount of time to wait between retries. 164 func (q *TransactionReceiptQuery) SetMinBackoff(min time.Duration) *TransactionReceiptQuery { 165 q.Query.SetMinBackoff(min) 166 return q 167 } 168 169 // SetPaymentTransactionID assigns the payment transaction id. 170 func (q *TransactionReceiptQuery) SetPaymentTransactionID(transactionID TransactionID) *TransactionReceiptQuery { 171 q.Query.SetPaymentTransactionID(transactionID) 172 return q 173 } 174 175 func (q *TransactionReceiptQuery) SetLogLevel(level LogLevel) *TransactionReceiptQuery { 176 q.Query.SetLogLevel(level) 177 return q 178 } 179 180 // ---------- Parent functions specific implementation ---------- 181 182 func (q *TransactionReceiptQuery) getMethod(channel *_Channel) _Method { 183 return _Method{ 184 query: channel._GetCrypto().GetTransactionReceipts, 185 } 186 } 187 188 func (q *TransactionReceiptQuery) mapStatusError(_ Executable, response interface{}) error { 189 status := Status(response.(*services.Response).GetTransactionGetReceipt().GetHeader().GetNodeTransactionPrecheckCode()) 190 switch status { 191 case StatusPlatformTransactionNotCreated, StatusBusy, StatusUnknown, StatusOk: 192 break 193 default: 194 return ErrHederaPreCheckStatus{ 195 Status: status, 196 } 197 } 198 199 return ErrHederaPreCheckStatus{ 200 Status: Status(response.(*services.Response).GetTransactionGetReceipt().GetReceipt().GetStatus()), 201 } 202 } 203 204 func (q *TransactionReceiptQuery) getName() string { 205 return "TransactionReceiptQuery" 206 } 207 208 func (q *TransactionReceiptQuery) buildQuery() *services.Query { 209 body := &services.TransactionGetReceiptQuery{ 210 Header: q.pbHeader, 211 } 212 213 if q.transactionID.AccountID != nil { 214 body.TransactionID = q.transactionID._ToProtobuf() 215 } 216 217 if q.duplicates != nil { 218 body.IncludeDuplicates = *q.duplicates 219 } 220 221 if q.childReceipts != nil { 222 body.IncludeChildReceipts = q.GetIncludeChildren() 223 } 224 225 return &services.Query{ 226 Query: &services.Query_TransactionGetReceipt{ 227 TransactionGetReceipt: body, 228 }, 229 } 230 } 231 232 func (q *TransactionReceiptQuery) validateNetworkOnIDs(client *Client) error { 233 if client == nil || !client.autoValidateChecksums { 234 return nil 235 } 236 237 if err := q.transactionID.AccountID.ValidateChecksum(client); err != nil { 238 return err 239 } 240 241 return nil 242 } 243 244 func (q *TransactionReceiptQuery) shouldRetry(_ Executable, response interface{}) _ExecutionState { 245 status := Status(response.(*services.Response).GetTransactionGetReceipt().GetHeader().GetNodeTransactionPrecheckCode()) 246 247 switch status { 248 case StatusPlatformTransactionNotCreated, StatusBusy, StatusUnknown, StatusReceiptNotFound, StatusRecordNotFound, StatusPlatformNotActive: 249 return executionStateRetry 250 case StatusOk: 251 break 252 default: 253 return executionStateError 254 } 255 256 status = Status(response.(*services.Response).GetTransactionGetReceipt().GetReceipt().GetStatus()) 257 258 switch status { 259 case StatusBusy, StatusUnknown, StatusOk, StatusReceiptNotFound, StatusRecordNotFound, StatusPlatformNotActive: 260 return executionStateRetry 261 default: 262 return executionStateFinished 263 } 264 } 265 266 func (q *TransactionReceiptQuery) getQueryResponse(response *services.Response) queryResponse { 267 return response.GetTransactionGetReceipt() 268 }