Files
apostol-dm/src/app/Bitcoin.hpp
Преподобный Ален fd95cdd315 Committing updates.
2022-09-23 23:20:18 +03:00

736 lines
27 KiB
C++

/*++
Module Name:
Bitcoin.hpp
Notices:
Bitcoin library
Author:
Copyright (c) Prepodobny Alen
mailto: alienufo@inbox.ru
mailto: ufocomp@gmail.com
--*/
#ifndef APOSTOL_BITCOIN_HPP
#define APOSTOL_BITCOIN_HPP
#ifdef BITCOIN_VERSION_4
//#include <bitcoin/system.hpp>
#include <bitcoin/system/formats/base_10.hpp>
#include <bitcoin/system/formats/base_16.hpp>
#include <bitcoin/system/formats/base_32.hpp>
#include <bitcoin/system/formats/base_58.hpp>
#include <bitcoin/system/formats/base_64.hpp>
#include <bitcoin/system/formats/base_85.hpp>
#include <bitcoin/system/config/base16.hpp>
#include <bitcoin/system/wallet/message.hpp>
#include <bitcoin/system/wallet/payment_address.hpp>
#include <bitcoin/system/wallet/witness_address.hpp>
#include <bitcoin/system/wallet/ek_token.hpp>
#include <bitcoin/system/wallet/ek_public.hpp>
#include <bitcoin/system/wallet/encrypted_keys.hpp>
#include <bitcoin/system/config/script.hpp>
#include <bitcoin/client/history.hpp>
#include <bitcoin/client/stealth.hpp>
using namespace bc;
using namespace bc::system;
using namespace bc::system::config;
using namespace bc::system::wallet;
using namespace bc::client;
#else
#ifdef BITCOIN_VERSION_3_7_x
#include <bitcoin/system.hpp>
#else
#include <bitcoin/bitcoin.hpp>
#endif
#include <bitcoin/protocol.hpp>
#include <bitcoin/client/define.hpp>
#include <bitcoin/client/obelisk_client.hpp>
#include <bitcoin/client/version.hpp>
using namespace bc;
using namespace bc::chain;
using namespace bc::machine;
using namespace bc::config;
using namespace bc::wallet;
using namespace bc::client;
#endif
//----------------------------------------------------------------------------------------------------------------------
#define BX_EK_PUBLIC_TO_EC_INVALID_PASSPHRASE \
"The passphrase is incorrect."
#define BX_EK_ADDRESS_SHORT_SEED \
"The seed is less than 192 bits long."
#define BX_TOKEN_NEW_SHORT_SALT \
"The salt is less than 32 bits long."
#define BX_TOKEN_NEW_REQUIRES_ICU \
"The command requires an ICU build."
#define BX_CONNECTION_FAILURE \
"Could not connect to server: %1%"
#define BX_HD_NEW_SHORT_SEED \
"The seed is less than 128 bits long."
#define BX_HD_NEW_INVALID_KEY \
"The seed produced an invalid key."
//----------------------------------------------------------------------------------------------------------------------
#define BX_NO_TRANSFERS_FOUND "No transfers found on account: %s."
#define BX_INVALID_SECRET_KEY_COUNT "Invalid count of secret keys (2 or 3 expected)."
#define BX_INSUFFICIENT_FUNDS "Insufficient funds on account: %s."
#define BX_INSUFFICIENT_FEE "Insufficient transaction fee on account: %s."
//----------------------------------------------------------------------------------------------------------------------
/**
* The minimum safe length of a seed in bits (multiple of 8).
*/
BC_CONSTEXPR size_t minimum_seed_bits = 128;
/**
* The minimum safe length of a seed in bytes (16).
*/
BC_CONSTEXPR size_t minimum_seed_size = minimum_seed_bits / bc::byte_bits;
//----------------------------------------------------------------------------------------------------------------------
extern "C++" {
namespace Apostol {
namespace Bech32
{
/** Encode a Bech32 string. Returns the empty string in case of failure. */
std::string encode(const std::string& hrp, const std::vector<uint8_t>& values);
/** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */
std::pair<std::string, std::vector<uint8_t> > decode(const std::string& str);
}
namespace SegWit
{
/** Decode a SegWit address. Returns (witver, witprog). witver = -1 means failure. */
std::pair<int, std::vector<uint8_t> > decode(const std::string& hrp, const std::string& addr);
/** Encode a SegWit address. Empty string means failure. */
std::string encode(const std::string& hrp, int witver, const std::vector<uint8_t>& witprog);
uint32_t checksum(const std::string& hrp, int witver, const std::vector<uint8_t>& witprog);
}
namespace Bitcoin {
typedef TList<ec_private> CPrivateList;
//--------------------------------------------------------------------------------------------------------------
struct CTransactionFee {
CString Fee;
uint_t min;
uint_t max;
};
struct CBitcoinConfig {
std::string endpoint = "tcp://mainnet.libbitcoin.net:9091";
uint64_t version_hd = hd_private::mainnet;
uint16_t version_ec = ec_private::mainnet;
uint8_t version_key = payment_address::mainnet_p2kh;
uint8_t version_script = payment_address::mainnet_p2sh;
CTransactionFee Miner {"1%", 200, 2000};
uint_t min_output = 200;
CString Symbol = "BTC";
};
//--------------------------------------------------------------------------------------------------------------
extern CBitcoinConfig BitcoinConfig;
//--------------------------------------------------------------------------------------------------------------
enum CAddressDecodeType { adtInfo, adtHtml, adtJson };
std::string string_to_hex(const std::string& input);
std::string hex_to_string(const std::string& input);
//--------------------------------------------------------------------------------------------------------------
std::string sha1(const std::string &value);
CString sha1(const CString &Value);
//--------------------------------------------------------------------------------------------------------------
std::string sha256(const std::string &value);
CString sha256(const CString &Value);
//--------------------------------------------------------------------------------------------------------------
std::string ripemd160(const std::string &value);
CString ripemd160(const CString &Value);
//--------------------------------------------------------------------------------------------------------------
double satoshi_to_btc(uint64_t Value);
uint64_t btc_to_satoshi(double Value);
//--------------------------------------------------------------------------------------------------------------
bool valid_address(const CString& Address);
//--------------------------------------------------------------------------------------------------------------
bool valid_public_key(const std::string& key);
bool valid_public_key(const CString& Key);
//--------------------------------------------------------------------------------------------------------------
bool key_belongs_address(const std::string& key, const std::string& address);
bool key_belongs_address(const CString& Key, const CString& Address);
//--------------------------------------------------------------------------------------------------------------
bool address_decode(CAddressDecodeType type, const CString& Address, CString& Result);
//--------------------------------------------------------------------------------------------------------------
bool address_decode(const CString& Address, CJSON& Result);
bool address_decode(const CString& Address, CString& Result);
//--------------------------------------------------------------------------------------------------------------
bool unwrap_legacy(wallet::wrapped_data &data, const wallet::payment_address &address);
bool unwrap_legacy(wallet::wrapped_data &data, const std::string &address);
//--------------------------------------------------------------------------------------------------------------
bool unwrap_segwit(wallet::wrapped_data &data, const std::string &address);
//--------------------------------------------------------------------------------------------------------------
bool IsLegacyAddress(const std::string& address);
bool IsLegacyAddress(const CString& Address);
bool IsSegWitAddress(const std::string& addr);
bool IsSegWitAddress(const CString& Addr);
bool IsBitcoinAddress(const std::string& addr);
bool IsBitcoinAddress(const CString& Addr);
//--------------------------------------------------------------------------------------------------------------
wallet::ek_token token_new(const std::string &passphrase, const data_chunk& salt);
wallet::ek_public ek_public(const wallet::ek_token &token, const data_chunk& seed, uint8_t version = payment_address::mainnet_p2kh);
wallet::ec_public ek_public_to_ec(const std::string &passphrase, const wallet::ek_public &key);
wallet::payment_address ek_address(const wallet::ek_token &token, const data_chunk& seed, uint8_t version = payment_address::mainnet_p2kh);
//--------------------------------------------------------------------------------------------------------------
wallet::hd_private hd_new(const data_chunk& seed, uint64_t prefixes = hd_private::mainnet);
wallet::ec_private hd_to_ec_private(const wallet::hd_key& key, uint64_t prefixes = hd_private::mainnet);
wallet::ec_public hd_to_ec_public(const wallet::hd_key& key, uint32_t prefix = hd_public::mainnet);
//--------------------------------------------------------------------------------------------------------------
bool verify_message(const std::string& msg, const std::string& addr, const std::string& sig);
bool VerifyMessage(const CString& Message, const CString& Address, const CString& Signature);
//--------------------------------------------------------------------------------------------------------------
#ifdef BITCOIN_VERSION_4
std::string address_to_key(const wallet::payment_address &address);
#endif
chain::script get_witness_script(const ec_public& key1, const ec_public& key2, const ec_public& key3);
chain::script get_redeem_script(const ec_public& key1, const ec_public& key2, const ec_public& key3);
std::string script_to_address(const chain::script &script, uint8_t version = payment_address::mainnet_p2sh);
std::string script_to_address(const std::string &script, uint8_t version = payment_address::mainnet_p2sh);
//--------------------------------------------------------------------------------------------------------------
#ifdef WITH_BITCOIN_CLIENT
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, 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, uint16_t timeout = 10);
void send_tx(const std::string& hex, CJSON& Result, uint16_t timeout = 10);
//--------------------------------------------------------------------------------------------------------------
//-- CBalance --------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
class CBalance {
private:
uint32_t m_Transfers;
uint32_t m_Height;
uint32_t m_Received;
uint32_t m_Spent;
CDateTime m_TimeStamp;
protected:
CJSON m_History;
CJSON m_Header;
public:
CBalance() {
m_Transfers = 0;
m_Height = 0;
m_Received = 0;
m_Spent = 0;
m_TimeStamp = 0;
}
void Clear();
void Fetch(const CString &Address);
const CJSON &History() const { return m_History; };
const CJSON &Header() const { return m_Header; };
uint32_t Transfers() const { return m_Transfers; }
uint32_t Height() const { return m_Height; }
CDateTime TimeStamp() const { return m_TimeStamp; }
uint32_t Received() const { return m_Received; }
uint32_t Spent() const { return m_Spent; }
uint32_t Balance() const {
return m_Received - m_Spent;
}
};
#endif
//--------------------------------------------------------------------------------------------------------------
//-- CWitness --------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
class CWitness {
private:
std::vector<ec_private> m_secrets;
std::vector<ec_public> m_keys;
uint8_t m_signatures;
hash_digest m_hash;
chain::script m_script;
chain::script m_embedded;
void bind_script();
void bind_embedded();
public:
CWitness();
explicit CWitness(uint8_t signatures);
CWitness(const ec_private& key1, const ec_private& key2);
CWitness(const ec_private& key1, const ec_private& key2, const ec_private& key3);
CWitness(const ec_private& key1, const ec_private& key2, const ec_public& key3);
CWitness(const ec_private& key1, const ec_private& key2, const ec_private& key3, const ec_public& key4);
CWitness(const ec_public& key1, const ec_public& key2, const ec_public& key3);
void make(const ec_private& key1, const ec_private& key2);
void make(const ec_private& key1, const ec_private& key2, const ec_private& key3);
void make(const ec_private& key1, const ec_private& key2, const ec_public& key3);
void make(const ec_private& key1, const ec_private& key2, const ec_private& key3, const ec_public& key4);
void make(const ec_public& key1, const ec_public& key2, const ec_public& key3);
void bind();
const hash_digest& hash() const;
const chain::script& script() const { return m_script; };
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<ec_private> &secrets() const { return m_secrets; };
const std::vector<ec_public> &keys() const { return m_keys; };
};
//--------------------------------------------------------------------------------------------------------------
//-- CRecipient ------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
typedef struct CRecipient {
CString Address {};
uint64_t Amount;
CRecipient() {
Amount = 0;
}
CRecipient(const CRecipient &Other) {
if (this != &Other) {
this->Address = Other.Address;
this->Amount = Other.Amount;
}
};
CRecipient(const CString &Address, uint64_t Amount) {
this->Address = Address;
this->Amount = Amount;
}
CRecipient &operator=(const CRecipient &Other) {
if (this != &Other) {
this->Address = Other.Address;
this->Amount = Other.Amount;
}
return *this;
};
inline bool operator!=(const CRecipient &Value) { return Address != Value.Address; };
inline bool operator==(const CRecipient &Value) { return Address == Value.Address; };
} CRecipient, *PRecipient;
//--------------------------------------------------------------------------------------------------------------
typedef TList<CRecipient> CRecipients;
//--------------------------------------------------------------------------------------------------------------
//-- raw -------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
/**
* Serialization helper to convert between a byte stream and data_chunk.
*/
class raw
{
public:
/**
* Default constructor.
*/
raw();
/**
* Initialization constructor.
* @param[in] text The value to initialize with.
*/
raw(const std::string& text);
/**
* Initialization constructor.
* @param[in] value The value to initialize with.
*/
raw(data_chunk value);
/**
* Copy constructor.
* @param[in] other The object to copy into self on construct.
*/
raw(const raw& other);
/**
* Overload cast to internal type.
* @return This object's value cast to internal type.
*/
operator const data_chunk&() const;
/**
* Overload cast to generic data reference.
* @return This object's value cast to a generic data reference.
*/
operator data_slice() const;
/**
* Overload stream in. Throws if input is invalid.
* @param[in] input The input stream to read the value from.
* @param[out] argument The object to receive the read value.
* @return The input stream reference.
*/
friend std::istream& operator>>(std::istream& input,
raw& argument);
/**
* Overload stream out.
* @param[in] output The output stream to write the value to.
* @param[out] argument The object from which to obtain the value.
* @return The output stream reference.
*/
friend std::ostream& operator<<(std::ostream& output,
const raw& argument);
private:
/**
* The state of this object's raw data.
*/
data_chunk value_;
};
class wrapper
{
public:
/**
* Default constructor.
*/
wrapper();
/**
* Initialization constructor.
*
* @param[in] wrapped The value to initialize with.
*/
wrapper(const std::string& wrapped);
/**
* Initialization constructor.
* @param[in] wrapped The wrapped value to initialize with.
*/
wrapper(const data_chunk& wrapped);
/**
* Initialization constructor.
* @param[in] wrapped The wrapped value to initialize with.
*/
wrapper(const wallet::wrapped_data& wrapped);
/**
* Initialization constructor.
* @param[in] address The payment address to initialize with.
*/
wrapper(const wallet::payment_address& address);
/**
* Initialization constructor.
* @param[in] version The version for the new wrapped value.
* @param[in] payload The payload for the new wrapped value.
*/
wrapper(uint8_t version, const data_chunk& payload);
/**
* Copy constructor.
* @param[in] other The object to copy into self on construct.
*/
wrapper(const wrapper& other);
/**
* Serialize the wrapper to bytes according to the wire protocol.
* @return The byte serialized copy of the wrapper.
*/
const data_chunk to_data() const;
/**
* Overload cast to internal type.
* @return This object's value cast to internal type.
*/
operator const wallet::wrapped_data&() const;
/**
* Overload stream in. Throws if input is invalid.
* @param[in] input The input stream to read the value from.
* @param[out] argument The object to receive the read value.
* @return The input stream reference.
*/
friend std::istream& operator>>(std::istream& input,
wrapper& argument);
/**
* Overload stream out.
* @param[in] output The output stream to write the value to.
* @param[out] argument The object from which to obtain the value.
* @return The output stream reference.
*/
friend std::ostream& operator<<(std::ostream& output,
const wrapper& argument);
private:
/**
* The state of this object's data.
*/
wallet::wrapped_data value_;
};
/**
* Serialization helper to convert between string and message_signature.
*/
class signature
{
public:
/**
* Default constructor.
*/
signature();
/**
* Initialization constructor.
* @param[in] hexcode The value to initialize with.
*/
signature(const std::string& hexcode);
/**
* Initialization constructor.
* @param[in] value The value to initialize with.
*/
signature(const wallet::message_signature& value);
/**
* Copy constructor.
* @param[in] other The object to copy into self on construct.
*/
signature(const signature& other);
/**
* Overload cast to internal type.
* @return This object's value cast to internal type.
*/
operator wallet::message_signature&();
/**
* Overload cast to internal type.
* @return This object's value cast to internal type.
*/
operator const wallet::message_signature&() const;
/// Serializer.
std::string encoded() const;
/**
* Overload stream in. If input is invalid sets no bytes in argument.
* @param[in] input The input stream to read the value from.
* @param[out] argument The object to receive the read value.
* @return The input stream reference.
*/
friend std::istream& operator>>(std::istream& input, signature& argument);
/**
* Overload stream out.
* @param[in] output The output stream to write the value to.
* @param[out] argument The object from which to obtain the value.
* @return The output stream reference.
*/
friend std::ostream& operator<<(std::ostream& output, const signature& argument);
private:
/**
* The state of this object.
*/
wallet::message_signature value_;
};
/**
* Serialization helper to convert between base16/raw script and script_type.
*/
class script
{
public:
/**
* Default constructor.
*/
script();
/**
* Initialization constructor.
* @param[in] mnemonic The value to initialize with.
*/
script(const std::string& mnemonic);
/**
* Initialization constructor.
* @param[in] value The value to initialize with.
*/
script(const chain::script& value);
/**
* Initialization constructor.
* @param[in] value The value to initialize with.
*/
script(const data_chunk& value);
/**
* Initialization constructor.
* @param[in] tokens The mnemonic tokens to initialize with.
*/
script(const std::vector<std::string>& tokens);
/**
* Copy constructor.
* @param[in] other The object to copy into self on construct.
*/
script(const script& other);
/**
* Serialize the script to bytes according to the wire protocol.
* @return The byte serialized copy of the script.
*/
const bc::data_chunk to_data() const;
/**
* Return a pretty-printed copy of the script.
* @return A mnemonic-printed copy of the internal script.
*/
const std::string to_string() const;
/**
* Overload cast to internal type.
* @return This object's value cast to internal type.
*/
operator const chain::script&() const;
/**
* Overload stream in. Throws if input is invalid.
* @param[in] input The input stream to read the value from.
* @param[out] argument The object to receive the read value.
* @return The input stream reference.
*/
friend std::istream& operator>>(std::istream& input,
script& argument);
/**
* Overload stream out.
* @param[in] output The output stream to write the value to.
* @param[out] argument The object from which to obtain the value.
* @return The output stream reference.
*/
friend std::ostream& operator<<(std::ostream& output,
const script& argument);
private:
/**
* The state of this object.
*/
chain::script value_;
};
} // namespace Bitcoin
} // namespace Apostol
using namespace Apostol::Bitcoin;
using namespace Apostol::Bech32;
using namespace Apostol::SegWit;
}
#endif //APOSTOL_BITCOIN_HPP