github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/transaction_record_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 // TransactionRecordQuery 30 // Get the record for a transaction. If the transaction requested a record, then the record lasts 31 // for one hour, and a state proof is available for it. If the transaction created an account, file, 32 // or smart contract instance, then the record will contain the ID for what it created. If the 33 // transaction called a smart contract function, then the record contains the result of that call. 34 // If the transaction was a cryptocurrency transfer, then the record includes the TransferList which 35 // gives the details of that transfer. If the transaction didn't return anything that should be in 36 // the record, then the results field will be set to nothing. 37 type TransactionRecordQuery struct { 38 Query 39 transactionID *TransactionID 40 includeChildRecords *bool 41 duplicates *bool 42 } 43 44 // NewTransactionRecordQuery creates TransactionRecordQuery which 45 // gets the record for a transaction. If the transaction requested a record, then the record lasts 46 // for one hour, and a state proof is available for it. If the transaction created an account, file, 47 // or smart contract instance, then the record will contain the ID for what it created. If the 48 // transaction called a smart contract function, then the record contains the result of that call. 49 // If the transaction was a cryptocurrency transfer, then the record includes the TransferList which 50 // gives the details of that transfer. If the transaction didn't return anything that should be in 51 // the record, then the results field will be set to nothing. 52 func NewTransactionRecordQuery() *TransactionRecordQuery { 53 header := services.QueryHeader{} 54 return &TransactionRecordQuery{ 55 Query: _NewQuery(true, &header), 56 } 57 } 58 59 // When execution is attempted, a single attempt will timeout when this deadline is reached. (The SDK may subsequently retry the execution.) 60 func (q *TransactionRecordQuery) SetGrpcDeadline(deadline *time.Duration) *TransactionRecordQuery { 61 q.Query.SetGrpcDeadline(deadline) 62 return q 63 } 64 65 // SetIncludeChildren Sets whether the response should include the records of any child transactions spawned by the 66 // top-level transaction with the given transactionID. 67 func (q *TransactionRecordQuery) SetIncludeChildren(includeChildRecords bool) *TransactionRecordQuery { 68 q.includeChildRecords = &includeChildRecords 69 return q 70 } 71 72 // GetIncludeChildren returns whether the response should include the records of any child transactions spawned by the 73 // top-level transaction with the given transactionID. 74 func (q *TransactionRecordQuery) GetIncludeChildren() bool { 75 if q.includeChildRecords != nil { 76 return *q.includeChildRecords 77 } 78 79 return false 80 } 81 82 // SetIncludeDuplicates Sets whether records of processing duplicate transactions should be returned along with the record 83 // of processing the first consensus transaction with the given id whose status was neither 84 // INVALID_NODE_ACCOUNT nor <tt>INVALID_PAYER_SIGNATURE; or, if no such 85 // record exists, the record of processing the first transaction to reach consensus with the 86 // given transaction id.. 87 func (q *TransactionRecordQuery) SetIncludeDuplicates(includeDuplicates bool) *TransactionRecordQuery { 88 q.duplicates = &includeDuplicates 89 return q 90 } 91 92 // GetIncludeDuplicates returns whether records of processing duplicate transactions should be returned along with the record 93 // of processing the first consensus transaction with the given id. 94 func (q *TransactionRecordQuery) GetIncludeDuplicates() bool { 95 if q.duplicates != nil { 96 return *q.duplicates 97 } 98 99 return false 100 } 101 102 func (q *TransactionRecordQuery) GetCost(client *Client) (Hbar, error) { 103 return q.Query.getCost(client, q) 104 } 105 106 // Execute executes the Query with the provided client 107 func (q *TransactionRecordQuery) Execute(client *Client) (TransactionRecord, error) { 108 resp, err := q.Query.execute(client, q) 109 110 if err != nil { 111 if precheckErr, ok := err.(ErrHederaPreCheckStatus); ok { 112 return TransactionRecord{}, _NewErrHederaReceiptStatus(precheckErr.TxID, precheckErr.Status) 113 } 114 return TransactionRecord{}, err 115 } 116 117 return _TransactionRecordFromProtobuf(resp.GetTransactionGetRecord(), q.transactionID), nil 118 } 119 120 // SetTransactionID sets the TransactionID for this TransactionRecordQuery. 121 func (q *TransactionRecordQuery) SetTransactionID(transactionID TransactionID) *TransactionRecordQuery { 122 q.transactionID = &transactionID 123 return q 124 } 125 126 // GetTransactionID returns the TransactionID for which the receipt is being requested. 127 func (q *TransactionRecordQuery) GetTransactionID() TransactionID { 128 if q.transactionID == nil { 129 return TransactionID{} 130 } 131 132 return *q.transactionID 133 } 134 135 // SetNodeAccountIDs sets the _Node AccountID for this TransactionRecordQuery. 136 func (q *TransactionRecordQuery) SetNodeAccountIDs(accountID []AccountID) *TransactionRecordQuery { 137 q.Query.SetNodeAccountIDs(accountID) 138 return q 139 } 140 141 // SetQueryPayment sets the Hbar payment to pay the _Node a fee for handling this query 142 func (q *TransactionRecordQuery) SetQueryPayment(queryPayment Hbar) *TransactionRecordQuery { 143 q.Query.SetQueryPayment(queryPayment) 144 return q 145 } 146 147 // SetMaxQueryPayment sets the maximum payment allowed for this Query. 148 func (q *TransactionRecordQuery) SetMaxQueryPayment(queryMaxPayment Hbar) *TransactionRecordQuery { 149 q.Query.SetMaxQueryPayment(queryMaxPayment) 150 return q 151 } 152 153 // SetMaxRetry sets the max number of errors before execution will fail. 154 func (q *TransactionRecordQuery) SetMaxRetry(count int) *TransactionRecordQuery { 155 q.Query.SetMaxRetry(count) 156 return q 157 } 158 159 // SetMaxBackoff The maximum amount of time to wait between retries. 160 // Every retry attempt will increase the wait time exponentially until it reaches this time. 161 func (q *TransactionRecordQuery) SetMaxBackoff(max time.Duration) *TransactionRecordQuery { 162 q.Query.SetMaxBackoff(max) 163 return q 164 } 165 166 // SetMinBackoff sets the minimum amount of time to wait between retries. 167 func (q *TransactionRecordQuery) SetMinBackoff(min time.Duration) *TransactionRecordQuery { 168 q.Query.SetMinBackoff(min) 169 return q 170 } 171 172 // SetPaymentTransactionID assigns the payment transaction id. 173 func (q *TransactionRecordQuery) SetPaymentTransactionID(transactionID TransactionID) *TransactionRecordQuery { 174 q.paymentTransactionIDs._Clear()._Push(transactionID)._SetLocked(true) 175 return q 176 } 177 178 func (q *TransactionRecordQuery) SetLogLevel(level LogLevel) *TransactionRecordQuery { 179 q.Query.SetLogLevel(level) 180 return q 181 } 182 183 // ---------- Parent functions specific implementation ---------- 184 185 func (q *TransactionRecordQuery) getMethod(channel *_Channel) _Method { 186 return _Method{ 187 query: channel._GetCrypto().GetTxRecordByTxID, 188 } 189 } 190 191 func (q *TransactionRecordQuery) mapStatusError(_ Executable, response interface{}) error { 192 query := response.(*services.Response) 193 switch Status(query.GetTransactionGetRecord().GetHeader().GetNodeTransactionPrecheckCode()) { 194 case StatusPlatformTransactionNotCreated, StatusBusy, StatusUnknown, StatusReceiptNotFound, StatusRecordNotFound, StatusOk: 195 break 196 default: 197 return ErrHederaPreCheckStatus{ 198 Status: Status(query.GetTransactionGetRecord().GetHeader().GetNodeTransactionPrecheckCode()), 199 } 200 } 201 202 return ErrHederaReceiptStatus{ 203 Status: Status(query.GetTransactionGetRecord().GetTransactionRecord().GetReceipt().GetStatus()), 204 // TxID: _TransactionIDFromProtobuf(_Request.Query.pb.GetTransactionGetRecord().TransactionID, networkName), 205 Receipt: _TransactionReceiptFromProtobuf(query.GetTransactionGetReceipt(), nil), 206 } 207 } 208 209 func (q *TransactionRecordQuery) getName() string { 210 return "TransactionRecordQuery" 211 } 212 213 func (q *TransactionRecordQuery) buildQuery() *services.Query { 214 body := &services.TransactionGetRecordQuery{ 215 Header: q.pbHeader, 216 } 217 218 if q.includeChildRecords != nil { 219 body.IncludeChildRecords = q.GetIncludeChildren() 220 } 221 222 if q.duplicates != nil { 223 body.IncludeDuplicates = q.GetIncludeDuplicates() 224 } 225 226 if q.transactionID.AccountID != nil { 227 body.TransactionID = q.transactionID._ToProtobuf() 228 } 229 230 return &services.Query{ 231 Query: &services.Query_TransactionGetRecord{ 232 TransactionGetRecord: body, 233 }, 234 } 235 } 236 237 func (q *TransactionRecordQuery) validateNetworkOnIDs(client *Client) error { 238 if client == nil || !client.autoValidateChecksums { 239 return nil 240 } 241 242 if err := q.transactionID.AccountID.ValidateChecksum(client); err != nil { 243 return err 244 } 245 246 return nil 247 } 248 249 func (q *TransactionRecordQuery) shouldRetry(_ Executable, response interface{}) _ExecutionState { 250 status := Status(response.(*services.Response).GetTransactionGetRecord().GetHeader().GetNodeTransactionPrecheckCode()) 251 252 switch status { 253 case StatusPlatformTransactionNotCreated, StatusBusy, StatusUnknown, StatusReceiptNotFound, StatusRecordNotFound, StatusPlatformNotActive: 254 return executionStateRetry 255 case StatusOk: 256 if response.(*services.Response).GetTransactionGetRecord().GetHeader().ResponseType == services.ResponseType_COST_ANSWER { 257 return executionStateFinished 258 } 259 default: 260 return executionStateError 261 } 262 263 status = Status(response.(*services.Response).GetTransactionGetRecord().GetTransactionRecord().GetReceipt().GetStatus()) 264 265 switch status { 266 case StatusBusy, StatusUnknown, StatusOk, StatusReceiptNotFound, StatusRecordNotFound, StatusPlatformNotActive: 267 return executionStateRetry 268 case StatusSuccess: 269 return executionStateFinished 270 default: 271 return executionStateError 272 } 273 } 274 275 func (q *TransactionRecordQuery) getQueryResponse(response *services.Response) queryResponse { 276 return response.GetTransactionGetRecord() 277 }