mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge commit '4d2f20570' into develop_060
This commit is contained in:
		
						commit
						19a6f09cc8
					
				| @ -295,6 +295,7 @@ jobs: | ||||
|     environment: | ||||
|       CC: clang | ||||
|       CXX: clang++ | ||||
|       CMAKE_OPTIONS: -DLLL=ON | ||||
|     steps: | ||||
|       - checkout | ||||
|       - run: *run_build | ||||
| @ -304,6 +305,8 @@ jobs: | ||||
|   b_ubu: &build_ubuntu1904 | ||||
|     docker: | ||||
|       - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.docker-image-rev >> | ||||
|     environment: | ||||
|       CMAKE_OPTIONS: -DLLL=ON | ||||
|     steps: | ||||
|       - checkout | ||||
|       - run: *run_build | ||||
| @ -314,12 +317,13 @@ jobs: | ||||
|     <<: *build_ubuntu1904 | ||||
|     environment: | ||||
|       FORCE_RELEASE: ON | ||||
|       CMAKE_OPTIONS: -DLLL=ON | ||||
| 
 | ||||
|   b_ubu18: &build_ubuntu1804 | ||||
|     docker: | ||||
|       - image: ethereum/solidity-buildpack-deps:ubuntu1804-<< pipeline.parameters.docker-image-rev >> | ||||
|     environment: | ||||
|       CMAKE_OPTIONS: -DCMAKE_CXX_FLAGS=-O2 | ||||
|       CMAKE_OPTIONS: -DCMAKE_CXX_FLAGS=-O2 -DLLL=ON | ||||
|       CMAKE_BUILD_TYPE: RelWithDebugInfo | ||||
|     steps: | ||||
|       - checkout | ||||
| @ -364,7 +368,7 @@ jobs: | ||||
|     <<: *build_ubuntu1904 | ||||
|     environment: | ||||
|       CMAKE_BUILD_TYPE: Debug | ||||
|       CMAKE_OPTIONS: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/cxx20.cmake -DUSE_CVC4=OFF | ||||
|       CMAKE_OPTIONS: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/cxx20.cmake -DUSE_CVC4=OFF -DLLL=ON | ||||
|     steps: | ||||
|       - checkout | ||||
|       - run: *run_build | ||||
| @ -404,6 +408,7 @@ jobs: | ||||
|       - image: archlinux/base | ||||
|     environment: | ||||
|       TERM: xterm | ||||
|       CMAKE_OPTIONS: -DLLL=ON | ||||
|     steps: | ||||
|       - run: | ||||
|           name: Install build dependencies | ||||
| @ -420,6 +425,7 @@ jobs: | ||||
|     environment: | ||||
|       TERM: xterm | ||||
|       CMAKE_BUILD_TYPE: Debug | ||||
|       CMAKE_OPTIONS: -DLLL=ON | ||||
|     steps: | ||||
|       - checkout | ||||
|       - restore_cache: | ||||
|  | ||||
| @ -46,6 +46,7 @@ Language Features: | ||||
| 
 | ||||
| 
 | ||||
| Compiler Features: | ||||
|  * Commandline Interface: Allow translation from yul / strict assembly to EWasm using ``solc --yul --yul-dialect evm --machine eWasm`` | ||||
|  * SMTChecker: Add support to constructors including constructor inheritance. | ||||
|  * Yul: When compiling via Yul, string literals from the Solidity code are kept as string literals if every character is safely printable. | ||||
|  * Yul Optimizer: Perform loop-invariant code motion. | ||||
|  | ||||
| @ -1077,25 +1077,17 @@ void CompilerStack::generateEWasm(ContractDefinition const& _contract) | ||||
| 		return; | ||||
| 
 | ||||
| 	// Re-parse the Yul IR in EVM dialect
 | ||||
| 	yul::AssemblyStack evmStack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, m_optimiserSettings); | ||||
| 	evmStack.parseAndAnalyze("", compiledContract.yulIROptimized); | ||||
| 	yul::AssemblyStack stack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, m_optimiserSettings); | ||||
| 	stack.parseAndAnalyze("", compiledContract.yulIROptimized); | ||||
| 
 | ||||
| 	// Turn into eWasm dialect
 | ||||
| 	yul::Object ewasmObject = yul::EVMToEWasmTranslator( | ||||
| 		yul::EVMDialect::strictAssemblyForEVMObjects(m_evmVersion) | ||||
| 	).run(*evmStack.parserResult()); | ||||
| 	stack.optimize(); | ||||
| 	stack.translate(yul::AssemblyStack::Language::EWasm); | ||||
| 	stack.optimize(); | ||||
| 
 | ||||
| 	// Re-inject into an assembly stack for the eWasm dialect
 | ||||
| 	yul::AssemblyStack ewasmStack(m_evmVersion, yul::AssemblyStack::Language::EWasm, m_optimiserSettings); | ||||
| 	// TODO this is a hack for now - provide as structured AST!
 | ||||
| 	ewasmStack.parseAndAnalyze("", "{}"); | ||||
| 	*ewasmStack.parserResult() = move(ewasmObject); | ||||
| 	ewasmStack.optimize(); | ||||
| 
 | ||||
| 	//cout << yul::AsmPrinter{}(*ewasmStack.parserResult()->code) << endl;
 | ||||
| 	//cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl;
 | ||||
| 
 | ||||
| 	// Turn into eWasm text representation.
 | ||||
| 	auto result = ewasmStack.assemble(yul::AssemblyStack::Machine::eWasm); | ||||
| 	auto result = stack.assemble(yul::AssemblyStack::Machine::eWasm); | ||||
| 	compiledContract.eWasm = std::move(result.assembly); | ||||
| 	compiledContract.eWasmObject = std::move(*result.bytecode); | ||||
| } | ||||
|  | ||||
| @ -34,6 +34,7 @@ | ||||
| #include <libyul/backends/evm/EVMMetrics.h> | ||||
| #include <libyul/backends/wasm/WasmDialect.h> | ||||
| #include <libyul/backends/wasm/EWasmObjectCompiler.h> | ||||
| #include <libyul/backends/wasm/EVMToEWasmTranslator.h> | ||||
| #include <libyul/optimiser/Metrics.h> | ||||
| #include <libyul/ObjectParser.h> | ||||
| #include <libyul/optimiser/Suite.h> | ||||
| @ -101,6 +102,23 @@ void AssemblyStack::optimize() | ||||
| 	solAssert(analyzeParsed(), "Invalid source code after optimization."); | ||||
| } | ||||
| 
 | ||||
