diff --git a/src/app/Bitcoin.cpp b/src/app/Bitcoin.cpp index e21aee9..f3bfb50 100644 --- a/src/app/Bitcoin.cpp +++ b/src/app/Bitcoin.cpp @@ -770,12 +770,12 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - uint64_t fetch_balance(const wallet::payment_address &address) { - uint64_t result = 0; + void fetch_balance(const wallet::payment_address &address, client::proxy::history_handler on_reply, + client::proxy::error_handler on_error, uint16_t timeout) { client::connection_type connection = {}; connection.retries = 0; - connection.timeout_seconds = 5; + connection.timeout_seconds = timeout; connection.server = config::endpoint(BitcoinConfig.endpoint); client::obelisk_client client(connection); @@ -784,19 +784,8 @@ namespace Apostol { throw Delphi::Exception::Exception(BX_CONNECTION_FAILURE, connection.server); } - auto on_reply = [&result](const history::list& rows) { - result = balancer(rows); - }; - - auto on_error = [](const code& error) { -// if (error != error::success) -// throw Delphi::Exception::ExceptionFrm("Failed to retrieve history: %s", message.c_str()); - }; - - client.blockchain_fetch_history3(on_error, on_reply, address); + client.blockchain_fetch_history3(std::move(on_error), std::move(on_reply), address); client.wait(); - - return result; } //-------------------------------------------------------------------------------------------------------------- @@ -847,10 +836,10 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void fetch_history(const wallet::payment_address &address, CJSON& Result) { + void fetch_history(const wallet::payment_address &address, CJSON& Result, uint16_t timeout) { client::connection_type connection = {}; connection.retries = 0; - connection.timeout_seconds = 5; + connection.timeout_seconds = timeout; connection.server = config::endpoint(BitcoinConfig.endpoint); client::obelisk_client client(connection); @@ -890,10 +879,10 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void fetch_header(uint32_t height, CJSON &Result) { + void fetch_header(uint32_t height, CJSON &Result, uint16_t timeout) { client::connection_type connection = {}; connection.retries = 0; - connection.timeout_seconds = 5; + connection.timeout_seconds = timeout; connection.server = config::endpoint(BitcoinConfig.endpoint); client::obelisk_client client(connection); @@ -915,10 +904,10 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void fetch_header(const hash_digest& hash, CJSON &Result) { + void fetch_header(const hash_digest& hash, CJSON &Result, uint16_t timeout) { client::connection_type connection = {}; connection.retries = 0; - connection.timeout_seconds = 5; + connection.timeout_seconds = timeout; connection.server = config::endpoint(BitcoinConfig.endpoint); client::obelisk_client client(connection); @@ -940,10 +929,10 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void send_tx(const chain::transaction& tx, CJSON& Result) { + void send_tx(const chain::transaction& tx, CJSON& Result, uint16_t timeout) { client::connection_type connection = {}; connection.retries = 0; - connection.timeout_seconds = 5; + connection.timeout_seconds = timeout; connection.server = config::endpoint(BitcoinConfig.endpoint); client::obelisk_client client(connection); @@ -966,7 +955,7 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void send_tx(const std::string &hex, CJSON &Result) { + void send_tx(const std::string &hex, CJSON &Result, uint16_t timeout) { chain::transaction tx; data_chunk data; @@ -976,7 +965,7 @@ namespace Apostol { if (!tx.from_data(data, true, true)) throw Delphi::Exception::Exception("Invalid transaction data."); - send_tx(tx, Result); + send_tx(tx, Result, timeout); } #endif // WITH_BITCOIN_CLIENT #endif // BITCOIN_VERSION_4 @@ -1163,6 +1152,11 @@ namespace Apostol { payment_address CWitness::to_address(uint8_t version) const { return payment_address(m_embedded, version); } + //-------------------------------------------------------------------------------------------------------------- + + std::string CWitness::to_witness(const std::string &hrp) const { + return SegWit::encode(hrp, 0, m_embedded.witness_program()); + } //-------------------------------------------------------------------------------------------------------------- diff --git a/src/app/Bitcoin.hpp b/src/app/Bitcoin.hpp index 25af8a2..0902d48 100644 --- a/src/app/Bitcoin.hpp +++ b/src/app/Bitcoin.hpp @@ -245,15 +245,16 @@ namespace Apostol { std::string script_to_address(const std::string &script, uint8_t version = payment_address::mainnet_p2sh); //-------------------------------------------------------------------------------------------------------------- #ifdef WITH_BITCOIN_CLIENT - uint64_t fetch_balance(const wallet::payment_address &address); + void fetch_balance(const wallet::payment_address &address, client::proxy::history_handler on_reply, + client::proxy::error_handler on_error, uint16_t timeout = 10); //-------------------------------------------------------------------------------------------------------------- - void fetch_history(const wallet::payment_address &address, CJSON& Result); - void fetch_header(uint32_t height, CJSON& Result); - void fetch_header(const hash_digest& hash, CJSON& Result); + void fetch_history(const wallet::payment_address &address, CJSON& Result, uint16_t timeout = 10); + void fetch_header(uint32_t height, CJSON& Result, uint16_t timeout = 10); + void fetch_header(const hash_digest& hash, CJSON& Result, uint16_t timeout = 10); - void send_tx(const chain::transaction& tx, CJSON& Result); - void send_tx(const std::string& hex, CJSON& Result); + void send_tx(const chain::transaction& tx, CJSON& Result, uint16_t timeout = 10); + void send_tx(const std::string& hex, CJSON& Result, uint16_t timeout = 10); //-------------------------------------------------------------------------------------------------------------- @@ -358,6 +359,7 @@ namespace Apostol { const chain::script& embedded() const {return m_embedded; }; payment_address to_address(uint8_t version = payment_address::mainnet_p2sh) const; + std::string to_witness(const std::string &hrp = "bc") const; const std::vector &secrets() const { return m_secrets; }; const std::vector &keys() const { return m_keys; }; diff --git a/src/app/Deal.cpp b/src/app/Deal.cpp index 8427092..04fae90 100644 --- a/src/app/Deal.cpp +++ b/src/app/Deal.cpp @@ -226,10 +226,10 @@ namespace Apostol { CDealType CDeal::StringToType(const CString &Value) { const auto &status = Value.Lower(); - if (status.Find("prepayment") != CString::npos || status.Find("prepaid") != CString::npos) { - return dtPrepaid; - } else if (status.Find("postpayment") != CString::npos || status.Find("postpaid") != CString::npos) { - return dtPostpaid; + if (status.Find("prepayment") != CString::npos) { + return dtPrepayment; + } else if (status.Find("postpayment") != CString::npos) { + return dtPostpayment; } else { throw ExceptionFrm(R"(Invalid order type value: "%s".)", status.c_str()); } @@ -238,9 +238,9 @@ namespace Apostol { CString CDeal::TypeToString(CDealType Type) { switch (Type) { - case dtPrepaid: + case dtPrepayment: return "Prepayment"; - case dtPostpaid: + case dtPostpayment: return "Postpayment"; default: return "Unknown"; @@ -249,9 +249,9 @@ namespace Apostol { //-------------------------------------------------------------------------------------------------------------- CString CDeal::TypeCodeToString(const CString &Code) { - if (Code == "prepaid.deal") { + if (Code == "prepayment.deal") { return {"Prepayment"}; - } else if (Code == "postpaid.deal") { + } else if (Code == "postpayment.deal") { return {"Postpayment"}; } else { throw ExceptionFrm(R"(Invalid type code value: "%s".)", Code.c_str()); @@ -366,9 +366,9 @@ namespace Apostol { //-------------------------------------------------------------------------------------------------------------- std::string CDeal::get_payment_hd(const std::string &key1, const std::string &key2, std::string &key3, - uint64_t version_key, uint8_t version_script) { + uint64_t prefixes, uint8_t version_script) { - CWitness Witness(ec_public(key1), ec_public(key2), key3.empty() ? to_public_hd(version_key) : ec_public(key3)); + CWitness Witness(ec_public(key1), ec_public(key2), key3.empty() ? to_public_hd(prefixes) : ec_public(key3)); if (key3.empty()) key3 = Witness.keys()[2].encoded(); @@ -379,6 +379,18 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- + std::string CDeal::get_payment_witness(const std::string &key1, const std::string &key2, std::string &key3, + uint64_t prefixes) { + + CWitness Witness(ec_public(key1), ec_public(key2), key3.empty() ? to_public_hd(prefixes) : ec_public(key3)); + + if (key3.empty()) + key3 = Witness.keys()[2].encoded(); + + return Witness.to_witness(prefixes == hd_private::mainnet ? "bc" : "tb"); + } + //-------------------------------------------------------------------------------------------------------------- + CString CDeal::GetPaymentEK(const CString &Key1, const CString &Key2, CString &Key3, uint8_t version_key, uint8_t version_script) { @@ -392,12 +404,24 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - CString CDeal::GetPaymentHD(const CString &Key1, const CString &Key2, CString &Key3, uint64_t version_key, - uint8_t version_script) { + CString CDeal::GetPaymentHD(const CString &Key1, const CString &Key2, CString &Key3, + uint64_t prefixes, uint8_t version_script) { std::string key3(Key3); - const auto& payment = get_payment_hd(Key1.c_str(), Key2.c_str(), key3, version_key, version_script); + const auto& payment = get_payment_hd(Key1.c_str(), Key2.c_str(), key3, prefixes, version_script); + + Key3 = key3; + + return payment; + } + //-------------------------------------------------------------------------------------------------------------- + + CString CDeal::GetPaymentSW(const CString &Key1, const CString &Key2, CString &Key3, uint64_t prefixes) { + + std::string key3(Key3); + + const auto& payment = get_payment_witness(Key1.c_str(), Key2.c_str(), key3, prefixes); Key3 = key3; diff --git a/src/app/Deal.hpp b/src/app/Deal.hpp index 4b679c3..98f4436 100644 --- a/src/app/Deal.hpp +++ b/src/app/Deal.hpp @@ -156,7 +156,7 @@ namespace Apostol { //-------------------------------------------------------------------------------------------------------------- - enum CDealType { dtPrepaid = 0, dtPostpaid }; + enum CDealType { dtPrepayment = 0, dtPostpayment }; //-------------------------------------------------------------------------------------------------------------- enum CFeedBackStatus { fsNegative = -1, fsNeutral = 0, fsPositive = 1 }; @@ -169,7 +169,7 @@ namespace Apostol { typedef struct DealData { CDealOrder Order = doCreate; - CDealType Type = dtPrepaid; + CDealType Type = dtPrepayment; // Hidden value CString Code {}; @@ -245,9 +245,12 @@ namespace Apostol { uint8_t version_script = payment_address::mainnet_p2sh); std::string get_payment_hd(const std::string &key1, const std::string &key2, std::string &key3, - uint64_t version_key = hd_private::mainnet, + uint64_t prefixes = hd_private::mainnet, uint8_t version_script = payment_address::mainnet_p2sh); + std::string get_payment_witness(const std::string &key1, const std::string &key2, std::string &key3, + uint64_t prefixes = hd_private::mainnet); + public: CDeal(); @@ -264,9 +267,12 @@ namespace Apostol { uint8_t version_script = payment_address::mainnet_p2sh); CString GetPaymentHD(const CString &Key1, const CString &Key2, CString &Key3, - uint64_t version_key = hd_private::mainnet, + uint64_t prefixes = hd_private::mainnet, uint8_t version_script = payment_address::mainnet_p2sh); + CString GetPaymentSW(const CString &Key1, const CString &Key2, CString &Key3, + uint64_t prefixes = hd_private::mainnet); + static CDealOrder StringToOrder(const CString &Value); static CString OrderToString(CDealOrder Order); diff --git a/src/modules/Workers/WebService/WebService.cpp b/src/modules/Workers/WebService/WebService.cpp index ad0ff48..dc87387 100644 --- a/src/modules/Workers/WebService/WebService.cpp +++ b/src/modules/Workers/WebService/WebService.cpp @@ -768,8 +768,11 @@ namespace Apostol { auto& Data = Deal.Data(); if (Data.Order == doCreate) { - Data.Payment.Address = Deal.GetPaymentHD(BTCKeys.Names(0), BTCKeys.Names(1), - Deal.Data().Transaction.Key, BitcoinConfig.version_hd, BitcoinConfig.version_script); + const auto isSegWit = IsSegWitAddress(Data.Seller.Address) && IsSegWitAddress(Data.Customer.Address); + + Data.Payment.Address = isSegWit ? + Deal.GetPaymentSW(BTCKeys.Names(0), BTCKeys.Names(1), Deal.Data().Transaction.Key, BitcoinConfig.version_hd) : + Deal.GetPaymentHD(BTCKeys.Names(0), BTCKeys.Names(1), Deal.Data().Transaction.Key, BitcoinConfig.version_hd, BitcoinConfig.version_script); Node["deal"]["date"] = Data.Date.c_str(); diff --git a/src/modules/Workers/WebSocket/WebSocket.cpp b/src/modules/Workers/WebSocket/WebSocket.cpp index 788b2b4..a565e28 100644 --- a/src/modules/Workers/WebSocket/WebSocket.cpp +++ b/src/modules/Workers/WebSocket/WebSocket.cpp @@ -895,8 +895,11 @@ namespace Apostol { auto& Data = Deal.Data(); if (Data.Order == doCreate) { - Data.Payment.Address = Deal.GetPaymentHD(BTCKeys.Names(0), BTCKeys.Names(1), - Deal.Data().Transaction.Key, BitcoinConfig.version_hd, BitcoinConfig.version_script); + const auto isSegWit = IsSegWitAddress(Data.Seller.Address) && IsSegWitAddress(Data.Customer.Address); + + Data.Payment.Address = isSegWit ? + Deal.GetPaymentSW(BTCKeys.Names(0), BTCKeys.Names(1), Deal.Data().Transaction.Key, BitcoinConfig.version_hd) : + Deal.GetPaymentHD(BTCKeys.Names(0), BTCKeys.Names(1), Deal.Data().Transaction.Key, BitcoinConfig.version_hd, BitcoinConfig.version_script); Node["deal"]["date"] = Data.Date.c_str();