Skip to content

Commit

Permalink
Merge pull request #1622 from ethereum/develop
Browse files Browse the repository at this point in the history
Solidity version 0.4.9
  • Loading branch information
chriseth committed Jan 31, 2017
2 parents 60cc166 + 7b18c9d commit 364da42
Show file tree
Hide file tree
Showing 66 changed files with 2,362 additions and 899 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ include(EthPolicy)
eth_policy()

# project name and version should be set after cmake_policy CMP0048
set(PROJECT_VERSION "0.4.8")
set(PROJECT_VERSION "0.4.9")
project(solidity VERSION ${PROJECT_VERSION})

# Let's find our dependencies
Expand Down
21 changes: 21 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
### 0.4.9 (2017-01-31)

Features:
* Compiler interface: Contracts and libraries can be referenced with a ``file:`` prefix to make them unique.
* Compiler interface: Report source location for "stack too deep" errors.
* AST: Use deterministic node identifiers.
* Inline assembly: introduce ``invalid`` (EIP141) as an opcode.
* Type system: Introduce type identifier strings.
* Type checker: Warn about invalid checksum for addresses and deduce type from valid ones.
* Metadata: Do not include platform in the version number.
* Metadata: Add option to store sources as literal content.
* Code generator: Extract array utils into low-level functions.
* Code generator: Internal errors (array out of bounds, etc.) now cause a reversion by using an invalid
instruction (0xfe - EIP141) instead of an invalid jump. Invalid jump is still kept for explicit throws.

Bugfixes:
* Code generator: Allow recursive structs.
* Inline assembly: Disallow variables named like opcodes.
* Type checker: Allow multiple events of the same name (but with different arities or argument types)
* Natspec parser: Fix error with ``@param`` parsing and whitespace.

### 0.4.8 (2017-01-13)

Features:
Expand Down
2 changes: 2 additions & 0 deletions cmake/scripts/buildinfo.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ if (SOL_COMMIT_HASH AND SOL_LOCAL_CHANGES)
set(SOL_COMMIT_HASH "${SOL_COMMIT_HASH}.mod")
endif()

set(SOL_VERSION_COMMIT "commit.${SOL_COMMIT_HASH}")
set(SOl_VERSION_PLATFORM ETH_BUILD_PLATFORM)
set(SOL_VERSION_BUILDINFO "commit.${SOL_COMMIT_HASH}.${ETH_BUILD_PLATFORM}")

set(TMPFILE "${ETH_DST_DIR}/BuildInfo.h.tmp")
Expand Down
2 changes: 2 additions & 0 deletions cmake/templates/BuildInfo.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@
#define ETH_BUILD_PLATFORM "@ETH_BUILD_PLATFORM@"
#define SOL_VERSION_PRERELEASE "@SOL_VERSION_PRERELEASE@"
#define SOL_VERSION_BUILDINFO "@SOL_VERSION_BUILDINFO@"
#define SOL_VERSION_COMMIT "@SOL_VERSION_COMMIT@"
#define SOL_VERSION_PLATFORM "@SOL_VERSION_PLATFORM@"
6 changes: 3 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,16 @@ def setup(sphinx):

# General information about the project.
project = 'Solidity'
copyright = '2016, Ethereum'
copyright = '2016-2017, Ethereum'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.4.8'
version = '0.4.9'
# The full version, including alpha/beta/rc tags.
release = '0.4.8-develop'
release = '0.4.9-develop'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
33 changes: 20 additions & 13 deletions docs/control-structures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ contract can be called internally.
External Function Calls
-----------------------

