diff --git a/src/api/ApiServer.cpp b/src/api/ApiServer.cpp index 494a3518..dbe027dc 100644 --- a/src/api/ApiServer.cpp +++ b/src/api/ApiServer.cpp @@ -18,6 +18,8 @@ #include "controller/path/block.hpp" #include "controller/path/block/identifier.hpp" #include "controller/path/block/height.hpp" +#include "controller/path/block/template.hpp" +#include "controller/path/block/submit.hpp" #include "controller/path/info/version.hpp" #include "oatpp/network/Server.hpp" @@ -82,6 +84,14 @@ void ApiServer::run() { docEndpoints->append(blockController->getEndpoints()); router->addController(blockController); + auto blockTemplateController = std::make_shared(); + docEndpoints->append(blockTemplateController->getEndpoints()); + router->addController(blockTemplateController); + + auto blockSubmitController = std::make_shared(); + docEndpoints->append(blockSubmitController->getEndpoints()); + router->addController(blockSubmitController); + auto blockHeightController = std::make_shared(); docEndpoints->append(blockHeightController->getEndpoints()); router->addController(blockHeightController); diff --git a/src/api/controller/path/block/submit.hpp b/src/api/controller/path/block/submit.hpp new file mode 100644 index 00000000..30a6e512 --- /dev/null +++ b/src/api/controller/path/block/submit.hpp @@ -0,0 +1,75 @@ +// Copyright (c) 2017-2025 Lethean (https://lt.hn) +// +// Licensed under the European Union Public Licence (EUPL) version 1.2. +// You may obtain a copy of the licence at: +// +// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl +// +// The EUPL is a copyleft licence that is compatible with the MIT/X11 +// licence used by the original projects; but maintains OSS status, +// where regional copyright law requires ownership to dictate licence terms. +// +// SPDX‑License‑Identifier: EUPL-1.2 +// + +#ifndef BlockSubmitController_hpp +#define BlockSubmitController_hpp + +#include "oatpp/web/server/api/ApiController.hpp" +#include "oatpp/core/macro/codegen.hpp" +#include "controller/ApiCoreInfo.hpp" +#include "modal/block/submit_request.hpp" +#include "modal/block/submit_response.hpp" +#include "currency_core/currency_format_utils.h" +#include "currency_core/verification_context.h" + +#include OATPP_CODEGEN_BEGIN(ApiController) + +class BlockSubmitController : public oatpp::web::server::api::ApiController { +private: + OATPP_COMPONENT(std::shared_ptr, m_core_info); +public: + explicit BlockSubmitController(OATPP_COMPONENT(std::shared_ptr, objectMapper)) + : oatpp::web::server::api::ApiController(objectMapper) {} +public: + + ENDPOINT_INFO(submitBlock) { + info->summary = "Submit a new block to the network"; + info->addTag("Block"); + info->addConsumes>("application/json"); + info->addResponse>(Status::CODE_200, "application/json"); + info->addResponse(Status::CODE_400, "text/plain"); + info->addResponse(Status::CODE_406, "text/plain"); + } + ENDPOINT("POST", "/block/submit", submitBlock, BODY_DTO(Object, requestModel)) { + if (!requestModel->block_blob || requestModel->block_blob->empty()) { + return createResponse(Status::CODE_400, "Missing block_blob"); + } + + currency::blobdata blockblob; + if (!epee::string_tools::parse_hexstr_to_binbuff(*requestModel->block_blob, blockblob)) { + return createResponse(Status::CODE_400, "Wrong block blob"); + } + + currency::block b = AUTO_VAL_INIT(b); + if (!currency::parse_and_validate_block_from_blob(blockblob, b)) { + return createResponse(Status::CODE_400, "Wrong block blob"); + } + + currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); + if (!m_core_info->getCore().handle_block_found(b, &bvc)) { + if (bvc.m_added_to_altchain) { + return createResponse(Status::CODE_406, "Block added as alternative"); + } + return createResponse(Status::CODE_406, "Block not accepted"); + } + + auto responseModel = SubmitBlockResponseModel::createShared(); + responseModel->status = "OK"; + return createDtoResponse(Status::CODE_200, responseModel); + } +}; + +#include OATPP_CODEGEN_END(ApiController) + +#endif /* BlockSubmitController_hpp */ diff --git a/src/api/controller/path/block/template.hpp b/src/api/controller/path/block/template.hpp new file mode 100644 index 00000000..1fd62abe --- /dev/null +++ b/src/api/controller/path/block/template.hpp @@ -0,0 +1,104 @@ +// Copyright (c) 2017-2025 Lethean (https://lt.hn) +// +// Licensed under the European Union Public Licence (EUPL) version 1.2. +// You may obtain a copy of the licence at: +// +// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl +// +// The EUPL is a copyleft licence that is compatible with the MIT/X11 +// licence used by the original projects; but maintains OSS status, +// where regional copyright law requires ownership to dictate licence terms. +// +// SPDX‑License‑Identifier: EUPL-1.2 +// + +#ifndef BlockTemplateController_hpp +#define BlockTemplateController_hpp + +#include "oatpp/web/server/api/ApiController.hpp" +#include "oatpp/core/macro/codegen.hpp" +#include "controller/ApiCoreInfo.hpp" +#include "modal/block/template_request.hpp" +#include "modal/block/template.hpp" +#include "currency_core/currency_format_utils.h" + +#include OATPP_CODEGEN_BEGIN(ApiController) + +class BlockTemplateController : public oatpp::web::server::api::ApiController { +private: + OATPP_COMPONENT(std::shared_ptr, m_core_info); +public: + explicit BlockTemplateController(OATPP_COMPONENT(std::shared_ptr, objectMapper)) + : oatpp::web::server::api::ApiController(objectMapper) {} +public: + + ENDPOINT_INFO(createBlockTemplate) { + info->summary = "Create a block template for mining"; + info->addTag("Block"); + info->addConsumes>("application/json"); + info->addResponse>(Status::CODE_200, "application/json"); + info->addResponse(Status::CODE_400, "text/plain"); + info->addResponse(Status::CODE_500, "text/plain"); + } + ENDPOINT("POST", "/block/template", createBlockTemplate, BODY_DTO(Object, requestModel)) { + currency::create_block_template_params params = AUTO_VAL_INIT(params); + + if (!currency::get_account_address_from_str(params.miner_address, *requestModel->miner_address)) { + return createResponse(Status::CODE_400, "Failed to parse miner_address"); + } + if (requestModel->stakeholder_address && !currency::get_account_address_from_str(params.stakeholder_address, *requestModel->stakeholder_address)) { + return createResponse(Status::CODE_400, "Failed to parse stakeholder_address"); + } + + params.ex_nonce = requestModel->ex_nonce ? *requestModel->ex_nonce : ""; + params.pos = requestModel->pos; + params.ignore_pow_ts_check = requestModel->ignore_pow_ts_check; + + if (requestModel->pe) { + params.pe.amount = requestModel->pe->amount; + params.pe.g_index = requestModel->pe->g_index; + epee::string_tools::hex_to_pod(*requestModel->pe->keyimage, params.pe.keyimage); + params.pe.block_timestamp = requestModel->pe->block_timestamp; + params.pe.stake_unlock_time = requestModel->pe->stake_unlock_time; + epee::string_tools::hex_to_pod(*requestModel->pe->tx_id, params.pe.tx_id); + params.pe.tx_out_index = requestModel->pe->tx_out_index; + params.pe.wallet_index = requestModel->pe->wallet_index; + } + + for (const auto& tx_hex : *requestModel->explicit_txs) { + currency::transaction tx; + currency::blobdata tx_blob; + if (!epee::string_tools::parse_hexstr_to_binbuff(*tx_hex, tx_blob) || !currency::parse_and_validate_tx_from_blob(tx_blob, tx)) { + return createResponse(Status::CODE_400, "Failed to parse explicit_txs"); + } + params.explicit_txs.push_back(tx); + } + + currency::create_block_template_response response = AUTO_VAL_INIT(response); + if (!m_core_info->getCore().get_block_template(params, response)) { + return createResponse(Status::CODE_500, "Internal error: failed to create block template"); + } + + auto model = BlockTemplateModel::createShared(); + model->blocktemplate_blob = epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(response.b)); + model->difficulty = response.diffic.convert_to(); + model->height = response.height; + model->block_reward_without_fee = response.block_reward_without_fee; + model->block_reward = response.block_reward; + model->txs_fee = response.txs_fee; + model->prev_hash = epee::string_tools::pod_to_hex(response.b.prev_id); + model->seed = epee::string_tools::pod_to_hex(currency::ethash_epoch_to_seed(currency::ethash_height_to_epoch(response.height))); + + auto tgc_model = TxGenerationContextModel::createShared(); + // This is a very complex object with many cryptographic details. + // For now, we will leave it empty as it's not essential for basic mining. + // A dedicated endpoint could be created later to expose this if needed. + model->miner_tx_tgc = tgc_model; + + return createDtoResponse(Status::CODE_200, model); + } +}; + +#include OATPP_CODEGEN_END(ApiController) + +#endif /* BlockTemplateController_hpp */ diff --git a/src/api/modal/block/submit_request.hpp b/src/api/modal/block/submit_request.hpp new file mode 100644 index 00000000..2f055a6c --- /dev/null +++ b/src/api/modal/block/submit_request.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2017-2025 Lethean (https://lt.hn) +// +// Licensed under the European Union Public Licence (EUPL) version 1.2. +// You may obtain a copy of the licence at: +// +// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl +// +// The EUPL is a copyleft licence that is compatible with the MIT/X11 +// licence used by the original projects; but maintains OSS status, +// where regional copyright law requires ownership to dictate licence terms. +// +// SPDX‑License‑Identifier: EUPL-1.2 +// + +#ifndef SubmitBlockRequestModel_hpp +#define SubmitBlockRequestModel_hpp + +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/Types.hpp" + +#include OATPP_CODEGEN_BEGIN(DTO) + +class SubmitBlockRequestModel final : public oatpp::DTO +{ + DTO_INIT(SubmitBlockRequestModel, DTO); + + DTO_FIELD(String, block_blob); +}; + +#include OATPP_CODEGEN_END(DTO) + +#endif /* SubmitBlockRequestModel_hpp */ diff --git a/src/api/modal/block/submit_response.hpp b/src/api/modal/block/submit_response.hpp new file mode 100644 index 00000000..9b227783 --- /dev/null +++ b/src/api/modal/block/submit_response.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2017-2025 Lethean (https://lt.hn) +// +// Licensed under the European Union Public Licence (EUPL) version 1.2. +// You may obtain a copy of the licence at: +// +// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl +// +// The EUPL is a copyleft licence that is compatible with the MIT/X11 +// licence used by the original projects; but maintains OSS status, +// where regional copyright law requires ownership to dictate licence terms. +// +// SPDX‑License‑Identifier: EUPL-1.2 +// + +#ifndef SubmitBlockResponseModel_hpp +#define SubmitBlockResponseModel_hpp + +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/Types.hpp" + +#include OATPP_CODEGEN_BEGIN(DTO) + +class SubmitBlockResponseModel final : public oatpp::DTO +{ + DTO_INIT(SubmitBlockResponseModel, DTO); + + DTO_FIELD(String, status); +}; + +#include OATPP_CODEGEN_END(DTO) + +#endif /* SubmitBlockResponseModel_hpp */ diff --git a/src/api/modal/block/template.hpp b/src/api/modal/block/template.hpp new file mode 100644 index 00000000..61b29ce5 --- /dev/null +++ b/src/api/modal/block/template.hpp @@ -0,0 +1,41 @@ +// Copyright (c) 2017-2025 Lethean (https://lt.hn) +// +// Licensed under the European Union Public Licence (EUPL) version 1.2. +// You may obtain a copy of the licence at: +// +// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl +// +// The EUPL is a copyleft licence that is compatible with the MIT/X11 +// licence used by the original projects; but maintains OSS status, +// where regional copyright law requires ownership to dictate licence terms. +// +// SPDX‑License‑Identifier: EUPL-1.2 +// + +#ifndef BlockTemplateModel_hpp +#define BlockTemplateModel_hpp + +#include "../meta/tx_generation_context.hpp" +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/Types.hpp" + +#include OATPP_CODEGEN_BEGIN(DTO) + +class BlockTemplateModel final : public oatpp::DTO +{ + DTO_INIT(BlockTemplateModel, DTO); + + DTO_FIELD(String, blocktemplate_blob); + DTO_FIELD(String, difficulty); + DTO_FIELD(UInt64, height); + DTO_FIELD(Object, miner_tx_tgc); + DTO_FIELD(UInt64, block_reward_without_fee); + DTO_FIELD(UInt64, block_reward); + DTO_FIELD(UInt64, txs_fee); + DTO_FIELD(String, prev_hash); + DTO_FIELD(String, seed); +}; + +#include OATPP_CODEGEN_END(DTO) + +#endif /* BlockTemplateModel_hpp */ diff --git a/src/api/modal/block/template_request.hpp b/src/api/modal/block/template_request.hpp new file mode 100644 index 00000000..fd3e8131 --- /dev/null +++ b/src/api/modal/block/template_request.hpp @@ -0,0 +1,39 @@ +// Copyright (c) 2017-2025 Lethean (https://lt.hn) +// +// Licensed under the European Union Public Licence (EUPL) version 1.2. +// You may obtain a copy of the licence at: +// +// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl +// +// The EUPL is a copyleft licence that is compatible with the MIT/X11 +// licence used by the original projects; but maintains OSS status, +// where regional copyright law requires ownership to dictate licence terms. +// +// SPDX‑License‑Identifier: EUPL-1.2 +// + +#ifndef BlockTemplateRequestModel_hpp +#define BlockTemplateRequestModel_hpp + +#include "../meta/pos_entry.hpp" +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/Types.hpp" + +#include OATPP_CODEGEN_BEGIN(DTO) + +class BlockTemplateRequestModel final : public oatpp::DTO +{ + DTO_INIT(BlockTemplateRequestModel, DTO); + + DTO_FIELD(String, miner_address); + DTO_FIELD(String, stakeholder_address); + DTO_FIELD(String, ex_nonce); + DTO_FIELD(Boolean, pos, "pos_block"); + DTO_FIELD(Boolean, ignore_pow_ts_check); + DTO_FIELD(Object, pe); + DTO_FIELD(List, explicit_txs); +}; + +#include OATPP_CODEGEN_END(DTO) + +#endif /* BlockTemplateRequestModel_hpp */ diff --git a/src/api/modal/meta/pos_entry.hpp b/src/api/modal/meta/pos_entry.hpp new file mode 100644 index 00000000..ede3a71b --- /dev/null +++ b/src/api/modal/meta/pos_entry.hpp @@ -0,0 +1,39 @@ +// Copyright (c) 2017-2025 Lethean (https://lt.hn) +// +// Licensed under the European Union Public Licence (EUPL) version 1.2. +// You may obtain a copy of the licence at: +// +// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl +// +// The EUPL is a copyleft licence that is compatible with the MIT/X11 +// licence used by the original projects; but maintains OSS status, +// where regional copyright law requires ownership to dictate licence terms. +// +// SPDX‑License‑Identifier: EUPL-1.2 +// + +#ifndef PosEntryModel_hpp +#define PosEntryModel_hpp + +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/Types.hpp" + +#include OATPP_CODEGEN_BEGIN(DTO) + +class PosEntryModel final : public oatpp::DTO +{ + DTO_INIT(PosEntryModel, DTO); + + DTO_FIELD(UInt64, amount); + DTO_FIELD(UInt64, g_index); + DTO_FIELD(String, keyimage); + DTO_FIELD(UInt64, block_timestamp); + DTO_FIELD(UInt64, stake_unlock_time); + DTO_FIELD(String, tx_id); + DTO_FIELD(UInt64, tx_out_index); + DTO_FIELD(UInt64, wallet_index); +}; + +#include OATPP_CODEGEN_END(DTO) + +#endif /* PosEntryModel_hpp */ diff --git a/src/api/modal/meta/tx_generation_context.hpp b/src/api/modal/meta/tx_generation_context.hpp new file mode 100644 index 00000000..d7d00b12 --- /dev/null +++ b/src/api/modal/meta/tx_generation_context.hpp @@ -0,0 +1,55 @@ +// Copyright (c) 2017-2025 Lethean (https://lt.hn) +// +// Licensed under the European Union Public Licence (EUPL) version 1.2. +// You may obtain a copy of the licence at: +// +// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl +// +// The EUPL is a copyleft licence that is compatible with the MIT/X11 +// licence used by the original projects; but maintains OSS status, +// where regional copyright law requires ownership to dictate licence terms. +// +// SPDX‑License‑Identifier: EUPL-1.2 +// + +#ifndef TxGenerationContextModel_hpp +#define TxGenerationContextModel_hpp + +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/Types.hpp" + +#include OATPP_CODEGEN_BEGIN(DTO) + +class TxGenerationContextModel final : public oatpp::DTO +{ + DTO_INIT(TxGenerationContextModel, DTO); + + DTO_FIELD(List, asset_ids); + DTO_FIELD(List, blinded_asset_ids); + DTO_FIELD(List, amount_commitments); + DTO_FIELD(List, asset_id_blinding_masks); + DTO_FIELD(List, amounts); + DTO_FIELD(List, amount_blinding_masks); + DTO_FIELD(List, pseudo_outs_blinded_asset_ids); + DTO_FIELD(List, pseudo_outs_plus_real_out_blinding_masks); + DTO_FIELD(List, real_zc_ins_asset_ids); + DTO_FIELD(List, zc_input_amounts); + DTO_FIELD(String, pseudo_out_amount_commitments_sum); + DTO_FIELD(String, pseudo_out_amount_blinding_masks_sum); + DTO_FIELD(String, real_in_asset_id_blinding_mask_x_amount_sum); + DTO_FIELD(String, amount_commitments_sum); + DTO_FIELD(String, amount_blinding_masks_sum); + DTO_FIELD(String, asset_id_blinding_mask_x_amount_sum); + DTO_FIELD(String, ao_asset_id); + DTO_FIELD(String, ao_asset_id_pt); + DTO_FIELD(String, ao_amount_commitment); + DTO_FIELD(String, ao_amount_blinding_mask); + DTO_FIELD(Boolean, ao_commitment_in_outputs); + DTO_FIELD(String, tx_key_pub); + DTO_FIELD(String, tx_key_sec); + DTO_FIELD(String, tx_pub_key_p); +}; + +#include OATPP_CODEGEN_END(DTO) + +#endif /* TxGenerationContextModel_hpp */ diff --git a/src/api/modal/transaction/send_request.hpp b/src/api/modal/transaction/send_request.hpp new file mode 100644 index 00000000..3afb8e5e --- /dev/null +++ b/src/api/modal/transaction/send_request.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2017-2025 Lethean (https://lt.hn) +// +// Licensed under the European Union Public Licence (EUPL) version 1.2. +// You may obtain a copy of the licence at: +// +// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl +// +// The EUPL is a copyleft licence that is compatible with the MIT/X11 +// licence used by the original projects; but maintains OSS status, +// where regional copyright law requires ownership to dictate licence terms. +// +// SPDX‑License‑Identifier: EUPL-1.2 +// + +#ifndef SendTransactionRequestModel_hpp +#define SendTransactionRequestModel_hpp + +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/Types.hpp" + +#include OATPP_CODEGEN_BEGIN(DTO) + +class SendTransactionRequestModel final : public oatpp::DTO +{ + DTO_INIT(SendTransactionRequestModel, DTO); + + DTO_FIELD(String, tx_as_hex); +}; + +#include OATPP_CODEGEN_END(DTO) + +#endif /* SendTransactionRequestModel_hpp */ diff --git a/src/api/modal/transaction/send_response.hpp b/src/api/modal/transaction/send_response.hpp new file mode 100644 index 00000000..203d8fac --- /dev/null +++ b/src/api/modal/transaction/send_response.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2017-2025 Lethean (https://lt.hn) +// +// Licensed under the European Union Public Licence (EUPL) version 1.2. +// You may obtain a copy of the licence at: +// +// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl +// +// The EUPL is a copyleft licence that is compatible with the MIT/X11 +// licence used by the original projects; but maintains OSS status, +// where regional copyright law requires ownership to dictate licence terms. +// +// SPDX‑License‑Identifier: EUPL-1.2 +// + +#ifndef SendTransactionResponseModel_hpp +#define SendTransactionResponseModel_hpp + +#include "oatpp/core/macro/codegen.hpp" +#include "oatpp/core/Types.hpp" + +#include OATPP_CODEGEN_BEGIN(DTO) + +class SendTransactionResponseModel final : public oatpp::DTO +{ + DTO_INIT(SendTransactionResponseModel, DTO); + + DTO_FIELD(String, status); +}; + +#include OATPP_CODEGEN_END(DTO) + +#endif /* SendTransactionResponseModel_hpp */