2016-01-18 15:33:29 +00:00
// Copyright (c) 2011-2016 The Cryptonote developers
2015-09-18 11:55:31 +00:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2015-05-27 12:08:46 +00:00
2015-07-30 15:22:07 +00:00
# include "../IntegrationTestLib/BaseFunctionalTests.h"
2015-05-27 12:08:46 +00:00
2015-07-30 15:22:07 +00:00
# include <thread>
2015-05-27 12:08:46 +00:00
# include <Logging/ConsoleLogger.h>
2015-07-30 15:22:07 +00:00
# include "CryptoNoteCore/Account.h"
# include "WalletLegacyObserver.h"
2015-05-27 12:08:46 +00:00
# undef ERROR
using namespace CryptoNote ;
using namespace Logging ;
inline std : : string shortAddress ( const std : : string & addr ) {
return addr . substr ( 0 , 6 ) ;
}
2015-07-30 15:22:07 +00:00
class MultiVersionTest : Tests : : Common : : BaseFunctionalTests {
2015-05-27 12:08:46 +00:00
public :
2015-07-30 15:22:07 +00:00
MultiVersionTest ( const CryptoNote : : Currency & currency , System : : Dispatcher & d , const Tests : : Common : : BaseFunctionalTestsConfig & config , Logging : : ILogger & log ) :
BaseFunctionalTests ( currency , d , config ) , m_config ( config ) , m_nodeCount ( config . daemons . size ( ) ) , logger ( log , " MultiVersion " ) { }
2015-05-27 12:08:46 +00:00
void run ( ) {
if ( m_config . daemons . empty ( ) ) {
logger ( ERROR , BRIGHT_RED ) < < " No daemons configured, exiting " ;
return ;
}
2015-07-30 15:22:07 +00:00
launchTestnet ( m_nodeCount , Tests : : Common : : BaseFunctionalTests : : Line ) ;
2015-05-27 12:08:46 +00:00
createWallets ( ) ;
miningTest ( ) ;
// create some address for mining
2015-07-30 15:22:07 +00:00
CryptoNote : : AccountBase stashAddress ;
2015-05-27 12:08:46 +00:00
stashAddress . generate ( ) ;
auto stashAddressStr = m_currency . accountAddressAsString ( stashAddress ) ;
unlockMoney ( stashAddressStr ) ;
std : : vector < uint64_t > balances ;
for ( auto & o : m_observers ) {
balances . push_back ( o - > totalBalance ( ) ) ;
}
printBalances ( ) ;
// transfer money from each wallet to each other
for ( size_t i = 0 ; i < m_nodeCount ; + + i ) {
auto & srcWallet = * m_wallets [ i ] ;
for ( size_t wi = 0 ; wi < m_nodeCount ; + + wi ) {
if ( i ! = wi ) {
2015-07-30 15:22:07 +00:00
CryptoNote : : WalletLegacyTransfer transfer ;
2015-05-27 12:08:46 +00:00
transfer . address = m_wallets [ wi ] - > getAddress ( ) ;
transfer . amount = ( i * 1000 + wi * 100 ) * m_currency . coin ( ) ;
logger ( INFO , BRIGHT_YELLOW ) < < " Sending from " < < shortAddress ( srcWallet . getAddress ( ) ) < < " to " < < shortAddress ( transfer . address ) < < " amount = " < < m_currency . formatAmount ( transfer . amount ) ;
auto txid = srcWallet . sendTransaction ( transfer , m_currency . minimumFee ( ) ) ;
balances [ i ] - = transfer . amount + m_currency . minimumFee ( ) ;
balances [ wi ] + = transfer . amount ;
auto res = m_observers [ i ] - > waitSendResult ( txid ) ;
if ( res ) {
logger ( ERROR , BRIGHT_RED ) < < " Failed to send transaction: " < < res . message ( ) ;
throw std : : runtime_error ( " Failed to send transaction: " + res . message ( ) ) ;
}
logger ( INFO ) < < " Sent successfully " ;
}
}
}
nodeDaemons [ 0 ] - > startMining ( 1 , stashAddressStr ) ;
for ( size_t i = 0 ; i < m_nodeCount ; + + i ) {
uint64_t total ;
logger ( INFO ) < < i < < " Expected target balance: " < < m_currency . formatAmount ( balances [ i ] ) ;
while ( ( total = m_wallets [ i ] - > pendingBalance ( ) + m_wallets [ i ] - > actualBalance ( ) ) ! = balances [ i ] ) {
logger ( INFO ) < < i < < " - total: " < < m_currency . formatAmount ( total ) < < " , waiting " ;
m_observers [ i ] - > waitTotalBalanceChange ( ) ;
}
}
nodeDaemons [ 0 ] - > stopMining ( ) ;
printBalances ( ) ;
}
void miningTest ( ) {
auto prevHeight = nodeDaemons [ 0 ] - > getLocalHeight ( ) ;
// mine block from each node to each wallet
for ( size_t i = 0 ; i < m_nodeCount ; + + i ) {
for ( size_t shift = 0 ; shift < m_nodeCount ; + + shift ) {
logger ( INFO , BRIGHT_YELLOW ) < < " Starting mining from node " < < i < < " -> wallet at node " < < shift ;
while ( nodeDaemons [ i ] - > getLocalHeight ( ) ! = prevHeight ) {
std : : this_thread : : sleep_for ( std : : chrono : : seconds ( 1 ) ) ;
}
logger ( INFO ) < < " Starting mining at height " < < prevHeight ;
nodeDaemons [ i ] - > startMining ( 1 , m_wallets [ shift ] - > getAddress ( ) ) ;
uint64_t newHeight = 0 ;
while ( ( newHeight = nodeDaemons [ i ] - > getLocalHeight ( ) ) = = prevHeight ) {
std : : this_thread : : sleep_for ( std : : chrono : : seconds ( 1 ) ) ;
}
nodeDaemons [ i ] - > stopMining ( ) ;
logger ( INFO ) < < " Block mined, new height = " < < newHeight ;
prevHeight = nodeDaemons [ i ] - > getLocalHeight ( ) ;
logger ( INFO , BRIGHT_YELLOW ) < < " Waiting for balance to change " ;
auto res = m_observers [ shift ] - > waitPendingBalanceChangeFor ( std : : chrono : : seconds ( m_currency . difficultyTarget ( ) * 5 ) ) ;
if ( ! res . first ) {
logger ( ERROR , BRIGHT_RED ) < < " Timeout waiting for balance to change! " ;
throw std : : runtime_error ( " Timeout " ) ;
}
}
}
}
void unlockMoney ( const std : : string & miningAddress ) {
logger ( INFO , BRIGHT_YELLOW ) < < " Starting to mine blocks to unlock money " ;
// unlock money
nodeDaemons [ 0 ] - > startMining ( 1 , miningAddress ) ;
for ( auto & o : m_observers ) {
o - > waitActualBalanceChange ( ) ;
}
nodeDaemons [ 0 ] - > stopMining ( ) ;
logger ( INFO , BRIGHT_YELLOW ) < < " Unlocked all, waiting for all daemons to sync blockchain " ;
auto minerHeight = nodeDaemons [ 0 ] - > getLocalHeight ( ) ;
logger ( INFO ) < < " Miner height: " < < minerHeight ;
bool unsynced = true ;
while ( unsynced ) {
unsynced = false ;
for ( auto & o : m_observers ) {
if ( o - > getCurrentHeight ( ) < minerHeight ) {
unsynced = true ;
break ;
}
}
if ( unsynced ) {
std : : this_thread : : sleep_for ( std : : chrono : : seconds ( 1 ) ) ;
}
}
logger ( INFO ) < < " OK " ;
}
void printBalances ( ) {
for ( auto & w : m_wallets ) {
auto pending = w - > pendingBalance ( ) ;
auto actual = w - > actualBalance ( ) ;
logger ( INFO , BRIGHT_GREEN ) < <
" Wallet " < < shortAddress ( w - > getAddress ( ) ) < <
" : " < < m_currency . formatAmount ( actual ) < <
" / " < < m_currency . formatAmount ( pending ) < <
" total = " < < m_currency . formatAmount ( pending + actual ) ;
}
}
void createWallets ( ) {
for ( auto & daemon : nodeDaemons ) {
std : : unique_ptr < INode > node ;
2015-07-30 15:22:07 +00:00
std : : unique_ptr < IWalletLegacy > wallet ;
2015-05-27 12:08:46 +00:00
daemon - > makeINode ( node ) ;
makeWallet ( wallet , node ) ;
2015-07-30 15:22:07 +00:00
std : : unique_ptr < WalletLegacyObserver > observer ( new WalletLegacyObserver ) ;
2015-05-27 12:08:46 +00:00
wallet - > addObserver ( observer . get ( ) ) ;
m_nodes . push_back ( std : : move ( node ) ) ;
m_wallets . push_back ( std : : move ( wallet ) ) ;
m_observers . push_back ( std : : move ( observer ) ) ;
}
}
void startShiftedMining ( size_t shift ) {
for ( size_t i = 0 ; i < m_nodeCount ; + + i ) {
nodeDaemons [ i ] - > startMining ( 1 , m_wallets [ ( i + shift ) % m_nodeCount ] - > getAddress ( ) ) ;
}
}
void waitAllPendingBalancesChange ( ) {
for ( auto & o : m_observers ) {
o - > waitPendingBalanceChange ( ) ;
}
}
void stopAllMining ( ) {
for ( auto & n : nodeDaemons ) {
n - > stopMining ( ) ;
}
}
private :
const size_t m_nodeCount ;
2015-07-30 15:22:07 +00:00
const Tests : : Common : : BaseFunctionalTestsConfig & m_config ;
2015-05-27 12:08:46 +00:00
std : : vector < std : : unique_ptr < INode > > m_nodes ;
2015-07-30 15:22:07 +00:00
std : : vector < std : : unique_ptr < IWalletLegacy > > m_wallets ;
std : : vector < std : : unique_ptr < WalletLegacyObserver > > m_observers ;
2015-05-27 12:08:46 +00:00
Logging : : LoggerRef logger ;
} ;
2015-07-30 15:22:07 +00:00
void testMultiVersion ( const CryptoNote : : Currency & currency , System : : Dispatcher & d , const Tests : : Common : : BaseFunctionalTestsConfig & config ) {
2015-05-27 12:08:46 +00:00
Logging : : ConsoleLogger log ;
MultiVersionTest test ( currency , d , config , log ) ;
test . run ( ) ;
}