| void AssemblyStack::translate(AssemblyStack::Language _targetLanguage) | ||||
| { | ||||
| 	if (m_language == _targetLanguage) | ||||
| 		return; | ||||
| 
 | ||||
| 	solAssert( | ||||
| 		m_language == Language::StrictAssembly && _targetLanguage == Language::EWasm, | ||||
| 		"Invalid language combination" | ||||
| 	); | ||||
| 
 | ||||
| 	*m_parserResult = EVMToEWasmTranslator( | ||||
| 		languageToDialect(m_language, m_evmVersion) | ||||
| 	).run(*parserResult()); | ||||
| 
 | ||||
| 	m_language = _targetLanguage; | ||||
| } | ||||
| 
 | ||||
| bool AssemblyStack::analyzeParsed() | ||||
| { | ||||
| 	solAssert(m_parserResult, ""); | ||||
|  | ||||
| @ -81,6 +81,9 @@ public: | ||||
| 	/// If the settings (see constructor) disabled the optimizer, nothing is done here.
 | ||||
| 	void optimize(); | ||||
| 
 | ||||
| 	/// Translate the source to a different language / dialect.
 | ||||
| 	void translate(Language _targetLanguage); | ||||
| 
 | ||||
| 	/// Run the assembly step (should only be called after parseAndAnalyze).
 | ||||
| 	MachineAssemblyObject assemble(Machine _machine) const; | ||||
| 
 | ||||
|  | ||||
| @ -122,6 +122,7 @@ static string const g_strHelp = "help"; | ||||
| static string const g_strInputFile = "input-file"; | ||||
| static string const g_strInterface = "interface"; | ||||
| static string const g_strYul = "yul"; | ||||
| static string const g_strYulDialect = "yul-dialect"; | ||||
| static string const g_strIR = "ir"; | ||||
| static string const g_strIPFS = "ipfs"; | ||||
| static string const g_strEWasm = "ewasm"; | ||||
| @ -235,6 +236,13 @@ static set<string> const g_machineArgs | ||||
| 	g_streWasm | ||||
| }; | ||||
| 
 | ||||
| /// Possible arguments to for --yul-dialect
 | ||||
| static set<string> const g_yulDialectArgs | ||||
| { | ||||
| 	g_strEVM, | ||||
| 	g_streWasm | ||||
| }; | ||||
| 
 | ||||
| /// Possible arguments to for --metadata-hash
 | ||||
