IWallet implementation improvements

This commit is contained in:
Antonio Juarez 2015-09-04 17:14:17 +01:00
parent a6588cfc58
commit 6c35e24634
12 changed files with 116 additions and 29 deletions

View file

@ -121,7 +121,7 @@ public:
virtual void start() = 0;
virtual void stop() = 0;
//blocks until an event occured
//blocks until an event occurred
virtual WalletEvent getEvent() = 0;
};

View file

@ -163,7 +163,8 @@ const CheckpointData CHECKPOINTS[] = {
{800000, "d7fa4eea02e5ce60b949136569c0ea7ac71ea46e0065311054072ac415560b86"},
{804000, "bcc8b3782499aae508c40d5587d1cc5d68281435ea9bfc6804a262047f7b934d"},
{810500, "302b2349f221232820adc3dadafd8a61b035491e33af669c78a687949eb0a381"},
{816000, "32b7fdd4e4d715db81f8f09f4ba5e5c78e8113f2804d61a57378baee479ce745"}
{816000, "32b7fdd4e4d715db81f8f09f4ba5e5c78e8113f2804d61a57378baee479ce745"},
{822000, "a3c9603c6813a0dc0efc40db288c356d1a7f02d1d2e47bee04346e73715f8984"}
};
} // CryptoNote

View file