The expressions ``this.g(8);`` and ``c.g(2);`` (where ``g`` is a contract
The expressions ``this.g(8);`` and ``c.g(2);`` (where ``c`` is a contract
instance) are also valid function calls, but this time, the function
will be called "externally", via a message call and not directly via jumps.
Please note that function calls on ``this`` cannot be used in the constructor, as the
Expand Down Expand Up @@ -384,18 +384,23 @@ In the following example, we show how ``throw`` can be used to easily revert an

Currently, Solidity automatically generates a runtime exception in the following situations:

1. If you access an array at a too large or negative index (i.e. ``x[i]`` where ``i >= x.length`` or ``i < 0``).
1. If you access a fixed-length ``bytesN`` at a too large or negative index.
1. If you call a function via a message call but it does not finish properly (i.e. it runs out of gas, has no matching function, or throws an exception itself), except when a low level operation ``call``, ``send``, ``delegatecall`` or ``callcode`` is used. The low level operations never throw exceptions but indicate failures by returning ``false``.
1. If you create a contract using the ``new`` keyword but the contract creation does not finish properly (see above for the definition of "not finish properly").
1. If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``).
1. If you shift by a negative amount.
1. If you convert a value too big or negative into an enum type.
1. If you perform an external function call targeting a contract that contains no code.
1. If your contract receives Ether via a public function without ``payable`` modifier (including the constructor and the fallback function).
1. If your contract receives Ether via a public accessor function.

Internally, Solidity performs an "invalid jump" when an exception is thrown and thus causes the EVM to revert all changes made to the state. The reason for this is that there is no safe way to continue execution, because an expected effect did not occur. Because we want to retain the atomicity of transactions, the safest thing to do is to revert all changes and make the whole transaction (or at least call) without effect.
#. If you access an array at a too large or negative index (i.e. ``x[i]`` where ``i >= x.length`` or ``i < 0``).
#. If you access a fixed-length ``bytesN`` at a too large or negative index.
#. If you call a function via a message call but it does not finish properly (i.e. it runs out of gas, has no matching function, or throws an exception itself), except when a low level operation ``call``, ``send``, ``delegatecall`` or ``callcode`` is used. The low level operations never throw exceptions but indicate failures by returning ``false``.
#. If you create a contract using the ``new`` keyword but the contract creation does not finish properly (see above for the definition of "not finish properly").
#. If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``).
#. If you shift by a negative amount.
#. If you convert a value too big or negative into an enum type.
#. If you perform an external function call targeting a contract that contains no code.
#. If your contract receives Ether via a public function without ``payable`` modifier (including the constructor and the fallback function).
#. If your contract receives Ether via a public accessor function.
#. If you call a zero-initialized variable of internal function type.

Internally, Solidity performs an "invalid jump" when a user-provided exception is thrown. In contrast, it performs an invalid operation
(instruction ``0xfe``) if a runtime exception is encountered. In both cases, this causes
the EVM to revert all changes made to the state. The reason for this is that there is no safe way to continue execution, because an expected effect
did not occur. Because we want to retain the atomicity of transactions, the safest thing to do is to revert all changes and make the whole transaction
(or at least call) without effect.

.. index:: ! assembly, ! asm, ! evmasm

Expand Down Expand Up @@ -627,6 +632,8 @@ The opcodes ``pushi`` and ``jumpdest`` cannot be used directly.
+-------------------------+------+-----------------------------------------------------------------+
| selfdestruct(a) | `-` | end execution, destroy current contract and send funds to a |
+-------------------------+------+-----------------------------------------------------------------+
| invalid | `-` | end execution with invalid instruction |
+-------------------------+------+-----------------------------------------------------------------+
| log0(p, s) | `-` | log without topics and data mem[p..(p+s)) |
+-------------------------+------+-----------------------------------------------------------------+
| log1(p, s, t1) | `-` | log with topic t1 and data mem[p..(p+s)) |
Expand Down
2 changes: 1 addition & 1 deletion docs/grammar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ NumberUnit = 'wei' | 'szabo' | 'finney' | 'ether'
| 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years'
HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')
StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"'
Identifier = [a-zA-Z_] [a-zA-Z_0-9]*
Identifier = [a-zA-Z_$] [a-zA-Z_$0-9]*

HexNumber = '0x' [0-9a-fA-F]+
DecimalNumber = [0-9]+
Expand Down
23 changes: 23 additions & 0 deletions docs/installing-solidity.rst
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ you should fork Solidity and add your personal fork as a second remote:
cd solidity
git remote add personal [email protected]:[username]/solidity.git
Solidity has git submodules. Ensure they are properly loaded:

.. code:: bash
git submodule update --init --recursive
Prerequisites - macOS
---------------------
Expand Down Expand Up @@ -211,6 +216,24 @@ Alternatively, you can build for Windows on the command-line, like so:
cmake --build . --config RelWithDebInfo
The version string in detail
============================

