-
Notifications
You must be signed in to change notification settings - Fork 0
/
actions_create_transaction.go
137 lines (121 loc) · 3.81 KB
/
actions_create_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
137
package horizon
import (
"fmt"
"net/http"
"gitlab.com/distributed_lab/logan/v3/errors"
"gitlab.com/distributed_lab/txsub"
"gitlab.com/tokend/go/xdr"
"gitlab.com/tokend/horizon/render/hal"
"gitlab.com/tokend/horizon/render/problem"
"gitlab.com/tokend/horizon/resource"
txsubHelper "gitlab.com/tokend/horizon/txsub"
)
// TransactionCreateAction submits a transaction to the stellar-core network
// on behalf of the requesting client.
type TransactionCreateAction struct {
Action
tx string
result txsub.Result
resource resource.TransactionSuccess
}
// JSON format action handler
func (action *TransactionCreateAction) JSON() {
action.Do(
action.ValidateBodyType,
action.loadTX,
action.loadResult,
action.loadResource,
func() {
hal.Render(action.W, action.resource)
})
}
func (action *TransactionCreateAction) loadTX() {
action.tx = action.GetNonEmptyString("tx")
}
func (action *TransactionCreateAction) loadResult() {
envelopeInfo, err := txsubHelper.ExtractEnvelopeInfo(action.tx, action.App.CoreInfo.NetworkPassphrase)
if err != nil {
action.Err = &problem.P{
Type: "transaction_malformed",
Title: "Transaction Malformed",
Status: http.StatusBadRequest,
Detail: "Horizon could not decode the transaction envelope in this " +
"request. A transaction should be an XDR TransactionEnvelope struct " +
"encoded using base64. The envelope read from this request is " +
"echoed in the `extras.envelope_xdr` field of this response for your " +
"convenience.",
Extras: map[string]interface{}{
"envelope_xdr": action.tx,
},
}
return
}
action.result = action.App.submitter.Submit(action.Ctx, envelopeInfo)
if action.result.HasInternalError() {
action.Log.WithError(action.result.Err).Error("Failed to submit tx")
action.Err = &problem.ServerError
return
}
if action.result.Err == nil {
action.resource.Populate(action.Ctx, action.result)
return
}
}
func (action *TransactionCreateAction) loadResource() {
p, err := txResultToProblem(&action.result)
if err != nil {
action.Log.WithError(err).Error("failed to craft problem")
action.Err = &problem.ServerError
return
}
if p != nil {
action.Err = p
return
}
}
func txResultToProblem(result *txsub.Result) (*problem.P, error) {
if result.Err == nil {
return nil, nil
}
txSubError, ok := result.Err.(txsub.Error)
if !ok {
return nil, errors.New("Unexpected error type")
}
switch txSubError.Type() {
case txsub.Timeout:
return &problem.Timeout, nil
case txsub.RejectedTx:
var parsedResult xdr.TransactionResult
err := xdr.SafeUnmarshalBase64(txSubError.ResultXDR(), &parsedResult)
if err != nil {
return nil, errors.Wrap(err, "Failed to get parse tx result")
}
var parsedEnvelope xdr.TransactionEnvelope
err = xdr.SafeUnmarshalBase64(result.EnvelopeXDR, &parsedEnvelope)
if err != nil {
return nil, errors.Wrap(err, "Failed to unmarshal tx envelope")
}
resultCodes, err := resource.NewTransactionResultCodes(parsedResult)
if err != nil {
return nil, errors.Wrap(err, "Failed to create transaction result codes")
}
return &problem.P{
Type: "transaction_failed",
Title: "Transaction Failed",
Status: http.StatusBadRequest,
Detail: "The transaction failed when submitted to the stellar network. " +
"The `extras.result_codes` field on this response contains further " +
"details. Descriptions of each code can be found at: " +
"https://www.stellar.org/developers/learn/concepts/list-of-operations.html",
Extras: map[string]interface{}{
"envelope_xdr": result.EnvelopeXDR,
"result_xdr": txSubError.ResultXDR(),
"result_codes": resultCodes,
"parsed_result": &parsedResult,
"parsed_envelope": &parsedEnvelope,
},
}, nil
default:
return nil, errors.New(fmt.Sprintf("Unexpected error type: %d", txSubError.Type()))
}
}