diff --git a/Dockerfile b/Dockerfile index 1c373cbc9..fde5213e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,26 +41,26 @@ RUN set -ex && \ rm -rf /var/lib/apt COPY --from=builder /src/build/x86_64-linux-gnu/release/bin /usr/local/bin/ -# Create monero user -RUN adduser --system --group --disabled-password monero && \ - mkdir -p /wallet /home/monero/.bitmonero && \ - chown -R monero:monero /home/monero/.bitmonero && \ - chown -R monero:monero /wallet +# Create salvium user +RUN adduser --system --group --disabled-password salvium && \ + mkdir -p /wallet /home/salvium/.salvium && \ + chown -R salvium:salvium /home/salvium/.salvium && \ + chown -R salvium:salvium /wallet # Contains the blockchain -VOLUME /home/monero/.bitmonero +VOLUME /home/salvium/.salvium # Generate your wallet via accessing the container and run: # cd /wallet -# monero-wallet-cli +# salvium-wallet-cli VOLUME /wallet -EXPOSE 18080 -EXPOSE 18081 +EXPOSE 19080 +EXPOSE 19081 -# switch to user monero -USER monero +# switch to user salvium +USER salvium -ENTRYPOINT ["monerod"] -CMD ["--p2p-bind-ip=0.0.0.0", "--p2p-bind-port=18080", "--rpc-bind-ip=0.0.0.0", "--rpc-bind-port=18081", "--non-interactive", "--confirm-external-bind"] +ENTRYPOINT ["salviumd"] +CMD ["--p2p-bind-ip=0.0.0.0", "--p2p-bind-port=19080", "--rpc-bind-ip=0.0.0.0", "--rpc-bind-port=19081", "--non-interactive", "--confirm-external-bind"] diff --git a/README.md b/README.md index 68acc6d94..e574ff521 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Salvium Zero v0.4.0 +# Salvium Zero v0.4.1 Copyright (c) 2023-2024, Salvium Portions Copyright (c) 2014-2023, The Monero Project @@ -23,7 +23,7 @@ Portions Copyright (c) 2012-2013 The Cryptonote developers. - Web: [salvium.io](https://salvium.io) - Mail: [dev@salvium.io](mailto:dev@salvium.io) -- GitHub: [https://github.com/somerandomcryptoguy/salvium](https://github.com/somerandomcryptoguy/salvium) +- GitHub: [https://github.com/salvium/salvium](https://github.com/salvium/salvium) ## Introduction @@ -147,7 +147,7 @@ pkg install git gmake cmake pkgconf boost-libs libzmq4 libsodium unbound Clone recursively to pull-in needed submodule(s): ``` -git clone --recursive https://github.com/somerandomcryptoguy/salvium +git clone --recursive https://github.com/salvium/salvium ``` If you already have a repo cloned, initialize and update: @@ -249,9 +249,9 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch ( * Clone Salvium and checkout the most recent release version: ```bash - git clone https://github.com/somerandomcryptoguy/salvium + git clone https://github.com/salvium/salvium cd salvium - git checkout v0.4.0 + git checkout v0.4.1 ``` * Build: @@ -359,7 +359,7 @@ application. * To git clone, run: ```bash - git clone --recursive https://github.com/somerandomcryptoguy/salvium + git clone --recursive https://github.com/salvium/salvium ``` **Building** @@ -370,10 +370,10 @@ application. cd salvium ``` -* If you would like a specific [version/tag](https://github.com/somerandomcryptoguy/salvium/tags), do a git checkout for that version. eg. 'v0.4.0'. If you don't care about the version and just want binaries from master, skip this step: +* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.4.1'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.4.0 + git checkout v0.4.1 ``` * If you are on a 64-bit system, run: diff --git a/contrib/depends/hosts/mingw32.mk b/contrib/depends/hosts/mingw32.mk index 58a9a929d..775331223 100644 --- a/contrib/depends/hosts/mingw32.mk +++ b/contrib/depends/hosts/mingw32.mk @@ -1,4 +1,4 @@ -mingw32_CFLAGS=-pipe +mingw32_CFLAGS=-pipe -pthread mingw32_CXXFLAGS=$(mingw32_CFLAGS) mingw32_ARFLAGS=cr diff --git a/contrib/depends/packages/zeromq.mk b/contrib/depends/packages/zeromq.mk index 669d06d83..5dc28c136 100644 --- a/contrib/depends/packages/zeromq.mk +++ b/contrib/depends/packages/zeromq.mk @@ -5,7 +5,7 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=6653ef5910f17954861fe72332e68b03ca6e4d9c7160eb3a8de5a5a913bfab43 define $(package)_set_vars - $(package)_config_opts=--without-documentation --disable-shared --without-libsodium --disable-curve + $(package)_config_opts=--without-documentation --disable-shared --without-libsodium --disable-curve --with-cv-impl=pthread $(package)_config_opts_linux=--with-pic $(package)_config_opts_freebsd=--with-pic $(package)_cxxflags=-std=c++11 diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat index 593f4708d..247c00a78 100644 Binary files a/src/blocks/checkpoints.dat and b/src/blocks/checkpoints.dat differ diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 0fba347db..ea36cdf41 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -6049,7 +6049,7 @@ void Blockchain::cancel() } #if defined(PER_BLOCK_CHECKPOINT) -static const char expected_block_hashes_hash[] = "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"; +static const char expected_block_hashes_hash[] = "7f60b4980ea16b32e3f9fc1959d9d4116ba91f2b067bd70b3e21c44520096d14"; void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints) { if (get_checkpoints == nullptr || !m_fast_sync) diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 077597d0b..5ee533563 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -401,7 +401,7 @@ namespace cryptonote int64_t diff = static_cast(hshd.current_height) - static_cast(m_core.get_current_blockchain_height()); uint64_t abs_diff = std::abs(diff); uint64_t max_block_height = std::max(hshd.current_height,m_core.get_current_blockchain_height()); - uint64_t last_block_v1 = m_core.get_nettype() == TESTNET ? 624633 : m_core.get_nettype() == MAINNET ? 1009826 : (uint64_t)-1; + uint64_t last_block_v1 = 0;//m_core.get_nettype() == TESTNET ? 624633 : m_core.get_nettype() == MAINNET ? 1009826 : (uint64_t)-1; uint64_t diff_v2 = max_block_height > last_block_v1 ? std::min(abs_diff, max_block_height - last_block_v1) : 0; MCLOG(is_inital ? el::Level::Info : el::Level::Debug, "global", el::Color::Yellow, context << "Sync data returned a new top block candidate: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height << " [Your node is " << abs_diff << " blocks (" << tools::get_human_readable_timespan((abs_diff - diff_v2) * DIFFICULTY_TARGET_V1 + diff_v2 * DIFFICULTY_TARGET_V2) << ") " diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 459a6a396..98dc37f1a 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -299,10 +299,9 @@ namespace nodetool private: const std::vector m_seed_nodes_list = - { "seeds.moneroseeds.se" - , "seeds.moneroseeds.ae.org" - , "seeds.moneroseeds.ch" - , "seeds.moneroseeds.li" + { "seed01.salvium.io" + , "seed02.salvium.io" + , "seed03.salvium.io" }; bool islimitup=false; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 30e3d31b9..717296811 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -705,32 +705,24 @@ namespace nodetool std::set full_addrs; if (m_nettype == cryptonote::TESTNET) { - full_addrs.insert("176.9.0.187:28080"); - full_addrs.insert("88.99.173.38:28080"); - full_addrs.insert("51.79.173.165:28080"); - full_addrs.insert("192.99.8.110:28080"); - full_addrs.insert("37.187.74.171:28080"); + full_addrs.insert("152.42.130.46:29080"); + full_addrs.insert("45.55.138.87:29080"); + full_addrs.insert("209.97.164.15:29080"); } else if (m_nettype == cryptonote::STAGENET) { - full_addrs.insert("176.9.0.187:38080"); - full_addrs.insert("88.99.173.38:38080"); - full_addrs.insert("51.79.173.165:38080"); - full_addrs.insert("192.99.8.110:38080"); - full_addrs.insert("37.187.74.171:38080"); + full_addrs.insert("152.42.130.46:39080"); + full_addrs.insert("45.55.138.87:39080"); + full_addrs.insert("209.97.164.15:39080"); } else if (m_nettype == cryptonote::FAKECHAIN) { } else { - full_addrs.insert("176.9.0.187:18080"); - full_addrs.insert("88.198.163.90:18080"); - full_addrs.insert("66.85.74.134:18080"); - full_addrs.insert("88.99.173.38:18080"); - full_addrs.insert("51.79.173.165:18080"); - full_addrs.insert("192.99.8.110:18080"); - full_addrs.insert("37.187.74.171:18080"); + full_addrs.insert("152.42.130.46:19080"); + full_addrs.insert("45.55.138.87:19080"); + full_addrs.insert("209.97.164.15:19080"); } return full_addrs; } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 3de42b667..e43c62820 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -8444,7 +8444,7 @@ bool simple_wallet::yield_info(const std::vector &args) { % print_money(total_yield) % print_money(yield_per_stake); - // Now summarise our own YIELD TXs that are yet to amture + // Now summarise our own YIELD TXs that are yet to mature tools::wallet2::transfer_container transfers; m_wallet->get_transfers(transfers); if (transfers.empty()) diff --git a/src/version.cpp.in b/src/version.cpp.in index 5e572465f..7041ce71c 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@" -#define DEF_SALVIUM_VERSION "0.4.0" +#define DEF_SALVIUM_VERSION "0.4.4-beta1" #define DEF_MONERO_VERSION_TAG "release" #define DEF_MONERO_VERSION "0.18.3.3" #define DEF_MONERO_RELEASE_NAME "Zero" diff --git a/src/wallet/api/CMakeLists.txt b/src/wallet/api/CMakeLists.txt index af7948d8a..110020170 100644 --- a/src/wallet/api/CMakeLists.txt +++ b/src/wallet/api/CMakeLists.txt @@ -35,6 +35,7 @@ set(wallet_api_sources wallet_manager.cpp transaction_info.cpp transaction_history.cpp + yield_info.cpp pending_transaction.cpp utils.cpp address_book.cpp @@ -50,6 +51,7 @@ set(wallet_api_private_headers wallet_manager.h transaction_info.h transaction_history.h + yield_info.h pending_transaction.h common_defines.h address_book.h diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 9f5e41156..84212a4a4 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -150,6 +150,7 @@ void TransactionHistoryImpl::refresh() ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0; ti->m_unlock_time = pd.m_unlock_time; + ti->m_type = static_cast(static_cast(pd.m_tx_type)); m_history.push_back(ti); } @@ -193,6 +194,7 @@ void TransactionHistoryImpl::refresh() ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0; + ti->m_type = static_cast(static_cast(pd.m_tx.type)); // single output transaction might contain multiple transfers for (const auto &d: pd.m_dests) { @@ -229,6 +231,7 @@ void TransactionHistoryImpl::refresh() ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = 0; + ti->m_type = static_cast(static_cast(pd.m_tx.type)); for (const auto &d : pd.m_dests) { ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)}); @@ -258,6 +261,7 @@ void TransactionHistoryImpl::refresh() ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index); ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = 0; + ti->m_type = static_cast(static_cast(pd.m_tx_type)); m_history.push_back(ti); LOG_PRINT_L1(__FUNCTION__ << ": Unconfirmed payment found " << pd.m_amount); diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index 572b04316..687623f0c 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -149,4 +149,9 @@ uint64_t TransactionInfoImpl::unlockTime() const return m_unlock_time; } +Monero::transaction_type TransactionInfoImpl::type() const +{ + return m_type; +} + } // namespace diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 6337f2aaa..a2cd120ce 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -62,6 +62,7 @@ public: virtual const std::vector &transfers() const override; virtual uint64_t confirmations() const override; virtual uint64_t unlockTime() const override; + virtual Monero::transaction_type type() const override; private: int m_direction; @@ -81,6 +82,7 @@ private: std::vector m_transfers; uint64_t m_confirmations; uint64_t m_unlock_time; + Monero::transaction_type m_type; friend class TransactionHistoryImpl; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index e2b0e672c..94b0c19ea 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -30,6 +30,7 @@ #include "wallet.h" +#include "yield_info.h" #include "pending_transaction.h" #include "unsigned_transaction.h" #include "transaction_history.h" @@ -1430,6 +1431,19 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat return nullptr; } +PendingTransaction *WalletImpl::createStakeTransaction(uint64_t amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices) +{ + // Need to populate {dst_entr, payment_id, asset_type, is_return} + const string dst_addr = m_wallet->get_subaddress_as_str({subaddr_account, 0});//MY LOCAL (SUB)ADDRESS + const string payment_id = ""; + const string asset_type = "SAL"; + const bool is_return = false; + + LOG_ERROR("createStakeTransaction: called"); + + return createTransactionMultDest(Monero::transaction_type::STAKE, std::vector {dst_addr}, payment_id, amount ? (std::vector {amount}) : (optional>()), mixin_count, asset_type, is_return, priority, subaddr_account, subaddr_indices); +} + // TODO: // 1 - properly handle payment id (add another menthod with explicit 'payment_id' param) // 2 - check / design how "Transaction" can be single interface @@ -1440,7 +1454,7 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat // - unconfirmed_transfer_details; // - confirmed_transfer_details) -PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector &dst_addr, const string &payment_id, optional> amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices) +PendingTransaction *WalletImpl::createTransactionMultDest(const Monero::transaction_type &tx_type, const std::vector &dst_addr, const string &payment_id, optional> amount, uint32_t mixin_count, const std::string &asset_type, const bool is_return, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices) { clearStatus(); @@ -1451,6 +1465,8 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vectoradjust_priority(static_cast(priority)); + const cryptonote::transaction_type converted_tx_type = static_cast(static_cast(tx_type)); + PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); do { @@ -1496,8 +1512,10 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vectoradjust_mixin(mixin_count); if (amount) { - transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, "SAL", "SAL", cryptonote::transaction_type::TRANSFER, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, "SAL", "SAL", converted_tx_type, fake_outs_count, 0 /* unlock_time */, adjusted_priority, extra, subaddr_account, subaddr_indices); } else { - transaction->m_pending_tx = m_wallet->create_transactions_all(0, cryptonote::transaction_type::TRANSFER, "SAL", info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_all(0, converted_tx_type, "SAL", info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */, adjusted_priority, extra, subaddr_account, subaddr_indices); } @@ -1605,10 +1623,10 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector amount, uint32_t mixin_count, - PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices) + const std::string &asset_type, const bool is_return, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices) { - return createTransactionMultDest(std::vector {dst_addr}, payment_id, amount ? (std::vector {*amount}) : (optional>()), mixin_count, priority, subaddr_account, subaddr_indices); + return createTransactionMultDest(Monero::transaction_type::TRANSFER, std::vector {dst_addr}, payment_id, amount ? (std::vector {*amount}) : (optional>()), mixin_count, asset_type, is_return, priority, subaddr_account, subaddr_indices); } PendingTransaction *WalletImpl::createSweepUnmixableTransaction() @@ -2590,4 +2608,11 @@ uint64_t WalletImpl::getBytesSent() return m_wallet->get_bytes_sent(); } +YieldInfo * WalletImpl::getYieldInfo() +{ + auto yi = new YieldInfoImpl(*this); + bool ok = m_wallet->get_yield_summary_info(yi->m_burnt, yi->m_supply, yi->m_locked, yi->m_yield, yi->m_yield_per_stake, yi->m_num_entries, yi->m_payouts); + return yi; +} + } // namespace diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index dc20b8cb7..709bb8df1 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -42,6 +42,7 @@ namespace Monero { class TransactionHistoryImpl; +class YieldInfoImpl; class PendingTransactionImpl; class UnsignedTransactionImpl; class AddressBookImpl; @@ -152,16 +153,24 @@ public: bool hasMultisigPartialKeyImages() const override; PendingTransaction* restoreMultisigTransaction(const std::string& signData) override; - PendingTransaction * createTransactionMultDest(const std::vector &dst_addr, const std::string &payment_id, - optional> amount, uint32_t mixin_count, - PendingTransaction::Priority priority = PendingTransaction::Priority_Low, - uint32_t subaddr_account = 0, - std::set subaddr_indices = {}) override; + PendingTransaction * createStakeTransaction(uint64_t amount, + uint32_t mixin_count, + PendingTransaction::Priority priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, + std::set subaddr_indices = {}) override; + PendingTransaction * createTransactionMultDest(const transaction_type &tx_type, + const std::vector &dst_addr, const std::string &payment_id, + optional> amount, uint32_t mixin_count, + const std::string &asset_type, const bool is_return, + PendingTransaction::Priority priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, + std::set subaddr_indices = {}) override; PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, - optional amount, uint32_t mixin_count, - PendingTransaction::Priority priority = PendingTransaction::Priority_Low, - uint32_t subaddr_account = 0, - std::set subaddr_indices = {}) override; + optional amount, uint32_t mixin_count, + const std::string &asset_type, const bool is_return, + PendingTransaction::Priority priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, + std::set subaddr_indices = {}) override; virtual PendingTransaction * createSweepUnmixableTransaction() override; bool submitTransaction(const std::string &fileName) override; virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override; @@ -225,6 +234,8 @@ public: virtual uint64_t getBytesReceived() override; virtual uint64_t getBytesSent() override; + YieldInfo * getYieldInfo() override; + private: void clearStatus() const; void setStatusError(const std::string& message) const; @@ -239,6 +250,7 @@ private: bool doInit(const std::string &daemon_address, const std::string &proxy_address, uint64_t upper_transaction_size_limit = 0, bool ssl = false); private: + friend class YieldInfoImpl; friend class PendingTransactionImpl; friend class UnsignedTransactionImpl; friend class TransactionHistoryImpl; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 636ea15f7..2605f4754 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -49,6 +49,18 @@ enum NetworkType : uint8_t { STAGENET }; +enum transaction_type : uint8_t { + UNSET = 0, + MINER = 1, + PROTOCOL = 2, + TRANSFER = 3, + CONVERT = 4, + BURN = 5, + STAKE = 6, + RETURN = 7, + MAX = 7 +}; + namespace Utils { bool isAddressLocal(const std::string &hostaddr); void onStartup(); @@ -67,6 +79,28 @@ enum NetworkType : uint8_t { bool set; }; +struct YieldInfo +{ + enum Status { + Status_Ok, + Status_Error + }; + + virtual ~YieldInfo() = 0; + virtual int status() const = 0; + virtual std::string errorString() const = 0; + virtual bool update() = 0; + virtual uint64_t burnt() const = 0; + virtual uint64_t locked() const = 0; + virtual uint64_t supply() const = 0; + virtual uint64_t ybi_data_size() const = 0; + virtual uint64_t yield() const = 0; + virtual uint64_t yield_per_stake() const = 0; + virtual std::string period() const = 0; + virtual std::vector> payouts() const = 0; +}; + + /** * @brief Transaction-like interface for sending money */ @@ -199,6 +233,7 @@ struct TransactionInfo virtual std::string paymentId() const = 0; //! only applicable for output transactions virtual const std::vector & transfers() const = 0; + virtual Monero::transaction_type type() const = 0; }; /** * @brief The TransactionHistory - interface for displaying transaction history @@ -826,12 +861,32 @@ struct Wallet */ virtual PendingTransaction* restoreMultisigTransaction(const std::string& signData) = 0; + /*! + * \brief createStakeTransaction creates staking transaction. + * \param amount amount + * \param mixin_count mixin count. if 0 passed, wallet will use default value + * \param subaddr_account subaddress account from which the input funds are taken + * \param subaddr_indices set of subaddress indices to use for transfer or sweeping. if set empty, all are chosen when sweeping, and one or more are automatically chosen when transferring. after execution, returns the set of actually used indices + * \param priority + * \return PendingTransaction object. caller is responsible to check PendingTransaction::status() + * after object returned + */ + + virtual PendingTransaction * createStakeTransaction(uint64_t amount, + uint32_t mixin_count, + PendingTransaction::Priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, + std::set subaddr_indices = {}) = 0; + /*! * \brief createTransactionMultDest creates transaction with multiple destinations. if dst_addr is an integrated address, payment_id is ignored + * \param tx_type the type of transaction being created * \param dst_addr vector of destination address as string * \param payment_id optional payment_id, can be empty string * \param amount vector of amounts * \param mixin_count mixin count. if 0 passed, wallet will use default value + * \param asset_type type of asset to create as output + * \param is_return whether this is a return_payment or not * \param subaddr_account subaddress account from which the input funds are taken * \param subaddr_indices set of subaddress indices to use for transfer or sweeping. if set empty, all are chosen when sweeping, and one or more are automatically chosen when transferring. after execution, returns the set of actually used indices * \param priority @@ -839,11 +894,13 @@ struct Wallet * after object returned */ - virtual PendingTransaction * createTransactionMultDest(const std::vector &dst_addr, const std::string &payment_id, - optional> amount, uint32_t mixin_count, - PendingTransaction::Priority = PendingTransaction::Priority_Low, - uint32_t subaddr_account = 0, - std::set subaddr_indices = {}) = 0; + virtual PendingTransaction * createTransactionMultDest(const transaction_type &tx_type, + const std::vector &dst_addr, const std::string &payment_id, + optional> amount, uint32_t mixin_count, + const std::string &asset_type, const bool is_return, + PendingTransaction::Priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, + std::set subaddr_indices = {}) = 0; /*! * \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored @@ -851,6 +908,8 @@ struct Wallet * \param payment_id optional payment_id, can be empty string * \param amount amount * \param mixin_count mixin count. if 0 passed, wallet will use default value + * \param asset_type type of asset to create as output + * \param is_return whether this is a return_payment or not * \param subaddr_account subaddress account from which the input funds are taken * \param subaddr_indices set of subaddress indices to use for transfer or sweeping. if set empty, all are chosen when sweeping, and one or more are automatically chosen when transferring. after execution, returns the set of actually used indices * \param priority @@ -860,6 +919,7 @@ struct Wallet virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, optional amount, uint32_t mixin_count, + const std::string &asset_type, const bool is_return, PendingTransaction::Priority = PendingTransaction::Priority_Low, uint32_t subaddr_account = 0, std::set subaddr_indices = {}) = 0; @@ -1092,6 +1152,9 @@ struct Wallet //! get bytes sent virtual uint64_t getBytesSent() = 0; + + //! get yield information + virtual YieldInfo * getYieldInfo() = 0; }; /** diff --git a/src/wallet/api/yield_info.cpp b/src/wallet/api/yield_info.cpp new file mode 100644 index 000000000..9ff401534 --- /dev/null +++ b/src/wallet/api/yield_info.cpp @@ -0,0 +1,131 @@ +// Copyright (c) 2024, Salvium (author: SRCG) +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "yield_info.h" +#include "wallet.h" +#include "common_defines.h" + +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_basic/cryptonote_basic_impl.h" +#include "common/base58.h" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace Monero { + + YieldInfo::~YieldInfo() {} + + YieldInfoImpl::YieldInfoImpl(WalletImpl &wallet) + : m_wallet(wallet) + { + m_status = Status_Ok; + m_burnt = 0; + m_locked = 0; + m_supply = 0; + m_yield = 0; + m_yield_per_stake = 0; + m_num_entries = 0; + } + + YieldInfoImpl::~YieldInfoImpl() + { + + } + + int YieldInfoImpl::status() const + { + return m_status; + } + + string YieldInfoImpl::errorString() const + { + return m_errorString; + } + + std::string YieldInfoImpl::period() const + { + // Calculate the number of entries as a human-readable time period + uint64_t ts = m_num_entries * 120; + std::string result; + stringstream ss; + ss << std::setfill('0') << std::setw(2) << (ts / 86400) + << ":" << std::setw(2) << ((ts % 86400) / 3600) + << ":" << std::setw(2) << ((ts % 3600) / 60) + << ":" << std::setw(2) << (ts % 60) << " (DD:HH:MM:SS)"; + return ss.str(); + } + + bool YieldInfoImpl::update() + { + return false; + } + + uint64_t YieldInfoImpl::burnt() const + { + return m_burnt; + } + + uint64_t YieldInfoImpl::locked() const + { + return m_locked; + } + + uint64_t YieldInfoImpl::supply() const + { + return m_supply; + } + + uint64_t YieldInfoImpl::ybi_data_size() const + { + return m_num_entries; + } + + uint64_t YieldInfoImpl::yield() const + { + return m_yield; + } + + uint64_t YieldInfoImpl::yield_per_stake() const + { + return m_yield_per_stake; + } + + std::vector> YieldInfoImpl::payouts() const + { + return m_payouts; + } + +} diff --git a/src/wallet/api/yield_info.h b/src/wallet/api/yield_info.h new file mode 100644 index 000000000..8ec98fb42 --- /dev/null +++ b/src/wallet/api/yield_info.h @@ -0,0 +1,74 @@ +// Copyright (c) 2024, Salvium (author: SRCG) +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "wallet/api/wallet2_api.h" +#include "wallet/wallet2.h" + +#include +#include + + +namespace Monero { + +class WalletImpl; +class YieldInfoImpl : public YieldInfo +{ +public: + YieldInfoImpl(WalletImpl &wallet); + ~YieldInfoImpl(); + int status() const override; + std::string errorString() const override; + bool update() override; + uint64_t burnt() const override; + uint64_t locked() const override; + uint64_t supply() const override; + uint64_t ybi_data_size() const override; + uint64_t yield() const override; + uint64_t yield_per_stake() const override; + std::string period() const override; + std::vector> payouts() const override; + +private: + friend class WalletImpl; + WalletImpl &m_wallet; + + int m_status; + std::string m_errorString; + uint64_t m_burnt; + uint64_t m_locked; + uint64_t m_supply; + uint64_t m_yield; + uint64_t m_yield_per_stake; + uint64_t m_num_entries; + std::string m_period; + std::vector> m_payouts; +}; + +} diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 102a5fe7e..ccf3c269e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2380,6 +2380,105 @@ bool wallet2::get_yield_info(std::vector& ybi_data } } //---------------------------------------------------------------------------------------------------- +bool wallet2::get_yield_summary_info(uint64_t &total_burnt, + uint64_t &total_supply, + uint64_t &total_locked, + uint64_t &total_yield, + uint64_t &yield_per_stake, + uint64_t &ybi_data_size, + std::vector> &payouts + ) +{ + // Get the total circulating supply of SALs + std::vector> supply_amounts; + if(!get_circulating_supply(supply_amounts)) { + return false; + } + boost::multiprecision::uint128_t total_supply_128 = 0; + for (auto supply_asset: supply_amounts) { + if (supply_asset.first == "SAL") { + boost::multiprecision::uint128_t supply_128(supply_asset.second); + total_supply_128 = supply_128; + break; + } + } + total_supply = total_supply_128.convert_to(); + + // Get the yield data from the blockchain + std::vector ybi_data; + bool r = get_yield_info(ybi_data); + if (!r) + return false; + + ybi_data_size = ybi_data.size(); + + // Scan the entries we have received to gather the state (total yield over period captured) + total_burnt = 0; + total_yield = 0; + yield_per_stake = 0; + for (size_t idx=1; idx 0) { + boost::multiprecision::uint128_t yield_per_stake_128 = ybi_data.back().slippage_total_this_block; + yield_per_stake_128 *= COIN; + yield_per_stake_128 /= ybi_data.back().locked_coins_tally; + yield_per_stake = yield_per_stake_128.convert_to(); + } + + // Iterate over the transfers in our wallet + std::map map_payouts; + for (size_t idx = m_transfers.size()-1; idx>0; --idx) { + const tools::wallet2::transfer_details& td = m_transfers[idx]; + //if (td.m_block_height < ybi_data[0].block_height) break; + if (td.m_tx.type == cryptonote::transaction_type::STAKE) { + if (map_payouts.count(idx)) { + payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, m_transfers[map_payouts[idx]].m_amount - td.m_tx.amount_burnt)); + } else { + payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, 0)); + } + } else if (td.m_tx.type == cryptonote::transaction_type::PROTOCOL) { + // Store list of reverse-lookup indices to tell YIELD TXs how much they earned + if (m_transfers[td.m_td_origin_idx].m_tx.type == cryptonote::transaction_type::STAKE) + map_payouts[td.m_td_origin_idx] = idx; + } + } + + // Return success to caller + return true; +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::get_yield_payouts(std::vector> &payouts) { + + // Iterate over the transfers in our wallet + std::map map_payouts; + for (size_t idx = m_transfers.size()-1; idx>0; --idx) { + const tools::wallet2::transfer_details& td = m_transfers[idx]; + //if (td.m_block_height < ybi_data[0].block_height) break; + if (td.m_tx.type == cryptonote::transaction_type::STAKE) { + if (map_payouts.count(idx)) { + payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, m_transfers[map_payouts[idx]].m_amount - td.m_tx.amount_burnt)); + } else { + payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, 0)); + } + } else if (td.m_tx.type == cryptonote::transaction_type::PROTOCOL) { + // Store list of reverse-lookup indices to tell YIELD TXs how much they earned + if (m_transfers[td.m_td_origin_idx].m_tx.type == cryptonote::transaction_type::STAKE) + map_payouts[td.m_td_origin_idx] = idx; + } + } + return true; +} +//---------------------------------------------------------------------------------------------------- void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector &o_indices, const std::vector &asset_type_output_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map, size_t> *output_tracker_cache, bool ignore_callbacks) { PERF_TIMER(process_new_transaction); @@ -2687,7 +2786,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote if (!ignore_callbacks && 0 != m_callback) m_callback->on_money_received(height, txid, tx, td.m_amount, td.asset_type, 0, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time, td.m_td_origin_idx); } - std::string asset_type = m_transfers.back().asset_type; + std::string asset_type = tx_scan_info[o].asset_type; if (total_received_1.count(asset_type)) total_received_1[asset_type] += amount; else @@ -2715,10 +2814,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote } } else if (tx.type == cryptonote::transaction_type::TRANSFER) { + + // We might store garbage entries here occasionally, but they shouldn't impact performance significantly crypto::public_key P_change = crypto::null_pkey; - size_t change_idx = m_transfers.back().m_internal_output_index; + size_t change_idx = o; THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(tx.vout[change_idx], P_change), error::wallet_internal_error, "Failed to get output public key"); - m_subaddresses[P_change] = {0,0}; + m_subaddresses[P_change] = tx_scan_info[o].received->index;//{0,0}; m_salvium_txs.insert({P_change, m_transfers.size()-1}); } } @@ -2999,7 +3100,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote // only for regular transfers if (!miner_tx) { for (auto& asset: total_received_1) { - if (asset.second != total_received_2[asset.first]) { + if (asset.second != total_received_2[asset.first] + (asset.first == source_asset ? sub_change : 0)) { //if (source_asset == dest_asset && !miner_tx) { //if (total_received_1 != total_received_2) //{ @@ -13005,18 +13106,14 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err) uint64_t wallet2::get_approximate_blockchain_height() const { - // time of v2 fork - const time_t fork_time = m_nettype == TESTNET ? 1448285909 : m_nettype == STAGENET ? 1520937818 : 1458748658; - // v2 fork block - const uint64_t fork_block = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? 32000 : 1009827; + // time of v1 fork + const time_t fork_time = 1719997643; + // v1 fork block + const uint64_t fork_block = 0; // avg seconds per block const int seconds_per_block = DIFFICULTY_TARGET_V2; // Calculated blockchain height uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block; - // testnet and stagenet got some huge rollbacks, so the estimation is way off - static const uint64_t approximate_rolled_back_blocks = m_nettype == TESTNET ? 342100 : 30000; - if ((m_nettype == TESTNET || m_nettype == STAGENET) && approx_blockchain_height > approximate_rolled_back_blocks) - approx_blockchain_height -= approximate_rolled_back_blocks; LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height); return approx_blockchain_height; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 4cb4c9732..d14ff92e8 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1747,6 +1747,15 @@ private: bool get_pricing_record(oracle::pricing_record& pr, const uint64_t height); bool get_circulating_supply(std::vector> &amounts); bool get_yield_info(std::vector& ybi_data); + bool get_yield_summary_info(uint64_t &total_burnt, + uint64_t &total_supply, + uint64_t &total_locked, + uint64_t &total_yield, + uint64_t &yield_per_stake, + uint64_t &ybi_data_size, + std::vector> &payouts + ); + bool get_yield_payouts(std::vector> &payouts); private: /*! diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 5d7309fc1..44f1415fc 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -462,7 +462,7 @@ namespace tools std::string asset_type = req.asset_type.empty() ? "SAL" : boost::algorithm::to_upper_copy(req.asset_type); // verify that the asset is in the list of in-wallet assets if (std::find(assets_in_wallet.begin(), assets_in_wallet.end(), asset_type) == assets_in_wallet.end()) { - er.message = std::string("Invalid source asset specified: ") + asset_type; + er.message = std::string("Source asset '") + asset_type + "' not found in wallet"; return false; } std::vector assets = req.all_assets ? assets_in_wallet : std::vector{asset_type}; @@ -897,7 +897,7 @@ namespace tools return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool wallet_rpc_server::validate_transfer(const std::list& destinations, const std::string& payment_id, std::vector& dsts, std::vector& extra, bool at_least_one_destination, epee::json_rpc::error& er) + bool wallet_rpc_server::validate_transfer(const std::list& destinations, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& type, const std::string& payment_id, std::vector& dsts, std::vector& extra, bool at_least_one_destination, epee::json_rpc::error& er) { crypto::hash8 integrated_payment_id = crypto::null_hash8; std::string extra_nonce; @@ -932,6 +932,7 @@ namespace tools de.is_subaddress = info.is_subaddress; de.amount = it->amount; de.is_integrated = info.has_payment_id; + de.asset_type = it->asset_type; dsts.push_back(de); if (info.has_payment_id) @@ -1107,8 +1108,11 @@ namespace tools CHECK_MULTISIG_ENABLED(); + // Cast the TX type into the correct var + const cryptonote::transaction_type type = static_cast(req.tx_type); + // validate the transfer requested and populate dsts & extra - if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er)) + if (!validate_transfer(req.destinations, req.source_asset, req.dest_asset, type, req.payment_id, dsts, extra, true, er)) { return false; } @@ -1117,7 +1121,7 @@ namespace tools { uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint32_t priority = m_wallet->adjust_priority(req.priority); - std::vector ptx_vector = m_wallet->create_transactions_2(dsts, req.source_asset, req.dest_asset, static_cast(req.tx_type), mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, req.subtract_fee_from_outputs); + std::vector ptx_vector = m_wallet->create_transactions_2(dsts, req.source_asset, req.dest_asset, type, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, req.subtract_fee_from_outputs); if (ptx_vector.empty()) { @@ -1161,8 +1165,11 @@ namespace tools CHECK_MULTISIG_ENABLED(); - // validate the transfer requested and populate dsts & extra; RPC_TRANSFER::request and RPC_TRANSFER_SPLIT::request are identical types. - if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er)) + // Cast the TX type into the correct var + const cryptonote::transaction_type type = static_cast(req.tx_type); + + // validate the transfer requested and populate dsts & extra + if (!validate_transfer(req.destinations, req.source_asset, req.dest_asset, type, req.payment_id, dsts, extra, true, er)) { return false; } @@ -1172,7 +1179,7 @@ namespace tools uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint32_t priority = m_wallet->adjust_priority(req.priority); LOG_PRINT_L2("on_transfer_split calling create_transactions_2"); - std::vector ptx_vector = m_wallet->create_transactions_2(dsts, req.source_asset, req.dest_asset, static_cast(req.tx_type), mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices); + std::vector ptx_vector = m_wallet->create_transactions_2(dsts, req.source_asset, req.dest_asset, type, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices); LOG_PRINT_L2("on_transfer_split called create_transactions_2"); if (ptx_vector.empty()) @@ -1597,13 +1604,17 @@ namespace tools CHECK_MULTISIG_ENABLED(); - // validate the transfer requested and populate dsts & extra - std::list destination; - destination.push_back(wallet_rpc::transfer_destination()); - destination.back().amount = 0; - destination.back().address = req.address; std::string asset_type = req.asset_type.empty() ? "SAL" : req.asset_type; - if (!validate_transfer(destination, req.payment_id, dsts, extra, true, er)) + + // validate the transfer requested and populate dsts & extra + std::list destinations; + destinations.push_back(wallet_rpc::transfer_destination()); + destinations.back().amount = 0; + destinations.back().address = req.address; + destinations.back().asset_type = asset_type; + + // validate the transfer requested and populate dsts & extra + if (!validate_transfer(destinations, asset_type, asset_type, cryptonote::transaction_type::TRANSFER, req.payment_id, dsts, extra, true, er)) { return false; } @@ -1665,12 +1676,17 @@ namespace tools CHECK_MULTISIG_ENABLED(); + std::string asset_type = req.asset_type.empty() ? "SAL" : req.asset_type; + // validate the transfer requested and populate dsts & extra - std::list destination; - destination.push_back(wallet_rpc::transfer_destination()); - destination.back().amount = 0; - destination.back().address = req.address; - if (!validate_transfer(destination, req.payment_id, dsts, extra, true, er)) + std::list destinations; + destinations.push_back(wallet_rpc::transfer_destination()); + destinations.back().amount = 0; + destinations.back().address = req.address; + destinations.back().asset_type = asset_type; + + // validate the transfer requested and populate dsts & extra + if (!validate_transfer(destinations, asset_type, asset_type, cryptonote::transaction_type::TRANSFER, req.payment_id, dsts, extra, true, er)) { return false; } diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 3308d1751..40bb543e2 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -268,7 +268,7 @@ namespace tools bool get_tx_key, Ts& tx_key, Tu &amount, Ta &amounts_by_dest, Tu &fee, Tu &weight, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay, Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, Tk &spent_key_images, epee::json_rpc::error &er); - bool validate_transfer(const std::list& destinations, const std::string& payment_id, std::vector& dsts, std::vector& extra, bool at_least_one_destination, epee::json_rpc::error& er); + bool validate_transfer(const std::list& destinations, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& type, const std::string& payment_id, std::vector& dsts, std::vector& extra, bool at_least_one_destination, epee::json_rpc::error& er); void check_background_mining(); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index ee1bcfa7c..310a832e3 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -465,9 +465,11 @@ namespace wallet_rpc { uint64_t amount; std::string address; + std::string asset_type; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) KV_SERIALIZE(address) + KV_SERIALIZE(asset_type) END_KV_SERIALIZE_MAP() }; @@ -921,6 +923,7 @@ namespace wallet_rpc bool do_not_relay; bool get_tx_hex; bool get_tx_metadata; + std::string asset_type; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(address) @@ -934,6 +937,7 @@ namespace wallet_rpc KV_SERIALIZE_OPT(do_not_relay, false) KV_SERIALIZE_OPT(get_tx_hex, false) KV_SERIALIZE_OPT(get_tx_metadata, false) + KV_SERIALIZE(asset_type) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init request; diff --git a/utils/conf/salviumd.conf b/utils/conf/salviumd.conf new file mode 100644 index 000000000..542b8d54b --- /dev/null +++ b/utils/conf/salviumd.conf @@ -0,0 +1,8 @@ +# Configuration for salviumd +# Syntax: any command line option may be specified as 'clioptionname=value'. +# Boolean options such as 'no-igd' are specified as 'no-igd=1'. +# See 'salviumd --help' for all available options. + +data-dir=/var/lib/salvium +log-file=/var/log/salvium/salvium.log +log-level=0 diff --git a/utils/systemd/salviumd.service b/utils/systemd/salviumd.service new file mode 100644 index 000000000..79d7d6edd --- /dev/null +++ b/utils/systemd/salviumd.service @@ -0,0 +1,20 @@ +[Unit] +Description=Salvium Full Node +After=network.target + +[Service] +User=salvium +Group=salvium +WorkingDirectory=~ +StateDirectory=salvium +LogsDirectory=salvium + +Type=simple +ExecStart=/usr/bin/salviumd --config-file /etc/salviumd.conf --non-interactive +StandardOutput=null +StandardError=null + +Restart=always + +[Install] +WantedBy=multi-user.target