mirror of
				https://git.wownero.com/wownero/wownero.git
				synced 2024-08-15 01:03:23 +00:00 
			
		
		
		
	Merge pull request #6810
19b2283 New add_aux_pow RPC to support merge mining (moneromooo-monero)
			
			
This commit is contained in:
		
						commit
						8d7c1135b8
					
				
					 14 changed files with 720 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -87,6 +87,10 @@ void hash_extra_jh(const void *data, size_t length, char *hash);
 | 
			
		|||
void hash_extra_skein(const void *data, size_t length, char *hash);
 | 
			
		||||
 | 
			
		||||
void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash);
 | 
			
		||||
bool tree_path(size_t count, size_t idx, uint32_t *path);
 | 
			
		||||
bool tree_branch(const char (*hashes)[HASH_SIZE], size_t count, const char *hash, char (*branch)[HASH_SIZE], size_t *depth, uint32_t *path);
 | 
			
		||||
bool tree_branch_hash(const char hash[HASH_SIZE], const char (*branch)[HASH_SIZE], size_t depth, uint32_t path, char root[HASH_SIZE]);
 | 
			
		||||
bool is_branch_in_tree(const char hash[HASH_SIZE], const char root[HASH_SIZE], const char (*branch)[HASH_SIZE], size_t depth, uint32_t path);
 | 
			
		||||
 | 
			
		||||
#define RX_BLOCK_VERSION	12
 | 
			
		||||
