diff --git a/VERSION b/VERSION index 209f5795d..419f30096 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.19.0 \ No newline at end of file +3.19.0 diff --git a/libdevcore/JsonUtils.cpp b/libdevcore/JsonUtils.cpp index 1a6f96c43..660e92170 100644 --- a/libdevcore/JsonUtils.cpp +++ b/libdevcore/JsonUtils.cpp @@ -57,10 +57,12 @@ std::string dev::jsonTypeAsString( json_spirit::Value_type _type ) { } void dev::requireJsonFields( json_spirit::mObject const& _o, std::string const& _config, - std::map< std::string, JsonFieldOptions > const& _validationMap ) { + std::map< std::string, JsonFieldOptions > const& _validationMap, + std::function< bool( const std::string& ) > _callbackForUnexpected ) { // check for unexpected fiedls for ( auto const& field : _o ) { - if ( !_validationMap.count( field.first ) ) { + // _callbackForUnexpected allows to accept ertain unexpected fields + if ( !_validationMap.count( field.first ) && !_callbackForUnexpected( field.first ) ) { std::string const comment = "Unexpected field '" + field.first + "' in config: " + _config; cerror << comment << "\n" diff --git a/libdevcore/JsonUtils.h b/libdevcore/JsonUtils.h index f9bc8dd25..2948e971b 100644 --- a/libdevcore/JsonUtils.h +++ b/libdevcore/JsonUtils.h @@ -41,6 +41,10 @@ using JsonFieldOptions = std::pair< JsonTypeSet, JsonFieldPresence >; @param _validationMap a map with json objects that would be checked. "objName" -> {js::str_type, jsonField::Required} */ -void requireJsonFields( json_spirit::mObject const& _o, std::string const& _configName, - std::map< std::string, JsonFieldOptions > const& _validationMap ); +void requireJsonFields( + json_spirit::mObject const& _o, std::string const& _configName, + std::map< std::string, JsonFieldOptions > const& _validationMap, + std::function< bool( const std::string& ) > _callbackForUnexpected = []( const std::string& ) { + return false; + } ); } // namespace dev diff --git a/libdevcore/LevelDB.h b/libdevcore/LevelDB.h index c2a1f7ee9..9674cb9ec 100644 --- a/libdevcore/LevelDB.h +++ b/libdevcore/LevelDB.h @@ -26,8 +26,8 @@ #include #include -#include "shared_mutex" #include +#include namespace dev::db { class LevelDB : public DatabaseFace { diff --git a/libethashseal/Ethash.cpp b/libethashseal/Ethash.cpp index b8109c7e9..3f893f308 100644 --- a/libethashseal/Ethash.cpp +++ b/libethashseal/Ethash.cpp @@ -130,18 +130,6 @@ void Ethash::verify( Strictness _s, BlockHeader const& _bi, BlockHeader const& _ } } -void Ethash::verifyTransaction( ImportRequirements::value _ir, TransactionBase const& _t, - BlockHeader const& _header, u256 const& _startGasUsed ) const { - SealEngineFace::verifyTransaction( _ir, _t, _header, _startGasUsed ); - - if ( _ir & ImportRequirements::TransactionSignatures ) { - if ( _header.number() >= chainParams().EIP158ForkBlock ) { - uint64_t chainID = chainParams().chainID; - _t.checkChainId( chainID, chainParams().skaleDisableChainIdCheck ); - } // if - } -} - u256 Ethash::childGasLimit( BlockHeader const& _bi, u256 const& _gasFloorTarget ) const { u256 gasFloorTarget = _gasFloorTarget == Invalid256 ? 3141562 : _gasFloorTarget; u256 gasLimit = _bi.gasLimit(); diff --git a/libethashseal/Ethash.h b/libethashseal/Ethash.h index 0fdc6e3dc..92dd767cb 100644 --- a/libethashseal/Ethash.h +++ b/libethashseal/Ethash.h @@ -52,8 +52,6 @@ class Ethash : public SealEngineBase { StringHashMap jsInfo( BlockHeader const& _bi ) const override; void verify( Strictness _s, BlockHeader const& _bi, BlockHeader const& _parent, bytesConstRef _block ) const override; - void verifyTransaction( ImportRequirements::value _ir, TransactionBase const& _t, - BlockHeader const& _header, u256 const& _startGasUsed ) const override; void populateFromParent( BlockHeader& _bi, BlockHeader const& _parent ) const override; strings sealers() const override; diff --git a/libethcore/ChainOperationParams.cpp b/libethcore/ChainOperationParams.cpp index a42ff19cf..4f11713a9 100644 --- a/libethcore/ChainOperationParams.cpp +++ b/libethcore/ChainOperationParams.cpp @@ -22,6 +22,9 @@ */ #include "ChainOperationParams.h" + +#include + #include #include @@ -42,6 +45,14 @@ PrecompiledContract::PrecompiledContract( unsigned _base, unsigned _word, }, _exec, _startingBlock, _allowedAddresses ) {} +time_t SChain::getPatchTimestamp( SchainPatchEnum _patchEnum ) const { + assert( _patchEnum < SchainPatchEnum::PatchesCount ); + if ( _patchEnum < SchainPatchEnum::PatchesCount ) + return _patchTimestamps[static_cast< size_t >( _patchEnum )]; + else + return 0; +} + ChainOperationParams::ChainOperationParams() : m_blockReward( "0x4563918244F40000" ), minGasLimit( 0x1388 ), @@ -52,43 +63,33 @@ ChainOperationParams::ChainOperationParams() difficultyBoundDivisor( 0x0800 ), durationLimit( 0x0d ) {} -EVMSchedule const& ChainOperationParams::scheduleForBlockNumber( u256 const& _blockNumber ) const { - if ( _blockNumber >= skaleUnlimitedForkBlock ) - return SkaleSchedule_Unlimited; - else if ( _blockNumber >= skale1024ForkBlock ) - return SkaleSchedule_1024k; - else if ( _blockNumber >= skale512ForkBlock ) - return SkaleSchedule_512k; - else if ( _blockNumber >= skale256ForkBlock ) - return SkaleSchedule_256k; - else if ( _blockNumber >= skale128ForkBlock ) - return SkaleSchedule_128k; - else if ( _blockNumber >= skale64ForkBlock ) - return SkaleSchedule_64k; - else if ( _blockNumber >= skale32ForkBlock ) - return SkaleSchedule_32k; - else if ( _blockNumber >= skale16ForkBlock ) - return SkaleSchedule_16k; - else if ( _blockNumber >= experimentalForkBlock ) - return ExperimentalSchedule; - else if ( _blockNumber >= istanbulForkBlock ) - return IstanbulSchedule; - else if ( _blockNumber >= constantinopleFixForkBlock ) - return ConstantinopleFixSchedule; - else if ( _blockNumber >= constantinopleForkBlock ) - return ConstantinopleSchedule; - else if ( _blockNumber >= eWASMForkBlock ) - return EWASMSchedule; - else if ( _blockNumber >= byzantiumForkBlock ) - return ByzantiumSchedule; - else if ( _blockNumber >= EIP158ForkBlock ) - return EIP158Schedule; - else if ( _blockNumber >= EIP150ForkBlock ) - return EIP150Schedule; - else if ( _blockNumber >= homesteadForkBlock ) - return HomesteadSchedule; +EVMSchedule const ChainOperationParams::makeEvmSchedule( + time_t _committedBlockTimestamp, u256 const& _workingBlockNumber ) const { + EVMSchedule result; + + // 1 decide by block number + if ( _workingBlockNumber >= experimentalForkBlock ) + result = ExperimentalSchedule; + else if ( _workingBlockNumber >= istanbulForkBlock ) + result = IstanbulSchedule; + else if ( _workingBlockNumber >= constantinopleFixForkBlock ) + result = ConstantinopleFixSchedule; + else if ( _workingBlockNumber >= constantinopleForkBlock ) + result = ConstantinopleSchedule; + else if ( _workingBlockNumber >= byzantiumForkBlock ) + result = ByzantiumSchedule; + else if ( _workingBlockNumber >= EIP158ForkBlock ) + result = EIP158Schedule; + else if ( _workingBlockNumber >= EIP150ForkBlock ) + result = EIP150Schedule; else - return FrontierSchedule; + result = HomesteadSchedule; + + // 2 based on previous - decide by timestamp + if ( PushZeroPatch::isEnabledWhen( _committedBlockTimestamp ) ) + result = PushZeroPatch::makeSchedule( result ); + + return result; } u256 ChainOperationParams::blockReward( EVMSchedule const& _schedule ) const { @@ -98,6 +99,16 @@ u256 ChainOperationParams::blockReward( EVMSchedule const& _schedule ) const { return m_blockReward; } +u256 ChainOperationParams::blockReward( + time_t _committedBlockTimestamp, u256 const& _workingBlockNumber ) const { + EVMSchedule const& schedule{ makeEvmSchedule( _committedBlockTimestamp, _workingBlockNumber ) }; + return blockReward( schedule ); +} + void ChainOperationParams::setBlockReward( u256 const& _newBlockReward ) { m_blockReward = _newBlockReward; } + +time_t ChainOperationParams::getPatchTimestamp( SchainPatchEnum _patchEnum ) const { + return sChain.getPatchTimestamp( _patchEnum ); +} diff --git a/libethcore/ChainOperationParams.h b/libethcore/ChainOperationParams.h index b6e182d65..5d773e216 100644 --- a/libethcore/ChainOperationParams.h +++ b/libethcore/ChainOperationParams.h @@ -28,6 +28,7 @@ #include #include +#include #include "libethcore/Common.h" #include "libethcore/EVMSchedule.h" @@ -173,16 +174,12 @@ struct SChain { int emptyBlockIntervalMs = -1; int64_t levelDBReopenIntervalMs = -1; size_t t = 1; - time_t revertableFSPatchTimestamp = 0; - time_t contractStoragePatchTimestamp = 0; - time_t contractStorageZeroValuePatchTimestamp = 0; - time_t verifyDaSigsPatchTimestamp = 0; - time_t storageDestructionPatchTimestamp = 0; - time_t powCheckPatchTimestamp = 0; - time_t precompiledConfigPatchTimestamp = 0; - time_t pushZeroPatchTimestamp = 0; - time_t skipInvalidTransactionsPatchTimestamp = 0; - time_t correctForkInPowPatchTimestamp = 0; + + // key is patch name + // public - for tests, don't access it directly + std::vector< time_t > _patchTimestamps = + std::vector< time_t >( static_cast< int >( SchainPatchEnum::PatchesCount ) ); + time_t getPatchTimestamp( SchainPatchEnum _patchEnum ) const; SChain() { name = "TestChain"; @@ -210,8 +207,10 @@ struct ChainOperationParams { u256 m_blockReward; public: - EVMSchedule const& scheduleForBlockNumber( u256 const& _blockNumber ) const; + EVMSchedule const makeEvmSchedule( + time_t _committedBlockTimestamp, u256 const& _workingBlockNumber ) const; u256 blockReward( EVMSchedule const& _schedule ) const; + u256 blockReward( time_t _committedBlockTimestamp, u256 const& _workingBlockNumber ) const; void setBlockReward( u256 const& _newBlockReward ); u256 maximumExtraDataSize = 1024; u256 accountStartNonce = 0; @@ -257,6 +256,24 @@ struct ChainOperationParams { u256 externalGasDifficulty = ~u256( 0 ); typedef std::vector< std::string > vecAdminOrigins_t; vecAdminOrigins_t vecAdminOrigins; // wildcard based folters for IP addresses + + time_t getPatchTimestamp( SchainPatchEnum _patchEnum ) const; + + bool isPrecompiled( Address const& _a, u256 const& _blockNumber ) const { + return precompiled.count( _a ) != 0 && _blockNumber >= precompiled.at( _a ).startingBlock(); + } + bigint costOfPrecompiled( + Address const& _a, bytesConstRef _in, u256 const& _blockNumber ) const { + return precompiled.at( _a ).cost( _in, *this, _blockNumber ); + } + std::pair< bool, bytes > executePrecompiled( + Address const& _a, bytesConstRef _in, u256 const& ) const { + return precompiled.at( _a ).execute( _in ); + } + bool precompiledExecutionAllowedFrom( + Address const& _a, Address const& _from, bool _readOnly ) const { + return precompiled.at( _a ).executionAllowedFrom( _from, _readOnly ); + } }; } // namespace eth diff --git a/libethcore/EVMSchedule.h b/libethcore/EVMSchedule.h index fe744dd16..b9aec53b5 100644 --- a/libethcore/EVMSchedule.h +++ b/libethcore/EVMSchedule.h @@ -46,6 +46,7 @@ struct EVMSchedule { bool haveExtcodehash = false; bool haveChainID = false; bool haveSelfbalance = false; + bool havePush0 = false; std::array< unsigned, 8 > tierStepGas; unsigned expGas = 10; unsigned expByteGas = 10; @@ -93,7 +94,6 @@ struct EVMSchedule { }; static const EVMSchedule DefaultSchedule = EVMSchedule(); -static const EVMSchedule FrontierSchedule = EVMSchedule( false, false, 21000 ); static const EVMSchedule HomesteadSchedule = EVMSchedule( true, true, 53000 ); static const EVMSchedule EIP150Schedule = [] { @@ -125,12 +125,6 @@ static const EVMSchedule ByzantiumSchedule = [] { return schedule; }(); -static const EVMSchedule EWASMSchedule = [] { - EVMSchedule schedule = ByzantiumSchedule; - schedule.maxCodeSize = std::numeric_limits< unsigned >::max(); - return schedule; -}(); - static const EVMSchedule ConstantinopleSchedule = [] { EVMSchedule schedule = ByzantiumSchedule; schedule.haveCreate2 = true; @@ -174,60 +168,6 @@ static const EVMSchedule ExperimentalSchedule = [] { return schedule; }(); -static const EVMSchedule SkaleSchedule_base = [] { - EVMSchedule schedule = ConstantinopleSchedule; - return schedule; -}(); - -static const EVMSchedule SkaleSchedule_16k = [] { - EVMSchedule schedule = SkaleSchedule_base; - schedule.maxCodeSize = 1024 * 16; - return schedule; -}(); - -static const EVMSchedule SkaleSchedule_32k = [] { - EVMSchedule schedule = SkaleSchedule_base; - schedule.maxCodeSize = 1024 * 32; - return schedule; -}(); - -static const EVMSchedule SkaleSchedule_64k = [] { - EVMSchedule schedule = SkaleSchedule_base; - schedule.maxCodeSize = 1024 * 64; - return schedule; -}(); - -static const EVMSchedule SkaleSchedule_128k = [] { - EVMSchedule schedule = SkaleSchedule_base; - schedule.maxCodeSize = 1024 * 128; - return schedule; -}(); - -static const EVMSchedule SkaleSchedule_256k = [] { - EVMSchedule schedule = SkaleSchedule_base; - schedule.maxCodeSize = 1024 * 256; - return schedule; -}(); - -static const EVMSchedule SkaleSchedule_512k = [] { - EVMSchedule schedule = SkaleSchedule_base; - schedule.maxCodeSize = 1024 * 512; - return schedule; -}(); - -static const EVMSchedule SkaleSchedule_1024k = [] { - EVMSchedule schedule = SkaleSchedule_base; - schedule.maxCodeSize = 1024 * 1024; - return schedule; -}(); - -static const EVMSchedule SkaleSchedule_Unlimited = [] { - EVMSchedule schedule = SkaleSchedule_base; - schedule.maxCodeSize = std::numeric_limits< unsigned >::max(); - return schedule; -}(); - - inline EVMSchedule const& latestScheduleForAccountVersion( u256 const& _version ) { if ( _version == 0 ) return IstanbulSchedule; diff --git a/libethcore/SealEngine.cpp b/libethcore/SealEngine.cpp index c72280397..b9cd03c6f 100644 --- a/libethcore/SealEngine.cpp +++ b/libethcore/SealEngine.cpp @@ -20,7 +20,7 @@ #include "SealEngine.h" #include "TransactionBase.h" -#include +#include #include "../libdevcore/microprofile.h" @@ -94,11 +94,12 @@ void SealEngineFace::populateFromParent( BlockHeader& _bi, BlockHeader const& _p _bi.populateFromParent( _parent ); } -void SealEngineFace::verifyTransaction( ImportRequirements::value _ir, TransactionBase const& _t, - BlockHeader const& _header, u256 const& _gasUsed ) const { +void SealEngineFace::verifyTransaction( ChainOperationParams const& _chainParams, + ImportRequirements::value _ir, TransactionBase const& _t, time_t _committedBlockTimestamp, + BlockHeader const& _header, u256 const& _gasUsed ) { // verifyTransaction is the only place where TransactionBase is used instead of Transaction. u256 gas; - if ( POWCheckPatch::isEnabled() ) { + if ( PowCheckPatch::isEnabledWhen( _committedBlockTimestamp ) ) { // new behavior is to use pow-enabled gas gas = _t.gas(); } else { @@ -108,26 +109,27 @@ void SealEngineFace::verifyTransaction( ImportRequirements::value _ir, Transacti MICROPROFILE_SCOPEI( "SealEngineFace", "verifyTransaction", MP_ORCHID ); if ( ( _ir & ImportRequirements::TransactionSignatures ) && - _header.number() < chainParams().EIP158ForkBlock && _t.isReplayProtected() ) + _header.number() < _chainParams.EIP158ForkBlock && _t.isReplayProtected() ) BOOST_THROW_EXCEPTION( InvalidSignature() ); if ( ( _ir & ImportRequirements::TransactionSignatures ) && - _header.number() < chainParams().experimentalForkBlock && _t.hasZeroSignature() ) + _header.number() < _chainParams.experimentalForkBlock && _t.hasZeroSignature() ) BOOST_THROW_EXCEPTION( InvalidSignature() ); if ( ( _ir & ImportRequirements::TransactionBasic ) && - _header.number() >= chainParams().experimentalForkBlock && _t.hasZeroSignature() && + _header.number() >= _chainParams.experimentalForkBlock && _t.hasZeroSignature() && ( _t.value() != 0 || _t.gasPrice() != 0 || _t.nonce() != 0 ) ) BOOST_THROW_EXCEPTION( InvalidZeroSignatureTransaction() << errinfo_got( static_cast< bigint >( _t.gasPrice() ) ) << errinfo_got( static_cast< bigint >( _t.value() ) ) << errinfo_got( static_cast< bigint >( _t.nonce() ) ) ); - if ( _header.number() >= chainParams().homesteadForkBlock && + if ( _header.number() >= _chainParams.homesteadForkBlock && ( _ir & ImportRequirements::TransactionSignatures ) && _t.hasSignature() ) _t.checkLowS(); - eth::EVMSchedule const& schedule = evmSchedule( _header.number() ); + eth::EVMSchedule const& schedule = + _chainParams.makeEvmSchedule( _committedBlockTimestamp, _header.number() ); // Pre calculate the gas needed for execution if ( ( _ir & ImportRequirements::TransactionBasic ) && _t.baseGasRequired( schedule ) > gas ) @@ -141,6 +143,13 @@ void SealEngineFace::verifyTransaction( ImportRequirements::value _ir, Transacti static_cast< bigint >( _header.gasLimit() - _gasUsed ), static_cast< bigint >( gas ), string( "_gasUsed + (bigint)_t.gas() > _header.gasLimit()" ) ) ); + + if ( _ir & ImportRequirements::TransactionSignatures ) { + if ( _header.number() >= _chainParams.EIP158ForkBlock ) { + uint64_t chainID = _chainParams.chainID; + _t.checkChainId( chainID, _chainParams.skaleDisableChainIdCheck ); + } // if + } } SealEngineFace* SealEngineRegistrar::create( ChainOperationParams const& _params ) { @@ -151,11 +160,13 @@ SealEngineFace* SealEngineRegistrar::create( ChainOperationParams const& _params return ret; } -EVMSchedule const& SealEngineBase::evmSchedule( u256 const& _blockNumber ) const { - return chainParams().scheduleForBlockNumber( _blockNumber ); +EVMSchedule SealEngineBase::evmSchedule( + time_t _committedBlockTimestamp, u256 const& _workingBlockNumber ) const { + return chainParams().makeEvmSchedule( _committedBlockTimestamp, _workingBlockNumber ); } -u256 SealEngineBase::blockReward( u256 const& _blockNumber ) const { - EVMSchedule const& schedule{ evmSchedule( _blockNumber ) }; +u256 SealEngineBase::blockReward( + time_t _committedBlockTimestamp, u256 const& _workingBlockNumber ) const { + EVMSchedule const& schedule{ evmSchedule( _committedBlockTimestamp, _workingBlockNumber ) }; return chainParams().blockReward( schedule ); } diff --git a/libethcore/SealEngine.h b/libethcore/SealEngine.h index b51a87bbf..463ddd9b0 100644 --- a/libethcore/SealEngine.h +++ b/libethcore/SealEngine.h @@ -57,8 +57,9 @@ class SealEngineFace { virtual void verify( Strictness _s, BlockHeader const& _bi, BlockHeader const& _parent = BlockHeader(), bytesConstRef _block = bytesConstRef() ) const; /// Additional verification for transactions in blocks. - virtual void verifyTransaction( ImportRequirements::value _ir, TransactionBase const& _t, - BlockHeader const& _header, u256 const& _gasUsed ) const; + static void verifyTransaction( ChainOperationParams const& _chainParams, + ImportRequirements::value _ir, TransactionBase const& _t, time_t _committedBlockTimestamp, + BlockHeader const& _header, u256 const& _gasUsed ); /// Don't forget to call Super::populateFromParent when subclassing & overriding. virtual void populateFromParent( BlockHeader& _bi, BlockHeader const& _parent ) const; @@ -93,8 +94,10 @@ class SealEngineFace { setChainParams( _params ); return this; } - virtual EVMSchedule const& evmSchedule( u256 const& _blockNumber ) const = 0; - virtual u256 blockReward( u256 const& _blockNumber ) const = 0; + virtual EVMSchedule evmSchedule( + time_t _committedBlockTimestamp, u256 const& _workingBlockNumber ) const = 0; + virtual u256 blockReward( + time_t _committedBlockTimestamp, u256 const& _workingBlockNumber ) const = 0; virtual bool isPrecompiled( Address const& _a, u256 const& _blockNumber ) const { return m_params.precompiled.count( _a ) != 0 && @@ -135,8 +138,10 @@ class SealEngineBase : public SealEngineFace { void onSealGenerated( std::function< void( bytes const& ) > const& _f ) override { m_onSealGenerated = _f; } - EVMSchedule const& evmSchedule( u256 const& _blockNumber ) const override; - u256 blockReward( u256 const& _blockNumber ) const override; + EVMSchedule evmSchedule( + time_t _committedBlockTimestamp, u256 const& _blockNumber ) const override; + u256 blockReward( + time_t _committedBlockTimestamp, u256 const& _workingBlockNumber ) const override; protected: std::function< void( bytes const& s ) > m_onSealGenerated; diff --git a/libethereum/Block.cpp b/libethereum/Block.cpp index 9198a9daa..deed6f7ce 100644 --- a/libethereum/Block.cpp +++ b/libethereum/Block.cpp @@ -351,7 +351,8 @@ pair< TransactionReceipts, bool > Block::sync( // caller if we hit the limit for ( Transaction& transaction : transactions ) { - transaction.checkOutExternalGas( _bc.chainParams(), _bc.number() ); + transaction.checkOutExternalGas( + _bc.chainParams(), _bc.info().timestamp(), _bc.number(), false ); } assert( _bc.currentHash() == m_currentBlock.parentHash() ); @@ -484,7 +485,7 @@ tuple< TransactionReceipts, unsigned > Block::syncEveryone( LOG( m_logger ) << "Transaction " << tr.sha3() << " WouldNotBeInBlock: gasPrice " << tr.gasPrice() << " < " << _gasPrice; - if ( SkipInvalidTransactionsPatch::isEnabled() ) { + if ( SkipInvalidTransactionsPatch::isEnabledInWorkingBlock() ) { // Add to the user-originated transactions that we've executed. m_transactions.push_back( tr ); m_transactionSet.insert( tr.sha3() ); @@ -508,7 +509,7 @@ tuple< TransactionReceipts, unsigned > Block::syncEveryone( ExecutionResult res = execute( _bc.lastBlockHashes(), tr, Permanence::Committed, OnOpFunc() ); - if ( !SkipInvalidTransactionsPatch::isEnabled() || + if ( !SkipInvalidTransactionsPatch::isEnabledInWorkingBlock() || res.excepted != TransactionException::WouldNotBeInBlock ) { receipts.push_back( m_receipts.back() ); @@ -631,7 +632,8 @@ u256 Block::enact( VerifiedBlockRef const& _block, BlockChain const& _bc ) { // << " (state #" // << state().getNonce( tr.from() ) << ") value = " << tr.value() << // endl; - const_cast< Transaction& >( tr ).checkOutExternalGas( _bc.chainParams(), _bc.number() ); + const_cast< Transaction& >( tr ).checkOutExternalGas( + _bc.chainParams(), _bc.info().timestamp(), _bc.number(), false ); execute( _bc.lastBlockHashes(), tr ); // cerr << "Now: " // << "State #" << state().getNonce( tr.from() ) << endl; @@ -762,7 +764,8 @@ u256 Block::enact( VerifiedBlockRef const& _block, BlockChain const& _bc ) { assert( _bc.sealEngine() ); DEV_TIMED_ABOVE( "applyRewards", 500 ) - applyRewards( rewarded, _bc.sealEngine()->blockReward( m_currentBlock.number() ) ); + applyRewards( rewarded, + _bc.sealEngine()->blockReward( previousInfo().timestamp(), m_currentBlock.number() ) ); if ( m_currentBlock.gasUsed() != gasUsed() ) { // Do not commit changes of state @@ -812,14 +815,15 @@ ExecutionResult Block::executeHistoricCall( LastBlockHashesFace const& _lh, Tran u256 const gasUsed = _transactionIndex ? receipt( _transactionIndex - 1 ).cumulativeGasUsed() : 0; - EnvInfo const envInfo{ info(), _lh, gasUsed, m_sealEngine->chainParams().chainID }; + EnvInfo const envInfo( info(), _lh, this->previousInfo().timestamp(), gasUsed, + m_sealEngine->chainParams().chainID ); if ( _tracer ) { try { HistoricState stateBefore( m_state.mutableHistoricState() ); - auto resultReceipt = m_state.mutableHistoricState().execute( - envInfo, *m_sealEngine, _t, skale::Permanence::Uncommitted, onOp ); + auto resultReceipt = m_state.mutableHistoricState().execute( envInfo, + m_sealEngine->chainParams(), _t, skale::Permanence::Uncommitted, onOp ); _tracer->finalizeAndPrintTrace( resultReceipt.first, stateBefore, m_state.mutableHistoricState() ); @@ -834,7 +838,7 @@ ExecutionResult Block::executeHistoricCall( LastBlockHashesFace const& _lh, Tran } } else { auto resultReceipt = m_state.mutableHistoricState().execute( - envInfo, *m_sealEngine, _t, skale::Permanence::Reverted, onOp ); + envInfo, m_sealEngine->chainParams(), _t, skale::Permanence::Reverted, onOp ); return resultReceipt.first; } } catch ( std::exception& e ) { @@ -866,7 +870,8 @@ ExecutionResult Block::execute( State stateSnapshot = _p != Permanence::Reverted ? m_state.createStateModifyCopyAndPassLock() : m_state; - EnvInfo envInfo = EnvInfo( info(), _lh, gasUsed(), m_sealEngine->chainParams().chainID ); + EnvInfo envInfo = EnvInfo( + info(), _lh, previousInfo().timestamp(), gasUsed(), m_sealEngine->chainParams().chainID ); // "bad" transaction receipt for failed transactions TransactionReceipt const null_receipt = @@ -881,7 +886,8 @@ ExecutionResult Block::execute( if ( _t.isInvalid() ) throw -1; // will catch below - resultReceipt = stateSnapshot.execute( envInfo, *m_sealEngine, _t, _p, _onOp ); + resultReceipt = + stateSnapshot.execute( envInfo, m_sealEngine->chainParams(), _t, _p, _onOp ); // use fake receipt created above if execution throws!! } catch ( const TransactionException& ex ) { @@ -905,7 +911,7 @@ ExecutionResult Block::execute( if ( _p == Permanence::Committed || _p == Permanence::CommittedWithoutState || _p == Permanence::Uncommitted ) { // Add to the user-originated transactions that we've executed. - if ( !SkipInvalidTransactionsPatch::isEnabled() || + if ( !SkipInvalidTransactionsPatch::isEnabledWhen( previousInfo().timestamp() ) || resultReceipt.first.excepted != TransactionException::WouldNotBeInBlock ) { m_transactions.push_back( _t ); m_receipts.push_back( resultReceipt.second ); @@ -950,13 +956,15 @@ void Block::updateBlockhashContract() { if ( m_state.code( c_blockhashContractAddress ) != c_blockhashContractCode ) { State state = m_state.createStateModifyCopy(); state.setCode( c_blockhashContractAddress, bytes( c_blockhashContractCode ), - m_sealEngine->evmSchedule( blockNumber ).accountVersion ); + m_sealEngine->evmSchedule( this->m_previousBlock.timestamp(), blockNumber ) + .accountVersion ); state.commit( dev::eth::CommitBehaviour::KeepEmptyAccounts ); } } else { m_state.createContract( c_blockhashContractAddress ); m_state.setCode( c_blockhashContractAddress, bytes( c_blockhashContractCode ), - m_sealEngine->evmSchedule( blockNumber ).accountVersion ); + m_sealEngine->evmSchedule( this->m_previousBlock.timestamp(), blockNumber ) + .accountVersion ); m_state.commit( dev::eth::CommitBehaviour::KeepEmptyAccounts ); } } @@ -1022,7 +1030,8 @@ void Block::commitToSeal( // Apply rewards last of all. assert( _bc.sealEngine() ); - applyRewards( uncleBlockHeaders, _bc.sealEngine()->blockReward( m_currentBlock.number() ) ); + applyRewards( uncleBlockHeaders, + _bc.sealEngine()->blockReward( previousInfo().timestamp(), m_currentBlock.number() ) ); // Commit any and all changes to the trie that are in the cache, then update the state root // accordingly. diff --git a/libethereum/Block.h b/libethereum/Block.h index 204224248..4164b73e9 100644 --- a/libethereum/Block.h +++ b/libethereum/Block.h @@ -299,6 +299,7 @@ class Block { /// Get the header information on the present block. BlockHeader const& info() const { return m_currentBlock; } + BlockHeader const& previousInfo() const { return m_previousBlock; } void startReadState(); diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 677d19b48..b4eb2cec0 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -173,24 +174,6 @@ unsigned c_maxCacheSize = 1024 * 1024 * 64; /// Min size, below which we don't bother flushing it. unsigned c_minCacheSize = 1024 * 1024 * 32; -bool hasPotentialInvalidTransactionsInBlock( BlockNumber _bn, const BlockChain& _bc ) { - if ( _bn == 0 ) - return false; - - if ( SkipInvalidTransactionsPatch::getActivationTimestamp() == 0 ) - return true; - - if ( _bn == PendingBlock ) - return !SkipInvalidTransactionsPatch::isEnabled(); - - if ( _bn == LatestBlock ) - _bn = _bc.number(); - - time_t prev_ts = _bc.info( _bc.numberHash( _bn - 1 ) ).timestamp(); - - return prev_ts < SkipInvalidTransactionsPatch::getActivationTimestamp(); -} - string BlockChain::getChainDirName( const ChainParams& _cp ) { return toHex( BlockHeader( _cp.genesisBlock() ).hash().ref().cropped( 0, 4 ) ); } @@ -370,7 +353,8 @@ std::pair< h256, unsigned > BlockChain::transactionLocation( h256 const& _transa auto blockNumber = this->number( ta.blockHash ); - if ( !hasPotentialInvalidTransactionsInBlock( blockNumber, *this ) ) + if ( !SkipInvalidTransactionsPatch::hasPotentialInvalidTransactionsInBlock( + blockNumber, *this ) ) return std::make_pair( ta.blockHash, ta.index ); // rest is for blocks with possibility of invalid transactions @@ -1101,7 +1085,7 @@ void BlockChain::clearBlockBlooms( unsigned _begin, unsigned _end ) { } void BlockChain::rescue( State const& /*_state*/ ) { - clog( VerbosityInfo, "BlockChain" ) << "Rescuing database..." << endl; + clog( VerbosityInfo, "BlockChain" ) << "Rescuing database..."; throw std::logic_error( "Rescueing is not implemented" ); unsigned u = 1; @@ -1116,8 +1100,7 @@ void BlockChain::rescue( State const& /*_state*/ ) { } } unsigned l = u / 2; - clog( VerbosityInfo, "BlockChain" ) - << cc::debug( "Finding last likely block number..." ) << endl; + clog( VerbosityInfo, "BlockChain" ) << cc::debug( "Finding last likely block number..." ); while ( u - l > 1 ) { unsigned m = ( u + l ) / 2; clog( VerbosityInfo, "BlockChain" ) << " " << m << flush; @@ -1126,7 +1109,7 @@ void BlockChain::rescue( State const& /*_state*/ ) { else u = m; } - clog( VerbosityInfo, "BlockChain" ) << " lowest is " << l << endl; + clog( VerbosityInfo, "BlockChain" ) << " lowest is " << l; for ( ; l > 0; --l ) { h256 h = numberHash( l ); clog( VerbosityInfo, "BlockChain" ) @@ -1145,7 +1128,7 @@ void BlockChain::rescue( State const& /*_state*/ ) { } catch ( ... ) { } } - clog( VerbosityInfo, "BlockChain" ) << "OK." << endl; + clog( VerbosityInfo, "BlockChain" ) << "OK."; rewind( l ); } @@ -1752,7 +1735,9 @@ VerifiedBlockRef BlockChain::verifyBlock( bytesConstRef _block, Transaction t( d, ( _ir & ImportRequirements::TransactionSignatures ) ? CheckTransaction::Everything : CheckTransaction::None ); - m_sealEngine->verifyTransaction( _ir, t, h, 0 ); // the gasUsed vs + Ethash::verifyTransaction( chainParams(), _ir, t, + this->info( numberHash( h.number() - 1 ) ).timestamp(), h, + 0 ); // the gasUsed vs // blockGasLimit is checked // later in enact function res.transactions.push_back( t ); @@ -1776,3 +1761,18 @@ unsigned BlockChain::chainStartBlockNumber() const { auto const value = m_extrasDB->lookup( c_sliceChainStart ); return value.empty() ? 0 : number( h256( value, h256::FromBinary ) ); } + +bool BlockChain::isPatchTimestampActiveInBlockNumber( time_t _ts, BlockNumber _bn ) const { + if ( _bn == 0 || _ts == 0 ) + return false; + + if ( _bn == LatestBlock ) + _bn = number(); + + if ( _bn == PendingBlock ) + _bn = number() + 1; + + time_t prev_ts = this->info( this->numberHash( _bn - 1 ) ).timestamp(); + + return prev_ts >= _ts; +} diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 593475fb1..4bc3f99ef 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -453,6 +453,10 @@ class BlockChain { return 0; } + // simple thing to compare _bn-1's timestamp with ts + // maybe need cahing for faster operation + bool isPatchTimestampActiveInBlockNumber( time_t _ts, BlockNumber _bn ) const; + private: static h256 chunkId( unsigned _level, unsigned _index ) { return h256( _index * 0xff + _level ); diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 0a79f6baa..6b92ea48a 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -1,6 +1,7 @@ file( GLOB sources "*.cpp" "*.h" ) -add_library( ethereum ${sources} InstanceMonitor.cpp InstanceMonitor.h) +add_library( ethereum ${sources} InstanceMonitor.cpp InstanceMonitor.h + SchainPatchEnum.h) target_compile_options( ethereum PRIVATE -Wno-error=deprecated-copy -Wno-error=unused-result -Wno-error=unused-parameter -Wno-error=unused-variable -Wno-error=maybe-uninitialized diff --git a/libethereum/ChainParams.cpp b/libethereum/ChainParams.cpp index 23134a877..ca4f51b6b 100644 --- a/libethereum/ChainParams.cpp +++ b/libethereum/ChainParams.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -38,11 +39,12 @@ #include #include "Account.h" -#include "GenesisInfo.h" #include "ValidationSchemes.h" #include +#include + using namespace std; using namespace dev; using namespace eth; @@ -105,7 +107,6 @@ ChainParams ChainParams::loadConfig( params[c_skaleDisableChainIdCheck].get_bool() : false; - if ( obj.count( c_skaleConfig ) ) { processSkaleConfigItems( cp, obj ); } @@ -303,50 +304,17 @@ void ChainParams::processSkaleConfigItems( ChainParams& cp, json_spirit::mObject if ( sChainObj.count( "multiTransactionMode" ) ) s.multiTransactionMode = sChainObj.at( "multiTransactionMode" ).get_bool(); - if ( sChainObj.count( "revertableFSPatchTimestamp" ) ) - s.revertableFSPatchTimestamp = sChainObj.at( "revertableFSPatchTimestamp" ).get_int64(); - - s.contractStoragePatchTimestamp = - sChainObj.count( "contractStoragePatchTimestamp" ) ? - sChainObj.at( "contractStoragePatchTimestamp" ).get_int64() : - 0; - - s.contractStorageZeroValuePatchTimestamp = - sChainObj.count( "contractStorageZeroValuePatchTimestamp" ) ? - sChainObj.at( "contractStorageZeroValuePatchTimestamp" ).get_int64() : - 0; - - s.verifyDaSigsPatchTimestamp = sChainObj.count( "verifyDaSigsPatchTimestamp" ) ? - sChainObj.at( "verifyDaSigsPatchTimestamp" ).get_int64() : - 0; - - s.storageDestructionPatchTimestamp = - sChainObj.count( "storageDestructionPatchTimestamp" ) ? - sChainObj.at( "storageDestructionPatchTimestamp" ).get_int64() : - 0; - - s.powCheckPatchTimestamp = sChainObj.count( "powCheckPatchTimestamp" ) ? - sChainObj.at( "powCheckPatchTimestamp" ).get_int64() : - 0; - - s.precompiledConfigPatchTimestamp = - sChainObj.count( "precompiledConfigPatchTimestamp" ) ? - sChainObj.at( "precompiledConfigPatchTimestamp" ).get_int64() : - 0; - - s.pushZeroPatchTimestamp = sChainObj.count( "pushZeroPatchTimestamp" ) ? - sChainObj.at( "pushZeroPatchTimestamp" ).get_int64() : - 0; - - s.skipInvalidTransactionsPatchTimestamp = - sChainObj.count( "skipInvalidTransactionsPatchTimestamp" ) ? - sChainObj.at( "skipInvalidTransactionsPatchTimestamp" ).get_int64() : - 0; - - s.correctForkInPowPatchTimestamp = - sChainObj.count( "correctForkInPowPatchTimestamp" ) ? - sChainObj.at( "correctForkInPowPatchTimestamp" ).get_int64() : - 0; + // extract all "*PatchTimestamp" records + for ( const auto& it : sChainObj ) { + const string& key = it.first; + if ( boost::algorithm::ends_with( key, "PatchTimestamp" ) ) { + string patchName = boost::algorithm::erase_last_copy( key, "Timestamp" ); + patchName[0] = toupper( patchName[0] ); + SchainPatchEnum patchEnum = getEnumForPatchName( patchName ); + s._patchTimestamps[static_cast< size_t >( patchEnum )] = + it.second.get_int64(); // time_t is signed + } // if + } // for if ( sChainObj.count( "nodeGroups" ) ) { vector< NodeGroup > nodeGroups; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 19bd071b8..1cd97c9f3 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -52,20 +52,11 @@ #include #endif +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include -#include #include #include @@ -163,21 +154,6 @@ Client::Client( ChainParams const& _params, int _networkID, }; init( _forceAction, _networkID ); - - // Set timestamps for patches - TotalStorageUsedPatch::g_client = this; - ContractStorageLimitPatch::setTimestamp( chainParams().sChain.contractStoragePatchTimestamp ); - ContractStorageZeroValuePatch::setTimestamp( - chainParams().sChain.contractStorageZeroValuePatchTimestamp ); - VerifyDaSigsPatch::setTimestamp( chainParams().sChain.verifyDaSigsPatchTimestamp ); - RevertableFSPatch::setTimestamp( chainParams().sChain.revertableFSPatchTimestamp ); - StorageDestructionPatch::setTimestamp( chainParams().sChain.storageDestructionPatchTimestamp ); - POWCheckPatch::setTimestamp( chainParams().sChain.powCheckPatchTimestamp ); - PushZeroPatch::setTimestamp( chainParams().sChain.pushZeroPatchTimestamp ); - SkipInvalidTransactionsPatch::setTimestamp( - this->chainParams().sChain.skipInvalidTransactionsPatchTimestamp ); - PrecompiledConfigPatch::setTimestamp( chainParams().sChain.precompiledConfigPatchTimestamp ); - CorrectForkInPowPatch::setTimestamp( chainParams().sChain.correctForkInPowPatchTimestamp ); } @@ -337,13 +313,12 @@ void Client::init( WithExisting _forceAction, u256 _networkId ) { m_snapshotAgentInited = true; } + SchainPatch::init( chainParams() ); + SchainPatch::useLatestBlockTimestamp( blockChain().info().timestamp() ); + TotalStorageUsedPatch::init( this ); // HACK Needed to set env var for consensus AmsterdamFixPatch::isEnabled( *this ); - // needed for checkOutExternalGas - CorrectForkInPowPatch::lastBlockTimestamp = blockChain().info().timestamp(); - CorrectForkInPowPatch::lastBlockNumber = blockChain().number(); - initCPUUSage(); doWork( false ); @@ -613,9 +588,7 @@ size_t Client::importTransactionsAsBlock( sealUnconditionally( false ); importWorkingBlock(); - // this needs to be updated as soon as possible, as it's used in new transactions validation - CorrectForkInPowPatch::lastBlockTimestamp = blockChain().info().timestamp(); - CorrectForkInPowPatch::lastBlockNumber = blockChain().number(); + SchainPatch::useLatestBlockTimestamp( blockChain().info().timestamp() ); if ( !UnsafeRegion::isActive() ) { LOG( m_loggerDetail ) << "Total unsafe time so far = " @@ -666,7 +639,7 @@ size_t Client::syncTransactions( // HACK remove block verification and put it directly in blockchain!! // TODO remove block verification and put it directly in blockchain!! while ( m_working.isSealed() ) { - cnote << "m_working.isSealed. sleeping" << endl; + cnote << "m_working.isSealed. sleeping"; usleep( 1000 ); } @@ -677,18 +650,6 @@ size_t Client::syncTransactions( TransactionReceipts newPendingReceipts; unsigned goodReceipts; - ContractStorageLimitPatch::lastBlockTimestamp = blockChain().info().timestamp(); - ContractStorageZeroValuePatch::lastBlockTimestamp = blockChain().info().timestamp(); - RevertableFSPatch::lastBlockTimestamp = blockChain().info().timestamp(); - StorageDestructionPatch::lastBlockTimestamp = blockChain().info().timestamp(); - POWCheckPatch::lastBlockTimestamp = blockChain().info().timestamp(); - PushZeroPatch::lastBlockTimestamp = blockChain().info().timestamp(); - SkipInvalidTransactionsPatch::lastBlockTimestamp = blockChain().info().timestamp(); - PrecompiledConfigPatch::lastBlockTimestamp = blockChain().info().timestamp(); - CorrectForkInPowPatch::lastBlockTimestamp = blockChain().info().timestamp(); - CorrectForkInPowPatch::lastBlockNumber = blockChain().number(); - - DEV_WRITE_GUARDED( x_working ) { assert( !m_working.isSealed() ); @@ -1128,19 +1089,6 @@ Block Client::blockByNumber( BlockNumber _h ) const { } #endif -Block Client::latestBlock() const { - // TODO Why it returns not-filled block??! (see Block ctor) - try { - DEV_GUARDED( m_blockImportMutex ) { return Block( bc(), bc().currentHash(), m_state ); } - assert( false ); - return Block( bc() ); - } catch ( Exception& ex ) { - ex << errinfo_block( bc().block( bc().currentHash() ) ); - onBadBlock( ex ); - return Block( bc() ); - } -} - void Client::flushTransactions() { doWork(); } @@ -1218,14 +1166,15 @@ h256 Client::importTransaction( Transaction const& _t ) { state = this->state().createStateReadOnlyCopy(); gasBidPrice = this->gasBidPrice(); - // We need to check external gas under mutex to be sure about current block bumber + // We need to check external gas under mutex to be sure about current block number // correctness - const_cast< Transaction& >( _t ).checkOutExternalGas( chainParams(), number() ); + const_cast< Transaction& >( _t ).checkOutExternalGas( + chainParams(), bc().info().timestamp(), number(), false ); } - Executive::verifyTransaction( _t, + Executive::verifyTransaction( _t, bc().info().timestamp(), bc().number() ? this->blockInfo( bc().currentHash() ) : bc().genesis(), state, - *bc().sealEngine(), 0, gasBidPrice, chainParams().sChain.multiTransactionMode ); + chainParams(), 0, gasBidPrice, chainParams().sChain.multiTransactionMode ); ImportResult res; if ( chainParams().sChain.multiTransactionMode && state.getNonce( _t.sender() ) < _t.nonce() && @@ -1295,7 +1244,7 @@ ExecutionResult Client::call( Address const& _from, u256 _value, Address _dest, } #endif - Block temp = latestBlock(); + Block temp = preSeal(); // TODO there can be race conditions between prev and next line! State readStateForLock = temp.mutableState().createStateReadOnlyCopy(); @@ -1396,7 +1345,7 @@ Json::Value Client::traceBlock( BlockNumber _blockNumber, Json::Value const& _js Transaction tx = transactions.at( k ); auto hashString = toHexPrefixed( tx.sha3() ); transactionLog["txHash"] = hashString; - tx.checkOutExternalGas( chainParams(), _blockNumber ); + tx.checkOutExternalGas( chainParams(), bc().info().timestamp(), number(), false ); auto tracer = std::make_shared< AlethStandardTrace >( tx, historicBlock.author(), traceOptions ); auto executionResult = diff --git a/libethereum/Client.h b/libethereum/Client.h index 4f7b8ea3d..da19e9b93 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -142,6 +142,10 @@ class Client : public ClientBase, protected Worker { /// Blocks until all pending transactions have been processed. void flushTransactions() override; + using ClientBase::blockDetails; + using ClientBase::blockInfo; // for another overload + using ClientBase::uncleHashes; + /// Retrieve pending transactions Transactions pending() const override; @@ -264,8 +268,6 @@ class Client : public ClientBase, protected Worker { /// Queues a function to be executed in the main thread (that owns the blockchain, etc). void executeInMainThread( std::function< void() > const& _function ); - Block latestBlock() const; - /// should be called after the constructor of the most derived class finishes. void startWorking() { assert( m_skaleHost ); diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 6b6d530b4..bc88f0e34 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -23,7 +23,7 @@ */ #include "ClientBase.h" -#include +#include #include #include @@ -80,8 +80,8 @@ void ClientWatch::append_changes( const LocalisedLogEntry& entry ) { } std::pair< bool, ExecutionResult > ClientBase::estimateGasStep( int64_t _gas, Block& _latestBlock, - Address const& _from, Address const& _destination, u256 const& _value, u256 const& _gasPrice, - bytes const& _data ) { + Block& _pendingBlock, Address const& _from, Address const& _destination, u256 const& _value, + u256 const& _gasPrice, bytes const& _data ) { u256 nonce = _latestBlock.transactionsFrom( _from ); Transaction t; if ( _destination ) @@ -91,12 +91,13 @@ std::pair< bool, ExecutionResult > ClientBase::estimateGasStep( int64_t _gas, Bl t.forceSender( _from ); t.forceChainId( chainId() ); t.ignoreExternalGas(); - EnvInfo const env( _latestBlock.info(), bc().lastBlockHashes(), 0, _gas ); + EnvInfo const env( _pendingBlock.info(), bc().lastBlockHashes(), + _pendingBlock.previousInfo().timestamp(), 0, _gas ); // Make a copy of state!! It will be deleted after step! State tempState = _latestBlock.mutableState(); tempState.addBalance( _from, ( u256 )( t.gas() * t.gasPrice() + t.value() ) ); ExecutionResult executionResult = - tempState.execute( env, *bc().sealEngine(), t, Permanence::Reverted ).first; + tempState.execute( env, bc().chainParams(), t, Permanence::Reverted ).first; if ( executionResult.excepted == TransactionException::OutOfGas || executionResult.excepted == TransactionException::OutOfGasBase || executionResult.excepted == TransactionException::OutOfGasIntrinsic || @@ -116,15 +117,19 @@ std::pair< u256, ExecutionResult > ClientBase::estimateGas( Address const& _from int64_t upperBound = _maxGas; if ( upperBound == Invalid256 || upperBound > c_maxGasEstimate ) upperBound = c_maxGasEstimate; - int64_t lowerBound = - CorrectForkInPowPatch::isEnabled() ? - Transaction::baseGasRequired( !_dest, &_data, - bc().sealEngine()->chainParams().scheduleForBlockNumber( bc().number() ) ) : - Transaction::baseGasRequired( !_dest, &_data, EVMSchedule() ); - - Block bk = latestBlock(); - if ( upperBound > bk.info().gasLimit() ) { - upperBound = bk.info().gasLimit().convert_to< int64_t >(); + int64_t lowerBound; + if ( CorrectForkInPowPatch::isEnabledInWorkingBlock() ) + lowerBound = Transaction::baseGasRequired( !_dest, &_data, + bc().sealEngine()->chainParams().makeEvmSchedule( + bc().info().timestamp(), bc().number() ) ); + else + lowerBound = Transaction::baseGasRequired( !_dest, &_data, EVMSchedule() ); + + Block latest = latestBlock(); + Block pending = preSeal(); + + if ( upperBound > pending.info().gasLimit() ) { + upperBound = pending.info().gasLimit().convert_to< int64_t >(); } u256 gasPrice = _gasPrice == Invalid256 ? gasBidPrice() : _gasPrice; @@ -135,19 +140,20 @@ std::pair< u256, ExecutionResult > ClientBase::estimateGas( Address const& _from // If not run binary search to find optimal gas limit. auto estimatedStep = - estimateGasStep( upperBound, bk, _from, _dest, _value, gasPrice, _data ); + estimateGasStep( upperBound, latest, pending, _from, _dest, _value, gasPrice, _data ); if ( estimatedStep.first ) { auto executionResult = estimatedStep.second; auto gasUsed = std::max( executionResult.gasUsed.convert_to< int64_t >(), lowerBound ); - estimatedStep = estimateGasStep( gasUsed, bk, _from, _dest, _value, gasPrice, _data ); + estimatedStep = + estimateGasStep( gasUsed, latest, pending, _from, _dest, _value, gasPrice, _data ); if ( estimatedStep.first ) { return make_pair( gasUsed, executionResult ); } while ( lowerBound + 1 < upperBound ) { int64_t middle = ( lowerBound + upperBound ) / 2; - estimatedStep = - estimateGasStep( middle, bk, _from, _dest, _value, gasPrice, _data ); + estimatedStep = estimateGasStep( + middle, latest, pending, _from, _dest, _value, gasPrice, _data ); if ( estimatedStep.first ) { upperBound = middle; } else { @@ -160,7 +166,8 @@ std::pair< u256, ExecutionResult > ClientBase::estimateGas( Address const& _from } return make_pair( upperBound, - estimateGasStep( upperBound, bk, _from, _dest, _value, gasPrice, _data ).second ); + estimateGasStep( upperBound, latest, pending, _from, _dest, _value, gasPrice, _data ) + .second ); } catch ( ... ) { // TODO: Some sort of notification of failure. return make_pair( u256(), ExecutionResult() ); @@ -499,6 +506,10 @@ BlockDetails ClientBase::pendingDetails() const { pm.parentHash(), h256s{}, postSeal().blockData().size() ); } +EVMSchedule ClientBase::evmSchedule() const { + return sealEngine()->evmSchedule( bc().info().timestamp(), pendingInfo().number() ); +} + u256 ClientBase::gasLimitRemaining() const { return postSeal().gasLimitRemaining(); } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index ab4b7a812..1dd089b72 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -92,7 +92,7 @@ class ClientBase : public Interface { /// @param _callback Optional callback function for progress reporting std::pair< u256, ExecutionResult > estimateGas( Address const& _from, u256 _value, Address _dest, bytes const& _data, int64_t _maxGas, u256 _gasPrice, - GasEstimationCallback const& _callback ) override; + GasEstimationCallback const& _callback = GasEstimationCallback() ) override; u256 balanceAt( Address _a ) const override; u256 countAt( Address _a ) const override; @@ -117,6 +117,12 @@ class ClientBase : public Interface { LocalisedLogEntries peekWatch( unsigned _watchId ) const override; LocalisedLogEntries checkWatch( unsigned _watchId ) override; + using Interface::blockDetails; + using Interface::blockInfo; // for another overload + using Interface::transactionHashes; + using Interface::uncle; + using Interface::uncleHashes; + h256 hashFromNumber( BlockNumber _number ) const override; BlockNumber numberFromHash( h256 _blockHash ) const override; int compareBlockHashes( h256 _h1, h256 _h2 ) const override; @@ -147,15 +153,14 @@ class ClientBase : public Interface { } return transactionCount( hashFromNumber( _block ) ); } + using Interface::uncleCount; unsigned uncleCount( h256 _blockHash ) const override; unsigned number() const override; h256s pendingHashes() const override; BlockHeader pendingInfo() const override; BlockDetails pendingDetails() const override; - EVMSchedule evmSchedule() const override { - return sealEngine()->evmSchedule( pendingInfo().number() ); - } + EVMSchedule evmSchedule() const override; ImportResult injectBlock( bytes const& _block ) override; @@ -217,7 +222,7 @@ class ClientBase : public Interface { private: std::pair< bool, ExecutionResult > estimateGasStep( int64_t _gas, Block& _latestBlock, - Address const& _from, Address const& _destination, u256 const& _value, + Block& _pendingBlock, Address const& _from, Address const& _destination, u256 const& _value, u256 const& _gasPrice, bytes const& _data ); }; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index d3e93b6b8..70a945efc 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -164,19 +165,21 @@ string StandardTrace::json( bool _styled ) const { Executive::Executive( Block& _s, BlockChain const& _bc, const u256& _gasPrice, unsigned _level, bool _readOnly ) : m_s( _s.mutableState() ), - m_envInfo( _s.info(), _bc.lastBlockHashes(), 0, _bc.chainID() ), + m_envInfo( + _s.info(), _bc.lastBlockHashes(), _s.previousInfo().timestamp(), 0, _bc.chainID() ), m_depth( _level ), m_readOnly( _readOnly ), - m_sealEngine( *_bc.sealEngine() ), + m_chainParams( _bc.chainParams() ), m_systemGasPrice( _gasPrice ) {} Executive::Executive( Block& _s, LastBlockHashesFace const& _lh, const u256& _gasPrice, unsigned _level, bool _readOnly ) : m_s( _s.mutableState() ), - m_envInfo( _s.info(), _lh, 0, _s.sealEngine()->chainParams().chainID ), + m_envInfo( _s.info(), _lh, _s.previousInfo().timestamp(), 0, + _s.sealEngine()->chainParams().chainID ), m_depth( _level ), m_readOnly( _readOnly ), - m_sealEngine( *_s.sealEngine() ), + m_chainParams( _s.sealEngine()->chainParams() ), m_systemGasPrice( _gasPrice ) {} u256 Executive::gasUsed() const { @@ -188,9 +191,10 @@ void Executive::accrueSubState( SubState& _parentContext ) { _parentContext += m_ext->sub; } -void Executive::verifyTransaction( Transaction const& _transaction, BlockHeader const& _blockHeader, - const State& _state, const SealEngineFace& _sealEngine, u256 const& _gasUsed, - const u256& _gasPrice, const bool _allowFuture ) { +void Executive::verifyTransaction( Transaction const& _transaction, time_t _committedBlockTimestamp, + BlockHeader const& _blockHeader, const State& _state, + const eth::ChainOperationParams& _chainParams, u256 const& _gasUsed, const u256& _gasPrice, + const bool _allowFuture ) { MICROPROFILE_SCOPEI( "Executive", "verifyTransaction", MP_GAINSBORO ); if ( !_transaction.hasExternalGas() && _transaction.gasPrice() < _gasPrice ) { @@ -199,8 +203,8 @@ void Executive::verifyTransaction( Transaction const& _transaction, BlockHeader static_cast< bigint >( _transaction.gasPrice() ) ) ); } - _sealEngine.verifyTransaction( - ImportRequirements::Everything, _transaction, _blockHeader, _gasUsed ); + Ethash::verifyTransaction( _chainParams, ImportRequirements::Everything, _transaction, + _committedBlockTimestamp, _blockHeader, _gasUsed ); if ( !_transaction.hasZeroSignature() ) { // skip nonce check for calls @@ -244,11 +248,12 @@ void Executive::verifyTransaction( Transaction const& _transaction, BlockHeader void Executive::initialize( Transaction const& _transaction ) { MICROPROFILE_SCOPEI( "Executive", "initialize", MP_GAINSBORO ); m_t = _transaction; - m_baseGasRequired = m_t.baseGasRequired( m_sealEngine.evmSchedule( m_envInfo.number() ) ); + m_baseGasRequired = m_t.baseGasRequired( + m_chainParams.makeEvmSchedule( m_envInfo.committedBlockTimestamp(), m_envInfo.number() ) ); try { - verifyTransaction( _transaction, m_envInfo.header(), m_s, m_sealEngine, m_envInfo.gasUsed(), - m_systemGasPrice ); + verifyTransaction( _transaction, m_envInfo.committedBlockTimestamp(), m_envInfo.header(), + m_s, m_chainParams, m_envInfo.gasUsed(), m_systemGasPrice ); } catch ( Exception const& ex ) { m_excepted = toTransactionException( ex ); throw; @@ -293,7 +298,7 @@ bool Executive::call( CallParameters const& _p, u256 const& _gasPrice, Address c // for the transaction. // Increment associated nonce for sender. if ( _p.senderAddress != MaxAddress || - m_envInfo.number() < m_sealEngine.chainParams().constantinopleForkBlock ) { // EIP86 + m_envInfo.number() < m_chainParams.constantinopleForkBlock ) { // EIP86 MICROPROFILE_SCOPEI( "Executive", "call-incNonce", MP_SEAGREEN ); m_s.incNonce( _p.senderAddress ); } @@ -301,11 +306,11 @@ bool Executive::call( CallParameters const& _p, u256 const& _gasPrice, Address c m_savepoint = m_s.savepoint(); - if ( m_sealEngine.isPrecompiled( _p.codeAddress, m_envInfo.number() ) && - m_sealEngine.precompiledExecutionAllowedFrom( + if ( m_chainParams.isPrecompiled( _p.codeAddress, m_envInfo.number() ) && + m_chainParams.precompiledExecutionAllowedFrom( _p.codeAddress, _p.senderAddress, m_readOnly ) ) { MICROPROFILE_SCOPEI( "Executive", "call-precompiled", MP_CYAN ); - bigint g = m_sealEngine.costOfPrecompiled( _p.codeAddress, _p.data, m_envInfo.number() ); + bigint g = m_chainParams.costOfPrecompiled( _p.codeAddress, _p.data, m_envInfo.number() ); if ( _p.gas < g ) { m_excepted = TransactionException::OutOfGasBase; // Bail from exception. @@ -316,7 +321,7 @@ bool Executive::call( CallParameters const& _p, u256 const& _gasPrice, Address c // https://github.com/ethereum/go-ethereum/pull/3341/files#diff-2433aa143ee4772026454b8abd76b9dd // We mark the account as touched here, so that is can be removed among other touched // empty accounts (after tx finalization) - if ( m_envInfo.number() >= m_sealEngine.chainParams().EIP158ForkBlock ) + if ( m_envInfo.number() >= m_chainParams.EIP158ForkBlock ) m_s.addBalance( _p.codeAddress, 0 ); return true; // true actually means "all finished - nothing more to be done regarding @@ -328,7 +333,7 @@ bool Executive::call( CallParameters const& _p, u256 const& _gasPrice, Address c // dev::eth::g_state = m_s.delegateWrite(); dev::eth::g_overlayFS = m_s.fs(); tie( success, output ) = - m_sealEngine.executePrecompiled( _p.codeAddress, _p.data, m_envInfo.number() ); + m_chainParams.executePrecompiled( _p.codeAddress, _p.data, m_envInfo.number() ); // m_s = dev::eth::g_state.delegateWrite(); size_t outputSize = output.size(); m_output = owning_bytes_ref{ std::move( output ), 0, outputSize }; @@ -346,7 +351,7 @@ bool Executive::call( CallParameters const& _p, u256 const& _gasPrice, Address c h256 codeHash = m_s.codeHash( _p.codeAddress ); // Contract will be executed with the version stored in account auto const version = m_s.version( _p.codeAddress ); - m_ext = make_shared< ExtVM >( m_s, m_envInfo, m_sealEngine, _p.receiveAddress, + m_ext = make_shared< ExtVM >( m_s, m_envInfo, m_chainParams, _p.receiveAddress, _p.senderAddress, _origin, _p.apparentValue, _gasPrice, _p.data, &c, codeHash, version, m_depth, false, _p.staticCall, m_readOnly ); } @@ -388,7 +393,7 @@ bool Executive::executeCreate( Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin, u256 const& _version ) { if ( _sender != MaxAddress || - m_envInfo.number() < m_sealEngine.chainParams().experimentalForkBlock ) // EIP86 + m_envInfo.number() < m_chainParams.experimentalForkBlock ) // EIP86 m_s.incNonce( _sender ); m_savepoint = m_s.savepoint(); @@ -415,7 +420,7 @@ bool Executive::executeCreate( Address const& _sender, u256 const& _endowment, m_s.transferBalance( _sender, m_newAddress, _endowment ); u256 newNonce = m_s.requireAccountStartNonce(); - if ( m_envInfo.number() >= m_sealEngine.chainParams().EIP158ForkBlock ) + if ( m_envInfo.number() >= m_chainParams.EIP158ForkBlock ) newNonce += 1; m_s.setNonce( m_newAddress, newNonce ); @@ -423,7 +428,7 @@ bool Executive::executeCreate( Address const& _sender, u256 const& _endowment, // Schedule _init execution if not empty. if ( !_init.empty() ) - m_ext = make_shared< ExtVM >( m_s, m_envInfo, m_sealEngine, m_newAddress, _sender, _origin, + m_ext = make_shared< ExtVM >( m_s, m_envInfo, m_chainParams, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, sha3( _init ), _version, m_depth, true, false ); else diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 9bc8c0ec5..cf1b2715c 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -102,13 +102,13 @@ class StandardTrace { class Executive { public: /// Simple constructor; executive will operate on given state, with the given environment info. - Executive( skale::State& _s, EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, - const u256& _gasPrice, unsigned _level = 0, bool _readOnly = true ) + Executive( skale::State& _s, EnvInfo const& _envInfo, ChainOperationParams const& _chainParams, + const u256& _gasPrice, unsigned _level, bool _readOnly = true ) : m_s( _s ), m_envInfo( _envInfo ), m_depth( _level ), m_readOnly( _readOnly ), - m_sealEngine( _sealEngine ), + m_chainParams( _chainParams ), m_systemGasPrice( _gasPrice ) {} /** Easiest constructor. @@ -202,9 +202,10 @@ class Executive { /// Revert all changes made to the state by this execution. void revert(); - static void verifyTransaction( Transaction const& _transaction, BlockHeader const& _blockHeader, - const skale::State& _state, const SealEngineFace& _sealEngine, u256 const& _gasUsed, - const u256& _gasPrice, const bool _allowFuture = false ); + static void verifyTransaction( Transaction const& _transaction, time_t _committedBlockTimestamp, + BlockHeader const& _blockHeader, const skale::State& _state, + const ChainOperationParams& _chainParams, u256 const& _gasUsed, const u256& _gasPrice, + const bool _allowFuture = false ); private: /// @returns false iff go() must be called (and thus a VM execution in required). @@ -235,7 +236,7 @@ class Executive { LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize(). u256 m_gasCost; - SealEngineFace const& m_sealEngine; + ChainOperationParams const& m_chainParams; u256 m_systemGasPrice; bool m_isCreation = false; diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp index a20931378..453cb0ec0 100644 --- a/libethereum/ExtVM.cpp +++ b/libethereum/ExtVM.cpp @@ -127,7 +127,7 @@ evmc_status_code transactionExceptionToEvmcStatusCode( TransactionException ex ) CallResult ExtVM::call( CallParameters& _p ) { - Executive e{ m_s, envInfo(), m_sealEngine, 0, depth + 1, m_readOnly }; + Executive e{ m_s, envInfo(), m_chainParams, 0, depth + 1, m_readOnly }; if ( !e.call( _p, gasPrice, origin ) ) { go( depth, e, _p.onOp ); e.accrueSubState( sub ); @@ -151,7 +151,7 @@ void ExtVM::setStore( u256 _n, u256 _v ) { CreateResult ExtVM::create( u256 _endowment, u256& io_gas, bytesConstRef _code, Instruction _op, u256 _salt, OnOpFunc const& _onOp ) { - Executive e{ m_s, envInfo(), m_sealEngine, 0, depth + 1 }; + Executive e{ m_s, envInfo(), m_chainParams, 0, depth + 1 }; bool result = false; if ( _op == Instruction::CREATE ) result = e.createOpcode( myAddress, _endowment, gasPrice, io_gas, _code, origin ); @@ -185,7 +185,7 @@ h256 ExtVM::blockHash( u256 _number ) { if ( _number >= currentNumber || _number < ( std::max< u256 >( 256, currentNumber ) - 256 ) ) return h256(); - if ( currentNumber < m_sealEngine.chainParams().experimentalForkBlock + 256 ) { + if ( currentNumber < m_chainParams.experimentalForkBlock + 256 ) { h256 const parentHash = envInfo().header().parentHash(); h256s const lastHashes = envInfo().lastHashes().precedingHashes( parentHash ); @@ -199,6 +199,7 @@ h256 ExtVM::blockHash( u256 _number ) { tx.forceSender( caller ); ExecutionResult res; - std::tie( res, std::ignore ) = m_s.execute( envInfo(), m_sealEngine, tx, Permanence::Reverted ); + std::tie( res, std::ignore ) = + m_s.execute( envInfo(), m_chainParams, tx, Permanence::Reverted ); return h256( res.output ); } diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index 8f166359d..4076b0c10 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -37,15 +37,15 @@ class SealEngineFace; class ExtVM : public ExtVMFace { public: /// Full constructor. - ExtVM( skale::State& _s, EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, + ExtVM( skale::State& _s, EnvInfo const& _envInfo, ChainOperationParams const& _chainParams, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, h256 const& _codeHash, u256 const& _version, unsigned _depth, bool _isCreate, bool _staticCall, bool _readOnly = true ) : ExtVMFace( _envInfo, _myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _codeHash, _version, _depth, _isCreate, _staticCall ), m_s( _s ), - m_sealEngine( _sealEngine ), - m_evmSchedule( initEvmSchedule( envInfo().number(), _version ) ), + m_chainParams( _chainParams ), + m_evmSchedule( initEvmSchedule( _version ) ), m_readOnly( _readOnly ) { // Contract: processing account must exist. In case of CALL, the ExtVM // is created only if an account has code (so exist). In case of CREATE @@ -95,9 +95,7 @@ class ExtVM : public ExtVMFace { virtual void suicide( Address _a ) override final; /// Return the EVM gas-price schedule for this execution context. - virtual EVMSchedule const& evmSchedule() const override final { - return m_sealEngine.evmSchedule( envInfo().number() ); - } + virtual EVMSchedule const& evmSchedule() const override final { return m_evmSchedule; } skale::State const& state() const { return m_s; } @@ -105,10 +103,11 @@ class ExtVM : public ExtVMFace { h256 blockHash( u256 _number ) override; private: - EVMSchedule const& initEvmSchedule( int64_t _blockNumber, u256 const& _version ) const { + EVMSchedule initEvmSchedule( u256 const& _version ) const { // If _version is latest for the block, select corresponding latest schedule. // Otherwise run with the latest schedule known to correspond to the _version. - EVMSchedule const& currentBlockSchedule = m_sealEngine.evmSchedule( _blockNumber ); + EVMSchedule currentBlockSchedule = m_chainParams.makeEvmSchedule( + envInfo().committedBlockTimestamp(), envInfo().number() ); if ( currentBlockSchedule.accountVersion == _version ) return currentBlockSchedule; else @@ -116,8 +115,8 @@ class ExtVM : public ExtVMFace { } skale::State& m_s; ///< A reference to the base state. - SealEngineFace const& m_sealEngine; - EVMSchedule const& m_evmSchedule; + ChainOperationParams const& m_chainParams; + EVMSchedule const m_evmSchedule; bool m_readOnly; }; diff --git a/libethereum/Precompiled.cpp b/libethereum/Precompiled.cpp index aecc33209..ecbf7f770 100644 --- a/libethereum/Precompiled.cpp +++ b/libethereum/Precompiled.cpp @@ -36,8 +36,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -809,7 +809,9 @@ ETH_REGISTER_PRECOMPILED( getConfigVariableUint256 )( bytesConstRef _in ) { std::string strValue; // call to skaleConfig.sChain.nodes means call to the historic data // need to proccess it in a different way - if ( isCallToHistoricData( rawName ) && PrecompiledConfigPatch::isEnabled() ) { + // TODO Check if this precompiled can be called on historic block + if ( isCallToHistoricData( rawName ) && + PrecompiledConfigPatch::isEnabledInWorkingBlock() ) { if ( !g_skaleHost ) throw std::runtime_error( "SkaleHost accessor was not initialized" ); @@ -917,7 +919,9 @@ ETH_REGISTER_PRECOMPILED( getConfigVariableString )( bytesConstRef _in ) { std::string strValue; // call to skaleConfig.sChain.nodes means call to the historic data // need to proccess it in a different way - if ( isCallToHistoricData( rawName ) && PrecompiledConfigPatch::isEnabled() ) { + // TODO Check if this precompiled can be called on historic block + if ( isCallToHistoricData( rawName ) && + PrecompiledConfigPatch::isEnabledInWorkingBlock() ) { if ( !g_skaleHost ) throw std::runtime_error( "SkaleHost accessor was not initialized" ); diff --git a/libethereum/SchainPatch.cpp b/libethereum/SchainPatch.cpp index 393baf086..1ae076376 100644 --- a/libethereum/SchainPatch.cpp +++ b/libethereum/SchainPatch.cpp @@ -1 +1,95 @@ #include "SchainPatch.h" + +#include + +using namespace dev::eth; + +ChainOperationParams SchainPatch::chainParams; +std::atomic< time_t > SchainPatch::committedBlockTimestamp; + +SchainPatchEnum getEnumForPatchName( const std::string& _patchName ) { + if ( _patchName == "RevertableFSPatch" ) + return SchainPatchEnum::RevertableFSPatch; + else if ( _patchName == "PrecompiledConfigPatch" ) + return SchainPatchEnum::PrecompiledConfigPatch; + else if ( _patchName == "PowCheckPatch" ) + return SchainPatchEnum::PowCheckPatch; + else if ( _patchName == "CorrectForkInPowPatch" ) + return SchainPatchEnum::CorrectForkInPowPatch; + else if ( _patchName == "ContractStorageZeroValuePatch" ) + return SchainPatchEnum::ContractStorageZeroValuePatch; + else if ( _patchName == "PushZeroPatch" ) + return SchainPatchEnum::PushZeroPatch; + else if ( _patchName == "VerifyDaSigsPatch" ) + return SchainPatchEnum::VerifyDaSigsPatch; + else if ( _patchName == "ContractStoragePatch" ) + return SchainPatchEnum::ContractStoragePatch; + else if ( _patchName == "StorageDestructionPatch" ) + return SchainPatchEnum::StorageDestructionPatch; + else if ( _patchName == "SkipInvalidTransactionsPatch" ) + return SchainPatchEnum::SkipInvalidTransactionsPatch; + else + throw std::out_of_range( _patchName ); +} + +std::string getPatchNameForEnum( SchainPatchEnum _enumValue ) { + switch ( _enumValue ) { + case SchainPatchEnum::RevertableFSPatch: + return "RevertableFSPatch"; + case SchainPatchEnum::PrecompiledConfigPatch: + return "PrecompiledConfigPatch"; + case SchainPatchEnum::PowCheckPatch: + return "PowCheckPatch"; + case SchainPatchEnum::CorrectForkInPowPatch: + return "CorrectForkInPowPatch"; + case SchainPatchEnum::ContractStorageZeroValuePatch: + return "ContractStorageZeroValuePatch"; + case SchainPatchEnum::PushZeroPatch: + return "PushZeroPatch"; + case SchainPatchEnum::VerifyDaSigsPatch: + return "VerifyDaSigsPatch"; + case SchainPatchEnum::ContractStoragePatch: + return "ContractStoragePatch"; + case SchainPatchEnum::StorageDestructionPatch: + return "StorageDestructionPatch"; + case SchainPatchEnum::SkipInvalidTransactionsPatch: + return "SkipInvalidTransactionsPatch"; + case SchainPatchEnum::SelfdestructStorageLimitPatch: + return "SelfdestructStorageLimitPatch"; + default: + throw std::out_of_range( + "UnknownPatch #" + std::to_string( static_cast< size_t >( _enumValue ) ) ); + } +} + +void SchainPatch::init( const dev::eth::ChainOperationParams& _cp ) { + chainParams = _cp; + for ( size_t i = 0; i < _cp.sChain._patchTimestamps.size(); ++i ) { + printInfo( getPatchNameForEnum( static_cast< SchainPatchEnum >( i ) ), + _cp.sChain._patchTimestamps[i] ); + } +} + +void SchainPatch::useLatestBlockTimestamp( time_t _timestamp ) { + committedBlockTimestamp = _timestamp; +} + +void SchainPatch::printInfo( const std::string& _patchName, time_t _timeStamp ) { + if ( _timeStamp == 0 ) { + cnote << "Patch " << _patchName << " is disabled"; + } else { + cnote << "Patch " << _patchName << " is set at timestamp " << _timeStamp; + } +} + +bool SchainPatch::isPatchEnabledWhen( + SchainPatchEnum _patchEnum, time_t _committedBlockTimestamp ) { + time_t activationTimestamp = chainParams.getPatchTimestamp( _patchEnum ); + return activationTimestamp != 0 && _committedBlockTimestamp >= activationTimestamp; +} + +EVMSchedule PushZeroPatch::makeSchedule( const EVMSchedule& _base ) { + EVMSchedule ret = _base; + ret.havePush0 = true; + return ret; +} diff --git a/libethereum/SchainPatch.h b/libethereum/SchainPatch.h index 5bafcdcd0..d8fabce97 100644 --- a/libethereum/SchainPatch.h +++ b/libethereum/SchainPatch.h @@ -1,17 +1,133 @@ #ifndef SCHAINPATCH_H #define SCHAINPATCH_H +#include "SchainPatchEnum.h" + +#include + #include +#include + +namespace dev { +namespace eth { +struct EVMSchedule; +} +} // namespace dev + + class SchainPatch { public: - static void printInfo( const std::string& _patchName, time_t _timeStamp ) { - if ( _timeStamp == 0 ) { - cnote << "Patch " << _patchName << " is disabled"; - } else { - cnote << "Patch " << _patchName << " is set at timestamp " << _timeStamp; - } + static void init( const dev::eth::ChainOperationParams& _cp ); + static void useLatestBlockTimestamp( time_t _timestamp ); + + static SchainPatchEnum getEnumForPatchName( const std::string& _patchName ); + +protected: + static void printInfo( const std::string& _patchName, time_t _timeStamp ); + static bool isPatchEnabledInWorkingBlock( SchainPatchEnum _patchEnum ) { + time_t activationTimestamp = chainParams.getPatchTimestamp( _patchEnum ); + return activationTimestamp != 0 && committedBlockTimestamp >= activationTimestamp; } + static bool isPatchEnabledWhen( SchainPatchEnum _patchEnum, time_t _committedBlockTimestamp ); + +protected: + static dev::eth::ChainOperationParams chainParams; + static std::atomic< time_t > committedBlockTimestamp; }; +#define DEFINE_AMNESIC_PATCH( CustomPatch ) \ + class CustomPatch : public SchainPatch { \ + public: \ + static SchainPatchEnum getEnum() { return SchainPatchEnum::CustomPatch; } \ + static bool isEnabledInWorkingBlock() { \ + return isPatchEnabledInWorkingBlock( getEnum() ); \ + } \ + }; + +// TODO One more overload - with EnvInfo? +#define DEFINE_SIMPLE_PATCH( CustomPatch ) \ + class CustomPatch : public SchainPatch { \ + public: \ + static SchainPatchEnum getEnum() { return SchainPatchEnum::CustomPatch; } \ + static bool isEnabledInWorkingBlock() { \ + return isPatchEnabledInWorkingBlock( getEnum() ); \ + } \ + static bool isEnabledWhen( time_t _committedBlockTimestamp ) { \ + return isPatchEnabledWhen( getEnum(), _committedBlockTimestamp ); \ + } \ + }; + +#define DEFINE_EVM_PATCH( CustomPatch ) \ + class CustomPatch : public SchainPatch { \ + public: \ + static SchainPatchEnum getEnum() { return SchainPatchEnum::CustomPatch; } \ + static bool isEnabledInWorkingBlock() { \ + return isPatchEnabledInWorkingBlock( getEnum() ); \ + } \ + static bool isEnabledWhen( time_t _committedBlockTimestamp ) { \ + return isPatchEnabledWhen( getEnum(), _committedBlockTimestamp ); \ + } \ + static dev::eth::EVMSchedule makeSchedule( const dev::eth::EVMSchedule& base ); \ + }; + +/* + * Context: enable revertable filestorage precompileds + */ +DEFINE_SIMPLE_PATCH( RevertableFSPatch ) + +/* + * Context: enable precompiled contracts to read historical config data + */ +DEFINE_AMNESIC_PATCH( PrecompiledConfigPatch ) + +/* + * Context: enable fix for POW txns gas limit check + */ +DEFINE_SIMPLE_PATCH( PowCheckPatch ) + +/* + * Context: use current, and not Constantinople, fork in Transaction::checkOutExternalGas() + */ +DEFINE_SIMPLE_PATCH( CorrectForkInPowPatch ) + +/* + * Context: contractStorageUsed counter didn't work well in one case + * Solution: we fixed the bug and added new config field introudceChangesTimestamp + * Purpose: avoid incorrect txn behaviour + * Version introduced: + */ +DEFINE_AMNESIC_PATCH( ContractStorageZeroValuePatch ) + +/* + * Context: enable effective storage destruction + */ +DEFINE_EVM_PATCH( PushZeroPatch ) + +/* + * Context: contractStorageUsed counter didn't work well in one case + * Solution: we fixed the bug and added new config field introudceChangesTimestamp + * Purpose: avoid incorrect txn behaviour + * Version introduced: + */ +DEFINE_SIMPLE_PATCH( VerifyDaSigsPatch ) + +/* + * Context: contractStorageUsed counter didn't work well in one case + * Solution: we fixed the bug and added new config field introudceChangesTimestamp + * Purpose: avoid incorrect txn behaviour + * Version introduced: + */ +DEFINE_AMNESIC_PATCH( ContractStoragePatch ) + +/* + * Context: enable effective storage destruction + */ +DEFINE_AMNESIC_PATCH( StorageDestructionPatch ); + +/* + * Enable restriction on contract storage size, when it's doing selfdestruct + */ +DEFINE_SIMPLE_PATCH( SelfdestructStorageLimitPatch ); + #endif // SCHAINPATCH_H diff --git a/libethereum/SchainPatchEnum.h b/libethereum/SchainPatchEnum.h new file mode 100644 index 000000000..b1f439211 --- /dev/null +++ b/libethereum/SchainPatchEnum.h @@ -0,0 +1,26 @@ +#ifndef SCHAINPATCHENUM_H +#define SCHAINPATCHENUM_H + +#include +#include + +enum class SchainPatchEnum { + RevertableFSPatch, + PrecompiledConfigPatch, + PowCheckPatch, + CorrectForkInPowPatch, + ContractStorageZeroValuePatch, + PushZeroPatch, + VerifyDaSigsPatch, + ContractStoragePatch, + StorageDestructionPatch, + SkipInvalidTransactionsPatch, + SelfdestructStorageLimitPatch, + PatchesCount +}; + +extern SchainPatchEnum getEnumForPatchName( const std::string& _patchName ); +extern std::string getPatchNameForEnum( SchainPatchEnum enumValue ); + + +#endif // SCHAINPATCHENUM_H diff --git a/libethereum/SkaleHost.cpp b/libethereum/SkaleHost.cpp index 01434a060..7988705e8 100644 --- a/libethereum/SkaleHost.cpp +++ b/libethereum/SkaleHost.cpp @@ -47,7 +47,6 @@ using namespace std; #include #include #include -#include #include @@ -81,8 +80,7 @@ std::unique_ptr< ConsensusInterface > DefaultConsensusFactory::create( std::map< std::string, std::uint64_t > patchTimeStamps; patchTimeStamps["verifyDaSigsPatchTimestamp"] = - VerifyDaSigsPatch::getVerifyDaSigsPatchTimestamp(); - + m_client.chainParams().getPatchTimestamp( SchainPatchEnum::VerifyDaSigsPatch ); auto consensus_engine_ptr = make_unique< ConsensusEngine >( _extFace, m_client.number(), ts, 0, patchTimeStamps, m_client.chainParams().sChain.consensusStorageLimit ); @@ -433,9 +431,10 @@ ConsensusExtFace::transactions_vector SkaleHost::pendingTransactions( m_debugTracer.tracepoint( "fetch_transactions" ); int counter = 0; + BlockHeader latestInfo = static_cast< const Interface& >( m_client ).blockInfo( LatestBlock ); Transactions txns = m_tq.topTransactionsSync( - _limit, [this, &to_delete, &counter]( const Transaction& tx ) -> bool { + _limit, [this, &to_delete, &counter, &latestInfo]( const Transaction& tx ) -> bool { if ( m_tq.getCategory( tx.sha3() ) != 1 ) // take broadcasted return false; @@ -446,9 +445,8 @@ ConsensusExtFace::transactions_vector SkaleHost::pendingTransactions( if ( tx.verifiedOn < m_lastBlockWithBornTransactions ) try { bool isMtmEnabled = m_client.chainParams().sChain.multiTransactionMode; - Executive::verifyTransaction( tx, - static_cast< const Interface& >( m_client ).blockInfo( LatestBlock ), - m_client.state().createStateReadOnlyCopy(), *m_client.sealEngine(), 0, + Executive::verifyTransaction( tx, latestInfo.timestamp(), latestInfo, + m_client.state().createStateReadOnlyCopy(), m_client.chainParams(), 0, getGasPrice(), isMtmEnabled ); } catch ( const exception& ex ) { if ( to_delete.count( tx.sha3() ) == 0 ) @@ -628,6 +626,9 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro // HACK this is for not allowing new transactions in tq between deletion and block creation! // TODO decouple SkaleHost and Client!!! size_t n_succeeded; + + BlockHeader latestInfo = static_cast< const Interface& >( m_client ).blockInfo( LatestBlock ); + DEV_GUARDED( m_client.m_blockImportMutex ) { m_debugTracer.tracepoint( "drop_good_transactions" ); @@ -653,7 +654,8 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro // TODO clear occasionally this cache?! if ( m_m_transaction_cache.find( sha.asArray() ) != m_m_transaction_cache.cend() ) { Transaction t = m_m_transaction_cache.at( sha.asArray() ); - t.checkOutExternalGas( m_client.chainParams(), m_client.number(), true ); + t.checkOutExternalGas( + m_client.chainParams(), latestInfo.timestamp(), m_client.number(), true ); out_txns.push_back( t ); LOG( m_debugLogger ) << "Dropping good txn " << sha << std::endl; m_debugTracer.tracepoint( "drop_good" ); @@ -667,7 +669,8 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro // ).detach(); } else { Transaction t( data, CheckTransaction::Everything, true ); - t.checkOutExternalGas( m_client.chainParams(), m_client.number() ); + t.checkOutExternalGas( + m_client.chainParams(), latestInfo.timestamp(), m_client.number(), false ); out_txns.push_back( t ); LOG( m_debugLogger ) << "Will import consensus-born txn"; m_debugTracer.tracepoint( "import_consensus_born" ); @@ -908,8 +911,8 @@ void SkaleHost::broadcastFunc() { m_broadcaster->broadcast( rlp ); } } catch ( const std::exception& ex ) { - cwarn << "BROADCAST EXCEPTION CAUGHT" << endl; - cwarn << ex.what() << endl; + cwarn << "BROADCAST EXCEPTION CAUGHT"; + cwarn << ex.what(); } // catch } // if diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 5bd057524..2d8f80f6e 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -28,8 +28,8 @@ #include #include #include +#include #include -#include using namespace std; using namespace dev; @@ -193,7 +193,8 @@ u256 Transaction::gasPrice() const { } } -void Transaction::checkOutExternalGas( const ChainParams& _cp, uint64_t _bn, bool _force ) { +void Transaction::checkOutExternalGas( const ChainParams& _cp, time_t _committedBlockTimestamp, + uint64_t _committedBlockNumber, bool _force ) { u256 const& difficulty = _cp.externalGasDifficulty; assert( difficulty > 0 ); if ( ( _force || !m_externalGasIsChecked ) && !isInvalid() ) { @@ -203,18 +204,12 @@ void Transaction::checkOutExternalGas( const ChainParams& _cp, uint64_t _bn, boo } u256 externalGas = ~u256( 0 ) / u256( hash ) / difficulty; if ( externalGas > 0 ) - ctrace << "Mined gas: " << externalGas << endl; + ctrace << "Mined gas: " << externalGas; EVMSchedule scheduleForUse = ConstantinopleSchedule; - if ( CorrectForkInPowPatch::isEnabled() ) - scheduleForUse = _cp.scheduleForBlockNumber( _bn ); - - // never call checkOutExternalGas with non-last block - if ( _bn != CorrectForkInPowPatch::getLastBlockNumber() ) { - ctrace << _bn << " != " << CorrectForkInPowPatch::getLastBlockNumber(); - BOOST_THROW_EXCEPTION( std::runtime_error( - "Internal error: checkOutExternalGas() has invalid block number" ) ); - } + if ( CorrectForkInPowPatch::isEnabledWhen( _committedBlockTimestamp ) ) + scheduleForUse = _cp.makeEvmSchedule( + _committedBlockTimestamp, _committedBlockNumber ); // BUG should be +1 if ( externalGas >= baseGasRequired( scheduleForUse ) ) m_externalGas = externalGas; diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index dffadb347..e35edf50b 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -122,7 +122,8 @@ class Transaction : public TransactionBase { u256 gasPrice() const; - void checkOutExternalGas( const ChainParams& _cp, uint64_t _bn, bool _force = false ); + void checkOutExternalGas( const ChainParams& _cp, time_t _committedBlockTimestamp, + uint64_t _committedBlockNumber, bool _force ); void ignoreExternalGas() { m_externalGasIsChecked = true; diff --git a/libethereum/ValidationSchemes.cpp b/libethereum/ValidationSchemes.cpp index bcd49dd33..4040e774a 100644 --- a/libethereum/ValidationSchemes.cpp +++ b/libethereum/ValidationSchemes.cpp @@ -17,7 +17,13 @@ along with cpp-ethereum. If not, see . */ #include "ValidationSchemes.h" + +#include + #include + +#include + #include using namespace std; @@ -254,7 +260,6 @@ void validateConfigJson( js::mObject const& _obj ) { { { js::int_type }, JsonFieldPresence::Optional } }, { "rotateAfterBlock", { { js::int_type }, JsonFieldPresence::Optional } }, { "contractStorageLimit", { { js::int_type }, JsonFieldPresence::Optional } }, - { "contractStoragePatchTimestamp", { { js::int_type }, JsonFieldPresence::Optional } }, { "dbStorageLimit", { { js::int_type }, JsonFieldPresence::Optional } }, { "nodes", { { js::array_type }, JsonFieldPresence::Required } }, { "maxConsensusStorageBytes", { { js::int_type }, JsonFieldPresence::Optional } }, @@ -263,22 +268,20 @@ void validateConfigJson( js::mObject const& _obj ) { { "maxSkaledLeveldbStorageBytes", { { js::int_type }, JsonFieldPresence::Optional } }, { "freeContractDeployment", { { js::bool_type }, JsonFieldPresence::Optional } }, { "multiTransactionMode", { { js::bool_type }, JsonFieldPresence::Optional } }, - { "revertableFSPatchTimestamp", { { js::int_type }, JsonFieldPresence::Optional } }, - { "contractStorageZeroValuePatchTimestamp", - { { js::int_type }, JsonFieldPresence::Optional } }, - { "verifyDaSigsPatchTimestamp", { { js::int_type }, JsonFieldPresence::Optional } }, - { "storageDestructionPatchTimestamp", - { { js::int_type }, JsonFieldPresence::Optional } }, - { "powCheckPatchTimestamp", { { js::int_type }, JsonFieldPresence::Optional } }, - { "pushZeroPatchTimestamp", { { js::int_type }, JsonFieldPresence::Optional } }, - { "nodeGroups", { { js::obj_type }, JsonFieldPresence::Optional } }, { "nodeGroups", { { js::obj_type }, JsonFieldPresence::Optional } }, - { "skipInvalidTransactionsPatchTimestamp", - { { js::int_type }, JsonFieldPresence::Optional } }, - { "precompiledConfigPatchTimestamp", - { { js::int_type }, JsonFieldPresence::Optional } }, - { "correctForkInPowPatchTimestamp", - { { js::int_type }, JsonFieldPresence::Optional } } } ); + { "nodeGroups", { { js::obj_type }, JsonFieldPresence::Optional } } }, + []( const string& _key ) { + // function fow allowing fields + // exception means bad name + try { + string patchName = boost::algorithm::erase_last_copy( _key, "Timestamp" ); + patchName[0] = toupper( patchName[0] ); + getEnumForPatchName( patchName ); + return true; + } catch ( const std::out_of_range& ) { + return false; + } + } ); js::mArray const& nodes = sChain.at( "nodes" ).get_array(); for ( auto const& obj : nodes ) { diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 8d3f22bd9..4771e9004 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -131,17 +131,19 @@ struct CallParameters { class EnvInfo { public: - EnvInfo( BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed, - u256 const& _chainID ) - : m_headerInfo( _current ), + EnvInfo( BlockHeader const& _working, LastBlockHashesFace const& _lh, + time_t _committedBlockTimestamp, u256 const& _gasUsed, u256 const& _chainID ) + : m_headerInfo( _working ), m_lastHashes( _lh ), + m_committedBlockTimestamp( _committedBlockTimestamp ), m_gasUsed( _gasUsed ), m_chainID( _chainID ) {} // Constructor with custom gasLimit - used in some synthetic scenarios like eth_estimateGas RPC // method - EnvInfo( BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed, - u256 const& _gasLimit, u256 const& _chainID ) - : EnvInfo( _current, _lh, _gasUsed, _chainID ) { + EnvInfo( BlockHeader const& _working, LastBlockHashesFace const& _lh, + time_t _committedBlockTimestamp, u256 const& _gasUsed, u256 const& _gasLimit, + u256 const& _chainID ) + : EnvInfo( _working, _lh, _committedBlockTimestamp, _gasUsed, _chainID ) { m_headerInfo.setGasLimit( _gasLimit ); } @@ -153,12 +155,14 @@ class EnvInfo { u256 const& difficulty() const { return m_headerInfo.difficulty(); } u256 const& gasLimit() const { return m_headerInfo.gasLimit(); } LastBlockHashesFace const& lastHashes() const { return m_lastHashes; } + time_t committedBlockTimestamp() const { return m_committedBlockTimestamp; } u256 const& gasUsed() const { return m_gasUsed; } u256 const& chainID() const { return m_chainID; } private: BlockHeader m_headerInfo; LastBlockHashesFace const& m_lastHashes; + time_t m_committedBlockTimestamp; u256 m_gasUsed; u256 m_chainID; }; diff --git a/libevm/LegacyVM.cpp b/libevm/LegacyVM.cpp index 2fdbf431d..f0128a9f2 100644 --- a/libevm/LegacyVM.cpp +++ b/libevm/LegacyVM.cpp @@ -16,7 +16,7 @@ */ #include "LegacyVM.h" -#include "libskale/PushZeroPatch.h" +#include using namespace std; using namespace dev; @@ -1370,7 +1370,7 @@ void LegacyVM::interpretCases() { // we need to increment program counter only by one since // the value is not read from program code as in PUSH1 CASE( PUSH0 ) { - if ( !PushZeroPatch::isEnabled() ) { + if ( !m_schedule->havePush0 ) { throwBadInstruction(); } ON_OP(); diff --git a/libhistoric/AlethExecutive.cpp b/libhistoric/AlethExecutive.cpp index f65a5bc58..fbe3de73e 100644 --- a/libhistoric/AlethExecutive.cpp +++ b/libhistoric/AlethExecutive.cpp @@ -12,6 +12,7 @@ #include "libethereum/Interface.h" #include "libevm/LegacyVM.h" #include "libevm/VMFactory.h" +#include #include using namespace std; @@ -75,10 +76,11 @@ void AlethExecutive::accrueSubState( SubState& _parentContext ) { void AlethExecutive::initialize( Transaction const& _transaction ) { m_t = _transaction; - m_baseGasRequired = m_t.baseGasRequired( m_sealEngine.evmSchedule( m_envInfo.number() ) ); + m_baseGasRequired = m_t.baseGasRequired( + m_chainParams.makeEvmSchedule( m_envInfo.committedBlockTimestamp(), m_envInfo.number() ) ); try { - m_sealEngine.verifyTransaction( - ImportRequirements::Everything, m_t, m_envInfo.header(), m_envInfo.gasUsed() ); + Ethash::verifyTransaction( m_chainParams, ImportRequirements::Everything, m_t, + m_envInfo.committedBlockTimestamp(), m_envInfo.header(), m_envInfo.gasUsed() ); } catch ( Exception const& ex ) { m_excepted = toTransactionException( ex ); throw; @@ -150,14 +152,14 @@ bool AlethExecutive::call( // for the transaction. // Increment associated nonce for sender. if ( _p.senderAddress != MaxAddress || - m_envInfo.number() < m_sealEngine.chainParams().experimentalForkBlock ) // EIP86 + m_envInfo.number() < m_chainParams.experimentalForkBlock ) // EIP86 m_s.incNonce( _p.senderAddress ); } m_savepoint = m_s.savepoint(); - if ( m_sealEngine.isPrecompiled( _p.codeAddress, m_envInfo.number() ) ) { + if ( m_chainParams.isPrecompiled( _p.codeAddress, m_envInfo.number() ) ) { // Empty RIPEMD contract needs to be deleted even in case of OOG // because of the anomaly on the main net caused by buggy behavior by both Geth and Parity // https://github.com/ethereum/go-ethereum/pull/3341/files#diff-2433aa143ee4772026454b8abd76b9dd @@ -168,7 +170,7 @@ bool AlethExecutive::call( if ( _p.receiveAddress == c_RipemdPrecompiledAddress ) m_s.unrevertableTouch( _p.codeAddress ); - bigint g = m_sealEngine.costOfPrecompiled( _p.codeAddress, _p.data, m_envInfo.number() ); + bigint g = m_chainParams.costOfPrecompiled( _p.codeAddress, _p.data, m_envInfo.number() ); if ( _p.gas < g ) { m_excepted = TransactionException::OutOfGasBase; // Bail from exception. @@ -179,7 +181,7 @@ bool AlethExecutive::call( bytes output; bool success; tie( success, output ) = - m_sealEngine.executePrecompiled( _p.codeAddress, _p.data, m_envInfo.number() ); + m_chainParams.executePrecompiled( _p.codeAddress, _p.data, m_envInfo.number() ); size_t outputSize = output.size(); m_output = owning_bytes_ref{ std::move( output ), 0, outputSize }; if ( !success ) { @@ -196,7 +198,7 @@ bool AlethExecutive::call( // Contract will be executed with the version stored in account auto const version = m_s.version( _p.codeAddress ); - m_ext = make_shared< AlethExtVM >( m_s, m_envInfo, m_sealEngine, _p.receiveAddress, + m_ext = make_shared< AlethExtVM >( m_s, m_envInfo, m_chainParams, _p.receiveAddress, _p.senderAddress, _origin, _p.apparentValue, _gasPrice, _p.data, &c, codeHash, version, m_depth, false, _p.staticCall ); } @@ -210,7 +212,9 @@ bool AlethExecutive::call( bool AlethExecutive::create( Address const& _txSender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin ) { // Contract will be created with the version corresponding to latest hard fork - auto const latestVersion = m_sealEngine.evmSchedule( m_envInfo.number() ).accountVersion; + auto const latestVersion = + m_chainParams.makeEvmSchedule( m_envInfo.committedBlockTimestamp(), m_envInfo.number() ) + .accountVersion; return createWithAddressFromNonceAndSender( _txSender, _endowment, _gasPrice, _gas, _init, _origin, latestVersion ); } @@ -244,7 +248,7 @@ bool AlethExecutive::executeCreate( Address const& _sender, u256 const& _endowme u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin, u256 const& _version ) { if ( _sender != MaxAddress || - m_envInfo.number() < m_sealEngine.chainParams().experimentalForkBlock ) // EIP86 + m_envInfo.number() < m_chainParams.experimentalForkBlock ) // EIP86 m_s.incNonce( _sender ); m_savepoint = m_s.savepoint(); @@ -271,7 +275,7 @@ bool AlethExecutive::executeCreate( Address const& _sender, u256 const& _endowme m_s.transferBalance( _sender, m_newAddress, _endowment ); u256 newNonce = m_s.requireAccountStartNonce(); - if ( m_envInfo.number() >= m_sealEngine.chainParams().EIP158ForkBlock ) + if ( m_envInfo.number() >= m_chainParams.EIP158ForkBlock ) newNonce += 1; m_s.setNonce( m_newAddress, newNonce ); @@ -279,7 +283,7 @@ bool AlethExecutive::executeCreate( Address const& _sender, u256 const& _endowme // Schedule _init execution if not empty. if ( !_init.empty() ) - m_ext = make_shared< AlethExtVM >( m_s, m_envInfo, m_sealEngine, m_newAddress, _sender, + m_ext = make_shared< AlethExtVM >( m_s, m_envInfo, m_chainParams, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, sha3( _init ), _version, m_depth, true, false ); else diff --git a/libhistoric/AlethExecutive.h b/libhistoric/AlethExecutive.h index 62f18c8b1..eb61ea2d1 100644 --- a/libhistoric/AlethExecutive.h +++ b/libhistoric/AlethExecutive.h @@ -47,8 +47,8 @@ class AlethExecutive { public: /// Simple constructor; executive will operate on given state, with the given environment info. AlethExecutive( dev::eth::HistoricState& _s, EnvInfo const& _envInfo, - SealEngineFace const& _sealEngine, unsigned _level = 0 ) - : m_s( _s ), m_envInfo( _envInfo ), m_depth( _level ), m_sealEngine( _sealEngine ){}; + ChainOperationParams const& _chainParams, unsigned _level = 0 ) + : m_s( _s ), m_envInfo( _envInfo ), m_depth( _level ), m_chainParams( _chainParams ){}; /** Easiest constructor. * Creates executive to operate on the state of end of the given block, populating environment @@ -167,7 +167,7 @@ class AlethExecutive { LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize(). u256 m_gasCost; - SealEngineFace const& m_sealEngine; + ChainOperationParams const& m_chainParams; bool m_isCreation = false; Address m_newAddress; diff --git a/libhistoric/AlethExtVM.cpp b/libhistoric/AlethExtVM.cpp index ab7f12199..0ffa58a8b 100644 --- a/libhistoric/AlethExtVM.cpp +++ b/libhistoric/AlethExtVM.cpp @@ -119,7 +119,7 @@ evmc_status_code AlethExtVM::transactionExceptionToEvmcStatusCode( TransactionEx CallResult AlethExtVM::call( CallParameters& _p ) { - dev::eth::AlethExecutive e{ m_s, envInfo(), m_sealEngine, depth + 1 }; + dev::eth::AlethExecutive e{ m_s, envInfo(), m_chainParams, depth + 1 }; if ( !e.call( _p, gasPrice, origin ) ) { go( depth, e, _p.onOp ); e.accrueSubState( sub ); @@ -143,7 +143,7 @@ void AlethExtVM::setStore( u256 _n, u256 _v ) { CreateResult AlethExtVM::create( u256 _endowment, u256& io_gas, bytesConstRef _code, Instruction _op, u256 _salt, OnOpFunc const& _onOp ) { - AlethExecutive e{ m_s, envInfo(), m_sealEngine, depth + 1 }; + AlethExecutive e{ m_s, envInfo(), m_chainParams, depth + 1 }; bool result = false; if ( _op == Instruction::CREATE ) result = e.createOpcode( myAddress, _endowment, gasPrice, io_gas, _code, origin ); @@ -177,7 +177,7 @@ h256 AlethExtVM::blockHash( u256 _number ) { if ( _number >= currentNumber || _number < ( std::max< u256 >( 256, currentNumber ) - 256 ) ) return h256(); - if ( currentNumber < m_sealEngine.chainParams().experimentalForkBlock + 256 ) { + if ( currentNumber < m_chainParams.experimentalForkBlock + 256 ) { h256 const parentHash = envInfo().header().parentHash(); h256s const lastHashes = envInfo().lastHashes().precedingHashes( parentHash ); @@ -192,6 +192,6 @@ h256 AlethExtVM::blockHash( u256 _number ) { ExecutionResult res; std::tie( res, std::ignore ) = - m_s.execute( envInfo(), m_sealEngine, tx, skale::Permanence::Reverted ); + m_s.execute( envInfo(), m_chainParams, tx, skale::Permanence::Reverted ); return h256( res.output ); } diff --git a/libhistoric/AlethExtVM.h b/libhistoric/AlethExtVM.h index 41eed8015..c7a3785d1 100644 --- a/libhistoric/AlethExtVM.h +++ b/libhistoric/AlethExtVM.h @@ -30,15 +30,17 @@ class SealEngineFace; class AlethExtVM : public ExtVMFace { public: /// Full constructor. - AlethExtVM( HistoricState& _s, EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, - Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, - bytesConstRef _data, bytesConstRef _code, h256 const& _codeHash, u256 const& _version, - unsigned _depth, bool _isCreate, bool _staticCall ) + AlethExtVM( HistoricState& _s, EnvInfo const& _envInfo, + ChainOperationParams const& _chainParams, Address _myAddress, Address _caller, + Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, + h256 const& _codeHash, u256 const& _version, unsigned _depth, bool _isCreate, + bool _staticCall ) : ExtVMFace( _envInfo, _myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _codeHash, _version, _depth, _isCreate, _staticCall ), m_s( _s ), - m_sealEngine( _sealEngine ), - m_evmSchedule( initEvmSchedule( envInfo().number(), _version ) ) { + m_chainParams( _chainParams ), + m_evmSchedule( initEvmSchedule( + _envInfo.committedBlockTimestamp(), envInfo().number(), _version ) ) { // Contract: processing account must exist. In case of CALL, the ExtVM // is created only if an account has code (so exist). In case of CREATE // the account must be created first. @@ -97,10 +99,12 @@ class AlethExtVM : public ExtVMFace { static evmc_status_code transactionExceptionToEvmcStatusCode( TransactionException ex ); private: - EVMSchedule const& initEvmSchedule( int64_t _blockNumber, u256 const& _version ) const { + EVMSchedule initEvmSchedule( + time_t _committedBlockTimestamp, int64_t _workingBlockNumber, u256 const& _version ) const { // If _version is latest for the block, select corresponding latest schedule. // Otherwise run with the latest schedule known to correspond to the _version. - EVMSchedule const& currentBlockSchedule = m_sealEngine.evmSchedule( _blockNumber ); + EVMSchedule currentBlockSchedule = + m_chainParams.makeEvmSchedule( _committedBlockTimestamp, _workingBlockNumber ); if ( currentBlockSchedule.accountVersion == _version ) return currentBlockSchedule; else @@ -109,8 +113,9 @@ class AlethExtVM : public ExtVMFace { dev::eth::HistoricState& m_s; ///< A reference to the base state. - SealEngineFace const& m_sealEngine; - EVMSchedule const& m_evmSchedule; + time_t m_committedBlockTimestamp; + ChainOperationParams const& m_chainParams; + EVMSchedule const m_evmSchedule; }; } // namespace eth diff --git a/libhistoric/HistoricState.cpp b/libhistoric/HistoricState.cpp index d1e8f6d57..6d5ef615c 100644 --- a/libhistoric/HistoricState.cpp +++ b/libhistoric/HistoricState.cpp @@ -585,11 +585,11 @@ void HistoricState::rollback( size_t _savepoint ) { } std::pair< ExecutionResult, TransactionReceipt > HistoricState::execute( EnvInfo const& _envInfo, - SealEngineFace const& _sealEngine, Transaction const& _t, skale::Permanence _p, + eth::ChainOperationParams const& _chainParams, Transaction const& _t, skale::Permanence _p, OnOpFunc const& _onOp ) { // Create and initialize the executive. This will throw fairly cheaply and quickly if the // transaction is bad in any way. - AlethExecutive e( *this, _envInfo, _sealEngine ); + AlethExecutive e( *this, _envInfo, _chainParams, 0 ); ExecutionResult res; e.setResultRecipient( res ); @@ -620,7 +620,7 @@ std::pair< ExecutionResult, TransactionReceipt > HistoricState::execute( EnvInfo } TransactionReceipt const receipt = - _envInfo.number() >= _sealEngine.chainParams().byzantiumForkBlock ? + _envInfo.number() >= _chainParams.byzantiumForkBlock ? TransactionReceipt( statusCode, startGasUsed + e.gasUsed(), e.logs() ) : TransactionReceipt( globalRoot(), startGasUsed + e.gasUsed(), e.logs() ); diff --git a/libhistoric/HistoricState.h b/libhistoric/HistoricState.h index ab07529b7..201e214d3 100644 --- a/libhistoric/HistoricState.h +++ b/libhistoric/HistoricState.h @@ -157,7 +157,7 @@ class HistoricState { /// Execute a given transaction. /// This will change the state accordingly. std::pair< ExecutionResult, TransactionReceipt > execute( EnvInfo const& _envInfo, - SealEngineFace const& _sealEngine, Transaction const& _t, + eth::ChainOperationParams const& _chainParams, Transaction const& _t, skale::Permanence _p = skale::Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc() ); diff --git a/libskale/CMakeLists.txt b/libskale/CMakeLists.txt index 26b492aa1..f05274265 100644 --- a/libskale/CMakeLists.txt +++ b/libskale/CMakeLists.txt @@ -12,18 +12,9 @@ set(sources SnapshotHashAgent.cpp UnsafeRegion.cpp TotalStorageUsedPatch.cpp - ContractStorageLimitPatch.cpp - ContractStorageZeroValuePatch.cpp - VerifyDaSigsPatch.cpp AmsterdamFixPatch.cpp - RevertableFSPatch.cpp OverlayFS.cpp - StorageDestructionPatch.cpp - POWCheckPatch.cpp - PrecompiledConfigPatch.cpp - PushZeroPatch.cpp SkipInvalidTransactionsPatch.cpp - CorrectForkInPowPatch.cpp ) set(headers @@ -38,14 +29,9 @@ set(headers SnapshotHashAgent.h UnsafeRegion.h TotalStorageUsedPatch.h - ContractStorageLimitPatch.h AmsterdamFixPatch.h - RevertableFSPatch.h - POWCheckPatch.h - PrecompiledConfigPatch.h OverlayFS.h SkipInvalidTransactionsPatch.h - CorrectForkInPowPatch.h ) add_library(skale ${sources} ${headers}) diff --git a/libskale/ContractStorageLimitPatch.cpp b/libskale/ContractStorageLimitPatch.cpp deleted file mode 100644 index 3e15ef1cc..000000000 --- a/libskale/ContractStorageLimitPatch.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "ContractStorageLimitPatch.h" - -time_t ContractStorageLimitPatch::contractStoragePatchTimestamp; -time_t ContractStorageLimitPatch::lastBlockTimestamp; - -bool ContractStorageLimitPatch::isEnabled() { - if ( contractStoragePatchTimestamp == 0 ) { - return false; - } - return contractStoragePatchTimestamp <= lastBlockTimestamp; -} diff --git a/libskale/ContractStorageLimitPatch.h b/libskale/ContractStorageLimitPatch.h deleted file mode 100644 index f7442b572..000000000 --- a/libskale/ContractStorageLimitPatch.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef CONTRACTSTORAGELIMITPATCH_H -#define CONTRACTSTORAGELIMITPATCH_H - -#include - -#include - -namespace dev { -namespace eth { -class Client; -} -} // namespace dev - -/* - * Context: contractStorageUsed counter didn't work well in one case - * Solution: we fixed the bug and added new config field introudceChangesTimestamp - * Purpose: avoid incorrect txn behaviour - * Version introduced: - */ -class ContractStorageLimitPatch : public SchainPatch { -public: - static bool isEnabled(); - - static void setTimestamp( time_t _timeStamp ) { - printInfo( __FILE__, _timeStamp ); - contractStoragePatchTimestamp = _timeStamp; - } - -private: - friend class dev::eth::Client; - static time_t contractStoragePatchTimestamp; - static time_t lastBlockTimestamp; -}; - -#endif // CONTRACTSTORAGELIMITPATCH_H diff --git a/libskale/ContractStorageZeroValuePatch.cpp b/libskale/ContractStorageZeroValuePatch.cpp deleted file mode 100644 index b77887f74..000000000 --- a/libskale/ContractStorageZeroValuePatch.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "ContractStorageZeroValuePatch.h" - -time_t ContractStorageZeroValuePatch::contractStorageZeroValuePatchTimestamp = 0; -time_t ContractStorageZeroValuePatch::lastBlockTimestamp = 0; - -bool ContractStorageZeroValuePatch::isEnabled() { - if ( contractStorageZeroValuePatchTimestamp == 0 ) { - return false; - } - return contractStorageZeroValuePatchTimestamp <= lastBlockTimestamp; -} diff --git a/libskale/ContractStorageZeroValuePatch.h b/libskale/ContractStorageZeroValuePatch.h deleted file mode 100644 index f64d3059a..000000000 --- a/libskale/ContractStorageZeroValuePatch.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef CONTRACTSTORAGEZEROVALUEPATCH_H -#define CONTRACTSTORAGEZEROVALUEPATCH_H - -#include - -#include - -namespace dev { -namespace eth { -class Client; -} -} // namespace dev - -/* - * Context: contractStorageUsed counter didn't work well in one case - * Solution: we fixed the bug and added new config field introudceChangesTimestamp - * Purpose: avoid incorrect txn behaviour - * Version introduced: - */ -class ContractStorageZeroValuePatch : public SchainPatch { -public: - static bool isEnabled(); - - static void setTimestamp( time_t _timeStamp ) { - printInfo( __FILE__, _timeStamp ); - contractStorageZeroValuePatchTimestamp = _timeStamp; - } - - -private: - friend class dev::eth::Client; - static time_t contractStorageZeroValuePatchTimestamp; - static time_t lastBlockTimestamp; -}; - -#endif // CONTRACTSTORAGEZEROVALUYEPATCH_H diff --git a/libskale/CorrectForkInPowPatch.cpp b/libskale/CorrectForkInPowPatch.cpp deleted file mode 100644 index aec18bc29..000000000 --- a/libskale/CorrectForkInPowPatch.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "CorrectForkInPowPatch.h" - -time_t CorrectForkInPowPatch::activationTimestamp; -time_t CorrectForkInPowPatch::lastBlockTimestamp; -unsigned CorrectForkInPowPatch::lastBlockNumber; - -bool CorrectForkInPowPatch::isEnabled() { - if ( activationTimestamp == 0 ) { - return false; - } - return activationTimestamp <= lastBlockTimestamp; -} diff --git a/libskale/CorrectForkInPowPatch.h b/libskale/CorrectForkInPowPatch.h deleted file mode 100644 index 94c0f766e..000000000 --- a/libskale/CorrectForkInPowPatch.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef CORRECTFORKINPOWPATCH_H -#define CORRECTFORKINPOWPATCH_H - -#include - -#include - -namespace dev { -namespace eth { -class Client; -} -namespace test { -class TestBlockChain; -class TestOutputHelperFixture; -} // namespace test -} // namespace dev - -/* - * Context: use current, and not Constantinople, fork in Transaction::checkOutExternalGas() - */ -class CorrectForkInPowPatch : public SchainPatch { -public: - static bool isEnabled(); - - static void setTimestamp( time_t _timeStamp ) { - printInfo( __FILE__, _timeStamp ); - activationTimestamp = _timeStamp; - } - - static unsigned getLastBlockNumber() { return lastBlockNumber; } - -private: - friend class dev::eth::Client; - friend class dev::test::TestBlockChain; - friend class dev::test::TestOutputHelperFixture; - static time_t activationTimestamp; - static time_t lastBlockTimestamp; - static unsigned lastBlockNumber; -}; - -#endif // CORRECTFORKINPOWPATCH_H diff --git a/libskale/OverlayDB.cpp b/libskale/OverlayDB.cpp index 2c6b5eebb..113cb9987 100644 --- a/libskale/OverlayDB.cpp +++ b/libskale/OverlayDB.cpp @@ -23,8 +23,8 @@ */ #include "OverlayDB.h" -#include "ContractStorageZeroValuePatch.h" #include "libhistoric/HistoricState.h" +#include #include @@ -151,7 +151,7 @@ void OverlayDB::commitStorageValues() { static const h256 ZERO_VALUE( 0 ); - if ( ContractStorageZeroValuePatch::isEnabled() && value == ZERO_VALUE ) { + if ( ContractStorageZeroValuePatch::isEnabledInWorkingBlock() && value == ZERO_VALUE ) { // if the value is zero, the pair will be deleted in LevelDB // if it exists m_db_face->kill( diff --git a/libskale/OverlayFS.cpp b/libskale/OverlayFS.cpp index 8796dff4d..d9867249e 100644 --- a/libskale/OverlayFS.cpp +++ b/libskale/OverlayFS.cpp @@ -23,8 +23,8 @@ */ #include "OverlayFS.h" -#include "RevertableFSPatch.h" #include +#include #include #include diff --git a/libskale/POWCheckPatch.cpp b/libskale/POWCheckPatch.cpp deleted file mode 100644 index 79a43dddd..000000000 --- a/libskale/POWCheckPatch.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "POWCheckPatch.h" - -time_t POWCheckPatch::powCheckPatchTimestamp; -time_t POWCheckPatch::lastBlockTimestamp; - -bool POWCheckPatch::isEnabled() { - if ( powCheckPatchTimestamp == 0 ) { - return false; - } - return powCheckPatchTimestamp <= lastBlockTimestamp; -} diff --git a/libskale/POWCheckPatch.h b/libskale/POWCheckPatch.h deleted file mode 100644 index 65a4f5905..000000000 --- a/libskale/POWCheckPatch.h +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -#ifndef POWCHECKPATCH_H -#define POWCHECKPATCH_H - -namespace dev { -namespace eth { -class Client; -} -} // namespace dev - -/* - * Context: enable fix for POW txns gas limit check - */ -class POWCheckPatch : public SchainPatch { -public: - static bool isEnabled(); - - static void setTimestamp( time_t _timeStamp ) { - printInfo( __FILE__, _timeStamp ); - powCheckPatchTimestamp = _timeStamp; - } - -private: - friend class dev::eth::Client; - static time_t powCheckPatchTimestamp; - static time_t lastBlockTimestamp; -}; - -#endif // POWCHECKPATCH_H diff --git a/libskale/PrecompiledConfigPatch.cpp b/libskale/PrecompiledConfigPatch.cpp deleted file mode 100644 index f36557d61..000000000 --- a/libskale/PrecompiledConfigPatch.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "PrecompiledConfigPatch.h" - -time_t PrecompiledConfigPatch::precompiledConfigPatchTimestamp; -time_t PrecompiledConfigPatch::lastBlockTimestamp; - -bool PrecompiledConfigPatch::isEnabled() { - if ( precompiledConfigPatchTimestamp == 0 ) { - return false; - } - return precompiledConfigPatchTimestamp <= lastBlockTimestamp; -} diff --git a/libskale/PrecompiledConfigPatch.h b/libskale/PrecompiledConfigPatch.h deleted file mode 100644 index 776dd47cc..000000000 --- a/libskale/PrecompiledConfigPatch.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef PRECOMPILEDCONFIGPATCH_H -#define PRECOMPILEDCONFIGPATCH_H - -#include -#include - -namespace dev { -namespace eth { -class Client; -} -} // namespace dev - -/* - * Context: enable precompiled contracts to read historical config data - */ -class PrecompiledConfigPatch : public SchainPatch { -public: - static bool isEnabled(); - - static void setTimestamp( time_t _timeStamp ) { - printInfo( __FILE__, _timeStamp ); - precompiledConfigPatchTimestamp = _timeStamp; - } - -private: - friend class dev::eth::Client; - static time_t precompiledConfigPatchTimestamp; - static time_t lastBlockTimestamp; -}; - - -#endif // PRECOMPILEDCONFIGPATCH_H diff --git a/libskale/PushZeroPatch.cpp b/libskale/PushZeroPatch.cpp deleted file mode 100644 index e7ef4f6c1..000000000 --- a/libskale/PushZeroPatch.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "PushZeroPatch.h" - -time_t PushZeroPatch::pushZeroPatchTimestamp; -time_t PushZeroPatch::lastBlockTimestamp; - -bool PushZeroPatch::isEnabled() { - if ( pushZeroPatchTimestamp == 0 ) { - return false; - } - return pushZeroPatchTimestamp <= lastBlockTimestamp; -} diff --git a/libskale/PushZeroPatch.h b/libskale/PushZeroPatch.h deleted file mode 100644 index 6ebab4e9f..000000000 --- a/libskale/PushZeroPatch.h +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include - -namespace dev { -namespace eth { -class Client; -} -} // namespace dev - -/* - * Context: enable effective storage destruction - */ -class PushZeroPatch : public SchainPatch { -public: - static bool isEnabled(); - - static void setTimestamp( time_t _timeStamp ) { - printInfo( __FILE__, _timeStamp ); - pushZeroPatchTimestamp = _timeStamp; - } - - -private: - friend class dev::eth::Client; - static time_t pushZeroPatchTimestamp; - static time_t lastBlockTimestamp; -}; \ No newline at end of file diff --git a/libskale/RevertableFSPatch.cpp b/libskale/RevertableFSPatch.cpp deleted file mode 100644 index 3f638befd..000000000 --- a/libskale/RevertableFSPatch.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "RevertableFSPatch.h" - -time_t RevertableFSPatch::revertableFSPatchTimestamp; -time_t RevertableFSPatch::lastBlockTimestamp; - -bool RevertableFSPatch::isEnabled() { - if ( revertableFSPatchTimestamp == 0 ) { - return false; - } - return revertableFSPatchTimestamp <= lastBlockTimestamp; -} \ No newline at end of file diff --git a/libskale/RevertableFSPatch.h b/libskale/RevertableFSPatch.h deleted file mode 100644 index 83321bfec..000000000 --- a/libskale/RevertableFSPatch.h +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include - -namespace dev { -namespace eth { -class Client; -} -} // namespace dev - -/* - * Context: enable revertable filestorage precompileds - */ -class RevertableFSPatch : public SchainPatch { -public: - static bool isEnabled(); - - static void setTimestamp( time_t _timeStamp ) { - printInfo( __FILE__, _timeStamp ); - revertableFSPatchTimestamp = _timeStamp; - } - -private: - friend class dev::eth::Client; - static time_t revertableFSPatchTimestamp; - static time_t lastBlockTimestamp; -}; \ No newline at end of file diff --git a/libskale/SkipInvalidTransactionsPatch.cpp b/libskale/SkipInvalidTransactionsPatch.cpp index 5ab660337..571f1bc96 100644 --- a/libskale/SkipInvalidTransactionsPatch.cpp +++ b/libskale/SkipInvalidTransactionsPatch.cpp @@ -2,11 +2,21 @@ using namespace dev::eth; -time_t SkipInvalidTransactionsPatch::activationTimestamp; -time_t SkipInvalidTransactionsPatch::lastBlockTimestamp; +bool SkipInvalidTransactionsPatch::hasPotentialInvalidTransactionsInBlock( + dev::eth::BlockNumber _bn, const dev::eth::BlockChain& _bc ) { + if ( _bn == 0 ) + return false; + + time_t activationTimestamp = _bc.chainParams().getPatchTimestamp( getEnum() ); -bool SkipInvalidTransactionsPatch::isEnabled() { if ( activationTimestamp == 0 ) - return false; - return lastBlockTimestamp >= activationTimestamp; + return true; + + if ( _bn == dev::eth::PendingBlock ) + return !isEnabledInWorkingBlock(); + + if ( _bn == dev::eth::LatestBlock ) + _bn = _bc.number(); + + return !isEnabledInBlock( _bc, _bn ); } diff --git a/libskale/SkipInvalidTransactionsPatch.h b/libskale/SkipInvalidTransactionsPatch.h index 7c171b09e..558c9261b 100644 --- a/libskale/SkipInvalidTransactionsPatch.h +++ b/libskale/SkipInvalidTransactionsPatch.h @@ -2,7 +2,7 @@ #define SKIPINVALIDTRANSACTIONSPATCH_H #include -#include +#include #include #include #include @@ -32,21 +32,24 @@ class Client; // Transactions are removed from Transaction Queue as usually. // TODO better start to apply patches from 1st block after timestamp, not second + class SkipInvalidTransactionsPatch : public SchainPatch { public: - static bool isEnabled(); - - static void setTimestamp( time_t _activationTimestamp ) { - activationTimestamp = _activationTimestamp; - printInfo( __FILE__, _activationTimestamp ); + static SchainPatchEnum getEnum() { return SchainPatchEnum::SkipInvalidTransactionsPatch; } + static bool isEnabledInWorkingBlock() { return isPatchEnabledInWorkingBlock( getEnum() ); } + static bool isEnabledWhen( time_t _committedBlockTimestamp ) { + return isPatchEnabledWhen( getEnum(), _committedBlockTimestamp ); } - - static time_t getActivationTimestamp() { return activationTimestamp; } - -private: - friend class dev::eth::Client; - static time_t activationTimestamp; - static time_t lastBlockTimestamp; + static bool isEnabledInBlock( + const dev::eth::BlockChain& _bc, dev::eth::BlockNumber _bn = dev::eth::PendingBlock ) { + time_t timestamp = _bc.chainParams().getPatchTimestamp( getEnum() ); + return _bc.isPatchTimestampActiveInBlockNumber( timestamp, _bn ); + } + // returns true if block N can contain invalid transactions + // returns false if this block was created with SkipInvalidTransactionsPatch and they were + // skipped + static bool hasPotentialInvalidTransactionsInBlock( + dev::eth::BlockNumber _bn, const dev::eth::BlockChain& _bc ); }; #endif // SKIPINVALIDTRANSACTIONSPATCH_H diff --git a/libskale/State.cpp b/libskale/State.cpp index 3e3526610..405eb2c69 100644 --- a/libskale/State.cpp +++ b/libskale/State.cpp @@ -36,8 +36,6 @@ #include #include -#include "ContractStorageLimitPatch.h" - #include "libweb3jsonrpc/Eth.h" #include "libweb3jsonrpc/JsonHelper.h" @@ -45,8 +43,7 @@ #include #include -#include -#include +#include namespace fs = boost::filesystem; @@ -359,7 +356,7 @@ std::unordered_map< Address, u256 > State::addresses() const { boost::shared_lock< boost::shared_mutex > lock( *x_db_ptr ); if ( !checkVersion() ) { cerror << "Current state version is " << m_currentVersion << " but stored version is " - << *m_storedVersion << endl; + << *m_storedVersion; BOOST_THROW_EXCEPTION( AttemptToReadFromStateInThePast() ); } @@ -441,7 +438,7 @@ eth::Account* State::account( Address const& _address ) { if ( !checkVersion() ) { cerror << "Current state version is " << m_currentVersion << " but stored version is " - << *m_storedVersion << endl; + << *m_storedVersion; BOOST_THROW_EXCEPTION( AttemptToReadFromStateInThePast() ); } @@ -510,7 +507,7 @@ void State::commit( dev::eth::CommitBehaviour _commitBehaviour ) { m_db_ptr->kill( address ); m_db_ptr->killAuxiliary( address, Auxiliary::CODE ); - if ( StorageDestructionPatch::isEnabled() ) { + if ( StorageDestructionPatch::isEnabledInWorkingBlock() ) { clearStorage( address ); } @@ -669,7 +666,7 @@ std::map< h256, std::pair< u256, u256 > > State::storage_WITHOUT_LOCK( const Address& _contract ) const { if ( !checkVersion() ) { cerror << "Current state version is " << m_currentVersion << " but stored version is " - << *m_storedVersion << endl; + << *m_storedVersion; BOOST_THROW_EXCEPTION( AttemptToReadFromStateInThePast() ); } @@ -689,7 +686,7 @@ std::map< h256, std::pair< u256, u256 > > State::storage_WITHOUT_LOCK( } } - cdebug << "Self-destruct cleared values:" << storage.size() << endl; + cdebug << "Self-destruct cleared values:" << storage.size(); return storage; } @@ -896,7 +893,7 @@ void State::rollback( size_t _savepoint ) { // change log entry. switch ( change.kind ) { case Change::Storage: - if ( ContractStorageLimitPatch::isEnabled() ) { + if ( ContractStoragePatch::isEnabledInWorkingBlock() ) { rollbackStorageChange( change, account ); } else { account.setStorage( change.key, change.value ); @@ -925,7 +922,7 @@ void State::rollback( size_t _savepoint ) { m_changeLog.pop_back(); } clearFileStorageCache(); - if ( !ContractStorageLimitPatch::isEnabled() ) { + if ( !ContractStoragePatch::isEnabledInWorkingBlock() ) { resetStorageChanges(); } } @@ -1008,16 +1005,17 @@ bool State::empty() const { } std::pair< ExecutionResult, TransactionReceipt > State::execute( EnvInfo const& _envInfo, - SealEngineFace const& _sealEngine, Transaction const& _t, Permanence _p, + eth::ChainOperationParams const& _chainParams, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp ) { // Create and initialize the executive. This will throw fairly cheaply and quickly if the // transaction is bad in any way. // HACK 0 here is for gasPrice - Executive e( *this, _envInfo, _sealEngine, 0, 0, _p != Permanence::Committed ); + // TODO Not sure that 1st 0 as timestamp is acceptable here + Executive e( *this, _envInfo, _chainParams, 0, 0, _p != Permanence::Committed ); ExecutionResult res; e.setResultRecipient( res ); - bool isCacheEnabled = RevertableFSPatch::isEnabled(); + bool isCacheEnabled = RevertableFSPatch::isEnabledWhen( _envInfo.committedBlockTimestamp() ); resetOverlayFS( isCacheEnabled ); auto onOp = _onOp; @@ -1058,14 +1056,14 @@ std::pair< ExecutionResult, TransactionReceipt > State::execute( EnvInfo const& // shaLastTx.hex() << "\n"; TransactionReceipt receipt = - _envInfo.number() >= _sealEngine.chainParams().byzantiumForkBlock ? + _envInfo.number() >= _chainParams.byzantiumForkBlock ? TransactionReceipt( statusCode, startGasUsed + e.gasUsed(), e.logs() ) : TransactionReceipt( EmptyTrie, startGasUsed + e.gasUsed(), e.logs() ); receipt.setRevertReason( strRevertReason ); m_db_ptr->addReceiptToPartials( receipt ); m_fs_ptr->commit(); - removeEmptyAccounts = _envInfo.number() >= _sealEngine.chainParams().EIP158ForkBlock; + removeEmptyAccounts = _envInfo.number() >= _chainParams.EIP158ForkBlock; commit( removeEmptyAccounts ? dev::eth::CommitBehaviour::RemoveEmptyAccounts : dev::eth::CommitBehaviour::KeepEmptyAccounts ); @@ -1077,7 +1075,7 @@ std::pair< ExecutionResult, TransactionReceipt > State::execute( EnvInfo const& } TransactionReceipt receipt = - _envInfo.number() >= _sealEngine.chainParams().byzantiumForkBlock ? + _envInfo.number() >= _chainParams.byzantiumForkBlock ? TransactionReceipt( statusCode, startGasUsed + e.gasUsed(), e.logs() ) : TransactionReceipt( EmptyTrie, startGasUsed + e.gasUsed(), e.logs() ); receipt.setRevertReason( strRevertReason ); diff --git a/libskale/State.h b/libskale/State.h index 0fe41329e..94c7118ea 100644 --- a/libskale/State.h +++ b/libskale/State.h @@ -55,7 +55,6 @@ struct hash< boost::filesystem::path > { namespace dev { namespace eth { -class SealEngineFace; class Executive; } // namespace eth } // namespace dev @@ -339,7 +338,7 @@ class State { /// Execute a given transaction. /// This will change the state accordingly. std::pair< dev::eth::ExecutionResult, dev::eth::TransactionReceipt > execute( - dev::eth::EnvInfo const& _envInfo, dev::eth::SealEngineFace const& _sealEngine, + dev::eth::EnvInfo const& _envInfo, dev::eth::ChainOperationParams const& _chainParams, dev::eth::Transaction const& _t, Permanence _p = Permanence::Committed, dev::eth::OnOpFunc const& _onOp = dev::eth::OnOpFunc() ); diff --git a/libskale/StorageDestructionPatch.cpp b/libskale/StorageDestructionPatch.cpp deleted file mode 100644 index 5ae6b03c7..000000000 --- a/libskale/StorageDestructionPatch.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "StorageDestructionPatch.h" - -time_t StorageDestructionPatch::storageDestructionPatchTimestamp; -time_t StorageDestructionPatch::lastBlockTimestamp; - -bool StorageDestructionPatch::isEnabled() { - if ( storageDestructionPatchTimestamp == 0 ) { - return false; - } - return storageDestructionPatchTimestamp <= lastBlockTimestamp; -} diff --git a/libskale/StorageDestructionPatch.h b/libskale/StorageDestructionPatch.h deleted file mode 100644 index fb16bbb4d..000000000 --- a/libskale/StorageDestructionPatch.h +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include - -namespace dev { -namespace eth { -class Client; -} -} // namespace dev - -/* - * Context: enable effective storage destruction - */ -class StorageDestructionPatch : public SchainPatch { -public: - static bool isEnabled(); - - static void setTimestamp( time_t _timeStamp ) { - printInfo( __FILE__, _timeStamp ); - storageDestructionPatchTimestamp = _timeStamp; - } - - -private: - friend class dev::eth::Client; - static time_t storageDestructionPatchTimestamp; - static time_t lastBlockTimestamp; -}; \ No newline at end of file diff --git a/libskale/TotalStorageUsedPatch.cpp b/libskale/TotalStorageUsedPatch.cpp index f9438d09d..81a100655 100644 --- a/libskale/TotalStorageUsedPatch.cpp +++ b/libskale/TotalStorageUsedPatch.cpp @@ -8,12 +8,12 @@ using namespace dev; using namespace dev::eth; const Address magicAddress( toAddress( "0xE8E4Ea98530Bfe86f841E258fd6F3FD5c210c68f" ) ); -dev::eth::Client* TotalStorageUsedPatch::g_client; +dev::eth::Client* TotalStorageUsedPatch::client; void TotalStorageUsedPatch::onProgress( batched_io::db_operations_face& _db, size_t _blockNumber ) { if ( !_db.exists( dev::db::Slice( "\x0totalStorageUsed", 17 ) ) ) return; - if ( g_client->countAt( magicAddress ) == 0 ) + if ( client->countAt( magicAddress ) == 0 ) _db.insert( dev::db::Slice( "\x0totalStorageUsed", 17 ), dev::db::Slice( std::to_string( _blockNumber * 32 ) ) ); else diff --git a/libskale/TotalStorageUsedPatch.h b/libskale/TotalStorageUsedPatch.h index a15b5576b..40344833e 100644 --- a/libskale/TotalStorageUsedPatch.h +++ b/libskale/TotalStorageUsedPatch.h @@ -22,6 +22,10 @@ class Client; */ class TotalStorageUsedPatch : public SchainPatch { public: + static void init( dev::eth::Client* _client ) { + assert( _client ); + client = _client; + } static bool isInitOnChainNeeded( batched_io::db_operations_face& _db ) { return !_db.exists( ( dev::db::Slice ) "pieceUsageBytes" ); } @@ -32,8 +36,7 @@ class TotalStorageUsedPatch : public SchainPatch { static void onProgress( batched_io::db_operations_face& _db, size_t _blockNumber ); private: - friend class dev::eth::Client; - static dev::eth::Client* g_client; + static dev::eth::Client* client; }; #endif // TOTALSTORAGEUSEDPATCH_H diff --git a/libskale/VerifyDaSigsPatch.cpp b/libskale/VerifyDaSigsPatch.cpp deleted file mode 100644 index c8cf7a905..000000000 --- a/libskale/VerifyDaSigsPatch.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "VerifyDaSigsPatch.h" - -time_t VerifyDaSigsPatch::verifyDaSigsPatchTimestamp = 0; -time_t VerifyDaSigsPatch::lastBlockTimestamp = 0; - -bool VerifyDaSigsPatch::isEnabled() { - if ( verifyDaSigsPatchTimestamp == 0 ) { - return false; - } - return verifyDaSigsPatchTimestamp <= lastBlockTimestamp; -} -time_t VerifyDaSigsPatch::getVerifyDaSigsPatchTimestamp() { - return verifyDaSigsPatchTimestamp; -} diff --git a/libskale/VerifyDaSigsPatch.h b/libskale/VerifyDaSigsPatch.h deleted file mode 100644 index 426412507..000000000 --- a/libskale/VerifyDaSigsPatch.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef VERIFYDASIGSPATCH_H -#define VERIFYDASIDSPATCH_H - -#include - -#include - -namespace dev { -namespace eth { -class Client; -} -} // namespace dev - -/* - * Context: contractStorageUsed counter didn't work well in one case - * Solution: we fixed the bug and added new config field introudceChangesTimestamp - * Purpose: avoid incorrect txn behaviour - * Version introduced: - */ -class VerifyDaSigsPatch : public SchainPatch { -public: - static bool isEnabled(); - -private: - friend class dev::eth::Client; - static time_t verifyDaSigsPatchTimestamp; - static time_t lastBlockTimestamp; - - static void setTimestamp( time_t _timeStamp ) { - printInfo( __FILE__, _timeStamp ); - verifyDaSigsPatchTimestamp = _timeStamp; - } - -public: - static time_t getVerifyDaSigsPatchTimestamp(); -}; - -#endif \ No newline at end of file diff --git a/libskale/httpserveroverride.cpp b/libskale/httpserveroverride.cpp index f76c94c69..be29eecef 100644 --- a/libskale/httpserveroverride.cpp +++ b/libskale/httpserveroverride.cpp @@ -2607,12 +2607,14 @@ bool SkaleServerOverride::implStartListening( // proxygen HTTP cc::success( "/" ) + cc::notice( esm2str( esm ) ) + " " ); return true; } catch ( const std::exception& ex ) { - logTraceServerEvent( false, ipVer, bIsSSL ? "HTTPS" : "HTTP", pSrv->serverIndex(), esm, + logTraceServerEvent( false, ipVer, bIsSSL ? "HTTPS" : "HTTP", + pSrv ? pSrv->serverIndex() : -1, esm, cc::fatal( "FAILED" ) + cc::error( " to start " ) + cc::attention( "proxygen" ) + cc::debug( "/" ) + cc::warn( bIsSSL ? "HTTPS" : "HTTP" ) + cc::error( " server: " ) + cc::warn( ex.what() ) ); } catch ( ... ) { - logTraceServerEvent( false, ipVer, bIsSSL ? "HTTPS" : "HTTP", pSrv->serverIndex(), esm, + logTraceServerEvent( false, ipVer, bIsSSL ? "HTTPS" : "HTTP", + pSrv ? pSrv->serverIndex() : -1, esm, cc::fatal( "FAILED" ) + cc::error( " to start " ) + cc::attention( "proxygen" ) + cc::debug( "/" ) + cc::warn( bIsSSL ? "HTTPS" : "HTTP" ) + cc::error( " server: " ) + cc::warn( "unknown exception" ) ); diff --git a/libweb3jsonrpc/Eth.cpp b/libweb3jsonrpc/Eth.cpp index dad59ce88..b50874935 100644 --- a/libweb3jsonrpc/Eth.cpp +++ b/libweb3jsonrpc/Eth.cpp @@ -110,29 +110,9 @@ void GappedTransactionIndexCache::ensureCached( BlockNumber _bn, } // for } -// returns true if block N can contain invalid transactions -// returns false if this block was created with SkipInvalidTransactionsPatch and they were skipped -bool hasPotentialInvalidTransactionsInBlock( BlockNumber _bn, const Interface& _client ) { - if ( _bn == 0 ) - return false; - - if ( SkipInvalidTransactionsPatch::getActivationTimestamp() == 0 ) - return true; - - if ( _bn == PendingBlock ) - return !SkipInvalidTransactionsPatch::isEnabled(); - - if ( _bn == LatestBlock ) - _bn = _client.number(); - - time_t prev_ts = _client.blockInfo( _bn - 1 ).timestamp(); - - return prev_ts < SkipInvalidTransactionsPatch::getActivationTimestamp(); -} - #endif -Eth::Eth( const std::string& configPath, eth::Interface& _eth, eth::AccountHolder& _ethAccounts ) +Eth::Eth( const std::string& configPath, eth::Client& _eth, eth::AccountHolder& _ethAccounts ) : skutils::json_config_file_accessor( configPath ), m_eth( _eth ), m_ethAccounts( _ethAccounts ), @@ -294,7 +274,8 @@ Json::Value Eth::eth_getBlockTransactionCountByHash( string const& _blockHash ) #ifdef HISTORIC_STATE BlockNumber bn = client()->numberFromHash( blockHash ); - if ( !hasPotentialInvalidTransactionsInBlock( bn, *client() ) ) + if ( !SkipInvalidTransactionsPatch::hasPotentialInvalidTransactionsInBlock( + bn, client()->blockChain() ) ) #endif return toJS( client()->transactionCount( blockHash ) ); #ifdef HISTORIC_STATE @@ -313,7 +294,8 @@ Json::Value Eth::eth_getBlockTransactionCountByNumber( string const& _blockNumbe #ifdef HISTORIC_STATE BlockNumber bn = jsToBlockNumber( _blockNumber ); - if ( !hasPotentialInvalidTransactionsInBlock( bn, *client() ) ) + if ( !SkipInvalidTransactionsPatch::hasPotentialInvalidTransactionsInBlock( + bn, client()->blockChain() ) ) #endif return toJS( client()->transactionCount( jsToBlockNumber( _blockNumber ) ) ); #ifdef HISTORIC_STATE @@ -561,7 +543,8 @@ Json::Value Eth::eth_getBlockByHash( string const& _blockHash, bool _includeTran #ifdef HISTORIC_STATE BlockNumber bn = client()->numberFromHash( h ); - if ( hasPotentialInvalidTransactionsInBlock( bn, *client() ) ) { + if ( SkipInvalidTransactionsPatch::hasPotentialInvalidTransactionsInBlock( + bn, client()->blockChain() ) ) { // remove invalid transactions size_t index = 0; Transactions::iterator newEnd = std::remove_if( transactions.begin(), @@ -578,7 +561,8 @@ Json::Value Eth::eth_getBlockByHash( string const& _blockHash, bool _includeTran #ifdef HISTORIC_STATE BlockNumber bn = client()->numberFromHash( h ); - if ( hasPotentialInvalidTransactionsInBlock( bn, *client() ) ) { + if ( SkipInvalidTransactionsPatch::hasPotentialInvalidTransactionsInBlock( + bn, client()->blockChain() ) ) { // remove invalid transactions size_t index = 0; h256s::iterator newEnd = std::remove_if( transactions.begin(), transactions.end(), @@ -649,7 +633,8 @@ Json::Value Eth::eth_getTransactionByBlockHashAndIndex( #ifdef HISTORIC_STATE BlockNumber bn = client()->numberFromHash( bh ); - if ( hasPotentialInvalidTransactionsInBlock( bn, *client() ) ) + if ( SkipInvalidTransactionsPatch::hasPotentialInvalidTransactionsInBlock( + bn, client()->blockChain() ) ) try { ti = m_gapCache->realIndexFromGapped( bn, ti ); } catch ( const out_of_range& ) { @@ -673,7 +658,8 @@ Json::Value Eth::eth_getTransactionByBlockNumberAndIndex( unsigned int ti = static_cast< unsigned int >( jsToInt( _transactionIndex ) ); #ifdef HISTORIC_STATE - if ( hasPotentialInvalidTransactionsInBlock( bn, *client() ) ) + if ( SkipInvalidTransactionsPatch::hasPotentialInvalidTransactionsInBlock( + bn, client()->blockChain() ) ) try { ti = m_gapCache->realIndexFromGapped( bn, ti ); } catch ( const out_of_range& ) { @@ -728,7 +714,8 @@ LocalisedTransactionReceipt Eth::eth_getTransactionReceipt( string const& _trans auto rcp = cli->localisedTransactionReceipt( h ); #ifdef HISTORIC_STATE - if ( hasPotentialInvalidTransactionsInBlock( rcp.blockNumber(), *client() ) ) { + if ( SkipInvalidTransactionsPatch::hasPotentialInvalidTransactionsInBlock( + rcp.blockNumber(), client()->blockChain() ) ) { // skip invalid if ( rcp.gasUsed() == 0 ) { m_receiptsCache.put( cacheKey, nullptr ); diff --git a/libweb3jsonrpc/Eth.h b/libweb3jsonrpc/Eth.h index 8059860d7..38b4ce866 100644 --- a/libweb3jsonrpc/Eth.h +++ b/libweb3jsonrpc/Eth.h @@ -43,7 +43,7 @@ class KeyPair; namespace eth { class AccountHolder; struct TransactionSkeleton; -class Interface; +class Client; class LocalisedTransactionReceipt; } // namespace eth } // namespace dev @@ -57,7 +57,7 @@ namespace _detail { // cache for transaction index mapping class GappedTransactionIndexCache { public: - GappedTransactionIndexCache( size_t _cacheSize, const dev::eth::Interface& _client ) + GappedTransactionIndexCache( size_t _cacheSize, const dev::eth::Client& _client ) : client( _client ), cacheSize( _cacheSize ) { assert( _cacheSize > 0 ); } @@ -116,7 +116,7 @@ class GappedTransactionIndexCache { private: mutable std::shared_mutex mtx; - const dev::eth::Interface& client; + const dev::eth::Client& client; const size_t cacheSize; enum { UNDEFINED = ( size_t ) -1 }; @@ -135,7 +135,7 @@ std::string exceptionToErrorMessage(); */ class Eth : public dev::rpc::EthFace, public skutils::json_config_file_accessor { public: - Eth( const std::string& configPath, eth::Interface& _eth, eth::AccountHolder& _ethAccounts ); + Eth( const std::string& configPath, eth::Client& _eth, eth::AccountHolder& _ethAccounts ); virtual RPCModules implementedModules() const override { return RPCModules{ RPCModule{ "eth", "1.0" } }; @@ -220,9 +220,9 @@ class Eth : public dev::rpc::EthFace, public skutils::json_config_file_accessor void setTransactionDefaults( eth::TransactionSkeleton& _t ); protected: - eth::Interface* client() { return &m_eth; } + eth::Client* client() { return &m_eth; } - eth::Interface& m_eth; + eth::Client& m_eth; eth::AccountHolder& m_ethAccounts; // a cache that maps the call request to the pair of response string and block number diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4a7b264cc..a0a15a45e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -86,8 +86,8 @@ target_link_libraries(testeth PRIVATE ${DEPS_INSTALL_ROOT}/lib/libcrypto.a ${DEPS_INSTALL_ROOT}/lib/libz.a idn2 - ${DEPS_INSTALL_ROOT}/lib/liblzma.a ${DEPS_INSTALL_ROOT}/lib/libunwind.a + ${DEPS_INSTALL_ROOT}/lib/liblzma.a batched-io ) if (CONSENSUS) diff --git a/test/historicstate/hardhat/hardhat.config.js b/test/historicstate/hardhat/hardhat.config.js index 78f7f8c07..c423ba22d 100644 --- a/test/historicstate/hardhat/hardhat.config.js +++ b/test/historicstate/hardhat/hardhat.config.js @@ -3,14 +3,27 @@ require('@openzeppelin/hardhat-upgrades'); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { - solidity: "0.8.17", + solidity: "0.8.25", }; /* Address 0x907cd0881E50d359bb9Fd120B1A5A143b1C97De6 */ const INSECURE_PRIVATE_KEY = "bd200f4e7f597f3c2c77fb405ee7fabeb249f63f03f43d5927b4fa0c43cfe85e"; module.exports = { - solidity: "0.8.20", + solidity: { + compilers: [ + { + version: `0.8.25`, + settings: { + optimizer: { + enabled: true, + runs: 15000 + }, + evmVersion: `shanghai` + } + }, + ], + }, networks: { skaled: { url: `http://localhost:1234`, diff --git a/test/historicstate/hardhat/scripts/push0_historic_state_patch_test.ts b/test/historicstate/hardhat/scripts/push0_historic_state_patch_test.ts new file mode 100644 index 000000000..3eeede9ba --- /dev/null +++ b/test/historicstate/hardhat/scripts/push0_historic_state_patch_test.ts @@ -0,0 +1,92 @@ +const OWNER_ADDRESS: string = "0x907cd0881E50d359bb9Fd120B1A5A143b1C97De6"; +const ZERO_ADDRESS: string = "0xO000000000000000000000000000000000000000"; +const INITIAL_MINT: bigint = 10000000000000000000000000000000000000000; + +import {ethers} from "hardhat"; + +async function waitUntilNextBlock() { + + const current = await hre.ethers.provider.getBlockNumber(); + let newBlock = current; + console.log(`BLOCK_NUMBER ${current}`); + + while (newBlock == current) { + newBlock = await hre.ethers.provider.getBlockNumber(); + } + + console.log(`BLOCK_NUMBER ${newBlock}`); + + return current; + +} + +function CHECK(result: any): void { + if (!result) { + const message: string = `Check failed ${result}` + console.log(message); + throw message; + } +} + +async function getAndPrintTrace(hash: string): Promise { + + const trace = await ethers.provider.send('debug_traceTransaction', [hash, {}]); + + console.log(JSON.stringify(trace, null, 4)); + return trace; +} + +async function deployWriteAndDestroy(): Promise { + + console.log(`Deploying ...`); + + const Push0Test = await ethers.getContractFactory("Push0"); + const test = await Push0Test.deploy(); + const testContract = await test.deployed(); + + + const deployBn = await ethers.provider.getBlockNumber(); + + const hash = testContract.deployTransaction.hash; + console.log(`Gas limit ${testContract.deployTransaction.gasLimit}`); + console.log(`Contract deployed to ${testContract.address} at block ${deployBn} tx hash ${hash}`); + + console.log(`Now testing`); + + + for (let i = 0; i < 1000; i++) { + + console.log("Current Linux Time in Seconds: ", Math.floor(new Date().getTime() / 1000)); + + const historicBlockNumber = '0x' + parseInt(deployBn).toString(16); + + // Encode the call to the `getZero` method + const data2 = testContract.interface.encodeFunctionData("getZero", []); + + await waitUntilNextBlock(); + + // Create the call transaction object + const callTransaction = { + to: testContract.address, // The address of the contract + data: data2, // The encoded function call + }; + + // Use provider.call to execute the call at the specific historic block number + await ethers.provider.call(callTransaction); + await ethers.provider.call(callTransaction, historicBlockNumber); + + } +} + + + +async function main(): Promise { + await deployWriteAndDestroy(); +} + +// We recommend this pattern to be able to use async/await everywhere +// and properly handle errors. +main().catch((error: any) => { + console.error(error); + process.exitCode = 1; +}); \ No newline at end of file diff --git a/test/historicstate/patches/LegacyVM.cpp.test_timestamp_in_historic_state.patch b/test/historicstate/patches/LegacyVM.cpp.test_timestamp_in_historic_state.patch new file mode 100644 index 000000000..3fd85960d --- /dev/null +++ b/test/historicstate/patches/LegacyVM.cpp.test_timestamp_in_historic_state.patch @@ -0,0 +1,28 @@ +Subject: [PATCH] 1583 Fix crash because of unknown name +--- +Index: libevm/LegacyVM.cpp +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/libevm/LegacyVM.cpp b/libevm/LegacyVM.cpp +--- a/libevm/LegacyVM.cpp (revision a1daeb278f2d38c308366ebfdd39963b939cef90) ++++ b/libevm/LegacyVM.cpp (date 1712249617890) +@@ -1360,9 +1360,14 @@ + // we need to increment program counter only by one since + // the value is not read from program code as in PUSH1 + CASE( PUSH0 ) { +- if ( !m_schedule->havePush0 ) { +- throwBadInstruction(); +- } ++ ++ cerr << ":::::" << m_schedule->havePush0 << endl; ++ cerr << ":::::" << m_schedule->havePush0 << endl; ++ cerr << "Have push0:::::" << m_schedule->havePush0 << endl; ++ cerr << "Have push0:::::" << m_schedule->havePush0 << endl; ++ cerr << ":::::" << m_schedule->havePush0 << endl; ++ cerr << ":::::" << m_schedule->havePush0 << endl; ++ + ON_OP(); + updateIOGas(); + m_SPP[0] = 0; diff --git a/test/jsontests b/test/jsontests index b1cbbff98..98ba9f3fb 160000 --- a/test/jsontests +++ b/test/jsontests @@ -1 +1 @@ -Subproject commit b1cbbff9888a6854f04f58917ab3400395933f5a +Subproject commit 98ba9f3fb0ffdc8bec89b4f623f684eca86e733f diff --git a/test/tools/jsontests/BlockChainTests.cpp b/test/tools/jsontests/BlockChainTests.cpp index ac9dc294f..9ce5789f8 100644 --- a/test/tools/jsontests/BlockChainTests.cpp +++ b/test/tools/jsontests/BlockChainTests.cpp @@ -507,10 +507,10 @@ void testBCTest( json_spirit::mObject const& _o ) { if ( blockFromFields.blockHeader().parentHash() == preHash ) { State const postState = testChain.topBlock().state(); assert( testChain.getInterface().sealEngine() ); - bigint reward = calculateMiningReward( testChain.topBlock().blockHeader().number(), + bigint reward = calculateMiningReward( testChain.topBlock().blockHeader().timestamp(), testChain.topBlock().blockHeader().number(), uncleNumbers.size() >= 1 ? uncleNumbers[0] : 0, uncleNumbers.size() >= 2 ? uncleNumbers[1] : 0, - *testChain.getInterface().sealEngine() ); + testChain.getInterface().sealEngine()->chainParams() ); ImportTest::checkBalance( preState, postState, reward ); } else { cnote << "Block Number " << testChain.topBlock().blockHeader().number(); @@ -544,9 +544,9 @@ void testBCTest( json_spirit::mObject const& _o ) { ImportTest::compareStates( postState, blockchain.topBlock().state() ); } -bigint calculateMiningReward( u256 const& _blNumber, u256 const& _unNumber1, u256 const& _unNumber2, - SealEngineFace const& _sealEngine ) { - bigint const baseReward = _sealEngine.blockReward( _blNumber ); +bigint calculateMiningReward( time_t _committedBlockTimestamp, u256 const& _blNumber, u256 const& _unNumber1, u256 const& _unNumber2, + ChainOperationParams const& _cp ) { + bigint const baseReward = _cp.blockReward( _committedBlockTimestamp, _blNumber ); bigint reward = baseReward; // INCLUDE_UNCLE = BASE_REWARD / 32 // UNCLE_REWARD = BASE_REWARD * (8 - Bn + Un) / 8 diff --git a/test/tools/jsontests/BlockChainTests.h b/test/tools/jsontests/BlockChainTests.h index bfa1f7962..0312859b9 100644 --- a/test/tools/jsontests/BlockChainTests.h +++ b/test/tools/jsontests/BlockChainTests.h @@ -77,8 +77,8 @@ void checkJsonSectionForInvalidBlock( mObject& _blObj ); void checkExpectedException( mObject& _blObj, Exception const& _e ); void checkBlocks( TestBlock const& _blockFromFields, TestBlock const& _blockFromRlp, string const& _testname ); -bigint calculateMiningReward( u256 const& _blNumber, u256 const& _unNumber1, u256 const& _unNumber2, - SealEngineFace const& _sealEngine ); +bigint calculateMiningReward( time_t _committedBlockTimestamp, u256 const& _blNumber, u256 const& _unNumber1, u256 const& _unNumber2, + ChainOperationParams const& _cp ); json_spirit::mObject fillBCTest( json_spirit::mObject const& _input ); void testBCTest( json_spirit::mObject const& _o ); diff --git a/test/tools/jsontests/TransactionTests.cpp b/test/tools/jsontests/TransactionTests.cpp index cd870ca99..96b19dd67 100644 --- a/test/tools/jsontests/TransactionTests.cpp +++ b/test/tools/jsontests/TransactionTests.cpp @@ -102,7 +102,8 @@ json_spirit::mObject FillTransactionTest( json_spirit::mObject const& _o ) { Exception() << errinfo_comment( TestOutputHelper::get().testName() + "transaction from RLP signature is invalid" ) ); - se->verifyTransaction( ImportRequirements::Everything, txFromFields, bh, 0 ); + // TODO Remove SealEngine from tests too! + se->verifyTransaction( se->chainParams(), ImportRequirements::Everything, txFromFields, 0, bh, 0 ); if ( expectSection.count( "sender" ) > 0 ) { string expectSender = toString( expectSection["sender"].get_str() ); BOOST_CHECK_MESSAGE( toString( txFromFields.sender() ) == expectSender, @@ -160,7 +161,8 @@ void TestTransactionTest( json_spirit::mObject const& _o ) { RLP rlp( stream ); txFromRlp = Transaction( rlp.data(), CheckTransaction::Everything ); bool onExperimentalAndZeroSig = onExperimental && txFromRlp.hasZeroSignature(); - se->verifyTransaction( ImportRequirements::Everything, txFromRlp, bh, 0 ); + // TODO Remove SealEngine from tests too! + se->verifyTransaction( se->chainParams(), ImportRequirements::Everything, txFromRlp, 0, bh, 0 ); if ( !( txFromRlp.signature().isValid() || onExperimentalAndZeroSig ) ) BOOST_THROW_EXCEPTION( Exception() << errinfo_comment( testname + diff --git a/test/tools/jsontests/vm.cpp b/test/tools/jsontests/vm.cpp index 4151cc773..939dd07da 100644 --- a/test/tools/jsontests/vm.cpp +++ b/test/tools/jsontests/vm.cpp @@ -92,7 +92,7 @@ mObject FakeExtVM::exportEnv() { return ret; } -EnvInfo FakeExtVM::importEnv( mObject const& _o, LastBlockHashesFace const& _lastBlockHashes ) { +EnvInfo FakeExtVM::importEnv( mObject const& _o, LastBlockHashesFace const& _lastBlockHashes, time_t _committedBlockTimestamp ) { // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) assert( _o.count( "currentGasLimit" ) > 0 ); assert( _o.count( "currentDifficulty" ) > 0 ); @@ -109,7 +109,7 @@ EnvInfo FakeExtVM::importEnv( mObject const& _o, LastBlockHashesFace const& _las blockHeader.setTimestamp( toPositiveInt64( _o.at( "currentTimestamp" ) ) ); blockHeader.setAuthor( Address( _o.at( "currentCoinbase" ).get_str() ) ); blockHeader.setNumber( toPositiveInt64( _o.at( "currentNumber" ) ) ); - return EnvInfo( blockHeader, _lastBlockHashes, 0, 0 ); + return EnvInfo( blockHeader, _lastBlockHashes, _committedBlockTimestamp, 0, 0 ); } mObject FakeExtVM::exportState() { @@ -313,7 +313,7 @@ json_spirit::mValue VmTestSuite::doTests( json_spirit::mValue const& _input, boo BOOST_REQUIRE_MESSAGE( testInput.count( "expect" ) == 0, testname + " expect set!" ); TestLastBlockHashes lastBlockHashes( h256s( 256, h256() ) ); - eth::EnvInfo env = FakeExtVM::importEnv( testInput.at( "env" ).get_obj(), lastBlockHashes ); + eth::EnvInfo env = FakeExtVM::importEnv( testInput.at( "env" ).get_obj(), lastBlockHashes, 0 ); FakeExtVM fev( env ); fev.importState( testInput.at( "pre" ).get_obj() ); @@ -446,7 +446,8 @@ json_spirit::mValue VmTestSuite::doTests( json_spirit::mValue const& _input, boo BOOST_REQUIRE_MESSAGE( testInput.at( "logs" ).type() == str_type, testname + " logs field is not a string." ); - dev::test::FakeExtVM test( eth::EnvInfo{BlockHeader{}, lastBlockHashes, 0, 0} ); + // use all patches here ("1") + dev::test::FakeExtVM test( eth::EnvInfo{BlockHeader{}, lastBlockHashes, 1, 0, 0} ); test.importState( testInput.at( "post" ).get_obj() ); test.importCallCreates( testInput.at( "callcreates" ).get_array() ); diff --git a/test/tools/jsontests/vm.h b/test/tools/jsontests/vm.h index 80176151a..4c0c510cd 100644 --- a/test/tools/jsontests/vm.h +++ b/test/tools/jsontests/vm.h @@ -77,7 +77,7 @@ class FakeExtVM : public eth::ExtVMFace { u256 doPosts(); json_spirit::mObject exportEnv(); static dev::eth::EnvInfo importEnv( - json_spirit::mObject const& _o, eth::LastBlockHashesFace const& _lastBlockHashes ); + json_spirit::mObject const& _o, eth::LastBlockHashesFace const& _lastBlockHashes, time_t _committedBlockTimestamp ); json_spirit::mObject exportState(); void importState( json_spirit::mObject const& _object ); json_spirit::mObject exportExec(); diff --git a/test/tools/libtesteth/BlockChainHelper.cpp b/test/tools/libtesteth/BlockChainHelper.cpp index 757ac6169..6b0eaea87 100644 --- a/test/tools/libtesteth/BlockChainHelper.cpp +++ b/test/tools/libtesteth/BlockChainHelper.cpp @@ -21,7 +21,7 @@ * that manage block/transaction import and test mining */ -#include +#include #include #include @@ -476,8 +476,7 @@ void TestBlockChain::reset( TestBlock const& _genesisBlock ) { bool TestBlockChain::addBlock( TestBlock const& _block ) { - CorrectForkInPowPatch::lastBlockTimestamp = m_blockChain->info().timestamp(); - CorrectForkInPowPatch::lastBlockNumber = m_blockChain->number(); + SchainPatch::useLatestBlockTimestamp(m_blockChain->info().timestamp()); while ( true ) { try { @@ -501,8 +500,7 @@ bool TestBlockChain::addBlock( TestBlock const& _block ) { State st( block.state() ); m_lastBlock.setState( st ); - CorrectForkInPowPatch::lastBlockTimestamp = m_blockChain->info().timestamp(); - CorrectForkInPowPatch::lastBlockNumber = m_blockChain->number(); + SchainPatch::useLatestBlockTimestamp(m_blockChain->info().timestamp()); return true; } diff --git a/test/tools/libtesteth/ImportTest.cpp b/test/tools/libtesteth/ImportTest.cpp index 7ecf2283d..a805514e8 100644 --- a/test/tools/libtesteth/ImportTest.cpp +++ b/test/tools/libtesteth/ImportTest.cpp @@ -103,7 +103,7 @@ void ImportTest::makeBlockchainTestFromStateTest( set< eth::Network > const& _ne // Calculate the block reward ChainParams const chainParams{genesisInfo( net )}; - EVMSchedule const schedule = chainParams.scheduleForBlockNumber( 1 ); + EVMSchedule const schedule = chainParams.makeEvmSchedule( 0, 1 ); // u256 const blockReward = chainParams.blockReward(schedule); TrExpectSection search{trDup, smap}; @@ -262,11 +262,11 @@ std::tuple< State, ImportTest::ExecOutput, skale::ChangeLog > ImportTest::execut StandardTrace st; st.setShowMnemonics(); st.setOptions( Options::get().jsontraceOptions ); - out = initialState.execute( _env, *se.get(), _tr, Permanence::Committed, st.onOp() ); + out = initialState.execute( _env, se->chainParams(), _tr, Permanence::Committed, st.onOp() ); cout << st.json(); cout << "{\"stateRoot\": \"Is not supported\"}"; } else - out = initialState.execute( _env, *se.get(), _tr, Permanence::Uncommitted ); + out = initialState.execute( _env, se->chainParams(), _tr, Permanence::Uncommitted ); // the changeLog might be broken under --jsontrace, because it uses intialState.execute with // Permanence::Committed rather than Permanence::Uncommitted @@ -357,7 +357,8 @@ void ImportTest::importEnv( json_spirit::mObject const& _o ) { header.setAuthor( Address( _o.at( "currentCoinbase" ).get_str() ) ); m_lastBlockHashes.reset( new TestLastBlockHashes( lastHashes( header.number() ) ) ); - m_envInfo.reset( new EnvInfo( header, *m_lastBlockHashes, 0, mainnetChainID() ) ); + // enable all patches ("1") + m_envInfo.reset( new EnvInfo( header, *m_lastBlockHashes, 1, 0, mainnetChainID() ) ); } // import state from not fully declared json_spirit::mObject, writing to _stateOptionsMap which diff --git a/test/tools/libtesteth/TestHelper.cpp b/test/tools/libtesteth/TestHelper.cpp index 7384cff09..9e8918e51 100644 --- a/test/tools/libtesteth/TestHelper.cpp +++ b/test/tools/libtesteth/TestHelper.cpp @@ -117,7 +117,7 @@ void simulateMining( Client& client, size_t numBlocks, const dev::Address &addre State state = client.state().createStateModifyCopy(); u256 reward = 0; for ( size_t blockNumber = 0; blockNumber < numBlocks; ++blockNumber ) { - reward += client.sealEngine()->blockReward( blockNumber ); + reward += client.sealEngine()->blockReward( 1, blockNumber ); } state.addBalance( address, reward ); state.commit(); diff --git a/test/tools/libtesteth/TestOutputHelper.cpp b/test/tools/libtesteth/TestOutputHelper.cpp index f5ec7cdf2..745896c64 100644 --- a/test/tools/libtesteth/TestOutputHelper.cpp +++ b/test/tools/libtesteth/TestOutputHelper.cpp @@ -20,7 +20,7 @@ * Fixture class for boost output when running testeth */ -#include +#include #include #include #include @@ -103,8 +103,6 @@ void TestOutputHelper::printTestExecStats() { } TestOutputHelperFixture::TestOutputHelperFixture() { TestOutputHelper::get().initTest(); - CorrectForkInPowPatch::lastBlockTimestamp = 1; - CorrectForkInPowPatch::lastBlockNumber = 0; } TestOutputHelperFixture::~TestOutputHelperFixture() { diff --git a/test/tools/libtesteth/boostTest.cpp b/test/tools/libtesteth/boostTest.cpp index 6fd218178..45fb63b2b 100644 --- a/test/tools/libtesteth/boostTest.cpp +++ b/test/tools/libtesteth/boostTest.cpp @@ -137,7 +137,6 @@ void setCLocale() { int main( int argc, const char* argv[] ) { MicroProfileSetEnableAllGroups( true ); UnsafeRegion::init("."); - std::srand( time( nullptr ) ); std::string const dynamicTestSuiteName = "customTestSuite"; setCLocale(); diff --git a/test/unittests/libethcore/SealEngineTest.cpp b/test/unittests/libethcore/SealEngineTest.cpp index 003795371..4ee30ce56 100644 --- a/test/unittests/libethcore/SealEngineTest.cpp +++ b/test/unittests/libethcore/SealEngineTest.cpp @@ -61,15 +61,15 @@ BOOST_AUTO_TEST_CASE( UnsignedTransactionIsValidBeforeExperimental, header.setNumber( 1 ); - ethash.SealEngineFace::verifyTransaction( - ImportRequirements::TransactionSignatures, tx, header, 0 ); // check that it doesn't throw + SealEngineFace::verifyTransaction( params, ImportRequirements::TransactionSignatures, + tx, 1, header, 0 ); // check that it doesn't throw } BOOST_AUTO_TEST_CASE( UnsignedTransactionIsValidInExperimental ) { header.setNumber( 0x1010 ); - ethash.SealEngineFace::verifyTransaction( - ImportRequirements::TransactionSignatures, tx, header, 0 ); // check that it doesn't throw + SealEngineFace::verifyTransaction( params, ImportRequirements::TransactionSignatures, + tx, 1, header, 0 ); // check that it doesn't throw } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unittests/libethereum/ClientTest.cpp b/test/unittests/libethereum/ClientTest.cpp index 81781fa7c..a3f8850e0 100644 --- a/test/unittests/libethereum/ClientTest.cpp +++ b/test/unittests/libethereum/ClientTest.cpp @@ -390,7 +390,8 @@ static std::string const c_genesisInfoSkaleTest = std::string() + "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000" + "blockReward": "0x4563918244F40000", + "skaleDisableChainIdCheck": true }, "genesis": { "nonce": "0x0000000000000042", diff --git a/test/unittests/libethereum/ExtVMTest.cpp b/test/unittests/libethereum/ExtVMTest.cpp index d8e140099..548d30033 100644 --- a/test/unittests/libethereum/ExtVMTest.cpp +++ b/test/unittests/libethereum/ExtVMTest.cpp @@ -49,7 +49,7 @@ class ExtVMConstantinopleFixTestFixture : public TestOutputHelperFixture { } EnvInfo createEnvInfo( BlockHeader const& _header ) const { - return {_header, lastBlockHashes, 0, blockchain.chainID()}; + return {_header, lastBlockHashes, 1, 0, blockchain.chainID()}; } NetworkSelector networkSelector; @@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE( BlockhashOutOfBoundsRetunsZero, TestLastBlockHashes lastBlockHashes( {} ); EnvInfo envInfo( createEnvInfo( block.info() ) ); Address addr( "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" ); - ExtVM extVM( block.mutableState(), envInfo, *blockchain.sealEngine(), addr, addr, addr, 0, 0, + ExtVM extVM( block.mutableState(), envInfo, blockchain.sealEngine()->chainParams(), addr, addr, addr, 0, 0, {}, {}, {}, 0, 0, false, false ); BOOST_CHECK_EQUAL( extVM.blockHash( 100 ), h256() ); @@ -85,9 +85,9 @@ BOOST_AUTO_TEST_CASE( BlockhashBeforeConstantinopleReliesOnLastHashes, h256s lastHashes{h256( "0xaaabbbccc" ), h256( "0xdddeeefff" )}; TestLastBlockHashes lastBlockHashes( lastHashes ); - EnvInfo envInfo( block.info(), lastBlockHashes, 0, blockchain.chainID() ); + EnvInfo envInfo( block.info(), lastBlockHashes, block.info().timestamp(), 0, blockchain.chainID() ); Address addr( "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" ); - ExtVM extVM( block.mutableState(), envInfo, *blockchain.sealEngine(), addr, addr, addr, 0, 0, + ExtVM extVM( block.mutableState(), envInfo, blockchain.sealEngine()->chainParams(), addr, addr, addr, 0, 0, {}, {}, {}, 0, 0, false, false ); h256 hash = extVM.blockHash( 1 ); BOOST_REQUIRE_EQUAL( hash, lastHashes[0] ); diff --git a/test/unittests/libethereum/PrecompiledTest.cpp b/test/unittests/libethereum/PrecompiledTest.cpp index 20498f3d9..bec328e70 100644 --- a/test/unittests/libethereum/PrecompiledTest.cpp +++ b/test/unittests/libethereum/PrecompiledTest.cpp @@ -32,8 +32,7 @@ #include #include #include -#include -#include +#include #include diff --git a/test/unittests/libethereum/SkaleHost.cpp b/test/unittests/libethereum/SkaleHost.cpp index 930339da0..3d743ce5f 100644 --- a/test/unittests/libethereum/SkaleHost.cpp +++ b/test/unittests/libethereum/SkaleHost.cpp @@ -137,6 +137,8 @@ struct SkaleHostFixture : public TestOutputHelperFixture { if( params.count("multiTransactionMode") && stoi( params.at( "multiTransactionMode" ) ) ) chainParams.sChain.multiTransactionMode = true; + if( params.count("skipInvalidTransactionsPatchTimestamp") && stoi( params.at( "skipInvalidTransactionsPatchTimestamp" ) ) ) + chainParams.sChain._patchTimestamps[static_cast(SchainPatchEnum::SkipInvalidTransactionsPatch)] = stoi( params.at( "skipInvalidTransactionsPatchTimestamp" ) ); accountHolder.reset( new FixedAccountHolder( [&]() { return client.get(); }, {} ) ); accountHolder->setAccounts( {coinbase, account2} ); @@ -232,16 +234,17 @@ struct SkaleHostFixture : public TestOutputHelperFixture { { u256 balanceAfter = client->balanceAt( senderAddress ); \ BOOST_REQUIRE_GE( balanceBefore - balanceAfter, decrease ); } -BOOST_FIXTURE_TEST_SUITE( SkaleHostSuite, SkaleHostFixture ) //, *boost::unit_test::disabled() ) +BOOST_AUTO_TEST_SUITE( SkaleHostSuite ) //, *boost::unit_test::disabled() ) auto skipInvalidTransactionsVariants = boost::unit_test::data::make({false, true}); BOOST_DATA_TEST_CASE( validTransaction, skipInvalidTransactionsVariants, skipInvalidTransactionsFlag ) { - if(skipInvalidTransactionsFlag){ - const_cast(client->chainParams()).sChain.skipInvalidTransactionsPatchTimestamp = 1; - } - SkipInvalidTransactionsPatch::setTimestamp(client->chainParams().sChain.skipInvalidTransactionsPatchTimestamp); + SkaleHostFixture fixture( std::map( {{"skipInvalidTransactionsPatchTimestamp", to_string(int(skipInvalidTransactionsFlag))}} ) ); + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& accountHolder = fixture.accountHolder; + auto& stub = fixture.stub; auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -288,10 +291,10 @@ BOOST_DATA_TEST_CASE( transactionRlpBad, skipInvalidTransactionsVariants, skipIn // , *boost::unit_test::precondition( dev::test::run_not_express ) ) { - if(skipInvalidTransactionsFlag){ - const_cast(client->chainParams()).sChain.skipInvalidTransactionsPatchTimestamp = 1; - } - SkipInvalidTransactionsPatch::setTimestamp(client->chainParams().sChain.skipInvalidTransactionsPatchTimestamp); + SkaleHostFixture fixture( std::map( {{"skipInvalidTransactionsPatchTimestamp", to_string(int(skipInvalidTransactionsFlag))}} ) ); + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& stub = fixture.stub; auto senderAddress = coinbase.address(); @@ -374,10 +377,11 @@ BOOST_DATA_TEST_CASE( transactionSigZero, skipInvalidTransactionsVariants, skipI // , *boost::unit_test::precondition( dev::test::run_not_express ) ) { - if(skipInvalidTransactionsFlag){ - const_cast(client->chainParams()).sChain.skipInvalidTransactionsPatchTimestamp = 1; - } - SkipInvalidTransactionsPatch::setTimestamp(client->chainParams().sChain.skipInvalidTransactionsPatchTimestamp); + SkaleHostFixture fixture( std::map( {{"skipInvalidTransactionsPatchTimestamp", to_string(int(skipInvalidTransactionsFlag))}} ) ); + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& accountHolder = fixture.accountHolder; + auto& stub = fixture.stub; auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -429,10 +433,11 @@ BOOST_DATA_TEST_CASE( transactionSigBad, skipInvalidTransactionsVariants, skipIn // , *boost::unit_test::precondition( dev::test::run_not_express ) ) { - if(skipInvalidTransactionsFlag){ - const_cast(client->chainParams()).sChain.skipInvalidTransactionsPatchTimestamp = 1; - } - SkipInvalidTransactionsPatch::setTimestamp(client->chainParams().sChain.skipInvalidTransactionsPatchTimestamp); + SkaleHostFixture fixture( std::map( {{"skipInvalidTransactionsPatchTimestamp", to_string(int(skipInvalidTransactionsFlag))}} ) ); + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& accountHolder = fixture.accountHolder; + auto& stub = fixture.stub; auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -484,10 +489,11 @@ BOOST_DATA_TEST_CASE( transactionGasIncorrect, skipInvalidTransactionsVariants, // , *boost::unit_test::precondition( dev::test::run_not_express ) ) { - if(skipInvalidTransactionsFlag){ - const_cast(client->chainParams()).sChain.skipInvalidTransactionsPatchTimestamp = 1; - } - SkipInvalidTransactionsPatch::setTimestamp(client->chainParams().sChain.skipInvalidTransactionsPatchTimestamp); + SkaleHostFixture fixture( std::map( {{"skipInvalidTransactionsPatchTimestamp", to_string(int(skipInvalidTransactionsFlag))}} ) ); + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& accountHolder = fixture.accountHolder; + auto& stub = fixture.stub; auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -537,10 +543,11 @@ BOOST_DATA_TEST_CASE( transactionGasNotEnough, skipInvalidTransactionsVariants, // , *boost::unit_test::precondition( dev::test::run_not_express ) ) { - if(skipInvalidTransactionsFlag){ - const_cast(client->chainParams()).sChain.skipInvalidTransactionsPatchTimestamp = 1; - } - SkipInvalidTransactionsPatch::setTimestamp(client->chainParams().sChain.skipInvalidTransactionsPatchTimestamp); + SkaleHostFixture fixture( std::map( {{"skipInvalidTransactionsPatchTimestamp", to_string(int(skipInvalidTransactionsFlag))}} ) ); + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& accountHolder = fixture.accountHolder; + auto& stub = fixture.stub; auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -598,10 +605,11 @@ BOOST_DATA_TEST_CASE( transactionGasNotEnough, skipInvalidTransactionsVariants, // nonce too big BOOST_DATA_TEST_CASE( transactionNonceBig, skipInvalidTransactionsVariants, skipInvalidTransactionsFlag ) { - if(skipInvalidTransactionsFlag){ - const_cast(client->chainParams()).sChain.skipInvalidTransactionsPatchTimestamp = 1; - } - SkipInvalidTransactionsPatch::setTimestamp(client->chainParams().sChain.skipInvalidTransactionsPatchTimestamp); + SkaleHostFixture fixture( std::map( {{"skipInvalidTransactionsPatchTimestamp", to_string(int(skipInvalidTransactionsFlag))}} ) ); + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& accountHolder = fixture.accountHolder; + auto& stub = fixture.stub; auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -650,10 +658,11 @@ BOOST_DATA_TEST_CASE( transactionNonceSmall, skipInvalidTransactionsVariants, sk //, *boost::unit_test::precondition( dev::test::run_not_express ) ) { - if(skipInvalidTransactionsFlag){ - const_cast(client->chainParams()).sChain.skipInvalidTransactionsPatchTimestamp = 1; - } - SkipInvalidTransactionsPatch::setTimestamp(client->chainParams().sChain.skipInvalidTransactionsPatchTimestamp); + SkaleHostFixture fixture( std::map( {{"skipInvalidTransactionsPatchTimestamp", to_string(int(skipInvalidTransactionsFlag))}} ) ); + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& accountHolder = fixture.accountHolder; + auto& stub = fixture.stub; auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -714,10 +723,11 @@ BOOST_DATA_TEST_CASE( transactionNonceSmall, skipInvalidTransactionsVariants, sk // not enough cash BOOST_DATA_TEST_CASE( transactionBalanceBad, skipInvalidTransactionsVariants, skipInvalidTransactionsFlag ) { - if(skipInvalidTransactionsFlag){ - const_cast(client->chainParams()).sChain.skipInvalidTransactionsPatchTimestamp = 1; - } - SkipInvalidTransactionsPatch::setTimestamp(client->chainParams().sChain.skipInvalidTransactionsPatchTimestamp); + SkaleHostFixture fixture( std::map( {{"skipInvalidTransactionsPatchTimestamp", to_string(int(skipInvalidTransactionsFlag))}} ) ); + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& accountHolder = fixture.accountHolder; + auto& stub = fixture.stub; auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -792,10 +802,10 @@ BOOST_DATA_TEST_CASE( transactionGasBlockLimitExceeded, skipInvalidTransactionsV // , *boost::unit_test::precondition( dev::test::run_not_express ) ) { - if(skipInvalidTransactionsFlag){ - const_cast(client->chainParams()).sChain.skipInvalidTransactionsPatchTimestamp = 1; - } - SkipInvalidTransactionsPatch::setTimestamp(client->chainParams().sChain.skipInvalidTransactionsPatchTimestamp); + SkaleHostFixture fixture( std::map( {{"skipInvalidTransactionsPatchTimestamp", to_string(int(skipInvalidTransactionsFlag))}} ) ); + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& stub = fixture.stub; auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -808,7 +818,7 @@ BOOST_DATA_TEST_CASE( transactionGasBlockLimitExceeded, skipInvalidTransactionsV json["nonce"] = 0; json["gasPrice"] = 0; - Transaction tx1 = tx_from_json( json ); + Transaction tx1 = fixture.tx_from_json( json ); RLPStream stream1; tx1.streamRLP( stream1 ); @@ -820,7 +830,7 @@ BOOST_DATA_TEST_CASE( transactionGasBlockLimitExceeded, skipInvalidTransactionsV json["nonce"] = 1; json["gas"] = jsToDecimal( toJS( client->chainParams().gasLimit - 21000 + 1 ) ); - Transaction tx2 = tx_from_json( json ); + Transaction tx2 = fixture.tx_from_json( json ); RLPStream stream2; tx2.streamRLP( stream2 ); @@ -855,11 +865,19 @@ BOOST_DATA_TEST_CASE( transactionGasBlockLimitExceeded, skipInvalidTransactionsV // Last transaction should be dropped from block proposal BOOST_AUTO_TEST_CASE( gasLimitInBlockProposal ) { + + SkaleHostFixture fixture; + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& skaleHost = fixture.skaleHost; + auto& stub = fixture.stub; + auto& account2 = fixture.account2; + auto receiver = KeyPair::create(); { auto wr_state = client->state().createStateModifyCopy(); - wr_state.addBalance( account2.address(), client->chainParams().gasLimit * 1000 + dev::eth::ether ); + wr_state.addBalance( fixture.account2.address(), client->chainParams().gasLimit * 1000 + dev::eth::ether ); wr_state.commit(); } @@ -871,7 +889,7 @@ BOOST_AUTO_TEST_CASE( gasLimitInBlockProposal ) { json["nonce"] = 0; json["gasPrice"] = 1000; - Transaction tx1 = tx_from_json( json ); + Transaction tx1 = fixture.tx_from_json( json ); RLPStream stream1; tx1.streamRLP( stream1 ); @@ -880,7 +898,7 @@ BOOST_AUTO_TEST_CASE( gasLimitInBlockProposal ) { json["from"] = toJS( account2.address() ); json["gas"] = jsToDecimal( toJS( client->chainParams().gasLimit - 21000 + 1 ) ); - Transaction tx2 = tx_from_json( json ); + Transaction tx2 = fixture.tx_from_json( json ); RLPStream stream2; tx2.streamRLP( stream2 ); @@ -901,6 +919,14 @@ BOOST_AUTO_TEST_CASE( gasLimitInBlockProposal ) { BOOST_AUTO_TEST_CASE( transactionDropReceive //, *boost::unit_test::precondition( dev::test::run_not_express ) ) { + + SkaleHostFixture fixture; + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& skaleHost = fixture.skaleHost; + auto& stub = fixture.stub; + auto& tq = fixture.tq; + auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -912,8 +938,8 @@ BOOST_AUTO_TEST_CASE( transactionDropReceive json["nonce"] = 1; // 1st tx - Transaction tx1 = tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams(), client->number() ); + Transaction tx1 = fixture.tx_from_json( json ); + tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number(), false ); // submit it! tq->import( tx1 ); @@ -922,7 +948,7 @@ BOOST_AUTO_TEST_CASE( transactionDropReceive u256 value2 = 20000 * dev::eth::szabo; json["value"] = jsToDecimal( toJS( value2 ) ); json["nonce"] = 0; - bytes tx2 = bytes_from_json( json ); + bytes tx2 = fixture.bytes_from_json( json ); // receive it! skaleHost->receiveTransaction( toJS( tx2 ) ); @@ -935,7 +961,7 @@ BOOST_AUTO_TEST_CASE( transactionDropReceive json["value"] = jsToDecimal( toJS( value3 ) ); json["nonce"] = 0; - bytes tx3 = bytes_from_json( json ); + bytes tx3 = fixture.bytes_from_json( json ); // return it from consensus! CHECK_BLOCK_BEGIN; @@ -957,6 +983,13 @@ BOOST_AUTO_TEST_CASE( transactionDropReceive BOOST_AUTO_TEST_CASE( transactionDropQueue, *boost::unit_test::precondition( dev::test::run_not_express ) ) { + + SkaleHostFixture fixture; + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& stub = fixture.stub; + auto& tq = fixture.tq; + auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -969,8 +1002,8 @@ BOOST_AUTO_TEST_CASE( transactionDropQueue, json["nonce"] = 1; // 1st tx - Transaction tx1 = tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams(), client->number() ); + Transaction tx1 = fixture.tx_from_json( json ); + tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number(), false ); // submit it! tq->import( tx1 ); @@ -983,7 +1016,7 @@ BOOST_AUTO_TEST_CASE( transactionDropQueue, json["value"] = jsToDecimal( toJS( value2 ) ); json["nonce"] = 0; - Transaction tx2 = tx_from_json( json ); + Transaction tx2 = fixture.tx_from_json( json ); RLPStream stream2; tx2.streamRLP( stream2 ); @@ -1014,6 +1047,13 @@ BOOST_AUTO_TEST_CASE( transactionDropQueue, BOOST_AUTO_TEST_CASE( transactionDropByGasPrice // , *boost::unit_test::precondition( dev::test::run_not_express ) ) { + + SkaleHostFixture fixture; + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& stub = fixture.stub; + auto& tq = fixture.tq; + auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -1026,8 +1066,8 @@ BOOST_AUTO_TEST_CASE( transactionDropByGasPrice json["nonce"] = 1; // 1st tx - Transaction tx1 = tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams(), client->number() ); + Transaction tx1 = fixture.tx_from_json( json ); + tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number(), false ); // submit it! tq->import( tx1 ); @@ -1040,7 +1080,7 @@ BOOST_AUTO_TEST_CASE( transactionDropByGasPrice json["value"] = jsToDecimal( toJS( value2 ) ); json["nonce"] = 0; - Transaction tx2 = tx_from_json( json ); + Transaction tx2 = fixture.tx_from_json( json ); RLPStream stream2; tx2.streamRLP( stream2 ); @@ -1071,12 +1111,21 @@ BOOST_AUTO_TEST_CASE( transactionDropByGasPrice BOOST_AUTO_TEST_CASE( transactionDropByGasPriceReceive // , *boost::unit_test::precondition( dev::test::run_not_express ) ) { + + SkaleHostFixture fixture; + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& skaleHost = fixture.skaleHost; + auto& stub = fixture.stub; + auto& tq = fixture.tq; + auto& account2 = fixture.account2; + auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); { auto wr_state = client->state().createStateModifyCopy(); - wr_state.addBalance( account2.address(), 1 * ether ); + wr_state.addBalance( fixture.account2.address(), 1 * ether ); wr_state.commit(); } @@ -1089,8 +1138,8 @@ BOOST_AUTO_TEST_CASE( transactionDropByGasPriceReceive json["gasPrice"] = "1000"; // 1st tx - Transaction tx1 = tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams(), client->number() ); + Transaction tx1 = fixture.tx_from_json( json ); + tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number(), false ); RLPStream stream1; tx1.streamRLP( stream1 ); @@ -1107,7 +1156,7 @@ BOOST_AUTO_TEST_CASE( transactionDropByGasPriceReceive json["value"] = jsToDecimal( toJS( value2 ) ); json["nonce"] = 0; - Transaction tx2 = tx_from_json( json ); + Transaction tx2 = fixture.tx_from_json( json ); RLPStream stream2; tx2.streamRLP( stream2 ); @@ -1137,6 +1186,12 @@ BOOST_AUTO_TEST_CASE( transactionDropByGasPriceReceive BOOST_AUTO_TEST_CASE( transactionRace // , *boost::unit_test::precondition( dev::test::run_not_express ) ) { + + SkaleHostFixture fixture; + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& stub = fixture.stub; + auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -1149,7 +1204,7 @@ BOOST_AUTO_TEST_CASE( transactionRace json["gasPrice"] = jsToDecimal( toJS( gasPrice ) ); json["nonce"] = 0; - Transaction tx = tx_from_json( json ); + Transaction tx = fixture.tx_from_json( json ); RLPStream stream; tx.streamRLP( stream ); @@ -1181,7 +1236,7 @@ BOOST_AUTO_TEST_CASE( transactionRace // 3 send new tx and see nonce json["nonce"] = 1; - Transaction tx2 = tx_from_json( json ); + Transaction tx2 = fixture.tx_from_json( json ); client->importTransaction( tx2 ); } @@ -1190,6 +1245,13 @@ BOOST_AUTO_TEST_CASE( transactionRace BOOST_AUTO_TEST_CASE( partialCatchUp // , *boost::unit_test::precondition( dev::test::run_not_express ) ) { + + SkaleHostFixture fixture; + auto& client = fixture.client; + auto& coinbase = fixture.coinbase; + auto& accountHolder = fixture.accountHolder; + auto& stub = fixture.stub; + auto senderAddress = coinbase.address(); auto receiver = KeyPair::create(); @@ -1239,6 +1301,10 @@ BOOST_AUTO_TEST_CASE( partialCatchUp } BOOST_AUTO_TEST_CASE( getBlockRandom ) { + + SkaleHostFixture fixture; + auto& skaleHost = fixture.skaleHost; + PrecompiledExecutor exec = PrecompiledRegistrar::executor( "getBlockRandom" ); auto res = exec( bytesConstRef() ); u256 blockRandom = skaleHost->getBlockRandom(); @@ -1247,6 +1313,10 @@ BOOST_AUTO_TEST_CASE( getBlockRandom ) { } BOOST_AUTO_TEST_CASE( getIMABLSPUblicKey ) { + + SkaleHostFixture fixture; + auto& skaleHost = fixture.skaleHost; + PrecompiledExecutor exec = PrecompiledRegistrar::executor( "getIMABLSPublicKey" ); auto res = exec( bytesConstRef() ); std::array< std::string, 4 > imaBLSPublicKey = skaleHost->getIMABLSPublicKey(); diff --git a/test/unittests/libethereum/Transaction.cpp b/test/unittests/libethereum/Transaction.cpp index 14e53d159..46403923d 100644 --- a/test/unittests/libethereum/Transaction.cpp +++ b/test/unittests/libethereum/Transaction.cpp @@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE( TransactionGasRequired, "79f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0ef" "ffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" ), CheckTransaction::None ); - BOOST_CHECK_EQUAL( tr.baseGasRequired( FrontierSchedule ), 14 * 68 + 21000 ); + BOOST_CHECK_EQUAL( tr.baseGasRequired( HomesteadSchedule ), 14 * 68 + 21000 ); BOOST_CHECK_EQUAL( tr.baseGasRequired( IstanbulSchedule ), 14 * 16 + 21000 ); } diff --git a/test/unittests/libevm/VMTest.cpp b/test/unittests/libevm/VMTest.cpp index fedb0e35c..9edcf9aeb 100644 --- a/test/unittests/libevm/VMTest.cpp +++ b/test/unittests/libevm/VMTest.cpp @@ -17,6 +17,7 @@ along with cpp-ethereum. If not, see . */ +#include #include #include #include @@ -55,7 +56,7 @@ class Create2TestFixture : public TestOutputHelperFixture { virtual ~Create2TestFixture() { state.releaseWriteLock(); } void testCreate2worksInConstantinople() { - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, ref( inputData ), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); vm->exec( gas, extVm, OnOpFunc{} ); @@ -66,7 +67,7 @@ class Create2TestFixture : public TestOutputHelperFixture { void testCreate2isInvalidBeforeConstantinople() { se.reset( ChainParams( genesisInfo( Network::ByzantiumTest ) ).createSealEngine() ); - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, ref( inputData ), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); BOOST_REQUIRE_THROW( vm->exec( gas, extVm, OnOpFunc{} ), BadInstruction ); @@ -75,7 +76,7 @@ class Create2TestFixture : public TestOutputHelperFixture { void testCreate2succeedsIfAddressHasEther() { state.addBalance( expectedAddress, 1 * ether ); - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, ref( inputData ), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); vm->exec( gas, extVm, OnOpFunc{} ); @@ -86,7 +87,7 @@ class Create2TestFixture : public TestOutputHelperFixture { void testCreate2doesntChangeContractIfAddressExists() { state.setCode( expectedAddress, bytes{inputData}, 0 ); - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, ref( inputData ), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); vm->exec( gas, extVm, OnOpFunc{} ); @@ -96,7 +97,7 @@ class Create2TestFixture : public TestOutputHelperFixture { void testCreate2isForbiddenInStaticCall() { staticCall = true; - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, ref( inputData ), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); BOOST_REQUIRE_THROW( vm->exec( gas, extVm, OnOpFunc{} ), DisallowedStateChange ); @@ -109,7 +110,7 @@ class Create2TestFixture : public TestOutputHelperFixture { state.createContract( expectedAddress ); state.setStorage( expectedAddress, 1, 1 ); - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, ref( inputData ), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); vm->exec( gas, extVm, OnOpFunc{} ); @@ -127,7 +128,7 @@ class Create2TestFixture : public TestOutputHelperFixture { state.createContract( expectedAddress ); state.setStorage( expectedAddress, 1, 1 ); - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, ref( inputData ), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); vm->exec( gas, extVm, OnOpFunc{} ); @@ -136,7 +137,7 @@ class Create2TestFixture : public TestOutputHelperFixture { } void testCreate2costIncludesInitCodeHashing() { - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, ref( inputData ), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); uint64_t gasBefore = 0; @@ -174,7 +175,7 @@ class Create2TestFixture : public TestOutputHelperFixture { State state = State( 0 ).createStateModifyCopy(); std::unique_ptr< SealEngineFace > se{ ChainParams( genesisInfo( Network::ConstantinopleTest ) ).createSealEngine()}; - EnvInfo envInfo{blockHeader, lastBlockHashes, 0, se->chainParams().chainID}; + EnvInfo envInfo{blockHeader, lastBlockHashes, 1, 0, se->chainParams().chainID}; u256 value = 0; u256 gasPrice = 1; @@ -219,7 +220,7 @@ class ExtcodehashTestFixture : public TestOutputHelperFixture { } void testExtcodehashWorksInConstantinople() { - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, extAddress.ref(), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); owning_bytes_ref ret = vm->exec( gas, extVm, OnOpFunc{} ); @@ -228,7 +229,7 @@ class ExtcodehashTestFixture : public TestOutputHelperFixture { } void testExtcodehashHasCorrectCost() { - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, extAddress.ref(), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); bigint gasBefore; @@ -250,7 +251,7 @@ class ExtcodehashTestFixture : public TestOutputHelperFixture { void testExtCodeHashisInvalidBeforeConstantinople() { se.reset( ChainParams( genesisInfo( Network::ByzantiumTest ) ).createSealEngine() ); - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, extAddress.ref(), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); BOOST_REQUIRE_THROW( vm->exec( gas, extVm, OnOpFunc{} ), BadInstruction ); @@ -260,7 +261,7 @@ class ExtcodehashTestFixture : public TestOutputHelperFixture { Address addressWithEmptyCode{KeyPair::create().address()}; state.addBalance( addressWithEmptyCode, 1 * ether ); - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, addressWithEmptyCode.ref(), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); @@ -273,7 +274,7 @@ class ExtcodehashTestFixture : public TestOutputHelperFixture { void testExtCodeHashOfNonExistentAccount() { Address addressNonExisting{0x1234}; - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, addressNonExisting.ref(), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); @@ -285,7 +286,7 @@ class ExtcodehashTestFixture : public TestOutputHelperFixture { void testExtCodeHashOfPrecomileZeroBalance() { Address addressPrecompile{0x1}; - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, addressPrecompile.ref(), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); @@ -298,7 +299,7 @@ class ExtcodehashTestFixture : public TestOutputHelperFixture { Address addressPrecompile{0x1}; state.addBalance( addressPrecompile, 1 * ether ); - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, addressPrecompile.ref(), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); @@ -319,7 +320,7 @@ class ExtcodehashTestFixture : public TestOutputHelperFixture { bytes extAddressPrefixed = bytes{1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc} + extAddress.ref(); - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, ref( extAddressPrefixed ), ref( code ), sha3( code ), version, depth, isCreate, staticCall ); @@ -335,7 +336,7 @@ class ExtcodehashTestFixture : public TestOutputHelperFixture { State state{0}; std::unique_ptr< SealEngineFace > se{ ChainParams( genesisInfo( Network::ConstantinopleTest ) ).createSealEngine()}; - EnvInfo envInfo{blockHeader, lastBlockHashes, 0, se->chainParams().chainID}; + EnvInfo envInfo{blockHeader, lastBlockHashes, 1, 0, se->chainParams().chainID}; u256 value = 0; u256 gasPrice = 1; @@ -425,7 +426,7 @@ class SstoreTestFixture : public TestOutputHelperFixture { state.commit( dev::eth::CommitBehaviour::RemoveEmptyAccounts ); bytes const code = fromHex( _codeStr ); - ExtVM extVm( state, envInfo, *se, to, from, from, value, gasPrice, inputData, ref( code ), + ExtVM extVm( state, envInfo, se->chainParams(), to, from, from, value, gasPrice, inputData, ref( code ), sha3( code ), version, depth, isCreate, staticCall ); u256 gasBefore = gas; @@ -443,7 +444,7 @@ class SstoreTestFixture : public TestOutputHelperFixture { State state = State( 0 ).createStateModifyCopy(); std::unique_ptr< SealEngineFace > se{ ChainParams( genesisInfo( Network::ConstantinopleTest ) ).createSealEngine()}; - EnvInfo envInfo{blockHeader, lastBlockHashes, 0, se->chainParams().chainID}; + EnvInfo envInfo{blockHeader, lastBlockHashes, 1, 0, se->chainParams().chainID}; u256 value = 0; u256 gasPrice = 1; @@ -472,7 +473,7 @@ class ChainIDTestFixture : public TestOutputHelperFixture { explicit ChainIDTestFixture( VMFace* _vm ) : vm{_vm} { state.addBalance( address, 1 * ether ); } void testChainIDWorksInIstanbul() { - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, {}, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, {}, ref( code ), sha3( code ), version, depth, isCreate, staticCall ); owning_bytes_ref ret = vm->exec( gas, extVm, OnOpFunc{} ); @@ -481,7 +482,7 @@ class ChainIDTestFixture : public TestOutputHelperFixture { } void testChainIDHasCorrectCost() { - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, {}, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, {}, ref( code ), sha3( code ), version, depth, isCreate, staticCall ); bigint gasBefore; @@ -504,7 +505,7 @@ class ChainIDTestFixture : public TestOutputHelperFixture { se.reset( ChainParams( genesisInfo( Network::ConstantinopleFixTest ) ).createSealEngine() ); version = ConstantinopleFixSchedule.accountVersion; - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, {}, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, {}, ref( code ), sha3( code ), version, depth, isCreate, staticCall ); BOOST_REQUIRE_THROW( vm->exec( gas, extVm, OnOpFunc{} ), BadInstruction ); @@ -517,7 +518,7 @@ class ChainIDTestFixture : public TestOutputHelperFixture { State state{0}; std::unique_ptr< SealEngineFace > se{ ChainParams( genesisInfo( Network::IstanbulTest ) ).createSealEngine()}; - EnvInfo envInfo{blockHeader, lastBlockHashes, 0, se->chainParams().chainID}; + EnvInfo envInfo{blockHeader, lastBlockHashes, 1, 0, se->chainParams().chainID}; u256 value = 0; u256 gasPrice = 1; @@ -551,14 +552,14 @@ class BalanceFixture : public TestOutputHelperFixture { explicit BalanceFixture( VMFace* _vm ) : vm{_vm} { state.addBalance( address, 1 * ether ); } void testSelfBalanceWorksInIstanbul() { - ExtVM extVmSelfBalance( state, envInfo, *se, address, address, address, value, gasPrice, {}, + ExtVM extVmSelfBalance( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, {}, ref( codeSelfBalance ), sha3( codeSelfBalance ), version, depth, isCreate, staticCall ); owning_bytes_ref retSelfBalance = vm->exec( gas, extVmSelfBalance, OnOpFunc{} ); BOOST_REQUIRE_EQUAL( fromBigEndian< u256 >( retSelfBalance ), 1 * ether ); - ExtVM extVmBalance( state, envInfo, *se, address, address, address, value, gasPrice, {}, + ExtVM extVmBalance( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, {}, ref( codeBalance ), sha3( codeBalance ), version, depth, isCreate, staticCall ); owning_bytes_ref retBalance = vm->exec( gas, extVmBalance, OnOpFunc{} ); @@ -568,7 +569,7 @@ class BalanceFixture : public TestOutputHelperFixture { } void testSelfBalanceHasCorrectCost() { - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, {}, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, {}, ref( codeSelfBalance ), sha3( codeSelfBalance ), version, depth, isCreate, staticCall ); bigint gasBefore; @@ -588,7 +589,7 @@ class BalanceFixture : public TestOutputHelperFixture { } void testBalanceHasCorrectCost() { - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, {}, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, {}, ref( codeBalance ), sha3( codeBalance ), version, depth, isCreate, staticCall ); bigint gasBefore; @@ -611,7 +612,7 @@ class BalanceFixture : public TestOutputHelperFixture { se.reset( ChainParams( genesisInfo( Network::ConstantinopleFixTest ) ).createSealEngine() ); version = ConstantinopleFixSchedule.accountVersion; - ExtVM extVm( state, envInfo, *se, address, address, address, value, gasPrice, {}, + ExtVM extVm( state, envInfo, se->chainParams(), address, address, address, value, gasPrice, {}, ref( codeSelfBalance ), sha3( codeSelfBalance ), version, depth, isCreate, staticCall ); BOOST_REQUIRE_THROW( vm->exec( gas, extVm, OnOpFunc{} ), BadInstruction ); @@ -624,7 +625,7 @@ class BalanceFixture : public TestOutputHelperFixture { State state{0}; std::unique_ptr< SealEngineFace > se{ ChainParams( genesisInfo( Network::IstanbulTest ) ).createSealEngine()}; - EnvInfo envInfo{blockHeader, lastBlockHashes, 0, se->chainParams().chainID}; + EnvInfo envInfo{blockHeader, lastBlockHashes, 1, 0, se->chainParams().chainID}; u256 value = 0; u256 gasPrice = 1; @@ -648,6 +649,47 @@ class BalanceFixture : public TestOutputHelperFixture { std::unique_ptr< VMFace > vm; }; +class InstructionTestFixture : public TestOutputHelperFixture { +public: + InstructionTestFixture() : vm{new LegacyVM()} { + ChainParams cp( genesisInfo( Network::IstanbulTest ) ); + cp.sChain._patchTimestamps[static_cast(SchainPatchEnum::PushZeroPatch)] = 1; + SchainPatch::init(cp); + + se.reset(cp.createSealEngine()); + envInfo = std::make_unique ( blockHeader, lastBlockHashes, 1, 0, cp.chainID ); + + state.addBalance( address, 1 * ether ); + } + + void testCode( std::string const& _codeStr ) { + + bytes const code = fromHex( _codeStr ); + + ExtVM extVm( state, *envInfo, se->chainParams(), address, address, address, value, gasPrice, {}, + ref( code ), sha3( code ), version, depth, isCreate, staticCall ); + + owning_bytes_ref ret = vm->exec( gas, extVm, OnOpFunc{} ); + } + + BlockHeader blockHeader{initBlockHeader()}; + LastBlockHashes lastBlockHashes; + Address address{KeyPair::create().address()}; + State state{0}; + std::unique_ptr< SealEngineFace > se; + std::unique_ptr envInfo; + + u256 value = 0; + u256 gasPrice = 1; + u256 version = IstanbulSchedule.accountVersion; + int depth = 0; + bool isCreate = false; + bool staticCall = false; + u256 gas = 1000000; + + std::unique_ptr< LegacyVM > vm; +}; + class LegacyVMBalanceFixture : public BalanceFixture { public: LegacyVMBalanceFixture() : BalanceFixture{new LegacyVM} {} @@ -857,6 +899,18 @@ BOOST_AUTO_TEST_CASE( LegacyVMSelfBalanceisInvalidBeforeIstanbul, } BOOST_AUTO_TEST_SUITE_END() +BOOST_FIXTURE_TEST_SUITE( InstructionSuite, InstructionTestFixture ) + +BOOST_AUTO_TEST_CASE( Push0 ) { + string code = "5f"; + BOOST_REQUIRE_NO_THROW( this->testCode(code) ); + u256s stack = vm->stack(); + BOOST_REQUIRE_EQUAL(stack.size(), 1); + BOOST_REQUIRE_EQUAL(stack[0], u256()); +} + +BOOST_AUTO_TEST_SUITE_END() + BOOST_AUTO_TEST_SUITE_END() BOOST_FIXTURE_TEST_SUITE( SkaleInterpreterSuite, TestOutputHelperFixture ) diff --git a/test/unittests/libweb3jsonrpc/jsonrpc.cpp b/test/unittests/libweb3jsonrpc/jsonrpc.cpp index 8f6b53f25..6e5d772f6 100644 --- a/test/unittests/libweb3jsonrpc/jsonrpc.cpp +++ b/test/unittests/libweb3jsonrpc/jsonrpc.cpp @@ -62,7 +62,7 @@ using namespace dev; using namespace dev::eth; using namespace dev::test; -static size_t rand_port = 1024 + rand() % 64000; +static size_t rand_port = ( srand(time(nullptr)), 1024 + rand() % 64000 ); static std::string const c_genesisConfigString = R"( @@ -293,9 +293,12 @@ JsonRpcFixture( const std::string& _config = "", bool _owner = true, chainParams.sChain.contractStorageLimit = 128; // 615 + 1430 is experimentally-derived block size + average extras size chainParams.sChain.dbStorageLimit = 320.5*( 615 + 1430 ); - chainParams.sChain.contractStoragePatchTimestamp = 1; + chainParams.sChain._patchTimestamps[static_cast(SchainPatchEnum::ContractStoragePatch)] = 1; + chainParams.sChain._patchTimestamps[static_cast(SchainPatchEnum::StorageDestructionPatch)] = 1; powPatchActivationTimestamp = time(nullptr) + 60; - chainParams.sChain.correctForkInPowPatchTimestamp = powPatchActivationTimestamp; // 10 guessed seconds + chainParams.sChain._patchTimestamps[static_cast(SchainPatchEnum::CorrectForkInPowPatch)] = powPatchActivationTimestamp; + push0PatchActivationTimestamp = time(nullptr) + 10; + chainParams.sChain._patchTimestamps[static_cast(SchainPatchEnum::PushZeroPatch)] = push0PatchActivationTimestamp; chainParams.sChain.emptyBlockIntervalMs = _emptyBlockIntervalMs; // add random extra data to randomize genesis hash and get random DB path, // so that tests can be run in parallel @@ -303,6 +306,7 @@ JsonRpcFixture( const std::string& _config = "", bool _owner = true, chainParams.extraData = h256::random().asBytes(); chainParams.nodeInfo.port = chainParams.nodeInfo.port6 = rand_port; chainParams.sChain.nodes[0].port = chainParams.sChain.nodes[0].port6 = rand_port; + chainParams.skaleDisableChainIdCheck = true; } chainParams.sChain.multiTransactionMode = _mtmEnabled; chainParams.nodeInfo.syncNode = _isSyncNode; @@ -430,6 +434,7 @@ JsonRpcFixture( const std::string& _config = "", bool _owner = true, std::string adminSession; SkaleServerOverride* skale_server_connector; time_t powPatchActivationTimestamp; + time_t push0PatchActivationTimestamp; }; struct RestrictedAddressFixture : public JsonRpcFixture { @@ -1315,6 +1320,110 @@ BOOST_AUTO_TEST_CASE( create_opcode ) { BOOST_CHECK( response2 != response1 ); } +BOOST_AUTO_TEST_CASE( push0_patch_activation ) { + JsonRpcFixture fixture; + auto senderAddress = fixture.coinbase.address(); + + fixture.client->setAuthor( senderAddress ); + dev::eth::simulateMining( *( fixture.client ), 1 ); + + fixture.client->setAuthor( fixture.account2.address() ); + dev::eth::simulateMining( *( fixture.client ), 1 ); + +/* +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.8.2; + +contract Push0Test { + fallback() external payable { + assembly { + let t := add(9, 10) + } + } +} + +then convert to yul: solc --ir p0test.sol >p0test.yul + +then change code: + { + let r := add(88,99) + let tmp := verbatim_0i_1o(hex"5f") + } + +then compile! + +*/ + string compiled = + "608060405234156100135761001261003b565b5b61001b610040565b610023610031565b6101b761004382396101b781f35b6000604051905090565b600080fd5b56fe608060405261000f36600061015b565b805160208201f35b60006060905090565b6000604051905090565b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100738261002a565b810181811067ffffffffffffffff821117156100925761009161003b565b5b80604052505050565b60006100a5610020565b90506100b1828261006a565b919050565b600067ffffffffffffffff8211156100d1576100d061003b565b5b6100da8261002a565b9050602081019050919050565b60006100f2826100b6565b6100fb8161009b565b915082825250919050565b7f7375636365737300000000000000000000000000000000000000000000000000600082015250565b600061013b60076100e7565b905061014960208201610106565b90565b600061015661012f565b905090565b6000610165610017565b809150600a6009015f505061017861014c565b9150509291505056fea2646970667358221220b3871ed09fbcbb1dac74c3cd48dafa5d097bea7c808b5ff2c16a996cf108d3c664736f6c63430008190033"; +// "60806040523415601057600f6031565b5b60166036565b601c6027565b604c60398239604c81f35b6000604051905090565b600080fd5b56fe6080604052600a600c565b005b60636058015f505056fea2646970667358221220ee9861b869ceda6de64f2ec7ccbebf2babce54b35502a866a4193e05ae595e1f64736f6c63430008130033"; + + Json::Value create; + + create["from"] = toJS( senderAddress ); + create["code"] = compiled; + create["gas"] = "1000000"; + + string txHash = fixture.rpcClient->eth_sendTransaction( create ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + + Json::Value receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash ); + BOOST_REQUIRE_EQUAL( receipt["status"], string( "0x1" ) ); // deploy should succeed + string contractAddress = receipt["contractAddress"].asString(); + + Json::Value callObject; + + callObject["from"] = toJS( fixture.account2.address() ); + callObject["to"] = contractAddress; + + // first try without PushZeroPatch + + txHash = fixture.rpcClient->eth_sendTransaction( callObject ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash ); + BOOST_REQUIRE_EQUAL( receipt["status"], string( "0x0" ) ); // exec should fail + + string callResult = fixture.rpcClient->eth_call(callObject, "latest"); + BOOST_REQUIRE_EQUAL( callResult, string( "0x" ) ); // call too + + // wait for block after timestamp + BOOST_REQUIRE_LT( fixture.client->blockInfo(LatestBlock).timestamp(), fixture.push0PatchActivationTimestamp ); + while( time(nullptr) < fixture.push0PatchActivationTimestamp ) + sleep(1); + + // 1st timestamp-crossing block + txHash = fixture.rpcClient->eth_sendTransaction( callObject ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + BOOST_REQUIRE_GE( fixture.client->blockInfo(LatestBlock).timestamp(), fixture.push0PatchActivationTimestamp ); + + uint64_t crossingBlockNumber = fixture.client->number(); + (void) crossingBlockNumber; + + // in the "corssing" block tx still should fail + receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash ); + BOOST_REQUIRE_EQUAL( receipt["status"], string( "0x0" ) ); + + // in 1st block with patch call should succeed + callResult = fixture.rpcClient->eth_call(callObject, "latest"); + BOOST_REQUIRE_NE( callResult, string( "0x" ) ); + + // tx should succeed too + txHash = fixture.rpcClient->eth_sendTransaction( callObject ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash ); + BOOST_REQUIRE_EQUAL( receipt["status"], string( "0x1" ) ); + +#ifdef HISTORIC_STATE + // histoic call should fail before activation and succees after it + + callResult = fixture.rpcClient->eth_call(callObject, toJS(crossingBlockNumber-1)); + BOOST_REQUIRE_EQUAL( callResult, string( "0x" ) ); + + callResult = fixture.rpcClient->eth_call(callObject, toJS(crossingBlockNumber)); + BOOST_REQUIRE_NE( callResult, string( "0x" ) ); +#endif +} + BOOST_AUTO_TEST_CASE( eth_estimateGas ) { JsonRpcFixture fixture( c_genesisConfigString ); @@ -2055,8 +2164,8 @@ contract TestEstimateGas { dev::bytes data = dev::jsToBytes( estimateGasCall["data"].asString() ); BOOST_REQUIRE( dev::jsToU256( estimatedGas ) > dev::eth::TransactionBase::baseGasRequired( - false, &data, fixture.client->chainParams().scheduleForBlockNumber( - fixture.client->number() ) ) ); + false, &data, fixture.client->chainParams().makeEvmSchedule( + fixture.client->latestBlock().info().timestamp(), fixture.client->number() ) ) ); // try to send with this gas estimateGasCall["gas"] = toJS( jsToInt( estimatedGas ) ); @@ -3397,7 +3506,7 @@ BOOST_AUTO_TEST_CASE( cached_filestorage ) { auto _config = c_genesisConfigString; Json::Value ret; Json::Reader().parse( _config, ret ); - ret["skaleConfig"]["sChain"]["revertableFSPatchTimestamp"] = 1; + ret["skaleConfig"]["sChain"]["revertableFSPatchTimestamp"] = 1; Json::FastWriter fastWriter; std::string config = fastWriter.write( ret ); RestrictedAddressFixture fixture( config );