Browse Source

Actual contract creator and add solidity to AlethZero interface.

cl-refactor
Christian 10 years ago
parent
commit
adcf062367
  1. 2
      alethzero/CMakeLists.txt
  2. 17
      alethzero/MainWin.cpp
  3. 13
      libsolidity/Compiler.cpp
  4. 2
      libsolidity/Compiler.h
  5. 4
      libsolidity/CompilerContext.h
  6. 49
      libsolidity/CompilerStack.cpp
  7. 43
      libsolidity/CompilerStack.h
  8. 5
      libsolidity/Scanner.cpp
  9. 3
      libsolidity/Scanner.h
  10. 35
      test/solidityCompiler.cpp

2
alethzero/CMakeLists.txt

@ -53,7 +53,7 @@ else ()
endif () endif ()
qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets)
target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore) target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmface devcore)
if (APPLE) if (APPLE)
# First have qt5 install plugins and frameworks # First have qt5 install plugins and frameworks

17
alethzero/MainWin.cpp

@ -35,6 +35,9 @@
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <liblll/CodeFragment.h> #include <liblll/CodeFragment.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libethereum/BlockChain.h> #include <libethereum/BlockChain.h>
#include <libethereum/ExtVM.h> #include <libethereum/ExtVM.h>
@ -1560,6 +1563,20 @@ void Main::on_data_textChanged()
{ {
m_data = fromHex(src); m_data = fromHex(src);
} }
else if (src.substr(0, 8) == "contract") // improve this heuristic
{
shared_ptr<solidity::Scanner> scanner = make_shared<solidity::Scanner>();
try
{
m_data = dev::solidity::CompilerStack::compile(src, scanner);
}
catch (dev::Exception const& exception)
{
ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", *scanner);
errors.push_back(error.str());
}
}
else else
{ {
m_data = dev::eth::compileLLL(src, m_enableOptimizer, &errors); m_data = dev::eth::compileLLL(src, m_enableOptimizer, &errors);

13
libsolidity/Compiler.cpp

@ -46,9 +46,22 @@ void Compiler::compileContract(ContractDefinition& _contract)
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
m_context.addFunction(*function); m_context.addFunction(*function);
appendFunctionSelector(_contract.getDefinedFunctions()); appendFunctionSelector(_contract.getDefinedFunctions());
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
function->accept(*this); function->accept(*this);
packIntoContractCreator();
}
void Compiler::packIntoContractCreator()
{
CompilerContext creatorContext;
eth::AssemblyItem sub = creatorContext.addSubroutine(m_context.getAssembly());
// stack contains sub size
creatorContext << eth::Instruction::DUP1 << sub << u256(0) << eth::Instruction::CODECOPY;
creatorContext << u256(0) << eth::Instruction::RETURN;
swap(m_context, creatorContext);
} }
void Compiler::appendFunctionSelector(vector<ASTPointer<FunctionDefinition>> const& _functions) void Compiler::appendFunctionSelector(vector<ASTPointer<FunctionDefinition>> const& _functions)

2
libsolidity/Compiler.h

@ -40,6 +40,8 @@ public:
static bytes compile(ContractDefinition& _contract); static bytes compile(ContractDefinition& _contract);
private: private:
/// Creates a new compiler context / assembly and packs the current code into the data part.
void packIntoContractCreator();
void appendFunctionSelector(std::vector<ASTPointer<FunctionDefinition> > const& _functions); void appendFunctionSelector(std::vector<ASTPointer<FunctionDefinition> > const& _functions);
void appendFunctionCallSection(FunctionDefinition const& _function); void appendFunctionCallSection(FunctionDefinition const& _function);
void appendCalldataUnpacker(FunctionDefinition const& _function); void appendCalldataUnpacker(FunctionDefinition const& _function);

4
libsolidity/CompilerContext.h

