Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overt transactions #114

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions include/BlockchainExplorerData.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

#include "CryptoTypes.h"
#include "CryptoNote.h"
#include "BlockchainExplorerData.h"
#include "CryptoNoteCore/TransactionExtra.h"
#include <boost/variant.hpp>

namespace CryptoNote {
Expand Down Expand Up @@ -89,6 +89,14 @@ struct TransactionExtraDetails {
std::vector<uint8_t> raw;
};

struct TransactionExtraDetails2 {
std::vector<size_t> padding;
Crypto::PublicKey publicKey;
BinaryArray nonce;
BinaryArray raw;
TransactionExtraDisclosure disclosure;
};

struct transactionOutputDetails2 {
TransactionOutput output;
uint64_t globalIndex;
Expand All @@ -112,13 +120,6 @@ struct MultisignatureInputDetails {

typedef boost::variant<BaseInputDetails, KeyInputDetails, MultisignatureInputDetails> transactionInputDetails2;

struct TransactionExtraDetails2 {
std::vector<size_t> padding;
Crypto::PublicKey publicKey;
BinaryArray nonce;
BinaryArray raw;
};

struct TransactionDetails {
Crypto::Hash hash;
uint64_t size = 0;
Expand Down
4 changes: 2 additions & 2 deletions include/IWalletLegacy.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ class IWalletLegacy {
virtual void getAccountKeys(AccountKeys& keys) = 0;
virtual bool getSeed(std::string& electrum_words) = 0;

virtual TransactionId sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0;
virtual TransactionId sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0;
virtual TransactionId sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, bool overt = false) = 0;
virtual TransactionId sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, bool overt = false) = 0;
virtual TransactionId sendFusionTransaction(const std::list<TransactionOutputInformation>& fusionInputs, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0;
virtual std::error_code cancelTransaction(size_t transferId) = 0;

Expand Down
2 changes: 2 additions & 0 deletions src/BlockchainExplorer/BlockchainExplorerDataBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ bool BlockchainExplorerDataBuilder::fillTxExtra(const std::vector<uint8_t>& rawE
extraDetails.publicKey = std::move(boost::get<TransactionExtraPublicKey>(field).publicKey);
} else if (typeid(TransactionExtraNonce) == field.type()) {
extraDetails.nonce = boost::get<TransactionExtraNonce>(field).nonce;
} else if (typeid(TransactionExtraDisclosure) == field.type()) {
extraDetails.disclosure = std::move(boost::get<TransactionExtraDisclosure>(field));
}
}
return true;
Expand Down
71 changes: 70 additions & 1 deletion src/CryptoNoteCore/Blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ bool operator<(const Crypto::KeyImage& keyImage1, const Crypto::KeyImage& keyIma
}
}

#define CURRENT_BLOCKCACHE_STORAGE_ARCHIVE_VER 1
#define CURRENT_BLOCKCACHE_STORAGE_ARCHIVE_VER 2
#define CURRENT_BLOCKCHAININDICES_STORAGE_ARCHIVE_VER 1

namespace CryptoNote {
Expand Down Expand Up @@ -204,6 +204,9 @@ class BlockCacheSerializer {
logger(INFO) << operation << "transaction map...";
s(m_bs.m_transactionMap, "transactions");

logger(INFO) << operation << "overt transactions...";
s(m_bs.m_overt_transactions, "overt_transactions");

logger(INFO) << operation << "spent keys...";
if (s.type() == ISerializer::OUTPUT) {
writeSequence<Blockchain::SpentKeyImage>(m_bs.spentKeyImages.begin(), m_bs.spentKeyImages.end(), "spent_key_images", s);
Expand Down Expand Up @@ -564,6 +567,7 @@ void Blockchain::rebuildCache() {
spentKeyImages.clear();
m_outputs.clear();
m_multisignatureOutputs.clear();
m_overt_transactions.clear();
for (uint32_t b = 0; b < m_blocks.size(); ++b) {
if (b % 1000 == 0) {
logger(INFO, BRIGHT_WHITE) << "Height " << b << " of " << m_blocks.size();
Expand Down Expand Up @@ -597,6 +601,16 @@ void Blockchain::rebuildCache() {
m_multisignatureOutputs[out.amount].push_back(usage);
}
}

// process overt txs
TransactionExtraDisclosure pp;
if (getTransactionDisclosureFromExtra(transaction.tx.extra, pp)) {
for (auto d : pp.declarations) {
if (std::find(m_overt_transactions[transactionHash].begin(), m_overt_transactions[transactionHash].end(), m_currency.accountAddressAsString(d.first)) == m_overt_transactions[transactionHash].end()) {
m_overt_transactions[transactionHash].push_back(m_currency.accountAddressAsString(d.first));
}
}
}
}
}

Expand Down Expand Up @@ -640,6 +654,7 @@ bool Blockchain::resetAndSetGenesisBlock(const Block& b) {
m_timestampIndex.clear();
m_generatedTransactionsIndex.clear();
m_orphanBlocksIndex.clear();
m_overt_transactions.clear();

block_verification_context bvc = boost::value_initialized<block_verification_context>();
addNewBlock(b, bvc);
Expand Down Expand Up @@ -2346,6 +2361,15 @@ bool Blockchain::pushTransaction(BlockEntry& block, const Crypto::Hash& transact

m_paymentIdIndex.add(transaction.tx);

TransactionExtraDisclosure pp;
if (getTransactionDisclosureFromExtra(transaction.tx.extra, pp)) {
for (auto d : pp.declarations) {
if (std::find(m_overt_transactions[transactionHash].begin(), m_overt_transactions[transactionHash].end(), m_currency.accountAddressAsString(d.first)) == m_overt_transactions[transactionHash].end()) {
m_overt_transactions[transactionHash].push_back(m_currency.accountAddressAsString(d.first));
}
}
}

return true;
}

Expand Down Expand Up @@ -2445,6 +2469,14 @@ void Blockchain::popTransaction(const Transaction& transaction, const Crypto::Ha

m_paymentIdIndex.remove(transaction);

if (m_overt_transactions.find(transactionHash) != m_overt_transactions.end()) {
size_t count = m_overt_transactions.erase(transactionHash);
if (count != 1) {
logger(ERROR, BRIGHT_RED) <<
"Blockchain consistency broken - cannot find transaction by hash.";
}
}

size_t count = m_transactionMap.erase(transactionHash);
if (count != 1) {
logger(ERROR, BRIGHT_RED) <<
Expand Down Expand Up @@ -2719,6 +2751,25 @@ bool Blockchain::getGeneratedTransactionsNumber(uint32_t height, uint64_t& gener
return m_generatedTransactionsIndex.find(height, generatedTransactions);
}

size_t Blockchain::getOvertTransactionsCount() {
std::lock_guard<decltype(m_blockchain_lock)> lk(m_blockchain_lock);
return m_overt_transactions.size();
}

size_t Blockchain::getOvertTransactionsAddressesCount() {
std::lock_guard<decltype(m_blockchain_lock)> lk(m_blockchain_lock);
std::set<std::string> addresses;
for (const auto& o : m_overt_transactions) {
for (const auto& a : o.second) {
if (std::find(addresses.begin(), addresses.end(), a) == addresses.end()) {
addresses.emplace(a);
}
}
}

return addresses.size();
}

bool Blockchain::getOrphanBlockIdsByHeight(uint32_t height, std::vector<Crypto::Hash>& blockHashes) {
std::lock_guard<decltype(m_blockchain_lock)> lk(m_blockchain_lock);
return m_orphanBlocksIndex.find(height, blockHashes);
Expand All @@ -2734,6 +2785,24 @@ bool Blockchain::getTransactionIdsByPaymentId(const Crypto::Hash& paymentId, std
return m_paymentIdIndex.find(paymentId, transactionHashes);
}

bool Blockchain::getOvertTransactionIdsForAddress(const std::string& address, std::vector<Crypto::Hash>& tx_ids) {
std::lock_guard<decltype(m_blockchain_lock)> lk(m_blockchain_lock);

std::vector<Crypto::Hash> found_ids;
for (const auto& o : m_overt_transactions) {
if (std::find(o.second.begin(), o.second.end(), address) != o.second.end()) {
found_ids.push_back(o.first);
}
}

if (!found_ids.empty()) {
tx_ids = std::move(found_ids);
return true;
}

return false;
}

bool Blockchain::loadTransactions(const Block& block, std::vector<Transaction>& transactions) {
transactions.resize(block.transactionHashes.size());
size_t transactionSize;
Expand Down
5 changes: 5 additions & 0 deletions src/CryptoNoteCore/Blockchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ namespace CryptoNote {
bool getOrphanBlockIdsByHeight(uint32_t height, std::vector<Crypto::Hash>& blockHashes);
bool getBlockIdsByTimestamp(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t blocksNumberLimit, std::vector<Crypto::Hash>& hashes, uint32_t& blocksNumberWithinTimestamps);
bool getTransactionIdsByPaymentId(const Crypto::Hash& paymentId, std::vector<Crypto::Hash>& transactionHashes);
bool getOvertTransactionIdsForAddress(const std::string& address, std::vector<Crypto::Hash>& tx_ids);
size_t getOvertTransactionsCount();
size_t getOvertTransactionsAddressesCount();
bool isBlockInMainChain(const Crypto::Hash& blockId);
bool isInCheckpointZone(const uint32_t height);

Expand Down Expand Up @@ -288,6 +291,7 @@ namespace CryptoNote {
>
> SpentKeyImagesContainer;
typedef std::unordered_map<Crypto::Hash, BlockEntry> blocks_ext_by_hash;
typedef std::unordered_map<Crypto::Hash, std::vector<std::string>> overtTransactionsContainer;
typedef google::sparse_hash_map<uint64_t, std::vector<std::pair<TransactionIndex, uint16_t>>> outputs_container; //Crypto::Hash - tx hash, size_t - index of out in transaction
typedef google::sparse_hash_map<uint64_t, std::vector<MultisignatureOutputUsage>> MultisignatureOutputsContainer;

Expand All @@ -301,6 +305,7 @@ namespace CryptoNote {
size_t m_current_block_cumul_sz_limit;
blocks_ext_by_hash m_alternative_chains; // Crypto::Hash -> block_extended_info
outputs_container m_outputs;
overtTransactionsContainer m_overt_transactions;

std::string m_config_folder;
Checkpoints m_checkpoints;
Expand Down
12 changes: 12 additions & 0 deletions src/CryptoNoteCore/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ size_t Core::getAlternativeBlocksCount() {
return m_blockchain.getAlternativeBlocksCount();
}

size_t Core::getOvertTransactionsCount() {
return m_blockchain.getOvertTransactionsCount();
}

size_t Core::getOvertTransactionsAddressesCount() {
return m_blockchain.getOvertTransactionsAddressesCount();
}

bool Core::getblockEntry(uint32_t height, uint64_t& block_cumulative_size, difficulty_type& difficulty, uint64_t& already_generated_coins, uint64_t& reward, uint64_t& transactions_count, uint64_t& timestamp) {
return m_blockchain.getblockEntry(static_cast<size_t>(height), block_cumulative_size, difficulty, already_generated_coins, reward, transactions_count, timestamp);
}
Expand Down Expand Up @@ -1155,6 +1163,10 @@ bool Core::getTransactionsByPaymentId(const Crypto::Hash& paymentId, std::vector
return true;
}

bool Core::getOvertTransactionIdsForAddress(const std::string& address, std::vector<Crypto::Hash>& tx_ids) {
return m_blockchain.getOvertTransactionIdsForAddress(address, tx_ids);
}

std::vector<Crypto::Hash> Core::getTransactionHashesByPaymentId(const Crypto::Hash& paymentId) {
logger(DEBUGGING) << "getTransactionHashesByPaymentId request with paymentId " << paymentId;

Expand Down
3 changes: 3 additions & 0 deletions src/CryptoNoteCore/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ namespace CryptoNote {
virtual bool getBlocksByTimestamp(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t blocksNumberLimit, std::vector<Block>& blocks, uint32_t& blocksNumberWithinTimestamps) override;
virtual bool getPoolTransactionsByTimestamp(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t transactionsNumberLimit, std::vector<Transaction>& transactions, uint64_t& transactionsNumberWithinTimestamps) override;
virtual bool getTransactionsByPaymentId(const Crypto::Hash& paymentId, std::vector<Transaction>& transactions) override;
virtual bool getOvertTransactionIdsForAddress(const std::string& address, std::vector<Crypto::Hash>& tx_ids) override;
virtual std::vector<Crypto::Hash> getTransactionHashesByPaymentId(const Crypto::Hash& paymentId) override;
virtual bool getOutByMSigGIndex(uint64_t amount, uint64_t gindex, MultisignatureOutput& out) override;
virtual std::unique_ptr<IBlock> getBlock(const Crypto::Hash& blocksId) override;
Expand Down Expand Up @@ -135,6 +136,8 @@ namespace CryptoNote {

bool get_alternative_blocks(std::list<Block>& blocks);
virtual size_t getAlternativeBlocksCount() override;
virtual size_t getOvertTransactionsCount() override;
virtual size_t getOvertTransactionsAddressesCount() override;

void set_cryptonote_protocol(i_cryptonote_protocol* pprotocol);
void set_checkpoints(Checkpoints&& chk_pts);
Expand Down
80 changes: 79 additions & 1 deletion src/CryptoNoteCore/CryptoNoteFormatUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <set>
#include <Logging/LoggerRef.h>
#include <Common/Varint.h>
#include "Common/Base58.h"

#include "Serialization/BinaryOutputStreamSerializer.h"
#include "Serialization/BinaryInputStreamSerializer.h"
Expand Down Expand Up @@ -123,7 +124,8 @@ bool constructTransaction(
Transaction& tx,
uint64_t unlock_time,
Crypto::SecretKey &tx_key,
Logging::ILogger& log) {
Logging::ILogger& log,
bool overt) {
LoggerRef logger(log, "construct_tx");

tx.inputs.clear();
Expand Down Expand Up @@ -232,6 +234,58 @@ bool constructTransaction(
return false;
}

if (overt) {
TransactionExtraDisclosure disclosure;

/* We need hash of something for proofs, we don't have tx/prefix hash yet
* so why don't we use tx public key?
*/
Crypto::Hash keyHash = reinterpret_cast<Crypto::Hash &>(txkey.publicKey);

/* Signature to provably distinguish sender. To check we cycle through
* declarations until signature matches address in declaration.
*/
Crypto::generate_signature(keyHash, sender_account_keys.address.spendPublicKey, sender_account_keys.spendSecretKey, disclosure.senderSignature);

/* Generate declarations for each unique destination (remove duplicates
* because we need address - proof pair only once).
*/
std::vector<TransactionDestinationEntry> dsts(destinations);
sort(dsts.begin(), dsts.end());
dsts.erase(unique(dsts.begin(), dsts.end()), dsts.end());

bool foundSender = false;
for (TransactionDestinationEntry d : dsts) {
std::string proof;
if (!get_tx_proof(keyHash, d.addr, tx_key, proof, log)) {
return false;
}
disclosure.declarations.push_back(std::make_pair(d.addr, proof));

/* In edge case when signature doesn't match any of the addresses it means
* that everything was sent to destination without change. In this case
* add another dummy disclosure with sender's address and proof that proves
* nothing in order to store sender's address.
*/
if (d.addr.spendPublicKey == sender_account_keys.address.spendPublicKey &&
d.addr.viewPublicKey == sender_account_keys.address.viewPublicKey) {
foundSender = true;
}
}
if (!foundSender) {
std::string proof;
AccountPublicAddress address = sender_account_keys.address;
if (!get_tx_proof(keyHash, address, tx_key, proof, log)) {
return false;
}
disclosure.declarations.push_back(std::make_pair(address, proof));
}

if (!appendTransactionDisclosureToExtra(tx.extra, disclosure)) {
logger(ERROR) << "Couldn't append overt transaction disclosure";
}
}

//generate ring signatures
Hash tx_prefix_hash;
getObjectHash(*static_cast<TransactionPrefix*>(&tx), tx_prefix_hash);
Expand Down Expand Up @@ -580,4 +634,28 @@ bool is_valid_decomposed_amount(uint64_t amount) {
return true;
}

bool get_tx_proof(Crypto::Hash& txid, CryptoNote::AccountPublicAddress& address, Crypto::SecretKey& tx_key, std::string& sig_str, Logging::ILogger& log) {
LoggerRef logger(log, "construct_tx");
Crypto::KeyImage p = *reinterpret_cast<Crypto::KeyImage*>(&address.viewPublicKey);
Crypto::KeyImage k = *reinterpret_cast<Crypto::KeyImage*>(&tx_key);
Crypto::KeyImage pk = Crypto::scalarmultKey(p, k);
Crypto::PublicKey R;
Crypto::PublicKey rA = reinterpret_cast<const PublicKey&>(pk);
Crypto::secret_key_to_public_key(tx_key, R);
Crypto::Signature sig;
try {
Crypto::generate_tx_proof(txid, R, address.viewPublicKey, rA, tx_key, sig);
}
catch (const std::runtime_error &e) {
logger(ERROR) << "Proof generation error: " << *e.what();
return false;
}

sig_str = std::string("ProofV1") +
Tools::Base58::encode(std::string((const char *)&rA, sizeof(Crypto::PublicKey))) +
Tools::Base58::encode(std::string((const char *)&sig, sizeof(Crypto::Signature)));

return true;
}

}
13 changes: 11 additions & 2 deletions src/CryptoNoteCore/CryptoNoteFormatUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,21 @@ struct TransactionDestinationEntry {

TransactionDestinationEntry() : amount(0), addr(boost::value_initialized<AccountPublicAddress>()) {}
TransactionDestinationEntry(uint64_t amount, const AccountPublicAddress &addr) : amount(amount), addr(addr) {}
};

bool operator<(const TransactionDestinationEntry& a) const {
return a.addr.spendPublicKey.data < addr.spendPublicKey.data && a.addr.viewPublicKey.data < addr.viewPublicKey.data;
}

bool operator==(const TransactionDestinationEntry& a) const {
return a.addr.spendPublicKey == addr.spendPublicKey && a.addr.viewPublicKey == addr.viewPublicKey;
}
};

bool constructTransaction(
const AccountKeys& senderAccountKeys,
const std::vector<TransactionSourceEntry>& sources,
const std::vector<TransactionDestinationEntry>& destinations,
std::vector<uint8_t> extra, Transaction& transaction, uint64_t unlock_time, Crypto::SecretKey &tx_key, Logging::ILogger& log);
std::vector<uint8_t> extra, Transaction& transaction, uint64_t unlock_time, Crypto::SecretKey &tx_key, Logging::ILogger& log, bool overt = false);


bool is_out_to_acc(const AccountKeys& acc, const KeyOutput& out_key, const Crypto::PublicKey& tx_pub_key, size_t keyIndex);
Expand Down Expand Up @@ -127,4 +134,6 @@ Crypto::Hash get_tx_tree_hash(const std::vector<Crypto::Hash>& tx_hashes);
Crypto::Hash get_tx_tree_hash(const Block& b);
bool is_valid_decomposed_amount(uint64_t amount);

bool get_tx_proof(Crypto::Hash& txid, CryptoNote::AccountPublicAddress& address, Crypto::SecretKey& tx_key, std::string& sig_str, Logging::ILogger& log);

}
Loading