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

Bug/1994 max fee per gas check #2073

Open
wants to merge 9 commits into
base: v4.0.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
20 changes: 11 additions & 9 deletions libethcore/TransactionBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ std::vector< bytes > validateAccessListRLP( const RLP& _data ) {
return {};
}


for ( const auto& d : rlpList ) {
if ( !d.isList() )
BOOST_THROW_EXCEPTION( InvalidTransactionFormat() << errinfo_comment(
Expand Down Expand Up @@ -236,8 +235,8 @@ void TransactionBase::fillFromBytesType1(
}
}

void TransactionBase::fillFromBytesType2(
bytesConstRef _rlpData, CheckTransaction _checkSig, bool _allowInvalid ) {
void TransactionBase::fillFromBytesType2( bytesConstRef _rlpData, CheckTransaction _checkSig,
bool _allowInvalid, bool _maxFeePerGasPatchEnabled ) {
bytes croppedRlp( _rlpData.begin() + 1, _rlpData.end() );
RLP const rlp( croppedRlp );
try {
Expand All @@ -249,7 +248,9 @@ void TransactionBase::fillFromBytesType2(
m_nonce = rlp[1].toInt< u256 >();
m_maxPriorityFeePerGas = rlp[2].toInt< u256 >();
m_maxFeePerGas = rlp[3].toInt< u256 >();
if ( m_maxPriorityFeePerGas > m_maxPriorityFeePerGas )

auto toCompare = _maxFeePerGasPatchEnabled ? m_maxFeePerGas : m_maxPriorityFeePerGas;
if ( m_maxPriorityFeePerGas > toCompare )
BOOST_THROW_EXCEPTION( InvalidTransactionFormat() << errinfo_comment(
"maxFeePerGas cannot be less than maxPriorityFeePerGas (The "
"total must be the larger of the two)" ) );
Expand Down Expand Up @@ -305,7 +306,7 @@ void TransactionBase::fillFromBytesType2(
}

void TransactionBase::fillFromBytesByType( bytesConstRef _rlpData, CheckTransaction _checkSig,
bool _allowInvalid, TransactionType _type ) {
bool _allowInvalid, TransactionType _type, bool _maxFeePerGasPatchEnabled ) {
switch ( _type ) {
case TransactionType::Legacy:
fillFromBytesLegacy( _rlpData, _checkSig, _allowInvalid );
Expand All @@ -314,7 +315,7 @@ void TransactionBase::fillFromBytesByType( bytesConstRef _rlpData, CheckTransact
fillFromBytesType1( _rlpData, _checkSig, _allowInvalid );
break;
case TransactionType::Type2:
fillFromBytesType2( _rlpData, _checkSig, _allowInvalid );
fillFromBytesType2( _rlpData, _checkSig, _allowInvalid, _maxFeePerGasPatchEnabled );
break;
default:
BOOST_THROW_EXCEPTION(
Expand All @@ -331,13 +332,14 @@ TransactionType TransactionBase::getTransactionType( bytesConstRef _rlp ) {
return TransactionType( _rlp[0] );
}

TransactionBase::TransactionBase(
bytesConstRef _rlpData, CheckTransaction _checkSig, bool _allowInvalid, bool _eip1559Enabled ) {
TransactionBase::TransactionBase( bytesConstRef _rlpData, CheckTransaction _checkSig,
bool _allowInvalid, bool _eip1559Enabled, bool _maxFeePerGasPatchEnabled ) {
MICROPROFILE_SCOPEI( "TransactionBase", "ctor", MP_GOLD2 );
try {
if ( _eip1559Enabled ) {
TransactionType txnType = getTransactionType( _rlpData );
fillFromBytesByType( _rlpData, _checkSig, _allowInvalid, txnType );
fillFromBytesByType(
_rlpData, _checkSig, _allowInvalid, txnType, _maxFeePerGasPatchEnabled );
} else {
fillFromBytesLegacy( _rlpData, _checkSig, _allowInvalid );
}
Expand Down
15 changes: 9 additions & 6 deletions libethcore/TransactionBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,15 @@ class TransactionBase {

/// Constructs a transaction from the given RLP.
explicit TransactionBase( bytesConstRef _rlp, CheckTransaction _checkSig,
bool _allowInvalid = false, bool _eip1559Enabled = false );
bool _allowInvalid = false, bool _eip1559Enabled = false,
bool _maxFeePerGasPatchEnabled = false );

/// Constructs a transaction from the given RLP.
explicit TransactionBase( bytes const& _rlp, CheckTransaction _checkSig,
bool _allowInvalid = false, bool _eip1559Enabled = false )
: TransactionBase( &_rlp, _checkSig, _allowInvalid, _eip1559Enabled ) {}
bool _allowInvalid = false, bool _eip1559Enabled = false,
bool _maxFeePerGasPatchEnabled = false )
: TransactionBase(
&_rlp, _checkSig, _allowInvalid, _eip1559Enabled, _maxFeePerGasPatchEnabled ) {}

TransactionBase( TransactionBase const& ) = default;

Expand Down Expand Up @@ -329,13 +332,13 @@ class TransactionBase {

/// Constructs a transaction from the given RLP and transaction type.
void fillFromBytesByType( bytesConstRef _rlpData, CheckTransaction _checkSig,
bool _allowInvalid, TransactionType _type );
bool _allowInvalid, TransactionType _type, bool _maxFeePerGasPatchEnabled );
void fillFromBytesLegacy(
bytesConstRef _rlpData, CheckTransaction _checkSig, bool _allowInvalid );
void fillFromBytesType1(
bytesConstRef _rlpData, CheckTransaction _checkSig, bool _allowInvalid );
void fillFromBytesType2(
bytesConstRef _rlpData, CheckTransaction _checkSig, bool _allowInvalid );
void fillFromBytesType2( bytesConstRef _rlpData, CheckTransaction _checkSig, bool _allowInvalid,
bool _maxFeePerGasPatchEnabled );

void streamLegacyTransaction( RLPStream& _s, IncludeSignature _sig, bool _forEip155hash ) const;
void streamType1Transaction( RLPStream& _s, IncludeSignature _sig ) const;
Expand Down
2 changes: 2 additions & 0 deletions libethereum/BlockChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,8 @@ VerifiedBlockRef BlockChain::verifyBlock( bytesConstRef _block,
CheckTransaction::None,
false,
EIP1559TransactionsPatch::isEnabledWhen(
this->info( numberHash( h.number() - 1 ) ).timestamp() ),
MaxFeePerGasPatch::isEnabledWhen(
this->info( numberHash( h.number() - 1 ) ).timestamp() ) );
Ethash::verifyTransaction( chainParams(), _ir, t,
this->info( numberHash( h.number() - 1 ) ).timestamp(), h,
Expand Down
10 changes: 10 additions & 0 deletions libethereum/ClientBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ Transaction ClientBase::transaction( h256 _transactionHash ) const {
auto tl = bc().transactionLocation( _transactionHash );
return Transaction( bc().transaction( _transactionHash ), CheckTransaction::Cheap, true,
EIP1559TransactionsPatch::isEnabledWhen(
blockInfo( numberFromHash( tl.first ) - 1 ).timestamp() ),
MaxFeePerGasPatch::isEnabledWhen(
blockInfo( numberFromHash( tl.first ) - 1 ).timestamp() ) );
}

Expand All @@ -377,6 +379,8 @@ Transaction ClientBase::transaction( h256 _blockHash, unsigned _i ) const {
// allow invalid
return Transaction( b[1][_i].data(), CheckTransaction::Cheap, true,
EIP1559TransactionsPatch::isEnabledWhen(
blockInfo( numberFromHash( _blockHash ) - 1 ).timestamp() ),
DmytroNazarenko marked this conversation as resolved.
Show resolved Hide resolved
MaxFeePerGasPatch::isEnabledWhen(
blockInfo( numberFromHash( _blockHash ) - 1 ).timestamp() ) );
else
return Transaction();
Expand All @@ -386,6 +390,8 @@ LocalisedTransaction ClientBase::localisedTransaction( h256 const& _blockHash, u
// allow invalid
Transaction t = Transaction( bc().transaction( _blockHash, _i ), CheckTransaction::Cheap, true,
EIP1559TransactionsPatch::isEnabledWhen(
blockInfo( numberFromHash( _blockHash ) - 1 ).timestamp() ),
MaxFeePerGasPatch::isEnabledWhen(
blockInfo( numberFromHash( _blockHash ) - 1 ).timestamp() ) );
return LocalisedTransaction( t, _blockHash, _i, numberFromHash( _blockHash ) );
}
Expand All @@ -401,6 +407,8 @@ LocalisedTransactionReceipt ClientBase::localisedTransactionReceipt(
Transaction t =
Transaction( bc().transaction( tl.first, tl.second ), CheckTransaction::Cheap, true,
EIP1559TransactionsPatch::isEnabledWhen(
blockInfo( numberFromHash( tl.first ) - 1 ).timestamp() ),
MaxFeePerGasPatch::isEnabledWhen(
blockInfo( numberFromHash( tl.first ) - 1 ).timestamp() ) );
TransactionReceipt tr = bc().transactionReceipt( tl.first, tl.second );
u256 gasUsed = tr.cumulativeGasUsed();
Expand Down Expand Up @@ -436,6 +444,8 @@ Transactions ClientBase::transactions( h256 _blockHash ) const {
auto txRlp = b[1][i];
res.emplace_back( bytesRefFromTransactionRlp( txRlp ), CheckTransaction::Cheap, true,
EIP1559TransactionsPatch::isEnabledWhen(
blockInfo( numberFromHash( _blockHash ) - 1 ).timestamp() ),
MaxFeePerGasPatch::isEnabledWhen(
blockInfo( numberFromHash( _blockHash ) - 1 ).timestamp() ) );
}
return res;
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 == "MaxFeePerGasPatch" )
return SchainPatchEnum::MaxFeePerGasPatch;
else
throw std::out_of_range( _patchName );
}
Expand Down Expand Up @@ -76,6 +78,8 @@ std::string getPatchNameForEnum( SchainPatchEnum _enumValue ) {
return "FlexibleDeploymentPatch";
case SchainPatchEnum::ExternalGasPatch:
return "ExternalGasPatch";
case SchainPatchEnum::MaxFeePerGasPatch:
return "MaxFeePerGasPatch";
default:
throw std::out_of_range(
"UnknownPatch #" + std::to_string( static_cast< size_t >( _enumValue ) ) );
Expand Down
6 changes: 6 additions & 0 deletions libethereum/SchainPatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,10 @@ DEFINE_SIMPLE_PATCH( FlexibleDeploymentPatch );
*/
DEFINE_SIMPLE_PATCH( ExternalGasPatch );

/*
* Context: fix the check in transaction constructor
* maxFeePerGas cannot be less than maxPriorityFeePerGas
*/
DEFINE_SIMPLE_PATCH( MaxFeePerGasPatch );

#endif // SCHAINPATCH_H
1 change: 1 addition & 0 deletions libethereum/SchainPatchEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum class SchainPatchEnum {
VerifyBlsSyncPatch,
FlexibleDeploymentPatch,
ExternalGasPatch,
MaxFeePerGasPatch,
PatchesCount
};

Expand Down
4 changes: 2 additions & 2 deletions libethereum/SkaleHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,8 @@ h256 SkaleHost::receiveTransaction( std::string _rlp ) {
}

Transaction transaction( jsToBytes( _rlp, OnFailed::Throw ), CheckTransaction::None, false,
EIP1559TransactionsPatch::isEnabledInWorkingBlock() );
EIP1559TransactionsPatch::isEnabledInWorkingBlock(),
MaxFeePerGasPatch::isEnabledInWorkingBlock() );
h256 sha = transaction.sha3();

//
Expand Down Expand Up @@ -575,7 +576,6 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro
h256 sha = sha3( data );
LOG( m_traceLogger ) << "Arrived txn: " << sha;


Transaction t( data, CheckTransaction::Everything, true,
EIP1559TransactionsPatch::isEnabledInWorkingBlock() );
t.checkOutExternalGas(
Expand Down
15 changes: 8 additions & 7 deletions libethereum/Transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,14 @@ Transaction::Transaction( const u256& _value, const u256& _gasPrice, const u256&
const bytes& _data, const u256& _nonce )
: TransactionBase( _value, _gasPrice, _gas, _data, _nonce ) {}

Transaction::Transaction(
bytesConstRef _rlpData, CheckTransaction _checkSig, bool _allowInvalid, bool _eip1559Enabled )
: TransactionBase( _rlpData, _checkSig, _allowInvalid, _eip1559Enabled ) {}

Transaction::Transaction(
const bytes& _rlp, CheckTransaction _checkSig, bool _allowInvalid, bool _eip1559Enabled )
: Transaction( &_rlp, _checkSig, _allowInvalid, _eip1559Enabled ) {}
Transaction::Transaction( bytesConstRef _rlpData, CheckTransaction _checkSig, bool _allowInvalid,
bool _eip1559Enabled, bool _maxFeePerGasPatchEnabled )
: TransactionBase(
_rlpData, _checkSig, _allowInvalid, _eip1559Enabled, _maxFeePerGasPatchEnabled ) {}

Transaction::Transaction( const bytes& _rlp, CheckTransaction _checkSig, bool _allowInvalid,
bool _eip1559Enabled, bool _maxFeePerGasPatchEnabled )
: Transaction( &_rlp, _checkSig, _allowInvalid, _eip1559Enabled, _maxFeePerGasPatchEnabled ) {}

bool Transaction::hasExternalGas() const {
if ( !m_externalGasIsChecked ) {
Expand Down
5 changes: 3 additions & 2 deletions libethereum/Transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,12 @@ class Transaction : public TransactionBase {

/// Constructs a transaction from the given RLP.
explicit Transaction( bytesConstRef _rlp, CheckTransaction _checkSig,
bool _allowInvalid = false, bool _eip1559Enabled = false );
bool _allowInvalid = false, bool _eip1559Enabled = false,
bool _maxFeePerGasPatchEnabled = false );

/// Constructs a transaction from the given RLP.
explicit Transaction( bytes const& _rlp, CheckTransaction _checkSig, bool _allowInvalid = false,
bool _eip1559Enabled = false );
bool _eip1559Enabled = false, bool _maxFeePerGasPatchEnabled = false );

Transaction( Transaction const& ) = default;

Expand Down
8 changes: 5 additions & 3 deletions libethereum/TransactionQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ ImportResult TransactionQueue::import(
bytesConstRef _transactionRLP, IfDropped _ik, bool _isFuture ) {
try {
Transaction t = Transaction( _transactionRLP, CheckTransaction::Everything, false,
EIP1559TransactionsPatch::isEnabledInWorkingBlock() );
EIP1559TransactionsPatch::isEnabledInWorkingBlock(),
MaxFeePerGasPatch::isEnabledInWorkingBlock() );
return import( t, _ik, _isFuture );
} catch ( Exception const& ) {
return ImportResult::Malformed;
Expand Down Expand Up @@ -528,8 +529,9 @@ void TransactionQueue::verifierBody() {

try {
Transaction t( work.transaction, CheckTransaction::Cheap, false,
EIP1559TransactionsPatch::isEnabledInWorkingBlock() ); // Signature will be
// checked later
EIP1559TransactionsPatch::isEnabledInWorkingBlock(),
MaxFeePerGasPatch::isEnabledInWorkingBlock() ); // Signature will be
// checked later
ImportResult ir = import( t );
m_onImport( ir, t.sha3(), work.nodeId );
} catch ( ... ) {
Expand Down
6 changes: 4 additions & 2 deletions libweb3jsonrpc/Eth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,8 @@ Json::Value Eth::setSchainExitTime( Json::Value const& /*_transaction*/ ) {
Json::Value Eth::eth_inspectTransaction( std::string const& _rlp ) {
try {
return toJson( Transaction( jsToBytes( _rlp, OnFailed::Throw ),
CheckTransaction::Everything, EIP1559TransactionsPatch::isEnabledInWorkingBlock() ) );
CheckTransaction::Everything, EIP1559TransactionsPatch::isEnabledInWorkingBlock(),
MaxFeePerGasPatch::isEnabledInWorkingBlock() ) );
} catch ( ... ) {
BOOST_THROW_EXCEPTION( JsonRpcException( Errors::ERROR_RPC_INVALID_PARAMS ) );
}
Expand All @@ -427,7 +428,8 @@ string Eth::eth_sendRawTransaction( std::string const& _rlp ) {
// Don't need to check the transaction signature (CheckTransaction::None) since it
// will be checked as a part of transaction import
Transaction t( jsToBytes( _rlp, OnFailed::Throw ), CheckTransaction::None, false,
EIP1559TransactionsPatch::isEnabledInWorkingBlock() );
EIP1559TransactionsPatch::isEnabledInWorkingBlock(),
MaxFeePerGasPatch::isEnabledInWorkingBlock() );
return toJS( client()->importTransaction( t, TransactionBroadcast::BroadcastToAll ) );
}

Expand Down
60 changes: 60 additions & 0 deletions test/unittests/libweb3jsonrpc/jsonrpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3629,6 +3629,66 @@ BOOST_AUTO_TEST_CASE( vInTxnSignature ) {
BOOST_REQUIRE( v < 2 && v >= 0 );
}

BOOST_AUTO_TEST_CASE( maxFeePerGasPatch ) {
std::string _config = c_genesisConfigString;
Json::Value ret;
Json::Reader().parse( _config, ret );

// Set chainID = 151
std::string chainID = "0x97";
ret["params"]["chainID"] = chainID;
time_t eip1559PatchActivationTimestamp = time(nullptr) - 1;
time_t maxFeePerGasPatchActivationTimestamp = time(nullptr) + 10;
ret["skaleConfig"]["sChain"]["MaxFeePerGasPatchTimestamp"] = maxFeePerGasPatchActivationTimestamp;
ret["skaleConfig"]["sChain"]["EIP1559TransactionsPatchTimestamp"] = eip1559PatchActivationTimestamp;

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

dev::eth::simulateMining( *( fixture.client ), 20 );
string senderAddress = toJS(fixture.coinbase.address());

Json::Value txRefill;
txRefill["to"] = "0x5EdF1e852fdD1B0Bc47C0307EF755C76f4B9c251";
txRefill["from"] = senderAddress;
txRefill["gas"] = "100000";
txRefill["gasPrice"] = fixture.rpcClient->eth_gasPrice();
txRefill["value"] = 1000000000000000000;
string txHash = fixture.rpcClient->eth_sendTransaction( txRefill );
dev::eth::mineTransaction( *( fixture.client ), 1 );

Json::Value receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
BOOST_REQUIRE( receipt["status"] == string( "0x1" ) );

// send a txn with maxPriorityFeePerGas > maxFeePerGas before MaxFeePerGasPatchTimestamp
txHash = fixture.rpcClient->eth_sendRawTransaction( "0x02f86d8197808504a817c8018504a817c800827530947d36af85a184e220a656525fcbb9a63b9ab3c12b8080c001a0db2fe04a66fa54bfe9c6e0166d85a31b34cbff10dbde0e0584081aec6bb33c30a06b956a49c52f1460da9f93fc495eaa863ae5a8c91ee9230c2f3976f5e74d4f47" );
dev::eth::mineTransaction( *( fixture.client ), 1 );

receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
BOOST_REQUIRE( receipt["status"] == string( "0x1" ) );

Json::Value tx = fixture.rpcClient->eth_getTransactionByHash( txHash );
BOOST_REQUIRE( dev::jsToU256( tx["maxFeePerGas"].asString() ) < dev::jsToU256( tx["maxPriorityFeePerGas"].asString() ) );

dev::eth::Transaction t = fixture.client->transaction( dev::h256( txHash ) );
BOOST_REQUIRE( t.maxFeePerGas() < t.maxPriorityFeePerGas() );

sleep( 10 );

// force 1 block to update timestamp
txRefill["to"] = "0xc868AF52a6549c773082A334E5AE232e0Ea3B513";
txRefill["from"] = senderAddress;
txRefill["gas"] = "100000";
txRefill["gasPrice"] = fixture.rpcClient->eth_gasPrice();
txRefill["value"] = 0;
txHash = fixture.rpcClient->eth_sendTransaction( txRefill );
dev::eth::mineTransaction( *( fixture.client ), 1 );

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

BOOST_AUTO_TEST_CASE( jsonrpcVersionInResponseHeader ) {
JsonRpcFixture fixture;

Expand Down
Loading