@ -84,6 +84,7 @@ void NodeRpcProxy::resetInternalState() {
m_nodeHeight.store(0, std::memory_order_relaxed);
m_networkHeight.store(0, std::memory_order_relaxed);
m_lastKnowHash = CryptoNote::NULL_HASH;
m_knownTxs.clear();
}
void NodeRpcProxy::init(const INode::Callback& callback) {
@ -176,6 +177,39 @@ void NodeRpcProxy::workerThread(const INode::Callback& initialized_callback) {
}
void NodeRpcProxy::updateNodeStatus() {
bool updateBlockchain = true;
while (updateBlockchain) {
updateBlockchainStatus();
updateBlockchain = !updatePoolStatus();
}
}
bool NodeRpcProxy::updatePoolStatus() {
std::vector<Crypto::Hash> knownTxs = getKnownTxsVector();
Crypto::Hash tailBlock = m_lastKnowHash;
bool isBcActual = false;
std::vector<std::unique_ptr<ITransactionReader>> addedTxs;
std::vector<Crypto::Hash> deletedTxsIds;
std::error_code ec = doGetPoolSymmetricDifference(std::move(knownTxs), tailBlock, isBcActual, addedTxs, deletedTxsIds);
if (ec) {
return true;
}
if (!isBcActual) {
return false;
}
if (!addedTxs.empty() || !deletedTxsIds.empty()) {
updatePoolState(addedTxs, deletedTxsIds);
m_observerManager.notify(&INodeObserver::poolChanged);
}
return true;
}
void NodeRpcProxy::updateBlockchainStatus() {
CryptoNote::COMMAND_RPC_GET_LAST_BLOCK_HEADER::request req = AUTO_VAL_INIT(req);
CryptoNote::COMMAND_RPC_GET_LAST_BLOCK_HEADER::response rsp = AUTO_VAL_INIT(rsp);
@ -224,6 +258,21 @@ void NodeRpcProxy::updatePeerCount() {
}
}
void NodeRpcProxy::updatePoolState(const std::vector<std::unique_ptr<ITransactionReader>>& addedTxs, const std::vector<Crypto::Hash>& deletedTxsIds) {
for (const auto& hash : deletedTxsIds) {
m_knownTxs.erase(hash);
}
for (const auto& tx : addedTxs) {
Hash hash = tx->getTransactionHash();
m_knownTxs.emplace(std::move(hash));
}
}
std::vector<Crypto::Hash> NodeRpcProxy::getKnownTxsVector() const {
return std::vector<Crypto::Hash>(m_knownTxs.begin(), m_knownTxs.end());
}
bool NodeRpcProxy::addObserver(INodeObserver* observer) {
return m_observerManager.add(observer);
}

View file

@ -22,6 +22,7 @@
#include <mutex>
#include <string>
#include <thread>
#include <unordered_set>
#include "Common/ObserverManager.h"
#include "INode.h"
@ -68,7 +69,6 @@ public:
virtual void getNewBlocks(std::vector<Crypto::Hash>&& knownBlockIds, std::vector<CryptoNote::block_complete_entry>& newBlocks, uint32_t& startHeight, const Callback& callback);
virtual void getTransactionOutsGlobalIndices(const Crypto::Hash& transactionHash, std::vector<uint32_t>& outsGlobalIndices, const Callback& callback) override;
virtual void queryBlocks(std::vector<Crypto::Hash>&& knownBlockIds, uint64_t timestamp, std::vector<BlockShortEntry>& newBlocks, uint32_t& startHeight, const Callback& callback) override;
// TODO INodeObserver::poolChanged() notification NOT implemented!!!
virtual void getPoolSymmetricDifference(std::vector<Crypto::Hash>&& knownPoolTxIds, Crypto::Hash knownBlockId, bool& isBcActual,
std::vector<std::unique_ptr<ITransactionReader>>& newTxs, std::vector<Crypto::Hash>& deletedTxIds, const Callback& callback) override;
virtual void getMultisignatureOutputByGlobalIndex(uint64_t amount, uint32_t gindex, MultisignatureOutput& out, const Callback& callback) override;
@ -87,9 +87,13 @@ private:
void resetInternalState();
void workerThread(const Callback& initialized_callback);
std::vector<Crypto::Hash> getKnownTxsVector() const;
void pullNodeStatusAndScheduleTheNext();
void updateNodeStatus();
void updateBlockchainStatus();
bool updatePoolStatus();
void updatePeerCount();
void updatePoolState(const std::vector<std::unique_ptr<ITransactionReader>>& addedTxs, const std::vector<Crypto::Hash>& deletedTxsIds);
std::error_code doRelayTransaction(const CryptoNote::Transaction& transaction);
std::error_code doGetRandomOutsByAmounts(std::vector<uint64_t>& amounts, uint64_t outsCount,
@ -144,6 +148,7 @@ private:
//protect it with mutex if decided to add worker threads
Crypto::Hash m_lastKnowHash;
std::atomic<uint64_t> m_lastLocalBlockTimestamp;
std::unordered_set<Crypto::Hash> m_knownTxs;
bool m_connected;
};

View file

@ -573,7 +573,10 @@ namespace CryptoNote
get_local_node_data(arg.node_data);
m_payload_handler.get_payload_sync_data(arg.payload_data);
proto.invoke(COMMAND_HANDSHAKE::ID, arg, rsp);
if (!proto.invoke(COMMAND_HANDSHAKE::ID, arg, rsp)) {
logger(Logging::ERROR) << context << "Failed to invoke COMMAND_HANDSHAKE, closing connection.";
return false;
}
context.version = rsp.node_data.version;

View file

@ -379,8 +379,9 @@ KeyPair WalletGreen::getViewKey() const {
std::string WalletGreen::createAddress() {
KeyPair spendKey;
Crypto::generate_keys(spendKey.publicKey, spendKey.secretKey);
uint64_t creationTimestamp = static_cast<uint64_t>(time(nullptr));
return doCreateAddress(spendKey.publicKey, spendKey.secretKey);
return doCreateAddress(spendKey.publicKey, spendKey.secretKey, creationTimestamp);
}
std::string WalletGreen::createAddress(const Crypto::SecretKey& spendSecretKey) {
@ -389,14 +390,14 @@ std::string WalletGreen::createAddress(const Crypto::SecretKey& spendSecretKey)
throw std::system_error(make_error_code(CryptoNote::error::KEY_GENERATION_ERROR));
}
return doCreateAddress(spendPublicKey, spendSecretKey);
return doCreateAddress(spendPublicKey, spendSecretKey, 0);
}
std::string WalletGreen::createAddress(const Crypto::PublicKey& spendPublicKey) {
return doCreateAddress(spendPublicKey, NULL_SECRET_KEY);
return doCreateAddress(spendPublicKey, NULL_SECRET_KEY, 0);
}
std::string WalletGreen::doCreateAddress(const Crypto::PublicKey& spendPublicKey, const Crypto::SecretKey& spendSecretKey) {
std::string WalletGreen::doCreateAddress(const Crypto::PublicKey& spendPublicKey, const Crypto::SecretKey& spendSecretKey, uint64_t creationTimestamp) {
throwIfNotInitialized();
throwIfStopped();
@ -405,7 +406,7 @@ std::string WalletGreen::doCreateAddress(const Crypto::PublicKey& spendPublicKey
}
try {
addWallet(spendPublicKey, spendSecretKey);
addWallet(spendPublicKey, spendSecretKey, creationTimestamp);
} catch (std::exception&) {
if (m_walletsContainer.get<RandomAccessIndex>().size() != 0) {
m_blockchainSynchronizer.start();
@ -419,7 +420,7 @@ std::string WalletGreen::doCreateAddress(const Crypto::PublicKey& spendPublicKey
return m_currency.accountAddressAsString({ spendPublicKey, m_viewPublicKey });
}
void WalletGreen::addWallet(const Crypto::PublicKey& spendPublicKey, const Crypto::SecretKey& spendSecretKey) {
void WalletGreen::addWallet(const Crypto::PublicKey& spendPublicKey, const Crypto::SecretKey& spendSecretKey, uint64_t creationTimestamp) {
auto& index = m_walletsContainer.get<KeysIndex>();
auto trackingMode = getTrackingMode();
@ -434,8 +435,6 @@ void WalletGreen::addWallet(const Crypto::PublicKey& spendPublicKey, const Crypt
throw std::system_error(make_error_code(error::ADDRESS_ALREADY_EXISTS));
}
time_t creationTimestamp = time(nullptr);
AccountSubscription sub;
sub.keys.address.viewPublicKey = m_viewPublicKey;
sub.keys.address.spendPublicKey = spendPublicKey;
@ -443,7 +442,7 @@ void WalletGreen::addWallet(const Crypto::PublicKey& spendPublicKey, const Crypt
sub.keys.spendSecretKey = spendSecretKey;
sub.transactionSpendableAge = m_transactionSoftLockTime;
sub.syncStart.height = 0;
sub.syncStart.timestamp = static_cast<uint64_t>(creationTimestamp) - (60 * 60 * 24);
sub.syncStart.timestamp = std::max(creationTimestamp, ACCOUNT_CREATE_TIME_ACCURACY) - ACCOUNT_CREATE_TIME_ACCURACY;
auto& trSubscription = m_synchronizer.addSubscription(sub);
ITransfersContainer* container = &trSubscription.getContainer();
@ -452,7 +451,7 @@ void WalletGreen::addWallet(const Crypto::PublicKey& spendPublicKey, const Crypt
wallet.spendPublicKey = spendPublicKey;
wallet.spendSecretKey = spendSecretKey;
wallet.container = container;
wallet.creationTimestamp = creationTimestamp;
wallet.creationTimestamp = static_cast<time_t>(creationTimestamp);
trSubscription.addObserver(this);
index.insert(insertIt, std::move(wallet));
@ -753,6 +752,12 @@ bool WalletGreen::updateWalletTransactionInfo(const Hash& hash, const CryptoNote
updated = true;
}
// Fix LegacyWallet error. Some old versions didn't fill extra field
if (transaction.extra.empty() && !info.extra.empty()) {
transaction.extra = Common::asString(info.extra);
updated = true;
}
bool isBase = info.totalAmountIn == 0;
if (transaction.isBase != isBase) {
transaction.isBase = isBase;
@ -767,7 +772,7 @@ bool WalletGreen::updateWalletTransactionInfo(const Hash& hash, const CryptoNote
throw std::system_error(make_error_code(std::errc::invalid_argument));
}
size_t WalletGreen::insertIncomingTransaction(const TransactionInformation& info, int64_t txBalance) {
size_t WalletGreen::insertBlockchainTransaction(const TransactionInformation& info, int64_t txBalance) {
auto& index = m_transactions.get<RandomAccessIndex>();
WalletTransaction tx;
@ -1166,8 +1171,12 @@ void WalletGreen::transactionUpdated(ITransfersSubscription* object, const Hash&
pushEvent(makeTransactionUpdatedEvent(id));
}
} else {
auto id = insertIncomingTransaction(info, txBalance);
insertIncomingTransfer(id, m_currency.accountAddressAsString({ getWalletRecord(container).spendPublicKey, m_viewPublicKey }), txBalance);
auto id = insertBlockchainTransaction(info, txBalance);
if (txBalance > 0) {
AccountPublicAddress walletAddress{ getWalletRecord(container).spendPublicKey, m_viewPublicKey };
insertIncomingTransfer(id, m_currency.accountAddressAsString(walletAddress), txBalance);
}
m_fusionTxsCache.emplace(id, isFusionTransaction(m_transactions.get<RandomAccessIndex>()[id]));
pushEvent(makeTransactionCreatedEvent(id));

View file

@ -86,7 +86,7 @@ protected:
void doShutdown();
void clearCaches();
void initWithKeys(const Crypto::PublicKey& viewPublicKey, const Crypto::SecretKey& viewSecretKey, const std::string& password);
std::string doCreateAddress(const Crypto::PublicKey& spendPublicKey, const Crypto::SecretKey& spendSecretKey);
std::string doCreateAddress(const Crypto::PublicKey& spendPublicKey, const Crypto::SecretKey& spendSecretKey, uint64_t creationTimestamp);
struct InputInfo {
TransactionTypes::InputKeyInfo keyInfo;
@ -133,7 +133,7 @@ protected:
const WalletRecord& getWalletRecord(CryptoNote::ITransfersContainer* container) const;
CryptoNote::AccountPublicAddress parseAddress(const std::string& address) const;
void addWallet(const Crypto::PublicKey& spendPublicKey, const Crypto::SecretKey& spendSecretKey);
void addWallet(const Crypto::PublicKey& spendPublicKey, const Crypto::SecretKey& spendSecretKey, uint64_t creationTimestamp);
bool isOutputUsed(const TransactionOutputInformation& out) const;
void markOutputsSpent(const Crypto::Hash& transactionHash, const std::vector<OutputToTransfer>& selectedTransfers);
void deleteSpentOutputs(const Crypto::Hash& transactionHash);
@ -177,7 +177,7 @@ protected:
size_t insertOutgoingTransaction(const Crypto::Hash& transactionHash, int64_t totalAmount, uint64_t fee, const BinaryArray& extra, uint64_t unlockTimestamp);
bool transactionExists(const Crypto::Hash& hash);
bool updateWalletTransactionInfo(const Crypto::Hash& hash, const CryptoNote::TransactionInformation& info);
size_t insertIncomingTransaction(const TransactionInformation& info, int64_t txBalance);
size_t insertBlockchainTransaction(const TransactionInformation& info, int64_t txBalance);
void insertIncomingTransfer(size_t txId, const std::string& address, int64_t amount);
void pushBackOutgoingTransfers(size_t txId, const std::vector<WalletTransfer> &destinations);
void insertUnlockTransactionJob(const Crypto::Hash& transactionHash, uint32_t blockHeight, CryptoNote::ITransfersContainer* container);

View file

@ -30,6 +30,10 @@
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
namespace CryptoNote {
const uint64_t ACCOUNT_CREATE_TIME_ACCURACY = 60 * 60 * 24;
struct WalletRecord {
Crypto::PublicKey spendPublicKey;
Crypto::SecretKey spendSecretKey;
@ -122,3 +126,5 @@ typedef std::unordered_map<Crypto::Hash, uint64_t> TransactionChanges;
typedef std::pair<size_t, CryptoNote::WalletTransfer> TransactionTransferPair;
typedef std::vector<TransactionTransferPair> WalletTransfers;
}

View file

@ -726,7 +726,7 @@ void WalletSerializer::subscribeWallets() {
sub.keys.spendSecretKey = wallet.spendSecretKey;
sub.transactionSpendableAge = m_transactionSoftLockTime;
sub.syncStart.height = 0;
sub.syncStart.timestamp = static_cast<uint64_t>(wallet.creationTimestamp) - (60 * 60 * 24);
sub.syncStart.timestamp = std::max(static_cast<uint64_t>(wallet.creationTimestamp), ACCOUNT_CREATE_TIME_ACCURACY) - ACCOUNT_CREATE_TIME_ACCURACY;
auto& subscription = m_synchronizer.addSubscription(sub);
bool r = index.modify(it, [&subscription] (WalletRecord& rec) { rec.container = &subscription.getContainer(); });

View file

@ -1,4 +1,4 @@
#define BUILD_COMMIT_ID "@VERSION@"
#define PROJECT_VERSION "1.0.8"
#define PROJECT_VERSION_BUILD_NO "608"
#define PROJECT_VERSION "1.0.8.1"
#define PROJECT_VERSION_BUILD_NO "614"
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"

View file

@ -22,6 +22,24 @@
#include "CryptoNoteCore/IBlock.h"
#include "CryptoNoteCore/VerificationContext.h"
ICoreStub::ICoreStub() :
topHeight(0),
globalIndicesResult(false),
randomOutsResult(false),
poolTxVerificationResult(true),
poolChangesResult(true) {
}
ICoreStub::ICoreStub(const CryptoNote::Block& genesisBlock) :
topHeight(0),
globalIndicesResult(false),
randomOutsResult(false),
poolTxVerificationResult(true),
poolChangesResult(true) {
addBlock(genesisBlock);
}
bool ICoreStub::addObserver(CryptoNote::ICoreObserver* observer) {
return true;
}

View file

@ -28,11 +28,8 @@
class ICoreStub: public CryptoNote::ICore {
public:
ICoreStub() : topHeight(0), globalIndicesResult(false), randomOutsResult(false), poolTxVerificationResult(true) {};
ICoreStub(const CryptoNote::Block& genesisBlock) : topHeight(0), globalIndicesResult(false), randomOutsResult(false), poolTxVerificationResult(true),
poolChangesResult(true) {
addBlock(genesisBlock);
};
ICoreStub();
ICoreStub(const CryptoNote::Block& genesisBlock);
virtual bool addObserver(CryptoNote::ICoreObserver* observer);
virtual bool removeObserver(CryptoNote::ICoreObserver* observer);
@ -124,6 +121,5 @@ private:
std::unordered_map<Crypto::Hash, CryptoNote::Transaction> transactions;
std::unordered_map<Crypto::Hash, CryptoNote::Transaction> transactionPool;
bool poolTxVerificationResult;
bool poolChangesResult;
};