Compare commits
13 Commits
v0.5.3-rc2
...
v0.5.4-rc4
| Author | SHA1 | Date | |
|---|---|---|---|
| 884db2b499 | |||
| ce7a1bdd96 | |||
| 57cbb146db | |||
| 85c856411e | |||
| 6fefb49da0 | |||
| c5c828516b | |||
| bb91b01cf7 | |||
| 7f0eda828a | |||
| d3f15211d7 | |||
| b828703bbd | |||
| 2fa8ef97ef | |||
| acb3af43f0 | |||
| 7abf28d87c |
@@ -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
|
||||
@@ -1,4 +1,4 @@
|
||||
# Salvium Zero v0.4.1
|
||||
# Salvium Zero v0.5.4-rc4
|
||||
|
||||
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.5.4-rc4
|
||||
```
|
||||
|
||||
* 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.5.4-rc4'. 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.5.4-rc4
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
+6
-6
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -216,6 +216,8 @@
|
||||
#define HF_VERSION_2021_SCALING 2
|
||||
#define HF_VERSION_ENABLE_N_OUTS 2
|
||||
|
||||
#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
|
||||
|
||||
@@ -577,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) {
|
||||
@@ -1153,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;
|
||||
}
|
||||
|
||||
@@ -1187,7 +1168,6 @@ namespace cryptonote
|
||||
tx_type,
|
||||
source_asset,
|
||||
destination_asset_types,
|
||||
zero_masks,
|
||||
inamounts,
|
||||
outamounts,
|
||||
fee,
|
||||
|
||||
+10
-12
@@ -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
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -8117,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())
|
||||
@@ -8159,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
|
||||
@@ -8313,6 +8313,14 @@ 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());
|
||||
@@ -8421,8 +8429,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);
|
||||
@@ -8685,7 +8694,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);
|
||||
@@ -8709,7 +8718,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");
|
||||
@@ -8729,7 +8738,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;
|
||||
@@ -8737,7 +8746,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;
|
||||
}
|
||||
@@ -8757,7 +8766,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");
|
||||
@@ -11364,7 +11373,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
@@ -1,5 +1,5 @@
|
||||
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_SALVIUM_VERSION "0.5.3-rc2"
|
||||
#define DEF_SALVIUM_VERSION "0.5.4-rc4"
|
||||
#define DEF_MONERO_VERSION_TAG "release"
|
||||
#define DEF_MONERO_VERSION "0.18.3.3"
|
||||
#define DEF_MONERO_RELEASE_NAME "Zero"
|
||||
|
||||
+49
-65
@@ -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,9 +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 idx = 0; idx < m_transfers_indices[asset_type].size(); idx++)
|
||||
//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];
|
||||
//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)
|
||||
{
|
||||
@@ -11371,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;
|
||||
@@ -11610,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));
|
||||
@@ -11706,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;
|
||||
@@ -14501,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;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
/*!
|
||||
|
||||
Reference in New Issue
Block a user