| static set<string> const g_metadataHashArgs | ||||
| { | ||||
| @ -713,15 +721,20 @@ Allowed options)", | ||||
| 		) | ||||
| 		( | ||||
| 			g_argAssemble.c_str(), | ||||
| 			"Switch to assembly mode, ignoring all options except --machine and --optimize and assumes input is assembly." | ||||
| 			"Switch to assembly mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is assembly." | ||||
| 		) | ||||
| 		( | ||||
| 			g_argYul.c_str(), | ||||
| 			"Switch to Yul mode, ignoring all options except --machine and --optimize and assumes input is Yul." | ||||
| 			"Switch to Yul mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is Yul." | ||||
| 		) | ||||
| 		( | ||||
| 			g_argStrictAssembly.c_str(), | ||||
| 			"Switch to strict assembly mode, ignoring all options except --machine and --optimize and assumes input is strict assembly." | ||||
| 			"Switch to strict assembly mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is strict assembly." | ||||
| 		) | ||||
| 		( | ||||
| 			g_strYulDialect.c_str(), | ||||
| 			po::value<string>()->value_name(boost::join(g_yulDialectArgs, ",")), | ||||
| 			"Input dialect to use in assembly or yul mode." | ||||
| 		) | ||||
| 		( | ||||
| 			g_argMachine.c_str(), | ||||
| @ -965,7 +978,27 @@ bool CommandLineInterface::processInput() | ||||
| 		} | ||||
| 		if (targetMachine == Machine::eWasm && inputLanguage == Input::StrictAssembly) | ||||
| 			inputLanguage = Input::EWasm; | ||||
| 		if (optimize && inputLanguage != Input::StrictAssembly) | ||||
| 		if (m_args.count(g_strYulDialect)) | ||||
| 		{ | ||||
| 			string dialect = m_args[g_strYulDialect].as<string>(); | ||||
| 			if (dialect == g_strEVM) | ||||
| 				inputLanguage = Input::StrictAssembly; | ||||
| 			else if (dialect == g_streWasm) | ||||
| 			{ | ||||
| 				inputLanguage = Input::EWasm; | ||||
| 				if (targetMachine != Machine::eWasm) | ||||
| 				{ | ||||
| 					serr() << "If you select eWasm as --yul-dialect, --machine has to be eWasm as well." << endl; | ||||
| 					return false; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				serr() << "Invalid option for --yul-dialect: " << dialect << endl; | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 		if (optimize && (inputLanguage != Input::StrictAssembly && inputLanguage != Input::EWasm)) | ||||
| 		{ | ||||
| 			serr() << | ||||
| 				"Optimizer can only be used for strict assembly. Use --" << | ||||
| @ -1409,11 +1442,22 @@ bool CommandLineInterface::assemble( | ||||
| 			_targetMachine == yul::AssemblyStack::Machine::EVM15 ? "EVM 1.5" : | ||||
| 			"eWasm"; | ||||
| 		sout() << endl << "======= " << src.first << " (" << machine << ") =======" << endl; | ||||
| 
 | ||||
| 		yul::AssemblyStack& stack = assemblyStacks[src.first]; | ||||
| 
 | ||||
| 		sout() << endl << "Pretty printed source:" << endl; | ||||
| 		sout() << stack.print() << endl; | ||||
| 
 | ||||
| 		if (_language != yul::AssemblyStack::Language::EWasm && _targetMachine == yul::AssemblyStack::Machine::eWasm) | ||||
| 		{ | ||||
| 			stack.translate(yul::AssemblyStack::Language::EWasm); | ||||
| 			stack.optimize(); | ||||
| 
 | ||||
| 			sout() << endl << "==========================" << endl; | ||||
| 			sout() << endl << "Translated source:" << endl; | ||||
| 			sout() << stack.print() << endl; | ||||
| 		} | ||||
| 
 | ||||
| 		yul::MachineAssemblyObject object; | ||||
| 		try | ||||
| 		{ | ||||
|  | ||||
| @ -86,6 +86,20 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm): | ||||
| 		assertThrow(false, Exception, "Berlin is not supported yet."); | ||||
| 	else //if (_evmVersion == langutil::EVMVersion::petersburg())
 | ||||
| 		m_evmRevision = EVMC_PETERSBURG; | ||||
| 
 | ||||
| 	// Mark all precompiled contracts as existing. Existing here means to have a balance (as per EIP-161).
 | ||||
| 	// NOTE: keep this in sync with `EVMHost::call` below.
 | ||||
| 	//
 | ||||
| 	// A lot of precompile addresses had a balance before they became valid addresses for precompiles.
 | ||||
| 	// For example all the precompile addresses allocated in Byzantium had a 1 wei balance sent to them
 | ||||
| 	// roughly 22 days before the update went live.
 | ||||
| 	for (unsigned precompiledAddress = 1; precompiledAddress <= 8; precompiledAddress++) | ||||
| 	{ | ||||
| 		evmc::address address{}; | ||||
| 		address.bytes[19] = precompiledAddress; | ||||
| 		// 1wei
 | ||||
| 		m_state.accounts[address].balance.bytes[31] = 1; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| evmc_storage_status EVMHost::set_storage(const evmc::address& _addr, const evmc::bytes32& _key, const evmc::bytes32& _value) noexcept | ||||
| @ -123,13 +137,13 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept | ||||
| 		return precompileRipeMD160(_message); | ||||
| 	else if (_message.destination == 0x0000000000000000000000000000000000000004_address) | ||||
| 		return precompileIdentity(_message); | ||||
| 	else if (_message.destination == 0x0000000000000000000000000000000000000005_address) | ||||
| 	else if (_message.destination == 0x0000000000000000000000000000000000000005_address && m_evmVersion >= langutil::EVMVersion::byzantium()) | ||||
| 		return precompileModExp(_message); | ||||
| 	else if (_message.destination == 0x0000000000000000000000000000000000000006_address) | ||||
| 	else if (_message.destination == 0x0000000000000000000000000000000000000006_address && m_evmVersion >= langutil::EVMVersion::byzantium()) | ||||
| 		return precompileALTBN128G1Add(_message); | ||||
| 	else if (_message.destination == 0x0000000000000000000000000000000000000007_address) | ||||
| 	else if (_message.destination == 0x0000000000000000000000000000000000000007_address && m_evmVersion >= langutil::EVMVersion::byzantium()) | ||||
| 		return precompileALTBN128G1Mul(_message); | ||||
| 	else if (_message.destination == 0x0000000000000000000000000000000000000008_address) | ||||
| 	else if (_message.destination == 0x0000000000000000000000000000000000000008_address && m_evmVersion >= langutil::EVMVersion::byzantium()) | ||||
| 		return precompileALTBN128PairingProduct(_message); | ||||
| 
 | ||||
| 	State stateBackup = m_state; | ||||
| @ -215,7 +229,7 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| evmc_tx_context EVMHost::get_tx_context() noexcept | ||||
| evmc_tx_context EVMHost::get_tx_context() const noexcept | ||||
| { | ||||
| 	evmc_tx_context ctx = {}; | ||||
| 	ctx.block_timestamp = m_state.timestamp; | ||||
| @ -231,7 +245,7 @@ evmc_tx_context EVMHost::get_tx_context() noexcept | ||||
| 	return ctx; | ||||
| } | ||||
| 
 | ||||
| evmc::bytes32 EVMHost::get_block_hash(int64_t _number) noexcept | ||||
| evmc::bytes32 EVMHost::get_block_hash(int64_t _number) const noexcept | ||||
| { | ||||
| 	return convertToEVMC(u256("0x3737373737373737373737373737373737373737373737373737373737373737") + _number); | ||||
| } | ||||
|  | ||||
| @ -68,12 +68,14 @@ public: | ||||
| 		std::vector<LogEntry> logs; | ||||
| 	}; | ||||
| 
 | ||||
| 	Account const* account(evmc::address const& _address) const | ||||
| 	{ | ||||
| 		auto it = m_state.accounts.find(_address); | ||||
| 		return it == m_state.accounts.end() ? nullptr : &it->second; | ||||
| 	} | ||||
| 
 | ||||
| 	Account* account(evmc::address const& _address) | ||||
| 	{ | ||||
| 		// Make all precompiled contracts exist.
 | ||||
| 		// Be future-proof and consider everything below 1024 as precompiled contract.
 | ||||
| 		if (u160(convertFromEVMC(_address)) < 1024) | ||||
| 			m_state.accounts[_address]; | ||||
| 		auto it = m_state.accounts.find(_address); | ||||
| 		return it == m_state.accounts.end() ? nullptr : &it->second; | ||||
| 	} | ||||
| @ -86,15 +88,19 @@ public: | ||||
| 		m_state.logs.clear(); | ||||
| 	} | ||||
| 
 | ||||
| 	bool account_exists(evmc::address const& _addr) noexcept final | ||||
| 	bool account_exists(evmc::address const& _addr) const noexcept final | ||||
| 	{ | ||||
| 		return account(_addr) != nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	evmc::bytes32 get_storage(evmc::address const& _addr, evmc::bytes32 const& _key) noexcept final | ||||
| 	evmc::bytes32 get_storage(evmc::address const& _addr, evmc::bytes32 const& _key) const noexcept final | ||||
| 	{ | ||||
| 		if (Account* acc = account(_addr)) | ||||
| 			return acc->storage[_key]; | ||||
| 		if (auto* acc = account(_addr)) | ||||
| 		{ | ||||
| 			auto it = acc->storage.find(_key); | ||||
| 			if (it != acc->storage.end()) | ||||
| 				return it->second; | ||||
| 		} | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| @ -104,21 +110,21 @@ public: | ||||
| 		evmc::bytes32 const& _value | ||||
| 	) noexcept; | ||||
| 
 | ||||
| 	evmc::uint256be get_balance(evmc::address const& _addr) noexcept final | ||||
| 	evmc::uint256be get_balance(evmc::address const& _addr) const noexcept final | ||||
| 	{ | ||||
| 		if (Account const* acc = account(_addr)) | ||||
| 			return acc->balance; | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	size_t get_code_size(evmc::address const& _addr) noexcept final | ||||
| 	size_t get_code_size(evmc::address const& _addr) const noexcept final | ||||
| 	{ | ||||
| 		if (Account const* acc = account(_addr)) | ||||
| 			return acc->code.size(); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	evmc::bytes32 get_code_hash(evmc::address const& _addr) noexcept final | ||||
| 	evmc::bytes32 get_code_hash(evmc::address const& _addr) const noexcept final | ||||
| 	{ | ||||
| 		if (Account const* acc = account(_addr)) | ||||
| 			return acc->codeHash; | ||||
| @ -130,7 +136,7 @@ public: | ||||
| 		size_t _codeOffset, | ||||
| 		uint8_t* _bufferData, | ||||
| 		size_t _bufferSize | ||||
| 	) noexcept final | ||||
| 	) const noexcept final | ||||
| 	{ | ||||
| 		size_t i = 0; | ||||
| 		if (Account const* acc = account(_addr)) | ||||
| @ -143,9 +149,9 @@ public: | ||||
| 
 | ||||
| 	evmc::result call(evmc_message const& _message) noexcept; | ||||
| 
 | ||||
| 	evmc_tx_context get_tx_context() noexcept; | ||||
| 	evmc_tx_context get_tx_context() const noexcept; | ||||
| 
 | ||||
| 	evmc::bytes32 get_block_hash(int64_t number) noexcept; | ||||
| 	evmc::bytes32 get_block_hash(int64_t number) const noexcept; | ||||
| 
 | ||||
| 	void emit_log( | ||||
| 		evmc::address const& _addr, | ||||
| @ -166,15 +172,15 @@ public: | ||||
| 	evmc::address m_coinbase = convertToEVMC(Address("0x7878787878787878787878787878787878787878")); | ||||
| 
 | ||||
| private: | ||||
| 	evmc::result precompileECRecover(evmc_message const& _message) noexcept; | ||||
| 	evmc::result precompileSha256(evmc_message const& _message) noexcept; | ||||
| 	evmc::result precompileRipeMD160(evmc_message const& _message) noexcept; | ||||
| 	evmc::result precompileIdentity(evmc_message const& _message) noexcept; | ||||
| 	evmc::result precompileModExp(evmc_message const& _message) noexcept; | ||||
| 	evmc::result precompileALTBN128G1Add(evmc_message const& _message) noexcept; | ||||
| 	evmc::result precompileALTBN128G1Mul(evmc_message const& _message) noexcept; | ||||
| 	evmc::result precompileALTBN128PairingProduct(evmc_message const& _message) noexcept; | ||||
| 	evmc::result precompileGeneric(evmc_message const& _message, std::map<bytes, bytes> const& _inOut) noexcept; | ||||
| 	static evmc::result precompileECRecover(evmc_message const& _message) noexcept; | ||||
| 	static evmc::result precompileSha256(evmc_message const& _message) noexcept; | ||||
| 	static evmc::result precompileRipeMD160(evmc_message const& _message) noexcept; | ||||
| 	static evmc::result precompileIdentity(evmc_message const& _message) noexcept; | ||||
| 	static evmc::result precompileModExp(evmc_message const& _message) noexcept; | ||||
| 	static evmc::result precompileALTBN128G1Add(evmc_message const& _message) noexcept; | ||||
| 	static evmc::result precompileALTBN128G1Mul(evmc_message const& _message) noexcept; | ||||
| 	static evmc::result precompileALTBN128PairingProduct(evmc_message const& _message) noexcept; | ||||
| 	static evmc::result precompileGeneric(evmc_message const& _message, std::map<bytes, bytes> const& _inOut) noexcept; | ||||
| 	/// @returns a result object with no gas usage and result data taken from @a _data.
 | ||||
| 	/// @note The return value is only valid as long as @a _data is alive!
 | ||||
| 	static evmc::result resultWithGas(evmc_message const& _message, bytes const& _data) noexcept; | ||||
|  | ||||
							
								
								
									
										1
									
								
								test/cmdlineTests/evm_to_wasm/args
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/cmdlineTests/evm_to_wasm/args
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| --assemble --optimize --yul-dialect evm --machine ewasm | ||||
							
								
								
									
										1
									
								
								test/cmdlineTests/evm_to_wasm/err
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/cmdlineTests/evm_to_wasm/err
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| Warning: Yul and its optimizer are still experimental. Please use the output with care. | ||||
							
								
								
									
										3
									
								
								test/cmdlineTests/evm_to_wasm/input.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								test/cmdlineTests/evm_to_wasm/input.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| { | ||||
|     sstore(0, 1) | ||||
| } | ||||
							
								
								
									
										104
									
								
								test/cmdlineTests/evm_to_wasm/output
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								test/cmdlineTests/evm_to_wasm/output
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | ||||
| 
 | ||||
| ======= evm_to_wasm/input.sol (eWasm) ======= | ||||
| 
 | ||||
| Pretty printed source: | ||||
| object "object" { | ||||
|     code { { sstore(0, 1) } } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| ========================== | ||||
| 
 | ||||
| Translated source: | ||||
| object "object" { | ||||
|     code { | ||||
|         function main() | ||||
|         { | ||||
|             let _1 := 0 | ||||
|             mstore_internal(0, _1, _1, _1, _1) | ||||
|             mstore_internal(32, _1, _1, _1, 1) | ||||
|             eth.storageStore(0, 32) | ||||
|         } | ||||
|         function endian_swap_16(x) -> y | ||||
|         { | ||||
|             y := i64.or(i64.and(i64.shl(x, 8), 0xff00), i64.and(i64.shr_u(x, 8), 0xff)) | ||||
|         } | ||||
|         function endian_swap_32(x) -> y | ||||
|         { | ||||
|             let hi := i64.shl(endian_swap_16(x), 16) | ||||
|             y := i64.or(hi, endian_swap_16(i64.shr_u(x, 16))) | ||||
|         } | ||||
|         function endian_swap(x) -> y | ||||
|         { | ||||
|             let hi := i64.shl(endian_swap_32(x), 32) | ||||
|             y := i64.or(hi, endian_swap_32(i64.shr_u(x, 32))) | ||||
|         } | ||||
|         function mstore_internal(pos, y1, y2, y3, y4) | ||||
|         { | ||||
|             i64.store(pos, endian_swap(y1)) | ||||
|             i64.store(i64.add(pos, 8), endian_swap(y2)) | ||||
|             i64.store(i64.add(pos, 16), endian_swap(y3)) | ||||
|             i64.store(i64.add(pos, 24), endian_swap(y4)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Binary representation: | ||||
| 0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010ab501052801017e420021004200200020002000200010054220200020002000420110054200a74220a710000b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001002421086210220022000421088100284210120010b1b01027e20001003422086210220022000422088100384210120010b3501007e2000a720011004370300200042087ca720021004370300200042107ca720031004370300200042187ca7200410043703000b | ||||
| 
 | ||||
| Text representation: | ||||
| (module | ||||
|     (import "ethereum" "storageStore" (func $eth.storageStore (param i32 i32))) | ||||
|     (memory $memory (export "memory") 1) | ||||
|     (export "main" (func $main)) | ||||
| 
 | ||||
| (func $main | ||||
|     (local $_1 i64) | ||||
|     (local.set $_1 (i64.const 0)) | ||||
|     (call $mstore_internal (i64.const 0) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)) | ||||
|     (call $mstore_internal (i64.const 32) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 1)) | ||||
|     (call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32))) | ||||
| ) | ||||
| 
 | ||||
| (func $endian_swap_16 | ||||
|     (param $x i64) | ||||
|     (result i64) | ||||
|     (local $y i64) | ||||
|     (local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255)))) | ||||
|     (local.get $y) | ||||
| ) | ||||
| 
 | ||||
| (func $endian_swap_32 | ||||
|     (param $x i64) | ||||
|     (result i64) | ||||
|     (local $y i64) | ||||
|     (local $hi i64) | ||||
|     (local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16))) | ||||
|     (local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16))))) | ||||
|     (local.get $y) | ||||
| ) | ||||
| 
 | ||||
| (func $endian_swap | ||||
|     (param $x i64) | ||||
|     (result i64) | ||||
|     (local $y i64) | ||||
|     (local $hi i64) | ||||
|     (local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32))) | ||||
|     (local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32))))) | ||||
|     (local.get $y) | ||||
| ) | ||||
| 
 | ||||
