From de2780c0fa6607f85266f2e01c1553ee3f9a38d1 Mon Sep 17 00:00:00 2001 From: Ed Tubbs Date: Thu, 24 Oct 2024 14:58:32 -0500 Subject: [PATCH] src: updated reference and error handling in rest doc: added rest.md --- doc/rest.md | 317 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/rest.c | 25 +++-- 2 files changed, 332 insertions(+), 10 deletions(-) create mode 100644 doc/rest.md diff --git a/doc/rest.md b/doc/rest.md new file mode 100644 index 000000000..6ecc914d0 --- /dev/null +++ b/doc/rest.md @@ -0,0 +1,317 @@ +# Libdogecoin SPV REST API Documentation + +## Table of Contents +- [Libdogecoin SPV REST API Documentation](#dogecoin-spv-rest-api-documentation) + - [Table of Contents](#table-of-contents) + - [Abstract](#abstract) + - [Endpoints](#endpoints) + - [GET /getBalance](#get-getbalance) + - [GET /getAddresses](#get-getaddresses) + - [GET /getTransactions](#get-gettransactions) + - [GET /getUTXOs](#get-getutxos) + - [GET /getWallet](#get-getwallet) + - [GET /getHeaders](#get-getheaders) + - [GET /getChaintip](#get-getchaintip) + +## Abstract + +This document describes the REST API endpoints exposed by the Libdogecoin SPV node. The API provides access to wallet information, such as balance, addresses, transactions, UTXOs, as well as wallet and blockchain data like wallet files, headers, and the chain tip. The API is designed to facilitate interaction with the Libdogecoin SPV node programmatically. + +## Endpoints + +--- + +### GET **/getBalance** + +Retrieves the total balance of the wallet. + +#### **Request** + +- **Method:** `GET` +- **URL:** `/getBalance` + +#### **Response** + +- **Content-Type:** `text/plain` +- **Body:** + + ``` + Wallet balance: + ``` + + Where `` is the total balance of the wallet in Dogecoin. + +#### **Example** + +```bash +curl http://localhost:/getBalance +``` + +#### **Sample Response** + +``` +Wallet balance: 123.45678900 +``` + +--- + +### GET **/getAddresses** + +Retrieves all addresses associated with the wallet. + +#### **Request** + +- **Method:** `GET` +- **URL:** `/getAddresses` + +#### **Response** + +- **Content-Type:** `text/plain` +- **Body:** + + ``` + address: + address: + ... + ``` + + Each line contains an address associated with the wallet. + +#### **Example** + +```bash +curl http://localhost:/getAddresses +``` + +#### **Sample Response** + +``` +address: DH5yaieqoZN36fDVciNyRueRGvGLR3mr7L +address: DQe1QeG4FxhEgvfuvGfC7oL5G2G87huuxU +``` + +--- + +### GET **/getTransactions** + +Retrieves all spent (non-spendable) transactions associated with the wallet. + +#### **Request** + +- **Method:** `GET` +- **URL:** `/getTransactions` + +#### **Response** + +- **Content-Type:** `text/plain` +- **Body:** + + ``` + ---------------------- + txid: + vout: + address:
+ script_pubkey: + amount: + confirmations: + spendable: + solvable: + ... + Spent Balance: + ``` + + Information about each spent transaction (UTXO) and the total spent balance. + +#### **Example** + +```bash +curl http://localhost:/getTransactions +``` + +#### **Sample Response** + +``` +---------------------- +txid: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +vout: 0 +address: DH5yaieqoZN36fDVciNyRueRGvGLR3mr7L +script_pubkey: 76a9144621d6a7f3b4ebbaee4e2d8c10eafbf1ccbc9c0a88ac +amount: 50.00000000 +confirmations: 100 +spendable: 0 +solvable: 1 +Spent Balance: 50.00000000 +``` + +--- + +### GET **/getUTXOs** + +Retrieves all unspent transaction outputs (UTXOs) associated with the wallet. + +#### **Request** + +- **Method:** `GET` +- **URL:** `/getUTXOs` + +#### **Response** + +- **Content-Type:** `text/plain` +- **Body:** + + ``` + ---------------------- + Unspent UTXO: + txid: + vout: + address:
+ script_pubkey: + amount: + spendable: + solvable: + ... + Total Unspent: + ``` + + Information about each unspent transaction output and the total unspent balance. + +#### **Example** + +```bash +curl http://localhost:/getUTXOs +``` + +#### **Sample Response** + +``` +---------------------- +Unspent UTXO: +txid: b1fea5241c4a1d7d1e6c6d619fbf3bb8b1ec3f1f1d2f4c5b6a7c8d9e0f1a2b3c +vout: 1 +address: DQe1QeG4FxhEgvfuvGfC7oL5G2G87huuxU +script_pubkey: 76a9145d6a7f3b4ebbaee4e2d8c10eafbf1ccbc9c0a88ac +amount: 75.00000000 +spendable: 1 +solvable: 1 +Total Unspent: 75.00000000 +``` + +--- + +### GET **/getWallet** + +Downloads the wallet file associated with the node. + +#### **Request** + +- **Method:** `GET` +- **URL:** `/getWallet` + +#### **Response** + +- **Content-Type:** `application/octet-stream` +- **Body:** + + Binary data of the wallet file. + +#### **Example** + +```bash +curl -O http://localhost:/getWallet +``` + +#### **Notes** + +- The response is a binary file. +- Ensure that it's secure as it contains sensitive information. + +--- + +### GET **/getHeaders** + +Downloads the headers file used by the SPV node. + +#### **Request** + +- **Method:** `GET` +- **URL:** `/getHeaders` + +#### **Response** + +- **Content-Type:** `application/octet-stream` +- **Body:** + + Binary data of the headers file. + +#### **Example** + +```bash +curl -O http://localhost:/getHeaders +``` + +#### **Notes** + +- The response is a binary file containing blockchain headers. +- Useful for debugging or analysis purposes. + +--- + +### GET **/getChaintip** + +Retrieves the current chain tip (the latest block height known to the node). + +#### **Request** + +- **Method:** `GET` +- **URL:** `/getChaintip` + +#### **Response** + +- **Content-Type:** `text/plain` +- **Body:** + + ``` + Chain tip: + ``` + + Where `` is the height of the latest block known to the SPV node. + +#### **Example** + +```bash +curl http://localhost:/getChaintip +``` + +#### **Sample Response** + +``` +Chain tip: 3500000 +``` + +--- + +## Additional Information + +- **Server Address:** Replace `` in the examples with the port number where your Libdogecoin SPV node is running. +- **Content Types:** + - Endpoints returning plain text data use `Content-Type: text/plain`. + - Endpoints returning binary data use `Content-Type: application/octet-stream`. +- **Security Considerations:** + - Sensitive endpoints like `/getWallet` expose critical data. + - Always safeguard your wallet file to prevent unauthorized access to your funds. + +## Usage Notes + +- **cURL:** The examples use `curl` for simplicity. You can use any HTTP node to interact with the API. +- **Error Handling:** If an endpoint encounters an error, it will respond with an appropriate HTTP status code and message. + - For example, if the wallet file is not found: + + ``` + HTTP/1.1 404 Not Found + Content-Type: text/plain + + Wallet file not found + ``` + +- **Concurrency:** The SPV node should handle multiple concurrent requests gracefully. However, ensure that shared resources like the wallet and UTXO set are managed in a thread-safe manner. + diff --git a/src/rest.c b/src/rest.c index 75cc7ae91..68b3a9d60 100644 --- a/src/rest.c +++ b/src/rest.c @@ -79,14 +79,14 @@ void dogecoin_http_request_cb(struct evhttp_request *req, void *arg) { dogecoin_mem_zero(wallet_total, 21); uint64_t wallet_total_u64 = 0; - if (HASH_COUNT(utxos) > 0) { + if (HASH_COUNT(wallet->utxos) > 0) { dogecoin_utxo* utxo; dogecoin_utxo* tmp; - HASH_ITER(hh, utxos, utxo, tmp) { + HASH_ITER(hh, wallet->utxos, utxo, tmp) { if (!utxo->spendable) { // For spent UTXOs evbuffer_add_printf(evb, "%s\n", "----------------------"); - evbuffer_add_printf(evb, "txid: %s\n", utils_uint8_to_hex(utxo->txid, sizeof utxo->txid)); + evbuffer_add_printf(evb, "txid: %s\n", utils_uint8_to_hex(utxo->txid, sizeof(utxo->txid))); evbuffer_add_printf(evb, "vout: %d\n", utxo->vout); evbuffer_add_printf(evb, "address: %s\n", utxo->address); evbuffer_add_printf(evb, "script_pubkey: %s\n", utxo->script_pubkey); @@ -146,15 +146,15 @@ void dogecoin_http_request_cb(struct evhttp_request *req, void *arg) { // Read the wallet file into a buffer char* buffer = malloc(file_size); if (buffer == NULL) { - fclose(file); evhttp_send_error(req, HTTP_INTERNAL, "Internal Server Error"); evbuffer_free(evb); return; } size_t result = fread(buffer, 1, file_size, file); - if (!result) { - evbuffer_free(evb); + if (result != file_size) { free(buffer); + evbuffer_free(evb); + evhttp_send_error(req, HTTP_INTERNAL, "Failed to read wallet file"); return; } @@ -184,15 +184,15 @@ void dogecoin_http_request_cb(struct evhttp_request *req, void *arg) { // Read the headers file into a buffer char* buffer = malloc(file_size); if (buffer == NULL) { - fclose(file); evhttp_send_error(req, HTTP_INTERNAL, "Internal Server Error"); evbuffer_free(evb); return; } size_t result = fread(buffer, 1, file_size, file); - if (!result) { - evbuffer_free(evb); + if (result != file_size) { free(buffer); + evbuffer_free(evb); + evhttp_send_error(req, HTTP_INTERNAL, "Failed to read headers file"); return; } @@ -213,7 +213,12 @@ void dogecoin_http_request_cb(struct evhttp_request *req, void *arg) { return; } - evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/plain"); + // Set Content-Type header if not already set + struct evkeyvalq* headers = evhttp_request_get_output_headers(req); + if (!evhttp_find_header(headers, "Content-Type")) { + evhttp_add_header(headers, "Content-Type", "text/plain"); + } + evhttp_send_reply(req, HTTP_OK, "OK", evb); evbuffer_free(evb); }