mirror of
https://github.com/oxen-io/oxen-core.git
synced 2023-12-14 02:22:56 +01:00
Blink synchronization
- Adds blink signature synchronization and storage through the regular p2p network - Adds wallet support (though this is still currently buggy and needs additional fixes - it sees the tx when it arrives in the mempool but isn't properly updating when the blink tx gets mined.)
This commit is contained in:
parent
ebb2bea452
commit
442f2182d2
18 changed files with 641 additions and 136 deletions
|
@ -1235,13 +1235,127 @@ namespace cryptonote
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
|
||||
{
|
||||
std::vector<cryptonote::blobdata> tx_blobs;
|
||||
tx_blobs.push_back(tx_blob);
|
||||
std::vector<tx_verification_context> tvcv(1);
|
||||
bool r = handle_incoming_txs(tx_blobs, tvcv, keeped_by_block, relayed, do_not_relay);
|
||||
bool r = handle_incoming_txs({{tx_blob}}, tvcv, keeped_by_block, relayed, do_not_relay);
|
||||
tvc = tvcv[0];
|
||||
return r;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_blinks(const std::vector<serializable_blink_metadata> &blinks, std::vector<crypto::hash> *bad_blinks, std::vector<crypto::hash> *missing_txs)
|
||||
{
|
||||
std::vector<uint8_t> store_blink(blinks.size(), false);
|
||||
size_t store_count = 0;
|
||||
// Step 1: figure out which referenced transactions we have and want blink info for (i.e. mined
|
||||
// but not immutable, or still in the mempool).
|
||||
{
|
||||
std::vector<crypto::hash> hashes;
|
||||
hashes.reserve(blinks.size());
|
||||
for (auto &bm : blinks)
|
||||
hashes.emplace_back(bm.tx_hash);
|
||||
|
||||
// If we don't take out this mempool lock here, before the blockchain_storage, we can deadlock
|
||||
// when we access the mempool later because it takes both locks in this order. TODO: make this
|
||||
// lock design stop sucking.
|
||||
CRITICAL_REGION_LOCAL(m_mempool);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain_storage);
|
||||
|
||||
auto tx_block_heights = m_blockchain_storage.get_transactions_heights(hashes);
|
||||
auto immutable_height = m_blockchain_storage.get_immutable_height();
|
||||
auto &db = m_blockchain_storage.get_db();
|
||||
for (size_t i = 0; i < blinks.size(); i++) {
|
||||
if (tx_block_heights[i])
|
||||
store_blink[i] = tx_block_heights[i] > immutable_height;
|
||||
else if (db.txpool_has_tx(hashes[i]))
|
||||
store_blink[i] = true;
|
||||
else if (missing_txs)
|
||||
missing_txs->emplace_back(hashes[i]);
|
||||
|
||||
if (store_blink[i])
|
||||
store_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!store_count) return true;
|
||||
|
||||
// Step 2: filter out any transactions for which we already have a blink signature
|
||||
{
|
||||
auto mempool_lock = m_mempool.blink_shared_lock();
|
||||
for (size_t i = 0; i < blinks.size(); i++)
|
||||
{
|
||||
if (store_blink[i] && m_mempool.get_blink(blinks[i].tx_hash, true /*have lock*/))
|
||||
{
|
||||
store_blink[i] = false; // Already have it, move along
|
||||
store_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!store_count) return true;
|
||||
|
||||
// Step 3: create new blink_tx objects for txes we want the blink signatures for, making sure
|
||||
// that all the given signature data is valid and that signatures validate. We can do all of
|
||||
// this without a lock.
|
||||
std::vector<std::shared_ptr<blink_tx>> new_blinks;
|
||||
new_blinks.reserve(store_count);
|
||||
std::unordered_map<uint64_t, std::shared_ptr<const service_nodes::quorum>> quorum_cache;
|
||||
bool bad = false;
|
||||
auto bad_blink = [&bad, bad_blinks](const crypto::hash &h, const char *what) {
|
||||
MINFO("Invalid blink tx " << h << ": " << what);
|
||||
bad = true;
|
||||
if (bad_blinks) bad_blinks->push_back(h);
|
||||
};
|
||||
for (size_t i = 0; i < blinks.size(); i++)
|
||||
{
|
||||
if (!store_blink[i])
|
||||
continue;
|
||||
auto &bdata = blinks[i];
|
||||
if (bdata.signature.size() != bdata.position.size() || bdata.signature.size() != bdata.quorum.size() ||
|
||||
bdata.signature.size() < service_nodes::BLINK_MIN_VOTES * tools::enum_count<blink_tx::subquorum> ||
|
||||
bdata.signature.size() > service_nodes::BLINK_SUBQUORUM_SIZE * tools::enum_count<blink_tx::subquorum> ||
|
||||
blink_tx::quorum_height(bdata.height, blink_tx::subquorum::base) == 0 ||
|
||||
!std::all_of(bdata.position.begin(), bdata.position.end(), [](const auto &p) { return p < service_nodes::BLINK_SUBQUORUM_SIZE; }) ||
|
||||
!std::all_of(bdata.quorum.begin(), bdata.quorum.end(), [](const auto &qi) { return qi < tools::enum_count<blink_tx::subquorum>; })
|
||||
) {
|
||||
bad_blink(bdata.tx_hash, "invalid signature data");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto blink_ptr = std::make_shared<blink_tx>(bdata.height, bdata.tx_hash);
|
||||
auto &blink = *blink_ptr;
|
||||
std::array<const std::vector<crypto::public_key> *, tools::enum_count<blink_tx::subquorum>> validators;
|
||||
for (uint8_t qi = 0; qi < tools::enum_count<blink_tx::subquorum>; qi++)
|
||||
{
|
||||
auto q_height = blink_tx::quorum_height(bdata.height, static_cast<blink_tx::subquorum>(qi));
|
||||
auto &q = quorum_cache[q_height];
|
||||
if (!q)
|
||||
q = get_quorum(service_nodes::quorum_type::blink, q_height);
|
||||
validators[qi] = &q->validators;
|
||||
}
|
||||
|
||||
try {
|
||||
for (size_t s = 0; s < bdata.signature.size(); s++)
|
||||
blink.add_signature(static_cast<blink_tx::subquorum>(bdata.quorum[s]), bdata.position[s], true /*approved*/, bdata.signature[s],
|
||||
validators[bdata.quorum[s]]->at(bdata.position[s]));
|
||||
} catch (const std::exception &e) {
|
||||
bad_blink(bdata.tx_hash, e.what());
|
||||
continue;
|
||||
}
|
||||
|
||||
new_blinks.push_back(std::move(blink_ptr));
|
||||
}
|
||||
|
||||
// Finally lock the blink pool and add all the blink signature data. It's possible that some
|
||||
// other thread got through the above loop before us and already added some of those, but that's
|
||||
// okay.
|
||||
{
|
||||
auto lock = m_mempool.blink_unique_lock();
|
||||
for (auto &b : new_blinks)
|
||||
m_mempool.add_existing_blink(std::move(b), true /*have lock*/);
|
||||
}
|
||||
|
||||
return !bad;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
std::future<std::pair<blink_result, std::string>> core::handle_blink_tx(const std::string &tx_blob)
|
||||
{
|
||||
|
@ -1516,7 +1630,7 @@ namespace cryptonote
|
|||
return m_service_node_list.handle_uptime_proof(proof, my_uptime_proof_confirmation);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::on_transaction_relayed(const cryptonote::blobdata& tx_blob)
|
||||
crypto::hash core::on_transaction_relayed(const cryptonote::blobdata& tx_blob)
|
||||
{
|
||||
std::vector<std::pair<crypto::hash, cryptonote::blobdata>> txs;
|
||||
cryptonote::transaction tx;
|
||||
|
@ -1524,10 +1638,11 @@ namespace cryptonote
|
|||
if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash))
|
||||
{
|
||||
LOG_ERROR("Failed to parse relayed transaction");
|
||||
return;
|
||||
return crypto::null_hash;
|
||||
}
|
||||
txs.push_back(std::make_pair(tx_hash, std::move(tx_blob)));
|
||||
m_mempool.set_relayed(txs);
|
||||
return tx_hash;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::relay_service_node_votes()
|
||||
|
|
|
@ -173,11 +173,36 @@ namespace cryptonote
|
|||
* @param keeped_by_block if the transactions have been in a block
|
||||
* @param relayed whether or not the transactions were relayed to us
|
||||
* @param do_not_relay whether to prevent the transactions from being relayed
|
||||
* @param blink_sigs the blink signature data that this tx arrived with, if any
|
||||
*
|
||||
* @return true if the transactions were accepted, false otherwise
|
||||
*/
|
||||
bool handle_incoming_txs(const std::vector<blobdata>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
|
||||
|
||||
/**
|
||||
* @brief handles received blink transaction signatures
|
||||
*
|
||||
* This takes a vector of blink transaction metadata (typically from a p2p peer), validates the
|
||||
* signatures, and (if valid) records the blink status. Blink transactions and signatures for
|
||||
* those transactions that are already mined beyond the immutability checkpoint are ignored.
|
||||
* Blink transactions that already have a set of valid signatures are similarly ignored (and
|
||||
* not revalidated).
|
||||
*
|
||||
* NB: This method is *not* used for partially signed blink transactions during the signing
|
||||
* process but rather only for valid, signed blinks.
|
||||
*
|
||||
* @param blinks vector of serializable_blink_metadata
|
||||
* @param bad_blinks optional pointer to vector in which to store hashes of any blink tx that
|
||||
* have invalid signature data (either invalid data, or a signature validation failure).
|
||||
* @param missing_txs optional pointer to vector in which to store any txes that were not found
|
||||
* on the blockchain or the mempool.
|
||||
*
|
||||
* @return true if there were no failures due to invalid signature data, false if there was one
|
||||
* or more. (Note that a true return does not indicate anything was added, and a false return
|
||||
* does not indicate that nothing was added).
|
||||
*/
|
||||
bool handle_incoming_blinks(const std::vector<serializable_blink_metadata> &blinks, std::vector<crypto::hash> *bad_blinks = nullptr, std::vector<crypto::hash> *missing_txs = nullptr);
|
||||
|
||||
/**
|
||||
* @brief handles an incoming blink transaction by dispatching it to the service node network
|
||||
* via quorumnet. If this node is not a service node this will start up quorumnet in
|
||||
|
@ -262,9 +287,10 @@ namespace cryptonote
|
|||
virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce);
|
||||
|
||||
/**
|
||||
* @brief called when a transaction is relayed
|
||||
* @brief called when a transaction is relayed; return the hash of the parsed tx, or null_hash
|
||||
* on parse failure.
|
||||
*/
|
||||
virtual void on_transaction_relayed(const cryptonote::blobdata& tx);
|
||||
virtual crypto::hash on_transaction_relayed(const cryptonote::blobdata& tx);
|
||||
|
||||
/**
|
||||
* @brief gets the miner instance
|
||||
|
@ -861,6 +887,13 @@ namespace cryptonote
|
|||
/// Time point at which the storage server and lokinet last pinged us
|
||||
std::atomic<time_t> m_last_storage_server_ping, m_last_lokinet_ping;
|
||||
|
||||
/**
|
||||
* @brief attempts to relay any transactions in the mempool which need it
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
bool relay_txpool_transactions();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
@ -978,13 +1011,6 @@ namespace cryptonote
|
|||
*/
|
||||
bool check_fork_time();
|
||||
|
||||
/**
|
||||
* @brief attempts to relay any transactions in the mempool which need it
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
bool relay_txpool_transactions();
|
||||
|
||||
/**
|
||||
* @brief checks DNS versions
|
||||
*
|
||||
|
|
|
@ -49,7 +49,7 @@ crypto::public_key blink_tx::get_sn_pubkey(subquorum q, int position, const serv
|
|||
auto blink_quorum = snl.get_quorum(quorum_type::blink, qheight);
|
||||
if (!blink_quorum) {
|
||||
// TODO FIXME XXX - we don't want a failure here; if this happens we need to go back into state
|
||||
// history to retrieve the state info.
|
||||
// history to retrieve the state info. (Or maybe this can't happen?)
|
||||
MERROR("FIXME: could not get blink quorum for blink_tx");
|
||||
return crypto::null_pkey;
|
||||
}
|
||||
|
@ -61,24 +61,35 @@ crypto::public_key blink_tx::get_sn_pubkey(subquorum q, int position, const serv
|
|||
};
|
||||
|
||||
crypto::hash blink_tx::hash(bool approved) const {
|
||||
crypto::hash tx_hash, blink_hash;
|
||||
if (!cryptonote::get_transaction_hash(tx, tx_hash))
|
||||
throw std::runtime_error("Cannot compute blink hash: tx hash is not valid");
|
||||
auto buf = tools::memcpy_le(height, tx_hash.data, uint8_t{approved});
|
||||
auto buf = tools::memcpy_le(height, get_txhash().data, uint8_t{approved});
|
||||
crypto::hash blink_hash;
|
||||
crypto::cn_fast_hash(buf.data(), buf.size(), blink_hash);
|
||||
return blink_hash;
|
||||
}
|
||||
|
||||
|
||||
bool blink_tx::add_signature(subquorum q, int position, bool approved, const crypto::signature &sig, const service_node_list &snl) {
|
||||
void blink_tx::limit_signatures(subquorum q, size_t max_size) {
|
||||
if (max_size > BLINK_SUBQUORUM_SIZE)
|
||||
throw std::domain_error("Internal error: too many potential blink signers!");
|
||||
else if (max_size < BLINK_SUBQUORUM_SIZE)
|
||||
for (size_t i = max_size; i < BLINK_SUBQUORUM_SIZE; i++)
|
||||
signatures_[static_cast<uint8_t>(q)][i].status = signature_status::rejected;
|
||||
}
|
||||
|
||||
bool blink_tx::add_signature(subquorum q, int position, bool approved, const crypto::signature &sig, const crypto::public_key &pubkey) {
|
||||
check_args(q, position, __func__);
|
||||
|
||||
if (!crypto::check_signature(hash(approved), get_sn_pubkey(q, position, snl), sig))
|
||||
if (!crypto::check_signature(hash(approved), pubkey, sig))
|
||||
throw signature_verification_error("Given blink quorum signature verification failed!");
|
||||
|
||||
return add_prechecked_signature(q, position, approved, sig);
|
||||
}
|
||||
|
||||
|
||||
bool blink_tx::add_signature(subquorum q, int position, bool approved, const crypto::signature &sig, const service_node_list &snl) {
|
||||
return add_signature(q, position, approved, sig, get_sn_pubkey(q, position, snl));
|
||||
}
|
||||
|
||||
bool blink_tx::add_prechecked_signature(subquorum q, int position, bool approved, const crypto::signature &sig) {
|
||||
check_args(q, position, __func__);
|
||||
|
||||
|
@ -110,4 +121,30 @@ bool blink_tx::rejected() const {
|
|||
});
|
||||
}
|
||||
|
||||
void blink_tx::fill_serialization_data(crypto::hash &tx_hash, uint64_t &height, std::vector<uint8_t> &quorum, std::vector<uint8_t> &position, std::vector<crypto::signature> &signature) const {
|
||||
tx_hash = get_txhash();
|
||||
height = this->height;
|
||||
constexpr size_t res_size = tools::enum_count<subquorum> * service_nodes::BLINK_SUBQUORUM_SIZE;
|
||||
quorum.reserve(res_size);
|
||||
position.reserve(res_size);
|
||||
signature.reserve(res_size);
|
||||
for (uint8_t qi = 0; qi < signatures_.size(); qi++) {
|
||||
for (uint8_t p = 0; p < signatures_[qi].size(); p++) {
|
||||
auto &sig = signatures_[qi][p];
|
||||
if (sig.status == signature_status::approved) {
|
||||
quorum.push_back(qi);
|
||||
position.push_back(p);
|
||||
signature.push_back(sig.sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crypto::hash blink_tx::tx_hash_visitor::operator()(const transaction &tx) const {
|
||||
crypto::hash h;
|
||||
if (!cryptonote::get_transaction_hash(tx, h))
|
||||
throw std::runtime_error("Failed to calculate transaction hash");
|
||||
return h;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,10 +52,19 @@ public:
|
|||
/// transaction was created.
|
||||
const uint64_t height;
|
||||
|
||||
/// The encapsulated transaction. Any modifications to this (including getting the tx_hash,
|
||||
/// which gets cached!) should either take place before the object is shared, or protected by
|
||||
/// the unique_lock.
|
||||
transaction tx;
|
||||
class tx_hash_visitor : public boost::static_visitor<crypto::hash> {
|
||||
public:
|
||||
crypto::hash operator()(const crypto::hash &h) const { return h; }
|
||||
crypto::hash operator()(const transaction &tx) const;
|
||||
};
|
||||
|
||||
/// The blink transaction *or* hash. The transaction is present when building a blink tx for
|
||||
/// blink quorum signing; for regular blink txes received via p2p this will contain the hash
|
||||
/// instead.
|
||||
boost::variant<transaction, crypto::hash> tx;
|
||||
|
||||
/// Returns the transaction hash
|
||||
crypto::hash get_txhash() const { return boost::apply_visitor(tx_hash_visitor{}, tx); }
|
||||
|
||||
class signature_verification_error : public std::runtime_error {
|
||||
using std::runtime_error::runtime_error;
|
||||
|
@ -64,13 +73,14 @@ public:
|
|||
// Not default constructible
|
||||
blink_tx() = delete;
|
||||
|
||||
/** Construct a new blink_tx from just a height; constructs a default transaction.
|
||||
*/
|
||||
explicit blink_tx(uint64_t height) : tx{}, height{height} {
|
||||
assert(quorum_height(subquorum::base) > 0);
|
||||
for (auto &q : signatures_)
|
||||
for (auto &s : q)
|
||||
s.status = signature_status::none;
|
||||
/// Construct a new blink_tx from just a height; constructs a default transaction.
|
||||
explicit blink_tx(uint64_t height) : height{height} {
|
||||
initialize();
|
||||
}
|
||||
|
||||
/// Construct a new blink_tx from a height and a hash
|
||||
explicit blink_tx(uint64_t height, const crypto::hash &txhash) : height{height}, tx{txhash} {
|
||||
initialize();
|
||||
}
|
||||
|
||||
/// Obtains a unique lock on this blink tx; required for any signature-mutating method unless
|
||||
|
@ -78,11 +88,32 @@ public:
|
|||
template <typename... Args>
|
||||
auto unique_lock(Args &&...args) { return std::unique_lock<std::shared_timed_mutex>{mutex_, std::forward<Args>(args)...}; }
|
||||
|
||||
/// Obtains a unique lock on this blink tx; required for any signature-dependent method unless
|
||||
/// Obtains a shared lock on this blink tx; required for any signature-dependent method unless
|
||||
/// otherwise noted
|
||||
template <typename... Args>
|
||||
auto shared_lock(Args &&...args) { return std::shared_lock<std::shared_timed_mutex>{mutex_, std::forward<Args>(args)...}; }
|
||||
|
||||
/**
|
||||
* Sets the maximum number of signatures for the given subquorum type, if the given size is less
|
||||
* than the ideal subquorum size. All signatures above the given count will be set to rejected.
|
||||
* Throws a std::domain_error if the given signatures count is too large.
|
||||
*
|
||||
* This should only be called immediately after construction (thus not needing a lock) and only
|
||||
* called (at most) once per subquorum.
|
||||
*
|
||||
* You can safely omit calling this if you only care about approvals; this only affects the
|
||||
* result of `rejected()`.
|
||||
*/
|
||||
void limit_signatures(subquorum q, size_t max_size);
|
||||
|
||||
/**
|
||||
* Adds a signature for the given quorum and position given an already-obtained blink subquorum
|
||||
* validator pubkey. Returns true if the signature was accepted and stored, false if a
|
||||
* signature was already present for the given quorum and position. Throws a
|
||||
* `blink_tx::signature_verification_error` if the signature fails validation.
|
||||
*/
|
||||
bool add_signature(subquorum q, int position, bool approved, const crypto::signature &sig, const crypto::public_key &pubkey);
|
||||
|
||||
/**
|
||||
* Adds a signature for the given quorum and position. Returns false if a signature was already
|
||||
* present; true if the signature was accepted and stored; and throws a
|
||||
|
@ -105,15 +136,14 @@ public:
|
|||
/**
|
||||
* Returns true if this blink tx is valid for inclusion in the blockchain, that is, has the
|
||||
* required number of approval signatures in each quorum. (Note that it is possible for a blink
|
||||
* tx to be neither approved() nor rejected()). You must hold a shared_lock when calling this.
|
||||
* tx to be neither approved() nor rejected()).
|
||||
*/
|
||||
bool approved() const;
|
||||
|
||||
/**
|
||||
* Returns true if this blink tx has been definitively rejected, that is, has enough rejection
|
||||
* signatures in at least one of the quorums that it is impossible for it to become approved().
|
||||
* (Note that it is possible for a blink tx to be neither approved() nor rejected()). You must
|
||||
* hold a shared_lock when calling this.
|
||||
* (Note that it is possible for a blink tx to be neither approved() nor rejected()).
|
||||
*/
|
||||
bool rejected() const;
|
||||
|
||||
|
@ -142,7 +172,23 @@ public:
|
|||
crypto::signature sig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fills the given blink serialization struct with the signature data. This is designed to work
|
||||
* directly with the components of a serializable_blink_metadata (but we don't want to have to
|
||||
* link to cryptonote_protocol where that is defined).
|
||||
*
|
||||
* A shared lock should be held by the caller.
|
||||
*/
|
||||
void fill_serialization_data(crypto::hash &tx_hash, uint64_t &height, std::vector<uint8_t> &quorum, std::vector<uint8_t> &position, std::vector<crypto::signature> &signature) const;
|
||||
|
||||
private:
|
||||
void initialize() {
|
||||
assert(quorum_height(subquorum::base) > 0);
|
||||
for (auto &q : signatures_)
|
||||
for (auto &s : q)
|
||||
s.status = signature_status::none;
|
||||
}
|
||||
|
||||
std::array<std::array<quorum_signature, service_nodes::BLINK_SUBQUORUM_SIZE>, tools::enum_count<subquorum>> signatures_;
|
||||
std::shared_timed_mutex mutex_;
|
||||
};
|
||||
|
|
|
@ -439,35 +439,74 @@ namespace cryptonote
|
|||
return add_tx(tx, h, bl, get_transaction_weight(tx, bl.size()), tvc, keeped_by_block, relayed, do_not_relay, version);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::add_blink(const std::shared_ptr<blink_tx> &blink_ptr, tx_verification_context &tvc, bool &blink_exists)
|
||||
bool tx_memory_pool::add_new_blink(const std::shared_ptr<blink_tx> &blink_ptr, tx_verification_context &tvc, bool &blink_exists)
|
||||
{
|
||||
assert((bool) blink_ptr);
|
||||
std::unique_lock<std::shared_timed_mutex> lock(m_blinks_mutex);
|
||||
auto lock = blink_unique_lock();
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
auto &tx = blink_ptr->tx;
|
||||
auto &blink = *blink_ptr;
|
||||
auto &tx = boost::get<transaction>(blink.tx); // will throw if just a hash w/o a transaction
|
||||
auto txhash = get_transaction_hash(tx);
|
||||
auto &ptr = m_blinks[txhash];
|
||||
blink_exists = (bool) ptr;
|
||||
|
||||
blink_exists = m_blinks.count(txhash);
|
||||
if (blink_exists)
|
||||
return false;
|
||||
ptr = blink_ptr;
|
||||
auto &blink = *ptr;
|
||||
|
||||
bool approved = blink.approved();
|
||||
auto hf_version = m_blockchain.get_ideal_hard_fork_version(blink.height);
|
||||
bool ret = add_tx(tx, tvc, false /*kept_by_block*/, false /*relayed*/, true /*do_not_relay*/, hf_version);
|
||||
if (!ret)
|
||||
m_blinks.erase(txhash);
|
||||
return ret;
|
||||
bool do_not_relay = !approved; // Only relay signed blinks
|
||||
bool result = add_tx(tx, tvc, false /*kept_by_block*/, false /*relayed*/, do_not_relay, hf_version);
|
||||
if (result && approved)
|
||||
m_blinks[txhash] = blink_ptr;
|
||||
return result;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
std::shared_ptr<blink_tx> tx_memory_pool::get_blink(const crypto::hash &tx_hash) const
|
||||
bool tx_memory_pool::add_existing_blink(std::shared_ptr<blink_tx> blink_ptr, bool have_lock)
|
||||
{
|
||||
std::shared_lock<std::shared_timed_mutex> lock(m_blinks_mutex);
|
||||
assert(blink_ptr && blink_ptr->approved());
|
||||
auto lock = have_lock ? blink_unique_lock(std::defer_lock) : blink_unique_lock();
|
||||
|
||||
auto &ptr = m_blinks[blink_ptr->get_txhash()];
|
||||
if (ptr)
|
||||
return false;
|
||||
|
||||
ptr = blink_ptr;
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
std::shared_ptr<blink_tx> tx_memory_pool::get_blink(const crypto::hash &tx_hash, bool have_lock) const
|
||||
{
|
||||
auto lock = have_lock ? blink_shared_lock(std::defer_lock) : blink_shared_lock();
|
||||
auto it = m_blinks.find(tx_hash);
|
||||
if (it != m_blinks.end())
|
||||
return it->second;
|
||||
return {};
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::has_blink(const crypto::hash &tx_hash, bool have_lock) const
|
||||
{
|
||||
auto lock = have_lock ? blink_shared_lock(std::defer_lock) : blink_shared_lock();
|
||||
return m_blinks.find(tx_hash) != m_blinks.end();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::add_missing_blink_hashes(const std::map<uint64_t, std::vector<crypto::hash>> &from)
|
||||
{
|
||||
uint64_t immutable_height = m_blockchain.get_immutable_height();
|
||||
|
||||
std::unique_lock<std::shared_timed_mutex> lock(m_blinks_mutex);
|
||||
for (const auto &h_txes : from) {
|
||||
if (h_txes.first <= immutable_height)
|
||||
continue;
|
||||
for (const auto &hash : h_txes.second) {
|
||||
if (!m_blinks.count(hash)) {
|
||||
auto &h = m_missing_blinks[hash];
|
||||
if (h_txes.first > h)
|
||||
h = h_txes.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
size_t tx_memory_pool::get_txpool_weight() const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
|
@ -780,7 +819,7 @@ namespace cryptonote
|
|||
const uint64_t now = time(NULL);
|
||||
txs.reserve(m_blockchain.get_txpool_tx_count());
|
||||
m_blockchain.for_all_txpool_txes([this, now, &txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *){
|
||||
if(!meta.do_not_relay && now - meta.last_relayed_time > get_relay_delay(now, meta.receive_time))
|
||||
if(!meta.do_not_relay && (!meta.relayed || now - meta.last_relayed_time > get_relay_delay(now, meta.receive_time)))
|
||||
{
|
||||
// if the tx is older than half the max lifetime, we don't re-relay it, to avoid a problem
|
||||
// mentioned by smooth where nodes would flush txes at slightly different times, causing
|
||||
|
@ -827,22 +866,46 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
int tx_memory_pool::set_relayable(const std::vector<crypto::hash> &tx_hashes) {
|
||||
int updated = 0;
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
LockedTXN lock(m_blockchain);
|
||||
for (auto &tx : tx_hashes)
|
||||
{
|
||||
try {
|
||||
txpool_tx_meta_t meta;
|
||||
if (m_blockchain.get_txpool_tx_meta(tx, meta) && meta.do_not_relay)
|
||||
{
|
||||
meta.do_not_relay = false;
|
||||
m_blockchain.update_txpool_tx(tx, meta);
|
||||
++updated;
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
MERROR("Failed to upate txpool transaction metadata: " << e.what());
|
||||
}
|
||||
}
|
||||
lock.commit();
|
||||
|
||||
return updated;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::set_relayed(const std::vector<std::pair<crypto::hash, cryptonote::blobdata>> &txs)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
const time_t now = time(NULL);
|
||||
LockedTXN lock(m_blockchain);
|
||||
for (auto it = txs.begin(); it != txs.end(); ++it)
|
||||
for (auto &tx : txs)
|
||||
{
|
||||
try
|
||||
{
|
||||
txpool_tx_meta_t meta;
|
||||
if (m_blockchain.get_txpool_tx_meta(it->first, meta))
|
||||
if (m_blockchain.get_txpool_tx_meta(tx.first, meta))
|
||||
{
|
||||
meta.relayed = true;
|
||||
meta.last_relayed_time = now;
|
||||
m_blockchain.update_txpool_tx(it->first, meta);
|
||||
m_blockchain.update_txpool_tx(tx.first, meta);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
|
@ -1217,12 +1280,22 @@ namespace cryptonote
|
|||
m_parsed_tx_cache.clear();
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
std::vector<uint8_t> tx_memory_pool::have_txs(const std::vector<crypto::hash> &hashes) const
|
||||
{
|
||||
std::vector<uint8_t> result(hashes.size(), false);
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
auto &db = m_blockchain.get_db();
|
||||
for (size_t i = 0; i < hashes.size(); i++)
|
||||
result[i] = db.txpool_has_tx(hashes[i]);
|
||||
|
||||
return result;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx(const crypto::hash &id) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
return m_blockchain.get_db().txpool_has_tx(id);
|
||||
return have_txs({{id}})[0];
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx) const
|
||||
|
|
|
@ -130,23 +130,74 @@ namespace cryptonote
|
|||
bool add_tx(transaction &tx, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version);
|
||||
|
||||
/**
|
||||
* @brief attempts to add a blink transaction to the transaction pool and blink pool. The
|
||||
* transaction is set for relaying if it has the required blink signatures, and not relayed
|
||||
* otherwise.
|
||||
* @brief attempts to add a blink transaction to the transaction pool.
|
||||
*
|
||||
* This is only for use for new transactions that should not exist yet on the chain or mempool
|
||||
* (and will fail if already does). See `add_existing_blink` instead to add blink data about a
|
||||
* transaction that already exists. This is only meant to be called during the SN blink signing
|
||||
* phase (and requires that the `tx` transaction be properly set to a full transaction);
|
||||
* ordinary nodes receiving a blink tx from the network should be going through
|
||||
* core.handle_incoming_blinks instead.
|
||||
*
|
||||
* Whether or not the transaction is added to the known blinks or marked for relaying depends on
|
||||
* whether the passed-in transaction has an `.approved()` status: if it does, the transaction is
|
||||
* set for relaying and added to the active blinks immediately; otherwise it is not added to the
|
||||
* known blinks and will not be relayed.
|
||||
*
|
||||
* The transaction is *not* added to the known blinks or marked for relaying unless it is passed
|
||||
* in with an `.approved()` status.
|
||||
*
|
||||
* @param blink - a shared_ptr to the blink details
|
||||
* @param tvc - the verification results
|
||||
* @param blink_exists - will be set to true if the addition fails because the blink tx already
|
||||
* exists
|
||||
*
|
||||
* @return true if the tx passes validations and has been added to tx/blink pools
|
||||
* @return true if the tx passes validations and has been added to the tx pool.
|
||||
*/
|
||||
bool add_blink(const std::shared_ptr<blink_tx> &blink, tx_verification_context& tvc, bool &blink_exists);
|
||||
bool add_new_blink(const std::shared_ptr<blink_tx> &blink, tx_verification_context& tvc, bool &blink_exists);
|
||||
|
||||
/**
|
||||
* @brief accesses blink tx details if the given tx hash is a known blink tx, nullptr otherwise.
|
||||
* @brief attempts to add blink transaction information about an existing blink transaction
|
||||
*
|
||||
* This method takes an approved blink_tx and records it in the known blinks data. No check is
|
||||
* done that the transaction actually exists on the blockchain or mempool. It is assumed that
|
||||
* the given shared_ptr is a new blink that is not yet shared between threads (and thus doesn't
|
||||
* need locking): sharing is expected only after it is added to the blinks via this method.
|
||||
*
|
||||
* NB: this function assumes that the given blink tx is valid and approved but does *not* check
|
||||
* it (except when compiling in debug mode).
|
||||
*
|
||||
* @param blink the blink_tx shared_ptr
|
||||
* @param have_lock can be specified as true to avoid taking out a unique lock on the blinks
|
||||
* data structure; it should only be specified if a unique lock on the blink data is already
|
||||
* held externally, i.e. by obtaining a lock with `blink_unique_lock`.
|
||||
*
|
||||
* @return true if the blink data was recorded, false if the given tx was already known.
|
||||
*/
|
||||
std::shared_ptr<blink_tx> get_blink(const crypto::hash &tx_hash) const;
|
||||
bool add_existing_blink(std::shared_ptr<blink_tx> blink, bool have_lock = false);
|
||||
|
||||
/**
|
||||
* @brief accesses blink tx details if the given tx hash is a known, approved blink tx, nullptr
|
||||
* otherwise.
|
||||
*
|
||||
* @param tx_hash the hash of the tx to access
|
||||
* @param have_lock can be specified as true to avoid taking out a shared lock; it should only
|
||||
* be specified if a shared lock on the blink data is already held externally.
|
||||
*/
|
||||
std::shared_ptr<blink_tx> get_blink(const crypto::hash &tx_hash, bool have_lock = false) const;
|
||||
|
||||
/**
|
||||
* Equivalent to `(bool) get_blink(...)`, but slightly more efficient when the blink information
|
||||
* isn't actually needed beyond an existance test (as it avoids copying the shared_ptr).
|
||||
*/
|
||||
bool has_blink(const crypto::hash &tx_hash, bool have_lock = false) const;
|
||||
|
||||
/**
|
||||
* @brief takes a map of blink { height -> [tx_hashes] } and records any that we don't already
|
||||
* know about (and are not before the immutable height) in the internal "m_want_blinks" to
|
||||
* request from p2p peers.
|
||||
*/
|
||||
void add_missing_blink_hashes(const std::map<uint64_t, std::vector<crypto::hash>> &potential);
|
||||
|
||||
/**
|
||||
* @brief takes a transaction with the given hash from the pool
|
||||
|
@ -173,6 +224,16 @@ namespace cryptonote
|
|||
*/
|
||||
bool have_tx(const crypto::hash &id) const;
|
||||
|
||||
/**
|
||||
* @brief determines whether the given tx hashes are in the mempool
|
||||
*
|
||||
* @param hashes vector of tx hashes
|
||||
*
|
||||
* @return vector of the same size as `hashes` of true (1) or false (0) values. (Not using
|
||||
* std::vector<bool> because it is broken by design).
|
||||
*/
|
||||
std::vector<uint8_t> have_txs(const std::vector<crypto::hash> &hashes) const;
|
||||
|
||||
/**
|
||||
* @brief action to take when notified of a block added to the blockchain
|
||||
*
|
||||
|
@ -210,6 +271,19 @@ namespace cryptonote
|
|||
*/
|
||||
void unlock() const;
|
||||
|
||||
/**
|
||||
* @brief obtains a unique lock on the approved blink tx pool
|
||||
*/
|
||||
template <typename... Args>
|
||||
auto blink_unique_lock(Args &&...args) const { return std::unique_lock<std::shared_timed_mutex>{m_blinks_mutex, std::forward<Args>(args)...}; }
|
||||
|
||||
/**
|
||||
* @brief obtains a shared lock on the approved blink tx pool
|
||||
*/
|
||||
template <typename... Args>
|
||||
auto blink_shared_lock(Args &&...args) const { return std::shared_lock<std::shared_timed_mutex>{m_blinks_mutex, std::forward<Args>(args)...}; }
|
||||
|
||||
|
||||
// load/store operations
|
||||
|
||||
/**
|
||||
|
@ -343,6 +417,16 @@ namespace cryptonote
|
|||
*/
|
||||
bool get_relayable_transactions(std::vector<std::pair<crypto::hash, cryptonote::blobdata>>& txs) const;
|
||||
|
||||
/**
|
||||
* @brief clear transactions' `do_not_relay` flags (if set) so that they can start being
|
||||
* relayed. (Note that it still must satisfy the other conditions of
|
||||
* `get_relayable_transactions` to actually be relayable).
|
||||
*
|
||||
* @return the number of txes that were found with an active `do_not_relay` flag that was
|
||||
* cleared.
|
||||
*/
|
||||
int set_relayable(const std::vector<crypto::hash> &tx_hashes);
|
||||
|
||||
/**
|
||||
* @brief tell the pool that certain transactions were just relayed
|
||||
*
|
||||
|
@ -598,9 +682,15 @@ namespace cryptonote
|
|||
std::unordered_map<crypto::hash, transaction> m_parsed_tx_cache;
|
||||
|
||||
mutable std::shared_timed_mutex m_blinks_mutex;
|
||||
// { height => { txhash => blink_tx, ... }, ... }
|
||||
|
||||
// Contains blink metadata for approved blink transactions. { txhash => blink_tx, ... }.
|
||||
std::unordered_map<crypto::hash, std::shared_ptr<cryptonote::blink_tx>> m_blinks;
|
||||
// TODO: clean up m_blinks once mined & immutably checkpointed
|
||||
|
||||
// Contains blink hashes that we don't have but have been told about by another node. (The
|
||||
// height is stored here for cleanup purposes).
|
||||
std::unordered_map<crypto::hash, uint64_t> m_missing_blinks;
|
||||
|
||||
// TODO: clean up m_blinks and m_missing_blinks once mined & immutably checkpointed
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -135,6 +135,21 @@ namespace cryptonote
|
|||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct serializable_blink_metadata {
|
||||
crypto::hash tx_hash;
|
||||
uint64_t height;
|
||||
std::vector<uint8_t> quorum;
|
||||
std::vector<uint8_t> position;
|
||||
std::vector<crypto::signature> signature;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_N(tx_hash, "#")
|
||||
KV_SERIALIZE_N(height, "h")
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(quorum, "q")
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(position, "p")
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(signature, "s")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
@ -144,11 +159,13 @@ namespace cryptonote
|
|||
|
||||
struct request_t
|
||||
{
|
||||
std::vector<blobdata> txs;
|
||||
std::vector<blobdata> txs;
|
||||
std::vector<serializable_blink_metadata> blinks;
|
||||
std::string _; // padding
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(txs)
|
||||
KV_SERIALIZE(blinks)
|
||||
KV_SERIALIZE(_)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
@ -183,13 +200,15 @@ namespace cryptonote
|
|||
std::vector<blobdata> txs;
|
||||
std::vector<block_complete_entry> blocks;
|
||||
std::vector<crypto::hash> missed_ids;
|
||||
uint64_t current_blockchain_height;
|
||||
uint64_t current_blockchain_height;
|
||||
std::vector<serializable_blink_metadata> blinks;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(txs)
|
||||
KV_SERIALIZE(blocks)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missed_ids)
|
||||
KV_SERIALIZE(current_blockchain_height)
|
||||
KV_SERIALIZE(blinks)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
@ -198,11 +217,21 @@ namespace cryptonote
|
|||
|
||||
struct CORE_SYNC_DATA
|
||||
{
|
||||
struct blink_sync_data {
|
||||
uint64_t height;
|
||||
std::vector<crypto::hash> hashes;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(height)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(hashes)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
uint64_t current_height;
|
||||
uint64_t cumulative_difficulty;
|
||||
crypto::hash top_id;
|
||||
uint8_t top_version;
|
||||
uint32_t pruning_seed;
|
||||
std::vector<blink_sync_data> blink_txs;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(current_height)
|
||||
|
@ -210,6 +239,7 @@ namespace cryptonote
|
|||
KV_SERIALIZE_VAL_POD_AS_BLOB(top_id)
|
||||
KV_SERIALIZE_OPT(top_version, (uint8_t)0)
|
||||
KV_SERIALIZE_OPT(pruning_seed, (uint32_t)0)
|
||||
KV_SERIALIZE(blink_txs)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace cryptonote
|
|||
bool deinit();
|
||||
void set_p2p_endpoint(nodetool::i_p2p_endpoint<connection_context>* p2p);
|
||||
//bool process_handshake_data(const blobdata& data, cryptonote_connection_context& context);
|
||||
bool process_payload_sync_data(const CORE_SYNC_DATA& hshd, cryptonote_connection_context& context, bool is_inital);
|
||||
bool process_payload_sync_data(CORE_SYNC_DATA&& hshd, cryptonote_connection_context& context, bool is_inital);
|
||||
bool get_payload_sync_data(blobdata& data);
|
||||
bool get_payload_sync_data(CORE_SYNC_DATA& hshd);
|
||||
bool get_stat_info(core_stat_info& stat_inf);
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "profile_tools.h"
|
||||
#include "net/network_throttle-detail.hpp"
|
||||
#include "common/pruning.h"
|
||||
#include "common/random.h"
|
||||
|
||||
#undef LOKI_DEFAULT_LOG_CATEGORY
|
||||
#define LOKI_DEFAULT_LOG_CATEGORY "net.cn"
|
||||
|
@ -296,7 +297,7 @@ namespace cryptonote
|
|||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_cryptonote_protocol_handler<t_core>::process_payload_sync_data(const CORE_SYNC_DATA& hshd, cryptonote_connection_context& context, bool is_inital)
|
||||
bool t_cryptonote_protocol_handler<t_core>::process_payload_sync_data(CORE_SYNC_DATA&& hshd, cryptonote_connection_context& context, bool is_inital)
|
||||
{
|
||||
if(context.m_state == cryptonote_connection_context::state_before_handshake && !is_inital)
|
||||
return true;
|
||||
|
@ -336,6 +337,32 @@ namespace cryptonote
|
|||
LOG_INFO_CC(context, "New connection posing as pruning seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) << ", seed address " << &context.m_pruning_seed);
|
||||
#endif
|
||||
|
||||
// Check for any blink txes being advertised that we don't know about
|
||||
{
|
||||
// Do this in two passes: first pass just validates and quits on failure
|
||||
uint64_t last_height = 0;
|
||||
for (auto &b : hshd.blink_txs) {
|
||||
if (b.height > last_height) {
|
||||
last_height = b.height;
|
||||
} else {
|
||||
MWARNING(context << " peer sent blink tx heights out of order, which is not valid; disconnecting");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (b.hashes.empty()) {
|
||||
MWARNING(context << " peer sent invalid blink tx hash data, disconnecting");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// { height -> [hash, ...], ... }, extracted from the serialized [height, ...], [[hash, ...], ...] vector pair.
|
||||
std::map<uint64_t, std::vector<crypto::hash>> blink_hashes;
|
||||
for (auto &b : hshd.blink_txs)
|
||||
blink_hashes.emplace_hint(blink_hashes.end(), b.height, std::move(b.hashes));
|
||||
|
||||
m_core.get_pool().add_missing_blink_hashes(blink_hashes);
|
||||
}
|
||||
|
||||
uint64_t target = m_core.get_target_blockchain_height();
|
||||
if (target == 0)
|
||||
target = m_core.get_current_blockchain_height();
|
||||
|
@ -896,7 +923,7 @@ namespace cryptonote
|
|||
template<class t_core>
|
||||
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& context)
|
||||
{
|
||||
MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes)");
|
||||
MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes w/ " << arg.blinks.size() << " blinks)");
|
||||
for (const auto &blob: arg.txs)
|
||||
MLOGIF_P2P_MESSAGE(cryptonote::transaction tx; crypto::hash hash; bool ret = cryptonote::parse_and_validate_tx_from_blob(blob, tx, hash);, ret, "Including transaction " << hash);
|
||||
|
||||
|
@ -914,27 +941,32 @@ namespace cryptonote
|
|||
|
||||
std::vector<cryptonote::blobdata> newtxs;
|
||||
newtxs.reserve(arg.txs.size());
|
||||
std::vector<tx_verification_context> tvcs;
|
||||
bool all_okay = m_core.handle_incoming_txs(arg.txs, tvcs, false /*kept by block*/, true /*relayed*/, false /*do not relay*/);
|
||||
|
||||
// If !all_okay we want to drop the connection, but we may still have added some incoming txs
|
||||
// and so still need to finish handling/relaying them
|
||||
for (size_t i = 0; i < arg.txs.size(); ++i)
|
||||
{
|
||||
cryptonote::tx_verification_context tvc{};
|
||||
m_core.handle_incoming_tx(arg.txs[i], tvc, false, true, false);
|
||||
if(tvc.m_verifivation_failed)
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L1("Tx verification failed, dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
return 1;
|
||||
}
|
||||
if(tvc.m_should_be_relayed)
|
||||
if (tvcs[i].m_should_be_relayed)
|
||||
newtxs.push_back(std::move(arg.txs[i]));
|
||||
}
|
||||
arg.txs = std::move(newtxs);
|
||||
|
||||
bool good_blinks = m_core.handle_incoming_blinks(arg.blinks);
|
||||
|
||||
if(arg.txs.size())
|
||||
{
|
||||
//TODO: add announce usage here
|
||||
relay_transactions(arg, context);
|
||||
}
|
||||
|
||||
if (!all_okay || !good_blinks)
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L1((!all_okay && !good_blinks ? "Tx and Blink" : !all_okay ? "Tx" : "Blink") << " verification(s) failed, dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
|
@ -2245,11 +2277,34 @@ skip:
|
|||
if (hide_tx_broadcast)
|
||||
MDEBUG("Attempting to conceal origin of tx via anonymity network connection(s)");
|
||||
|
||||
// no check for success, so tell core they're relayed unconditionally
|
||||
const bool pad_transactions = m_core.pad_transactions() || hide_tx_broadcast;
|
||||
for(auto tx_blob_it = arg.txs.begin(); tx_blob_it!=arg.txs.end(); ++tx_blob_it)
|
||||
|
||||
// no check for success, so tell core they're relayed unconditionally and snag a copy of the
|
||||
// hash so that we can look up any associated blink data we should include.
|
||||
std::vector<crypto::hash> relayed_txes;
|
||||
relayed_txes.reserve(arg.txs.size());
|
||||
for (auto &tx_blob : arg.txs)
|
||||
relayed_txes.push_back(
|
||||
m_core.on_transaction_relayed(tx_blob)
|
||||
);
|
||||
|
||||
// Rebuild arg.blinks from blink data that we have because we don't necessarily have the same
|
||||
// blink data that got sent to us (we may have additional blink info, or may have rejected some
|
||||
// of the incoming blink data).
|
||||
arg.blinks.clear();
|
||||
{
|
||||
m_core.on_transaction_relayed(*tx_blob_it);
|
||||
auto &pool = m_core.get_pool();
|
||||
auto lock = pool.blink_shared_lock();
|
||||
for (auto &hash : relayed_txes)
|
||||
{
|
||||
if (auto blink = pool.get_blink(hash))
|
||||
{
|
||||
arg.blinks.emplace_back();
|
||||
auto &data = arg.blinks.back();
|
||||
auto l = blink->shared_lock();
|
||||
blink->fill_serialization_data(data.tx_hash, data.height, data.quorum, data.position, data.signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pad_transactions)
|
||||
|
@ -2266,7 +2321,7 @@ skip:
|
|||
const bool broadcast_to_peer =
|
||||
peer_id &&
|
||||
(hide_tx_broadcast != bool(current_zone == epee::net_utils::zone::public_)) &&
|
||||
exclude_context.m_connection_id != context.m_connection_id;
|
||||
exclude_context.m_connection_id != context.m_connection_id;
|
||||
|
||||
if (broadcast_to_peer)
|
||||
connections.push_back({current_zone, context.m_connection_id});
|
||||
|
|
|
@ -615,12 +615,13 @@ std::string debug_known_signatures(blink_tx &btx, quorum_array &blink_quorums) {
|
|||
|
||||
/// Processes blink signatures; called immediately upon receiving a signature if we know about the
|
||||
/// tx; otherwise signatures are stored until we learn about the tx and then processed.
|
||||
void process_blink_signatures(SNNWrapper &snw, blink_tx &btx, quorum_array &blink_quorums, uint64_t quorum_checksum, std::list<pending_signature> &&signatures,
|
||||
void process_blink_signatures(SNNWrapper &snw, const std::shared_ptr<blink_tx> &btxptr, quorum_array &blink_quorums, uint64_t quorum_checksum, std::list<pending_signature> &&signatures,
|
||||
uint64_t reply_tag, // > 0 if we are expected to send a status update if it becomes accepted/rejected
|
||||
const std::string reply_pubkey, // who we are supposed to send the status update to
|
||||
const std::string &received_from = ""s /* x25519 of the peer that sent this, if available (to avoid trying to pointlessly relay back to them) */) {
|
||||
|
||||
bool already_approved = false, already_rejected = false;
|
||||
auto &btx = *btxptr;
|
||||
|
||||
// First check values and discard any signatures for positions we already have.
|
||||
{
|
||||
auto lock = btx.shared_lock(); // Don't take out a heavier unique lock until later when we are sure we need
|
||||
|
@ -644,9 +645,6 @@ void process_blink_signatures(SNNWrapper &snw, blink_tx &btx, quorum_array &blin
|
|||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
already_approved = btx.approved();
|
||||
already_rejected = btx.rejected();
|
||||
}
|
||||
if (signatures.empty())
|
||||
return;
|
||||
|
@ -673,10 +671,13 @@ void process_blink_signatures(SNNWrapper &snw, blink_tx &btx, quorum_array &blin
|
|||
if (signatures.empty())
|
||||
return;
|
||||
|
||||
bool now_approved = already_approved, now_rejected = already_rejected;
|
||||
bool became_approved = false, became_rejected = false;
|
||||
{
|
||||
auto lock = btx.unique_lock();
|
||||
|
||||
bool already_approved = btx.approved(),
|
||||
already_rejected = !already_approved && btx.rejected();
|
||||
|
||||
MTRACE("Before recording new signatures I have existing signatures: " << debug_known_signatures(btx, blink_quorums));
|
||||
|
||||
// Now actually add them (and do one last check on them)
|
||||
|
@ -691,7 +692,7 @@ void process_blink_signatures(SNNWrapper &snw, blink_tx &btx, quorum_array &blin
|
|||
auto &validators = blink_quorums[qi]->validators;
|
||||
|
||||
if (btx.add_prechecked_signature(subquorum, position, approval, signature)) {
|
||||
MDEBUG("Validated and stored " << (approval ? "approval" : "rejection") << " signature for tx " << btx.tx.hash << ", subquorum " << int{qi} << ", position " << position);
|
||||
MDEBUG("Validated and stored " << (approval ? "approval" : "rejection") << " signature for tx " << btx.get_txhash() << ", subquorum " << int{qi} << ", position " << position);
|
||||
++it;
|
||||
}
|
||||
else {
|
||||
|
@ -702,12 +703,26 @@ void process_blink_signatures(SNNWrapper &snw, blink_tx &btx, quorum_array &blin
|
|||
}
|
||||
|
||||
if (!signatures.empty()) {
|
||||
now_approved = btx.approved();
|
||||
now_rejected = btx.rejected();
|
||||
MDEBUG("Updated signatures; now have signatures: " << debug_known_signatures(btx, blink_quorums));
|
||||
|
||||
if (!already_approved && !already_rejected) {
|
||||
if (btx.approved()) {
|
||||
became_approved = true;
|
||||
} else if (btx.rejected()) {
|
||||
became_rejected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (became_approved) {
|
||||
MINFO("Accumulated enough signatures for blink tx: enabling tx relay");
|
||||
auto &pool = snw.core.get_pool();
|
||||
pool.add_existing_blink(btxptr);
|
||||
pool.set_relayable({{btx.get_txhash()}});
|
||||
snw.core.relay_txpool_transactions();
|
||||
}
|
||||
|
||||
if (signatures.empty())
|
||||
return;
|
||||
|
||||
|
@ -735,7 +750,7 @@ void process_blink_signatures(SNNWrapper &snw, blink_tx &btx, quorum_array &blin
|
|||
|
||||
bt_dict blink_sign_data{
|
||||
{"h", btx.height},
|
||||
{"#", get_data_as_string(btx.tx.hash)},
|
||||
{"#", get_data_as_string(btx.get_txhash())},
|
||||
{"q", quorum_checksum},
|
||||
{"i", std::move(i_list)},
|
||||
{"p", std::move(p_list)},
|
||||
|
@ -748,11 +763,11 @@ void process_blink_signatures(SNNWrapper &snw, blink_tx &btx, quorum_array &blin
|
|||
MTRACE("Done blink signature relay");
|
||||
|
||||
if (reply_tag && !reply_pubkey.empty()) {
|
||||
if (now_approved && !already_approved) {
|
||||
MINFO("Blink tx is now approved; sending result back to originating node");
|
||||
if (became_approved) {
|
||||
MINFO("Blink tx became approved; sending result back to originating node");
|
||||
snw.snn.send(reply_pubkey, "bl_good", bt_dict{{"!", reply_tag}}, send_option::optional{});
|
||||
} else if (now_rejected && !already_rejected) {
|
||||
MINFO("Blink tx is now rejected; sending result back to originating node");
|
||||
} else if (became_rejected) {
|
||||
MINFO("Blink tx became rejected; sending result back to originating node");
|
||||
snw.snn.send(reply_pubkey, "bl_bad", bt_dict{{"!", reply_tag}}, send_option::optional{});
|
||||
}
|
||||
}
|
||||
|
@ -868,9 +883,6 @@ void handle_blink(SNNetwork::message &m, void *self) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto btxptr = std::make_shared<blink_tx>(blink_height);
|
||||
auto &btx = *btxptr;
|
||||
|
||||
quorum_array blink_quorums;
|
||||
uint64_t checksum = get_int<uint64_t>(data.at("q"));
|
||||
try {
|
||||
|
@ -895,9 +907,17 @@ void handle_blink(SNNetwork::message &m, void *self) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto btxptr = std::make_shared<blink_tx>(blink_height);
|
||||
auto &btx = *btxptr;
|
||||
auto &tx = boost::get<cryptonote::transaction>(btx.tx);
|
||||
// If any quorums are too small set the extra spaces to rejected (this also checks that no
|
||||
// quorums are too big).
|
||||
for (size_t qi = 0; qi < blink_quorums.size(); qi++)
|
||||
btx.limit_signatures(static_cast<blink_tx::subquorum>(qi), blink_quorums[qi]->validators.size());
|
||||
|
||||
{
|
||||
crypto::hash tx_hash_actual;
|
||||
if (!cryptonote::parse_and_validate_tx_from_blob(tx_data, btx.tx, tx_hash_actual)) {
|
||||
if (!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx, tx_hash_actual)) {
|
||||
MINFO("Rejecting blink tx: failed to parse transaction data");
|
||||
if (tag)
|
||||
m.reply("bl_nostart", bt_dict{{"!", tag}, {"e", "Failed to parse transaction data"}});
|
||||
|
@ -971,7 +991,7 @@ void handle_blink(SNNetwork::message &m, void *self) {
|
|||
// Check tx for validity
|
||||
bool already_in_mempool;
|
||||
cryptonote::tx_verification_context tvc = {};
|
||||
bool approved = snw.core.get_pool().add_blink(btxptr, tvc, already_in_mempool);
|
||||
bool approved = snw.core.get_pool().add_new_blink(btxptr, tvc, already_in_mempool);
|
||||
|
||||
MINFO("Blink TX " << tx_hash << (approved ? " approved and added to mempool" : " rejected"));
|
||||
if (!approved)
|
||||
|
@ -990,7 +1010,7 @@ void handle_blink(SNNetwork::message &m, void *self) {
|
|||
signatures.emplace_back(approved, qi, pinfo.my_position[qi], sig);
|
||||
}
|
||||
|
||||
process_blink_signatures(snw, btx, blink_quorums, checksum, std::move(signatures), tag, m.pubkey);
|
||||
process_blink_signatures(snw, btxptr, blink_quorums, checksum, std::move(signatures), tag, m.pubkey);
|
||||
}
|
||||
|
||||
template <typename T, typename CopyValue>
|
||||
|
@ -1106,7 +1126,7 @@ void handle_blink_signature(SNNetwork::message &m, void *self) {
|
|||
|
||||
auto blink_quorums = get_blink_quorums(blink_height, snw.core.get_service_node_list(), &checksum); // throws if bad quorum or checksum mismatch
|
||||
|
||||
uint64_t reply_tag;
|
||||
uint64_t reply_tag = 0;
|
||||
std::string reply_pubkey;
|
||||
std::shared_ptr<blink_tx> btxptr;
|
||||
{
|
||||
|
@ -1133,11 +1153,10 @@ void handle_blink_signature(SNNetwork::message &m, void *self) {
|
|||
return;
|
||||
}
|
||||
|
||||
process_blink_signatures(snw, *btxptr, blink_quorums, checksum, std::move(signatures), reply_tag, reply_pubkey, m.pubkey);
|
||||
process_blink_signatures(snw, btxptr, blink_quorums, checksum, std::move(signatures), reply_tag, reply_pubkey, m.pubkey);
|
||||
}
|
||||
|
||||
|
||||
// tag -> {hash, promise, expiry}
|
||||
using blink_response = std::pair<cryptonote::blink_result, std::string>;
|
||||
struct blink_result_data {
|
||||
crypto::hash hash;
|
||||
|
|
|
@ -1336,6 +1336,7 @@ static void print_pool(const std::vector<cryptonote::tx_info> &transactions, boo
|
|||
<< "relayed: " << (tx_info.relayed ? boost::lexical_cast<std::string>(tx_info.last_relayed_time) + " (" + get_human_time_ago(tx_info.last_relayed_time, now) + ")" : "no") << "\n"
|
||||
<< std::boolalpha
|
||||
<< "do_not_relay: " << tx_info.do_not_relay << "\n"
|
||||
<< "blink: " << tx_info.blink << "\n"
|
||||
<< "kept_by_block: " << tx_info.kept_by_block << "\n"
|
||||
<< "double_spend_seen: " << tx_info.double_spend_seen << "\n"
|
||||
<< std::noboolalpha
|
||||
|
|
|
@ -984,7 +984,7 @@ namespace nodetool
|
|||
std::atomic<bool> hsh_result(false);
|
||||
|
||||
bool r = epee::net_utils::async_invoke_remote_command2<typename COMMAND_HANDSHAKE::response>(context_.m_connection_id, COMMAND_HANDSHAKE::ID, arg, zone.m_net_server.get_config_object(),
|
||||
[this, &pi, &ev, &hsh_result, &just_take_peerlist, &context_](int code, const typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context)
|
||||
[this, &pi, &ev, &hsh_result, &just_take_peerlist, &context_](int code, typename COMMAND_HANDSHAKE::response&& rsp, p2p_connection_context& context)
|
||||
{
|
||||
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ev.raise();});
|
||||
|
||||
|
@ -1009,7 +1009,7 @@ namespace nodetool
|
|||
hsh_result = true;
|
||||
if(!just_take_peerlist)
|
||||
{
|
||||
if(!m_payload_handler.process_payload_sync_data(rsp.payload_data, context, true))
|
||||
if(!m_payload_handler.process_payload_sync_data(std::move(rsp.payload_data), context, true))
|
||||
{
|
||||
LOG_WARNING_CC(context, "COMMAND_HANDSHAKE invoked, but process_payload_sync_data returned false, dropping connection.");
|
||||
hsh_result = false;
|
||||
|
@ -1068,7 +1068,7 @@ namespace nodetool
|
|||
|
||||
network_zone& zone = m_network_zones.at(context_.m_remote_address.get_zone());
|
||||
bool r = epee::net_utils::async_invoke_remote_command2<typename COMMAND_TIMED_SYNC::response>(context_.m_connection_id, COMMAND_TIMED_SYNC::ID, arg, zone.m_net_server.get_config_object(),
|
||||
[this](int code, const typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context)
|
||||
[this](int code, typename COMMAND_TIMED_SYNC::response&& rsp, p2p_connection_context& context)
|
||||
{
|
||||
context.m_in_timedsync = false;
|
||||
if(code < 0)
|
||||
|
@ -1085,7 +1085,7 @@ namespace nodetool
|
|||
}
|
||||
if(!context.m_is_income)
|
||||
m_network_zones.at(context.m_remote_address.get_zone()).m_peerlist.set_peer_just_seen(context.peer_id, context.m_remote_address, context.m_pruning_seed, context.m_rpc_port);
|
||||
if (!m_payload_handler.process_payload_sync_data(rsp.payload_data, context, false))
|
||||
if (!m_payload_handler.process_payload_sync_data(std::move(rsp.payload_data), context, false))
|
||||
{
|
||||
m_network_zones.at(context.m_remote_address.get_zone()).m_net_server.get_config_object().close(context.m_connection_id );
|
||||
}
|
||||
|
@ -2152,7 +2152,7 @@ namespace nodetool
|
|||
template<class t_payload_net_handler>
|
||||
int node_server<t_payload_net_handler>::handle_timed_sync(int command, typename COMMAND_TIMED_SYNC::request& arg, typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context)
|
||||
{
|
||||
if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, false))
|
||||
if(!m_payload_handler.process_payload_sync_data(std::move(arg.payload_data), context, false))
|
||||
{
|
||||
LOG_WARNING_CC(context, "Failed to process_payload_sync_data(), dropping connection");
|
||||
drop_connection(context);
|
||||
|
@ -2219,7 +2219,7 @@ namespace nodetool
|
|||
return 1;
|
||||
}
|
||||
|
||||
if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, true))
|
||||
if(!m_payload_handler.process_payload_sync_data(std::move(arg.payload_data), context, true))
|
||||
{
|
||||
LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but process_payload_sync_data returned false, dropping connection.");
|
||||
drop_connection(context);
|
||||
|
|
|
@ -438,7 +438,7 @@ void SNNetwork::worker_thread(std::string worker_id) {
|
|||
const bool &public_cmd = cmdit->second.second;
|
||||
if (!public_cmd && !msg.sn) {
|
||||
// If they aren't valid, tell them so that they can disconnect (and attempt to reconnect later with appropriate authentication)
|
||||
SN_LOG(warn, worker_id << " (of " << object_id << ") received quorum-only command from an non-SN authenticated remote; replying with a BYE");
|
||||
SN_LOG(warn, worker_id << "/" << object_id << " received quorum-only command " << msg.command << " from an non-SN authenticated remote; replying with a BYE");
|
||||
send(msg.pubkey, "BYE", send_option::incoming{});
|
||||
detail::send_control(get_control_socket(), "DISCONNECT", {{"pubkey",msg.pubkey}});
|
||||
continue;
|
||||
|
|
|
@ -721,6 +721,14 @@ namespace cryptonote
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto &pool = m_core.get_pool();
|
||||
auto lock = pool.blink_shared_lock();
|
||||
for (size_t i = 0; i < res.txs.size(); i++)
|
||||
if (pool.has_blink(vh[i], true /*have lock*/))
|
||||
res.txs[i].blink = true;
|
||||
}
|
||||
|
||||
for(const auto& miss_tx: missed_txs)
|
||||
{
|
||||
res.missed_tx.push_back(string_tools::pod_to_hex(miss_tx));
|
||||
|
|
|
@ -470,6 +470,7 @@ namespace cryptonote
|
|||
uint64_t block_timestamp; // Unix time at chich the block has been added to the blockchain.
|
||||
std::vector<uint64_t> output_indices; // List of transaction indexes.
|
||||
bool relayed;
|
||||
bool blink; // True if this is an approved, blink transaction (only for in_pool transactions or txes in recent blocks)
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tx_hash)
|
||||
|
@ -490,6 +491,7 @@ namespace cryptonote
|
|||
{
|
||||
KV_SERIALIZE(relayed)
|
||||
}
|
||||
KV_SERIALIZE(blink)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
@ -1457,6 +1459,7 @@ namespace cryptonote
|
|||
bool do_not_relay; // States if this transaction should not be relayed.
|
||||
bool double_spend_seen; // States if this transaction has been seen as double spend.
|
||||
std::string tx_blob; // Hexadecimal blob represnting the transaction.
|
||||
bool blink; // True if this is a signed blink transaction
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(id_hash)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) 2014-2019, The Monero Project
|
||||
// Copyright (c) 2018, The Loki Project
|
||||
// Copyright (c) 2018-2019, The Loki Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -8230,7 +8230,7 @@ void simple_wallet::wallet_idle_thread()
|
|||
uint64_t fetched_blocks;
|
||||
bool received_money;
|
||||
if (try_connect_to_daemon(true))
|
||||
m_wallet->refresh(m_wallet->is_trusted_daemon(), 0, fetched_blocks, received_money, false); // don't check the pool in background mode
|
||||
m_wallet->refresh(m_wallet->is_trusted_daemon(), 0, fetched_blocks, received_money);
|
||||
}
|
||||
catch(...) {}
|
||||
m_auto_refresh_refreshing = false;
|
||||
|
|
|
@ -1619,7 +1619,7 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &
|
|||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, const crypto::public_key &tx_pub_key, size_t vout_index, tx_scan_info_t &tx_scan_info, std::vector<tx_money_got_in_out> &tx_money_got_in_outs, std::vector<size_t> &outs, bool pool)
|
||||
void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, const crypto::public_key &tx_pub_key, size_t vout_index, tx_scan_info_t &tx_scan_info, std::vector<tx_money_got_in_out> &tx_money_got_in_outs, std::vector<size_t> &outs, bool pool, bool blink)
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(vout_index >= tx.vout.size(), error::wallet_internal_error, "Invalid vout index");
|
||||
|
||||
|
@ -1630,9 +1630,9 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
|
|||
CRITICAL_REGION_LOCAL(password_lock);
|
||||
if (!m_encrypt_keys_after_refresh)
|
||||
{
|
||||
boost::optional<epee::wipeable_string> pwd = m_callback->on_get_password(pool ? "output found in pool" : "output received");
|
||||
THROW_WALLET_EXCEPTION_IF(!pwd, error::password_needed, tr("Password is needed to compute key image for incoming loki"));
|
||||
THROW_WALLET_EXCEPTION_IF(!verify_password(*pwd), error::password_needed, tr("Invalid password: password is needed to compute key image for incoming loki"));
|
||||
boost::optional<epee::wipeable_string> pwd = m_callback->on_get_password(pool ? blink ? "blink output receive in pool" : "output found in pool" : "output received");
|
||||
THROW_WALLET_EXCEPTION_IF(!pwd, error::password_needed, tr("Password is needed to compute key image for incoming LOKI"));
|
||||
THROW_WALLET_EXCEPTION_IF(!verify_password(*pwd), error::password_needed, tr("Invalid password: password is needed to compute key image for incoming LOKI"));
|
||||
decrypt_keys(*pwd);
|
||||
m_encrypt_keys_after_refresh = *pwd;
|
||||
}
|
||||
|
@ -1723,7 +1723,9 @@ void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::has
|
|||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
|
||||
void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices,
|
||||
uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool blink, bool double_spend_seen,
|
||||
const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
|
||||
{
|
||||
if (tx.type != txtype::standard || tx.version <= txversion::v1)
|
||||
return;
|
||||
|
@ -1731,7 +1733,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||
PERF_TIMER(process_new_transaction);
|
||||
// In this function, tx (probably) only contains the base information
|
||||
// (that is, the prunable stuff may or may not be included)
|
||||
if (!miner_tx && !pool)
|
||||
if (!miner_tx && (!pool || blink))
|
||||
process_unconfirmed(txid, tx, height);
|
||||
|
||||
// NOTE: tx_scan_info contains the decoded amounts from the transaction destined for us
|
||||
|
@ -1881,7 +1883,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||
if (tx_scan_info[i].received)
|
||||
{
|
||||
hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations);
|
||||
scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], tx_money_got_in_outs, outs, pool);
|
||||
scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], tx_money_got_in_outs, outs, pool, blink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1897,7 +1899,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||
boost::unique_lock<hw::device> hwdev_lock (hwdev);
|
||||
hwdev.set_mode(hw::device::NONE);
|
||||
hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations);
|
||||
scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], tx_money_got_in_outs, outs, pool);
|
||||
scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], tx_money_got_in_outs, outs, pool, blink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1927,7 +1929,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||
if (kit == m_pub_keys.end())
|
||||
{
|
||||
uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount;
|
||||
if (!pool)
|
||||
if (!pool || blink)
|
||||
{
|
||||
pk_to_unlock_times[tx_scan_info[o].in_ephemeral.pub] = tx_scan_info[o].unlock_time;
|
||||
|
||||
|
@ -1935,7 +1937,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||
transfer_details& td = m_transfers.back();
|
||||
td.m_block_height = height;
|
||||
td.m_internal_output_index = o;
|
||||
td.m_global_output_index = o_indices[o];
|
||||
td.m_global_output_index = pool ? 0 : o_indices[o]; // blink tx doesn't have this; will get updated when it gets into a block
|
||||
td.m_tx = (const cryptonote::transaction_prefix&)tx;
|
||||
td.m_txid = txid;
|
||||
td.m_key_image = tx_scan_info[o].ki;
|
||||
|
@ -2080,12 +2082,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||
|
||||
uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount;
|
||||
uint64_t extra_amount = amount - m_transfers[kit->second].amount();
|
||||
if (!pool)
|
||||
if (!pool || blink)
|
||||
{
|
||||
transfer_details &td = m_transfers[kit->second];
|
||||
td.m_block_height = height;
|
||||
td.m_internal_output_index = o;
|
||||
td.m_global_output_index = o_indices[o];
|
||||
td.m_global_output_index = pool ? 0 : o_indices[o]; // blink tx doesn't have this; will get updated when it gets into a block
|
||||
td.m_tx = (const cryptonote::transaction_prefix&)tx;
|
||||
td.m_txid = txid;
|
||||
td.m_amount = amount;
|
||||
|
@ -2413,7 +2415,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
|
|||
{
|
||||
TIME_MEASURE_START(miner_tx_handle_time);
|
||||
if (m_refresh_type != RefreshNoCoinbase)
|
||||
process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset], output_tracker_cache);
|
||||
process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, false, tx_cache_data[tx_cache_data_offset], output_tracker_cache);
|
||||
++tx_cache_data_offset;
|
||||
TIME_MEASURE_FINISH(miner_tx_handle_time);
|
||||
|
||||
|
@ -2422,7 +2424,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
|
|||
THROW_WALLET_EXCEPTION_IF(bche.txs.size() != parsed_block.txes.size(), error::wallet_internal_error, "Wrong amount of transactions for block");
|
||||
for (size_t idx = 0; idx < b.tx_hashes.size(); ++idx)
|
||||
{
|
||||
process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++], output_tracker_cache);
|
||||
process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, false, tx_cache_data[tx_cache_data_offset++], output_tracker_cache);
|
||||
}
|
||||
TIME_MEASURE_FINISH(txs_handle_time);
|
||||
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
|
||||
|
@ -2953,11 +2955,11 @@ void wallet2::update_pool_state(bool refreshed)
|
|||
|
||||
if (get_pruned_tx(tx_entry, tx, tx_hash))
|
||||
{
|
||||
const std::vector<std::pair<crypto::hash, bool>>::const_iterator i = std::find_if(txids.begin(), txids.end(),
|
||||
auto i = std::find_if(txids.begin(), txids.end(),
|
||||
[tx_hash](const std::pair<crypto::hash, bool> &e) { return e.first == tx_hash; });
|
||||
if (i != txids.end())
|
||||
{
|
||||
process_new_transaction(tx_hash, tx, std::vector<uint64_t>(), 0, time(NULL), false, true, tx_entry.double_spend_seen, {});
|
||||
process_new_transaction(tx_hash, tx, {}, 0, time(NULL), false, true, tx_entry.blink, tx_entry.double_spend_seen, {});
|
||||
m_scanned_pool_txs[0].insert(tx_hash);
|
||||
if (m_scanned_pool_txs[0].size() > 5000)
|
||||
{
|
||||
|
@ -3096,7 +3098,7 @@ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> wallet2::create
|
|||
return cache;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money, bool check_pool)
|
||||
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money)
|
||||
{
|
||||
if (m_offline)
|
||||
{
|
||||
|
@ -3305,7 +3307,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
|
|||
try
|
||||
{
|
||||
// If stop() is called we don't need to check pending transactions
|
||||
if (check_pool && m_run.load(std::memory_order_relaxed))
|
||||
if (m_run.load(std::memory_order_relaxed))
|
||||
update_pool_state(refreshed);
|
||||
}
|
||||
catch (...)
|
||||
|
|
|
@ -895,7 +895,7 @@ private:
|
|||
bool is_deprecated() const;
|
||||
void refresh(bool trusted_daemon);
|
||||
void refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched);
|
||||
void refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money, bool check_pool = true);
|
||||
void refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money);
|
||||
bool refresh(bool trusted_daemon, uint64_t & blocks_fetched, bool& received_money, bool& ok);
|
||||
|
||||
void set_refresh_type(RefreshType refresh_type) { m_refresh_type = refresh_type; }
|
||||
|
@ -1549,7 +1549,7 @@ private:
|
|||
* \param password Password of wallet file
|
||||
*/
|
||||
bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password);
|
||||
void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
|
||||
void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool blink, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
|
||||
bool should_skip_block(const cryptonote::block &b, uint64_t height) const;
|
||||
void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
|
||||
void detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
|
||||
|
@ -1586,7 +1586,7 @@ private:
|
|||
bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const;
|
||||
bool should_pick_a_second_output(size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const;
|
||||
std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const;
|
||||
void scan_output(const cryptonote::transaction &tx, bool miner_tx, const crypto::public_key &tx_pub_key, size_t vout_index, tx_scan_info_t &tx_scan_info, std::vector<tx_money_got_in_out> &tx_money_got_in_outs, std::vector<size_t> &outs, bool pool);
|
||||
void scan_output(const cryptonote::transaction &tx, bool miner_tx, const crypto::public_key &tx_pub_key, size_t vout_index, tx_scan_info_t &tx_scan_info, std::vector<tx_money_got_in_out> &tx_money_got_in_outs, std::vector<size_t> &outs, bool pool, bool blink);
|
||||
void trim_hashchain();
|
||||
crypto::key_image get_multisig_composite_key_image(size_t n) const;
|
||||
rct::multisig_kLRki get_multisig_composite_kLRki(size_t n, const std::unordered_set<crypto::public_key> &ignore_set, std::unordered_set<rct::key> &used_L, std::unordered_set<rct::key> &new_used_L) const;
|
||||
|
|
Loading…
Reference in a new issue