The Solidity version string contains four parts:
- the version number
- pre-release tag, usually set to ``develop.YYYY.MM.DD`` or ``nightly.YYYY.MM.DD``
- commit in the format of ``commit.GITHASH``
- platform has arbitrary number of items, containing details about the platform and compiler

If there are local modifications, the commit will be postfixed with ``.mod``.

These parts are combined as required by Semver, where the Solidity pre-release tag equals to the Semver pre-release
and the Solidity commit and platform combined make up the Semver build metadata.

A relase example: ``0.4.8+commit.60cc1668.Emscripten.clang``.

A pre-release example: ``0.4.9-nightly.2017.1.17+commit.6ecb4aa3.Emscripten.clang``

Important information about versioning
======================================

Expand Down
13 changes: 13 additions & 0 deletions docs/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,19 @@ Fixed Point Numbers

**COMING SOON...**

.. index:: address, literal;address

.. _address_literals:

Address Literals
----------------

Hexadecimal literals that pass the address checksum test, for example
``0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF`` are of ``address`` type.
Hexadecimal literals that are between 39 and 41 digits
long and do not pass the checksum test produce
a warning and are treated as regular rational number literals.

.. index:: literal, literal;rational

.. _rational_literals:
Expand Down
3 changes: 2 additions & 1 deletion docs/utils/SolidityLexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class SolidityLexer(RegexLexer):
(r'(for|in|while|do|break|return|continue|switch|case|default|if|else|'
r'throw|try|catch|finally|new|delete|typeof|instanceof|void|'
r'this|import|mapping|returns|private|public|external|internal|'
r'constant|memory|storage)\b', Keyword, 'slashstartsregex'),
r'constant|memory|storage|payable)\b', Keyword, 'slashstartsregex'),
(r'(var|let|with|function|event|modifier|struct|enum|contract|library)\b', Keyword.Declaration, 'slashstartsregex'),
(r'(bytes|string|address|uint|int|bool|byte|' +
'|'.join(
Expand All @@ -67,6 +67,7 @@ class SolidityLexer(RegexLexer):
['ufixed%dx%d' % ((i), (j + 8)) for i in range(0, 256, 8) for j in range(0, 256 - i, 8)] +
['fixed%dx%d' % ((i), (j + 8)) for i in range(0, 256, 8) for j in range(0, 256 - i, 8)]
) + r')\b', Keyword.Type, 'slashstartsregex'),
(r'(wei|szabo|finney|ether|seconds|minutes|hours|days|weeks|years)\b', Keyword.Type, 'slashstartsregex'),
(r'(abstract|boolean|byte|char|class|const|debugger|double|enum|export|'
r'extends|final|float|goto|implements|int|interface|long|native|'
r'package|private|protected|public|short|static|super|synchronized|throws|'
Expand Down
40 changes: 38 additions & 2 deletions libdevcore/CommonData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@
* @date 2014
*/

#include "CommonData.h"
#include "Exceptions.h"
#include <libdevcore/CommonData.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/SHA3.h>

#include <boost/algorithm/string.hpp>

using namespace std;
using namespace dev;

Expand Down Expand Up @@ -95,3 +99,35 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw)
}
return ret;
}


bool dev::passesAddressChecksum(string const& _str, bool _strict)
{
string s = _str.substr(0, 2) == "0x" ? _str.substr(2) : _str;

if (s.length() != 40)
return false;

if (!_strict && (
_str.find_first_of("abcdef") == string::npos ||
_str.find_first_of("ABCDEF") == string::npos
))
return true;

h256 hash = keccak256(boost::algorithm::to_lower_copy(s, std::locale::classic()));
for (size_t i = 0; i < 40; ++i)
{
char addressCharacter = s[i];
bool lowerCase;
if ('a' <= addressCharacter && addressCharacter <= 'f')
lowerCase = true;
else if ('A' <= addressCharacter && addressCharacter <= 'F')
lowerCase = false;
else
continue;
unsigned nibble = (unsigned(hash[i / 2]) >> (4 * (1 - (i % 2)))) & 0xf;
if ((nibble >= 8) == lowerCase)
return false;
}
return true;
}
5 changes: 5 additions & 0 deletions libdevcore/CommonData.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,9 @@ bool contains(T const& _t, V const& _v)
return std::end(_t) != std::find(std::begin(_t), std::end(_t), _v);
}

