mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #10030 from ethereum/issue-7627
Fix dependency tracking for abstract contracts
This commit is contained in:
		
						commit
						0639467237
					
				| @ -3,7 +3,7 @@ | |||||||
| 
 | 
 | ||||||
| Bugfixes: | Bugfixes: | ||||||
|  * SMTChecker: Fix lack of reporting potential violations when using only the CHC engine. |  * SMTChecker: Fix lack of reporting potential violations when using only the CHC engine. | ||||||
| 
 |  * Code generator: Fix missing creation dependency tracking for abstract contracts. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ### 0.7.4 (2020-10-19) | ### 0.7.4 (2020-10-19) | ||||||
|  | |||||||
| @ -50,7 +50,7 @@ using namespace solidity::frontend; | |||||||
| 
 | 
 | ||||||
| pair<string, string> IRGenerator::run( | pair<string, string> IRGenerator::run( | ||||||
| 	ContractDefinition const& _contract, | 	ContractDefinition const& _contract, | ||||||
| 	map<ContractDefinition const*, string const> const& _otherYulSources | 	map<ContractDefinition const*, string_view const> const& _otherYulSources | ||||||
| ) | ) | ||||||
| { | { | ||||||
| 	string const ir = yul::reindent(generate(_contract, _otherYulSources)); | 	string const ir = yul::reindent(generate(_contract, _otherYulSources)); | ||||||
| @ -78,7 +78,7 @@ pair<string, string> IRGenerator::run( | |||||||
| 
 | 
 | ||||||
| string IRGenerator::generate( | string IRGenerator::generate( | ||||||
| 	ContractDefinition const& _contract, | 	ContractDefinition const& _contract, | ||||||
| 	map<ContractDefinition const*, string const> const& _otherYulSources | 	map<ContractDefinition const*, string_view const> const& _otherYulSources | ||||||
| ) | ) | ||||||
| { | { | ||||||
| 	auto subObjectSources = [&_otherYulSources](std::set<ContractDefinition const*, ASTNode::CompareByID> const& subObjects) -> string | 	auto subObjectSources = [&_otherYulSources](std::set<ContractDefinition const*, ASTNode::CompareByID> const& subObjects) -> string | ||||||
|  | |||||||
| @ -53,13 +53,13 @@ public: | |||||||
| 	/// (or just pretty-printed, depending on the optimizer settings).
 | 	/// (or just pretty-printed, depending on the optimizer settings).
 | ||||||
| 	std::pair<std::string, std::string> run( | 	std::pair<std::string, std::string> run( | ||||||
| 		ContractDefinition const& _contract, | 		ContractDefinition const& _contract, | ||||||
| 		std::map<ContractDefinition const*, std::string const> const& _otherYulSources | 		std::map<ContractDefinition const*, std::string_view const> const& _otherYulSources | ||||||
| 	); | 	); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	std::string generate( | 	std::string generate( | ||||||
| 		ContractDefinition const& _contract, | 		ContractDefinition const& _contract, | ||||||
| 		std::map<ContractDefinition const*, std::string const> const& _otherYulSources | 		std::map<ContractDefinition const*, std::string_view const> const& _otherYulSources | ||||||
| 	); | 	); | ||||||
| 	std::string generate(Block const& _block); | 	std::string generate(Block const& _block); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -525,6 +525,7 @@ bool CompilerStack::compile(State _stopAfter) | |||||||
| 
 | 
 | ||||||
| 	// Only compile contracts individually which have been requested.
 | 	// Only compile contracts individually which have been requested.
 | ||||||
| 	map<ContractDefinition const*, shared_ptr<Compiler const>> otherCompilers; | 	map<ContractDefinition const*, shared_ptr<Compiler const>> otherCompilers; | ||||||
|  | 
 | ||||||
| 	for (Source const* source: m_sourceOrder) | 	for (Source const* source: m_sourceOrder) | ||||||
| 		for (ASTPointer<ASTNode> const& node: source->ast->nodes()) | 		for (ASTPointer<ASTNode> const& node: source->ast->nodes()) | ||||||
| 			if (auto contract = dynamic_cast<ContractDefinition const*>(node.get())) | 			if (auto contract = dynamic_cast<ContractDefinition const*>(node.get())) | ||||||
| @ -1160,11 +1161,15 @@ void CompilerStack::compileContract( | |||||||
| 	if (m_hasError) | 	if (m_hasError) | ||||||
| 		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called compile with errors.")); | 		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called compile with errors.")); | ||||||
| 
 | 
 | ||||||
| 	if (_otherCompilers.count(&_contract) || !_contract.canBeDeployed()) | 	if (_otherCompilers.count(&_contract)) | ||||||
| 		return; | 		return; | ||||||
|  | 
 | ||||||
| 	for (auto const* dependency: _contract.annotation().contractDependencies) | 	for (auto const* dependency: _contract.annotation().contractDependencies) | ||||||
| 		compileContract(*dependency, _otherCompilers); | 		compileContract(*dependency, _otherCompilers); | ||||||
| 
 | 
 | ||||||
|  | 	if (!_contract.canBeDeployed()) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName()); | 	Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName()); | ||||||
| 
 | 
 | ||||||
| 	shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_revertStrings, m_optimiserSettings); | 	shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_revertStrings, m_optimiserSettings); | ||||||
| @ -1227,21 +1232,20 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) | |||||||
| 	if (m_hasError) | 	if (m_hasError) | ||||||
| 		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateIR with errors.")); | 		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateIR with errors.")); | ||||||
| 
 | 
 | ||||||
| 	if (!_contract.canBeDeployed()) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	map<ContractDefinition const*, string const> otherYulSources; |  | ||||||
| 
 |  | ||||||
| 	Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName()); | 	Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName()); | ||||||
| 	if (!compiledContract.yulIR.empty()) | 	if (!compiledContract.yulIR.empty()) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	string dependenciesSource; | 	string dependenciesSource; | ||||||
| 	for (auto const* dependency: _contract.annotation().contractDependencies) | 	for (auto const* dependency: _contract.annotation().contractDependencies) | ||||||
| 	{ |  | ||||||
| 		generateIR(*dependency); | 		generateIR(*dependency); | ||||||
| 		otherYulSources.emplace(dependency, m_contracts.at(dependency->fullyQualifiedName()).yulIR); | 
 | ||||||
| 	} | 	if (!_contract.canBeDeployed()) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	map<ContractDefinition const*, string_view const> otherYulSources; | ||||||
|  | 	for (auto const& pair: m_contracts) | ||||||
|  | 		otherYulSources.emplace(pair.second.contract, pair.second.yulIR); | ||||||
| 
 | 
 | ||||||
| 	IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings); | 	IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings); | ||||||
| 	tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract, otherYulSources); | 	tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract, otherYulSources); | ||||||
|  | |||||||
| @ -1505,6 +1505,96 @@ BOOST_AUTO_TEST_CASE(stopAfter_ast_output) | |||||||
| 	BOOST_CHECK(result["sources"]["a.sol"]["ast"].isObject()); | 	BOOST_CHECK(result["sources"]["a.sol"]["ast"].isObject()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | BOOST_AUTO_TEST_CASE(dependency_tracking_of_abstract_contract) | ||||||
|  | { | ||||||
|  | 	char const* input = R"( | ||||||
|  | 	{ | ||||||
|  | 		"language": "Solidity", | ||||||
|  | 		"sources": { | ||||||
|  | 			"BlockRewardAuRaBase.sol": { | ||||||
|  | 				"content": " contract Sacrifice { constructor() payable {} } abstract contract BlockRewardAuRaBase { function _transferNativeReward() internal { new Sacrifice(); } function _distributeTokenRewards() internal virtual; } " | ||||||
|  | 			}, | ||||||
|  | 			"BlockRewardAuRaCoins.sol": { | ||||||
|  | 				"content": " import \"./BlockRewardAuRaBase.sol\"; contract BlockRewardAuRaCoins is BlockRewardAuRaBase { function transferReward() public { _transferNativeReward(); } function _distributeTokenRewards() internal override {} } " | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		"settings": { | ||||||
|  | 			"outputSelection": { | ||||||
|  | 				"BlockRewardAuRaCoins.sol": { | ||||||
|  | 					"BlockRewardAuRaCoins": ["ir", "evm.bytecode.sourceMap"] | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	)"; | ||||||
|  | 
 | ||||||
|  | 	Json::Value parsedInput; | ||||||
|  | 	BOOST_REQUIRE(util::jsonParseStrict(input, parsedInput)); | ||||||
|  | 
 | ||||||
|  | 	solidity::frontend::StandardCompiler compiler; | ||||||
|  | 	Json::Value result = compiler.compile(parsedInput); | ||||||
|  | 
 | ||||||
|  | 	BOOST_REQUIRE(result["contracts"].isObject()); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"].size() == 1); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"].isObject()); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"].size() == 1); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"]["BlockRewardAuRaCoins"].isObject()); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"]["BlockRewardAuRaCoins"]["evm"].isObject()); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"]["BlockRewardAuRaCoins"]["ir"].isString()); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"]["BlockRewardAuRaCoins"]["evm"]["bytecode"].isObject()); | ||||||
|  | 	BOOST_REQUIRE(result["sources"].isObject()); | ||||||
|  | 	BOOST_REQUIRE(result["sources"].size() == 2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BOOST_AUTO_TEST_CASE(dependency_tracking_of_abstract_contract_yul) | ||||||
|  | { | ||||||
|  | 	char const* input = R"( | ||||||
|  | 	{ | ||||||
|  | 		"language": "Solidity", | ||||||
|  | 		"sources": { | ||||||
|  | 			"A.sol": { | ||||||
|  | 				"content": "contract A {} contract B {} contract C { constructor() { new B(); } } contract D {}" | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		"settings": { | ||||||
|  | 			"outputSelection": { | ||||||
|  | 				"A.sol": { | ||||||
|  | 					"C": ["ir"] | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	)"; | ||||||
|  | 
 | ||||||
|  | 	Json::Value parsedInput; | ||||||
|  | 	BOOST_REQUIRE(util::jsonParseStrict(input, parsedInput)); | ||||||
|  | 
 | ||||||
|  | 	solidity::frontend::StandardCompiler compiler; | ||||||
|  | 	Json::Value result = compiler.compile(parsedInput); | ||||||
|  | 
 | ||||||
|  | 	BOOST_REQUIRE(result["contracts"].isObject()); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"].size() == 1); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"]["A.sol"].isObject()); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"]["A.sol"].size() == 1); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"]["A.sol"]["C"].isObject()); | ||||||
|  | 	BOOST_REQUIRE(result["contracts"]["A.sol"]["C"]["ir"].isString()); | ||||||
|  | 
 | ||||||
|  | 	const string& irCode = result["contracts"]["A.sol"]["C"]["ir"].asString(); | ||||||
|  | 
 | ||||||
|  | 	// Make sure C and B contracts are deployed
 | ||||||
|  | 	BOOST_REQUIRE(irCode.find("object \"C") != string::npos); | ||||||
|  | 	BOOST_REQUIRE(irCode.find("object \"B") != string::npos); | ||||||
|  | 
 | ||||||
|  | 	// Make sure A and D are NOT deployed as they were not requested and are not
 | ||||||
|  | 	// in any dependency
 | ||||||
|  | 	BOOST_REQUIRE(irCode.find("object \"A") == string::npos); | ||||||
|  | 	BOOST_REQUIRE(irCode.find("object \"D") == string::npos); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	BOOST_REQUIRE(result["sources"].isObject()); | ||||||
|  | 	BOOST_REQUIRE(result["sources"].size() == 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() | ||||||
| 
 | 
 | ||||||
| } // end namespaces
 | } // end namespaces
 | ||||||
|  | |||||||
| @ -11,5 +11,7 @@ contract D { | |||||||
|     return test(); |     return test(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: true | ||||||
| // ---- | // ---- | ||||||
| // f() -> true | // f() -> true | ||||||
|  | |||||||
| @ -11,5 +11,7 @@ contract D { | |||||||
|     return test(); |     return test(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: true | ||||||
| // ---- | // ---- | ||||||
| // f() -> 2 | // f() -> 2 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user