Skip to content

Commit

Permalink
Merge branch 'v4.0.0' into feature/1900-remove-debug-symbols-release
Browse files Browse the repository at this point in the history
  • Loading branch information
olehnikolaiev authored Feb 27, 2025
2 parents cbdf7ba + b68a7f4 commit 9e6465b
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 8 deletions.
21 changes: 19 additions & 2 deletions libethereum/Block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,8 @@ tuple< TransactionReceipts, unsigned > Block::syncEveryone( BlockChain const& _b
m_receipts = m_state.safePartialTransactionReceipts( info().number() );
TransactionReceipts receipts = m_receipts;

TransactionReceipts receiptsOfCommited;

unsigned countBad = 0;

if ( m_receipts.size() > 0 ) {
Expand Down Expand Up @@ -548,6 +550,10 @@ tuple< TransactionReceipts, unsigned > Block::syncEveryone( BlockChain const& _b
ExecutionResult res =
execute( _bc.lastBlockHashes(), tr, Permanence::Committed, OnOpFunc(), i );

if ( !m_receipts.empty() ) {
receiptsOfCommited.push_back( m_receipts.back() );
}

if ( !SkipInvalidTransactionsPatch::isEnabledInWorkingBlock() ||
res.excepted != TransactionException::WouldNotBeInBlock ) {
receipts.push_back( m_receipts.back() );
Expand All @@ -557,7 +563,6 @@ tuple< TransactionReceipts, unsigned > Block::syncEveryone( BlockChain const& _b
++countBad;
}


} catch ( Exception& ex ) {
ex << errinfo_transactionIndex( i );
// throw;
Expand All @@ -573,7 +578,6 @@ tuple< TransactionReceipts, unsigned > Block::syncEveryone( BlockChain const& _b
// we got to the end of the block so we do not need partial transaction receipts anymore
m_state.safeRemoveAllPartialTransactionReceipts();


// since we committed changes corresponding to a particular block
// we need to create a new readonly snap
LDB_CHECK( m_state.getOriginalDb() );
Expand All @@ -587,6 +591,19 @@ tuple< TransactionReceipts, unsigned > Block::syncEveryone( BlockChain const& _b

LDB_CHECK( receipts.size() >= countBad );

if ( ClearPartialReceiptsPatch::isEnabledWhen( _timestamp ) ) {
// Making sure the old record was removed from the state db
// If it is the first block after patch timestamp
if ( !ClearPartialReceiptsPatch::isEnabledWhen( m_previousBlock.timestamp() ) ) {
m_state.safeRemoveLegacyPartialTransactionReceipts();
}
} else {
if ( !receiptsOfCommited.empty() ) {
// Saving partial receipts old way to be compatible with < 4.0 version
m_state.safeCommitLegacyPartialTransactionReceipts( receiptsOfCommited );
}
}

return make_tuple( receipts, receipts.size() - countBad );
}

Expand Down
4 changes: 4 additions & 0 deletions libethereum/SchainPatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ SchainPatchEnum getEnumForPatchName( const std::string& _patchName ) {
return SchainPatchEnum::FlexibleDeploymentPatch;
else if ( _patchName == "ExternalGasPatch" )
return SchainPatchEnum::ExternalGasPatch;
else if ( _patchName == "ClearPartialReceiptsPatch" )
return SchainPatchEnum::ClearPartialReceiptsPatch;
else if ( _patchName == "MaxFeePerGasPatch" )
return SchainPatchEnum::MaxFeePerGasPatch;
else
Expand Down Expand Up @@ -76,6 +78,8 @@ std::string getPatchNameForEnum( SchainPatchEnum _enumValue ) {
return "FlexibleDeploymentPatch";
case SchainPatchEnum::ExternalGasPatch:
return "ExternalGasPatch";
case SchainPatchEnum::ClearPartialReceiptsPatch:
return "ClearPartialReceiptsPatch";
case SchainPatchEnum::MaxFeePerGasPatch:
return "MaxFeePerGasPatch";
default:
Expand Down
7 changes: 7 additions & 0 deletions libethereum/SchainPatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class SchainPatch {
static std::atomic< time_t > committedBlockTimestamp;
};


#define DEFINE_AMNESIC_PATCH( CustomPatch ) \
class CustomPatch : public SchainPatch { \
public: \
Expand Down Expand Up @@ -146,6 +147,12 @@ DEFINE_SIMPLE_PATCH( FlexibleDeploymentPatch );
*/
DEFINE_SIMPLE_PATCH( ExternalGasPatch );

/*
* Purpose: do not save partial receipts after block is executed
* Version introduced: 4.0.0
*/
DEFINE_SIMPLE_PATCH( ClearPartialReceiptsPatch );

/*
* Context: fix the check in transaction constructor
* maxFeePerGas cannot be less than maxPriorityFeePerGas
Expand Down
1 change: 1 addition & 0 deletions libethereum/SchainPatchEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ enum class SchainPatchEnum {
VerifyBlsSyncPatch,
FlexibleDeploymentPatch,
ExternalGasPatch,
ClearPartialReceiptsPatch,
MaxFeePerGasPatch,
PatchesCount
};
Expand Down
33 changes: 32 additions & 1 deletion libskale/OverlayDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,38 @@ std::vector< dev::bytes > OverlayDB::getPartialTransactionReceipts(
return partialTransactionReceipts;
}

void OverlayDB::setLegacyPartialTransactionReceipts( const dev::bytes& _rawReceipt ) {
if ( m_db_face ) {
string legacyKey( "safeLastTransactionReceipts" );
m_db_face->insert( legacyKey, skale::slicing::toSlice( _rawReceipt ) );
m_db_face->commit( "Set legacy receipts" );
}
}

dev::bytes OverlayDB::getLegacyPartialTransactionReceipts() const {
dev::bytes legacyPartialTransactionReceipts;

string legacyKey( "safeLastTransactionReceipts" );

if ( m_db_face ) {
const std::string lookupResult = m_db_face->lookup( skale::slicing::toSlice( legacyKey ) );
if ( !lookupResult.empty() )
legacyPartialTransactionReceipts.insert(
legacyPartialTransactionReceipts.end(), lookupResult.begin(), lookupResult.end() );
}
return legacyPartialTransactionReceipts;
}

void OverlayDB::cleanupLegacyTransactionReceipts() {
string legacyKey( "safeLastTransactionReceipts" );
if ( m_db_face ) {
const std::string lookupResult = m_db_face->lookup( skale::slicing::toSlice( legacyKey ) );
if ( !lookupResult.empty() ) {
m_db_face->kill( legacyKey );
m_db_face->commit( "Cleanup legacy receipts" );
}
}
}

void OverlayDB::removeAllPartialTransactionReceipts() {
// first we get all keys
Expand All @@ -137,7 +169,6 @@ void OverlayDB::removeAllPartialTransactionReceipts() {
m_db_face->commit( "Clean partial keys" );
}


void OverlayDB::setLastExecutedTransactionHash( const dev::h256& _newHash ) {
this->lastExecutedTransactionHash = _newHash;
}
Expand Down
4 changes: 4 additions & 0 deletions libskale/OverlayDB.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ class OverlayDB {
void setPartialTransactionReceipt( const dev::bytes& _newReceipt,
dev::eth::BlockNumber _blockNumber, uint64_t _transactionIndex );

dev::bytes getLegacyPartialTransactionReceipts() const;
void setLegacyPartialTransactionReceipts( const dev::bytes& _newReceipt );
void cleanupLegacyTransactionReceipts();

// commit key-value pairs in storage
void commitStorageValues();
void commit();
Expand Down
32 changes: 31 additions & 1 deletion libskale/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,36 @@ void State::safeRemoveAllPartialTransactionReceipts() {
}


void State::safeRemoveLegacyPartialTransactionReceipts() {
if ( m_db_ptr ) {
m_db_ptr->cleanupLegacyTransactionReceipts();
}
}


dev::eth::TransactionReceipts State::safeLegacyPartialTransactionReceipts() {
if ( m_db_ptr ) {
auto rawTransactionReceipts = m_db_ptr->getLegacyPartialTransactionReceipts();
if ( !rawTransactionReceipts.empty() ) {
dev::RLP rlp( rawTransactionReceipts );
dev::eth::BlockReceipts blockReceipts( rlp );
return blockReceipts.receipts;
}
}
return dev::eth::TransactionReceipts();
}

void State::safeCommitLegacyPartialTransactionReceipts(
const dev::eth::TransactionReceipts& _receipts ) {
dev::eth::BlockReceipts blockReceipts;
blockReceipts.receipts.insert(
blockReceipts.receipts.begin(), _receipts.begin(), _receipts.end() );
if ( m_db_ptr ) {
m_db_ptr->setLegacyPartialTransactionReceipts( blockReceipts.rlp() );
}
}


void State::safeSetAndCommitPartialTransactionReceipt(
const dev::bytes& _receipt, dev::eth::BlockNumber _blockNumber, uint64_t _transactionIndex ) {
if ( m_db_ptr ) {
Expand Down Expand Up @@ -1224,4 +1254,4 @@ std::ostream& skale::operator<<( std::ostream& _out, State const& _s ) {
void State::createReadOnlyStateDBSnap( uint64_t _blockNumber ) {
LDB_CHECK( m_orig_db );
m_orig_db->createBlockSnap( _blockNumber );
}
}
6 changes: 6 additions & 0 deletions libskale/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,12 @@ class State {
dev::h256 safeLastExecutedTransactionHash();
dev::eth::TransactionReceipts safePartialTransactionReceipts(
dev::eth::BlockNumber _blockNumber );
void safeRemoveLegacyPartialTransactionReceipts();

void safeCommitLegacyPartialTransactionReceipts(
const dev::eth::TransactionReceipts& _receipts );
dev::eth::TransactionReceipts safeLegacyPartialTransactionReceipts();

void safeRemoveAllPartialTransactionReceipts();


Expand Down
79 changes: 75 additions & 4 deletions test/unittests/libweb3jsonrpc/jsonrpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,9 @@ struct RestrictedAddressFixture : public JsonRpcFixture {
ownerAddress = Address( "00000000000000000000000000000000000000AA" );
std::string fileName = "test";
path = dev::getDataDir() / "filestorage" / Address( ownerAddress ).hex() / fileName;
if ( boost::filesystem::exists( path ) ) {
boost::filesystem::remove_all( path );
}
data =
( "0x"
"00000000000000000000000000000000000000000000000000000000000000AA"
Expand Down Expand Up @@ -1734,7 +1737,7 @@ BOOST_AUTO_TEST_CASE( simplePoWTransaction ) {
auto latestBlockNumber = fixture.client->blockInfo(fixture.client->hashFromNumber(LatestBlock)).number();

// wait for patch turning on and see how it happens
string txHash;
string txHash;
BlockHeader badInfo, goodInfo;
uint64_t blockCounter = 2;
for ( ;; ) {
Expand Down Expand Up @@ -1773,6 +1776,72 @@ BOOST_AUTO_TEST_CASE( simplePoWTransaction ) {
BOOST_REQUIRE_EQUAL( receipt["status"], "0x1" );
}

BOOST_AUTO_TEST_CASE( clearPartialReceipts ) {
// Prepare fixture
std::string _config = c_genesisConfigString;
Json::Value ret;
Json::Reader().parse( _config, ret );

std::string chainID = "0x97"; // 151
ret["params"]["chainID"] = chainID;
time_t clearPartialReceiptsActivationTs = time(nullptr) + 10;
ret["skaleConfig"]["sChain"]["clearPartialReceiptsPatchTimestamp"] = clearPartialReceiptsActivationTs;

Json::FastWriter fastWriter;
std::string config = fastWriter.write( ret );
JsonRpcFixture fixture( config );

// To fill coinbase wallet
dev::eth::simulateMining( *( fixture.client ), 20 );

string senderAddress = toJS(fixture.coinbase.address());

Json::Value transactionCallObject;
transactionCallObject["from"] = toJS( senderAddress );
transactionCallObject["to"] = "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a";
transactionCallObject["data"] = "0x28b5e32b";

TransactionSkeleton ts = toTransactionSkeleton( transactionCallObject );
ts = fixture.client->populateTransactionWithDefaults( ts );
pair< bool, Secret > ar = fixture.accountHolder->authenticate( ts );
Transaction tx( ts, ar.second );

auto txHash = fixture.rpcClient->eth_sendRawTransaction( toJS( tx.toBytes() ) );
dev::eth::mineTransaction( *( fixture.client ), 1 );
auto receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
dev::eth::BlockNumber blockNumber = jsToInt(receipt["blockNumber"].asString());
State state( fixture.client->state() );
BOOST_REQUIRE_EQUAL( state.safePartialTransactionReceipts(blockNumber).size(), 0 );
BOOST_REQUIRE_EQUAL( state.safeLegacyPartialTransactionReceipts().size(), 1 );

sleep(10);

ts = toTransactionSkeleton( transactionCallObject );
ts = fixture.client->populateTransactionWithDefaults( ts );
ar = fixture.accountHolder->authenticate( ts );
Transaction txAfter( ts, ar.second );

auto txHashAfter = fixture.rpcClient->eth_sendRawTransaction( toJS( txAfter.toBytes() ) );
dev::eth::mineTransaction( *( fixture.client ), 1 );
auto receiptAfter = fixture.rpcClient->eth_getTransactionReceipt( txHashAfter );
dev::eth::BlockNumber blockNumberAfter = jsToInt(receiptAfter["blockNumber"].asString());
BOOST_REQUIRE_EQUAL( state.safePartialTransactionReceipts(blockNumberAfter).size(), 0 );
BOOST_REQUIRE_EQUAL( state.safeLegacyPartialTransactionReceipts().size(), 0 );


ts = toTransactionSkeleton( transactionCallObject );
ts = fixture.client->populateTransactionWithDefaults( ts );
ar = fixture.accountHolder->authenticate( ts );
Transaction txAfterAgain( ts, ar.second );

auto txHashAfterAgain = fixture.rpcClient->eth_sendRawTransaction( toJS( txAfterAgain.toBytes() ) );
dev::eth::mineTransaction( *( fixture.client ), 1 );
auto receiptAfterAgain = fixture.rpcClient->eth_getTransactionReceipt( txHashAfterAgain );
dev::eth::BlockNumber blockNumberAfterAgain = jsToInt(receiptAfterAgain["blockNumber"].asString());
BOOST_REQUIRE_EQUAL( state.safePartialTransactionReceipts(blockNumberAfterAgain).size(), 0 );
BOOST_REQUIRE_EQUAL( state.safeLegacyPartialTransactionReceipts().size(), 0 );
}

BOOST_AUTO_TEST_CASE( recalculateExternalGas ) {
std::string _config = c_genesisConfigString;
Json::Value ret;
Expand Down Expand Up @@ -3007,11 +3076,11 @@ BOOST_AUTO_TEST_CASE( debugGetPatchTimestamps ) {

std::string patchName = getPatchNameForEnum(patchEnum) + "Timestamp";
patchName[0] = tolower( patchName[0] );
configJson["skaleConfig"]["sChain"][patchName] = ts;
configJson["skaleConfig"]["sChain"][patchName] = ts;
}

Json::FastWriter fastWriter;
std::string customConfigFile = fastWriter.write( configJson );
std::string customConfigFile = fastWriter.write( configJson );

JsonRpcFixture fixture(customConfigFile, false, false, false, false);
Json::Value returnedPatchTimestamps = fixture.rpcClient->debug_getPatchTimestamps();
Expand All @@ -3022,7 +3091,7 @@ BOOST_AUTO_TEST_CASE( debugGetPatchTimestamps ) {

std::string patchName = getPatchNameForEnum(patchEnum) + "Timestamp";
patchName[0] = tolower( patchName[0] );
size_t returnedTimestamp = static_cast< size_t > (returnedPatchTimestamps[patchName].asInt());
size_t returnedTimestamp = static_cast< size_t > (returnedPatchTimestamps[patchName].asInt());

BOOST_REQUIRE_EQUAL( returnedTimestamp, patchTimestamps[patchIdx]);
}
Expand Down Expand Up @@ -3728,6 +3797,8 @@ BOOST_AUTO_TEST_CASE( maxFeePerGasPatch ) {
txHash = fixture.rpcClient->eth_sendTransaction( txRefill );
dev::eth::mineTransaction( *( fixture.client ), 1 );

sleep( 1 );

// send a txn with maxPriorityFeePerGas > maxFeePerGas after MaxFeePerGasPatchTimestamp, it should fail
BOOST_REQUIRE_THROW( fixture.rpcClient->eth_sendRawTransaction( "0x02f86d8197018504a817c8018504a817c800827530947d36af85a184e220a656525fcbb9a63b9ab3c12b8080c080a0aea5ff86373cbbbb33c9f3e9a25ceb9a694ee71beff452a4d29903d73fd30ca9a00458d4f7d54be178b42d230cc5a4740540d55b8ca0f9c74c79c1d49f6686b1e6" ), jsonrpc::JsonRpcException ); // INVALID_PARAMS
}
Expand Down

0 comments on commit 9e6465b

Please sign in to comment.