Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

1270 Remove consensus blocks from snapshots #1323

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libconsensus
16 changes: 14 additions & 2 deletions libethereum/Client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,9 @@ void Client::stopWorking() {
}


void Client::injectSkaleHost( std::shared_ptr< SkaleHost > _skaleHost ) {
void Client::injectSkaleHost( std::shared_ptr< SkaleHost > _skaleHost,
std::shared_ptr< std::vector< std::uint8_t > >
_startingFromSnapshotWithThisAsLastBlock) {
assert( !m_skaleHost );

m_skaleHost = _skaleHost;
Expand Down Expand Up @@ -652,7 +654,17 @@ size_t Client::importTransactionsAsBlock(
m_debugTracer.tracepoint( "doing_snapshot" );

t1 = boost::chrono::high_resolution_clock::now();
m_snapshotManager->doSnapshot( block_number );


// get serialized last consensus block

if ( !m_skaleHost ) {
throw std::runtime_error( "Null skalehost in " + string(__FUNCTION__) );
}

m_snapshotManager->doSnapshot( block_number,
m_skaleHost->getSerializedConsensusBlock(block_number));

t2 = boost::chrono::high_resolution_clock::now();
this->snapshot_calculation_time_ms =
boost::chrono::duration_cast< boost::chrono::milliseconds >( t2 - t1 ).count();
Expand Down
10 changes: 5 additions & 5 deletions libethereum/Client.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ class Client : public ClientBase, protected Worker {

void stopWorking();

void injectSkaleHost( std::shared_ptr< SkaleHost > _skaleHost = nullptr );

void injectSkaleHost( std::shared_ptr< SkaleHost > _skaleHost,
std::shared_ptr< std::vector< std::uint8_t > > _startingFromSnapshotWithThisAsLastBlock );
/// Get information on this chain.
ChainParams const& chainParams() const { return bc().chainParams(); }

Expand Down Expand Up @@ -245,10 +245,11 @@ class Client : public ClientBase, protected Worker {
Block latestBlock() const;

/// should be called after the constructor of the most derived class finishes.
void startWorking() {
void startWorking(std::shared_ptr< std::vector< std::uint8_t > >
_startingFromSnapshotWithThisAsLastBlock) {
assert( m_skaleHost );
Worker::startWorking(); // these two lines are dependent!!
m_skaleHost->startWorking();
m_skaleHost->startWorking(_startingFromSnapshotWithThisAsLastBlock);
};

/// Change the function that is called when a new block is imported
Expand Down Expand Up @@ -380,7 +381,6 @@ class Client : public ClientBase, protected Worker {
Block blockByNumber( BlockNumber _h ) const;
#endif

protected:
/// Called when Worker is starting.
void startedWorking() override;

Expand Down
2 changes: 1 addition & 1 deletion libethereum/ConsensusStub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void ConsensusStub::parseFullConfigAndCreateNode( const std::string&, const std:
// TODO think this architecture thoroughly
}

void ConsensusStub::startAll() {
void ConsensusStub::startAll( std::shared_ptr< std::vector< std::uint8_t > > ) {
Worker::startWorking();
}

Expand Down
5 changes: 4 additions & 1 deletion libethereum/ConsensusStub.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ class ConsensusStub : private dev::Worker, public ConsensusInterface {
~ConsensusStub() override;
void parseFullConfigAndCreateNode(
const std::string& _jsonConfig, const string& _gethURL ) override;
void startAll() override;

void startAll(
std::shared_ptr< std::vector< std::uint8_t > > _startingFromSnapshotWithThisAsLastBlock )
override;
void bootStrapAll() override;
void exitGracefully() override;
u256 getPriceForBlockId( uint64_t /*_blockId*/ ) const override { return 1000; }
Expand Down
16 changes: 15 additions & 1 deletion libethereum/SkaleHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,16 @@ class unlock_guard {
void will_exit() { m_will_exit = true; }
};



std::shared_ptr<std::vector<std::uint8_t>> SkaleHost::getSerializedConsensusBlock(
std::uint64_t _blockNumber) {
if (!m_extFace) {
throw std::runtime_error("Null m_extFace in " + string(__FUNCTION__));
}
return this->m_consensus->getSerializedBlock((uint64_t)_blockNumber);
};

ConsensusExtFace::transactions_vector SkaleHost::pendingTransactions(
size_t _limit, u256& _stateRoot ) {
assert( _limit > 0 );
Expand Down Expand Up @@ -773,7 +783,11 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro
cerror << "\n" << skutils::signal::generate_stack_trace() << "\n" << std::endl;
}

void SkaleHost::startWorking() {
// If starting from a snapshot, startWorking() all will pass to consensus the last comitted
// block coming from the snapshot. Normally, nullptr is passed.
void SkaleHost::startWorking(
std::shared_ptr< std::vector< std::uint8_t > >
_startingFromSnapshotWithThisAsLastBlock) {
if ( working )
return;

Expand Down
8 changes: 7 additions & 1 deletion libethereum/SkaleHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ class SkaleHost {
const std::string& _gethURL = "", bool _broadcastEnabled = true );
virtual ~SkaleHost();

void startWorking();
void startWorking(std::shared_ptr< std::vector< std::uint8_t > >
_startingFromSnapshotWithThisAsLastBlock);
void stopWorking();
bool isWorking() const { return this->working; }
bool exitedForcefully() const { return m_exitedForcefully; }
Expand Down Expand Up @@ -148,6 +149,11 @@ class SkaleHost {

SkaleDebugInterface::handler getDebugHandler() const { return m_debugHandler; }

// Get serialized consensus block for a particular block number
// this is used for snapshots
std::shared_ptr<std::vector<std::uint8_t>> getSerializedConsensusBlock(
std::uint64_t _blockNumber);

private:
std::atomic_bool working = false;
std::atomic_bool m_exitedForcefully = false;
Expand Down
24 changes: 23 additions & 1 deletion libskale/SnapshotManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ SnapshotManager::SnapshotManager( const fs::path& _dataDir,
// - exists
// - cannot read
// - cannot write
void SnapshotManager::doSnapshot( unsigned _blockNumber ) {
void SnapshotManager::doSnapshot( unsigned _blockNumber,
std::shared_ptr<std::vector<std::uint8_t>> _serializedLastConsensusBlock) {
fs::path snapshot_dir = snapshots_dir / to_string( _blockNumber );

UnsafeRegion::lock ur_lock;
Expand All @@ -125,6 +126,27 @@ void SnapshotManager::doSnapshot( unsigned _blockNumber ) {
} // catch

int dummy_counter = 0;


// consensus needs the last block to operate after a start from the snapshot
// just before creating snapshot, we copy the last consensus block
// if it was passed to us as a file into the prices.dir
if ( !_serializedLastConsensusBlock ) {
throw std::runtime_error( "Null consensus block in " + string( __FUNCTION__ ) );
}

auto pricesDir = volumes.at( SNAPSHOT_PRICES_DIR_INDEX );

// if file does not exist, it will be created, if exists it will be overwritten
std::ofstream outputFile(
pricesDir + "/" + LAST_CONSENSUS_BLOCK_FILE_NAME, std::ios::binary | std::ios::out );

outputFile.write( ( const char* ) _serializedLastConsensusBlock->data(),
_serializedLastConsensusBlock->size() );
outputFile.close();


// Now create shapshot for all volumes
for ( const string& vol : volumes ) {
int res = btrfs.subvolume.snapshot_r( ( data_dir / vol ).c_str(), snapshot_dir.c_str() );
if ( res )
Expand Down
12 changes: 10 additions & 2 deletions libskale/SnapshotManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@
#include <string>
#include <vector>

const std::string SNAPSHOT_PRICES_PREFIX = "prices_";
const std::string LAST_CONSENSUS_BLOCK_FILE_NAME = "last_consensus_block.bin";

constexpr std::uint64_t SNAPSHOT_PRICES_DIR_INDEX = 2;



class SnapshotManager {
//////////////////////// EXCEPTIONS /////////////////////

Expand Down Expand Up @@ -154,9 +161,10 @@ class SnapshotManager {
public:
SnapshotManager( const boost::filesystem::path& _dataDir,
const std::vector< std::string >& _volumes, const std::string& diffs_dir = std::string() );
void doSnapshot( unsigned _blockNumber );
void doSnapshot( unsigned _blockNumber,
std::shared_ptr<std::vector<std::uint8_t>> _serializedLastConsensusBlock );
void restoreSnapshot( unsigned _blockNumber );
boost::filesystem::path makeOrGetDiff( unsigned _toBlock );
boost::filesystem::path makeOrGetDiff( unsigned _toBlock);
void importDiff( unsigned _toBlock );
boost::filesystem::path getDiffPath( unsigned _toBlock );
void removeSnapshot( unsigned _blockNumber );
Expand Down
14 changes: 10 additions & 4 deletions skaled/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,11 @@ void downloadSnapshot( unsigned block_number, std::shared_ptr< SnapshotManager >
}

/// HACK refactor this piece of code! ///
vector< string > prefixes{ "prices_", "blocks_" };
// consensus prices directory now contains in addition to
// prices and the last consensus block
// this is the minimum needed for consensus to work well after a start
// from snapshot.
vector< string > prefixes{ SNAPSHOT_PRICES_PREFIX};
for ( const string& prefix : prefixes ) {
fs::path db_path;
for ( auto& f :
Expand Down Expand Up @@ -1511,11 +1515,13 @@ int main( int argc, char** argv ) try {
// auto mostRecentBlocksDBPath = (getDataDir() / ( "blocks_" + chainParams.nodeInfo.id.str()
// + ".db" )) / "1.db";

// PRICES directory contains prices and the last consensus block
// This is the minimum needed for consensus to work. In particular,
// consensus needs the previous block to make sure that the proposal time stamp
// is more or equal the previous block timestamp
snapshotManager.reset( new SnapshotManager( getDataDir(),
{ BlockChain::getChainDirName( chainParams ), "filestorage",
"prices_" + chainParams.nodeInfo.id.str() + ".db",
"blocks_" + chainParams.nodeInfo.id.str() + ".db"/*,
mostRecentBlocksDBPath.string()*/ },
SNAPSHOT_PRICES_PREFIX + chainParams.nodeInfo.id.str() + ".db" },
sharedSpace ? sharedSpace->getPath() : "" ) );
}

Expand Down
18 changes: 14 additions & 4 deletions test/unittests/libskale/HashSnapshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,16 @@ boost::unit_test::assertion_result option_all_test( boost::unit_test::test_unit_
}

namespace dev {
namespace test {
namespace test
{


std::shared_ptr<std::vector<std::uint8_t>> getSampleLastConsensusBlock() {
std::shared_ptr<vector<uint8_t>> sampleLastConsensusBlock;
sampleLastConsensusBlock.reset(new vector<uint8_t> { 1, 2, 3, 4, 5});
return sampleLastConsensusBlock;
}

class SnapshotHashAgentTest {
public:
SnapshotHashAgentTest( ChainParams& _chainParams, bool requireSnapshotMajority = true ) {
Expand Down Expand Up @@ -515,6 +524,7 @@ BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE( HashSnapshotTestSuite, *boost::unit_test::precondition( option_all_test ) )


BOOST_FIXTURE_TEST_CASE( SnapshotHashingTest, SnapshotHashingFixture,
*boost::unit_test::precondition( dev::test::run_not_express ) ) {
auto senderAddress = coinbase.address();
Expand All @@ -529,11 +539,11 @@ BOOST_FIXTURE_TEST_CASE( SnapshotHashingTest, SnapshotHashingFixture,
const int blocksToMine = 1;
dev::eth::simulateMining( *( client ), blocksToMine );

mgr->doSnapshot( 1 );
mgr->doSnapshot( 1 , getSampleLastConsensusBlock());
mgr->computeSnapshotHash( 1 );

dev::eth::simulateMining( *( client ), blocksToMine );
mgr->doSnapshot( 2 );
mgr->doSnapshot( 2 , getSampleLastConsensusBlock());

mgr->computeSnapshotHash( 2 );

Expand All @@ -554,7 +564,7 @@ BOOST_FIXTURE_TEST_CASE( SnapshotHashingTest, SnapshotHashingFixture,

BOOST_FIXTURE_TEST_CASE( SnapshotHashingFileStorageTest, SnapshotHashingFixture,
*boost::unit_test::precondition( dev::test::run_not_express ) ) {
mgr->doSnapshot( 4 );
mgr->doSnapshot( 4 , getSampleLastConsensusBlock());

mgr->computeSnapshotHash( 4, true );

Expand Down
Loading