Compare commits

...

32 Commits

Author SHA1 Message Date
Some Random Crypto Guy 1df18ca6a4 added hard fork 2 for v0.6.0 2024-10-22 12:04:03 +01:00
Some Random Crypto Guy 91b2ec275a Updated + fixed translations mechanism; updated fast-sync checkpoints; bumped version 2024-10-22 12:03:29 +01:00
Some Random Crypto Guy e45fdb863c Merge branch 'develop' 2024-10-21 14:18:51 +01:00
Some Random Crypto Guy cb2f9d3f75 updated seed IPs, updated mainnet checksums, bumped version 2024-10-18 14:37:36 +01:00
Some Random Crypto Guy 59025bb27b updated fast-sync checkpoints; updated testnet seed IPs 2024-10-18 13:55:50 +01:00
Some Random Crypto Guy 204c6fc778 fixed issue with migration to new difficulty algorithm; bumped version 2024-10-18 12:37:59 +01:00
Some Random Crypto Guy 78c2b4b1fb import of blockchain scanner - unfinished 2024-10-16 17:55:46 +01:00
Some Random Crypto Guy fcac456902 import of blockchain scanner - unfinished 2024-10-16 17:54:45 +01:00
Some Random Crypto Guy 1824a34a68 bumped version, ready for testnet 2024-10-15 12:08:58 +01:00
Some Random Crypto Guy 1786c628bf disabled yield reporting until daemon is synced 2024-10-15 11:26:14 +01:00
Some Random Crypto Guy 6b8df3cee5 disabled STAKE for multisig - deferred solution until Salvium One 2024-10-15 11:25:42 +01:00
Some Random Crypto Guy 884db2b499 solved issue of STAKE TXs paying out without view_tags; bumped version 2024-10-14 10:55:57 +01:00
Some Random Crypto Guy ce7a1bdd96 working multisig N-out-TX support 2024-10-11 13:38:07 +01:00
Some Random Crypto Guy 57cbb146db working multisig N-out-TX support 2024-10-11 13:29:55 +01:00
Some Random Crypto Guy 85c856411e resolved indexing error with m_transfers_indices changing from vector to set 2024-10-09 13:41:01 +01:00
Some Random Crypto Guy 6fefb49da0 fixed merge regression in wallet; updated build order for binary releases 2024-10-09 13:37:14 +01:00
Some Random Crypto Guy c5c828516b merged N-out-TX and multisig support; implemented new difficulty algorithm; bumped version 2024-10-09 13:20:51 +01:00
Some Random Crypto Guy 218911d9fc bumped RC version 2024-10-09 12:24:29 +01:00
Some Random Crypto Guy da3ef2511d fixed return_payment issues for N-out-TXs; fixed change_index being incorrect datatype; partial fix to asset_type RPC propagation issue 2024-10-09 12:21:50 +01:00
Some Random Crypto Guy 8b2b039036 N-out-TX support working for simple cases - needs edge case testing still 2024-10-08 12:03:20 +01:00
Some Random Crypto Guy 4d1c84fcaf Merge branch 'develop' 2024-10-04 10:06:24 +01:00
Some Random Crypto Guy bb91b01cf7 Merge branch 'multisig' into develop 2024-10-03 13:48:42 +01:00
Some Random Crypto Guy 7f0eda828a disabled staking on multisig wallets 2024-10-03 13:20:25 +01:00
Some Random Crypto Guy d3f15211d7 updated to support multisig wallets; fixed a couple of minor bugs; removed some extraneous code; bumped version 2024-10-03 10:01:29 +01:00
Some Random Crypto Guy b828703bbd added maturation block to output of yield_info in CLI wallet 2024-09-30 14:38:41 +01:00
Some Random Crypto Guy 2fa8ef97ef started work on support for STAKE and BURN commands in multisig 2024-09-30 13:08:07 +01:00
Some Random Crypto Guy acb3af43f0 initial implementation of multisig wallet / TX support 2024-09-27 16:15:42 +01:00
Some Random Crypto Guy d1eed6e9ff interim commit - NOT TESTED 2024-09-14 11:06:23 +01:00
Some Random Crypto Guy 30a2931067 fixed copy/paste glitch on previous 2024-09-09 12:01:15 +01:00
Some Random Crypto Guy 1c73dd0c9f switch to LWMA difficulty algorithm for HF2+ 2024-09-08 19:54:12 +01:00
Some Random Crypto Guy 1c84c00fe6 Merge branch 'main' into develop, ahead of new Salvium One development 2024-09-02 15:26:40 +01:00
SomeRandomDevopsGuy 7abf28d87c feat: Cross-Platform Binary Build and S3 Upload GitHub Action (#5)
* add CI

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

---------

Co-authored-by: SomeRandomDevopsGuy <srdg@srdg.io>
2024-09-02 12:08:32 +01:00
48 changed files with 28520 additions and 27871 deletions
+127
View File
@@ -0,0 +1,127 @@
name: ci/gh-actions/depends
on:
push:
paths-ignore:
- 'docs/**'
- '**/README.md'
pull_request:
paths-ignore:
- 'docs/**'
- '**/README.md'
env:
APT_SET_CONF: |
echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
CCACHE_SETTINGS: |
ccache --max-size=150M
ccache --set-config=compression=true
USE_DEVICE_TREZOR_MANDATORY: ON
jobs:
build-cross:
runs-on: ubuntu-20.04
env:
CCACHE_TEMPDIR: /tmp/.ccache-temp
strategy:
fail-fast: false
matrix:
toolchain:
- name: "RISCV 64bit"
host: "riscv64-linux-gnu"
packages: "python3 gperf g++-riscv64-linux-gnu"
- name: "ARM v7"
host: "arm-linux-gnueabihf"
packages: "python3 gperf g++-arm-linux-gnueabihf"
- name: "ARM v8"
host: "aarch64-linux-gnu"
packages: "python3 gperf g++-aarch64-linux-gnu"
- name: "i686 Win"
host: "i686-w64-mingw32"
packages: "python3 g++-mingw-w64-i686"
- name: "i686 Linux"
host: "i686-pc-linux-gnu"
packages: "gperf cmake g++-multilib python3-zmq"
- name: "Win64"
host: "x86_64-w64-mingw32"
packages: "cmake python3 g++-mingw-w64-x86-64"
- name: "x86_64 Linux"
host: "x86_64-unknown-linux-gnu"
packages: "gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev"
- name: "Cross-Mac x86_64"
host: "x86_64-apple-darwin"
packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
- name: "Cross-Mac aarch64"
host: "aarch64-apple-darwin"
packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
- name: "x86_64 Freebsd"
host: "x86_64-unknown-freebsd"
packages: "clang-8 gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev"
# - name: "ARMv8 Android"
# host: "aarch64-linux-android"
# packages: "gperf cmake python3"
name: ${{ matrix.toolchain.name }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
# Most volatile cache
- name: ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ matrix.toolchain.host }}-${{ github.sha }}
restore-keys: ccache-${{ matrix.toolchain.host }}-
# Less volatile cache
- name: depends cache
uses: actions/cache@v4
with:
path: contrib/depends/built
key: depends-${{ matrix.toolchain.host }}-${{ hashFiles('contrib/depends/packages/*') }}
restore-keys: |
depends-${{ matrix.toolchain.host }}-${{ hashFiles('contrib/depends/packages/*') }}
depends-${{ matrix.toolchain.host }}-
# Static cache
- name: OSX SDK cache
uses: actions/cache@v4
with:
path: contrib/depends/sdk-sources
key: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
restore-keys: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
- name: set apt conf
run: ${{env.APT_SET_CONF}}
- name: install dependencies
run: sudo apt update; sudo apt -y install build-essential libtool libssl-dev cmake autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache ${{ matrix.toolchain.packages }}
- name: prepare w64-mingw32
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'i686-w64-mingw32' }}
run: |
sudo update-alternatives --set ${{ matrix.toolchain.host }}-g++ $(which ${{ matrix.toolchain.host }}-g++-posix)
sudo update-alternatives --set ${{ matrix.toolchain.host }}-gcc $(which ${{ matrix.toolchain.host }}-gcc-posix)
- name: build
run: |
${{env.CCACHE_SETTINGS}}
make depends target=${{ matrix.toolchain.host }} -j2
- uses: actions/upload-artifact@v4
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin' || matrix.toolchain.host == 'aarch64-apple-darwin' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }}
with:
name: ${{ matrix.toolchain.name }}
path: |
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-cli*
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salviumd*
- name: zip daemon & cli
run: |
zip salvium-${GITHUB_REF_NAME}-${{ matrix.toolchain.host }}.zip /home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-rpc* /home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-cli* /home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salviumd*
ls -l
- name: "Deploy"
uses: keithweaver/aws-s3-github-action@v1.0.0
with:
command: cp
source: ./salvium-${{ github.ref_name }}-${{ matrix.toolchain.host }}.zip
destination: s3://${{ vars.S3_BUCKET }}/salvium-${{ github.ref_name }}-${{ matrix.toolchain.host }}.zip
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws_region: eu-west-1
flags: --acl public-read
+4 -4
View File
@@ -1,4 +1,4 @@
# Salvium Zero v0.4.1
# Salvium Zero v0.6.0
Copyright (c) 2023-2024, Salvium
Portions Copyright (c) 2014-2023, The Monero Project
@@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
```bash
git clone https://github.com/salvium/salvium
cd salvium
git checkout v0.4.1
git checkout v0.6.0
```
* Build:
@@ -370,10 +370,10 @@ application.
cd salvium
```
* 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:
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.6.0'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v0.4.1
git checkout v0.6.0
```
* If you are on a 64-bit system, run:
+6 -6
View File
@@ -4,6 +4,12 @@
TAG=`git tag -l --points-at HEAD`
COMMIT=`git rev-parse --short=9 HEAD`
# Build the 64-bit Windows release
USE_DEVICE_TREZOR=OFF make depends target=x86_64-w64-mingw32 -j12
pushd ./build/x86_64-w64-mingw32/release/bin > /dev/null
zip -ur ~/releases/salvium-${TAG}-win64.zip salviumd.exe salvium-wallet-cli.exe salvium-wallet-rpc.exe
popd > /dev/null
# Build the 64-bit Apple Silicon release
USE_DEVICE_TREZOR=OFF make depends target=aarch64-apple-darwin -j12
pushd ./build/aarch64-apple-darwin/release/bin > /dev/null
@@ -22,10 +28,4 @@ pushd ./build/x86_64-linux-gnu/release/bin > /dev/null
zip -ur ~/releases/salvium-${TAG}-linux-x86_64.zip salviumd salvium-wallet-cli salvium-wallet-rpc
popd > /dev/null
# Build the 64-bit Windows release
USE_DEVICE_TREZOR=OFF make depends target=x86_64-w64-mingw32 -j12
pushd ./build/x86_64-w64-mingw32/release/bin > /dev/null
zip -ur ~/releases/salvium-${TAG}-win64.zip salviumd.exe salvium-wallet-cli.exe salvium-wallet-rpc.exe
popd > /dev/null
# Finish
+11 -1
View File
@@ -1261,7 +1261,17 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
yield_tx_info yield_data;
yield_data.block_height = m_height;
yield_data.tx_hash = tx_hash;
yield_data.return_address = tx.return_address;
if (tx.version == TRANSACTION_VERSION_2_OUTS) {
if (tx.return_address == crypto::null_pkey)
throw0(DB_ERROR("missing return_address entry (needed to create yield data for PROTOCOL_TX) - v2 STAKE"));
yield_data.return_address = tx.return_address;
} else if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
if (tx.return_address_list.empty())
throw0(DB_ERROR("no return_address_list entry (needed to create yield data for the PROTOCOL_TX)"));
else if (tx.return_address_list.size() > 1)
throw0(DB_ERROR("too many return_address_list entries provided (only one needed to create yield data for the PROTOCOL_TX)"));
yield_data.return_address = tx.return_address_list[0];
}
yield_data.locked_coins = tx.amount_burnt;
if (tx.vin.empty())
throw0(DB_ERROR("tx.vin is empty (needed to create yield data for the PROTOCOL_TX)"));
+31
View File
@@ -133,6 +133,16 @@ monero_private_headers(blockchain_stats
${blockchain_stats_private_headers})
set(blockchain_scanner_sources
blockchain_scanner.cpp
)
set(blockchain_scanner_private_headers)
monero_private_headers(blockchain_scanner
${blockchain_scanner_private_headers})
monero_add_executable(blockchain_import
${blockchain_import_sources}
${blockchain_import_private_headers})
@@ -281,6 +291,27 @@ set_property(TARGET blockchain_depth
OUTPUT_NAME "salvium-blockchain-depth")
install(TARGETS blockchain_depth DESTINATION bin)
monero_add_executable(blockchain_scanner
${blockchain_scanner_sources}
${blockchain_scanner_private_headers})
target_link_libraries(blockchain_scanner
PRIVATE
cryptonote_core
blockchain_db
version
epee
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${EXTRA_LIBRARIES})
set_property(TARGET blockchain_scanner
PROPERTY
OUTPUT_NAME "salvium-blockchain-scanner")
install(TARGETS blockchain_scanner DESTINATION bin)
monero_add_executable(blockchain_stats
${blockchain_stats_sources}
${blockchain_stats_private_headers})
@@ -0,0 +1,499 @@
// Copyright (c) 2014-2019, The Monero Project
//
// 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.
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include "common/command_line.h"
#include "common/varint.h"
#include "cryptonote_basic/cryptonote_boost_serialization.h"
#include "cryptonote_core/tx_pool.h"
#include "cryptonote_core/cryptonote_core.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
#include "cryptonote_core/blockchain.h"
#include "blockchain_db/blockchain_db.h"
#include "oracle/pricing_record.h"
#include "version.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "bcutil"
#define DELIM "|"
namespace po = boost::program_options;
using namespace epee;
using namespace cryptonote;
static bool stop_requested = false;
int main(int argc, char* argv[])
{
TRY_ENTRY();
epee::string_tools::set_module_name_and_folder(argv[0]);
uint32_t log_level = 0;
uint64_t block_start = 0;
uint64_t block_stop = 0;
tools::on_startup();
boost::filesystem::path output_file_path;
po::options_description desc_cmd_only("Command line options");
po::options_description desc_cmd_sett("Command line options and settings options");
const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
const command_line::arg_descriptor<uint64_t> arg_block_start = {"block-start", "start at block number", block_start};
const command_line::arg_descriptor<uint64_t> arg_block_stop = {"block-stop", "Stop at block number", block_stop};
const command_line::arg_descriptor<std::string> arg_delimiter = {"delimiter", "\"<string>\"", DELIM};
command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir);
command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on);
command_line::add_arg(desc_cmd_sett, cryptonote::arg_stagenet_on);
command_line::add_arg(desc_cmd_sett, arg_log_level);
command_line::add_arg(desc_cmd_sett, arg_block_start);
command_line::add_arg(desc_cmd_sett, arg_block_stop);
command_line::add_arg(desc_cmd_sett, arg_delimiter);
command_line::add_arg(desc_cmd_only, command_line::arg_help);
po::options_description desc_options("Allowed options");
desc_options.add(desc_cmd_only).add(desc_cmd_sett);
po::variables_map vm;
bool r = command_line::handle_error_helper(desc_options, [&]()
{
auto parser = po::command_line_parser(argc, argv).options(desc_options);
po::store(parser.run(), vm);
po::notify(vm);
return true;
});
if (! r)
return 1;
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-stats.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
mlog_set_log(std::string(std::to_string(log_level) + ",bcutil:INFO").c_str());
LOG_PRINT_L0("Starting...");
std::string opt_data_dir = command_line::get_arg(vm, cryptonote::arg_data_dir);
bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
bool opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET;
block_start = command_line::get_arg(vm, arg_block_start);
block_stop = command_line::get_arg(vm, arg_block_stop);
std::string delimiter = command_line::get_arg(vm, arg_delimiter);
// If we wanted to use the memory pool, we would set up a fake_core.
// Use Blockchain instead of lower-level BlockchainDB for two reasons:
// 1. Blockchain has the init() method for easy setup
// 2. exporter needs to use get_current_blockchain_height(), get_block_id_by_height(), get_block_by_hash()
//
// cannot match blockchain_storage setup above with just one line,
// e.g.
// Blockchain* core_storage = new Blockchain(NULL);
// because unlike blockchain_storage constructor, which takes a pointer to
// tx_memory_pool, Blockchain's constructor takes tx_memory_pool object.
LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)");
std::unique_ptr<BlockchainAndPool> core_storage = std::make_unique<BlockchainAndPool>();
BlockchainDB* db = new_db();
if (db == NULL)
{
LOG_ERROR("Failed to initialize a database");
throw std::runtime_error("Failed to initialize a database");
}
LOG_PRINT_L0("database: LMDB");
boost::filesystem::path folder(opt_data_dir);
if (opt_stagenet) {
folder /= std::to_string(STAGENET_VERSION);
} else if (opt_testnet) {
folder /= std::to_string(TESTNET_VERSION);
}
folder /= db->get_db_name();
LOG_PRINT_L0("Loading blockchain from folder " << folder << " ...");
const std::string filename = folder.string();
try
{
db->open(filename, DBF_RDONLY);
}
catch (const std::exception& e)
{
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->blockchain.init(db, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");
tools::signal_handler::install([](int type) {
stop_requested = true;
});
const uint64_t db_height = db->height();
if (!block_stop)
block_stop = db_height;
MINFO("Starting from height " << block_start << ", stopping at height " << block_stop);
/*
* The default output can be plotted with GnuPlot using these commands:
set key autotitle columnhead
set title "Salvium Blockchain Growth"
set timefmt "%Y-%m-%d"
set xdata time
set xrange ["2014-04-17":*]
set format x "%Y-%m-%d"
set yrange [0:*]
set y2range [0:*]
set ylabel "Txs/Day"
set y2label "Bytes"
set y2tics nomirror
plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, '' using (timecolumn(1,"%Y-%m-%d")):7 axes x1y2 with lines
*/
// spit out a comment that GnuPlot can use as an index
std::cout << ENDL << "# DATA" << ENDL;
std::cout << "Date" << delimiter << "Height" << delimiter << "Transaction ID" << delimiter << "Reason" << delimiter << "Extra Information";
std::cout << ENDL;
#define MAX_INOUT 0xffffffff
#define MAX_RINGS 0xffffffff
struct tm prevtm = {0}, currtm;
uint64_t prevsz = 0, currsz = 0;
uint64_t prevtxs = 0, currtxs = 0;
uint64_t currblks = 0;
uint32_t txhr[24] = {0};
unsigned int i;
for (uint64_t h = block_start; h < block_stop; ++h)
{
cryptonote::blobdata bd = db->get_block_blob_from_height(h);
cryptonote::block blk;
if (!cryptonote::parse_and_validate_block_from_blob(bd, blk))
{
LOG_PRINT_L0("Bad block from db");
return 1;
}
time_t tt = blk.timestamp;
char timebuf[64];
epee::misc_utils::get_gmt_time(tt, currtm);
if (!prevtm.tm_year)
prevtm = currtm;
// catch change of day
if (currtm.tm_mday > prevtm.tm_mday || (currtm.tm_mday == 1 && prevtm.tm_mday > 27))
{
// check for timestamp fudging around month ends
if (prevtm.tm_mday == 1 && currtm.tm_mday > 27)
goto skip;
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d", &currtm);
prevtm = currtm;
}
skip:
currsz += bd.size();
uint64_t coinbase_amount;
uint64_t tx_fee_amount = 0;
std::set<std::string> used_assets, miner_tx_assets, protocol_tx_assets;
std::map<size_t, std::vector<std::string>> used_tx_versions;
used_assets.insert("SAL");
// Check TX versions
if (blk.miner_tx.version != 2) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX version detected" << delimiter << "version:" << blk.miner_tx.version << std::endl;
}
if (blk.protocol_tx.version != 2) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "invalid protocol TX version detected" << delimiter << "version:" << blk.protocol_tx.version << std::endl;
}
// Get the miner_tx assets
for (const auto& miner_tx_vout : blk.miner_tx.vout) {
std::string asset_type;
if (!cryptonote::get_output_asset_type(miner_tx_vout, asset_type)) {
throw std::runtime_error("Aborting: failed to get output asset type from miner_tx");
} else if (asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid output asset type from miner_tx");
}
miner_tx_assets.insert(asset_type);
}
// Get the protocol_tx assets
for (const auto& protocol_tx_vout : blk.protocol_tx.vout) {
std::string asset_type;
if (!cryptonote::get_output_asset_type(protocol_tx_vout, asset_type)) {
throw std::runtime_error("Aborting: failed to get output asset type from protocol_tx");
} else if (asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx");
}
protocol_tx_assets.insert(asset_type);
}
for (const auto& tx_id : blk.tx_hashes)
{
if (tx_id == crypto::null_hash)
{
throw std::runtime_error("Aborting: tx == null_hash");
}
if (!db->get_pruned_tx_blob(tx_id, bd))
{
throw std::runtime_error("Aborting: tx not found");
}
transaction tx;
if (!parse_and_validate_tx_base_from_blob(bd, tx))
{
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX detected" << delimiter << std::endl;
continue;
}
currsz += bd.size();
if (db->get_prunable_tx_blob(tx_id, bd))
currsz += bd.size();
currtxs++;
if (tx.version != 2) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX version detected" << delimiter << "version:" << tx.version << std::endl;
}
/*
std::string source;
std::string dest;
offshore::pricing_record pr;
if (!cryptonote::get_tx_asset_types(tx, source, dest, false)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "At least 1 input or 1 output of the tx was invalid" << delimiter << "get_tx_asset_types() failed : ";
if (source.empty()) {
std::cout << "source is empty" << std::endl;
}
if (dest.empty()) {
std::cout << "dest is empty" << std::endl;
}
}
if (!cryptonote::get_tx_type(source, dest, offshore, onshore, offshore_transfer, xusd_to_xasset, xasset_to_xusd, xasset_transfer)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "At least 1 input or 1 output of the tx was invalid" << delimiter << "get_tx_type() failed" << std::endl;
}
*/
// Add the source currency to the list of expected ones
used_assets.insert(tx.source_asset_type);
/*
if ((offshore && !tx.rct_signatures.txnOffshoreFee) ||
(onshore && !tx.rct_signatures.txnOffshoreFee_usd) ||
(xusd_to_xasset && !tx.rct_signatures.txnOffshoreFee_usd) ||
(xasset_to_xusd && !tx.rct_signatures.txnOffshoreFee_xasset)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "Missing conversion fee." << delimiter << "" <<
"Source:" << source << ", dest:" << dest <<
", XHV fees:" << tx.rct_signatures.txnFee << "," << tx.rct_signatures.txnOffshoreFee <<
", XUSD fees:" << tx.rct_signatures.txnFee_usd << "," << tx.rct_signatures.txnOffshoreFee_usd <<
", burnt:" << tx.amount_burnt << ", minted:" << tx.amount_minted << std::endl;
} else if ((offshore || onshore || xusd_to_xasset || xasset_to_xusd) && (!tx.amount_burnt || !tx.amount_minted)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "Missing burnt/minted value." << std::endl;
}
*/
/*
// Only run these checks for conversions
if (source != dest) {
// Check PR record is not too old
if (h > (tx.pricing_record_height + 10)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "pricing record used by tx was too old" <<
delimiter << "tx.pricing_record_height = " << tx.pricing_record_height << std::endl;
}
// Get the PR used by the TX
cryptonote::blobdata bd_pr = db->get_block_blob_from_height(tx.pricing_record_height);
cryptonote::block blk_pr;
if (!cryptonote::parse_and_validate_block_from_blob(bd_pr, blk_pr)) {
LOG_PRINT_L0("Bad block from db");
return 1;
}
// Get a more convenient handle on the conversion PR
pr = blk_pr.pricing_record;
// Verify the fees in 128-bit space
boost::multiprecision::uint128_t burnt_128 = tx.amount_burnt;
boost::multiprecision::uint128_t minted_128 = tx.amount_minted;
// calculate conversion fees
uint32_t fees_version = (h >= 831700) ? 2 : (h >= 653565) ? 2 : 1;
uint64_t blocks_to_unlock = tx.unlock_time - h + 1;
boost::multiprecision::uint128_t fee;
if (offshore) {
if (fees_version >= 3) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid fee version " << fees_version << "" << delimiter << "..." << std::endl;
} else if (fees_version == 2) {
fee =
(blocks_to_unlock >= 5030) ? (tx.amount_burnt / 500) :
(blocks_to_unlock >= 1430) ? (tx.amount_burnt / 20) :
(blocks_to_unlock >= 710) ? (tx.amount_burnt / 10) :
tx.amount_burnt / 5;
} else {
// Calculate the priority based on the unlock time
uint64_t priority =
(blocks_to_unlock >= 5030) ? 1 :
(blocks_to_unlock >= 1430) ? 2 :
(blocks_to_unlock >= 710) ? 3 :
4;
uint64_t unlock_time = 60 * pow(3, 4-priority);
// abs() implementation for uint64_t's
uint64_t delta = (pr.unused1 > pr.xUSD) ? pr.unused1 - pr.xUSD : pr.xUSD - pr.unused1;
// Estimate the fee
double scale = exp((M_PI / -1000.0) * (unlock_time - 60) * 1.2);
scale *= delta;
scale *= tx.amount_burnt;
scale /= 1000000000000;
fee = (boost::multiprecision::uint128_t)(scale);
}
if ((h >= 658500) && (fee != tx.rct_signatures.txnOffshoreFee)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid fee " << tx.rct_signatures.txnOffshoreFee << "" << delimiter << "check:" << fee << std::endl;
}
} else if (onshore) {
if (fees_version >= 3) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid fee version " << fees_version << "" << delimiter << "..." << std::endl;
} else if (fees_version == 2) {
fee =
(blocks_to_unlock >= 5030) ? (tx.amount_burnt / 500) :
(blocks_to_unlock >= 1430) ? (tx.amount_burnt / 20) :
(blocks_to_unlock >= 710) ? (tx.amount_burnt / 10) :
tx.amount_burnt / 5;
} else {
// Calculate the priority based on the unlock time
uint64_t priority =
(blocks_to_unlock >= 5030) ? 1 :
(blocks_to_unlock >= 1430) ? 2 :
(blocks_to_unlock >= 710) ? 3 :
4;
uint64_t unlock_time = 60 * pow(3, 4-priority);
// abs() implementation for uint64_t's
uint64_t delta = (pr.unused1 > pr.xUSD) ? pr.unused1 - pr.xUSD : pr.xUSD - pr.unused1;
// Estimate the fee
double scale = exp((M_PI / -1000.0) * (unlock_time - 60) * 1.2);
scale *= delta;
scale *= tx.amount_burnt;
scale /= 1000000000000;
fee = (boost::multiprecision::uint128_t)(scale);
}
if ((h >= 658500) && (fee != tx.rct_signatures.txnOffshoreFee_usd)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid offshore fee " << tx.rct_signatures.txnOffshoreFee_usd << "" << delimiter << "check:" << fee << std::endl;
}
} else if (xusd_to_xasset) {
fee = tx.amount_burnt;
fee *= 3;
fee /= 1000;
if (fee != tx.rct_signatures.txnOffshoreFee_usd) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid xusd_to_xasset fee " << tx.rct_signatures.txnOffshoreFee_usd << "" << delimiter << "check:" << fee << std::endl;
}
} else if (xasset_to_xusd) {
fee = tx.amount_burnt;
fee *= 3;
fee /= 1000;
if (fee != tx.rct_signatures.txnOffshoreFee_xasset) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid xasset_to_xusd fee " << tx.rct_signatures.txnOffshoreFee_xasset << "" << delimiter << "check:" << fee << std::endl;
}
}
// Check for 0 price in the source or destination currency
if (offshore|| xusd_to_xasset) {
if (!pr[dest]) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "0 exchange rate used for dest " << dest << "" << delimiter << "..." << std::endl;
} else if (pr[dest] == 1000000000000) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "1.0000 exchange rate used for dest " << dest << "" << delimiter << "..." << std::endl;
}
} else if (onshore || xasset_to_xusd) {
if (!pr[source]) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "0 exchange rate used for source " << source << "" << delimiter << "..." << std::endl;
} else if (pr[source] == 1000000000000) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "1.0000 exchange rate used for source " << source << "" << delimiter << "..." << std::endl;
}
}
}
*/
}
/*
// compare the asset sets
if (used_assets == miner_tx_assets) {
} else if (used_assets.empty() && (miner_tx_assets.size() == 1) && (miner_tx_assets.count("XHV") == 1)) {
} else {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "Mismatch in miner reward assets detected" << delimiter << "Used assets = { ";
for (auto const &i: used_assets)
std::cout << i << " ";
std::cout << "}, miner_tx claimed { ";
for (auto const &i: miner_tx_assets)
std::cout << i << " ";
std::cout << "}" << std::endl;
}
*/
currblks++;
if (stop_requested)
break;
}
return 0;
CATCH_ENTRY("Stats reporting error", 1);
}
Binary file not shown.
+13 -3
View File
@@ -200,8 +200,11 @@ namespace cryptonote
std::vector<uint8_t> extra;
// TX type
cryptonote::transaction_type type;
// Return address
crypto::public_key return_address;
// Return address list (must be at least 1 and at most BULLETPROOF_MAX_OUTPUTS-1 - the "-1" is for the change output)
std::vector<crypto::public_key> return_address_list;
//return_address_change_mask
std::vector<uint8_t> return_address_change_mask;
// Return TX public key
crypto::public_key return_pubkey;
// Source asset type
@@ -224,8 +227,13 @@ namespace cryptonote
if (type != cryptonote::transaction_type::PROTOCOL) {
VARINT_FIELD(amount_burnt)
if (type != cryptonote::transaction_type::MINER) {
FIELD(return_address)
FIELD(return_pubkey)
if (type == cryptonote::transaction_type::TRANSFER && version >= TRANSACTION_VERSION_N_OUTS) {
FIELD(return_address_list)
FIELD(return_address_change_mask)
} else {
FIELD(return_address)
FIELD(return_pubkey)
}
FIELD(source_asset_type)
FIELD(destination_asset_type)
VARINT_FIELD(amount_slippage_limit)
@@ -244,6 +252,8 @@ namespace cryptonote
extra.clear();
type = cryptonote::transaction_type::UNSET;
return_address = crypto::null_pkey;
return_address_list.clear();
return_address_change_mask.clear();
return_pubkey = crypto::null_pkey;
source_asset_type.clear();
destination_asset_type.clear();
@@ -166,24 +166,7 @@ namespace boost
inline void serialize(Archive &a, cryptonote::transaction_prefix &x, const boost::serialization::version_type ver)
{
a & x.version;
a & x.vin;
a & x.vout;
a & x.extra;
a & x.type;
if (x.type != cryptonote::transaction_type::MINER && x.type != cryptonote::transaction_type::PROTOCOL) {
a & x.return_address;
a & x.return_pubkey;
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_burnt;
a & x.amount_slippage_limit;
}
}
template <class Archive>
inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver)
{
a & x.version;
a & x.unlock_time;
a & x.vin;
a & x.vout;
a & x.extra;
@@ -191,8 +174,39 @@ namespace boost
if (x.type != cryptonote::transaction_type::PROTOCOL) {
a & x.amount_burnt;
if (x.type != cryptonote::transaction_type::MINER) {
a & x.return_address;
a & x.return_pubkey;
if (x.type == cryptonote::transaction_type::TRANSFER && x.version >= TRANSACTION_VERSION_N_OUTS) {
a & x.return_address_list;
a & x.return_address_change_mask;
} else {
a & x.return_address;
a & x.return_pubkey;
}
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_slippage_limit;
}
}
}
template <class Archive>
inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver)
{
a & x.version;
a & x.unlock_time;
a & x.vin;
a & x.vout;
a & x.extra;
a & x.type;
if (x.type != cryptonote::transaction_type::PROTOCOL) {
a & x.amount_burnt;
if (x.type != cryptonote::transaction_type::MINER) {
if (x.type == cryptonote::transaction_type::TRANSFER && x.version >= TRANSACTION_VERSION_N_OUTS) {
a & x.return_address_list;
a & x.return_address_change_mask;
} else {
a & x.return_address;
a & x.return_pubkey;
}
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_slippage_limit;
@@ -1232,7 +1232,7 @@ namespace cryptonote
{
for (const auto &o: tx.vout)
{
if (hf_version > HF_VERSION_VIEW_TAGS)
if (hf_version > HF_VERSION_REQUIRE_VIEW_TAGS)
{
// from v15, require outputs have view tags
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_tagged_key), false, "wrong variant type: "
@@ -1244,7 +1244,7 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_key in transaction id=" << get_transaction_hash(tx));
}
else //(hf_version == HF_VERSION_VIEW_TAGS)
else //(hf_version == HF_VERSION_VIEW_TAGS || hf_version == HF_VERSION_VIEW_TAGS+1)
{
// require outputs be of type txout_to_key OR txout_to_tagged_key
// to allow grace period before requiring all to be txout_to_tagged_key
@@ -1724,7 +1724,7 @@ namespace cryptonote
blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
crypto::hash tree_root_hash = get_tx_tree_hash(b);
blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
blob.append(tools::get_varint_data(b.tx_hashes.size() + (b.major_version >= HF_VERSION_ENABLE_N_OUTS ? 2 : 1)));
return blob;
}
//---------------------------------------------------------------
+58
View File
@@ -33,6 +33,7 @@
#include <cstddef>
#include <cstdint>
#include <vector>
#include <boost/math/special_functions/round.hpp>
#include "int-util.h"
#include "crypto/hash.h"
@@ -239,6 +240,63 @@ namespace cryptonote {
return res.convert_to<difficulty_type>();
}
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds) {
// LWMA difficulty algorithm
// Copyright (c) 2017-2018 Zawy
// MIT license http://www.opensource.org/licenses/mit-license.php.
// This is an improved version of Tom Harding's (Deger8) "WT-144"
// Karbowanec, Masari, Bitcoin Gold, and Bitcoin Cash have contributed.
// See https://github.com/zawy12/difficulty-algorithms/issues/3 for other algos.
// Do not use "if solvetime < 0 then solvetime = 1" which allows a catastrophic exploit.
// T= target_solvetime;
// N=45, 55, 70, 90, 120 for T=600, 240, 120, 90, and 60
const int64_t T = static_cast<int64_t>(target_seconds);
size_t N = DIFFICULTY_WINDOW_V2;
if (timestamps.size() > N) {
timestamps.resize(N + 1);
cumulative_difficulties.resize(N + 1);
}
size_t n = timestamps.size();
assert(n == cumulative_difficulties.size());
assert(n <= DIFFICULTY_WINDOW_V2);
// If new coin, just "give away" first 5 blocks at low difficulty
if ( n < 6 ) { return 1; }
// If height "n" is from 6 to N, then reset N to n-1.
else if (n < N+1) { N=n-1; }
// To get an average solvetime to within +/- ~0.1%, use an adjustment factor.
// adjust=0.99 for 90 < N < 130
const long double adjust = 0.998;
// The divisor k normalizes LWMA.
const long double k = N * (N + 1) / 2;
long double LWMA(0), sum_inverse_D(0), harmonic_mean_D(0), nextDifficulty(0);
int64_t solveTime(0);
uint64_t difficulty(0), next_difficulty(0);
// Loop through N most recent blocks.
for (size_t i = 1; i <= N; i++) {
solveTime = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i - 1]);
solveTime = std::min<int64_t>((T * 7), std::max<int64_t>(solveTime, (-7 * T)));
difficulty = (cumulative_difficulties[i] - cumulative_difficulties[i - 1]).convert_to<uint64_t>();
LWMA += (int64_t)(solveTime * i) / k;
sum_inverse_D += 1 / static_cast<double>(difficulty);
}
// Keep LWMA sane in case something unforeseen occurs.
if (static_cast<int64_t>(boost::math::round(LWMA)) < T / 20)
LWMA = static_cast<double>(T / 20);
harmonic_mean_D = N / sum_inverse_D * adjust;
nextDifficulty = harmonic_mean_D * T / LWMA;
next_difficulty = static_cast<uint64_t>(nextDifficulty);
return next_difficulty;
}
std::string hex(difficulty_type v)
{
static const char chars[] = "0123456789abcdef";
+2 -1
View File
@@ -58,6 +58,7 @@ namespace cryptonote
bool check_hash_128(const crypto::hash &hash, difficulty_type difficulty);
bool check_hash(const crypto::hash &hash, difficulty_type difficulty);
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
std::string hex(difficulty_type v);
}
@@ -59,6 +59,7 @@ namespace cryptonote
bool m_fee_too_low;
bool m_too_few_outputs;
bool m_tx_extra_too_big;
bool m_version_mismatch; // TX version wrong for the currently-active HF version
};
struct block_verification_context
+13 -5
View File
@@ -42,7 +42,9 @@
#define CRYPTONOTE_MAX_TX_PER_BLOCK 0x10000000
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60
#define CURRENT_TRANSACTION_VERSION 2
#define CURRENT_TRANSACTION_VERSION 3
#define TRANSACTION_VERSION_2_OUTS 2
#define TRANSACTION_VERSION_N_OUTS 3
#define CURRENT_BLOCK_MAJOR_VERSION 1
#define CURRENT_BLOCK_MINOR_VERSION 1
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2
@@ -85,9 +87,11 @@
#define DIFFICULTY_TARGET_V2 120 // seconds
#define DIFFICULTY_TARGET_V1 60 // seconds - before first fork
#define DIFFICULTY_WINDOW_V2 70 // blocks
#define DIFFICULTY_WINDOW 720 // blocks
#define DIFFICULTY_LAG 15 // !!!
#define DIFFICULTY_CUT 60 // timestamps to cut after sorting
#define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2
#define DIFFICULTY_BLOCKS_COUNT DIFFICULTY_WINDOW + DIFFICULTY_LAG
@@ -212,11 +216,15 @@
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT 2
#define HF_VERSION_2021_SCALING 2
#define HF_VERSION_ENABLE_CONVERT 2
#define HF_VERSION_ENABLE_ORACLE 2
#define HF_VERSION_SLIPPAGE_YIELD 2
#define HF_VERSION_ENABLE_N_OUTS 2
#define TESTNET_VERSION 11
#define HF_VERSION_REQUIRE_VIEW_TAGS 3
#define HF_VERSION_ENABLE_CONVERT 255
#define HF_VERSION_ENABLE_ORACLE 255
#define HF_VERSION_SLIPPAGE_YIELD 255
#define TESTNET_VERSION 12
#define STAGENET_VERSION 1
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
+94 -22
View File
@@ -888,6 +888,15 @@ start:
uint64_t height;
auto new_top_hash = get_tail_id(height); // get it again now that we have the lock
++height;
uint8_t version = get_current_hard_fork_version();
size_t difficulty_blocks_count;
if (version == 1) {
difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT;
} else {
difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V2;
}
if (!(new_top_hash == top_hash)) D=0;
ss << "Re-locked, height " << height << ", tail id " << new_top_hash << (new_top_hash == top_hash ? "" : " (different)") << std::endl;
top_hash = new_top_hash;
@@ -900,15 +909,15 @@ start:
bool check = false;
if (m_reset_timestamps_and_difficulties_height)
m_timestamps_and_difficulties_height = 0;
if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= DIFFICULTY_BLOCKS_COUNT)
if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= difficulty_blocks_count)
{
uint64_t index = height - 1;
m_timestamps.push_back(m_db->get_block_timestamp(index));
m_difficulties.push_back(m_db->get_block_cumulative_difficulty(index));
while (m_timestamps.size() > DIFFICULTY_BLOCKS_COUNT)
while (m_timestamps.size() > difficulty_blocks_count)
m_timestamps.erase(m_timestamps.begin());
while (m_difficulties.size() > DIFFICULTY_BLOCKS_COUNT)
while (m_difficulties.size() > difficulty_blocks_count)
m_difficulties.erase(m_difficulties.begin());
m_timestamps_and_difficulties_height = height;
@@ -921,7 +930,7 @@ start:
std::vector<difficulty_type> difficulties_from_cache = difficulties;
{
uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(DIFFICULTY_BLOCKS_COUNT));
uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(difficulty_blocks_count));
if (offset == 0)
++offset;
@@ -967,7 +976,12 @@ start:
}
size_t target = get_difficulty_target();
difficulty_type diff = next_difficulty(timestamps, difficulties, target);
difficulty_type diff;
if (version == 1) {
diff = next_difficulty(timestamps, difficulties, target);
} else {
diff = next_difficulty_v2(timestamps, difficulties, target);
}
CRITICAL_REGION_LOCAL1(m_difficulty_lock);
m_difficulty_for_next_block_top_hash = top_hash;
@@ -1026,11 +1040,18 @@ size_t Blockchain::recalculate_difficulties(boost::optional<uint64_t> start_heig
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> difficulties;
timestamps.reserve(DIFFICULTY_BLOCKS_COUNT + 1);
difficulties.reserve(DIFFICULTY_BLOCKS_COUNT + 1);
uint8_t version = get_current_hard_fork_version();
size_t difficulty_blocks_count;
if (version == 1) {
difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT;
} else {
difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V2;
}
timestamps.reserve(difficulty_blocks_count + 1);
difficulties.reserve(difficulty_blocks_count + 1);
if (start_height > 1)
{
for (uint64_t i = 0; i < DIFFICULTY_BLOCKS_COUNT; ++i)
for (uint64_t i = 0; i < difficulty_blocks_count; ++i)
{
uint64_t height = start_height - 1 - i;
if (height == 0)
@@ -1045,7 +1066,9 @@ size_t Blockchain::recalculate_difficulties(boost::optional<uint64_t> start_heig
for (uint64_t height = start_height; height <= top_height; ++height)
{
size_t target = DIFFICULTY_TARGET_V2;
difficulty_type recalculated_diff = next_difficulty(timestamps, difficulties, target);
difficulty_type recalculated_diff = (version == 1)
? next_difficulty(timestamps, difficulties, target)
: next_difficulty_v2(timestamps, difficulties, target);
boost::multiprecision::uint256_t recalculated_cum_diff_256 = boost::multiprecision::uint256_t(recalculated_diff) + last_cum_diff;
CHECK_AND_ASSERT_THROW_MES(recalculated_cum_diff_256 <= std::numeric_limits<difficulty_type>::max(), "Difficulty overflow!");
@@ -1073,9 +1096,9 @@ size_t Blockchain::recalculate_difficulties(boost::optional<uint64_t> start_heig
timestamps.push_back(m_db->get_block_timestamp(height));
difficulties.push_back(recalculated_cum_diff);
}
if (timestamps.size() > DIFFICULTY_BLOCKS_COUNT)
if (timestamps.size() > difficulty_blocks_count)
{
CHECK_AND_ASSERT_THROW_MES(timestamps.size() == DIFFICULTY_BLOCKS_COUNT + 1, "Wrong timestamps size: " << timestamps.size());
CHECK_AND_ASSERT_THROW_MES(timestamps.size() == difficulty_blocks_count + 1, "Wrong timestamps size: " << timestamps.size());
timestamps.erase(timestamps.begin());
difficulties.erase(difficulties.begin());
}
@@ -1299,16 +1322,23 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
LOG_PRINT_L3("Blockchain::" << __func__);
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> cumulative_difficulties;
uint8_t version = get_current_hard_fork_version();
size_t difficulty_blocks_count;
if (version == 1) {
difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT;
} else {
difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V2;
}
// if the alt chain isn't long enough to calculate the difficulty target
// based on its blocks alone, need to get more blocks from the main chain
if(alt_chain.size()< DIFFICULTY_BLOCKS_COUNT)
if(alt_chain.size()< difficulty_blocks_count)
{
CRITICAL_REGION_LOCAL(m_blockchain_lock);
// Figure out start and stop offsets for main chain blocks
size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front().height : bei.height;
size_t main_chain_count = DIFFICULTY_BLOCKS_COUNT - std::min(static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT), alt_chain.size());
size_t main_chain_count = difficulty_blocks_count - std::min(static_cast<size_t>(difficulty_blocks_count), alt_chain.size());
main_chain_count = std::min(main_chain_count, main_chain_stop_offset);
size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count;
@@ -1323,7 +1353,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
}
// make sure we haven't accidentally grabbed too many blocks...maybe don't need this check?
CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= DIFFICULTY_BLOCKS_COUNT, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << DIFFICULTY_BLOCKS_COUNT);
CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= difficulty_blocks_count, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << difficulty_blocks_count);
for (const auto &bei : alt_chain)
{
@@ -1335,8 +1365,8 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
// and timestamps from it alone
else
{
timestamps.resize(static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT));
cumulative_difficulties.resize(static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT));
timestamps.resize(static_cast<size_t>(difficulty_blocks_count));
cumulative_difficulties.resize(static_cast<size_t>(difficulty_blocks_count));
size_t count = 0;
size_t max_i = timestamps.size()-1;
// get difficulties and timestamps from most recent blocks in alt chain
@@ -1345,7 +1375,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
timestamps[max_i - count] = bei.bl.timestamp;
cumulative_difficulties[max_i - count] = bei.cumulative_difficulty;
count++;
if(count >= DIFFICULTY_BLOCKS_COUNT)
if(count >= difficulty_blocks_count)
break;
}
}
@@ -1354,7 +1384,11 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
size_t target = DIFFICULTY_TARGET_V2;
// calculate the difficulty target for the block and return it
return next_difficulty(timestamps, cumulative_difficulties, target);
if (version == 1) {
return next_difficulty(timestamps, cumulative_difficulties, target);
} else {
return next_difficulty_v2(timestamps, cumulative_difficulties, target);
}
}
//------------------------------------------------------------------
// This function does a sanity check on basic things that all miner
@@ -1448,6 +1482,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
switch (version) {
case HF_VERSION_BULLETPROOF_PLUS:
case HF_VERSION_ENABLE_N_OUTS:
if (b.miner_tx.amount_burnt > 0) {
CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt > money_in_use, false, "miner transaction is overflowed by amount_burnt");
money_in_use += b.miner_tx.amount_burnt;
@@ -3576,6 +3611,43 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
return true;
}
//------------------------------------------------------------------
bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verification_context &tvc) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
const uint8_t hf_version = m_hardfork->get_current_version();
// Prior to v2, only allow TX v2
if (hf_version < HF_VERSION_ENABLE_N_OUTS) {
// Check for N-out TXs
if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
MERROR_VER("N-out TXs are not permitted prior to v" + std::to_string(HF_VERSION_ENABLE_N_OUTS));
tvc.m_version_mismatch = true;
return false;
}
// Check for v1 TXs - genesis block protocol_tx exception required!
if (tx.version == 1 && epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(tx)) == "4f78ff511e860acd03138737a71505eb62eb78b620e180e58c8e13ed0e1e3e19") {
MERROR("v1 TXs are not permitted");
tvc.m_version_mismatch = true;
return false;
}
}
// After v2 allow N-out TXs for TRANSFER ONLY
if (hf_version >= HF_VERSION_ENABLE_N_OUTS) {
if (tx.version >= TRANSACTION_VERSION_N_OUTS && tx.type != cryptonote::transaction_type::TRANSFER) {
MERROR("N-out TXs are only permitted for TRANSFER TX type");
tvc.m_version_mismatch = true;
return false;
}
}
return true;
}
//------------------------------------------------------------------
bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
@@ -3590,7 +3662,7 @@ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const
bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys, const uint8_t &hf_version)
{
PERF_TIMER(expand_transaction_2);
CHECK_AND_ASSERT_MES(tx.version == 2, false, "Transaction version is not 2");
CHECK_AND_ASSERT_MES(tx.version == 2 || tx.version == 3, false, "Transaction version is not 2/3");
rct::rctSig &rv = tx.rct_signatures;
@@ -3779,7 +3851,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
// min/max tx version based on HF, and we accept v1 txes if having a non mixable
const size_t max_tx_version = (hf_version < HF_VERSION_SLIPPAGE_YIELD) ? 2 : CURRENT_TRANSACTION_VERSION;
const size_t max_tx_version = (hf_version >= HF_VERSION_ENABLE_N_OUTS) ? TRANSACTION_VERSION_N_OUTS : TRANSACTION_VERSION_2_OUTS;
if (tx.version > max_tx_version)
{
MERROR_VER("transaction version " << (unsigned)tx.version << " is higher than max accepted version " << max_tx_version);
@@ -6056,7 +6128,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "7f60b4980ea16b32e3f9fc1959d9d4116ba91f2b067bd70b3e21c44520096d14";
static const char expected_block_hashes_hash[] = "3cb6d33c311e54f2b8439a3e4cc047f6b9b74db9fd92955f1db131a5dfce1edf";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)
+13
View File
@@ -725,6 +725,19 @@ namespace cryptonote
*/
bool check_tx_outputs(const transaction& tx, tx_verification_context &tvc) const;
/**
* @brief check that a transaction's version & type conforms to current standards
*
* This function checks, for example at the time of this writing, that
* the TX version and type is supported by the current HF version on-chain.
*
* @param tx the transaction to check the version and type of
* @param tvc returned info about tx verification
*
* @return false if the TX version and/or type is unsupported, otherwise true
*/
bool check_tx_type_and_version(const transaction& tx, tx_verification_context &tvc) const;
/**
* @brief gets the block weight limit based on recent blocks
*
+2 -2
View File
@@ -842,8 +842,8 @@ namespace cryptonote
}
bad_semantics_txes_lock.unlock();
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
const size_t max_tx_version = (version < HF_VERSION_SLIPPAGE_YIELD) ? 2 : CURRENT_TRANSACTION_VERSION;
uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
const size_t max_tx_version = (hf_version >= HF_VERSION_ENABLE_N_OUTS) ? TRANSACTION_VERSION_N_OUTS : TRANSACTION_VERSION_2_OUTS;
if (tx.version == 0 || tx.version > max_tx_version)
{
// v2 is the latest one we know
+62 -31
View File
@@ -46,6 +46,11 @@ using namespace epee;
#include "ringct/rctSigs.h"
#include "oracle/asset_types.h"
extern "C"
{
#include "crypto/keccak.h"
#include "crypto/crypto-ops.h"
}
using namespace crypto;
namespace cryptonote
@@ -572,10 +577,10 @@ namespace cryptonote
uint64_t amount = block_reward;
summary_amounts += amount;
bool use_view_tags = hard_fork_version >= HF_VERSION_VIEW_TAGS;
crypto::view_tag view_tag;
if (use_view_tags)
crypto::derive_view_tag(derivation, 0, view_tag);
bool use_view_tags = hard_fork_version >= HF_VERSION_VIEW_TAGS;
crypto::view_tag view_tag;
if (use_view_tags)
crypto::derive_view_tag(derivation, 0, view_tag);
// Should we award some of the block reward to the stakers?
if (height != 0) {
@@ -583,6 +588,7 @@ namespace cryptonote
// Different forks take a different proportion of the block_reward for stakers
switch (hard_fork_version) {
case HF_VERSION_BULLETPROOF_PLUS:
case HF_VERSION_ENABLE_N_OUTS:
// SRCG: subtract 20% that will be rewarded to staking users
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
tx.amount_burnt = amount / 5;
@@ -653,8 +659,11 @@ namespace cryptonote
tx.set_null();
amount_keys.clear();
if (hf_version >= HF_VERSION_SLIPPAGE_YIELD) {
tx.version = 3;
tx.type = (tx_type == cryptonote::transaction_type::RETURN) ? cryptonote::TRANSFER : tx_type;
// Configure the correct TX version for the current HF + TX type
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER) {
tx.version = TRANSACTION_VERSION_N_OUTS;
} else {
tx.version = 2;
}
@@ -662,8 +671,6 @@ namespace cryptonote
tx.extra = extra;
crypto::public_key txkey_pub;
tx.type = (tx_type == cryptonote::transaction_type::RETURN) ? cryptonote::TRANSFER : tx_type;
tx.source_asset_type = source_asset;
tx.destination_asset_type = dest_asset;
@@ -849,7 +856,7 @@ namespace cryptonote
uint64_t summary_outs_money = 0;
//fill outputs
size_t output_index = 0;
size_t change_index = 0;
uint8_t change_index = 0;
for(const tx_destination_entry& dst_entr: destinations)
{
CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount);
@@ -891,7 +898,7 @@ namespace cryptonote
need_additional_txkeys, additional_tx_keys,
additional_tx_public_keys, amount_keys, out_eph_public_key,
use_view_tags, view_tag);
tx_out out;
cryptonote::set_tx_out(dst_entr.amount, dst_entr.asset_type, dst_entr.is_change ? 0 : unlock_time, out_eph_public_key, use_view_tags, view_tag, out);
tx.vout.push_back(out);
@@ -902,7 +909,51 @@ namespace cryptonote
remove_field_from_tx_extra(tx.extra, typeid(tx_extra_additional_pub_keys));
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE) {
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER) {
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
CHECK_AND_ASSERT_MES(tx.vout.size() >= 2, false, "Internal error - too few outputs for TRANSFER tx");
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key");
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for TRANSFER tx");
// Calculate the F points and change mask for every destination
for (size_t op_index=0; op_index<tx.vout.size(); ++op_index) {
// Calculate the y value for return_payment support
ec_scalar y;
struct {
char domain_separator[8];
rct::key amount_key;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 7);
buf.amount_key = amount_keys[op_index];
crypto::hash_to_scalar(&buf, sizeof(buf), y);
// Now generate the return address (and TX pubkey, although we will discard that)
crypto::public_key F = crypto::null_pkey;
crypto::public_key F_txpubkey = crypto::null_pkey;
CHECK_AND_ASSERT_MES(get_return_address(tx.version, tx.type, y, sender_account_keys, P_change, additional_tx_public_keys[op_index], F, F_txpubkey, hwdev), false, "Failed to get return_address");
// Push the F point into the TX vector of F points
tx.return_address_list.push_back(F);
// Calculate the encrypted_change_index data for this output
struct {
char domain_separator[8];
rct::key amount_key;
} eci_buf;
std::memset(eci_buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(eci_buf.domain_separator, "CHG_IDX", 8);
eci_buf.amount_key = amount_keys[op_index];
crypto::secret_key eci_out;
keccak((uint8_t *)&eci_buf, sizeof(eci_buf), (uint8_t*)&eci_out, sizeof(eci_out));
uint8_t eci_data = change_index ^ eci_out.data[0];
tx.return_address_change_mask.push_back(eci_data);
}
} else if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE) {
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
@@ -1102,26 +1153,7 @@ namespace cryptonote
if (sources[i].rct)
boost::get<txin_to_key>(tx.vin[i]).amount = 0;
}
std::vector<bool> zero_masks;
zero_masks.reserve(tx.vout.size());
for (size_t i = 0; i < tx.vout.size(); ++i) {
if (tx.type == cryptonote::transaction_type::STAKE) {
uint64_t unlock_time = 0;
bool ok = get_output_unlock_time(tx.vout[i], unlock_time);
if (!ok) {
LOG_ERROR("failed to get output asset type for tx.vout[" << i << "]");
return false;
}
if (unlock_time == 0) {
zero_masks.emplace_back(false);
} else {
zero_masks.emplace_back(true);
}
} else {
zero_masks.emplace_back(false);
}
// Clear the amount in the output
tx.vout[i].amount = 0;
}
@@ -1136,7 +1168,6 @@ namespace cryptonote
tx_type,
source_asset,
destination_asset_types,
zero_masks,
inamounts,
outamounts,
fee,
@@ -150,6 +150,7 @@ namespace cryptonote
FIELD(original)
VARINT_FIELD(amount)
FIELD(addr)
FIELD(asset_type)
FIELD(is_subaddress)
FIELD(is_integrated)
FIELD(is_change)
+3 -3
View File
@@ -259,10 +259,10 @@ namespace cryptonote
tvc.m_invalid_output = true;
return false;
}
// Check the TX type
if (tx.type <= cryptonote::transaction_type::UNSET || tx.type > cryptonote::transaction_type::MAX) {
LOG_PRINT_L1("Transaction with id= "<< id << " has invalid type " << (uint8_t)tx.type);
if (!m_blockchain.check_tx_type_and_version(tx, tvc)) {
LOG_PRINT_L1("Transaction with id= "<< id << " has invalid type " << (uint8_t)tx.type << " and/or version " << tx.version);
tvc.m_verifivation_failed = true;
return false;
}
@@ -130,7 +130,7 @@ bool ver_rct_non_semantics_simple_cached
// mixring. Future versions of the protocol may differ in this regard, but if this assumptions
// holds true in the future, enable the verification hash by modifying the `untested_tx`
// condition below.
const bool untested_tx = tx.version > 2 || tx.rct_signatures.type > rct::RCTTypeBulletproofPlus;
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeBulletproofPlus;
VER_ASSERT(!untested_tx, "Unknown TX type. Make sure RCT cache works correctly with this type and then enable it in the code here.");
// Don't cache older (or newer) rctSig types
+4 -4
View File
@@ -35,8 +35,8 @@ const hardfork_t mainnet_hard_forks[] = {
// version 1 from the start of the blockchain
{ 1, 1, 0, 1341378000 },
// version 2 starts from block 1000, which is on or around the 20th of March, 2016. Fork time finalised on 2015-09-20. No fork voting occurs for the v2 fork.
//{ 2, 1000, 0, 1442763710 },
// version 2 starts from block 89800, which is on or around the 4th of November, 2024. Fork time finalised on 2024-10-21. No fork voting occurs for the v2 fork.
{ 2, 89800, 0, 1729518000 },
};
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]);
const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)-1);
@@ -45,8 +45,8 @@ const hardfork_t testnet_hard_forks[] = {
// version 1 from the start of the blockchain
{ 1, 1, 0, 1341378000 },
// version 2 starts from block 1000, which is on or around the 23rd of November, 2015. Fork time finalised on 2015-11-20. No fork voting occurs for the v2 fork.
//{ 2, 1000, 0, 1445355000 },
// version 2 starts from block 250
{ 2, 250, 0, 1445355000 },
};
const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]);
const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1);
+10 -12
View File
@@ -84,13 +84,15 @@ namespace multisig
}
//----------------------------------------------------------------------------------------------------------------------
bool generate_multisig_composite_key_image(const cryptonote::account_keys &keys,
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddresses,
const crypto::public_key &out_key,
const crypto::public_key &tx_public_key,
const std::vector<crypto::public_key> &additional_tx_public_keys,
std::size_t real_output_index,
const std::vector<crypto::key_image> &pkis,
crypto::key_image &ki)
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddresses,
const crypto::public_key &out_key,
const crypto::public_key &tx_public_key,
const std::vector<crypto::public_key> &additional_tx_public_keys,
std::size_t real_output_index,
const std::vector<crypto::key_image> &pkis,
crypto::key_image &ki,
const bool use_origin_data,
const cryptonote::origin_data& origin_tx_data)
{
// create a multisig partial key image
// KI_partial = ([view key component] + [subaddress component] + [multisig privkeys]) * Hp(output one-time address)
@@ -98,11 +100,7 @@ namespace multisig
// - later, we add in the components held by other participants
cryptonote::keypair in_ephemeral;
// Populate this struct if you want to make use of multisig for Salvium!!!
assert(false);
cryptonote::origin_data origin_tx_data;
if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki, keys.get_device(), true, origin_tx_data))
if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki, keys.get_device(), use_origin_data, origin_tx_data))
return false;
std::unordered_set<crypto::key_image> used;
+10 -7
View File
@@ -59,11 +59,14 @@ namespace multisig
crypto::public_key &L,
crypto::public_key &R);
bool generate_multisig_composite_key_image(const cryptonote::account_keys &keys,
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddresses,
const crypto::public_key &out_key,
const crypto::public_key &tx_public_key,
const std::vector<crypto::public_key> &additional_tx_public_keys,
std::size_t real_output_index,
const std::vector<crypto::key_image> &pkis,
crypto::key_image &ki);
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddresses,
const crypto::public_key &out_key,
const crypto::public_key &tx_public_key,
const std::vector<crypto::public_key> &additional_tx_public_keys,
std::size_t real_output_index,
const std::vector<crypto::key_image> &pkis,
crypto::key_image &ki,
const bool use_origin_data,
const cryptonote::origin_data& origin_tx_data
);
} //namespace multisig
+357 -46
View File
@@ -58,6 +58,67 @@
namespace multisig {
rct::key sm(rct::key y, int n, const rct::key &x)
{
while (n--)
sc_mul(y.bytes, y.bytes, y.bytes);
sc_mul(y.bytes, y.bytes, x.bytes);
return y;
}
// Compute the inverse of a scalar, the clever way
rct::key invert(const rct::key &x)
{
rct::key _1, _10, _100, _11, _101, _111, _1001, _1011, _1111;
_1 = x;
sc_mul(_10.bytes, _1.bytes, _1.bytes);
sc_mul(_100.bytes, _10.bytes, _10.bytes);
sc_mul(_11.bytes, _10.bytes, _1.bytes);
sc_mul(_101.bytes, _10.bytes, _11.bytes);
sc_mul(_111.bytes, _10.bytes, _101.bytes);
sc_mul(_1001.bytes, _10.bytes, _111.bytes);
sc_mul(_1011.bytes, _10.bytes, _1001.bytes);
sc_mul(_1111.bytes, _100.bytes, _1011.bytes);
rct::key inv;
sc_mul(inv.bytes, _1111.bytes, _1.bytes);
inv = sm(inv, 123 + 3, _101);
inv = sm(inv, 2 + 2, _11);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 4, _1001);
inv = sm(inv, 2, _11);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 1 + 3, _101);
inv = sm(inv, 3 + 3, _101);
inv = sm(inv, 3, _111);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 2 + 3, _111);
inv = sm(inv, 2 + 2, _11);
inv = sm(inv, 1 + 4, _1011);
inv = sm(inv, 2 + 4, _1011);
inv = sm(inv, 6 + 4, _1001);
inv = sm(inv, 2 + 2, _11);
inv = sm(inv, 3 + 2, _11);
inv = sm(inv, 3 + 2, _11);
inv = sm(inv, 1 + 4, _1001);
inv = sm(inv, 1 + 3, _111);
inv = sm(inv, 2 + 4, _1111);
inv = sm(inv, 1 + 4, _1011);
inv = sm(inv, 3, _101);
inv = sm(inv, 2 + 4, _1111);
inv = sm(inv, 3, _101);
inv = sm(inv, 1 + 2, _11);
// Sanity check for successful inversion
rct::key tmp;
sc_mul(tmp.bytes, inv.bytes, x.bytes);
CHECK_AND_ASSERT_THROW_MES(tmp == rct::identity(), "invert failed");
return inv;
}
namespace signing {
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
@@ -108,9 +169,12 @@ static bool compute_keys_for_sources(
if (src.real_output >= src.outputs.size())
return false;
/*
// Populate this struct if you want to make use of multisig for Salvium!!!
assert(false);
cryptonote::origin_data origin_tx_data;
*/
bool use_origin_data = (src.origin_tx_data.tx_type != cryptonote::transaction_type::UNSET);
if (not cryptonote::generate_key_image_helper(
account_keys,
@@ -122,8 +186,8 @@ static bool compute_keys_for_sources(
tmp_keys,
tmp_key_image,
hwdev,
true,
origin_tx_data
use_origin_data,
src.origin_tx_data
)) {
return false;
}
@@ -338,27 +402,28 @@ static bool compute_keys_for_destinations(
std::vector<crypto::secret_key>& tx_aux_secret_keys,
rct::keyV& output_public_keys,
rct::keyV& output_amount_secret_keys,
std::vector<std::string>& asset_types,
std::vector<crypto::view_tag>& view_tags,
std::vector<uint64_t>& destination_amounts,
const cryptonote::transaction_type& tx_type,
bool& found_change,
std::size_t& change_index,
cryptonote::transaction& unsigned_tx
)
{
hw::device &hwdev = account_keys.get_device();
// check non-zero change amount case
if (change.amount > 0)
{
// the change output must be directed to the local account
if (change.addr != hwdev.get_subaddress(account_keys, {subaddr_account}))
return false;
// the change output must be directed to the local account
if (change.addr != hwdev.get_subaddress(account_keys, {subaddr_account}))
return false;
// expect the change destination to be in the destination set
if (std::find_if(destinations.begin(), destinations.end(),
[&change](const auto &destination) -> bool
{
return destination.addr == change.addr;
}) == destinations.end())
return false;
}
// expect the change destination to be in the destination set
if (std::find_if(destinations.begin(), destinations.end(),
[&change](const auto &destination) -> bool
{
return destination.addr == change.addr;
}) == destinations.end())
return false;
// collect non-change recipients into normal/subaddress buckets
std::unordered_set<cryptonote::account_public_address> unique_subbaddr_recipients;
@@ -423,12 +488,35 @@ static bool compute_keys_for_destinations(
}
// additional tx pubkeys: R_t
output_public_keys.resize(num_destinations);
view_tags.resize(num_destinations);
output_public_keys.clear();
view_tags.clear();
asset_types.clear();
destination_amounts.clear();
found_change = false;
std::vector<crypto::public_key> tx_aux_public_keys;
crypto::public_key temp_output_public_key;
size_t output_index = 0;
uint64_t amount_burnt = 0;
uint64_t amount_slippage_limit = 0;
for (std::size_t i = 0; i < num_destinations; ++i) {
// Is this a BURN or CONVERT TX?
if (tx_type == cryptonote::transaction_type::BURN || tx_type == cryptonote::transaction_type::CONVERT) {
// Do not create outputs that are for the destination asset type - discard them as unused
if (destinations[i].asset_type == unsigned_tx.destination_asset_type) {
amount_burnt += destinations[i].amount;
amount_slippage_limit = destinations[i].slippage_limit;
continue;
}
} else if (tx_type == cryptonote::transaction_type::STAKE) {
// Do not create outputs that are staked for yield - discard them as unused
if (!destinations[i].is_change) {
amount_burnt += destinations[i].amount;
continue;
}
}
crypto::view_tag vt; // Temporary variable to hold the view tag in case we create one
if (not hwdev.generate_output_ephemeral_keys(
unsigned_tx.version,
account_keys,
@@ -436,23 +524,42 @@ static bool compute_keys_for_destinations(
tx_secret_key,
destinations[i],
change.addr,
i,
output_index,
need_tx_aux_keys,
tx_aux_secret_keys,
tx_aux_public_keys,
output_amount_secret_keys,
temp_output_public_key,
use_view_tags,
view_tags[i] //unused variable if use_view_tags is not set
vt
)) {
return false;
}
output_public_keys[i] = rct::pk2rct(temp_output_public_key);
output_public_keys.push_back(rct::pk2rct(temp_output_public_key));
asset_types.push_back(destinations[i].asset_type);
if (use_view_tags)
view_tags.push_back(vt);
destination_amounts.push_back(destinations[i].amount);
if (destinations[i].is_change) {
found_change = true;
change_index = output_index; // Store the change_index - we will need this
}
output_index++;
}
if (num_destinations != output_amount_secret_keys.size())
return false;
//if (num_destinations != output_amount_secret_keys.size())
// return false;
if (reconstruction) {
// Verify the values match the unsigned_tx
CHECK_AND_ASSERT_MES(amount_burnt == unsigned_tx.amount_burnt, false, "Internal error - amount_burnt does not match unsigned_tx");
CHECK_AND_ASSERT_MES(amount_slippage_limit == unsigned_tx.amount_slippage_limit, false, "Internal error - amount_slippage_limit does not match unsigned_tx");
} else {
// Store the calculated values
unsigned_tx.amount_burnt = amount_burnt;
unsigned_tx.amount_slippage_limit = amount_slippage_limit;
}
CHECK_AND_ASSERT_MES(
tx_aux_public_keys.size() == tx_aux_secret_keys.size(),
false,
@@ -500,7 +607,11 @@ static bool onetime_addresses_are_unique(const rct::keyV& output_public_keys)
}
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
static bool set_tx_outputs(const rct::keyV& output_public_keys, cryptonote::transaction& unsigned_tx)
static bool set_tx_outputs(
const rct::keyV& output_public_keys,
const std::vector<std::string>& asset_types,
cryptonote::transaction& unsigned_tx
)
{
// sanity check: all onetime addresses should be unique
if (not onetime_addresses_are_unique(output_public_keys))
@@ -508,9 +619,11 @@ static bool set_tx_outputs(const rct::keyV& output_public_keys, cryptonote::tran
// set the tx outputs
const std::size_t num_destinations = output_public_keys.size();
CHECK_AND_ASSERT_MES(asset_types.size() == num_destinations, false,
"multisig signing protocol: internal error, asset_type array size mismatch.");
unsigned_tx.vout.resize(num_destinations);
for (std::size_t i = 0; i < num_destinations; ++i)
cryptonote::set_tx_out(0, "SAL", 0, rct::rct2pk(output_public_keys[i]), false, crypto::view_tag{}, unsigned_tx.vout[i]);
cryptonote::set_tx_out(0, asset_types[i], 0, rct::rct2pk(output_public_keys[i]), false, crypto::view_tag{}, unsigned_tx.vout[i]);
return true;
}
@@ -518,6 +631,7 @@ static bool set_tx_outputs(const rct::keyV& output_public_keys, cryptonote::tran
//----------------------------------------------------------------------------------------------------------------------
static bool set_tx_outputs_with_view_tags(
const rct::keyV& output_public_keys,
const std::vector<std::string>& asset_types,
const std::vector<crypto::view_tag>& view_tags,
cryptonote::transaction& unsigned_tx
)
@@ -528,11 +642,13 @@ static bool set_tx_outputs_with_view_tags(
// set the tx outputs (with view tags)
const std::size_t num_destinations = output_public_keys.size();
CHECK_AND_ASSERT_MES(asset_types.size() == num_destinations, false,
"multisig signing protocol: internal error, asset_type array size mismatch.");
CHECK_AND_ASSERT_MES(view_tags.size() == num_destinations, false,
"multisig signing protocol: internal error, view tag size mismatch.");
unsigned_tx.vout.resize(num_destinations);
for (std::size_t i = 0; i < num_destinations; ++i)
cryptonote::set_tx_out(0, "SAL", 0, rct::rct2pk(output_public_keys[i]), true, view_tags[i], unsigned_tx.vout[i]);
cryptonote::set_tx_out(0, asset_types[i], 0, rct::rct2pk(output_public_keys[i]), true, view_tags[i], unsigned_tx.vout[i]);
return true;
}
@@ -589,11 +705,112 @@ static bool try_reconstruct_range_proofs(const int bp_version,
return false;
}
//----------------------------------------------------------------------------------------------------------------------
static bool set_tx_return_address_information(const uint8_t hf_version,
const cryptonote::account_keys& account_keys,
const bool reconstruction,
size_t change_index,
crypto::public_key& txkey_pub,
cryptonote::transaction& unsigned_tx
)
{
if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER || unsigned_tx.type == cryptonote::transaction_type::STAKE) {
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER) {
if (hf_version >= HF_VERSION_ENABLE_N_OUTS) {
CHECK_AND_ASSERT_MES(unsigned_tx.vout.size() >= 2, false, "Internal error - incorrect number of outputs (<2) for TRANSFER tx");
} else {
CHECK_AND_ASSERT_MES(unsigned_tx.vout.size() == 2, false, "Internal error - incorrect number of outputs (!=2) for TRANSFER tx");
}
} else if (unsigned_tx.type == cryptonote::transaction_type::STAKE) {
CHECK_AND_ASSERT_MES(unsigned_tx.vout.size() == 1, false, "Internal error - incorrect number of outputs (!=1) for STAKE tx");
}
CHECK_AND_ASSERT_MES(change_index < unsigned_tx.vout.size(), false, "Internal error - invalid change_index");
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(unsigned_tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key");
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for TRANSFER tx");
// Get the uniqueness for this TX
crypto::ec_scalar y;
struct {
char domain_separator[8];
crypto::public_key pubkey;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 7);
buf.pubkey = P_change;
crypto::hash_to_scalar(&buf, sizeof(buf), y);
hw::device& hwdev = account_keys.get_device();
// First, we need to produce the multiplicative inverse of the scalar "y" (aka "y^-1")
rct::key key_y = (rct::key&)(y);
rct::key key_inv_y = invert(key_y);
crypto::public_key pk_aP_change = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(P_change), rct::sk2rct(account_keys.m_view_secret_key)));
// Sanity check that we can reverse the invert safely
rct::key key_aP_change = rct::pk2rct(pk_aP_change);
rct::key key_F = rct::scalarmultKey(key_aP_change, key_inv_y);
rct::key key_verify = rct::scalarmultKey(key_F, key_y);
CHECK_AND_ASSERT_MES(key_verify == key_aP_change, false, "at get_return_address: failed to verify invert() function with smK() approach");
if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER) {
// Store the F point - we do not need to generate a full return address in this instance
if (not reconstruction)
unsigned_tx.return_address = rct::rct2pk(key_F);
// Clear the pubkey, because it isn't used
if (not reconstruction)
unsigned_tx.return_pubkey = crypto::null_pkey;
} else if (unsigned_tx.type == cryptonote::transaction_type::STAKE) {
// CONVERT / YIELD Semantics
// From this point forward, we are departing from the original "return address" scheme
// We have to derive the full return address and TX pubkey, because PROTOCOL_TX cannot
// First, create a secret TX key (= s) - this will be lost at the end of this function, but that's OK
crypto::secret_key s = cryptonote::keypair::generate(hw::get_device("default")).sec;
// Next, calculate the corresponding TX public key (= sP_change)
// This has to be done using smK() call because of g_k_d() performing a torsion clear
if (not reconstruction)
unsigned_tx.return_pubkey = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(P_change), rct::sk2rct(s)));
// Next, calculate a derivation using the TX public key and our secret view key
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
bool r = hwdev.generate_key_derivation(unsigned_tx.return_pubkey, account_keys.m_view_secret_key, derivation);
CHECK_AND_ASSERT_MES(r, false, "in get_return_address(): failed to generate_key_derivation(" << unsigned_tx.return_pubkey << ", <view secret key>)");
// Finally, calculate the onetime address to be used for returns
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
r = crypto::derive_public_key(derivation, 0, P_change, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "in get_return_address(): failed to derive_public_key(" << derivation << ", " << key_y << ", "<< P_change << ")");
// Sanity checks
crypto::public_key P_change_verify = crypto::null_pkey;
r = crypto::derive_subaddress_public_key(out_eph_public_key, derivation, 0, P_change_verify);
CHECK_AND_ASSERT_MES(r, false, "in get_return_address(): failed sanity check derive_subaddress_public_key(" << out_eph_public_key << ", " << derivation << ", " << key_y << ", " << P_change_verify << ")");
CHECK_AND_ASSERT_MES(P_change == P_change_verify, false, "in get_return_address(): failed sanity check (keys do not match)");
// All is well - copy the return address
if (not reconstruction)
unsigned_tx.return_address = out_eph_public_key;
} else {
assert(false);
}
}
return true;
}
//----------------------------------------------------------------------------------------------------------------------
static bool set_tx_rct_signatures(
const std::uint64_t fee,
const std::vector<cryptonote::tx_source_entry>& sources,
const std::vector<cryptonote::tx_destination_entry>& destinations,
const std::vector<uint64_t>& destination_amounts,
const rct::keyV& input_secret_keys,
const rct::keyV& output_public_keys,
const rct::keyV& output_amount_secret_keys,
@@ -610,7 +827,7 @@ static bool set_tx_rct_signatures(
if (rct_config.range_proof_type != rct::RangeProofPaddedBulletproof)
return false;
const std::size_t num_destinations = destinations.size();
const std::size_t num_destinations = destination_amounts.size();
const std::size_t num_sources = sources.size();
// rct_signatures component of tx
@@ -633,7 +850,7 @@ static bool set_tx_rct_signatures(
rv.outPk.resize(num_destinations);
for (std::size_t i = 0; i < num_destinations; ++i) {
rv.outPk[i].dest = output_public_keys[i];
output_amounts[i] = destinations[i].amount;
output_amounts[i] = destination_amounts[i];
output_amount_masks[i] = genCommitmentMask(output_amount_secret_keys[i]);
rv.ecdhInfo[i].amount = rct::d2h(output_amounts[i]);
rct::addKeys2(
@@ -677,35 +894,38 @@ static bool set_tx_rct_signatures(
if (not reconstruction) {
a.resize(num_sources);
rv.p.pseudoOuts.resize(num_sources);
a[num_sources - 1] = rct::zero();
rct::key difference = rct::zero();
rct::key sumpouts = rct::zero();
rct::key sumouts = rct::zero();
for (std::size_t i = 0; i < num_destinations; ++i) {
sc_add(
a[num_sources - 1].bytes,
a[num_sources - 1].bytes,
sumouts.bytes,
sumouts.bytes,
output_amount_masks[i].bytes
);
}
for (std::size_t i = 0; i < num_sources - 1; ++i) {
for (std::size_t i = 0; i < num_sources; ++i) {
rct::skGen(a[i]);
sc_sub(
a[num_sources - 1].bytes,
a[num_sources - 1].bytes,
sc_add(
sumpouts.bytes,
sumpouts.bytes,
a[i].bytes
);
rct::genC(rv.p.pseudoOuts[i], a[i], sources[i].amount);
}
rct::genC(
rv.p.pseudoOuts[num_sources - 1],
a[num_sources - 1],
sources[num_sources - 1].amount
);
sc_sub(difference.bytes, sumpouts.bytes, sumouts.bytes);
rct::genC(rv.p_r, difference, 0);
}
// check balance if reconstructing the tx
else {
rv.p.pseudoOuts = unsigned_tx.rct_signatures.p.pseudoOuts;
rv.p_r = unsigned_tx.rct_signatures.p_r;
if (num_sources != rv.p.pseudoOuts.size())
return false;
rct::key balance_accumulator = rct::scalarmultH(rct::d2h(fee));
rct::key txnAmountBurntKey = rct::scalarmultH(rct::d2h(unsigned_tx.amount_burnt));
rct::addKeys(balance_accumulator, balance_accumulator, rv.p_r);
rct::addKeys(balance_accumulator, balance_accumulator, txnAmountBurntKey);
for (const auto& e: rv.outPk)
rct::addKeys(balance_accumulator, balance_accumulator, e.mask);
for (const auto& pseudoOut: rv.p.pseudoOuts)
@@ -828,6 +1048,8 @@ tx_builder_ringct_t::~tx_builder_ringct_t()
bool tx_builder_ringct_t::init(
const cryptonote::account_keys& account_keys,
const std::vector<std::uint8_t>& extra,
const cryptonote::transaction_type& tx_type,
const std::uint8_t hf_version,
const std::uint64_t unlock_time,
const std::uint32_t subaddr_account,
const std::set<std::uint32_t>& subaddr_minor_indices,
@@ -860,9 +1082,20 @@ bool tx_builder_ringct_t::init(
// decide if view tags are needed
const bool use_view_tags{view_tag_required(rct_config.bp_version)};
// Configure the correct TX version for the current HF + TX type
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && tx_type == cryptonote::transaction_type::TRANSFER) {
unsigned_tx.version = TRANSACTION_VERSION_N_OUTS;
} else {
unsigned_tx.version = 2;
}
// misc. fields
unsigned_tx.version = 2; //rct = 2
unsigned_tx.unlock_time = unlock_time;
unsigned_tx.type = (tx_type == cryptonote::transaction_type::RETURN) ? cryptonote::TRANSFER : tx_type;
unsigned_tx.source_asset_type = "SAL";
if (tx_type == cryptonote::transaction_type::BURN)
unsigned_tx.destination_asset_type = "BURN";
else
unsigned_tx.destination_asset_type = "SAL";
// sort inputs
sort_sources(sources);
@@ -899,7 +1132,11 @@ bool tx_builder_ringct_t::init(
// prepare outputs
rct::keyV output_public_keys;
rct::keyV output_amount_secret_keys;
std::vector<std::string> asset_types;
std::vector<crypto::view_tag> view_tags;
std::vector<uint64_t> destination_amounts;
bool found_change{false};
std::size_t change_index;
auto output_amount_secret_keys_wiper = epee::misc_utils::create_scope_leave_handler([&]{
memwipe(static_cast<rct::key *>(output_amount_secret_keys.data()), output_amount_secret_keys.size() * sizeof(rct::key));
});
@@ -915,25 +1152,99 @@ bool tx_builder_ringct_t::init(
tx_aux_secret_keys,
output_public_keys,
output_amount_secret_keys,
asset_types,
view_tags,
destination_amounts,
tx_type,
found_change,
change_index,
unsigned_tx))
return false;
// Check that the change element was found
if (!found_change)
return false;
// add inputs to tx
set_tx_inputs(sources, unsigned_tx);
// add output one-time addresses to tx
bool set_tx_outputs_result{false};
if (use_view_tags)
set_tx_outputs_result = set_tx_outputs_with_view_tags(output_public_keys, view_tags, unsigned_tx);
set_tx_outputs_result = set_tx_outputs_with_view_tags(output_public_keys, asset_types, view_tags, unsigned_tx);
else
set_tx_outputs_result = set_tx_outputs(output_public_keys, unsigned_tx);
set_tx_outputs_result = set_tx_outputs(output_public_keys, asset_types, unsigned_tx);
if (not set_tx_outputs_result)
return false;
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && unsigned_tx.type == cryptonote::transaction_type::TRANSFER) {
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
CHECK_AND_ASSERT_MES(unsigned_tx.vout.size() >= 2, false, "Internal error - too few outputs for multisig TRANSFER tx");
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(unsigned_tx.vout[change_index], P_change), false, "Internal error - failed to get multisig TX change output public key");
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for multisig TRANSFER tx");
// Calculate the F points and change mask for every destination
for (size_t op_index=0; op_index<unsigned_tx.vout.size(); ++op_index) {
// Calculate the y value for return_payment support
crypto::ec_scalar y;
struct {
char domain_separator[8];
rct::key amount_key;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 7);
buf.amount_key = output_amount_secret_keys[op_index];
crypto::hash_to_scalar(&buf, sizeof(buf), y);
// Now generate the return address EC point
// F = (y^-1).a.P_change
// First, we need to produce the multiplicative inverse of the scalar "y" (aka "y^-1")
rct::key key_y = (rct::key&)(y);
rct::key key_inv_y = invert(key_y);
crypto::public_key pk_aP_change = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(P_change), rct::sk2rct(account_keys.m_view_secret_key)));
// Sanity check that we can reverse the invert safely
rct::key key_aP_change = rct::pk2rct(pk_aP_change);
rct::key key_F = rct::scalarmultKey(key_aP_change, key_inv_y);
rct::key key_verify = rct::scalarmultKey(key_F, key_y);
CHECK_AND_ASSERT_MES(key_verify == key_aP_change, false, "at get_return_address: failed to verify invert() function with smK() approach");
// Push the F point into the TX vector of F points
if (not reconstruction)
unsigned_tx.return_address_list.push_back(rct::rct2pk(key_F));
// Calculate the encrypted_change_index data for this output
struct {
char domain_separator[8];
rct::key amount_key;
} eci_buf;
std::memset(eci_buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(eci_buf.domain_separator, "CHG_IDX", 8);
eci_buf.amount_key = output_amount_secret_keys[op_index];
crypto::secret_key eci_out;
keccak((uint8_t *)&eci_buf, sizeof(eci_buf), (uint8_t*)&eci_out, sizeof(eci_out));
uint8_t eci_data = change_index ^ eci_out.data[0];
if (not reconstruction)
unsigned_tx.return_address_change_mask.push_back(eci_data);
}
} else if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER || unsigned_tx.type == cryptonote::transaction_type::STAKE) {
// Get the tx public key
crypto::public_key txkey_pub = crypto::null_pkey;
// Calculate the return_address information needed
if (not set_tx_return_address_information(hf_version, account_keys, reconstruction, change_index, txkey_pub, unsigned_tx))
return false;
}
// prepare input signatures
if (not set_tx_rct_signatures(fee, sources, destinations, input_secret_keys, output_public_keys, output_amount_secret_keys,
if (not set_tx_rct_signatures(fee, sources, destination_amounts, input_secret_keys, output_public_keys, output_amount_secret_keys,
rct_config, reconstruction, unsigned_tx, CLSAG_contexts, cached_w))
return false;
@@ -29,6 +29,7 @@
#pragma once
#include "cryptonote_protocol/enums.h"
#include "ringct/rctTypes.h"
#include <set>
@@ -71,6 +72,8 @@ public:
bool init(
const cryptonote::account_keys& account_keys,
const std::vector<std::uint8_t>& extra,
const cryptonote::transaction_type& type,
const std::uint8_t hf_version,
const std::uint64_t unlock_time,
const std::uint32_t subaddr_account,
const std::set<std::uint32_t>& subaddr_minor_indices,
+6 -6
View File
@@ -705,9 +705,9 @@ namespace nodetool
std::set<std::string> full_addrs;
if (m_nettype == cryptonote::TESTNET)
{
full_addrs.insert("152.42.130.46:29080");
full_addrs.insert("45.55.138.87:29080");
full_addrs.insert("209.97.164.15:29080");
full_addrs.insert("72.5.43.63:29080");
full_addrs.insert("195.85.114.217:29080");
full_addrs.insert("206.188.197.72:29080");
}
else if (m_nettype == cryptonote::STAGENET)
{
@@ -720,9 +720,9 @@ namespace nodetool
}
else
{
full_addrs.insert("152.42.130.46:19080");
full_addrs.insert("45.55.138.87:19080");
full_addrs.insert("209.97.164.15:19080");
full_addrs.insert("193.149.187.26:19080");
full_addrs.insert("67.217.228.15:19080");
full_addrs.insert("216.245.184.4:19080");
}
return full_addrs;
}
+1 -4
View File
@@ -1110,7 +1110,6 @@ namespace rct {
const cryptonote::transaction_type tx_type,
const std::string& in_asset_type,
const std::vector<std::string> & destination_asset_types,
const std::vector<bool> &zero_masks,
const std::vector<xmr_amount> &inamounts,
const std::vector<xmr_amount> &outamounts,
xmr_amount txnFee,
@@ -1127,7 +1126,6 @@ namespace rct {
CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk");
CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations");
CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations");
CHECK_AND_ASSERT_THROW_MES(zero_masks.size() == destinations.size(), "Different number of zero_masks/destinations");
CHECK_AND_ASSERT_THROW_MES(index.size() == inSk.size(), "Different number of index/inSk");
CHECK_AND_ASSERT_THROW_MES(mixRing.size() == inSk.size(), "Different number of mixRing/inSk");
for (size_t n = 0; n < mixRing.size(); ++n) {
@@ -1312,7 +1310,6 @@ namespace rct {
const cryptonote::transaction_type tx_type,
const std::string& in_asset_type,
const std::vector<std::string> & destination_asset_types,
const std::vector<bool> &zero_masks,
const std::vector<xmr_amount> &inamounts,
const std::vector<xmr_amount> &outamounts,
const keyV &amount_keys,
@@ -1330,7 +1327,7 @@ namespace rct {
mixRing[i].resize(mixin+1);
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
}
return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, zero_masks, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev);
return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev);
}
//RingCT protocol
-2
View File
@@ -136,7 +136,6 @@ namespace rct {
const cryptonote::transaction_type tx_type,
const std::string& in_asset_type,
const std::vector<std::string> & destination_asset_types,
const std::vector<bool> &zero_masks,
const std::vector<xmr_amount> & inamounts,
const std::vector<xmr_amount> & outamounts,
const keyV &amount_keys,
@@ -152,7 +151,6 @@ namespace rct {
const cryptonote::transaction_type tx_type,
const std::string& in_asset_type,
const std::vector<std::string> & destination_asset_types,
const std::vector<bool> &zero_masks,
const std::vector<xmr_amount> & inamounts,
const std::vector<xmr_amount> & outamounts,
xmr_amount txnFee,
+1
View File
@@ -2998,6 +2998,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_yield_info(const COMMAND_RPC_GET_YIELD_INFO::request& req, COMMAND_RPC_GET_YIELD_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
CHECK_CORE_READY();
PERF_TIMER(on_get_yield_info);
uint64_t height = m_core.get_current_blockchain_height();
std::map<uint64_t, yield_block_info> ybi_cache;
+36
View File
@@ -269,6 +269,22 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::t
INSERT_INTO_JSON_OBJECT(dest, inputs, tx.vin);
INSERT_INTO_JSON_OBJECT(dest, outputs, tx.vout);
INSERT_INTO_JSON_OBJECT(dest, extra, tx.extra);
INSERT_INTO_JSON_OBJECT(dest, type, static_cast<uint8_t>(tx.type));
if (tx.type != cryptonote::transaction_type::PROTOCOL) {
INSERT_INTO_JSON_OBJECT(dest, amount_burnt, tx.amount_burnt);
if (tx.type != cryptonote::transaction_type::MINER) {
if (tx.type == cryptonote::transaction_type::TRANSFER && tx.version >= TRANSACTION_VERSION_N_OUTS) {
INSERT_INTO_JSON_OBJECT(dest, return_address_list, tx.return_address_list);
INSERT_INTO_JSON_OBJECT(dest, return_address_change_mask, tx.return_address_change_mask);
} else {
INSERT_INTO_JSON_OBJECT(dest, return_address, tx.return_address);
INSERT_INTO_JSON_OBJECT(dest, return_pubkey, tx.return_pubkey);
}
INSERT_INTO_JSON_OBJECT(dest, source_asset_type, tx.source_asset_type);
INSERT_INTO_JSON_OBJECT(dest, destination_asset_type, tx.destination_asset_type);
INSERT_INTO_JSON_OBJECT(dest, amount_slippage_limit, tx.amount_slippage_limit);
}
}
if (!tx.pruned)
{
INSERT_INTO_JSON_OBJECT(dest, signatures, tx.signatures);
@@ -291,6 +307,24 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx)
GET_FROM_JSON_OBJECT(val, tx.vin, inputs);
GET_FROM_JSON_OBJECT(val, tx.vout, outputs);
GET_FROM_JSON_OBJECT(val, tx.extra, extra);
uint8_t tx_type = 0;
GET_FROM_JSON_OBJECT(val, tx_type, type);
tx.type = static_cast<cryptonote::transaction_type>(tx_type);
if (tx.type != cryptonote::transaction_type::PROTOCOL) {
GET_FROM_JSON_OBJECT(val, tx.amount_burnt, amount_burnt);
if (tx.type != cryptonote::transaction_type::MINER) {
if (tx.type == cryptonote::transaction_type::TRANSFER && tx.version >= TRANSACTION_VERSION_N_OUTS) {
GET_FROM_JSON_OBJECT(val, tx.return_address_list, return_address_list);
GET_FROM_JSON_OBJECT(val, tx.return_address_change_mask, return_address_change_mask);
} else {
GET_FROM_JSON_OBJECT(val, tx.return_address, return_address);
GET_FROM_JSON_OBJECT(val, tx.return_pubkey, return_pubkey);
}
GET_FROM_JSON_OBJECT(val, tx.source_asset_type, source_asset_type);
GET_FROM_JSON_OBJECT(val, tx.destination_asset_type, destination_asset_type);
GET_FROM_JSON_OBJECT(val, tx.amount_slippage_limit, amount_slippage_limit);
}
}
GET_FROM_JSON_OBJECT(val, tx.rct_signatures, ringct);
const auto& sigs = val.FindMember("signatures");
@@ -1138,6 +1172,7 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig&
INSERT_INTO_JSON_OBJECT(dest, encrypted, sig.ecdhInfo);
INSERT_INTO_JSON_OBJECT(dest, commitments, transform(sig.outPk, just_mask));
INSERT_INTO_JSON_OBJECT(dest, fee, sig.txnFee);
INSERT_INTO_JSON_OBJECT(dest, p_r, sig.p_r);
}
// prunable
@@ -1174,6 +1209,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig)
GET_FROM_JSON_OBJECT(val, sig.ecdhInfo, encrypted);
GET_FROM_JSON_OBJECT(val, sig.outPk, commitments);
GET_FROM_JSON_OBJECT(val, sig.txnFee, fee);
GET_FROM_JSON_OBJECT(val, sig.p_r, p_r);
}
// prunable
+48 -34
View File
@@ -1691,7 +1691,7 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args)
for (auto &ptx: txs.m_ptx)
{
const crypto::hash txid = cryptonote::get_transaction_hash(ptx.tx);
const std::string filename = std::string("raw_multisig_monero_tx_") + epee::string_tools::pod_to_hex(txid);
const std::string filename = std::string("raw_multisig_salvium_tx_") + epee::string_tools::pod_to_hex(txid);
if (!filenames.empty())
filenames += ", ";
filenames += filename;
@@ -3432,7 +3432,7 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::on_command, this, &simple_wallet::sign_transfer, _1),
tr(USAGE_SIGN_TRANSFER),
tr("Sign a transaction from a file. If the parameter \"export_raw\" is specified, transaction raw hex data suitable for the daemon RPC /sendrawtransaction is exported.\n"
"Use the parameter <filename> to specify the file to read from. If not specified, the default \"unsigned_monero_tx\" will be used."));
"Use the parameter <filename> to specify the file to read from. If not specified, the default \"unsigned_salvium_tx\" will be used."));
m_cmd_binder.set_handler("submit_transfer",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::submit_transfer, _1),
tr("Submit a signed transaction from a file."));
@@ -7141,7 +7141,7 @@ bool simple_wallet::transfer_main(
}
else if (m_wallet->multisig())
{
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx");
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_salvium_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
@@ -7149,7 +7149,7 @@ bool simple_wallet::transfer_main(
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_monero_tx";
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_salvium_tx";
}
}
else if (m_wallet->get_account().get_device().has_tx_cold_sign())
@@ -7178,7 +7178,7 @@ bool simple_wallet::transfer_main(
}
else if (m_wallet->watch_only())
{
bool r = m_wallet->save_tx(ptx_vector, "unsigned_monero_tx");
bool r = m_wallet->save_tx(ptx_vector, "unsigned_salvium_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
@@ -7186,7 +7186,7 @@ bool simple_wallet::transfer_main(
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_monero_tx";
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_salvium_tx";
}
}
else
@@ -7249,7 +7249,7 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
// TODO: add locked versions
if (args_.size() < 2)
{
PRINT_USAGE(USAGE_TRANSFER);
PRINT_USAGE(USAGE_LOCKED_TRANSFER);
return true;
}
@@ -7344,26 +7344,26 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
if (m_wallet->multisig())
{
CHECK_MULTISIG_ENABLED();
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx");
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_salvium_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_monero_tx";
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_salvium_tx";
}
}
else if (m_wallet->watch_only())
{
bool r = m_wallet->save_tx(ptx_vector, "unsigned_monero_tx");
bool r = m_wallet->save_tx(ptx_vector, "unsigned_salvium_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_monero_tx";
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_salvium_tx";
}
}
else
@@ -7652,14 +7652,14 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
if (m_wallet->multisig())
{
CHECK_MULTISIG_ENABLED();
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx");
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_salvium_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_monero_tx";
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_salvium_tx";
}
}
else if (m_wallet->get_account().get_device().has_tx_cold_sign())
@@ -7689,14 +7689,14 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
}
else if (m_wallet->watch_only())
{
bool r = m_wallet->save_tx(ptx_vector, "unsigned_monero_tx");
bool r = m_wallet->save_tx(ptx_vector, "unsigned_salvium_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_monero_tx";
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_salvium_tx";
}
}
else
@@ -7887,14 +7887,14 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
if (m_wallet->multisig())
{
CHECK_MULTISIG_ENABLED();
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx");
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_salvium_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_monero_tx";
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_salvium_tx";
}
}
else if (m_wallet->get_account().get_device().has_tx_cold_sign())
@@ -7925,14 +7925,14 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
}
else if (m_wallet->watch_only())
{
bool r = m_wallet->save_tx(ptx_vector, "unsigned_monero_tx");
bool r = m_wallet->save_tx(ptx_vector, "unsigned_salvium_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_monero_tx";
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_salvium_tx";
}
}
else
@@ -8043,10 +8043,17 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
return true;
}
// Verify we have a valid return_address and tx_pubkey
if (td.m_tx.return_address == crypto::null_pkey || td.m_tx.return_pubkey != crypto::null_pkey) {
fail_msg_writer() << tr("invalid return_address/return_pubkey for txid ") << args_[0];
return true;
if (td.m_tx.version >= HF_VERSION_ENABLE_N_OUTS) {
if (td.m_tx.return_address_list.empty() || td.m_tx.return_address_change_mask.empty()) {
fail_msg_writer() << tr("invalid return_address_list for txid ") << args_[0];
return true;
}
} else {
// Verify we have a valid return_address and tx_pubkey
if (td.m_tx.return_address == crypto::null_pkey || td.m_tx.return_pubkey != crypto::null_pkey) {
fail_msg_writer() << tr("invalid return_address/return_pubkey for txid ") << args_[0];
return true;
}
}
// Check that we have the key image information, and that it is usable
@@ -8110,14 +8117,14 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
if (m_wallet->multisig())
{
CHECK_MULTISIG_ENABLED();
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx");
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_salvium_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_monero_tx";
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_salvium_tx";
}
}
else if (m_wallet->get_account().get_device().has_tx_cold_sign())
@@ -8152,14 +8159,14 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
}
else if (m_wallet->watch_only())
{
bool r = m_wallet->save_tx(ptx_vector, "unsigned_monero_tx");
bool r = m_wallet->save_tx(ptx_vector, "unsigned_salvium_tx");
if (!r)
{
fail_msg_writer() << tr("Failed to write transaction(s) to file");
}
else
{
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_monero_tx";
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_salvium_tx";
}
}
else
@@ -8306,6 +8313,12 @@ bool simple_wallet::stake(const std::vector<std::string> &args_)
return true;
}
if(m_wallet->multisig())
{
fail_msg_writer() << tr("This is a multisig wallet, staking is not currently supported");
return true;
}
std::vector<std::string> local_args;
local_args.push_back(m_wallet->get_subaddress_as_str({m_current_subaddress_account,0}));
local_args.insert(local_args.end(), args_.begin(), args_.end());
@@ -8414,8 +8427,9 @@ bool simple_wallet::yield_info(const std::vector<std::string> &args) {
% print_money(burnt)
% print_money(yield);
else
message_writer(console_color_green, false) << boost::format(tr("Height %d, txid %s, staked %s SAL, %s SAL accrued so far"))
message_writer(console_color_green, false) << boost::format(tr("Height %d (matures %d), txid %s, staked %s SAL, %s SAL accrued so far"))
% height
% (height + 21601)
% txid
% print_money(burnt)
% print_money(yield);
@@ -8678,7 +8692,7 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
}
bool export_raw = false;
std::string unsigned_filename = "unsigned_monero_tx";
std::string unsigned_filename = "unsigned_salvium_tx";
if (args_.size() > 2 || (args_.size() == 2 && args_[0] != "export_raw"))
{
PRINT_USAGE(USAGE_SIGN_TRANSFER);
@@ -8702,7 +8716,7 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
std::vector<tools::wallet2::pending_tx> ptx;
try
{
bool r = m_wallet->sign_tx(unsigned_filename, "signed_monero_tx", ptx, [&](const tools::wallet2::unsigned_tx_set &tx){ return accept_loaded_tx(tx); }, export_raw);
bool r = m_wallet->sign_tx(unsigned_filename, "signed_salvium_tx", ptx, [&](const tools::wallet2::unsigned_tx_set &tx){ return accept_loaded_tx(tx); }, export_raw);
if (!r)
{
fail_msg_writer() << tr("Failed to sign transaction");
@@ -8722,7 +8736,7 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
txids_as_text += (", ");
txids_as_text += epee::string_tools::pod_to_hex(get_transaction_hash(t.tx));
}
success_msg_writer(true) << tr("Transaction successfully signed to file ") << "signed_monero_tx" << ", txid " << txids_as_text;
success_msg_writer(true) << tr("Transaction successfully signed to file ") << "signed_salvium_tx" << ", txid " << txids_as_text;
if (export_raw)
{
std::string rawfiles_as_text;
@@ -8730,7 +8744,7 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
{
if (i > 0)
rawfiles_as_text += ", ";
rawfiles_as_text += "signed_monero_tx_raw" + (ptx.size() == 1 ? "" : ("_" + std::to_string(i)));
rawfiles_as_text += "signed_salvium_tx_raw" + (ptx.size() == 1 ? "" : ("_" + std::to_string(i)));
}
success_msg_writer(true) << tr("Transaction raw hex data exported to ") << rawfiles_as_text;
}
@@ -8750,7 +8764,7 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
try
{
std::vector<tools::wallet2::pending_tx> ptx_vector;
bool r = m_wallet->load_tx("signed_monero_tx", ptx_vector, [&](const tools::wallet2::signed_tx_set &tx){ return accept_loaded_tx(tx); });
bool r = m_wallet->load_tx("signed_salvium_tx", ptx_vector, [&](const tools::wallet2::signed_tx_set &tx){ return accept_loaded_tx(tx); });
if (!r)
{
fail_msg_writer() << tr("Failed to load transaction from file");
@@ -11357,7 +11371,7 @@ void simple_wallet::commit_or_save(std::vector<tools::wallet2::pending_tx>& ptx_
cryptonote::blobdata blob;
tx_to_blob(ptx.tx, blob);
const std::string blob_hex = epee::string_tools::buff_to_hex_nodelimer(blob);
const std::string filename = "raw_monero_tx" + (ptx_vector.size() == 1 ? "" : ("_" + std::to_string(i++)));
const std::string filename = "raw_salvium_tx" + (ptx_vector.size() == 1 ? "" : ("_" + std::to_string(i++)));
if (m_wallet->save_to_file(filename, blob_hex, true))
success_msg_writer(true) << tr("Transaction successfully saved to ") << filename << tr(", txid ") << txid;
else
+1 -1
View File
@@ -1,5 +1,5 @@
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
#define DEF_SALVIUM_VERSION "0.5.2"
#define DEF_SALVIUM_VERSION "0.6.0"
#define DEF_MONERO_VERSION_TAG "release"
#define DEF_MONERO_VERSION "0.18.3.3"
#define DEF_MONERO_RELEASE_NAME "Zero"
+124 -77
View File
@@ -2470,51 +2470,11 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt,
yield_per_stake_128 /= ybi_data.back().locked_coins_tally;
yield_per_stake = yield_per_stake_128.convert_to<uint64_t>();
}
/*
// Iterate over the transfers in our wallet
std::map<size_t, size_t> 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<std::tuple<size_t, std::string, uint64_t, uint64_t>> &payouts) {
// Iterate over the transfers in our wallet
std::map<size_t, size_t> 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<uint64_t> &o_indices, const std::vector<uint64_t> &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<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache, bool ignore_callbacks)
{
PERF_TIMER(process_new_transaction);
@@ -2750,9 +2710,9 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_asset_type(tx.vout[o], asset_type), error::wallet_internal_error, "failed to get output_asset_type");
m_transfers.push_back(transfer_details{});
if (m_transfers_indices.count(asset_type) == 0) {
m_transfers_indices[asset_type] = std::vector<size_t>{};
m_transfers_indices[asset_type] = std::set<size_t>{};
}
m_transfers_indices[asset_type].push_back(m_transfers.size()-1);
m_transfers_indices[asset_type].insert(m_transfers.size()-1);
transfer_details& td = m_transfers.back();
td.m_block_height = height;
td.m_internal_output_index = o;
@@ -8329,6 +8289,8 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
not multisig_tx_builder.init(
m_account.get_keys(),
ptx.construction_data.extra,
ptx.tx.type,
get_current_hard_fork(),
ptx.construction_data.unlock_time,
ptx.construction_data.subaddr_account,
ptx.construction_data.subaddr_indices,
@@ -10133,15 +10095,20 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
LOG_PRINT_L2("constructing tx");
auto sources_copy = sources;
multisig::signing::tx_builder_ringct_t multisig_tx_builder;
uint32_t hf_version = get_current_hard_fork();
if (m_multisig) {
// prepare the core part of a multisig tx (many tx attempts for different signer groups can be spun off this core piece)
std::set<std::uint32_t> subaddr_minor_indices;
for (size_t idx: selected_transfers) {
subaddr_minor_indices.insert(m_transfers[idx].m_subaddr_index.minor);
}
// Store the TX type
tx.type = tx_type;
THROW_WALLET_EXCEPTION_IF(
not multisig_tx_builder.init(m_account.get_keys(),
extra,
tx_type,
hf_version,
unlock_time,
subaddr_account,
subaddr_minor_indices,
@@ -10161,7 +10128,6 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
);
}
else {
uint32_t hf_version = get_current_hard_fork();
// Get the circulating supply data
std::vector<std::pair<std::string, std::string>> circ_amounts;
THROW_WALLET_EXCEPTION_IF(!get_circulating_supply(circ_amounts), error::wallet_internal_error, "Failed to get circulating supply");
@@ -10320,7 +10286,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
}
// try to find a rct input of enough size
for (size_t& i: m_transfers_indices[asset_type])
for (size_t i: m_transfers_indices[asset_type])
{
const transfer_details& td = m_transfers[i];
if (!is_spent(td, false) && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
@@ -10340,25 +10306,28 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
// this could be made better by picking one of the outputs to be a small one, since those
// are less useful since often below the needed money, so if one can be used in a pair,
// it gets rid of it for the future
for (size_t i = 0; i < m_transfers_indices[asset_type].size(); i++)
for (auto i=m_transfers_indices[asset_type].begin(); i!= m_transfers_indices[asset_type].end(); ++i)
{
size_t idx = m_transfers_indices[asset_type][i];
const transfer_details& td = m_transfers[i];
size_t idx = *i;
const transfer_details& td = m_transfers[idx];
if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below)
{
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
MDEBUG("Ignoring output " << idx << " of amount " << print_money(td.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
continue;
}
LOG_PRINT_L2("Considering input " << i << ", " << print_money(td.amount()));
for (size_t j = i + 1; j < m_transfers_indices[asset_type].size(); ++j)
LOG_PRINT_L2("Considering input " << idx << ", " << print_money(td.amount()));
if (i == m_transfers_indices[asset_type].end()) continue;
auto j = i;
std::advance(j, 1);
for (; j!=m_transfers_indices[asset_type].end(); ++j)
{
size_t idx2 = m_transfers_indices[asset_type][j];
size_t idx2 = *j;
const transfer_details& td2 = m_transfers[idx2];
if (td2.amount() > m_ignore_outputs_above || td2.amount() < m_ignore_outputs_below)
{
MDEBUG("Ignoring output " << j << " of amount " << print_money(td2.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
MDEBUG("Ignoring output " << idx2 << " of amount " << print_money(td2.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
continue;
}
if (!is_spent(td2, false) && !td2.m_frozen && !td2.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
@@ -10367,16 +10336,16 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
// already found. If the same, don't update, and oldest suitable outputs
// will be used in preference.
float relatedness = get_output_relatedness(td, td2);
LOG_PRINT_L2(" with input " << j << ", " << print_money(td2.amount()) << ", relatedness " << relatedness);
LOG_PRINT_L2(" with input " << idx2 << ", " << print_money(td2.amount()) << ", relatedness " << relatedness);
if (relatedness < current_output_relatdness)
{
// reset the current picks with those, and return them directly
// if they're unrelated. If they are related, we'll end up returning
// them if we find nothing better
picks.clear();
picks.push_back(i);
picks.push_back(j);
LOG_PRINT_L0("we could use " << i << " and " << j);
picks.push_back(idx);
picks.push_back(idx2);
LOG_PRINT_L0("we could use " << idx << " and " << idx2);
if (relatedness == 0.0f)
return picks;
current_output_relatdness = relatedness;
@@ -10693,7 +10662,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// Verify that we have outputs in our wallet for the correct asset_type
THROW_WALLET_EXCEPTION_IF(!m_transfers_indices.count(source_asset), error::wallet_internal_error, "Cannot find outputs with correct asset_type to pay for TX");
for (size_t& i: m_transfers_indices[source_asset])
for (size_t i: m_transfers_indices[source_asset])
{
const transfer_details& td = m_transfers[i];
if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
@@ -11298,8 +11267,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
// gather all dust and non-dust outputs of specified subaddress (if any) and below specified threshold (if any)
bool fund_found = false;
for (size_t i = 0; i < m_transfers.size(); ++i)
//for (size_t idx = 0; idx < m_transfers_indices[asset_type].size(); idx++)
for (const auto& i: m_transfers_indices[asset_type])
{
//size_t i = m_transfers_indices[asset_type][idx];
const transfer_details& td = m_transfers[i];
if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
{
@@ -11370,9 +11341,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector<size_t> transfers_indices)
{
// Get the asset_type and associated information
THROW_WALLET_EXCEPTION_IF(transfers_indices.empty() || transfers_indices.size()>1, error::wallet_internal_error, "Incorrect number of transfers_indices on return_payment");
THROW_WALLET_EXCEPTION_IF(transfers_indices.empty() || transfers_indices.size()>1, error::wallet_internal_error, tr("Incorrect number of transfers_indices on return_payment"));
size_t idx = transfers_indices[0];
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate return_payment origin index in m_transfers");
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, tr("cannot locate return_payment origin index in m_transfers"));
const transfer_details& td_origin = get_transfer_details(idx);
const std::string asset_type = td_origin.m_tx.source_asset_type;
bool is_subaddress = true;
@@ -11383,24 +11354,86 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector
uint32_t priority = adjust_priority(0);
std::vector<uint8_t> extra; // No need for a TX extra beyond that which will be calculated herein
// To return a payment, we need to know the y value to process the F value
// ...but the y value is calculated differently depending on the original TX
ec_scalar y;
crypto::public_key return_address = null_pkey;
// Get P_change from the TX
crypto::public_key P_change = crypto::null_pkey;
size_t change_index = (td_origin.m_internal_output_index == 0) ? 1 : 0;
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(td_origin.m_tx.vout[change_index], P_change), error::wallet_internal_error, "Failed to identify change output");
uint8_t change_index;
uint32_t hf_version = get_current_hard_fork();
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && td_origin.m_tx.version >= TRANSACTION_VERSION_N_OUTS) {
// Calculate z_i (the shared secret between sender and ourselves for the original TX)
crypto::public_key txkey_pub = null_pkey; // R
const std::vector<crypto::public_key> in_additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td_origin.m_tx);
if (in_additional_tx_pub_keys.size() != 0) {
THROW_WALLET_EXCEPTION_IF(in_additional_tx_pub_keys.size() != td_origin.m_tx.vout.size(),
error::wallet_internal_error,
tr("at create_transactions_return(): incorrect number of additional TX pubkeys in origin TX for return_payment"));
txkey_pub = in_additional_tx_pub_keys[td_origin.m_internal_output_index];
} else {
txkey_pub = get_tx_pub_key_from_extra(td_origin.m_tx);
}
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
THROW_WALLET_EXCEPTION_IF(!generate_key_derivation(txkey_pub, m_account.get_keys().m_view_secret_key, derivation),
error::wallet_internal_error,
tr("at create_transactions_return(): failed to generate_key_derivation"));
crypto::secret_key z_i;
derivation_to_scalar(derivation, td_origin.m_internal_output_index, z_i);
// Calculate the y value for return_payment support
struct {
char domain_separator[8];
rct::key amount_key;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 7);
buf.amount_key = rct::sk2rct(z_i);
crypto::hash_to_scalar(&buf, sizeof(buf), y);
// The change_index needs decoding too
uint8_t eci_data = td_origin.m_tx.return_address_change_mask[td_origin.m_internal_output_index];
// Calculate the encrypted_change_index data for this output
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "CHG_IDX", 8);
crypto::secret_key eci_out;
keccak((uint8_t *)&buf, sizeof(buf), (uint8_t*)&eci_out, sizeof(eci_out));
change_index = eci_data ^ eci_out.data[0];
return_address = td_origin.m_tx.return_address_list[td_origin.m_internal_output_index];
} else {
// Calculate y
struct {
char domain_separator[8];
crypto::public_key pubkey;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 6);
buf.pubkey = P_change;
crypto::hash_to_scalar(&buf, sizeof(buf), y);
// Change index is the one we didn't receive
change_index = (td_origin.m_internal_output_index == 0) ? 1 : 0;
return_address = td_origin.m_tx.return_address;
}
// Sanity check that we aren't attempting to return our own TX change output to ourselves
THROW_WALLET_EXCEPTION_IF(change_index == td_origin.m_internal_output_index, error::wallet_internal_error, tr("Attempting to return change to ourself"));
// Sanity check that we can obtain the change output from the origin TX
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(td_origin.m_tx.vout[change_index], P_change),
error::wallet_internal_error,
tr("Failed to identify change output"));
// Calculate yF
ec_scalar y;
struct {
char domain_separator[8];
crypto::public_key pubkey;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 6);
buf.pubkey = P_change;
crypto::hash_to_scalar(&buf, sizeof(buf), y);
rct::key key_y = (rct::key&)(y);
rct::key key_F = (rct::key&)(td_origin.m_tx.return_address);
rct::key key_F = (rct::key&)(return_address);
rct::key key_yF = rct::scalarmultKey(key_F, key_y);
// Build the subaddress to send the return to
@@ -11547,7 +11580,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
if (outputs > 1)
tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
THROW_WALLET_EXCEPTION_IF(needed_fee > available_for_fee, error::wallet_internal_error, "Transaction cannot pay for itself");
THROW_WALLET_EXCEPTION_IF(needed_fee > available_for_fee, error::wallet_internal_error, tr("Transaction cannot pay for itself"));
do {
LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_money(needed_fee) << " and we have " << print_money(test_ptx.fee));
@@ -11643,7 +11676,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
}
std::vector<cryptonote::tx_destination_entry> synthetic_dsts(1, cryptonote::tx_destination_entry("", a, address, is_subaddress, tx_type == cryptonote::transaction_type::RETURN));
synthetic_dsts.back().asset_type = asset_type;
THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, synthetic_dsts), error::wallet_internal_error, "Created transaction(s) failed sanity check");
THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, synthetic_dsts), error::wallet_internal_error, tr("Created transaction(s) failed sanity check"));
// if we made it this far, we're OK to actually send the transactions
return ptx_vector;
@@ -14438,7 +14471,21 @@ crypto::key_image wallet2::get_multisig_composite_key_image(size_t n) const
for (const auto &info: td.m_multisig_info)
for (const auto &pki: info.m_partial_key_images)
pkis.push_back(pki);
bool r = multisig::generate_multisig_composite_key_image(get_account().get_keys(), m_subaddresses, td.get_public_key(), tx_key, additional_tx_keys, td.m_internal_output_index, pkis, ki);
// SRCG: work out if we have origin data to use
bool use_origin_data = false;
cryptonote::origin_data origin_tx_data;
if (td.m_td_origin_idx != (uint64_t)-1) {
// Flag to indicate this is a TX that uses a return_address
const transfer_details& td_origin = get_transfer_details(td.m_td_origin_idx);
origin_tx_data.tx_pub_key = get_tx_pub_key_from_extra(td_origin.m_tx);
origin_tx_data.output_index = td_origin.m_internal_output_index;
origin_tx_data.tx_type = td_origin.m_tx.type;
use_origin_data = true;
}
bool r = multisig::generate_multisig_composite_key_image(get_account().get_keys(), m_subaddresses, td.get_public_key(), tx_key, additional_tx_keys, td.m_internal_output_index, pkis, ki, use_origin_data, origin_tx_data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
return ki;
}
+1 -2
View File
@@ -625,7 +625,7 @@ private:
};
typedef std::vector<transfer_details> transfer_container;
typedef serializable_unordered_map<std::string, std::vector<size_t>> transfer_details_indices;
typedef serializable_unordered_map<std::string, std::set<size_t>> transfer_details_indices;
typedef serializable_unordered_multimap<crypto::hash, payment_details> payment_container;
typedef std::set<uint32_t> unique_index_container;
@@ -1755,7 +1755,6 @@ private:
uint64_t &ybi_data_size,
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> &payouts
);
bool get_yield_payouts(std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> &payouts);
private:
/*!
+1 -1
View File
@@ -135,7 +135,7 @@ namespace wallet_args
command_line::add_arg(desc_params, arg_max_concurrency);
command_line::add_arg(desc_params, arg_config_file);
i18n_set_language("translations", "monero", lang);
i18n_set_language("translations", "salvium", lang);
po::options_description desc_all;
desc_all.add(desc_general).add(desc_params);
+2
View File
@@ -392,6 +392,7 @@ namespace tools
td.address = d.address(m_wallet->nettype(), pd.m_payment_id);
}
entry.asset_type = pd.m_tx.source_asset_type;
entry.type = "out";
entry.subaddr_index = { pd.m_subaddr_account, 0 };
for (uint32_t i: pd.m_subaddr_indices)
@@ -424,6 +425,7 @@ namespace tools
}
entry.type = is_failed ? "failed" : "pending";
entry.asset_type = pd.m_tx.source_asset_type;
entry.subaddr_index = { pd.m_subaddr_account, 0 };
for (uint32_t i: pd.m_subaddr_indices)
entry.subaddr_indices.push_back({pd.m_subaddr_account, i});
+514 -464
View File
File diff suppressed because it is too large Load Diff
+2694 -2761
View File
File diff suppressed because one or more lines are too long
+2693 -2762
View File
File diff suppressed because it is too large Load Diff
+2742 -2811
View File
File diff suppressed because one or more lines are too long
+2650 -2719
View File
File diff suppressed because it is too large Load Diff
+2701 -2770
View File
File diff suppressed because one or more lines are too long
+2722 -2791
View File
File diff suppressed because it is too large Load Diff
+2609 -2678
View File
File diff suppressed because it is too large Load Diff
+2703 -2771
View File
File diff suppressed because one or more lines are too long
+2252 -2319
View File
File diff suppressed because it is too large Load Diff
+2657 -2727
View File
File diff suppressed because it is too large Load Diff