diff --git a/config/services.go b/config/services.go index ca5f40f..5c1b53f 100644 --- a/config/services.go +++ b/config/services.go @@ -54,6 +54,7 @@ type Services struct { WebhookHandler *handlers.WebhookHandler Logger *slog.Logger Config *Config + ownsP2PClient bool } // Initialize creates and returns all application services. @@ -286,6 +287,7 @@ func (c *Config) initializeEmbedded(ctx context.Context, logger *slog.Logger, ch WebhookHandler: webhookHandler, Logger: logger, Config: c, + ownsP2PClient: ownsP2PClient, }, nil } @@ -316,8 +318,8 @@ func (s *Services) Close() error { } } - // Close P2P client (also stops Chaintracks via context) - if s.P2PClient != nil { + // Close P2P client only if we created it (caller owns it otherwise) + if s.P2PClient != nil && s.ownsP2PClient { if err := s.P2PClient.Close(); err != nil { errs = append(errs, fmt.Errorf("p2p client close: %w", err)) } diff --git a/docs/docs.go b/docs/docs.go index c87c5f8..4bb639b 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,6 +1,4 @@ // Package docs Code generated by swaggo/swag. DO NOT EDIT -// -//nolint:gochecknoglobals,gochecknoinits // generated file package docs import "github.com/swaggo/swag" @@ -164,13 +162,13 @@ const docTemplate = `{ "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/errors.ErrorFields" + "$ref": "#/definitions/arcerrors.ErrorFields" } }, "465": { "description": "ARC validation error", "schema": { - "$ref": "#/definitions/errors.ErrorFields" + "$ref": "#/definitions/arcerrors.ErrorFields" } }, "500": { @@ -214,10 +212,7 @@ const docTemplate = `{ "404": { "description": "Not Found", "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/arcerrors.ErrorFields" } }, "500": { @@ -302,13 +297,13 @@ const docTemplate = `{ "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/errors.ErrorFields" + "$ref": "#/definitions/arcerrors.ErrorFields" } }, "465": { "description": "ARC validation error", "schema": { - "$ref": "#/definitions/errors.ErrorFields" + "$ref": "#/definitions/arcerrors.ErrorFields" } } } @@ -316,7 +311,7 @@ const docTemplate = `{ } }, "definitions": { - "errors.ErrorFields": { + "arcerrors.ErrorFields": { "type": "object", "properties": { "detail": { @@ -414,6 +409,9 @@ const docTemplate = `{ "type": "integer" } }, + "status": { + "type": "integer" + }, "timestamp": { "type": "string" }, diff --git a/docs/swagger.json b/docs/swagger.json index 1c8de62..9dc5e85 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1,144 +1,38 @@ { - "basePath": "/", - "definitions": { - "errors.ErrorFields": { - "properties": { - "detail": { - "type": "string" - }, - "extraInfo": { - "type": "string" - }, - "status": { - "type": "integer" - }, - "title": { - "type": "string" - }, - "type": { - "type": "string" - } - }, - "type": "object" - }, - "fiber.TransactionRequest": { - "properties": { - "rawTx": { - "example": "0100000001...", - "type": "string" - } - }, - "type": "object" - }, - "models.Policy": { - "properties": { - "maxscriptsizepolicy": { - "type": "integer" - }, - "maxtxsigopscountspolicy": { - "type": "integer" - }, - "maxtxsizepolicy": { - "type": "integer" - }, - "miningFeeBytes": { - "type": "integer" - }, - "miningFeeSatoshis": { - "type": "integer" - } - }, - "type": "object" - }, - "models.Status": { - "enum": [ - "UNKNOWN", - "RECEIVED", - "SENT_TO_NETWORK", - "ACCEPTED_BY_NETWORK", - "SEEN_ON_NETWORK", - "DOUBLE_SPEND_ATTEMPTED", - "REJECTED", - "MINED", - "IMMUTABLE" - ], - "type": "string", - "x-enum-varnames": [ - "StatusUnknown", - "StatusReceived", - "StatusSentToNetwork", - "StatusAcceptedByNetwork", - "StatusSeenOnNetwork", - "StatusDoubleSpendAttempted", - "StatusRejected", - "StatusMined", - "StatusImmutable" - ] - }, - "models.TransactionStatus": { - "properties": { - "blockHash": { - "type": "string" - }, - "blockHeight": { - "type": "integer" - }, - "competingTxs": { - "items": { - "type": "string" - }, - "type": "array" - }, - "extraInfo": { - "type": "string" - }, - "merklePath": { - "items": { - "type": "integer" - }, - "type": "array" - }, - "timestamp": { - "type": "string" - }, - "txStatus": { - "$ref": "#/definitions/models.Status" - }, - "txid": { - "type": "string" - } - }, - "type": "object" - } - }, + "swagger": "2.0", "info": { + "description": "BSV transaction broadcast service with ARC-compatible endpoints.", + "title": "Arcade API", "contact": { "name": "BSV Blockchain", "url": "https://github.com/bsv-blockchain/arcade" }, - "description": "BSV transaction broadcast service with ARC-compatible endpoints.", "license": { "name": "Open BSV License", "url": "https://github.com/bsv-blockchain/arcade/blob/main/LICENSE" }, - "title": "Arcade API", "version": "0.1.0" }, + "basePath": "/", "paths": { "/events": { "get": { "description": "Server-Sent Events stream of transaction status updates. If callbackToken is provided, only events for that token are streamed.", + "produces": [ + "text/event-stream" + ], + "tags": [ + "arcade" + ], + "summary": "Stream transaction events", "parameters": [ { + "type": "string", "description": "Callback token from transaction submission", - "in": "query", "name": "callbackToken", - "type": "string" + "in": "query" } ], - "produces": [ - "text/event-stream" - ], "responses": { "200": { "description": "SSE stream of transaction status updates", @@ -146,11 +40,7 @@ "type": "string" } } - }, - "summary": "Stream transaction events", - "tags": [ - "arcade" - ] + } } }, "/health": { @@ -159,6 +49,10 @@ "produces": [ "text/plain" ], + "tags": [ + "arcade" + ], + "summary": "Health check", "responses": { "200": { "description": "OK", @@ -172,11 +66,7 @@ "type": "string" } } - }, - "summary": "Health check", - "tags": [ - "arcade" - ] + } } }, "/policy": { @@ -185,6 +75,10 @@ "produces": [ "application/json" ], + "tags": [ + "arcade" + ], + "summary": "Get policy", "responses": { "200": { "description": "OK", @@ -192,65 +86,65 @@ "$ref": "#/definitions/models.Policy" } } - }, - "summary": "Get policy", - "tags": [ - "arcade" - ] + } } }, "/tx": { "post": { + "description": "Submit a single transaction for broadcast. Accepts raw transaction bytes, hex string, or JSON with rawTx field.", "consumes": [ "application/json", "application/octet-stream", "text/plain" ], - "description": "Submit a single transaction for broadcast. Accepts raw transaction bytes, hex string, or JSON with rawTx field.", + "produces": [ + "application/json" + ], + "tags": [ + "arcade" + ], + "summary": "Submit transaction", "parameters": [ { "description": "Transaction data", - "in": "body", "name": "transaction", + "in": "body", "required": true, "schema": { "$ref": "#/definitions/fiber.TransactionRequest" } }, { + "type": "string", "description": "URL for status callbacks", - "in": "header", "name": "X-CallbackUrl", - "type": "string" + "in": "header" }, { + "type": "string", "description": "Token for SSE event filtering", - "in": "header", "name": "X-CallbackToken", - "type": "string" + "in": "header" }, { + "type": "string", "description": "Send all status updates (true/false)", - "in": "header", "name": "X-FullStatusUpdates", - "type": "string" + "in": "header" }, { + "type": "string", "description": "Skip fee validation (true/false)", - "in": "header", "name": "X-SkipFeeValidation", - "type": "string" + "in": "header" }, { + "type": "string", "description": "Skip script validation (true/false)", - "in": "header", "name": "X-SkipScriptValidation", - "type": "string" + "in": "header" } ], - "produces": [ - "application/json" - ], "responses": { "200": { "description": "OK", @@ -261,46 +155,46 @@ "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/errors.ErrorFields" + "$ref": "#/definitions/arcerrors.ErrorFields" } }, "465": { "description": "ARC validation error", "schema": { - "$ref": "#/definitions/errors.ErrorFields" + "$ref": "#/definitions/arcerrors.ErrorFields" } }, "500": { "description": "Internal Server Error", "schema": { + "type": "object", "additionalProperties": { "type": "string" - }, - "type": "object" + } } } - }, - "summary": "Submit transaction", - "tags": [ - "arcade" - ] + } } }, "/tx/{txid}": { "get": { "description": "Get the current status of a submitted transaction", + "produces": [ + "application/json" + ], + "tags": [ + "arcade" + ], + "summary": "Get transaction status", "parameters": [ { + "type": "string", "description": "Transaction ID", - "in": "path", "name": "txid", - "required": true, - "type": "string" + "in": "path", + "required": true } ], - "produces": [ - "application/json" - ], "responses": { "200": { "description": "OK", @@ -311,118 +205,224 @@ "404": { "description": "Not Found", "schema": { - "additionalProperties": { - "type": "string" - }, - "type": "object" + "$ref": "#/definitions/arcerrors.ErrorFields" } }, "500": { "description": "Internal Server Error", "schema": { + "type": "object", "additionalProperties": { "type": "string" - }, - "type": "object" + } } } - }, - "summary": "Get transaction status", - "tags": [ - "arcade" - ] + } } }, "/txs": { "post": { + "description": "Submit multiple transactions for broadcast", "consumes": [ "application/json" ], - "description": "Submit multiple transactions for broadcast", + "produces": [ + "application/json" + ], + "tags": [ + "arcade" + ], + "summary": "Submit multiple transactions", "parameters": [ { "description": "Array of transactions", - "in": "body", "name": "transactions", + "in": "body", "required": true, "schema": { + "type": "array", "items": { "$ref": "#/definitions/fiber.TransactionRequest" - }, - "type": "array" + } } }, { + "type": "string", "description": "URL for status callbacks", - "in": "header", "name": "X-CallbackUrl", - "type": "string" + "in": "header" }, { + "type": "string", "description": "Token for SSE event filtering", - "in": "header", "name": "X-CallbackToken", - "type": "string" + "in": "header" }, { + "type": "string", "description": "Send all status updates (true/false)", - "in": "header", "name": "X-FullStatusUpdates", - "type": "string" + "in": "header" }, { + "type": "string", "description": "Skip fee validation (true/false)", - "in": "header", "name": "X-SkipFeeValidation", - "type": "string" + "in": "header" }, { + "type": "string", "description": "Skip script validation (true/false)", - "in": "header", "name": "X-SkipScriptValidation", - "type": "string" + "in": "header" } ], - "produces": [ - "application/json" - ], "responses": { "200": { "description": "OK", "schema": { + "type": "array", "items": { "$ref": "#/definitions/models.TransactionStatus" - }, - "type": "array" + } } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/errors.ErrorFields" + "$ref": "#/definitions/arcerrors.ErrorFields" } }, "465": { "description": "ARC validation error", "schema": { - "$ref": "#/definitions/errors.ErrorFields" + "$ref": "#/definitions/arcerrors.ErrorFields" } } + } + } + } + }, + "definitions": { + "arcerrors.ErrorFields": { + "type": "object", + "properties": { + "detail": { + "type": "string" }, - "summary": "Submit multiple transactions", - "tags": [ - "arcade" - ] + "extraInfo": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "fiber.TransactionRequest": { + "type": "object", + "properties": { + "rawTx": { + "type": "string", + "example": "0100000001..." + } + } + }, + "models.Policy": { + "type": "object", + "properties": { + "maxscriptsizepolicy": { + "type": "integer" + }, + "maxtxsigopscountspolicy": { + "type": "integer" + }, + "maxtxsizepolicy": { + "type": "integer" + }, + "miningFeeBytes": { + "type": "integer" + }, + "miningFeeSatoshis": { + "type": "integer" + } + } + }, + "models.Status": { + "type": "string", + "enum": [ + "UNKNOWN", + "RECEIVED", + "SENT_TO_NETWORK", + "ACCEPTED_BY_NETWORK", + "SEEN_ON_NETWORK", + "DOUBLE_SPEND_ATTEMPTED", + "REJECTED", + "MINED", + "IMMUTABLE" + ], + "x-enum-varnames": [ + "StatusUnknown", + "StatusReceived", + "StatusSentToNetwork", + "StatusAcceptedByNetwork", + "StatusSeenOnNetwork", + "StatusDoubleSpendAttempted", + "StatusRejected", + "StatusMined", + "StatusImmutable" + ] + }, + "models.TransactionStatus": { + "type": "object", + "properties": { + "blockHash": { + "type": "string" + }, + "blockHeight": { + "type": "integer" + }, + "competingTxs": { + "type": "array", + "items": { + "type": "string" + } + }, + "extraInfo": { + "type": "string" + }, + "merklePath": { + "type": "array", + "items": { + "type": "integer" + } + }, + "status": { + "type": "integer" + }, + "timestamp": { + "type": "string" + }, + "txStatus": { + "$ref": "#/definitions/models.Status" + }, + "txid": { + "type": "string" + } } } }, "securityDefinitions": { "BearerAuth": { "description": "Bearer token authentication", - "in": "header", + "type": "apiKey", "name": "Authorization", - "type": "apiKey" + "in": "header" } - }, - "swagger": "2.0" -} + } +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 38e296d..0c119c1 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,6 +1,6 @@ basePath: / definitions: - errors.ErrorFields: + arcerrors.ErrorFields: properties: detail: type: string @@ -34,26 +34,26 @@ definitions: type: object models.Status: enum: - - UNKNOWN - - RECEIVED - - SENT_TO_NETWORK - - ACCEPTED_BY_NETWORK - - SEEN_ON_NETWORK - - DOUBLE_SPEND_ATTEMPTED - - REJECTED - - MINED - - IMMUTABLE + - UNKNOWN + - RECEIVED + - SENT_TO_NETWORK + - ACCEPTED_BY_NETWORK + - SEEN_ON_NETWORK + - DOUBLE_SPEND_ATTEMPTED + - REJECTED + - MINED + - IMMUTABLE type: string x-enum-varnames: - - StatusUnknown - - StatusReceived - - StatusSentToNetwork - - StatusAcceptedByNetwork - - StatusSeenOnNetwork - - StatusDoubleSpendAttempted - - StatusRejected - - StatusMined - - StatusImmutable + - StatusUnknown + - StatusReceived + - StatusSentToNetwork + - StatusAcceptedByNetwork + - StatusSeenOnNetwork + - StatusDoubleSpendAttempted + - StatusRejected + - StatusMined + - StatusImmutable models.TransactionStatus: properties: blockHash: @@ -70,6 +70,8 @@ definitions: items: type: integer type: array + status: + type: integer timestamp: type: string txStatus: @@ -90,14 +92,15 @@ info: paths: /events: get: - description: Server-Sent Events stream of transaction status updates. If callbackToken is provided, only events for that token are streamed. + description: Server-Sent Events stream of transaction status updates. If callbackToken + is provided, only events for that token are streamed. parameters: - - description: Callback token from transaction submission - in: query - name: callbackToken - type: string + - description: Callback token from transaction submission + in: query + name: callbackToken + type: string produces: - - text/event-stream + - text/event-stream responses: "200": description: SSE stream of transaction status updates @@ -105,12 +108,12 @@ paths: type: string summary: Stream transaction events tags: - - arcade + - arcade /health: get: description: Returns the health status of the service produces: - - text/plain + - text/plain responses: "200": description: OK @@ -122,12 +125,13 @@ paths: type: string summary: Health check tags: - - arcade + - arcade /policy: get: - description: Returns the transaction policy configuration including fee rates and limits + description: Returns the transaction policy configuration including fee rates + and limits produces: - - application/json + - application/json responses: "200": description: OK @@ -135,43 +139,44 @@ paths: $ref: '#/definitions/models.Policy' summary: Get policy tags: - - arcade + - arcade /tx: post: consumes: - - application/json - - application/octet-stream - - text/plain - description: Submit a single transaction for broadcast. Accepts raw transaction bytes, hex string, or JSON with rawTx field. + - application/json + - application/octet-stream + - text/plain + description: Submit a single transaction for broadcast. Accepts raw transaction + bytes, hex string, or JSON with rawTx field. parameters: - - description: Transaction data - in: body - name: transaction - required: true - schema: - $ref: '#/definitions/fiber.TransactionRequest' - - description: URL for status callbacks - in: header - name: X-CallbackUrl - type: string - - description: Token for SSE event filtering - in: header - name: X-CallbackToken - type: string - - description: Send all status updates (true/false) - in: header - name: X-FullStatusUpdates - type: string - - description: Skip fee validation (true/false) - in: header - name: X-SkipFeeValidation - type: string - - description: Skip script validation (true/false) - in: header - name: X-SkipScriptValidation - type: string + - description: Transaction data + in: body + name: transaction + required: true + schema: + $ref: '#/definitions/fiber.TransactionRequest' + - description: URL for status callbacks + in: header + name: X-CallbackUrl + type: string + - description: Token for SSE event filtering + in: header + name: X-CallbackToken + type: string + - description: Send all status updates (true/false) + in: header + name: X-FullStatusUpdates + type: string + - description: Skip fee validation (true/false) + in: header + name: X-SkipFeeValidation + type: string + - description: Skip script validation (true/false) + in: header + name: X-SkipScriptValidation + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -180,11 +185,11 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/errors.ErrorFields' + $ref: '#/definitions/arcerrors.ErrorFields' "465": description: ARC validation error schema: - $ref: '#/definitions/errors.ErrorFields' + $ref: '#/definitions/arcerrors.ErrorFields' "500": description: Internal Server Error schema: @@ -193,18 +198,18 @@ paths: type: object summary: Submit transaction tags: - - arcade + - arcade /tx/{txid}: get: description: Get the current status of a submitted transaction parameters: - - description: Transaction ID - in: path - name: txid - required: true - type: string + - description: Transaction ID + in: path + name: txid + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -213,9 +218,7 @@ paths: "404": description: Not Found schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/arcerrors.ErrorFields' "500": description: Internal Server Error schema: @@ -224,43 +227,43 @@ paths: type: object summary: Get transaction status tags: - - arcade + - arcade /txs: post: consumes: - - application/json + - application/json description: Submit multiple transactions for broadcast parameters: - - description: Array of transactions - in: body - name: transactions - required: true - schema: - items: - $ref: '#/definitions/fiber.TransactionRequest' - type: array - - description: URL for status callbacks - in: header - name: X-CallbackUrl - type: string - - description: Token for SSE event filtering - in: header - name: X-CallbackToken - type: string - - description: Send all status updates (true/false) - in: header - name: X-FullStatusUpdates - type: string - - description: Skip fee validation (true/false) - in: header - name: X-SkipFeeValidation - type: string - - description: Skip script validation (true/false) - in: header - name: X-SkipScriptValidation - type: string + - description: Array of transactions + in: body + name: transactions + required: true + schema: + items: + $ref: '#/definitions/fiber.TransactionRequest' + type: array + - description: URL for status callbacks + in: header + name: X-CallbackUrl + type: string + - description: Token for SSE event filtering + in: header + name: X-CallbackToken + type: string + - description: Send all status updates (true/false) + in: header + name: X-FullStatusUpdates + type: string + - description: Skip fee validation (true/false) + in: header + name: X-SkipFeeValidation + type: string + - description: Skip script validation (true/false) + in: header + name: X-SkipScriptValidation + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -271,14 +274,14 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/errors.ErrorFields' + $ref: '#/definitions/arcerrors.ErrorFields' "465": description: ARC validation error schema: - $ref: '#/definitions/errors.ErrorFields' + $ref: '#/definitions/arcerrors.ErrorFields' summary: Submit multiple transactions tags: - - arcade + - arcade securityDefinitions: BearerAuth: description: Bearer token authentication diff --git a/handlers/webhook.go b/handlers/webhook.go index a3339e8..ac1b6e3 100644 --- a/handlers/webhook.go +++ b/handlers/webhook.go @@ -161,6 +161,7 @@ func (h *WebhookHandler) deliverWebhook(ctx context.Context, sub models.Submissi slog.String("url", sub.CallbackURL), slog.String("status", string(status.Status))) + status.StatusCode = http.StatusOK payloadBytes, err := json.Marshal(status) if err != nil { h.logger.Error("Failed to marshal payload", diff --git a/models/transaction.go b/models/transaction.go index aabafae..6b04b71 100644 --- a/models/transaction.go +++ b/models/transaction.go @@ -39,6 +39,7 @@ func (h *HexBytes) UnmarshalJSON(data []byte) error { type TransactionStatus struct { TxID string `json:"txid"` Status Status `json:"txStatus"` + StatusCode int `json:"status,omitempty"` Timestamp time.Time `json:"timestamp"` BlockHash string `json:"blockHash,omitempty"` BlockHeight uint64 `json:"blockHeight,omitempty"` diff --git a/routes/fiber/routes.go b/routes/fiber/routes.go index 8e0ab5a..b600e56 100644 --- a/routes/fiber/routes.go +++ b/routes/fiber/routes.go @@ -106,7 +106,7 @@ func (r *Routes) handleGetPolicy(c *fiber.Ctx) error { // @Param X-SkipScriptValidation header string false "Skip script validation (true/false)" // @Success 200 {object} models.TransactionStatus // @Failure 400 {object} arcerrors.ErrorFields -// @Failure 465 {object} errors.ErrorFields "ARC validation error" +// @Failure 465 {object} arcerrors.ErrorFields "ARC validation error" // @Failure 500 {object} map[string]string // @Router /tx [post] func (r *Routes) handlePostTx(c *fiber.Ctx) error { @@ -127,6 +127,7 @@ func (r *Routes) handlePostTx(c *fiber.Ctx) error { return r.handleSubmitError(c, err) } + status.StatusCode = http.StatusOK return c.JSON(status) } @@ -144,7 +145,7 @@ func (r *Routes) handlePostTx(c *fiber.Ctx) error { // @Param X-SkipScriptValidation header string false "Skip script validation (true/false)" // @Success 200 {array} models.TransactionStatus // @Failure 400 {object} arcerrors.ErrorFields -// @Failure 465 {object} errors.ErrorFields "ARC validation error" +// @Failure 465 {object} arcerrors.ErrorFields "ARC validation error" // @Router /txs [post] func (r *Routes) handlePostTxs(c *fiber.Ctx) error { ctx := c.UserContext() @@ -173,6 +174,9 @@ func (r *Routes) handlePostTxs(c *fiber.Ctx) error { return r.handleSubmitError(c, err) } + for _, s := range statuses { + s.StatusCode = http.StatusOK + } return c.JSON(statuses) } @@ -200,17 +204,18 @@ func (r *Routes) handleSubmitError(c *fiber.Ctx, err error) error { // @Produce json // @Param txid path string true "Transaction ID" // @Success 200 {object} models.TransactionStatus -// @Failure 404 {object} map[string]string +// @Failure 404 {object} arcerrors.ErrorFields // @Failure 500 {object} map[string]string // @Router /tx/{txid} [get] func (r *Routes) handleGetTx(c *fiber.Ctx) error { status, err := r.service.GetStatus(c.UserContext(), c.Params("txid")) if err != nil { if strings.Contains(err.Error(), "not found") { - return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "Transaction not found"}) + return c.Status(http.StatusNotFound).JSON(arcerrors.NewErrorFields(arcerrors.StatusNotFound, "Transaction not found")) } return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to get status"}) } + status.StatusCode = http.StatusOK return c.JSON(status) } diff --git a/service/embedded/embedded.go b/service/embedded/embedded.go index 0f23934..052999b 100644 --- a/service/embedded/embedded.go +++ b/service/embedded/embedded.go @@ -445,8 +445,12 @@ func (e *Embedded) GetPolicy(_ context.Context) (*models.Policy, error) { // submitToTeranodeSync submits a transaction to a teranode endpoint, updates status, and returns the result. func (e *Embedded) submitToTeranodeSync(ctx context.Context, endpoint string, rawTx []byte, txid string) *models.TransactionStatus { + e.logger.Debug("submitting to teranode", slog.String("txid", txid), slog.String("endpoint", endpoint), slog.Int("rawTxSize", len(rawTx))) + statusCode, err := e.teranodeClient.SubmitTransaction(ctx, endpoint, rawTx) if err != nil { + e.logger.Warn("teranode submission failed", slog.String("txid", txid), slog.String("endpoint", endpoint), slog.String("error", err.Error())) + status := &models.TransactionStatus{ TxID: txid, Status: models.StatusRejected, @@ -462,6 +466,8 @@ func (e *Embedded) submitToTeranodeSync(ctx context.Context, endpoint string, ra return status } + e.logger.Debug("teranode submission succeeded", slog.String("txid", txid), slog.String("endpoint", endpoint), slog.Int("statusCode", statusCode)) + var txStatus models.Status switch statusCode { case http.StatusOK: