mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Create and output clone contracts.
This commit is contained in:
		
							parent
							
								
									f2f1e03007
								
							
						
					
					
						commit
						943fd623e1
					
				
							
								
								
									
										88
									
								
								Compiler.cpp
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								Compiler.cpp
									
									
									
									
									
								
							@ -25,6 +25,7 @@
 | 
			
		||||
#include <boost/range/adaptor/reversed.hpp>
 | 
			
		||||
#include <libevmcore/Instruction.h>
 | 
			
		||||
#include <libevmasm/Assembly.h>
 | 
			
		||||
#include <libevmcore/Params.h>
 | 
			
		||||
#include <libsolidity/AST.h>
 | 
			
		||||
#include <libsolidity/ExpressionCompiler.h>
 | 
			
		||||
#include <libsolidity/CompilerUtils.h>
 | 
			
		||||
@ -53,31 +54,45 @@ void Compiler::compileContract(ContractDefinition const& _contract,
 | 
			
		||||
	m_context = CompilerContext(); // clear it just in case
 | 
			
		||||
	{
 | 
			
		||||
		CompilerContext::LocationSetter locationSetterRunTime(m_context, _contract);
 | 
			
		||||
		CompilerUtils(m_context).initialiseFreeMemoryPointer();
 | 
			
		||||
		initializeContext(_contract, _contracts);
 | 
			
		||||
		appendFunctionSelector(_contract);
 | 
			
		||||
		set<Declaration const*> functions = m_context.getFunctionsWithoutCode();
 | 
			
		||||
		while (!functions.empty())
 | 
			
		||||
		{
 | 
			
		||||
			for (Declaration const* function: functions)
 | 
			
		||||
			{
 | 
			
		||||
				m_context.setStackOffset(0);
 | 
			
		||||
				function->accept(*this);
 | 
			
		||||
			}
 | 
			
		||||
			functions = m_context.getFunctionsWithoutCode();
 | 
			
		||||
		}
 | 
			
		||||
		appendFunctionsWithoutCode();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Swap the runtime context with the creation-time context
 | 
			
		||||
	swap(m_context, m_runtimeContext);
 | 
			
		||||
	CompilerContext::LocationSetter locationSetterCreationTime(m_context, _contract);
 | 
			
		||||
	CompilerUtils(m_context).initialiseFreeMemoryPointer();
 | 
			
		||||
	initializeContext(_contract, _contracts);
 | 
			
		||||
	packIntoContractCreator(_contract, m_runtimeContext);
 | 
			
		||||
	if (m_optimize)
 | 
			
		||||
		m_context.optimise(m_optimizeRuns);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Compiler::compileClone(
 | 
			
		||||
	ContractDefinition const& _contract,
 | 
			
		||||
	map<ContractDefinition const*, bytes const*> const& _contracts
 | 
			
		||||
)
 | 
			
		||||
{
 | 
			
		||||
	m_context = CompilerContext(); // clear it just in case
 | 
			
		||||
	initializeContext(_contract, _contracts);
 | 
			
		||||
 | 
			
		||||
	appendInitAndConstructorCode(_contract);
 | 
			
		||||
 | 
			
		||||
	//@todo determine largest return size of all runtime functions
 | 
			
		||||
	eth::AssemblyItem runtimeSub = m_context.addSubroutine(getCloneRuntime());
 | 
			
		||||
	solAssert(runtimeSub.data() < numeric_limits<size_t>::max(), "");
 | 
			
		||||
	m_runtimeSub = size_t(runtimeSub.data());
 | 
			
		||||
 | 
			
		||||
	// stack contains sub size
 | 
			
		||||
	m_context << eth::Instruction::DUP1 << runtimeSub << u256(0) << eth::Instruction::CODECOPY;
 | 
			
		||||
	m_context << u256(0) << eth::Instruction::RETURN;
 | 
			
		||||
 | 
			
		||||
	appendFunctionsWithoutCode();
 | 
			
		||||
 | 
			
		||||
	if (m_optimize)
 | 
			
		||||
		m_context.optimise(m_optimizeRuns);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
eth::AssemblyItem Compiler::getFunctionEntryLabel(FunctionDefinition const& _function) const
 | 
			
		||||
{
 | 
			
		||||
	return m_runtimeContext.getFunctionEntryLabelIfExists(_function);
 | 
			
		||||
@ -86,13 +101,14 @@ eth::AssemblyItem Compiler::getFunctionEntryLabel(FunctionDefinition const& _fun
 | 
			
		||||
void Compiler::initializeContext(ContractDefinition const& _contract,
 | 
			
		||||
								 map<ContractDefinition const*, bytes const*> const& _contracts)
 | 
			
		||||
{
 | 
			
		||||
	CompilerUtils(m_context).initialiseFreeMemoryPointer();
 | 
			
		||||
	m_context.setCompiledContracts(_contracts);
 | 
			
		||||
	m_context.setInheritanceHierarchy(_contract.getLinearizedBaseContracts());
 | 
			
		||||
	registerStateVariables(_contract);
 | 
			
		||||
	m_context.resetVisitedNodes(&_contract);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext)
 | 
			
		||||
void Compiler::appendInitAndConstructorCode(ContractDefinition const& _contract)
 | 
			
		||||
{
 | 
			
		||||
	// Determine the arguments that are used for the base constructors.
 | 
			
		||||
	std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
 | 
			
		||||
@ -126,22 +142,22 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
 | 
			
		||||
		appendConstructor(*constructor);
 | 
			
		||||
	else if (auto c = m_context.getNextConstructor(_contract))
 | 
			
		||||
		appendBaseConstructor(*c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext)
 | 
			
		||||
{
 | 
			
		||||
	appendInitAndConstructorCode(_contract);
 | 
			
		||||
 | 
			
		||||
	eth::AssemblyItem runtimeSub = m_context.addSubroutine(_runtimeContext.getAssembly());
 | 
			
		||||
	solAssert(runtimeSub.data() < numeric_limits<size_t>::max(), "");
 | 
			
		||||
	m_runtimeSub = size_t(runtimeSub.data());
 | 
			
		||||
 | 
			
		||||
	// stack contains sub size
 | 
			
		||||
	m_context << eth::Instruction::DUP1 << runtimeSub << u256(0) << eth::Instruction::CODECOPY;
 | 
			
		||||
	m_context << u256(0) << eth::Instruction::RETURN;
 | 
			
		||||
 | 
			
		||||
	// note that we have to include the functions again because of absolute jump labels
 | 
			
		||||
	set<Declaration const*> functions = m_context.getFunctionsWithoutCode();
 | 
			
		||||
	while (!functions.empty())
 | 
			
		||||
	{
 | 
			
		||||
		for (Declaration const* function: functions)
 | 
			
		||||
			function->accept(*this);
 | 
			
		||||
		functions = m_context.getFunctionsWithoutCode();
 | 
			
		||||
	}
 | 
			
		||||
	appendFunctionsWithoutCode();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor)
 | 
			
		||||
@ -618,6 +634,20 @@ bool Compiler::visit(PlaceholderStatement const& _placeholderStatement)
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Compiler::appendFunctionsWithoutCode()
 | 
			
		||||
{
 | 
			
		||||
	set<Declaration const*> functions = m_context.getFunctionsWithoutCode();
 | 
			
		||||
	while (!functions.empty())
 | 
			
		||||
	{
 | 
			
		||||
		for (Declaration const* function: functions)
 | 
			
		||||
		{
 | 
			
		||||
			m_context.setStackOffset(0);
 | 
			
		||||
			function->accept(*this);
 | 
			
		||||
		}
 | 
			
		||||
		functions = m_context.getFunctionsWithoutCode();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Compiler::appendModifierOrFunctionCode()
 | 
			
		||||
{
 | 
			
		||||
	solAssert(m_currentFunction, "");
 | 
			
		||||
@ -674,3 +704,21 @@ void Compiler::compileExpression(Expression const& _expression, TypePointer cons
 | 
			
		||||
	if (_targetType)
 | 
			
		||||
		CompilerUtils(m_context).convertType(*_expression.getType(), *_targetType);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
eth::Assembly Compiler::getCloneRuntime()
 | 
			
		||||
{
 | 
			
		||||
	eth::Assembly a;
 | 
			
		||||
	a << eth::Instruction::CALLDATASIZE;
 | 
			
		||||
	a << u256(0) << eth::Instruction::DUP1 << eth::Instruction::CALLDATACOPY;
 | 
			
		||||
	//@todo adjust for larger return values, make this dynamic.
 | 
			
		||||
	a << u256(0x20) << u256(0) << eth::Instruction::CALLDATASIZE;
 | 
			
		||||
	a << u256(0) << eth::Instruction::DUP1;
 | 
			
		||||
	// this is the address which has to be substituted by the linker.
 | 
			
		||||
	//@todo implement as special "marker" AssemblyItem.
 | 
			
		||||
	a << u256("0xcafecafecafecafecafecafecafecafecafecafe");
 | 
			
		||||
	a << u256(eth::c_callGas + 10) << eth::Instruction::GAS << eth::Instruction::SUB;
 | 
			
		||||
	a << eth::Instruction::CALLCODE;
 | 
			
		||||
	//@todo adjust for larger return values, make this dynamic.
 | 
			
		||||
	a << u256(0x20) << u256(0) << eth::Instruction::RETURN;
 | 
			
		||||
	return a;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								Compiler.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								Compiler.h
									
									
									
									
									
								
							@ -44,6 +44,12 @@ public:
 | 
			
		||||
 | 
			
		||||
	void compileContract(ContractDefinition const& _contract,
 | 
			
		||||
						 std::map<ContractDefinition const*, bytes const*> const& _contracts);
 | 
			
		||||
	/// Compiles a contract that uses CALLCODE to call into a pre-deployed version of the given
 | 
			
		||||
	/// contract at runtime, but contains the full creation-time code.
 | 
			
		||||
	void compileClone(
 | 
			
		||||
		ContractDefinition const& _contract,
 | 
			
		||||
		std::map<ContractDefinition const*, bytes const*> const& _contracts
 | 
			
		||||
	);
 | 
			
		||||
	bytes getAssembledBytecode() { return m_context.getAssembledBytecode(); }
 | 
			
		||||
	bytes getRuntimeBytecode() { return m_context.getAssembledRuntimeBytecode(m_runtimeSub); }
 | 
			
		||||
	/// @arg _sourceCodes is the map of input files to source code strings
 | 
			
		||||
@ -68,6 +74,8 @@ private:
 | 
			
		||||
	/// Adds the code that is run at creation time. Should be run after exchanging the run-time context
 | 
			
		||||
	/// with a new and initialized context. Adds the constructor code.
 | 
			
		||||
	void packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext);
 | 
			
		||||
	/// Appends state variable initialisation and constructor code.
 | 
			
		||||
	void appendInitAndConstructorCode(ContractDefinition const& _contract);
 | 
			
		||||
	void appendBaseConstructor(FunctionDefinition const& _constructor);
 | 
			
		||||
	void appendConstructor(FunctionDefinition const& _constructor);
 | 
			
		||||
	void appendFunctionSelector(ContractDefinition const& _contract);
 | 
			
		||||
@ -103,6 +111,9 @@ private:
 | 
			
		||||
	virtual bool visit(ExpressionStatement const& _expressionStatement) override;
 | 
			
		||||
	virtual bool visit(PlaceholderStatement const&) override;
 | 
			
		||||
 | 
			
		||||
	/// Repeatedly visits all function which are referenced but which are not compiled yet.
 | 
			
		||||
	void appendFunctionsWithoutCode();
 | 
			
		||||
 | 
			
		||||
	/// Appends one layer of function modifier code of the current function, or the function
 | 
			
		||||
	/// body itself if the last modifier was reached.
 | 
			
		||||
	void appendModifierOrFunctionCode();
 | 
			
		||||
@ -110,6 +121,9 @@ private:
 | 
			
		||||
	void appendStackVariableInitialisation(VariableDeclaration const& _variable);
 | 
			
		||||
	void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
 | 
			
		||||
 | 
			
		||||
	/// @returns the runtime assembly for clone contracts.
 | 
			
		||||
	static eth::Assembly getCloneRuntime();
 | 
			
		||||
 | 
			
		||||
	bool const m_optimize;
 | 
			
		||||
	unsigned const m_optimizeRuns;
 | 
			
		||||
	CompilerContext m_context;
 | 
			
		||||
 | 
			
		||||
@ -166,7 +166,13 @@ void CompilerStack::compile(bool _optimize, unsigned _runs)
 | 
			
		||||
				compiledContract.bytecode = compiler->getAssembledBytecode();
 | 
			
		||||
				compiledContract.runtimeBytecode = compiler->getRuntimeBytecode();
 | 
			
		||||
				compiledContract.compiler = move(compiler);
 | 
			
		||||
				compiler = make_shared<Compiler>(_optimize, _runs);
 | 
			
		||||
				compiler->compileContract(*contract, contractBytecode);
 | 
			
		||||
				contractBytecode[compiledContract.contract] = &compiledContract.bytecode;
 | 
			
		||||
 | 
			
		||||
				Compiler cloneCompiler(_optimize, _runs);
 | 
			
		||||
				cloneCompiler.compileClone(*contract, contractBytecode);
 | 
			
		||||
				compiledContract.cloneBytecode = cloneCompiler.getAssembledBytecode();
 | 
			
		||||
			}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -199,6 +205,11 @@ bytes const& CompilerStack::getRuntimeBytecode(string const& _contractName) cons
 | 
			
		||||
	return getContract(_contractName).runtimeBytecode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bytes const& CompilerStack::getCloneBytecode(string const& _contractName) const
 | 
			
		||||
{
 | 
			
		||||
	return getContract(_contractName).cloneBytecode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const
 | 
			
		||||
{
 | 
			
		||||
	return dev::sha3(getRuntimeBytecode(_contractName));
 | 
			
		||||
 | 
			
		||||
@ -99,6 +99,11 @@ public:
 | 
			
		||||
	bytes const& getBytecode(std::string const& _contractName = "") const;
 | 
			
		||||
	/// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor.
 | 
			
		||||
	bytes const& getRuntimeBytecode(std::string const& _contractName = "") const;
 | 
			
		||||
	/// @returns the bytecode of a contract that uses an already deployed contract via CALLCODE.
 | 
			
		||||
	/// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to
 | 
			
		||||
	/// substituted by the actual address. Note that this sequence starts end ends in three X
 | 
			
		||||
	/// characters but can contain anything in between.
 | 
			
		||||
	bytes const& getCloneBytecode(std::string const& _contractName = "") const;
 | 
			
		||||
	/// @returns normal contract assembly items
 | 
			
		||||
	eth::AssemblyItems const* getAssemblyItems(std::string const& _contractName = "") const;
 | 
			
		||||
	/// @returns runtime contract assembly items
 | 
			
		||||
@ -167,6 +172,7 @@ private:
 | 
			
		||||
		std::shared_ptr<Compiler> compiler;
 | 
			
		||||
		bytes bytecode;
 | 
			
		||||
		bytes runtimeBytecode;
 | 
			
		||||
		bytes cloneBytecode;
 | 
			
		||||
		std::shared_ptr<InterfaceHandler> interfaceHandler;
 | 
			
		||||
		mutable std::unique_ptr<std::string const> interface;
 | 
			
		||||
		mutable std::unique_ptr<std::string const> solidityInterface;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user