Skip to content

Commit

Permalink
Daemon synchronization and SimpleWallet improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Antonio Juarez committed Aug 19, 2015
1 parent deda499 commit a4b74ea
Show file tree
Hide file tree
Showing 29 changed files with 1,075 additions and 207 deletions.
15 changes: 13 additions & 2 deletions include/IWallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ enum class WalletTransactionState : uint8_t {
enum WalletEventType {
TRANSACTION_CREATED,
TRANSACTION_UPDATED,
BALANCE_UNLOCKED
BALANCE_UNLOCKED,
SYNC_PROGRESS_UPDATED,
SYNC_COMPLETED
};

struct WalletTransactionCreatedData {
Expand All @@ -48,11 +50,17 @@ struct WalletTransactionUpdatedData {
size_t transactionIndex;
};

struct WalletSynchronizationProgressUpdated {
uint32_t processedBlockCount;
uint32_t totalBlockCount;
};

struct WalletEvent {
WalletEventType type;
union {
WalletTransactionCreatedData transactionCreated;
WalletTransactionUpdatedData transactionUpdated;
WalletSynchronizationProgressUpdated synchronizationProgressUpdated;
};
};

Expand All @@ -78,6 +86,7 @@ class IWallet {
virtual ~IWallet() {}

virtual void initialize(const std::string& password) = 0;
virtual void initializeWithViewKey(const Crypto::SecretKey& viewSecretKey, const std::string& password) = 0;
virtual void load(std::istream& source, const std::string& password) = 0;
virtual void shutdown() = 0;

Expand All @@ -86,8 +95,10 @@ class IWallet {

virtual size_t getAddressCount() const = 0;
virtual std::string getAddress(size_t index) const = 0;
virtual KeyPair getAddressSpendKey(size_t index) const = 0;
virtual KeyPair getViewKey() const = 0;
virtual std::string createAddress() = 0;
virtual std::string createAddress(const KeyPair& spendKey) = 0;
virtual std::string createAddress(const Crypto::SecretKey& spendSecretKey) = 0;
virtual void deleteAddress(const std::string& address) = 0;

virtual uint64_t getActualBalance() const = 0;
Expand Down
3 changes: 2 additions & 1 deletion src/CryptoNoteConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ const CheckpointData CHECKPOINTS[] = {
{789000, "acef490bbccce3b7b7ae8554a414f55413fbf4ca1472c6359b126a4439bd9f01"},
{796000, "04e387a00d35db21d4d93d04040b31f22573972a7e61d72cc07d0ab69bcb9c44"},
{800000, "d7fa4eea02e5ce60b949136569c0ea7ac71ea46e0065311054072ac415560b86"},
{804000, "bcc8b3782499aae508c40d5587d1cc5d68281435ea9bfc6804a262047f7b934d"}
{804000, "bcc8b3782499aae508c40d5587d1cc5d68281435ea9bfc6804a262047f7b934d"},
{810500, "302b2349f221232820adc3dadafd8a61b035491e33af669c78a687949eb0a381"}
};
} // CryptoNote

Expand Down
4 changes: 3 additions & 1 deletion src/CryptoNoteCore/CoreConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ CoreConfig::CoreConfig() {
}

void CoreConfig::init(const boost::program_options::variables_map& options) {
configFolder = command_line::get_arg(options, command_line::arg_data_dir);
if (options.count(command_line::arg_data_dir.name) != 0 && (!options[command_line::arg_data_dir.name].defaulted() || configFolder == Tools::getDefaultDataDirectory())) {
configFolder = command_line::get_arg(options, command_line::arg_data_dir);
}
}

void CoreConfig::initOptions(boost::program_options::options_description& desc) {
Expand Down
4 changes: 3 additions & 1 deletion src/NodeRpcProxy/NodeErrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ enum NodeErrorCodes {
NETWORK_ERROR,
NODE_BUSY,
INTERNAL_NODE_ERROR,
REQUEST_ERROR
REQUEST_ERROR,
CONNECT_ERROR
};

// custom category:
Expand All @@ -54,6 +55,7 @@ class NodeErrorCategory : public std::error_category {
case NODE_BUSY: return "Node is busy";
case INTERNAL_NODE_ERROR: return "Internal node error";
case REQUEST_ERROR: return "Error in request parameters";
case CONNECT_ERROR: return "Can't connect to daemon";
default: return "Unknown error";
}
}
Expand Down
27 changes: 26 additions & 1 deletion src/NodeRpcProxy/NodeRpcProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ NodeRpcProxy::NodeRpcProxy(const std::string& nodeHost, unsigned short nodePort)
m_pullInterval(5000),
m_nodeHost(nodeHost),
m_nodePort(nodePort),
m_lastLocalBlockTimestamp(0) {
m_lastLocalBlockTimestamp(0),
m_connected(true) {
resetInternalState();
}

Expand Down Expand Up @@ -170,6 +171,8 @@ void NodeRpcProxy::workerThread(const INode::Callback& initialized_callback) {
m_context_group = nullptr;
m_httpClient = nullptr;
m_httpEvent = nullptr;
m_connected = false;
m_rpcProxyObserverManager.notify(&INodeRpcProxyObserver::connectionStatusUpdated, m_connected);
}

void NodeRpcProxy::updateNodeStatus() {
Expand Down Expand Up @@ -200,6 +203,10 @@ void NodeRpcProxy::updateNodeStatus() {
}

updatePeerCount();
if (m_connected != m_httpClient->isConnected()) {
m_connected = m_httpClient->isConnected();
m_rpcProxyObserverManager.notify(&INodeRpcProxyObserver::connectionStatusUpdated, m_connected);
}
}

void NodeRpcProxy::updatePeerCount() {
Expand All @@ -225,6 +232,14 @@ bool NodeRpcProxy::removeObserver(INodeObserver* observer) {
return m_observerManager.remove(observer);
}

bool NodeRpcProxy::addObserver(CryptoNote::INodeRpcProxyObserver* observer) {
return m_rpcProxyObserverManager.add(observer);
}

bool NodeRpcProxy::removeObserver(CryptoNote::INodeRpcProxyObserver* observer) {
return m_rpcProxyObserverManager.remove(observer);
}

size_t NodeRpcProxy::getPeerCount() const {
return m_peerCount.load(std::memory_order_relaxed);
}
Expand Down Expand Up @@ -563,6 +578,10 @@ void NodeRpcProxy::scheduleRequest(std::function<std::error_code()>&& procedure,
callback(std::make_error_code(std::errc::operation_canceled));
} else {
std::error_code ec = procedure();
if (m_connected != m_httpClient->isConnected()) {
m_connected = m_httpClient->isConnected();
m_rpcProxyObserverManager.notify(&INodeRpcProxyObserver::connectionStatusUpdated, m_connected);
}
callback(m_stop ? std::make_error_code(std::errc::operation_canceled) : ec);
}
}, std::move(procedure), std::move(callback)));
Expand All @@ -577,6 +596,8 @@ std::error_code NodeRpcProxy::binaryCommand(const std::string& url, const Reques
EventLock eventLock(*m_httpEvent);
invokeBinaryCommand(*m_httpClient, url, req, res);
ec = interpretResponseStatus(res.status);
} catch (const ConnectException&) {
ec = make_error_code(error::CONNECT_ERROR);
} catch (const std::exception&) {
ec = make_error_code(error::NETWORK_ERROR);
}
Expand All @@ -592,6 +613,8 @@ std::error_code NodeRpcProxy::jsonCommand(const std::string& url, const Request&
EventLock eventLock(*m_httpEvent);
invokeJsonCommand(*m_httpClient, url, req, res);
ec = interpretResponseStatus(res.status);
} catch (const ConnectException&) {
ec = make_error_code(error::CONNECT_ERROR);
} catch (const std::exception&) {
ec = make_error_code(error::NETWORK_ERROR);
}
Expand Down Expand Up @@ -627,6 +650,8 @@ std::error_code NodeRpcProxy::jsonRpcCommand(const std::string& method, const Re
ec = interpretResponseStatus(res.status);
}
}
} catch (const ConnectException&) {
ec = make_error_code(error::CONNECT_ERROR);
} catch (const std::exception&) {
ec = make_error_code(error::NETWORK_ERROR);
}
Expand Down
12 changes: 12 additions & 0 deletions src/NodeRpcProxy/NodeRpcProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ namespace CryptoNote {

class HttpClient;

class INodeRpcProxyObserver {
public:
virtual ~INodeRpcProxyObserver() {}
virtual void connectionStatusUpdated(bool connected) {}
};

class NodeRpcProxy : public CryptoNote::INode {
public:
NodeRpcProxy(const std::string& nodeHost, unsigned short nodePort);
Expand All @@ -44,6 +50,9 @@ class NodeRpcProxy : public CryptoNote::INode {
virtual bool addObserver(CryptoNote::INodeObserver* observer);
virtual bool removeObserver(CryptoNote::INodeObserver* observer);

virtual bool addObserver(CryptoNote::INodeRpcProxyObserver* observer);
virtual bool removeObserver(CryptoNote::INodeRpcProxyObserver* observer);

virtual void init(const Callback& callback);
virtual bool shutdown();

Expand Down Expand Up @@ -116,6 +125,7 @@ class NodeRpcProxy : public CryptoNote::INode {
System::Dispatcher* m_dispatcher = nullptr;
System::ContextGroup* m_context_group = nullptr;
Tools::ObserverManager<CryptoNote::INodeObserver> m_observerManager;
Tools::ObserverManager<CryptoNote::INodeRpcProxyObserver> m_rpcProxyObserverManager;

const std::string m_nodeHost;
const unsigned short m_nodePort;
Expand All @@ -134,6 +144,8 @@ class NodeRpcProxy : public CryptoNote::INode {
//protect it with mutex if decided to add worker threads
Crypto::Hash m_lastKnowHash;
std::atomic<uint64_t> m_lastLocalBlockTimestamp;

bool m_connected;
};

}
2 changes: 2 additions & 0 deletions src/P2p/ConnectionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ inline std::string get_protocol_state_string(CryptoNoteConnectionContext::state
return "state_normal";
case CryptoNoteConnectionContext::state_sync_required:
return "state_sync_required";
case CryptoNoteConnectionContext::state_pool_sync_required:
return "state_pool_sync_required";
case CryptoNoteConnectionContext::state_shutdown:
return "state_shutdown";
default:
Expand Down
27 changes: 18 additions & 9 deletions src/P2p/LevinProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ void LevinProtocol::sendMessage(uint32_t command, const BinaryArray& out, bool n
stream.writeSome(&head, sizeof(head));
stream.writeSome(out.data(), out.size());

m_conn.write(writeBuffer.data(), writeBuffer.size());
writeStrict(writeBuffer.data(), writeBuffer.size());
}

bool LevinProtocol::readCommand(Command& cmd) {
bucket_head2 head = { 0 };

if (!readStrict(&head, sizeof(head))) {
if (!readStrict(reinterpret_cast<uint8_t*>(&head), sizeof(head))) {
return false;
}

Expand Down Expand Up @@ -113,18 +113,27 @@ void LevinProtocol::sendReply(uint32_t command, const BinaryArray& out, int32_t
head.m_flags = LEVIN_PACKET_RESPONSE;
head.m_return_code = returnCode;

m_conn.write(reinterpret_cast<const uint8_t*>(&head), sizeof(head));
if (out.size() > 0) {
m_conn.write(reinterpret_cast<const uint8_t*>(out.data()), out.size());
}
BinaryArray writeBuffer;
writeBuffer.reserve(sizeof(head) + out.size());

Common::VectorOutputStream stream(writeBuffer);
stream.writeSome(&head, sizeof(head));
stream.writeSome(out.data(), out.size());

writeStrict(writeBuffer.data(), writeBuffer.size());
}

bool LevinProtocol::readStrict(void* ptr, size_t size) {
char* pos = reinterpret_cast<char*>(ptr);
void LevinProtocol::writeStrict(const uint8_t* ptr, size_t size) {
size_t offset = 0;
while (offset < size) {
offset += m_conn.write(ptr + offset, size - offset);
}
}

bool LevinProtocol::readStrict(uint8_t* ptr, size_t size) {
size_t offset = 0;
while (offset < size) {
size_t read = m_conn.read(reinterpret_cast<uint8_t*>(pos + offset), size - offset);
size_t read = m_conn.read(ptr + offset, size - offset);
if (read == 0) {
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion src/P2p/LevinProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ class LevinProtocol {

private:

bool readStrict(void* ptr, size_t size);
bool readStrict(uint8_t* ptr, size_t size);
void writeStrict(const uint8_t* ptr, size_t size);
System::TcpConnection& m_conn;
};

Expand Down
56 changes: 33 additions & 23 deletions src/P2p/NetNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,8 @@ namespace CryptoNote
});

System::Context<> timeoutContext(m_dispatcher, [&] {
System::Timer(m_dispatcher).sleep(std::chrono::milliseconds(m_config.m_net_config.connection_timeout));
// Here we use connection_timeout * 3, one for this handshake, and two for back ping from peer.
System::Timer(m_dispatcher).sleep(std::chrono::milliseconds(m_config.m_net_config.connection_timeout * 3));
handshakeContext.interrupt();
logger(DEBUGGING) << "Handshake with " << na << " timed out, interrupt it";
});
Expand Down Expand Up @@ -1049,7 +1050,9 @@ namespace CryptoNote
net_connection_id excludeId = excludeConnection ? *excludeConnection : boost::value_initialized<net_connection_id>();

forEachConnection([&](P2pConnectionContext& conn) {
if (conn.peerId && conn.m_connection_id != excludeId) {
if (conn.peerId && conn.m_connection_id != excludeId &&
(conn.m_state == CryptoNoteConnectionContext::state_normal ||
conn.m_state == CryptoNoteConnectionContext::state_synchronizing)) {
conn.pushMessage(P2pMessage(P2pMessage::NOTIFY, command, data_buff));
}
});
Expand All @@ -1068,41 +1071,48 @@ namespace CryptoNote
}

//-----------------------------------------------------------------------------------
bool NodeServer::try_ping(basic_node_data& node_data, P2pConnectionContext& context)
{
if(!node_data.my_port)
bool NodeServer::try_ping(basic_node_data& node_data, P2pConnectionContext& context) {
if(!node_data.my_port) {
return false;
}

uint32_t actual_ip = context.m_remote_ip;
if(!m_peerlist.is_ip_allowed(actual_ip))
if(!m_peerlist.is_ip_allowed(actual_ip)) {
return false;
}

std::string ip = Common::ipAddressToString(actual_ip);
auto ip = Common::ipAddressToString(actual_ip);
auto port = node_data.my_port;
PeerIdType pr = node_data.peer_id;
auto peerId = node_data.peer_id;

try {
System::TcpConnector connector(m_dispatcher);
System::TcpConnection conn = connector.connect(System::Ipv4Address(ip), static_cast<uint16_t>(port));

LevinProtocol proto(conn);

COMMAND_PING::request req;
COMMAND_PING::response rsp;
proto.invoke(COMMAND_PING::ID, req, rsp);

if (rsp.status != PING_OK_RESPONSE_STATUS_TEXT || pr != rsp.peer_id) {
logger(Logging::DEBUGGING) << context << "back ping invoke wrong response \"" << rsp.status << "\" from" << ip << ":" << port << ", hsh_peer_id=" << pr << ", rsp.peer_id=" << rsp.peer_id;
System::Context<> pingContext(m_dispatcher, [&] {
System::TcpConnector connector(m_dispatcher);
auto connection = connector.connect(System::Ipv4Address(ip), static_cast<uint16_t>(port));
LevinProtocol(connection).invoke(COMMAND_PING::ID, req, rsp);
});

System::Context<> timeoutContext(m_dispatcher, [&] {
System::Timer(m_dispatcher).sleep(std::chrono::milliseconds(m_config.m_net_config.connection_timeout * 2));
logger(DEBUGGING) << context << "Back ping timed out" << ip << ":" << port;
pingContext.interrupt();
});

pingContext.get();

if (rsp.status != PING_OK_RESPONSE_STATUS_TEXT || peerId != rsp.peer_id) {
logger(DEBUGGING) << context << "Back ping invoke wrong response \"" << rsp.status << "\" from" << ip
<< ":" << port << ", hsh_peer_id=" << peerId << ", rsp.peer_id=" << rsp.peer_id;
return false;
}

return true;

} catch (std::exception& e) {
logger(Logging::DEBUGGING) << context << "back ping to " << ip << ":" << port << " failed: " << e.what();
logger(DEBUGGING) << context << "Back ping connection to " << ip << ":" << port << " failed: " << e.what();
return false;
}

return false;
return true;
}

//-----------------------------------------------------------------------------------
Expand Down Expand Up @@ -1166,7 +1176,7 @@ namespace CryptoNote
pe.id = peer_id_l;
m_peerlist.append_with_peer_white(pe);

logger(Logging::TRACE) << context << "PING SUCCESS " << Common::ipAddressToString(context.m_remote_ip) << ":" << port_l;
logger(Logging::TRACE) << context << "BACK PING SUCCESS, " << Common::ipAddressToString(context.m_remote_ip) << ":" << port_l << " added to whitelist";
}
}

Expand Down
Loading

0 comments on commit a4b74ea

Please sign in to comment.