Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 61fecb0757 | |||
| af767856f0 | |||
| 02d48ecc72 | |||
| f382894d9c | |||
| c359843323 | |||
| db89485957 | |||
| a9d6ab839f | |||
| fef5d6e3a5 | |||
| c545b65f01 | |||
| c93a411c64 | |||
| 08798aaff0 | |||
| b660e2c154 | |||
| 24bf4d44f9 | |||
| 2f116a267b | |||
| e4f21ac12a | |||
| 01c0279543 | |||
| 47b898375b | |||
| 89271f9517 | |||
| d71a8a4feb | |||
| 903dacf470 | |||
| 2f554e2fcd | |||
| 83e3280861 | |||
| 429077e4c7 | |||
| 46c038018b | |||
| 5afa00d329 | |||
| 75e5e04509 | |||
| 1a31a67303 | |||
| ee84d41d34 | |||
| 23696c6c63 | |||
| 1583dcd07a | |||
| b234fcb6c6 | |||
| 5bda5f949e | |||
| f4818ad461 | |||
| 1ec4fd5b72 |
@@ -1,5 +1,5 @@
|
||||
Node-CryptoForkNote-Util
|
||||
====================
|
||||
Node-CryptoForkNote-Util with Merged Mining support
|
||||
===================================================
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cryptoforknote-util",
|
||||
"version": "4.0.0",
|
||||
"version": "7.0.0",
|
||||
"main": "cryptoforknote-util",
|
||||
"author": {
|
||||
"name": "LucasJones",
|
||||
|
||||
@@ -16,6 +16,10 @@ namespace crypto {
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
POD_CLASS cycle {
|
||||
public:
|
||||
uint32_t data[32];
|
||||
};
|
||||
POD_CLASS hash {
|
||||
char data[HASH_SIZE];
|
||||
};
|
||||
|
||||
+10
-8
@@ -3,11 +3,13 @@
|
||||
#define CURRENT_TRANSACTION_VERSION 1
|
||||
|
||||
enum BLOB_TYPE {
|
||||
BLOB_TYPE_CRYPTONOTE = 0,
|
||||
BLOB_TYPE_FORKNOTE1 = 1,
|
||||
BLOB_TYPE_FORKNOTE2 = 2,
|
||||
BLOB_TYPE_CRYPTONOTE2 = 3, // Masari
|
||||
BLOB_TYPE_CRYPTONOTE_RYO = 4, // Ryo
|
||||
BLOB_TYPE_CRYPTONOTE_LOKI = 5, // Loki
|
||||
BLOB_TYPE_CRYPTONOTE3 = 6, // Masari
|
||||
};
|
||||
BLOB_TYPE_CRYPTONOTE = 0,
|
||||
BLOB_TYPE_FORKNOTE1 = 1,
|
||||
BLOB_TYPE_FORKNOTE2 = 2,
|
||||
BLOB_TYPE_CRYPTONOTE2 = 3, // Masari
|
||||
BLOB_TYPE_CRYPTONOTE_RYO = 4, // Ryo
|
||||
BLOB_TYPE_CRYPTONOTE_LOKI = 5, // Loki
|
||||
BLOB_TYPE_CRYPTONOTE3 = 6, // Masari
|
||||
BLOB_TYPE_AEON = 7, // Aeon
|
||||
BLOB_TYPE_CRYPTONOTE_CUCKOO = 8, // MoneroV / Swap
|
||||
};
|
||||
|
||||
@@ -25,16 +25,20 @@
|
||||
#include "misc_language.h"
|
||||
#include "tx_extra.h"
|
||||
#include "ringct/rctTypes.h"
|
||||
#include "cryptonote_protocol/blobdatatype.h"
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
struct block;
|
||||
class transaction;
|
||||
class transaction_prefix;
|
||||
struct tx_extra_merge_mining_tag;
|
||||
|
||||
// Implemented in cryptonote_format_utils.cpp
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res);
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res);
|
||||
bool get_mm_tag_from_extra(const std::vector<uint8_t>& tx, tx_extra_merge_mining_tag& mm_tag);
|
||||
|
||||
const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash);
|
||||
@@ -137,6 +141,15 @@ namespace cryptonote
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
enum loki_version
|
||||
{
|
||||
loki_version_0 = 0,
|
||||
loki_version_1,
|
||||
loki_version_2,
|
||||
loki_version_3_per_output_unlock_times,
|
||||
loki_version_4_tx_types,
|
||||
};
|
||||
|
||||
class transaction_prefix
|
||||
{
|
||||
|
||||
@@ -151,20 +164,45 @@ namespace cryptonote
|
||||
//extra
|
||||
std::vector<uint8_t> extra;
|
||||
|
||||
//
|
||||
// NOTE: Loki specific
|
||||
//
|
||||
std::vector<uint64_t> output_unlock_times;
|
||||
bool is_deregister;
|
||||
enum loki_type_t
|
||||
{
|
||||
loki_type_standard,
|
||||
loki_type_deregister,
|
||||
loki_type_key_image_unlock,
|
||||
loki_type_count,
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
bool is_deregister;
|
||||
uint16_t type;
|
||||
};
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(version)
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI)
|
||||
if (version > loki_version_2 && blob_type == BLOB_TYPE_CRYPTONOTE_LOKI)
|
||||
{
|
||||
FIELD(output_unlock_times)
|
||||
FIELD(is_deregister)
|
||||
if (version == loki_version_3_per_output_unlock_times)
|
||||
FIELD(is_deregister)
|
||||
}
|
||||
VARINT_FIELD(unlock_time)
|
||||
FIELD(vin)
|
||||
FIELD(vout)
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI)
|
||||
{
|
||||
if (version >= loki_version_3_per_output_unlock_times && vout.size() != output_unlock_times.size()) return false;
|
||||
}
|
||||
FIELD(extra)
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI && version >= loki_version_4_tx_types)
|
||||
{
|
||||
VARINT_FIELD(type)
|
||||
if (static_cast<uint16_t>(type) >= loki_type_count) return false;
|
||||
}
|
||||
END_SERIALIZE()
|
||||
|
||||
|
||||
@@ -185,7 +223,7 @@ namespace cryptonote
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELDS(*static_cast<transaction_prefix *>(this))
|
||||
|
||||
if (version == 1 && blob_type != BLOB_TYPE_CRYPTONOTE2)
|
||||
if (version == 1 && blob_type != BLOB_TYPE_CRYPTONOTE2 && blob_type != BLOB_TYPE_CRYPTONOTE3)
|
||||
{
|
||||
ar.tag("signatures");
|
||||
ar.begin_array();
|
||||
@@ -319,8 +357,18 @@ namespace cryptonote
|
||||
if (hashing_serialization)
|
||||
{
|
||||
crypto::hash miner_tx_hash;
|
||||
if (!get_transaction_hash(b.miner_tx, miner_tx_hash))
|
||||
return false;
|
||||
|
||||
if (b.miner_tx.version < 2) {
|
||||
if (!get_transaction_hash(b.miner_tx, miner_tx_hash))
|
||||
return false;
|
||||
} else {
|
||||
get_transaction_prefix_hash(static_cast<const transaction_prefix&>(b.miner_tx), miner_tx_hash);
|
||||
const uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x36, 0x78, 0x9e, 0x7a, 0x1e, 0x28, 0x14, 0x36, 0x46, 0x42, 0x29, 0x82, 0x8f, 0x81, 0x7d, 0x66, 0x12, 0xf7, 0xb4, 0x77, 0xd6, 0x65, 0x91, 0xff, 0x96, 0xa9, 0xe0, 0x64, 0xbc, 0xc9, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
blobdata blobdata((char*)data, sizeof(data));
|
||||
const unsigned char* p = (unsigned char*)&miner_tx_hash;
|
||||
for (int i = 0; i != HASH_SIZE; ++ i, ++ p) blobdata[i] = *p;
|
||||
get_blob_hash(blobdata, miner_tx_hash);
|
||||
}
|
||||
|
||||
crypto::hash merkle_root;
|
||||
crypto::tree_hash_from_branch(b.miner_tx_branch.data(), b.miner_tx_branch.size(), miner_tx_hash, 0, merkle_root);
|
||||
@@ -381,14 +429,27 @@ namespace cryptonote
|
||||
uint8_t minor_version;
|
||||
uint64_t timestamp;
|
||||
crypto::hash prev_id;
|
||||
uint32_t nonce;
|
||||
uint64_t nonce;
|
||||
uint64_t nonce8;
|
||||
crypto::cycle cycle;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(major_version)
|
||||
VARINT_FIELD(minor_version)
|
||||
if (blob_type != BLOB_TYPE_FORKNOTE2) VARINT_FIELD(timestamp)
|
||||
FIELD(prev_id)
|
||||
if (blob_type != BLOB_TYPE_FORKNOTE2) FIELD(nonce)
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_CUCKOO) FIELD(nonce8)
|
||||
if (blob_type != BLOB_TYPE_FORKNOTE2) {
|
||||
if (blob_type == BLOB_TYPE_AEON) {
|
||||
FIELD(nonce)
|
||||
} else {
|
||||
uint32_t nonce32;
|
||||
if (typename Archive<W>::is_saving()) nonce32 = (uint32_t)nonce;
|
||||
FIELD_N("nonce", nonce32);
|
||||
if (!typename Archive<W>::is_saving()) nonce = nonce32;
|
||||
}
|
||||
}
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_CUCKOO) FIELD(cycle)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
||||
@@ -370,7 +370,7 @@ namespace cryptonote
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
|
||||
{
|
||||
// v1 transactions hash the entire blob
|
||||
if (t.version == 1 && t.blob_type != BLOB_TYPE_CRYPTONOTE2)
|
||||
if (t.version == 1 && t.blob_type != BLOB_TYPE_CRYPTONOTE2 && t.blob_type != BLOB_TYPE_CRYPTONOTE3)
|
||||
{
|
||||
size_t ignored_blob_size, &blob_size_ref = blob_size ? *blob_size : ignored_blob_size;
|
||||
return get_object_hash(t, res, blob_size_ref);
|
||||
@@ -429,13 +429,24 @@ namespace cryptonote
|
||||
//---------------------------------------------------------------
|
||||
bool get_block_hashing_blob(const block& b, blobdata& blob)
|
||||
{
|
||||
blob = t_serializable_object_to_blob(static_cast<const block_header&>(b));
|
||||
if (b.blob_type == BLOB_TYPE_CRYPTONOTE_CUCKOO) {
|
||||
blob = t_serializable_object_to_blob(b.major_version);
|
||||
blob.append(reinterpret_cast<const char*>(&b.minor_version), sizeof(b.minor_version));
|
||||
blob.append(reinterpret_cast<const char*>(&b.timestamp), sizeof(b.timestamp));
|
||||
blob.append(reinterpret_cast<const char*>(&b.prev_id), sizeof(b.prev_id));
|
||||
}
|
||||
else {
|
||||
blob = t_serializable_object_to_blob(static_cast<const block_header&>(b));
|
||||
}
|
||||
crypto::hash tree_root_hash = get_tx_tree_hash(b);
|
||||
blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
|
||||
blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
|
||||
if (b.blob_type == BLOB_TYPE_CRYPTONOTE3) {
|
||||
blob.append(reinterpret_cast<const char*>(&b.uncle), sizeof(b.uncle));
|
||||
}
|
||||
if (b.blob_type == BLOB_TYPE_CRYPTONOTE_CUCKOO) {
|
||||
blob.append(reinterpret_cast<const char*>(&b.nonce8), sizeof(b.nonce8));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
||||
+203
-16
@@ -1,19 +1,55 @@
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
// Copyright (c) 2014-2018, 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.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
|
||||
#define TX_EXTRA_PADDING_MAX_COUNT 255
|
||||
#define TX_EXTRA_NONCE_MAX_COUNT 255
|
||||
|
||||
#define TX_EXTRA_PADDING_MAX_COUNT 255
|
||||
#define TX_EXTRA_NONCE_MAX_COUNT 255
|
||||
#define TX_EXTRA_TAG_PADDING 0x00
|
||||
#define TX_EXTRA_TAG_PUBKEY 0x01
|
||||
#define TX_EXTRA_NONCE 0x02
|
||||
#define TX_EXTRA_MERGE_MINING_TAG 0x03
|
||||
#define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS 0x04
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_REGISTER 0x70
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_DEREGISTER 0x71
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_WINNER 0x72
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR 0x73
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_PUBKEY 0x74
|
||||
#define TX_EXTRA_TAG_TX_SECRET_KEY 0x75
|
||||
#define TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS 0x76
|
||||
#define TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK 0x77
|
||||
#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE
|
||||
|
||||
#define TX_EXTRA_TAG_PADDING 0x00
|
||||
#define TX_EXTRA_TAG_PUBKEY 0x01
|
||||
#define TX_EXTRA_NONCE 0x02
|
||||
#define TX_EXTRA_MERGE_MINING_TAG 0x03
|
||||
|
||||
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
|
||||
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
|
||||
#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
@@ -131,14 +167,165 @@ namespace cryptonote
|
||||
}
|
||||
};
|
||||
|
||||
// per-output additional tx pubkey for multi-destination transfers involving at least one subaddress
|
||||
struct tx_extra_additional_pub_keys
|
||||
{
|
||||
std::vector<crypto::public_key> data;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(data)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_mysterious_minergate
|
||||
{
|
||||
std::string data;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(data)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_service_node_winner
|
||||
{
|
||||
crypto::public_key m_service_node_key;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(m_service_node_key)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_service_node_pubkey
|
||||
{
|
||||
crypto::public_key m_service_node_key;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(m_service_node_key)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
||||
struct tx_extra_service_node_register
|
||||
{
|
||||
std::vector<crypto::public_key> m_public_spend_keys;
|
||||
std::vector<crypto::public_key> m_public_view_keys;
|
||||
uint64_t m_portions_for_operator;
|
||||
std::vector<uint64_t> m_portions;
|
||||
uint64_t m_expiration_timestamp;
|
||||
crypto::signature m_service_node_signature;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(m_public_spend_keys)
|
||||
FIELD(m_public_view_keys)
|
||||
FIELD(m_portions_for_operator)
|
||||
FIELD(m_portions)
|
||||
FIELD(m_expiration_timestamp)
|
||||
FIELD(m_service_node_signature)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_service_node_contributor
|
||||
{
|
||||
crypto::public_key m_spend_public_key;
|
||||
crypto::public_key m_view_public_key;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(m_spend_public_key)
|
||||
FIELD(m_view_public_key)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_service_node_deregister
|
||||
{
|
||||
struct vote
|
||||
{
|
||||
crypto::signature signature;
|
||||
uint32_t voters_quorum_index;
|
||||
};
|
||||
|
||||
uint64_t block_height;
|
||||
uint32_t service_node_index;
|
||||
std::vector<vote> votes;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(block_height)
|
||||
FIELD(service_node_index)
|
||||
FIELD(votes)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_tx_secret_key
|
||||
{
|
||||
crypto::secret_key key;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(key)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_tx_key_image_proofs
|
||||
{
|
||||
struct proof
|
||||
{
|
||||
crypto::key_image key_image;
|
||||
crypto::signature signature;
|
||||
};
|
||||
|
||||
std::vector<proof> proofs;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(proofs)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_tx_key_image_unlock
|
||||
{
|
||||
crypto::key_image key_image;
|
||||
crypto::signature signature;
|
||||
uint32_t nonce;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(key_image)
|
||||
FIELD(signature)
|
||||
FIELD(nonce)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
// tx_extra_field format, except tx_extra_padding and tx_extra_pub_key:
|
||||
// varint tag;
|
||||
// varint size;
|
||||
// varint data[];
|
||||
typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag> tx_extra_field;
|
||||
typedef boost::variant<tx_extra_padding,
|
||||
tx_extra_pub_key,
|
||||
tx_extra_nonce,
|
||||
tx_extra_merge_mining_tag,
|
||||
tx_extra_additional_pub_keys,
|
||||
tx_extra_mysterious_minergate,
|
||||
tx_extra_service_node_pubkey,
|
||||
tx_extra_service_node_register,
|
||||
tx_extra_service_node_contributor,
|
||||
tx_extra_service_node_winner,
|
||||
tx_extra_service_node_deregister,
|
||||
tx_extra_tx_secret_key,
|
||||
tx_extra_tx_key_image_proofs,
|
||||
tx_extra_tx_key_image_unlock
|
||||
> tx_extra_field;
|
||||
}
|
||||
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG);
|
||||
BLOB_SERIALIZER(cryptonote::tx_extra_service_node_deregister::vote);
|
||||
BLOB_SERIALIZER(cryptonote::tx_extra_tx_key_image_proofs::proof);
|
||||
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_register, TX_EXTRA_TAG_SERVICE_NODE_REGISTER);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_deregister, TX_EXTRA_TAG_SERVICE_NODE_DEREGISTER);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_contributor, TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_winner, TX_EXTRA_TAG_SERVICE_NODE_WINNER);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_pubkey, TX_EXTRA_TAG_SERVICE_NODE_PUBKEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_secret_key, TX_EXTRA_TAG_TX_SECRET_KEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_key_image_proofs, TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_key_image_unlock, TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK);
|
||||
|
||||
+153
-18
@@ -17,6 +17,9 @@ using namespace node;
|
||||
using namespace v8;
|
||||
using namespace cryptonote;
|
||||
|
||||
// cryptonote::append_mm_tag_to_extra writes byte with TX_EXTRA_MERGE_MINING_TAG (1 here) and VARINT DEPTH (2 here)
|
||||
const size_t MM_NONCE_SIZE = 1 + 2 + sizeof(crypto::hash);
|
||||
|
||||
blobdata uint64be_to_blob(uint64_t num) {
|
||||
blobdata res = " ";
|
||||
res[0] = num >> 56 & 0xff;
|
||||
@@ -29,7 +32,7 @@ blobdata uint64be_to_blob(uint64_t num) {
|
||||
res[7] = num & 0xff;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static bool fillExtra(cryptonote::block& block1, const cryptonote::block& block2) {
|
||||
cryptonote::tx_extra_merge_mining_tag mm_tag;
|
||||
mm_tag.depth = 0;
|
||||
@@ -41,13 +44,68 @@ static bool fillExtra(cryptonote::block& block1, const cryptonote::block& block2
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool fillExtraMM(cryptonote::block& block1, const cryptonote::block& block2) {
|
||||
cryptonote::tx_extra_merge_mining_tag mm_tag;
|
||||
mm_tag.depth = 0;
|
||||
if (!cryptonote::get_block_header_hash(block2, mm_tag.merkle_root)) {
|
||||
fprintf(stderr, "Can't get child block header hash!\n");
|
||||
return false;
|
||||
}
|
||||
std::vector<uint8_t> extra_nonce_replace;
|
||||
if (!cryptonote::append_mm_tag_to_extra(extra_nonce_replace, mm_tag)) {
|
||||
fprintf(stderr, "Can't append mm_tag extra!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extra_nonce_replace.size() != MM_NONCE_SIZE) {
|
||||
fprintf(stderr, "Wrong MM_NONCE_SIZE size!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t>& extra = block1.miner_tx.extra;
|
||||
size_t pos = 0;
|
||||
|
||||
while (pos < extra.size() && extra[pos] != TX_EXTRA_NONCE) {
|
||||
switch (extra[pos]) {
|
||||
case TX_EXTRA_TAG_PUBKEY: pos += 1 + sizeof(crypto::public_key); break;
|
||||
default: {
|
||||
fprintf(stderr, "Not supported extra tag found: %x\n", extra[pos]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pos + 1 >= extra.size()) {
|
||||
fprintf(stderr, "Can't find TX_EXTRA_NONCE in extra\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int extra_nonce_size = extra[pos + 1];
|
||||
const int new_extra_nonce_size = extra_nonce_size - MM_NONCE_SIZE;
|
||||
|
||||
if (new_extra_nonce_size < 0) {
|
||||
fprintf(stderr, "Too small extra size, can't fit MM tag here\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
extra[pos + 1] = new_extra_nonce_size;
|
||||
std::copy(extra_nonce_replace.begin(), extra_nonce_replace.end(), extra.begin() + pos + 1 + new_extra_nonce_size + 1);
|
||||
//extra.resize(pos + 1 + extra_nonce_size + 1);
|
||||
|
||||
// get the most recent timestamp (solve duplicated timestamps on child coin)
|
||||
if (block2.timestamp > block1.timestamp) block1.timestamp = block2.timestamp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool mergeBlocks(const cryptonote::block& block1, cryptonote::block& block2, const std::vector<crypto::hash>& branch2) {
|
||||
block2.timestamp = block1.timestamp;
|
||||
block2.parent_block.major_version = block1.major_version;
|
||||
block2.parent_block.minor_version = block1.minor_version;
|
||||
block2.parent_block.prev_id = block1.prev_id;
|
||||
block2.parent_block.nonce = block1.nonce;
|
||||
block2.parent_block.miner_tx = block1.miner_tx;
|
||||
block2.parent_block.prev_id = block1.prev_id;
|
||||
block2.parent_block.nonce = block1.nonce;
|
||||
block2.parent_block.miner_tx = block1.miner_tx;
|
||||
block2.parent_block.number_of_transactions = block1.tx_hashes.size() + 1;
|
||||
block2.parent_block.miner_tx_branch.resize(crypto::tree_depth(block1.tx_hashes.size() + 1));
|
||||
std::vector<crypto::hash> transactionHashes;
|
||||
@@ -66,11 +124,10 @@ static bool construct_parent_block(const cryptonote::block& b, cryptonote::block
|
||||
parent_block.nonce = b.parent_block.nonce;
|
||||
parent_block.miner_tx.version = CURRENT_TRANSACTION_VERSION;
|
||||
parent_block.miner_tx.unlock_time = 0;
|
||||
|
||||
return fillExtra(parent_block, b);
|
||||
}
|
||||
|
||||
NAN_METHOD(convert_blob) {
|
||||
NAN_METHOD(convert_blob) { // (parentBlockBuffer, cnBlobType)
|
||||
if (info.Length() < 1) return THROW_ERROR_EXCEPTION("You must provide one argument.");
|
||||
|
||||
Local<Object> target = info[0]->ToObject();
|
||||
@@ -85,17 +142,16 @@ NAN_METHOD(convert_blob) {
|
||||
blob_type = static_cast<enum BLOB_TYPE>(Nan::To<int>(info[1]).FromMaybe(0));
|
||||
}
|
||||
|
||||
//convert
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
b.set_blob_type(blob_type);
|
||||
if (!parse_and_validate_block_from_blob(input, b)) return THROW_ERROR_EXCEPTION("Failed to parse block");
|
||||
|
||||
if (blob_type == BLOB_TYPE_FORKNOTE2) {
|
||||
block parent_block;
|
||||
if (!construct_parent_block(b, parent_block)) return THROW_ERROR_EXCEPTION("Failed to construct parent block");
|
||||
if (!get_block_hashing_blob(parent_block, output)) return THROW_ERROR_EXCEPTION("Failed to create mining block");
|
||||
if (!construct_parent_block(b, parent_block)) return THROW_ERROR_EXCEPTION("convert_blob: Failed to construct parent block");
|
||||
if (!get_block_hashing_blob(parent_block, output)) return THROW_ERROR_EXCEPTION("convert_blob: Failed to create mining block");
|
||||
} else {
|
||||
if (!get_block_hashing_blob(b, output)) return THROW_ERROR_EXCEPTION("Failed to create mining block");
|
||||
if (!get_block_hashing_blob(b, output)) return THROW_ERROR_EXCEPTION("convert_blob: Failed to create mining block");
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> returnValue = Nan::CopyBuffer((char*)output.data(), output.size()).ToLocalChecked();
|
||||
@@ -109,7 +165,6 @@ NAN_METHOD(get_block_id) {
|
||||
if (!Buffer::HasInstance(target)) return THROW_ERROR_EXCEPTION("Argument should be a buffer object.");
|
||||
|
||||
blobdata input = std::string(Buffer::Data(target), Buffer::Length(target));
|
||||
blobdata output = "";
|
||||
|
||||
enum BLOB_TYPE blob_type = BLOB_TYPE_CRYPTONOTE;
|
||||
if (info.Length() >= 2) {
|
||||
@@ -129,18 +184,13 @@ NAN_METHOD(get_block_id) {
|
||||
info.GetReturnValue().Set(returnValue);
|
||||
}
|
||||
|
||||
NAN_METHOD(construct_block_blob) {
|
||||
NAN_METHOD(construct_block_blob) { // (parentBlockTemplateBuffer, nonceBuffer, cnBlobType)
|
||||
if (info.Length() < 2) return THROW_ERROR_EXCEPTION("You must provide two arguments.");
|
||||
|
||||
Local<Object> block_template_buf = info[0]->ToObject();
|
||||
Local<Object> nonce_buf = info[1]->ToObject();
|
||||
|
||||
if (!Buffer::HasInstance(block_template_buf) || !Buffer::HasInstance(nonce_buf)) return THROW_ERROR_EXCEPTION("Both arguments should be buffer objects.");
|
||||
if (Buffer::Length(nonce_buf) != 4) return THROW_ERROR_EXCEPTION("Nonce buffer has invalid size.");
|
||||
|
||||
uint32_t nonce = *reinterpret_cast<uint32_t*>(Buffer::Data(nonce_buf));
|
||||
blobdata block_template_blob = std::string(Buffer::Data(block_template_buf), Buffer::Length(block_template_buf));
|
||||
blobdata output = "";
|
||||
|
||||
enum BLOB_TYPE blob_type = BLOB_TYPE_CRYPTONOTE;
|
||||
if (info.Length() >= 3) {
|
||||
@@ -148,6 +198,12 @@ NAN_METHOD(construct_block_blob) {
|
||||
blob_type = static_cast<enum BLOB_TYPE>(Nan::To<int>(info[2]).FromMaybe(0));
|
||||
}
|
||||
|
||||
if (Buffer::Length(nonce_buf) != (blob_type == BLOB_TYPE_AEON ? 8 : 4)) return THROW_ERROR_EXCEPTION("Nonce buffer has invalid size.");
|
||||
|
||||
uint64_t nonce = blob_type == BLOB_TYPE_AEON ? *reinterpret_cast<uint64_t*>(Buffer::Data(nonce_buf)) : *reinterpret_cast<uint32_t*>(Buffer::Data(nonce_buf));
|
||||
blobdata block_template_blob = std::string(Buffer::Data(block_template_buf), Buffer::Length(block_template_buf));
|
||||
blobdata output = "";
|
||||
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
b.set_blob_type(blob_type);
|
||||
if (!parse_and_validate_block_from_blob(block_template_blob, b)) return THROW_ERROR_EXCEPTION("Failed to parse block");
|
||||
@@ -160,13 +216,18 @@ NAN_METHOD(construct_block_blob) {
|
||||
if (!mergeBlocks(parent_block, b, std::vector<crypto::hash>())) return THROW_ERROR_EXCEPTION("Failed to postprocess mining block");
|
||||
}
|
||||
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_CUCKOO) {
|
||||
if (info.Length() != 4) return THROW_ERROR_EXCEPTION("You must provide 4 arguments.");
|
||||
Local<Array> cycle = Local<Array>::Cast(info[3]);
|
||||
for (int i = 0; i < 32; i++ ) b.cycle.data[i] = cycle->Get(i)->NumberValue();
|
||||
}
|
||||
|
||||
if (!block_to_blob(b, output)) return THROW_ERROR_EXCEPTION("Failed to convert block to blob");
|
||||
|
||||
v8::Local<v8::Value> returnValue = Nan::CopyBuffer((char*)output.data(), output.size()).ToLocalChecked();
|
||||
info.GetReturnValue().Set(returnValue);
|
||||
}
|
||||
|
||||
|
||||
NAN_METHOD(address_decode) {
|
||||
if (info.Length() < 1) return THROW_ERROR_EXCEPTION("You must provide one argument.");
|
||||
|
||||
@@ -227,12 +288,86 @@ NAN_METHOD(address_decode_integrated) {
|
||||
}
|
||||
}
|
||||
|
||||
NAN_METHOD(get_merged_mining_nonce_size) {
|
||||
Local<Integer> returnValue = Nan::New(static_cast<uint32_t>(MM_NONCE_SIZE));
|
||||
info.GetReturnValue().Set(returnValue);
|
||||
}
|
||||
|
||||
NAN_METHOD(construct_mm_parent_block_blob) { // (parentBlockTemplate, blob_type, childBlockTemplate)
|
||||
if (info.Length() < 3) return THROW_ERROR_EXCEPTION("You must provide three arguments (parentBlock, blob_type, childBlock).");
|
||||
|
||||
Local<Object> target = info[0]->ToObject();
|
||||
Local<Object> child_target = info[2]->ToObject();
|
||||
|
||||
if (!Buffer::HasInstance(target)) return THROW_ERROR_EXCEPTION("First argument should be a buffer object.");
|
||||
if (!info[1]->IsNumber()) return THROW_ERROR_EXCEPTION("Second argument should be a number");
|
||||
if (!Buffer::HasInstance(child_target)) return THROW_ERROR_EXCEPTION("Third argument should be a buffer object.");
|
||||
|
||||
const enum BLOB_TYPE blob_type = static_cast<enum BLOB_TYPE>(Nan::To<int>(info[1]).FromMaybe(0));
|
||||
|
||||
blobdata input = std::string(Buffer::Data(target), Buffer::Length(target));
|
||||
blobdata child_input = std::string(Buffer::Data(child_target), Buffer::Length(child_target));
|
||||
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
b.set_blob_type(blob_type);
|
||||
if (!parse_and_validate_block_from_blob(input, b)) return THROW_ERROR_EXCEPTION("construct_mm_parent_block_blob: Failed to parse prent block");
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI) b.miner_tx.version = cryptonote::loki_version_2;
|
||||
|
||||
block b2 = AUTO_VAL_INIT(b2);
|
||||
b2.set_blob_type(BLOB_TYPE_FORKNOTE2);
|
||||
if (!parse_and_validate_block_from_blob(child_input, b2)) return THROW_ERROR_EXCEPTION("construct_mm_parent_block_blob: Failed to parse child block");
|
||||
|
||||
if (!fillExtraMM(b, b2)) return THROW_ERROR_EXCEPTION("construct_mm_parent_block_blob: Failed to add merged mining tag to parent block extra");
|
||||
|
||||
blobdata output = "";
|
||||
if (!block_to_blob(b, output)) return THROW_ERROR_EXCEPTION("construct_mm_parent_block_blob: Failed to convert child block to blob");
|
||||
|
||||
v8::Local<v8::Value> returnValue = Nan::CopyBuffer((char*)output.data(), output.size()).ToLocalChecked();
|
||||
info.GetReturnValue().Set(returnValue);
|
||||
}
|
||||
|
||||
NAN_METHOD(construct_mm_child_block_blob) { // (shareBuffer, blob_type, childBlockTemplate)
|
||||
if (info.Length() < 3) return THROW_ERROR_EXCEPTION("You must provide three arguments (shareBuffer, blob_type, block2).");
|
||||
|
||||
Local<Object> block_template_buf = info[0]->ToObject();
|
||||
Local<Object> child_block_template_buf = info[2]->ToObject();
|
||||
|
||||
if (!Buffer::HasInstance(block_template_buf)) return THROW_ERROR_EXCEPTION("First argument should be a buffer object.");
|
||||
if (!info[1]->IsNumber()) return THROW_ERROR_EXCEPTION("Second argument should be a number");
|
||||
if (!Buffer::HasInstance(child_block_template_buf)) return THROW_ERROR_EXCEPTION("Third argument should be a buffer object.");
|
||||
|
||||
const enum BLOB_TYPE blob_type = static_cast<enum BLOB_TYPE>(Nan::To<int>(info[1]).FromMaybe(0));
|
||||
|
||||
blobdata block_template_blob = std::string(Buffer::Data(block_template_buf), Buffer::Length(block_template_buf));
|
||||
blobdata child_block_template_blob = std::string(Buffer::Data(child_block_template_buf), Buffer::Length(child_block_template_buf));
|
||||
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
b.set_blob_type(blob_type);
|
||||
if (!parse_and_validate_block_from_blob(block_template_blob, b)) return THROW_ERROR_EXCEPTION("construct_mm_child_block_blob: Failed to parse parent block");
|
||||
|
||||
block b2 = AUTO_VAL_INIT(b2);
|
||||
b2.set_blob_type(BLOB_TYPE_FORKNOTE2);
|
||||
if (!parse_and_validate_block_from_blob(child_block_template_blob, b2)) return THROW_ERROR_EXCEPTION("construct_mm_child_block_blob: Failed to parse child block");
|
||||
|
||||
if (!mergeBlocks(b, b2, std::vector<crypto::hash>())) return THROW_ERROR_EXCEPTION("construct_mm_child_block_blob: Failed to postprocess mining block");
|
||||
|
||||
blobdata output = "";
|
||||
if (!block_to_blob(b2, output)) return THROW_ERROR_EXCEPTION("construct_mm_child_block_blob: Failed to convert child block to blob");
|
||||
|
||||
v8::Local<v8::Value> returnValue = Nan::CopyBuffer((char*)output.data(), output.size()).ToLocalChecked();
|
||||
info.GetReturnValue().Set(returnValue);
|
||||
}
|
||||
|
||||
NAN_MODULE_INIT(init) {
|
||||
Nan::Set(target, Nan::New("construct_block_blob").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(construct_block_blob)).ToLocalChecked());
|
||||
Nan::Set(target, Nan::New("get_block_id").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(get_block_id)).ToLocalChecked());
|
||||
Nan::Set(target, Nan::New("convert_blob").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(convert_blob)).ToLocalChecked());
|
||||
Nan::Set(target, Nan::New("address_decode").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(address_decode)).ToLocalChecked());
|
||||
Nan::Set(target, Nan::New("address_decode_integrated").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(address_decode_integrated)).ToLocalChecked());
|
||||
|
||||
Nan::Set(target, Nan::New("get_merged_mining_nonce_size").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(get_merged_mining_nonce_size)).ToLocalChecked());
|
||||
Nan::Set(target, Nan::New("construct_mm_parent_block_blob").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(construct_mm_parent_block_blob)).ToLocalChecked());
|
||||
Nan::Set(target, Nan::New("construct_mm_child_block_blob").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(construct_mm_child_block_blob)).ToLocalChecked());
|
||||
}
|
||||
|
||||
NODE_MODULE(cryptoforknote, init)
|
||||
|
||||
@@ -53,12 +53,14 @@ bool do_serialize(Archive<true> &ar, std::vector<crypto::signature> &v)
|
||||
|
||||
BLOB_SERIALIZER(crypto::chacha8_iv);
|
||||
BLOB_SERIALIZER(crypto::hash);
|
||||
BLOB_SERIALIZER(crypto::cycle);
|
||||
BLOB_SERIALIZER(crypto::hash8);
|
||||
BLOB_SERIALIZER(crypto::public_key);
|
||||
BLOB_SERIALIZER(crypto::secret_key);
|
||||
BLOB_SERIALIZER(crypto::key_derivation);
|
||||
BLOB_SERIALIZER(crypto::key_image);
|
||||
BLOB_SERIALIZER(crypto::signature);
|
||||
VARIANT_TAG(debug_archive, crypto::cycle, "cycle");
|
||||
VARIANT_TAG(debug_archive, crypto::hash, "hash");
|
||||
VARIANT_TAG(debug_archive, crypto::hash8, "hash8");
|
||||
VARIANT_TAG(debug_archive, crypto::public_key, "public_key");
|
||||
|
||||
Reference in New Issue
Block a user