| (func $mstore_internal | ||||
|     (param $pos i64) | ||||
|     (param $y1 i64) | ||||
|     (param $y2 i64) | ||||
|     (param $y3 i64) | ||||
|     (param $y4 i64) | ||||
|     (i64.store (i32.wrap_i64 (local.get $pos)) (call $endian_swap (local.get $y1))) | ||||
|     (i64.store (i32.wrap_i64 (i64.add (local.get $pos) (i64.const 8))) (call $endian_swap (local.get $y2))) | ||||
|     (i64.store (i32.wrap_i64 (i64.add (local.get $pos) (i64.const 16))) (call $endian_swap (local.get $y3))) | ||||
|     (i64.store (i32.wrap_i64 (i64.add (local.get $pos) (i64.const 24))) (call $endian_swap (local.get $y4))) | ||||
| ) | ||||
| 
 | ||||
| ) | ||||
| @ -530,7 +530,7 @@ typedef size_t (*evmc_get_code_size_fn)(struct evmc_host_context* context, | ||||
|                                         const evmc_address* address); | ||||
| 
 | ||||
| /**
 | ||||
|  * Get code size callback function. | ||||
|  * Get code hash callback function. | ||||
|  * | ||||
|  * This callback function is used by a VM to get the keccak256 hash of the code stored | ||||
|  * in the account at the given address. For existing accounts not having a code, this | ||||
|  | ||||
| @ -294,7 +294,7 @@ public: | ||||
|     /// Destructor responsible for automatically releasing attached resources.
 | ||||
|     ~result() noexcept | ||||
|     { | ||||
|         if (release) | ||||
|         if (release != nullptr) | ||||
|             release(this); | ||||
|     } | ||||
| 
 | ||||
| @ -342,10 +342,10 @@ public: | ||||
|     virtual ~HostInterface() noexcept = default; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::account_exists
 | ||||
|     virtual bool account_exists(const address& addr) noexcept = 0; | ||||
|     virtual bool account_exists(const address& addr) const noexcept = 0; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::get_storage
 | ||||
|     virtual bytes32 get_storage(const address& addr, const bytes32& key) noexcept = 0; | ||||
|     virtual bytes32 get_storage(const address& addr, const bytes32& key) const noexcept = 0; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::set_storage
 | ||||
|     virtual evmc_storage_status set_storage(const address& addr, | ||||
| @ -353,19 +353,19 @@ public: | ||||
|                                             const bytes32& value) noexcept = 0; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::get_balance
 | ||||
|     virtual uint256be get_balance(const address& addr) noexcept = 0; | ||||
|     virtual uint256be get_balance(const address& addr) const noexcept = 0; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::get_code_size
 | ||||
|     virtual size_t get_code_size(const address& addr) noexcept = 0; | ||||
|     virtual size_t get_code_size(const address& addr) const noexcept = 0; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::get_code_hash
 | ||||
|     virtual bytes32 get_code_hash(const address& addr) noexcept = 0; | ||||
|     virtual bytes32 get_code_hash(const address& addr) const noexcept = 0; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::copy_code
 | ||||
|     virtual size_t copy_code(const address& addr, | ||||
|                              size_t code_offset, | ||||
|                              uint8_t* buffer_data, | ||||
|                              size_t buffer_size) noexcept = 0; | ||||
|                              size_t buffer_size) const noexcept = 0; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::selfdestruct
 | ||||
|     virtual void selfdestruct(const address& addr, const address& beneficiary) noexcept = 0; | ||||
| @ -374,10 +374,10 @@ public: | ||||
|     virtual result call(const evmc_message& msg) noexcept = 0; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::get_tx_context
 | ||||
|     virtual evmc_tx_context get_tx_context() noexcept = 0; | ||||
|     virtual evmc_tx_context get_tx_context() const noexcept = 0; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::get_block_hash
 | ||||
|     virtual bytes32 get_block_hash(int64_t block_number) noexcept = 0; | ||||
|     virtual bytes32 get_block_hash(int64_t block_number) const noexcept = 0; | ||||
| 
 | ||||
|     /// @copydoc evmc_host_interface::emit_log
 | ||||
|     virtual void emit_log(const address& addr, | ||||
| @ -395,7 +395,7 @@ class HostContext : public HostInterface | ||||
| { | ||||
|     const evmc_host_interface* host = nullptr; | ||||
|     evmc_host_context* context = nullptr; | ||||
|     evmc_tx_context tx_context = {}; | ||||
|     mutable evmc_tx_context tx_context = {}; | ||||
| 
 | ||||
| public: | ||||
|     /// Default constructor for null Host context.
 | ||||
| @ -408,12 +408,12 @@ public: | ||||
|       : host{&interface}, context{ctx} | ||||
|     {} | ||||
| 
 | ||||
|     bool account_exists(const address& address) noexcept final | ||||
|     bool account_exists(const address& address) const noexcept final | ||||
|     { | ||||
|         return host->account_exists(context, &address); | ||||
|     } | ||||
| 
 | ||||
|     bytes32 get_storage(const address& address, const bytes32& key) noexcept final | ||||
|     bytes32 get_storage(const address& address, const bytes32& key) const noexcept final | ||||
|     { | ||||
|         return host->get_storage(context, &address, &key); | ||||
|     } | ||||
| @ -425,17 +425,17 @@ public: | ||||
|         return host->set_storage(context, &address, &key, &value); | ||||
|     } | ||||
| 
 | ||||
|     uint256be get_balance(const address& address) noexcept final | ||||
|     uint256be get_balance(const address& address) const noexcept final | ||||
|     { | ||||
|         return host->get_balance(context, &address); | ||||
|     } | ||||
| 
 | ||||
|     size_t get_code_size(const address& address) noexcept final | ||||
|     size_t get_code_size(const address& address) const noexcept final | ||||
|     { | ||||
|         return host->get_code_size(context, &address); | ||||
|     } | ||||
| 
 | ||||
|     bytes32 get_code_hash(const address& address) noexcept final | ||||
|     bytes32 get_code_hash(const address& address) const noexcept final | ||||
|     { | ||||
|         return host->get_code_hash(context, &address); | ||||
|     } | ||||
| @ -443,7 +443,7 @@ public: | ||||
|     size_t copy_code(const address& address, | ||||
|                      size_t code_offset, | ||||
|                      uint8_t* buffer_data, | ||||
|                      size_t buffer_size) noexcept final | ||||
|                      size_t buffer_size) const noexcept final | ||||
|     { | ||||
|         return host->copy_code(context, &address, code_offset, buffer_data, buffer_size); | ||||
|     } | ||||
| @ -464,14 +464,14 @@ public: | ||||
|     /// by assuming that the block timestamp should never be zero.
 | ||||
|     ///
 | ||||
|     /// @return The cached transaction context.
 | ||||
|     evmc_tx_context get_tx_context() noexcept final | ||||
|     evmc_tx_context get_tx_context() const noexcept final | ||||
|     { | ||||
|         if (tx_context.block_timestamp == 0) | ||||
|             tx_context = host->get_tx_context(context); | ||||
|         return tx_context; | ||||
|     } | ||||
| 
 | ||||
|     bytes32 get_block_hash(int64_t number) noexcept final | ||||
|     bytes32 get_block_hash(int64_t number) const noexcept final | ||||
|     { | ||||
|         return host->get_block_hash(context, number); | ||||
|     } | ||||
| @ -534,7 +534,7 @@ public: | ||||
|     /// Destructor responsible for automatically destroying the VM instance.
 | ||||
|     ~VM() noexcept | ||||
|     { | ||||
|         if (m_instance) | ||||
|         if (m_instance != nullptr) | ||||
|             m_instance->destroy(m_instance); | ||||
|     } | ||||
| 
 | ||||
| @ -570,6 +570,12 @@ public: | ||||
|     /// @copydoc evmc_vm::version
 | ||||
|     char const* version() const noexcept { return m_instance->version; } | ||||
| 
 | ||||
|     /// Checks if the VM has the given capability.
 | ||||
|     bool has_capability(evmc_capabilities capability) const noexcept | ||||
|     { | ||||
|         return (get_capabilities() & static_cast<evmc_capabilities_flagset>(capability)) != 0; | ||||
|     } | ||||
| 
 | ||||
|     /// @copydoc evmc::vm::get_capabilities
 | ||||
|     evmc_capabilities_flagset get_capabilities() const noexcept | ||||
|     { | ||||
|  | ||||
| @ -297,6 +297,12 @@ struct evmc_vm* evmc_load_and_configure(const char* config, enum evmc_loader_err | ||||
|                            "%s (%s): unsupported value '%s' for option '%s'", vm->name, path, | ||||
|                            option, name); | ||||
|             goto exit; | ||||
| 
 | ||||
|         default: | ||||
|             ec = set_error(EVMC_LOADER_INVALID_OPTION_VALUE, | ||||
|                            "%s (%s): unknown error when setting value '%s' for option '%s'", | ||||
|                            vm->name, path, option, name); | ||||
|             goto exit; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										315
									
								
								test/evmc/mocked_host.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								test/evmc/mocked_host.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,315 @@ | ||||
| // EVMC: Ethereum Client-VM Connector API.
 | ||||
| // Copyright 2019 The EVMC Authors.
 | ||||
| // Licensed under the Apache License, Version 2.0.
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <evmc/evmc.hpp> | ||||
| #include <algorithm> | ||||
| #include <string> | ||||
| #include <unordered_map> | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace evmc | ||||
| { | ||||
| /// The string of bytes.
 | ||||
| using bytes = std::basic_string<uint8_t>; | ||||
| 
 | ||||
| /// Extended value (by dirty flag) for account storage.
 | ||||
| struct storage_value | ||||
| { | ||||
|     /// The storage value.
 | ||||
|     bytes32 value; | ||||
| 
 | ||||
|     /// True means this value has been modified already by the current transaction.
 | ||||
|     bool dirty{false}; | ||||
| 
 | ||||
|     /// Default constructor.
 | ||||
|     storage_value() noexcept = default; | ||||
| 
 | ||||
|     /// Constructor.
 | ||||
|     storage_value(const bytes32& _value, bool _dirty = false) noexcept  // NOLINT
 | ||||
|       : value{_value}, dirty{_dirty} | ||||
|     {} | ||||
| }; | ||||
| 
 | ||||
| /// Mocked account.
 | ||||
| struct MockedAccount | ||||
| { | ||||
|     /// The account nonce.
 | ||||
|     int nonce = 0; | ||||
| 
 | ||||
|     /// The account code.
 | ||||
|     bytes code; | ||||
| 
 | ||||
|     /// The code hash. Can be a value not related to the actual code.
 | ||||
|     bytes32 codehash; | ||||
| 
 | ||||
|     /// The account balance.
 | ||||
|     uint256be balance; | ||||
| 
 | ||||
|     /// The account storage map.
 | ||||
|     std::unordered_map<bytes32, storage_value> storage; | ||||
| 
 | ||||
|     /// Helper method for setting balance by numeric type.
 | ||||
|     void set_balance(uint64_t x) noexcept | ||||
|     { | ||||
|         balance = uint256be{}; | ||||
|         for (std::size_t i = 0; i < sizeof(x); ++i) | ||||
|             balance.bytes[sizeof(balance) - 1 - i] = static_cast<uint8_t>(x >> (8 * i)); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /// Mocked EVMC Host implementation.
 | ||||
| class MockedHost : public Host | ||||
| { | ||||
| public: | ||||
|     /// LOG record.
 | ||||
|     struct log_record | ||||
|     { | ||||
|         /// The address of the account which created the log.
 | ||||
|         address creator; | ||||
| 
 | ||||
|         /// The data attached to the log.
 | ||||
|         bytes data; | ||||
| 
 | ||||
|         /// The log topics.
 | ||||
|         std::vector<bytes32> topics; | ||||
| 
 | ||||
|         /// Equal operator.
 | ||||
|         bool operator==(const log_record& other) const noexcept | ||||
|         { | ||||
|             return creator == other.creator && data == other.data && topics == other.topics; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /// SELFDESTRUCT record.
 | ||||
|     struct selfdestuct_record | ||||
|     { | ||||
|         /// The address of the account which has self-destructed.
 | ||||
|         address selfdestructed; | ||||
| 
 | ||||
|         /// The address of the beneficiary account.
 | ||||
|         address beneficiary; | ||||
| 
 | ||||
|         /// Equal operator.
 | ||||
|         bool operator==(const selfdestuct_record& other) const noexcept | ||||
|         { | ||||
|             return selfdestructed == other.selfdestructed && beneficiary == other.beneficiary; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /// The set of all accounts in the Host, organized by their addresses.
 | ||||
|     std::unordered_map<address, MockedAccount> accounts; | ||||
| 
 | ||||
|     /// The EVMC transaction context to be returned by get_tx_context().
 | ||||
|     evmc_tx_context tx_context = {}; | ||||
| 
 | ||||
|     /// The block header hash value to be returned by get_block_hash().
 | ||||
|     bytes32 block_hash = {}; | ||||
| 
 | ||||
|     /// The call result to be returned by the call() method.
 | ||||
|     evmc_result call_result = {}; | ||||
| 
 | ||||
|     /// The record of all block numbers for which get_block_hash() was called.
 | ||||
|     mutable std::vector<int64_t> recorded_blockhashes; | ||||
| 
 | ||||
|     /// The record of all account accesses.
 | ||||
|     mutable std::vector<address> recorded_account_accesses; | ||||
| 
 | ||||
|     /// The maximum number of entries in recorded_account_accesses record.
 | ||||
|     /// This is arbitrary value useful in fuzzing when we don't want the record to explode.
 | ||||
|     static constexpr auto max_recorded_account_accesses = 200; | ||||
| 
 | ||||
|     /// The record of all call messages requested in the call() method.
 | ||||
|     std::vector<evmc_message> recorded_calls; | ||||
| 
 | ||||
|     /// The maximum number of entries in recorded_calls record.
 | ||||
|     /// This is arbitrary value useful in fuzzing when we don't want the record to explode.
 | ||||
|     static constexpr auto max_recorded_calls = 100; | ||||
| 
 | ||||
|     /// The record of all LOGs passed to the emit_log() method.
 | ||||
|     std::vector<log_record> recorded_logs; | ||||
| 
 | ||||
|     /// The record of all SELFDESTRUCTs from the selfdestruct() method.
 | ||||
|     std::vector<selfdestuct_record> recorded_selfdestructs; | ||||
| 
 | ||||
| protected: | ||||
|     /// The copy of call inputs for the recorded_calls record.
 | ||||
|     std::vector<bytes> m_recorded_calls_inputs; | ||||
| 
 | ||||
|     /// Record an account access.
 | ||||
|     /// @param addr  The address of the accessed account.
 | ||||
|     void record_account_access(const address& addr) const | ||||
|     { | ||||
|         if (recorded_account_accesses.empty()) | ||||
|             recorded_account_accesses.reserve(max_recorded_account_accesses); | ||||
| 
 | ||||
|         if (recorded_account_accesses.size() < max_recorded_account_accesses) | ||||
|             recorded_account_accesses.emplace_back(addr); | ||||
|     } | ||||
| 
 | ||||
|     /// Returns true if an account exists (EVMC Host method).
 | ||||
|     bool account_exists(const address& addr) const noexcept override | ||||
|     { | ||||
|         record_account_access(addr); | ||||
|         return accounts.count(addr) != 0; | ||||
|     } | ||||
| 
 | ||||
|     /// Get the account's storage value at the given key (EVMC Host method).
 | ||||
|     bytes32 get_storage(const address& addr, const bytes32& key) const noexcept override | ||||
|     { | ||||
|         record_account_access(addr); | ||||
| 
 | ||||
|         const auto account_iter = accounts.find(addr); | ||||
|         if (account_iter == accounts.end()) | ||||
|             return {}; | ||||
| 
 | ||||
|         const auto storage_iter = account_iter->second.storage.find(key); | ||||
|         if (storage_iter != account_iter->second.storage.end()) | ||||
|             return storage_iter->second.value; | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     /// Set the account's storage value (EVMC Host method).
 | ||||
|     evmc_storage_status set_storage(const address& addr, | ||||
|                                     const bytes32& key, | ||||
|                                     const bytes32& value) noexcept override | ||||
|     { | ||||
|         record_account_access(addr); | ||||
|         const auto it = accounts.find(addr); | ||||
|         if (it == accounts.end()) | ||||
|             return EVMC_STORAGE_UNCHANGED; | ||||
| 
 | ||||
|         auto& old = it->second.storage[key]; | ||||
| 
 | ||||
|         // Follow https://eips.ethereum.org/EIPS/eip-1283 specification.
 | ||||
|         // WARNING! This is not complete implementation as refund is not handled here.
 | ||||
| 
 | ||||
|         if (old.value == value) | ||||
|             return EVMC_STORAGE_UNCHANGED; | ||||
| 
 | ||||
|         evmc_storage_status status{}; | ||||
|         if (!old.dirty) | ||||
|         { | ||||
|             old.dirty = true; | ||||
|             if (!old.value) | ||||
|                 status = EVMC_STORAGE_ADDED; | ||||
|             else if (value) | ||||
|                 status = EVMC_STORAGE_MODIFIED; | ||||
|             else | ||||
|                 status = EVMC_STORAGE_DELETED; | ||||
|         } | ||||
|         else | ||||
|             status = EVMC_STORAGE_MODIFIED_AGAIN; | ||||
| 
 | ||||
|         old.value = value; | ||||
|         return status; | ||||
|     } | ||||
| 
 | ||||
|     /// Get the account's balance (EVMC Host method).
 | ||||
|     uint256be get_balance(const address& addr) const noexcept override | ||||
|     { | ||||
|         record_account_access(addr); | ||||
|         const auto it = accounts.find(addr); | ||||
|         if (it == accounts.end()) | ||||
|             return {}; | ||||
| 
 | ||||
|         return it->second.balance; | ||||
|     } | ||||
| 
 | ||||
|     /// Get the account's code size (EVMC host method).
 | ||||
|     size_t get_code_size(const address& addr) const noexcept override | ||||
|     { | ||||
|         record_account_access(addr); | ||||
|         const auto it = accounts.find(addr); | ||||
|         if (it == accounts.end()) | ||||
|             return 0; | ||||
|         return it->second.code.size(); | ||||
|     } | ||||
| 
 | ||||
|     /// Get the account's code hash (EVMC host method).
 | ||||
|     bytes32 get_code_hash(const address& addr) const noexcept override | ||||
|     { | ||||
|         record_account_access(addr); | ||||
|         const auto it = accounts.find(addr); | ||||
|         if (it == accounts.end()) | ||||
|             return {}; | ||||
|         return it->second.codehash; | ||||
|     } | ||||
| 
 | ||||
|     /// Copy the account's code to the given buffer (EVMC host method).
 | ||||
|     size_t copy_code(const address& addr, | ||||
|                      size_t code_offset, | ||||
|                      uint8_t* buffer_data, | ||||
|                      size_t buffer_size) const noexcept override | ||||
|     { | ||||
|         record_account_access(addr); | ||||
|         const auto it = accounts.find(addr); | ||||
|         if (it == accounts.end()) | ||||
|             return 0; | ||||
| 
 | ||||
|         const auto& code = it->second.code; | ||||
| 
 | ||||
|         if (code_offset >= code.size()) | ||||
|             return 0; | ||||
| 
 | ||||
|         const auto n = std::min(buffer_size, code.size() - code_offset); | ||||
| 
 | ||||
|         if (n > 0) | ||||
|             std::copy_n(&code[code_offset], n, buffer_data); | ||||
|         return n; | ||||
|     } | ||||
| 
 | ||||
|     /// Selfdestruct the account (EVMC host method).
 | ||||
|     void selfdestruct(const address& addr, const address& beneficiary) noexcept override | ||||
|     { | ||||
|         record_account_access(addr); | ||||
|         recorded_selfdestructs.push_back({addr, beneficiary}); | ||||
|     } | ||||
| 
 | ||||
|     /// Call/create other contract (EVMC host method).
 | ||||
|     result call(const evmc_message& msg) noexcept override | ||||
|     { | ||||
|         record_account_access(msg.destination); | ||||
| 
 | ||||
|         if (recorded_calls.empty()) | ||||
|         { | ||||
|             recorded_calls.reserve(max_recorded_calls); | ||||
|             m_recorded_calls_inputs.reserve(max_recorded_calls);  // Iterators will not invalidate.
 | ||||
|         } | ||||
| 
 | ||||
|         if (recorded_calls.size() < max_recorded_calls) | ||||
|         { | ||||
|             recorded_calls.emplace_back(msg); | ||||
|             auto& call_msg = recorded_calls.back(); | ||||
|             if (call_msg.input_size > 0) | ||||
|             { | ||||
|                 m_recorded_calls_inputs.emplace_back(call_msg.input_data, call_msg.input_size); | ||||
|                 const auto& input_copy = m_recorded_calls_inputs.back(); | ||||
|                 call_msg.input_data = input_copy.data(); | ||||
|             } | ||||
|         } | ||||
|         return result{call_result}; | ||||
|     } | ||||
| 
 | ||||
|     /// Get transaction context (EVMC host method).
 | ||||
|     evmc_tx_context get_tx_context() const noexcept override { return tx_context; } | ||||
| 
 | ||||
|     /// Get the block header hash (EVMC host method).
 | ||||
|     bytes32 get_block_hash(int64_t block_number) const noexcept override | ||||
|     { | ||||
|         recorded_blockhashes.emplace_back(block_number); | ||||
|         return block_hash; | ||||
|     } | ||||
| 
 | ||||
|     /// Emit LOG (EVMC host method).
 | ||||
|     void emit_log(const address& addr, | ||||
|                   const uint8_t* data, | ||||
|                   size_t data_size, | ||||
|                   const bytes32 topics[], | ||||
|                   size_t topics_count) noexcept override | ||||
|     { | ||||
|         recorded_logs.push_back({addr, {data, data_size}, {topics, topics + topics_count}}); | ||||
|     } | ||||
| }; | ||||
| }  // namespace evmc
 | ||||
| @ -43,6 +43,7 @@ | ||||
| using namespace std; | ||||
| using namespace std::placeholders; | ||||
| using namespace dev::test; | ||||
| using namespace langutil; | ||||
| 
 | ||||
| #define ALSO_VIA_YUL(CODE) \ | ||||
| { \ | ||||
| @ -12859,6 +12860,9 @@ BOOST_AUTO_TEST_CASE(address_overload_resolution) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(snark) | ||||
| { | ||||
| 	if (dev::test::Options::get().evmVersion() <= EVMVersion::byzantium()) | ||||
| 		return; | ||||
| 
 | ||||
| 	char const* sourceCode = R"( | ||||
| 	library Pairing { | ||||
| 		struct G1Point { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user