@ -63,6 +63,9 @@ public:
eth::AssemblyItem pushNewTag() { return m_asm.append(m_asm.newPushTag()).tag(); } eth::AssemblyItem pushNewTag() { return m_asm.append(m_asm.newPushTag()).tag(); }
/// @returns a new tag without pushing any opcodes or data /// @returns a new tag without pushing any opcodes or data
eth::AssemblyItem newTag() { return m_asm.newTag(); } eth::AssemblyItem newTag() { return m_asm.newTag(); }
/// Adds a subroutine to the code (in the data section) and pushes its size (via a tag)
/// on the stack. @returns the assembly item corresponding to the pushed subroutine, i.e. its offset.
eth::AssemblyItem addSubroutine(eth::Assembly const& _assembly) { return m_asm.appendSubSize(_assembly); }
/// Append elements to the current instruction list and adjust @a m_stackOffset. /// Append elements to the current instruction list and adjust @a m_stackOffset.
CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; } CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; }
@ -70,6 +73,7 @@ public:
CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; } CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; }
CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; } CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; }
eth::Assembly const& getAssembly() const { return m_asm; }
void streamAssembly(std::ostream& _stream) const { _stream << m_asm; } void streamAssembly(std::ostream& _stream) const { _stream << m_asm; }
bytes getAssembledBytecode() const { return m_asm.assemble(); } bytes getAssembledBytecode() const { return m_asm.assemble(); }
private: private:

49
libsolidity/CompilerStack.cpp

@ -0,0 +1,49 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Full-stack compiler that converts a source code string to bytecode.
*/
#include <libsolidity/AST.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/CompilerStack.h>
using namespace std;
namespace dev
{
namespace solidity
{
bytes CompilerStack::compile(std::string const& _sourceCode, shared_ptr<Scanner> _scanner)
{
if (!_scanner)
_scanner = make_shared<Scanner>();
_scanner->reset(CharStream(_sourceCode));
ASTPointer<ContractDefinition> contract = Parser().parse(_scanner);
NameAndTypeResolver().resolveNamesAndTypes(*contract);
return Compiler::compile(*contract);
}
}
}

43
libsolidity/CompilerStack.h

@ -0,0 +1,43 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Full-stack compiler that converts a source code string to bytecode.
*/
#pragma once
#include <string>
#include <memory>
#include <libdevcore/Common.h>
namespace dev {
namespace solidity {
class Scanner; // forward
class CompilerStack
{
public:
/// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for
/// scanning the source code - this is useful for printing exception information.
static bytes compile(std::string const& _sourceCode, std::shared_ptr<Scanner> _scanner = std::shared_ptr<Scanner>());
};
}
}

5
libsolidity/Scanner.cpp

@ -103,11 +103,6 @@ int HexValue(char c)
} }
} // end anonymous namespace } // end anonymous namespace
Scanner::Scanner(CharStream const& _source)
{
reset(_source);
}
void Scanner::reset(CharStream const& _source) void Scanner::reset(CharStream const& _source)
{ {
m_source = _source; m_source = _source;

3
libsolidity/Scanner.h

@ -110,7 +110,8 @@ public:
bool complete_; bool complete_;
}; };
explicit Scanner(CharStream const& _source); Scanner() { reset(CharStream()); }
explicit Scanner(CharStream const& _source) { reset(_source); }
/// Resets the scanner as if newly constructed with _input as input. /// Resets the scanner as if newly constructed with _input as input.
void reset(CharStream const& _source); void reset(CharStream const& _source);

35
test/solidityCompiler.cpp

@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned boilerplateSize = 39; unsigned boilerplateSize = 51;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x0, // initialize local variable x
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2,
@ -101,13 +101,14 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned boilerplateSize = 76; unsigned shift = 76;
unsigned boilerplateSize = 88;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, // initialize return variable d byte(Instruction::PUSH1), 0x0, // initialize return variable d
byte(Instruction::DUP3), byte(Instruction::DUP3),
byte(Instruction::SWAP1), // assign b to d byte(Instruction::SWAP1), // assign b to d
byte(Instruction::POP), byte(Instruction::POP),
byte(Instruction::PUSH1), 0xa + boilerplateSize, // jump to return byte(Instruction::PUSH1), 0xa + shift, // jump to return
byte(Instruction::JUMP), byte(Instruction::JUMP),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(Instruction::SWAP4), // store d and fetch return address byte(Instruction::SWAP4), // store d and fetch return address
@ -119,11 +120,11 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers)
byte(Instruction::JUMPDEST), // beginning of g byte(Instruction::JUMPDEST), // beginning of g
byte(Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), // initialized e and h byte(Instruction::DUP1), // initialized e and h
byte(Instruction::PUSH1), 0x20 + boilerplateSize, // ret address byte(Instruction::PUSH1), 0x20 + shift, // ret address
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2,
byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0x3,
byte(Instruction::PUSH1), 0x1 + boilerplateSize, byte(Instruction::PUSH1), 0x1 + shift,
// stack here: ret e h 0x20 1 2 3 0x1 // stack here: ret e h 0x20 1 2 3 0x1
byte(Instruction::JUMP), byte(Instruction::JUMP),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
@ -153,28 +154,29 @@ BOOST_AUTO_TEST_CASE(ifStatement)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned boilerplateSize = 39; unsigned shift = 39;
unsigned boilerplateSize = 51;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), byte(Instruction::DUP1),
byte(Instruction::PUSH1), 0x1b + boilerplateSize, // "true" target byte(Instruction::PUSH1), 0x1b + shift, // "true" target
byte(Instruction::JUMPI), byte(Instruction::JUMPI),
// new check "else if" condition // new check "else if" condition
byte(Instruction::DUP1), byte(Instruction::DUP1),
byte(Instruction::NOT), byte(Instruction::NOT),
byte(Instruction::PUSH1), 0x13 + boilerplateSize, byte(Instruction::PUSH1), 0x13 + shift,
byte(Instruction::JUMPI), byte(Instruction::JUMPI),
// "else" body // "else" body
byte(Instruction::PUSH1), 0x4f, byte(Instruction::PUSH1), 0x4f,
byte(Instruction::POP), byte(Instruction::POP),
byte(Instruction::PUSH1), 0x17 + boilerplateSize, // exit path of second part byte(Instruction::PUSH1), 0x17 + shift, // exit path of second part
byte(Instruction::JUMP), byte(Instruction::JUMP),
// "else if" body // "else if" body
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x4e, byte(Instruction::PUSH1), 0x4e,
byte(Instruction::POP), byte(Instruction::POP),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x1f + boilerplateSize, byte(Instruction::PUSH1), 0x1f + shift,
byte(Instruction::JUMP), byte(Instruction::JUMP),
// "if" body // "if" body
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
@ -194,28 +196,29 @@ BOOST_AUTO_TEST_CASE(loops)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned boilerplateSize = 39; unsigned shift = 39;
unsigned boilerplateSize = 51;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,
byte(Instruction::NOT), byte(Instruction::NOT),
byte(Instruction::PUSH1), 0x21 + boilerplateSize, byte(Instruction::PUSH1), 0x21 + shift,
byte(Instruction::JUMPI), byte(Instruction::JUMPI),
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,
byte(Instruction::POP), byte(Instruction::POP),
byte(Instruction::PUSH1), 0x21 + boilerplateSize, byte(Instruction::PUSH1), 0x21 + shift,
byte(Instruction::JUMP), // break byte(Instruction::JUMP), // break
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2,
byte(Instruction::POP), byte(Instruction::POP),
byte(Instruction::PUSH1), 0x2 + boilerplateSize, byte(Instruction::PUSH1), 0x2 + shift,
byte(Instruction::JUMP), // continue byte(Instruction::JUMP), // continue
byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0x3,
byte(Instruction::POP), byte(Instruction::POP),
byte(Instruction::PUSH1), 0x22 + boilerplateSize, byte(Instruction::PUSH1), 0x22 + shift,
byte(Instruction::JUMP), // return byte(Instruction::JUMP), // return
byte(Instruction::PUSH1), 0x4, byte(Instruction::PUSH1), 0x4,
byte(Instruction::POP), byte(Instruction::POP),
byte(Instruction::PUSH1), 0x2 + boilerplateSize, byte(Instruction::PUSH1), 0x2 + shift,
byte(Instruction::JUMP), byte(Instruction::JUMP),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),

Loading…
Cancel
Save