/// @returns true iff @a _str passess the hex address checksum test.
/// @param _strict if false, hex strings with only uppercase or only lowercase letters
/// are considered valid.
bool passesAddressChecksum(std::string const& _str, bool _strict);

}
96 changes: 82 additions & 14 deletions libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ void Assembly::append(Assembly const& _a)
auto newDeposit = m_deposit + _a.deposit();
for (AssemblyItem i: _a.m_items)
{
if (i.type() == Tag || i.type() == PushTag)
if (i.type() == Tag || (i.type() == PushTag && i != errorTag()))
i.setData(i.data() + m_usedTags);
else if (i.type() == PushSub || i.type() == PushSubSize)
i.setData(i.data() + m_subs.size());
Expand Down Expand Up @@ -94,7 +94,10 @@ unsigned Assembly::bytesRequired(unsigned subTagSize) const
}
}

string Assembly::locationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const
namespace
{

string locationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location)
{
if (_location.isEmpty() || _sourceCodes.empty() || _location.start >= _location.end || _location.start < 0)
return "";
Expand All @@ -115,27 +118,92 @@ string Assembly::locationFromSources(StringMap const& _sourceCodes, SourceLocati
return cut;
}

ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
class Functionalizer
{
for (size_t i = 0; i < m_items.size(); ++i)
public:
Functionalizer (ostream& _out, string const& _prefix, StringMap const& _sourceCodes):
m_out(_out), m_prefix(_prefix), m_sourceCodes(_sourceCodes)
{}

void feed(AssemblyItem const& _item)
{
AssemblyItem const& item = m_items[i];
if (!item.location().isEmpty() && (i == 0 || m_items[i - 1].location() != item.location()))
if (!_item.location().isEmpty() && _item.location() != m_location)
{
_out << _prefix << " /*";
if (item.location().sourceName)
_out << " \"" + *item.location().sourceName + "\"";
if (!item.location().isEmpty())
_out << ":" << to_string(item.location().start) + ":" + to_string(item.location().end);
_out << " */" << endl;
flush();
printLocation();
m_location = _item.location();
}
_out << _prefix << (item.type() == Tag ? "" : " ") << item.toAssemblyText() << endl;
if (!(
_item.canBeFunctional() &&
_item.returnValues() <= 1 &&
_item.arguments() <= int(m_pending.size())
))
{
flush();
m_out << m_prefix << (_item.type() == Tag ? "" : " ") << _item.toAssemblyText() << endl;
return;
}
string expression = _item.toAssemblyText();
if (_item.arguments() > 0)
{
expression += "(";
for (int i = 0; i < _item.arguments(); ++i)
{
expression += m_pending.back();
m_pending.pop_back();
if (i + 1 < _item.arguments())
expression += ", ";
}
expression += ")";
}

m_pending.push_back(expression);
if (_item.returnValues() != 1)
flush();
}

void flush()
{
for (string const& expression: m_pending)
m_out << m_prefix << " " << expression << endl;
m_pending.clear();
}

void printLocation()
{
if (!m_location.sourceName && m_location.isEmpty())
return;
m_out << m_prefix << " /*";
if (m_location.sourceName)
m_out << " \"" + *m_location.sourceName + "\"";
if (!m_location.isEmpty())
m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end);
m_out << " " << locationFromSources(m_sourceCodes, m_location);
m_out << " */" << endl;
}

private:
strings m_pending;
SourceLocation m_location;

ostream& m_out;
string const& m_prefix;
StringMap const& m_sourceCodes;
};

}

ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
{
Functionalizer f(_out, _prefix, _sourceCodes);

for (auto const& i: m_items)
f.feed(i);
f.flush();

if (!m_data.empty() || !m_subs.empty())
{
_out << _prefix << "stop" << endl;
Json::Value data;
for (auto const& i: m_data)
assertThrow(u256(i.first) < m_subs.size(), AssemblyException, "Data not yet implemented.");

Expand Down
Loading

0 comments on commit 364da42

Please sign in to comment.