forked from tonicpow/go-minercraft
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquery_transaction.go
136 lines (118 loc) · 4.67 KB
/
query_transaction.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package minercraft
import (
"context"
"encoding/json"
"errors"
"net/http"
)
/*
Example query tx response from Merchant API:
{
"payload": "{\"apiVersion\":\"1.2.3\",\"timestamp\":\"2020-01-15T11:41:29.032Z\",\"returnResult\":\"failure\",\"resultDescription\":\"Transaction in mempool but not yet in block\",\"blockHash\":\"\",\"blockHeight\":0,\"minerId\":\"03fcfcfcd0841b0a6ed2057fa8ed404788de47ceb3390c53e79c4ecd1e05819031\",\"confirmations\":0,\"txSecondMempoolExpiry\":0}",
"signature": "3045022100f78a6ac49ef38fbe68db609ff194d22932d865d93a98ee04d2ecef5016872ba50220387bf7e4df323bf4a977dd22a34ea3ad42de1a2ec4e5af59baa13258f64fe0e5",
"publicKey": "03fcfcfcd0841b0a6ed2057fa8ed404788de47ceb3390c53e79c4ecd1e05819031",
"encoding": "UTF-8",
"mimetype": "application/json"
}
*/
// QueryTransactionResponse is the raw response from the Merchant API request
//
// Specs: https://github.com/bitcoin-sv-specs/brfc-merchantapi/tree/v1.2-beta#Query-transaction-status
type QueryTransactionResponse struct {
JSONEnvelope
Query *QueryPayload `json:"query"` // Custom field for unmarshalled payload data
}
/*
Example QueryTransactionResponse.Payload (unmarshalled):
Failure - in mempool but not in block
{
"apiVersion": "1.2.3",
"timestamp": "2020-01-15T11:41:29.032Z",
"txid": "6bdbcfab0526d30e8d68279f79dff61fb4026ace8b7b32789af016336e54f2f0",
"returnResult": "failure",
"resultDescription": "Transaction in mempool but not yet in block",
"blockHash": "",
"blockHeight": 0,
"minerId": "03fcfcfcd0841b0a6ed2057fa8ed404788de47ceb3390c53e79c4ecd1e05819031",
"confirmations": 0,
"txSecondMempoolExpiry": 0
}
Success - added to block
{
"apiVersion": "1.2.3",
"timestamp": "2020-01-15T12:09:37.394Z",
"txid": "6bdbcfab0526d30e8d68279f79dff61fb4026ace8b7b32789af016336e54f2f0",
"returnResult": "success",
"resultDescription": "",
"blockHash": "745093bb0c80780092d4ce6926e0caa753fe3accdc09c761aee89bafa85f05f4",
"blockHeight": 208,
"minerId": "03fcfcfcd0841b0a6ed2057fa8ed404788de47ceb3390c53e79c4ecd1e05819031",
"confirmations": 2,
"txSecondMempoolExpiry": 0
}
*/
// QueryPayload is the unmarshalled version of the payload envelope
type QueryPayload struct {
APIVersion string `json:"apiVersion"`
Timestamp string `json:"timestamp"`
TxID string `json:"txid"`
ReturnResult string `json:"returnResult"`
ResultDescription string `json:"resultDescription"`
BlockHash string `json:"blockHash"`
BlockHeight int64 `json:"blockHeight"`
MinerID string `json:"minerId"`
Confirmations int64 `json:"confirmations"`
TxSecondMempoolExpiry int64 `json:"txSecondMempoolExpiry"`
}
// QueryTransaction will fire a Merchant API request to check the status of a transaction
//
// This endpoint is used to check the current status of a previously submitted transaction.
// It returns a JSONEnvelope with a payload that contains the transaction status.
// The purpose of the envelope is to ensure strict consistency in the message content for
// the purpose of signing responses.
//
// Specs: https://github.com/bitcoin-sv-specs/brfc-merchantapi/tree/v1.2-beta#Query-transaction-status
func (c *Client) QueryTransaction(miner *Miner, txID string) (*QueryTransactionResponse, error) {
// Make sure we have a valid miner
if miner == nil {
return nil, errors.New("miner was nil")
}
// Make the HTTP request
result := queryTransaction(context.Background(), c, miner, txID)
if result.Response.Error != nil {
return nil, result.Response.Error
}
// Parse the response
response, err := result.parseQuery()
if err != nil {
return nil, err
}
// Valid?
if response.Query == nil || len(response.Query.ReturnResult) == 0 {
return nil, errors.New("failed getting query response from: " + miner.Name)
}
// Return the fully parsed response
return &response, nil
}
// queryTransaction will fire the HTTP request to retrieve the tx status
func queryTransaction(ctx context.Context, client *Client, miner *Miner, txHash string) (result *internalResult) {
result = &internalResult{Miner: miner}
result.Response = httpRequest(ctx, client, &httpPayload{
Method: http.MethodGet,
URL: defaultProtocol + miner.URL + routeQueryTx + txHash,
Token: miner.Token,
})
return
}
// parseQuery will convert the HTTP response into a struct and also unmarshal the payload JSON data
func (i *internalResult) parseQuery() (response QueryTransactionResponse, err error) {
// Process the initial response payload
if err = response.process(i.Miner, i.Response.BodyContents); err != nil {
return
}
// If we have a valid payload
if len(response.Payload) > 0 {
err = json.Unmarshal([]byte(response.Payload), &response.Query)
}
return
}