void rx_slow_hash_allocate_state(void);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -104,3 +104,154 @@ void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
 | 
			
		|||
    free(ints);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool tree_path(size_t count, size_t idx, uint32_t *path)
 | 
			
		||||
{
 | 
			
		||||
  if (count == 0)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  if (count == 1) {
 | 
			
		||||
    *path = 0;
 | 
			
		||||
  } else if (count == 2) {
 | 
			
		||||
    *path = idx == 0 ? 0 : 1;
 | 
			
		||||
  } else {
 | 
			
		||||
    size_t i, j;
 | 
			
		||||
 | 
			
		||||
    *path = 0;
 | 
			
		||||
    size_t cnt = tree_hash_cnt( count );
 | 
			
		||||
 | 
			
		||||
    for (i = 2 * cnt - count, j = 2 * cnt - count; j < cnt; i += 2, ++j) {
 | 
			
		||||
      if (idx == i || idx == i+1)
 | 
			
		||||
      {
 | 
			
		||||
        *path = (*path << 1) | (idx == i ? 0 : 1);
 | 
			
		||||
        idx = j;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    assert(i == count);
 | 
			
		||||
 | 
			
		||||
    while (cnt > 2) {
 | 
			
		||||
      cnt >>= 1;
 | 
			
		||||
      for (i = 0, j = 0; j < cnt; i += 2, ++j) {
 | 
			
		||||
        if (idx == i || idx == i + 1)
 | 
			
		||||
        {
 | 
			
		||||
          *path = (*path << 1) | (idx == i ? 0 : 1);
 | 
			
		||||
          idx = j;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (idx == 0 || idx == 1)
 | 
			
		||||
    {
 | 
			
		||||
      *path = (*path << 1) | (idx == 0 ? 0 : 1);
 | 
			
		||||
      idx = 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool tree_branch(const char (*hashes)[HASH_SIZE], size_t count, const char *hash, char (*branch)[HASH_SIZE], size_t *depth, uint32_t *path)
 | 
			
		||||
{
 | 
			
		||||
  size_t idx;
 | 
			
		||||
 | 
			
		||||
  if (count == 0)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  for (idx = 0; idx < count; ++idx)
 | 
			
		||||
    if (!memcmp(hash, hashes[idx], HASH_SIZE))
 | 
			
		||||
      break;
 | 
			
		||||
  if (idx == count)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  assert(count > 0);
 | 
			
		||||
  if (count == 1) {
 | 
			
		||||
    *depth = 0;
 | 
			
		||||
    *path = 0;
 | 
			
		||||
  } else if (count == 2) {
 | 
			
		||||
    *depth = 1;
 | 
			
		||||
    *path = idx == 0 ? 0 : 1;
 | 
			
		||||
    memcpy(branch[0], hashes[idx ^ 1], HASH_SIZE);
 | 
			
		||||
  } else {
 | 
			
		||||
    size_t i, j;
 | 
			
		||||
 | 
			
		||||
    *depth = 0;
 | 
			
		||||
    *path = 0;
 | 
			
		||||
    size_t cnt = tree_hash_cnt( count );
 | 
			
		||||
 | 
			
		||||
    char *ints = calloc(cnt, HASH_SIZE);  // zero out as extra protection for using uninitialized mem
 | 
			
		||||
    assert(ints);
 | 
			
		||||
 | 
			
		||||
    memcpy(ints, hashes, (2 * cnt - count) * HASH_SIZE);
 | 
			
		||||
 | 
			
		||||
    for (i = 2 * cnt - count, j = 2 * cnt - count; j < cnt; i += 2, ++j) {
 | 
			
		||||
      if (idx == i || idx == i+1)
 | 
			
		||||
      {
 | 
			
		||||
        memcpy(branch[*depth], hashes[idx == i ? i + 1 : i], HASH_SIZE);
 | 
			
		||||
        ++*depth;
 | 
			
		||||
        *path = (*path << 1) | (idx == i ? 0 : 1);
 | 
			
		||||
        idx = j;
 | 
			
		||||
      }
 | 
			
		||||
      cn_fast_hash(hashes[i], 64, ints + j * HASH_SIZE);
 | 
			
		||||
    }
 | 
			
		||||
    assert(i == count);
 | 
			
		||||
 | 
			
		||||
    while (cnt > 2) {
 | 
			
		||||
      cnt >>= 1;
 | 
			
		||||
      for (i = 0, j = 0; j < cnt; i += 2, ++j) {
 | 
			
		||||
        if (idx == i || idx == i + 1)
 | 
			
		||||
        {
 | 
			
		||||
          memcpy(branch[*depth], ints + (idx == i ? i + 1 : i) * HASH_SIZE, HASH_SIZE);
 | 
			
		||||
          ++*depth;
 | 
			
		||||
          *path = (*path << 1) | (idx == i ? 0 : 1);
 | 
			
		||||
          idx = j;
 | 
			
		||||
        }
 | 
			
		||||
        cn_fast_hash(ints + i * HASH_SIZE, 64, ints + j * HASH_SIZE);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (idx == 0 || idx == 1)
 | 
			
		||||
    {
 | 
			
		||||
      memcpy(branch[*depth], ints + (idx == 0 ? 1 : 0) * HASH_SIZE, HASH_SIZE);
 | 
			
		||||
      ++*depth;
 | 
			
		||||
      *path = (*path << 1) | (idx == 0 ? 0 : 1);
 | 
			
		||||
      idx = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    free(ints);
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool tree_branch_hash(const char hash[HASH_SIZE], const char (*branch)[HASH_SIZE], size_t depth, uint32_t path, char root[HASH_SIZE])
 | 
			
		||||
{
 | 
			
		||||
  size_t d;
 | 
			
		||||
  char partial[HASH_SIZE];
 | 
			
		||||
 | 
			
		||||
  memcpy(partial, hash, HASH_SIZE);
 | 
			
		||||
 | 
			
		||||
  for (d = 0; d < depth; ++d)
 | 
			
		||||
  {
 | 
			
		||||
    char buffer[2 * HASH_SIZE];
 | 
			
		||||
    if ((path >> (depth - d - 1)) & 1)
 | 
			
		||||
    {
 | 
			
		||||
      memcpy(buffer, branch[d], HASH_SIZE);
 | 
			
		||||
      memcpy(buffer + HASH_SIZE, partial, HASH_SIZE);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      memcpy(buffer, partial, HASH_SIZE);
 | 
			
		||||
      memcpy(buffer + HASH_SIZE, branch[d], HASH_SIZE);
 | 
			
		||||
    }
 | 
			
		||||
    cn_fast_hash(buffer, 2 * HASH_SIZE, partial);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  memcpy(root, partial, HASH_SIZE);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool is_branch_in_tree(const char hash[HASH_SIZE], const char root[HASH_SIZE], const char (*branch)[HASH_SIZE], size_t depth, uint32_t path)
 | 
			
		||||
{
 | 
			
		||||
  char res[HASH_SIZE];
 | 
			
		||||
  if (!tree_branch_hash(hash, branch, depth, path, res))
 | 
			
		||||
    return false;
 | 
			
		||||
  return memcmp(res, root, HASH_SIZE) == 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,6 +43,7 @@ set(cryptonote_basic_sources
 | 
			
		|||
  cryptonote_format_utils.cpp
 | 
			
		||||
  difficulty.cpp
 | 
			
		||||
  hardfork.cpp
 | 
			
		||||
  merge_mining.cpp
 | 
			
		||||
  miner.cpp)
 | 
			
		||||
 | 
			
		||||
set(cryptonote_basic_headers)
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +58,7 @@ set(cryptonote_basic_private_headers
 | 
			
		|||
  cryptonote_format_utils.h
 | 
			
		||||
  difficulty.h
 | 
			
		||||
  hardfork.h
 | 
			
		||||
  merge_mining.h
 | 
			
		||||
  miner.h
 | 
			
		||||
  tx_extra.h
 | 
			
		||||
  verification_context.h)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -727,6 +727,25 @@ namespace cryptonote
 | 
			
		|||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  //---------------------------------------------------------------
 | 
			
		||||
  bool add_mm_merkle_root_to_tx_extra(std::vector<uint8_t>& tx_extra, const crypto::hash& mm_merkle_root, size_t mm_merkle_tree_depth)
 | 
			
		||||
  {
 | 
			
		||||
    CHECK_AND_ASSERT_MES(mm_merkle_tree_depth < 32, false, "merge mining merkle tree depth should be less than 32");
 | 
			
		||||
    size_t start_pos = tx_extra.size();
 | 
			
		||||
    tx_extra.resize(tx_extra.size() + 3 + 32);
 | 
			
		||||
    //write tag
 | 
			
		||||
    tx_extra[start_pos] = TX_EXTRA_MERGE_MINING_TAG;
 | 
			
		||||
    //write data size
 | 
			
		||||
    ++start_pos;
 | 
			
		||||
    tx_extra[start_pos] = 33;
 | 
			
		||||
    //write depth varint (always one byte here)
 | 
			
		||||
    ++start_pos;
 | 
			
		||||
    tx_extra[start_pos] = mm_merkle_tree_depth;
 | 
			
		||||
    //write data
 | 
			
		||||
    ++start_pos;
 | 
			
		||||
    memcpy(&tx_extra[start_pos], &mm_merkle_root, 32);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  //---------------------------------------------------------------
 | 
			
		||||
  bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type)
 | 
			
		||||
  {
 | 
			
		||||
    if (tx_extra.empty())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,6 +83,7 @@ namespace cryptonote
 | 
			
		|||
  std::vector<crypto::public_key> get_additional_tx_pub_keys_from_extra(const transaction_prefix& tx);
 | 
			
		||||
  bool add_additional_tx_pub_keys_to_extra(std::vector<uint8_t>& tx_extra, const std::vector<crypto::public_key>& additional_pub_keys);
 | 
			
		||||
  bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
 | 
			
		||||
  bool add_mm_merkle_root_to_tx_extra(std::vector<uint8_t>& tx_extra, const crypto::hash& mm_merkle_root, size_t mm_merkle_tree_depth);
 | 
			
		||||
  bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type);
 | 
			
		||||
  void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id);
 | 
			
		||||
  void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										95
									
								
								src/cryptonote_basic/merge_mining.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/cryptonote_basic/merge_mining.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,95 @@
 | 
			
		|||
// Copyright (c) 2020, 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 <string.h>
 | 
			
		||||
#include "misc_log_ex.h"
 | 
			
		||||
#include "int-util.h"
 | 
			
		||||
#include "crypto/crypto.h"
 | 
			
		||||
#include "common/util.h"
 | 
			
		||||
#include "merge_mining.h"
 | 
			
		||||
 | 
			
		||||
using namespace epee;
 | 
			
		||||
 | 
			
		||||
#undef MONERO_DEFAULT_LOG_CATEGORY
 | 
			
		||||
#define MONERO_DEFAULT_LOG_CATEGORY "cn.mm"
 | 
			
		||||
 | 
			
		||||
using namespace crypto;
 | 
			
		||||
 | 
			
		||||
namespace cryptonote
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//---------------------------------------------------------------
 | 
			
		||||
uint32_t get_aux_slot(const crypto::hash &id, uint32_t nonce, uint32_t n_aux_chains)
 | 
			
		||||
{
 | 
			
		||||
  CHECK_AND_ASSERT_THROW_MES(n_aux_chains > 0, "n_aux_chains is 0");
 | 
			
		||||
 | 
			
		||||
  uint8_t buf[HASH_SIZE + sizeof(uint32_t) + 1];
 | 
			
		||||
  memcpy(buf, &id, HASH_SIZE);
 | 
			
		||||
  uint32_t v = SWAP32LE(nonce);
 | 
			
		||||
  memcpy(buf + HASH_SIZE, &v, sizeof(uint32_t));
 | 
			
		||||
  buf[HASH_SIZE + sizeof(uint32_t)] = config::HASH_KEY_MM_SLOT;
 | 
			
		||||
 | 
			
		||||
  crypto::hash res;
 | 
			
		||||
  tools::sha256sum(buf, sizeof(buf), res);
 | 
			
		||||
  v = *((const uint32_t*)&res);
 | 
			
		||||
  return SWAP32LE(v) % n_aux_chains;
 | 
			
		||||
}
 | 
			
		||||
//---------------------------------------------------------------
 | 
			
		||||
uint32_t get_path_from_aux_slot(uint32_t slot, uint32_t n_aux_chains)
 | 
			
		||||
{
 | 
			
		||||
  CHECK_AND_ASSERT_THROW_MES(n_aux_chains > 0, "n_aux_chains is 0");
 | 
			
		||||
  CHECK_AND_ASSERT_THROW_MES(slot < n_aux_chains, "slot >= n_aux_chains");
 | 
			
		||||
 | 
			
		||||
  uint32_t path = 0;
 | 
			
		||||
  CHECK_AND_ASSERT_THROW_MES(tree_path(n_aux_chains, slot, &path), "Failed to get path from aux slot");
 | 
			
		||||
  return path;
 | 
			
		||||
}
 | 
			
		||||
//---------------------------------------------------------------
 | 
			
		||||
uint32_t encode_mm_depth(uint32_t n_aux_chains, uint32_t nonce)
 | 
			
		||||
{
 | 
			
		||||
  CHECK_AND_ASSERT_THROW_MES(n_aux_chains > 0, "n_aux_chains is 0");
 | 
			
		||||
 | 
			
		||||
  // how many bits to we need to representing n_aux_chains - 1
 | 
			
		||||
  uint32_t n_bits = 1;
 | 
			
		||||
  while ((1u << n_bits) < n_aux_chains && n_bits < 16)
 | 
			
		||||
    ++n_bits;
 | 
			
		||||
  CHECK_AND_ASSERT_THROW_MES(n_bits <= 16, "Way too many bits required");
 | 
			
		||||
 | 
			
		||||
  const uint32_t depth = (n_bits - 1) | ((n_aux_chains - 1) << 3) | (nonce << (3 + n_bits));
 | 
			
		||||
  return depth;
 | 
			
		||||
}
 | 
			
		||||
//---------------------------------------------------------------
 | 
			
		||||
bool decode_mm_depth(uint32_t depth, uint32_t &n_aux_chains, uint32_t &nonce)
 | 
			
		||||
{
 | 
			
		||||
  const uint32_t n_bits = 1 + (depth & 7);
 | 
			
		||||
  n_aux_chains = 1 + (depth >> 3 & ((1 << n_bits) - 1));
 | 
			
		||||
  nonce = depth >> (3 + n_bits);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//---------------------------------------------------------------
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								src/cryptonote_basic/merge_mining.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/cryptonote_basic/merge_mining.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
// Copyright (c) 2020, 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.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include "crypto/crypto.h"
 | 
			
		||||
 | 
			
		||||
namespace cryptonote
 | 
			
		||||
{
 | 
			
		||||
  uint32_t get_aux_slot(const crypto::hash &id, uint32_t nonce, uint32_t n_aux_chains);
 | 
			
		||||
  uint32_t get_path_from_aux_slot(uint32_t slot, uint32_t n_aux_chains);
 | 
			
		||||
  uint32_t encode_mm_depth(uint32_t n_aux_chains, uint32_t nonce);
 | 
			
		||||
  bool decode_mm_depth(uint32_t depth, uint32_t &n_aux_chains, uint32_t &nonce);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -234,6 +234,7 @@ namespace config
 | 
			
		|||
  const unsigned char HASH_KEY_CLSAG_AGG_0[] = "CLSAG_agg_0";
 | 
			
		||||
  const unsigned char HASH_KEY_CLSAG_AGG_1[] = "CLSAG_agg_1";
 | 
			
		||||
  const char HASH_KEY_MESSAGE_SIGNING[] = "MoneroMessageSignature";
 | 
			
		||||
  const unsigned char HASH_KEY_MM_SLOT = 'm';
 | 
			
		||||
 | 
			
		||||
  namespace testnet
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -133,6 +133,18 @@ int main(int argc, char* argv[])
 | 
			
		|||
  {
 | 
			
		||||
    std::cout << "Parsed block:" << std::endl;
 | 
			
		||||
    std::cout << cryptonote::obj_to_json_str(block) << std::endl;
 | 
			
		||||
    bool parsed = cryptonote::parse_tx_extra(block.miner_tx.extra, fields);
 | 
			
		||||
    if (!parsed)
 | 
			
		||||
      std::cout << "Failed to parse tx_extra" << std::endl;
 | 
			
		||||
 | 
			
		||||
    if (!fields.empty())
 | 
			
		||||
    {
 | 
			
		||||
      print_extra_fields(fields);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      std::cout << "No fields were found in tx_extra" << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else if (cryptonote::parse_and_validate_tx_from_blob(blob, tx) || cryptonote::parse_and_validate_tx_base_from_blob(blob, tx))
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,6 +44,7 @@ using namespace epee;
 | 
			
		|||
#include "cryptonote_basic/cryptonote_format_utils.h"
 | 
			
		||||
#include "cryptonote_basic/account.h"
 | 
			
		||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
 | 
			
		||||
#include "cryptonote_basic/merge_mining.h"
 | 
			
		||||
#include "cryptonote_core/tx_sanity_check.h"
 | 
			
		||||
#include "misc_language.h"
 | 
			
		||||
#include "net/parse.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -1826,6 +1827,125 @@ namespace cryptonote
 | 
			
		|||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
  bool core_rpc_server::on_add_aux_pow(const COMMAND_RPC_ADD_AUX_POW::request& req, COMMAND_RPC_ADD_AUX_POW::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
 | 
			
		||||
  {
 | 
			
		||||
    RPC_TRACKER(add_aux_pow);
 | 
			
		||||
    bool r;
 | 
			
		||||
    if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_ADD_AUX_POW>(invoke_http_mode::JON_RPC, "add_aux_pow", req, res, r))
 | 
			
		||||
      return r;
 | 
			
		||||
 | 
			
		||||
    if (req.aux_pow.empty())
 | 
			
		||||
    {
 | 
			
		||||
      error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
 | 
			
		||||
      error_resp.message = "Empty aux pow hash vector";
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    crypto::hash merkle_root;
 | 
			
		||||
    size_t merkle_tree_depth = 0;
 | 
			
		||||
    std::vector<std::pair<crypto::hash, crypto::hash>> aux_pow;
 | 
			
		||||
    std::vector<crypto::hash> aux_pow_raw;
 | 
			
		||||
    aux_pow.reserve(req.aux_pow.size());
 | 
			
		||||
    aux_pow_raw.reserve(req.aux_pow.size());
 | 
			
		||||
    for (const auto &s: req.aux_pow)
 | 
			
		||||
    {
 | 
			
		||||
      aux_pow.push_back({});
 | 
			
		||||
      if (!epee::string_tools::hex_to_pod(s.id, aux_pow.back().first))
 | 
			
		||||
      {
 | 
			
		||||
        error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
 | 
			
		||||
        error_resp.message = "Invalid aux pow id";
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
      if (!epee::string_tools::hex_to_pod(s.hash, aux_pow.back().second))
 | 
			
		||||
      {
 | 
			
		||||
        error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
 | 
			
		||||
        error_resp.message = "Invalid aux pow hash";
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
      aux_pow_raw.push_back(aux_pow.back().second);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t path_domain = 1;
 | 
			
		||||
    while ((1u << path_domain) < aux_pow.size())
 | 
			
		||||
      ++path_domain;
 | 
			
		||||
    uint32_t nonce;
 | 
			
		||||
    const uint32_t max_nonce = 65535;
 | 
			
		||||
    bool collision = true;
 | 
			
		||||
    for (nonce = 0; nonce <= max_nonce; ++nonce)
 | 
			
		||||
    {
 | 
			
		||||
      std::vector<bool> slots(aux_pow.size(), false);
 | 
			
		||||
      collision = false;
 | 
			
		||||
      for (size_t idx = 0; idx < aux_pow.size(); ++idx)
 | 
			
		||||
      {
 | 
			
		||||
        const uint32_t slot = cryptonote::get_aux_slot(aux_pow[idx].first, nonce, aux_pow.size());
 | 
			
		||||
        if (slot >= aux_pow.size())
 | 
			
		||||
        {
 | 
			
		||||
          error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
 | 
			
		||||
          error_resp.message = "Computed slot is out of range";
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (slots[slot])
 | 
			
		||||
        {
 | 
			
		||||
          collision = true;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        slots[slot] = true;
 | 
			
		||||
      }
 | 
			
		||||
      if (!collision)
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    if (collision)
 | 
			
		||||
    {
 | 
			
		||||
      error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
 | 
			
		||||
      error_resp.message = "Failed to find a suitable nonce";
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    crypto::tree_hash((const char(*)[crypto::HASH_SIZE])aux_pow_raw.data(), aux_pow_raw.size(), merkle_root.data);
 | 
			
		||||
    res.merkle_root = epee::string_tools::pod_to_hex(merkle_root);
 | 
			
		||||
    res.merkle_tree_depth = cryptonote::encode_mm_depth(aux_pow.size(), nonce);
 | 
			
		||||
 | 
			
		||||
    blobdata blocktemplate_blob;
 | 
			
		||||
    if (!epee::string_tools::parse_hexstr_to_binbuff(req.blocktemplate_blob, blocktemplate_blob))
 | 
			
		||||
    {
 | 
			
		||||
      error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
 | 
			
		||||
      error_resp.message = "Invalid blocktemplate_blob";
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    block b;
 | 
			
		||||
    if (!parse_and_validate_block_from_blob(blocktemplate_blob, b))
 | 
			
		||||
    {
 | 
			
		||||
      error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB;
 | 
			
		||||
      error_resp.message = "Wrong blocktemplate_blob";
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!remove_field_from_tx_extra(b.miner_tx.extra, typeid(cryptonote::tx_extra_merge_mining_tag)))
 | 
			
		||||
    {
 | 
			
		||||
      error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
 | 
			
		||||
      error_resp.message = "Error removing existing merkle root";
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (!add_mm_merkle_root_to_tx_extra(b.miner_tx.extra, merkle_root, merkle_tree_depth))
 | 
			
		||||
    {
 | 
			
		||||
      error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
 | 
			
		||||
      error_resp.message = "Error adding merkle root";
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    b.invalidate_hashes();
 | 
			
		||||
    b.miner_tx.invalidate_hashes();
 | 
			
		||||
 | 
			
		||||
    const blobdata block_blob = t_serializable_object_to_blob(b);
 | 
			
		||||
    const blobdata hashing_blob = get_block_hashing_blob(b);
 | 
			
		||||
 | 
			
		||||
    res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob);
 | 
			
		||||
    res.blockhashing_blob = string_tools::buff_to_hex_nodelimer(hashing_blob);
 | 
			
		||||
    res.aux_pow = req.aux_pow;
 | 
			
		||||
    res.status = CORE_RPC_STATUS_OK;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
  bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
 | 
			
		||||
  {
 | 
			
		||||
    RPC_TRACKER(submitblock);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -146,6 +146,7 @@ namespace cryptonote
 | 
			
		|||
        MAP_JON_RPC_WE("on_getblockhash",        on_getblockhash,               COMMAND_RPC_GETBLOCKHASH)
 | 
			
		||||
        MAP_JON_RPC_WE("get_block_template",     on_getblocktemplate,           COMMAND_RPC_GETBLOCKTEMPLATE)
 | 
			
		||||
        MAP_JON_RPC_WE("getblocktemplate",       on_getblocktemplate,           COMMAND_RPC_GETBLOCKTEMPLATE)
 | 
			
		||||
        MAP_JON_RPC_WE("add_aux_pow",            on_add_aux_pow,                COMMAND_RPC_ADD_AUX_POW)
 | 
			
		||||
        MAP_JON_RPC_WE("submit_block",           on_submitblock,                COMMAND_RPC_SUBMITBLOCK)
 | 
			
		||||
        MAP_JON_RPC_WE("submitblock",            on_submitblock,                COMMAND_RPC_SUBMITBLOCK)
 | 
			
		||||
        MAP_JON_RPC_WE_IF("generateblocks",         on_generateblocks,             COMMAND_RPC_GENERATEBLOCKS, !m_restricted)
 | 
			
		||||
| 
						 | 
				
			
			@ -226,6 +227,7 @@ namespace cryptonote
 | 
			
		|||
    bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, const connection_context *ctx = NULL);
 | 
			
		||||
    bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
 | 
			
		||||
    bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
 | 
			
		||||
    bool on_add_aux_pow(const COMMAND_RPC_ADD_AUX_POW::request& req, COMMAND_RPC_ADD_AUX_POW::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
 | 
			
		||||
    bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
 | 
			
		||||
    bool on_generateblocks(const COMMAND_RPC_GENERATEBLOCKS::request& req, COMMAND_RPC_GENERATEBLOCKS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
 | 
			
		||||
    bool on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,7 +88,7 @@ namespace cryptonote
 | 
			
		|||
// advance which version they will stop working with
 | 
			
		||||
// Don't go over 32767 for any of these
 | 
			
		||||
#define CORE_RPC_VERSION_MAJOR 3
 | 
			
		||||
#define CORE_RPC_VERSION_MINOR 5
 | 
			
		||||
#define CORE_RPC_VERSION_MINOR 6
 | 
			
		||||
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
 | 
			
		||||
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -938,6 +938,52 @@ namespace cryptonote
 | 
			
		|||
    typedef epee::misc_utils::struct_init<response_t> response;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct COMMAND_RPC_ADD_AUX_POW
 | 
			
		||||
  {
 | 
			
		||||
    struct aux_pow_t
 | 
			
		||||
    {
 | 
			
		||||
      std::string id;
 | 
			
		||||
      std::string hash;
 | 
			
		||||
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE(id)
 | 
			
		||||
        KV_SERIALIZE(hash)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct request_t: public rpc_request_base
 | 
			
		||||
    {
 | 
			
		||||
      blobdata blocktemplate_blob;
 | 
			
		||||
      std::vector<aux_pow_t> aux_pow;
 | 
			
		||||
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE_PARENT(rpc_request_base)
 | 
			
		||||
        KV_SERIALIZE(blocktemplate_blob)
 | 
			
		||||
        KV_SERIALIZE(aux_pow)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
    typedef epee::misc_utils::struct_init<request_t> request;
 | 
			
		||||
 | 
			
		||||
    struct response_t: public rpc_response_base
 | 
			
		||||
    {
 | 
			
		||||
      blobdata blocktemplate_blob;
 | 
			
		||||
      blobdata blockhashing_blob;
 | 
			
		||||
      std::string merkle_root;
 | 
			
		||||
      uint32_t merkle_tree_depth;
 | 
			
		||||
      std::vector<aux_pow_t> aux_pow;
 | 
			
		||||
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE_PARENT(rpc_response_base)
 | 
			
		||||
        KV_SERIALIZE(blocktemplate_blob)
 | 
			
		||||
        KV_SERIALIZE(blockhashing_blob)
 | 
			
		||||
        KV_SERIALIZE(merkle_root)
 | 
			
		||||
        KV_SERIALIZE(merkle_tree_depth)
 | 
			
		||||
        KV_SERIALIZE(aux_pow)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
    typedef epee::misc_utils::struct_init<response_t> response;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct COMMAND_RPC_SUBMITBLOCK
 | 
			
		||||
  {
 | 
			
		||||
    typedef std::vector<std::string> request;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,7 @@
 | 
			
		|||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
 | 
			
		||||
#include "cryptonote_basic/merge_mining.h"
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -99,3 +100,215 @@ TEST(Crypto, verify_32)
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Crypto, tree_branch)
 | 
			
		||||
{
 | 
			
		||||
  crypto::hash inputs[6];
 | 
			
		||||
  crypto::hash branch[8];
 | 
			
		||||
  crypto::hash root, root2;
 | 
			
		||||
  size_t depth;
 | 
			
		||||
  uint32_t path, path2;
 | 
			
		||||
 | 
			
		||||
  auto hasher = [](const crypto::hash &h0, const crypto::hash &h1) -> crypto::hash
 | 
			
		||||
  {
 | 
			
		||||
    char buffer[64];
 | 
			
		||||
    memcpy(buffer, &h0, 32);
 | 
			
		||||
    memcpy(buffer + 32, &h1, 32);
 | 
			
		||||
    crypto::hash res;
 | 
			
		||||
    cn_fast_hash(buffer, 64, res);
 | 
			
		||||
    return res;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  for (int n = 0; n < 6; ++n)
 | 
			
		||||
  {
 | 
			
		||||
    memset(&inputs[n], 0, 32);
 | 
			
		||||
    inputs[n].data[0] = n + 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // empty
 | 
			
		||||
  ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 0, crypto::null_hash.data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
 | 
			
		||||
  // one, matching
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 1, inputs[0].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
  ASSERT_EQ(depth, 0);
 | 
			
		||||
  ASSERT_EQ(path, 0);
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_path(1, 0, &path2));
 | 
			
		||||
  ASSERT_EQ(path, path2);
 | 
			
		||||
  crypto::tree_hash((const char(*)[32])inputs, 1, root.data);
 | 
			
		||||
  ASSERT_EQ(root, inputs[0]);
 | 
			
		||||
  ASSERT_TRUE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
 | 
			
		||||
  // one, not found
 | 
			
		||||
  ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 1, inputs[1].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
 | 
			
		||||
  // two, index 0
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 2, inputs[0].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
  ASSERT_EQ(depth, 1);
 | 
			
		||||
  ASSERT_EQ(path, 0);
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_path(2, 0, &path2));
 | 
			
		||||
  ASSERT_EQ(path, path2);
 | 
			
		||||
  ASSERT_EQ(branch[0], inputs[1]);
 | 
			
		||||
  crypto::tree_hash((const char(*)[32])inputs, 2, root.data);
 | 
			
		||||
  ASSERT_EQ(root, hasher(inputs[0], inputs[1]));
 | 
			
		||||
  ASSERT_TRUE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
 | 
			
		||||
  // two, index 1
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 2, inputs[1].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
  ASSERT_EQ(depth, 1);
 | 
			
		||||
  ASSERT_EQ(path, 1);
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_path(2, 1, &path2));
 | 
			
		||||
  ASSERT_EQ(path, path2);
 | 
			
		||||
  ASSERT_EQ(branch[0], inputs[0]);
 | 
			
		||||
  crypto::tree_hash((const char(*)[32])inputs, 2, root.data);
 | 
			
		||||
  ASSERT_EQ(root, hasher(inputs[0], inputs[1]));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_TRUE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
 | 
			
		||||
  // two, not found
 | 
			
		||||
  ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 2, inputs[2].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
 | 
			
		||||
  // a b c 0
 | 
			
		||||
  //  x   y
 | 
			
		||||
  //    z
 | 
			
		||||
 | 
			
		||||
  // three, index 0
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 3, inputs[0].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
  ASSERT_GE(depth, 1);
 | 
			
		||||
  ASSERT_LE(depth, 2);
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_path(3, 0, &path2));
 | 
			
		||||
  ASSERT_EQ(path, path2);
 | 
			
		||||
  crypto::tree_hash((const char(*)[32])inputs, 3, root.data);
 | 
			
		||||
  ASSERT_EQ(root, hasher(inputs[0], hasher(inputs[1], inputs[2])));
 | 
			
		||||
  ASSERT_TRUE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
 | 
			
		||||
  // three, index 1
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 3, inputs[1].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
  ASSERT_GE(depth, 1);
 | 
			
		||||
  ASSERT_LE(depth, 2);
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_path(3, 1, &path2));
 | 
			
		||||
  ASSERT_EQ(path, path2);
 | 
			
		||||
  crypto::tree_hash((const char(*)[32])inputs, 3, root.data);
 | 
			
		||||
  ASSERT_EQ(root, hasher(inputs[0], hasher(inputs[1], inputs[2])));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_TRUE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
 | 
			
		||||
  // three, index 2
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 3, inputs[2].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
  ASSERT_GE(depth, 1);
 | 
			
		||||
  ASSERT_LE(depth, 2);
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_path(3, 2, &path2));
 | 
			
		||||
  ASSERT_EQ(path, path2);
 | 
			
		||||
  crypto::tree_hash((const char(*)[32])inputs, 3, root.data);
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_TRUE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch_hash(inputs[2].data, (const char(*)[32])branch, depth, path, root2.data));
 | 
			
		||||
  ASSERT_EQ(root, root2);
 | 
			
		||||
 | 
			
		||||
  // three, not found
 | 
			
		||||
  ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 3, inputs[3].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
 | 
			
		||||
  // a b c d e 0 0 0
 | 
			
		||||
  //    x   y
 | 
			
		||||
  //      z
 | 
			
		||||
  //    w
 | 
			
		||||
 | 
			
		||||
  // five, index 0
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 5, inputs[0].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
  ASSERT_GE(depth, 2);
 | 
			
		||||
  ASSERT_LE(depth, 3);
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_path(5, 0, &path2));
 | 
			
		||||
  ASSERT_EQ(path, path2);
 | 
			
		||||
  crypto::tree_hash((const char(*)[32])inputs, 5, root.data);
 | 
			
		||||
  ASSERT_TRUE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[5].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
 | 
			
		||||
  // five, index 1
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 5, inputs[1].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
  ASSERT_GE(depth, 2);
 | 
			
		||||
  ASSERT_LE(depth, 3);
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_path(5, 1, &path2));
 | 
			
		||||
  ASSERT_EQ(path, path2);
 | 
			
		||||
  crypto::tree_hash((const char(*)[32])inputs, 5, root.data);
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_TRUE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[5].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
 | 
			
		||||
  // five, index 2
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 5, inputs[2].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
  ASSERT_GE(depth, 2);
 | 
			
		||||
  ASSERT_LE(depth, 3);
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_path(5, 2, &path2));
 | 
			
		||||
  ASSERT_EQ(path, path2);
 | 
			
		||||
  crypto::tree_hash((const char(*)[32])inputs, 5, root.data);
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_TRUE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[5].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
 | 
			
		||||
  // five, index 4
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 5, inputs[4].data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
  ASSERT_GE(depth, 2);
 | 
			
		||||
  ASSERT_LE(depth, 3);
 | 
			
		||||
  ASSERT_TRUE(crypto::tree_path(5, 4, &path2));
 | 
			
		||||
  ASSERT_EQ(path, path2);
 | 
			
		||||
  crypto::tree_hash((const char(*)[32])inputs, 5, root.data);
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_TRUE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[5].data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
 | 
			
		||||
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth - 1, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth + 1, path));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path ^ 1));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path ^ 2));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path ^ 3));
 | 
			
		||||
  ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])(branch + 1), depth, path));
 | 
			
		||||
 | 
			
		||||
  // five, not found
 | 
			
		||||
  ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 5, crypto::null_hash.data, (char(*)[32])branch, &depth, &path));
 | 
			
		||||
 | 
			
		||||
  // depth encoding roundtrip
 | 
			
		||||
  for (uint32_t n_chains = 1; n_chains <= 65; ++n_chains)
 | 
			
		||||
  {
 | 
			
		||||
    for (uint32_t nonce = 0; nonce < 1024; ++nonce)
 | 
			
		||||
    {
 | 
			
		||||
      const uint32_t depth = cryptonote::encode_mm_depth(n_chains, nonce);
 | 
			
		||||
      uint32_t n_chains_2, nonce_2;
 | 
			
		||||
      ASSERT_TRUE(cryptonote::decode_mm_depth(depth, n_chains_2, nonce_2));
 | 
			
		||||
      ASSERT_EQ(n_chains, n_chains_2);
 | 
			
		||||
      ASSERT_EQ(nonce, nonce_2);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,6 +53,19 @@ class Daemon(object):
 | 
			
		|||
        return self.rpc.send_json_rpc_request(getblocktemplate)
 | 
			
		||||
    get_block_template = getblocktemplate
 | 
			
		||||
 | 
			
		||||
    def add_aux_pow(self, blocktemplate_blob, aux_pow, client = ""):
 | 
			
		||||
        add_aux_pow = {
 | 
			
		||||
            'method': 'add_aux_pow',
 | 
			
		||||
            'params': {
 | 
			
		||||
                'blocktemplate_blob': blocktemplate_blob,
 | 
			
		||||
                'aux_pow' : aux_pow,
 | 
			
		||||
                'client' : client,
 | 
			
		||||
            },
 | 
			
		||||
            'jsonrpc': '2.0',
 | 
			
		||||
            'id': '0'
 | 
			
		||||
        }
 | 
			
		||||
        return self.rpc.send_json_rpc_request(add_aux_pow)
 | 
			
		||||
 | 
			
		||||
    def send_raw_transaction(self, tx_as_hex, do_not_relay = False, do_sanity_checks = True, client = ""):
 | 
			
		||||
        send_raw_transaction = {
 | 
			
		||||
            'client': client,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue