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 ()
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)
# First have qt5 install plugins and frameworks

17
alethzero/MainWin.cpp

@ -35,6 +35,9 @@
#include <libdevcrypto/FileSystem.h>
#include <liblll/Compiler.h>
#include <liblll/CodeFragment.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h>
#include <libevm/VM.h>
#include <libethereum/BlockChain.h>
#include <libethereum/ExtVM.h>
@ -1560,6 +1563,20 @@ void Main::on_data_textChanged()
{
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
{
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())
m_context.addFunction(*function);
appendFunctionSelector(_contract.getDefinedFunctions());
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
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)

2
libsolidity/Compiler.h

@ -40,6 +40,8 @@ public:
static bytes compile(ContractDefinition& _contract);
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 appendFunctionCallSection(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(); }
/// @returns a new tag without pushing any opcodes or data
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.
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<<(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; }
bytes getAssembledBytecode() const { return m_asm.assemble(); }
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
Scanner::Scanner(CharStream const& _source)
{
reset(_source);
}
void Scanner::reset(CharStream const& _source)
{
m_source = _source;

3
libsolidity/Scanner.h

@ -110,7 +110,8 @@ public:
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.
void reset(CharStream const& _source);

35
test/solidityCompiler.cpp

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

Loading…
Cancel
Save