Merge remote-tracking branch 'origin/develop' into release

This commit is contained in:
chriseth 2016-10-25 15:31:36 +02:00
commit 2353da71c7
69 changed files with 1204 additions and 876 deletions

View File

@ -84,10 +84,11 @@ matrix:
# OS X Mavericks (10.9) # OS X Mavericks (10.9)
# https://en.wikipedia.org/wiki/OS_X_Mavericks # https://en.wikipedia.org/wiki/OS_X_Mavericks
# #
- os: osx # Disabled because of problems on travis.
osx_image: beta-xcode6.2 # - os: osx
env: # osx_image: beta-xcode6.2
- ZIP_SUFFIX=osx-mavericks # env:
# - ZIP_SUFFIX=osx-mavericks
# OS X Yosemite (10.10) # OS X Yosemite (10.10)
# https://en.wikipedia.org/wiki/OS_X_Yosemite # https://en.wikipedia.org/wiki/OS_X_Yosemite
@ -186,7 +187,9 @@ deploy:
script: test $TRAVIS_EMSCRIPTEN != On || scripts/release_emscripten.sh script: test $TRAVIS_EMSCRIPTEN != On || scripts/release_emscripten.sh
skip_cleanup: true skip_cleanup: true
on: on:
branch: develop branch:
- develop
- release
# This is the deploy target for the native build (Linux and macOS) # This is the deploy target for the native build (Linux and macOS)
# which generates ZIPs per commit. We are in agreement that # which generates ZIPs per commit. We are in agreement that

View File

@ -8,7 +8,7 @@ include(EthPolicy)
eth_policy() eth_policy()
# project name and version should be set after cmake_policy CMP0048 # project name and version should be set after cmake_policy CMP0048
set(PROJECT_VERSION "0.4.2") set(PROJECT_VERSION "0.4.3")
project(solidity VERSION ${PROJECT_VERSION}) project(solidity VERSION ${PROJECT_VERSION})
# Let's find our dependencies # Let's find our dependencies

View File

@ -1,3 +1,30 @@
### 0.4.3 (2016-10-25)
Features:
* Inline assembly: support both ``suicide`` and ``selfdestruct`` opcodes
(note: ``suicide`` is deprecated).
* Inline assembly: issue warning if stack is not balanced after block.
* Include ``keccak256()`` as an alias to ``sha3()``.
* Support shifting constant numbers.
Bugfixes:
* Commandline interface: Disallow unknown options in ``solc``.
* Name resolver: Allow inheritance of ``enum`` definitions.
* Type checker: Proper type checking for bound functions.
* Type checker: fixed crash related to invalid fixed point constants
* Type checker: fixed crash related to invalid literal numbers.
* Type checker: ``super.x`` does not look up ``x`` in the current contract.
* Code generator: expect zero stack increase after ``super`` as an expression.
* Code generator: fix an internal compiler error for ``L.Foo`` for ``enum Foo`` defined in library ``L``.
* Code generator: allow inheritance of ``enum`` definitions.
* Inline assembly: support the ``address`` opcode.
* Inline assembly: fix parsing of assignment after a label.
* Inline assembly: external variables of unsupported type (such as ``this``, ``super``, etc.)
are properly detected as unusable.
* Inline assembly: support variables within modifiers.
* Optimizer: fix related to stale knowledge about SHA3 operations
### 0.4.2 (2016-09-17) ### 0.4.2 (2016-09-17)
Bugfixes: Bugfixes:

View File

@ -27,6 +27,10 @@
# (c) 2016 cpp-ethereum contributors. # (c) 2016 cpp-ethereum contributors.
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
branches:
only:
- master
- develop
os: Visual Studio 2015 os: Visual Studio 2015
configuration: configuration:
- RelWithDebInfo - RelWithDebInfo

View File

@ -56,9 +56,9 @@ copyright = '2016, Ethereum'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.4.1' version = '0.4.3'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.4.1-develop' release = '0.4.3-develop'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -20,6 +20,9 @@ Contracts can be created "from outside" or from Solidity contracts.
When a contract is created, its constructor (a function with the same When a contract is created, its constructor (a function with the same
name as the contract) is executed once. name as the contract) is executed once.
A constructor is optional. Only one constructor is allowed and this means
overloading is not supported.
From ``web3.js``, i.e. the JavaScript From ``web3.js``, i.e. the JavaScript
API, this is done as follows:: API, this is done as follows::
@ -136,7 +139,7 @@ This means that cyclic creation dependencies are impossible.
) returns (bool ok) { ) returns (bool ok) {
// Check some arbitrary condition. // Check some arbitrary condition.
address tokenAddress = msg.sender; address tokenAddress = msg.sender;
return (sha3(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff); return (keccak256(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff);
} }
} }
@ -421,9 +424,9 @@ change by overriding).
.. index:: ! constant .. index:: ! constant
********** ************************
Constants Constant State Variables
********** ************************
State variables can be declared as constant (this is not yet implemented State variables can be declared as constant (this is not yet implemented
for array and struct types and not possible for mapping types). for array and struct types and not possible for mapping types).
@ -442,6 +445,27 @@ for these variables and every occurrence is replaced by their constant value.
The value expression can only contain integer arithmetics. The value expression can only contain integer arithmetics.
******************
Constant Functions
******************
Functions can be declared constant. These functions promise not to modify the state.
::
pragma solidity ^0.4.0;
contract C {
function f(uint a, uint b) constant returns (uint) {
return a * (b + 42);
}
}
.. note::
Accessor methods are marked constant.
.. warning::
The compiler does not enforce yet that a constant method is not modifying state.
.. index:: ! fallback function, function;fallback .. index:: ! fallback function, function;fallback
@ -544,7 +568,7 @@ to be searched for: It is possible to filter for specific values of
indexed arguments in the user interface. indexed arguments in the user interface.
If arrays (including ``string`` and ``bytes``) are used as indexed arguments, the If arrays (including ``string`` and ``bytes``) are used as indexed arguments, the
sha3-hash of it is stored as topic instead. Keccak-256 hash of it is stored as topic instead.
The hash of the signature of the event is one of the topics except if you The hash of the signature of the event is one of the topics except if you
declared the event with ``anonymous`` specifier. This means that it is declared the event with ``anonymous`` specifier. This means that it is
@ -622,7 +646,7 @@ as topics. The event call above can be performed in the same way as
); );
where the long hexadecimal number is equal to where the long hexadecimal number is equal to
``sha3("Deposit(address,hash256,uint256)")``, the signature of the event. ``keccak256("Deposit(address,hash256,uint256)")``, the signature of the event.
Additional Resources for Understanding Events Additional Resources for Understanding Events
============================================== ==============================================
@ -976,7 +1000,7 @@ are all compiled as calls (``DELEGATECALL``) to an external
contract/library. If you use libraries, take care that an contract/library. If you use libraries, take care that an
actual external function call is performed. actual external function call is performed.
``msg.sender``, ``msg.value`` and ``this`` will retain their values ``msg.sender``, ``msg.value`` and ``this`` will retain their values
in this call, though (prior to Homestead, ``msg.sender`` and in this call, though (prior to Homestead, because of the use of `CALLCODE`, ``msg.sender`` and
``msg.value`` changed, though). ``msg.value`` changed, though).
The following example shows how to use memory types and The following example shows how to use memory types and

View File

@ -15,7 +15,9 @@ In particular, we need help in the following areas:
<http://ethereum.stackexchange.com/>`_ and the `Solidity Gitter <http://ethereum.stackexchange.com/>`_ and the `Solidity Gitter
<https://gitter.im/ethereum/solidity>`_ <https://gitter.im/ethereum/solidity>`_
* Fixing and responding to `Solidity's GitHub issues * Fixing and responding to `Solidity's GitHub issues
<https://github.com/ethereum/solidity/issues>`_ <https://github.com/ethereum/solidity/issues>`_, especially those tagged as
`up-for-grabs <https://github.com/ethereum/solidity/issues?q=is%3Aopen+is%3Aissue+label%3Aup-for-grabs>`_ which are
meant as introductory issues for external contributors.
How to Report Issues How to Report Issues
==================== ====================

View File

@ -7,7 +7,7 @@ Expressions and Control Structures
Control Structures Control Structures
=================== ===================
Most of the control structures from C/JavaScript are available in Solidity Most of the control structures from C or JavaScript are available in Solidity
except for ``switch`` and ``goto``. So except for ``switch`` and ``goto``. So
there is: ``if``, ``else``, ``while``, ``for``, ``break``, ``continue``, ``return``, ``? :``, with there is: ``if``, ``else``, ``while``, ``for``, ``break``, ``continue``, ``return``, ``? :``, with
the usual semantics known from C or JavaScript. the usual semantics known from C or JavaScript.
@ -322,14 +322,16 @@ In the following example, we show how ``throw`` can be used to easily revert an
} }
} }
Currently, there are six situations, where exceptions happen automatically in Solidity: Currently, there are situations, where exceptions happen automatically in Solidity:
1. If you access an array beyond its length (i.e. ``x[i]`` where ``i >= x.length``). 1. If you access an array at a too large or negative index (i.e. ``x[i]`` where ``i >= x.length`` or ``i < 0``).
2. If a function called via a message call does not finish properly (i.e. it runs out of gas or throws an exception itself). 2. If you access a fixed-length ``bytesN`` at a too large or negative index.
3. If a non-existent function on a library is called or Ether is sent to a library. 3. 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``.
4. If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``). 4. 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").
5. If you perform an external function call targeting a contract that contains no code. 5. If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``).
6. If a contract-creation call using the ``new`` keyword fails. 6. If you perform an external function call targeting a contract that contains no code.
7. If your contract receives Ether via a public function without ``payable`` modifier (including the constructor and the fallback function).
8. 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. 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.
@ -503,7 +505,7 @@ The opcodes ``pushi`` and ``jumpdest`` cannot be used directly.
+-------------------------+------+-----------------------------------------------------------------+ +-------------------------+------+-----------------------------------------------------------------+
| pc | | current position in code | | pc | | current position in code |
+-------------------------+------+-----------------------------------------------------------------+ +-------------------------+------+-----------------------------------------------------------------+
| pop | `*` | remove topmost stack slot | | pop(x) | `-` | remove the element pushed by x |
+-------------------------+------+-----------------------------------------------------------------+ +-------------------------+------+-----------------------------------------------------------------+
| dup1 ... dup16 | | copy ith stack slot to the top (counting from top) | | dup1 ... dup16 | | copy ith stack slot to the top (counting from top) |
+-------------------------+------+-----------------------------------------------------------------+ +-------------------------+------+-----------------------------------------------------------------+
@ -559,9 +561,9 @@ The opcodes ``pushi`` and ``jumpdest`` cannot be used directly.
| delegatecall(g, a, in, | | identical to `callcode` but also keep ``caller`` | | delegatecall(g, a, in, | | identical to `callcode` but also keep ``caller`` |
| insize, out, outsize) | | and ``callvalue`` | | insize, out, outsize) | | and ``callvalue`` |
+-------------------------+------+-----------------------------------------------------------------+ +-------------------------+------+-----------------------------------------------------------------+
| return(p, s) | `*` | end execution, return data mem[p..(p+s)) | | return(p, s) | `-` | end execution, return data mem[p..(p+s)) |
+-------------------------+------+-----------------------------------------------------------------+ +-------------------------+------+-----------------------------------------------------------------+
| selfdestruct(a) | `*` | end execution, destroy current contract and send funds to a | | selfdestruct(a) | `-` | end execution, destroy current contract and send funds to a |
+-------------------------+------+-----------------------------------------------------------------+ +-------------------------+------+-----------------------------------------------------------------+
| log0(p, s) | `-` | log without topics and data mem[p..(p+s)) | | log0(p, s) | `-` | log without topics and data mem[p..(p+s)) |
+-------------------------+------+-----------------------------------------------------------------+ +-------------------------+------+-----------------------------------------------------------------+
@ -783,7 +785,7 @@ Conventions in Solidity
In contrast to EVM assembly, Solidity knows types which are narrower than 256 bits, In contrast to EVM assembly, Solidity knows types which are narrower than 256 bits,
e.g. ``uint24``. In order to make them more efficient, most arithmetic operations just e.g. ``uint24``. In order to make them more efficient, most arithmetic operations just
treat them as 256 bit numbers and the higher-order bits are only cleaned at the treat them as 256-bit numbers and the higher-order bits are only cleaned at the
point where it is necessary, i.e. just shortly before they are written to memory point where it is necessary, i.e. just shortly before they are written to memory
or before comparisons are performed. This means that if you access such a variable or before comparisons are performed. This means that if you access such a variable
from within inline assembly, you might have to manually clean the higher order bits from within inline assembly, you might have to manually clean the higher order bits

View File

@ -9,33 +9,12 @@ This list was originally compiled by `fivedogit <mailto:fivedogit@gmail.com>`_.
Basic Questions Basic Questions
*************** ***************
What is Solidity? Example contracts
================= =================
Solidity is the DEV-created (i.e. Ethereum Foundation-created),
Javascript-inspired language that can be used to create smart contracts
on the Ethereum blockchain. There are other
languages you can use as well (LLL, Serpent, etc). The main points in
favour of Solidity is that it is statically typed and offers many
advanced features like inheritance, libraries, complex
user-defined types and a bytecode optimizer.
Solidity contracts can be compiled a few different ways (see below) and the
resulting output can be cut/pasted into a geth console to deploy them to the
Ethereum blockchain.
There are some `contract examples <https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts/>`_ by fivedogit and There are some `contract examples <https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts/>`_ by fivedogit and
there should be a `test contract <https://github.com/ethereum/solidity/blob/develop/test/libsolidity/SolidityEndToEndTest.cpp>`_ for every single feature of Solidity. there should be a `test contract <https://github.com/ethereum/solidity/blob/develop/test/libsolidity/SolidityEndToEndTest.cpp>`_ for every single feature of Solidity.
How do I compile contracts?
===========================
Probably the fastest way is the `online compiler <https://ethereum.github.io/browser-solidity/>`_.
You can also use the ``solc`` binary which comes with cpp-ethereum to compile
contracts or an emerging option is to use Mix, the IDE.
Create and publish the most basic contract possible Create and publish the most basic contract possible
=================================================== ===================================================
@ -71,13 +50,6 @@ several blockchain explorers.
Contracts on the blockchain should have their original source Contracts on the blockchain should have their original source
code published if they are to be used by third parties. code published if they are to be used by third parties.
Does ``selfdestruct()`` free up space in the blockchain?
========================================================
It removes the contract bytecode and storage from the current block
into the future, but since the blockchain stores every single block (i.e.
all history), this will not actually free up space on full/archive nodes.
Create a contract that can be killed and return funds Create a contract that can be killed and return funds
===================================================== =====================================================
@ -113,32 +85,6 @@ Use a non-constant function (req ``sendTransaction``) to increment a variable in
See `value_incrementer.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/20_value_incrementer.sol>`_. See `value_incrementer.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/20_value_incrementer.sol>`_.
Get contract address in Solidity
================================
Short answer: The global variable ``this`` is the contract address.
See `basic_info_getter <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/15_basic_info_getter.sol>`_.
Long answer: ``this`` is a variable representing the current contract.
Its type is the type of the contract. Since any contract type basically inherits from the
``address`` type, ``this`` is always convertible to ``address`` and in this case contains
its own address.
What is the difference between a function marked ``constant`` and one that is not?
==================================================================================
``constant`` functions can perform some action and return a value, but cannot
change state (this is not yet enforced by the compiler). In other words, a
constant function cannot save or update any variables within the contract or wider
blockchain. These functions are called using ``c.someFunction(...)`` from
geth or any other web3.js environment.
"non-constant" functions (those lacking the ``constant`` specifier) must be called
with ``c.someMethod.sendTransaction({from:eth.accounts[x], gas: 1000000});``
That is, because they can change state, they have to have a gas
payment sent along to get the work done.
Get a contract to return its funds to you (not using ``selfdestruct(...)``). Get a contract to return its funds to you (not using ``selfdestruct(...)``).
============================================================================ ============================================================================
@ -146,52 +92,6 @@ This example demonstrates how to send funds from a contract to an address.
See `endowment_retriever <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/30_endowment_retriever.sol>`_. See `endowment_retriever <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/30_endowment_retriever.sol>`_.
What is a ``mapping`` and how do we use them?
=============================================
A mapping is very similar to a K->V hashmap.
If you have a state variable of type ``mapping (string -> uint) x;``, then you can
access the value by ``x["somekeystring"]``.
How can I get the length of a ``mapping``?
==========================================
Mappings are a rather low-level data structure. It does not store the keys
and it is not possible to know which or how many values are "set". Actually,
all values to all possible keys are set by default, they are just
initialised with the zero value.
In this sense, the attribute ``length`` for a mapping does not really apply.
If you want to have a "sized mapping", you can use the iterable mapping
(see below) or just a dynamically-sized array of structs.
Are ``mapping``'s iterable?
===========================
Mappings themselves are not iterable, but you can use a higher-level
datastructure on top of it, for example the `iterable mapping <https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol>`_.
Can I put arrays inside of a ``mapping``? How do I make a ``mapping`` of a ``mapping``?
=======================================================================================
Mappings are already syntactically similar to arrays as they are, therefore it doesn't make much sense to store an array in them. Rather what you should do is create a mapping of a mapping.
An example of this would be::
contract C {
struct myStruct {
uint someNumber;
string someString;
}
mapping(uint => mapping(string => myStruct)) myDynamicMapping;
function storeInMapping() {
myDynamicMapping[1]["Foo"] = myStruct(2, "Bar");
}
}
Can you return an array or a ``string`` from a solidity function call? Can you return an array or a ``string`` from a solidity function call?
====================================================================== ======================================================================
@ -223,61 +123,6 @@ Example::
} }
} }
What are ``event``'s and why do we need them?
=============================================
Let us suppose that you need a contract to alert the outside world when
something happens. The contract can fire an event, which can be listened to
from web3 (inside geth or a web application). The main advantage of events
is that they are stored in a special way on the blockchain so that it
is very easy to search for them.
What are the different function visibilities?
=============================================
The visibility specifiers do not only change the visibility but also
the way functions can be called. In general, functions in the
same contract can also be called internally (which is cheaper
and allows for memory types to be passed by reference). This
is done if you just use ``f(1,2)``. If you use ``this.f(1,2)``
or ``otherContract.f(1,2)``, the function is called externally.
Internal function calls have the advantage that you can use
all Solidity types as parameters, but you have to stick to the
simpler ABI types for external calls.
* ``external``: all, only externally
* ``public``: all (this is the default), externally and internally
* ``internal``: only this contract and contracts deriving from it, only internally
* ``private``: only this contract, only internally
Do contract constructors have to be publicly visible?
=====================================================
You can use the visibility specifiers, but they do not yet have any effect.
The constructor is removed from the contract code once it is deployed,
Can a contract have multiple constructors?
==========================================
No, a contract can have only one constructor.
More specifically, it can only have one function whose name matches
that of the constructor.
Having multiple constructors with different number of arguments
or argument types, as it is possible in other languages
is not allowed in Solidity.
Is a constructor required?
==========================
No. If there is no constructor, a generic one without arguments and no actions will be used.
Are timestamps (``now,`` ``block.timestamp``) reliable? Are timestamps (``now,`` ``block.timestamp``) reliable?
======================================================= =======================================================
@ -363,14 +208,6 @@ Examples::
C c = new C(); C c = new C();
} }
What is the ``modifier`` keyword?
=================================
Modifiers are a way to prepend or append code to a function in order
to add guards, initialisation or cleanup functionality in a concise way.
For examples, see the `features.sol <https://github.com/ethereum/dapp-bin/blob/master/library/features.sol>`_.
How do structs work? How do structs work?
==================== ====================
@ -590,12 +427,6 @@ The correct way to do this is the following::
} }
} }
Can a regular (i.e. non-contract) ethereum account be closed permanently like a contract can?
=============================================================================================
No. Non-contract accounts "exist" as long as the private key is known by
someone or can be generated in some way.
What is the difference between ``bytes`` and ``byte[]``? What is the difference between ``bytes`` and ``byte[]``?
======================================================== ========================================================
@ -641,16 +472,6 @@ Use the constructor. Anything inside it will be executed when the contract is fi
See `replicator.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/50_replicator.sol>`_. See `replicator.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/50_replicator.sol>`_.
Can a contract create another contract?
=======================================
Yes, see `replicator.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/50_replicator.sol>`_.
Note that the full code of the created contract has to be included in the creator contract.
This also means that cyclic creations are not possible (because the contract would have
to contain its own code) - at least not in a general way.
How do you create 2-dimensional arrays? How do you create 2-dimensional arrays?
======================================= =======================================
@ -709,10 +530,12 @@ How do I initialize a contract with only a specific amount of wei?
Currently the approach is a little ugly, but there is little that can be done to improve it. Currently the approach is a little ugly, but there is little that can be done to improve it.
In the case of a ``contract A`` calling a new instance of ``contract B``, parentheses have to be used around In the case of a ``contract A`` calling a new instance of ``contract B``, parentheses have to be used around
``new B`` because ``B.value`` would refer to a member of ``B`` called ``value``. ``new B`` because ``B.value`` would refer to a member of ``B`` called ``value``.
You will need to make sure that you have both contracts aware of each other's presence. You will need to make sure that you have both contracts aware of each other's presence and that ``contract B`` has a ``payable`` constructor.
In this example:: In this example::
contract B {} contract B {
function B() payable {}
}
contract A { contract A {

View File

@ -1,8 +1,12 @@
Solidity Solidity
======== ========
Solidity is a high-level language whose syntax is similar to that of JavaScript Solidity is a contract-oriented, high-level language whose syntax is similar to that of JavaScript
and it is designed to compile to code for the Ethereum Virtual Machine. and it is designed to target the Ethereum Virtual Machine.
Solidity is statically typed, supports inheritance, libraries and complex
user-defines types among other features.
As you will see, it is possible to create contracts for voting, As you will see, it is possible to create contracts for voting,
crowdfunding, blind auctions, multi-signature wallets and more. crowdfunding, blind auctions, multi-signature wallets and more.
@ -16,7 +20,7 @@ Useful links
* `Ethereum <https://ethereum.org>`_ * `Ethereum <https://ethereum.org>`_
* `Changelog <https://github.com/ethereum/wiki/wiki/Solidity-Changelog>`_ * `Changelog <https://github.com/ethereum/solidity/blob/develop/Changelog.md>`_
* `Story Backlog <https://www.pivotaltracker.com/n/projects/1189488>`_ * `Story Backlog <https://www.pivotaltracker.com/n/projects/1189488>`_

View File

@ -9,7 +9,7 @@ Installing Solidity
Versioning Versioning
========== ==========
Solidity versions follow `semantic versioning <https://semver.org>` and in addition to Solidity versions follow `semantic versioning <https://semver.org>`_ and in addition to
releases, **nightly development builds** are also made available. The nightly builds releases, **nightly development builds** are also made available. The nightly builds
are not guaranteed to be working and despite best efforts they might contain undocumented are not guaranteed to be working and despite best efforts they might contain undocumented
and/or broken changes. We recommend to use the latest release. Package installers below and/or broken changes. We recommend to use the latest release. Package installers below
@ -205,10 +205,11 @@ to semver and the severity of the change. Finally, a release is always made with
of the current nightly build, but without the ``prerelease`` specifier. of the current nightly build, but without the ``prerelease`` specifier.
Example: Example:
- 0) the 0.4.0 release is made
- 1) nightly build has a version of 0.4.1 from now on 0. the 0.4.0 release is made
- 2) non-breaking changes are introduced - no change in version 1. nightly build has a version of 0.4.1 from now on
- 3) a breaking change is introduced - version is bumped to 0.5.0 2. non-breaking changes are introduced - no change in version
- 4) the 0.5.0 release is made 3. a breaking change is introduced - version is bumped to 0.5.0
4. the 0.5.0 release is made
This behaviour works well with the version pragma. This behaviour works well with the version pragma.

View File

@ -348,10 +348,12 @@ storage. A contract can neither read nor write to any storage apart
from its own. from its own.
The second memory area is called **memory**, of which a contract obtains The second memory area is called **memory**, of which a contract obtains
a freshly cleared instance for each message call. Memory can be a freshly cleared instance for each message call. Memory is linear and can be
addressed at byte level, but read and written to in 32 byte (256-bit) addressed at byte level, but reads are limited to a width of 256 bits, while writes
chunks. Memory is more costly the larger it grows (it scales can be either 8 bits or 256 bits wide. Memory is expanded by a word (256-bit), when
quadratically). accessing (either reading or writing) a previously untouched memory word (ie. any offset
within a word). At the time of expansion, the cost in gas must be paid. Memory is more
costly the larger it grows (it scales quadratically).
The EVM is not a register machine but a stack machine, so all The EVM is not a register machine but a stack machine, so all
computations are performed on an area called the **stack**. It has a maximum size of computations are performed on an area called the **stack**. It has a maximum size of
@ -453,13 +455,19 @@ receives the address of the new contract on the stack.
.. index:: selfdestruct .. index:: selfdestruct
``selfdestruct`` Self-destruct
================ =============
The only possibility that code is removed from the blockchain is The only possibility that code is removed from the blockchain is
when a contract at that address performs the ``selfdestruct`` operation. when a contract at that address performs the ``selfdestruct`` operation.
The remaining Ether stored at that address is sent to a designated The remaining Ether stored at that address is sent to a designated
target and then the storage and code is removed. target and then the storage and code is removed from the state.
Note that even if a contract's code does not contain a call to ``selfdestruct``, .. warning:: Even if a contract's code does not contain a call to ``selfdestruct``,
it can still perform that operation using ``delegatecall`` or ``callcode``. it can still perform that operation using ``delegatecall`` or ``callcode``.
.. note:: The pruning of old contracts may or may not be implemented by Ethereum
clients. Additionally, archive nodes could choose to keep the contract storage
and code indefinitely.
.. note:: Currently **external accounts** cannot be removed from the state.

View File

@ -34,17 +34,17 @@ Statically-sized variables (everything except mapping and dynamically-sized arra
The elements of structs and arrays are stored after each other, just as if they were given explicitly. The elements of structs and arrays are stored after each other, just as if they were given explicitly.
Due to their unpredictable size, mapping and dynamically-sized array types use a ``sha3`` Due to their unpredictable size, mapping and dynamically-sized array types use a Keccak-256 hash
computation to find the starting position of the value or the array data. These starting positions are always full stack slots. computation to find the starting position of the value or the array data. These starting positions are always full stack slots.
The mapping or the dynamic array itself The mapping or the dynamic array itself
occupies an (unfilled) slot in storage at some position ``p`` according to the above rule (or by occupies an (unfilled) slot in storage at some position ``p`` according to the above rule (or by
recursively applying this rule for mappings to mappings or arrays of arrays). For a dynamic array, this slot stores the number of elements in the array (byte arrays and strings are an exception here, see below). For a mapping, the slot is unused (but it is needed so that two equal mappings after each other will use a different hash distribution). recursively applying this rule for mappings to mappings or arrays of arrays). For a dynamic array, this slot stores the number of elements in the array (byte arrays and strings are an exception here, see below). For a mapping, the slot is unused (but it is needed so that two equal mappings after each other will use a different hash distribution).
Array data is located at ``sha3(p)`` and the value corresponding to a mapping key Array data is located at ``keccak256(p)`` and the value corresponding to a mapping key
``k`` is located at ``sha3(k . p)`` where ``.`` is concatenation. If the value is again a ``k`` is located at ``keccak256(k . p)`` where ``.`` is concatenation. If the value is again a
non-elementary type, the positions are found by adding an offset of ``sha3(k . p)``. non-elementary type, the positions are found by adding an offset of ``keccak256(k . p)``.
``bytes`` and ``string`` store their data in the same slot where also the length is stored if they are short. In particular: If the data is at most ``31`` bytes long, it is stored in the higher-order bytes (left aligned) and the lowest-order byte stores ``length * 2``. If it is longer, the main slot stores ``length * 2 + 1`` and the data is stored as usual in ``sha3(slot)``. ``bytes`` and ``string`` store their data in the same slot where also the length is stored if they are short. In particular: If the data is at most ``31`` bytes long, it is stored in the higher-order bytes (left aligned) and the lowest-order byte stores ``length * 2``. If it is longer, the main slot stores ``length * 2 + 1`` and the data is stored as usual in ``keccak256(slot)``.
So for the following contract snippet:: So for the following contract snippet::
@ -54,7 +54,25 @@ So for the following contract snippet::
mapping(uint => mapping(uint => s)) data; mapping(uint => mapping(uint => s)) data;
} }
The position of ``data[4][9].b`` is at ``sha3(uint256(9) . sha3(uint256(4) . uint256(1))) + 1``. The position of ``data[4][9].b`` is at ``keccak256(uint256(9) . keccak256(uint256(4) . uint256(1))) + 1``.
****************
Layout in Memory
****************
Solidity reserves three 256-bit slots:
- 0 - 64: scratch space for hashing methods
- 64 - 96: currently allocated memory size (aka. free memory pointer)
Scratch space can be used between statements (ie. within inline assembly).
Solidity always places new objects at the free memory pointer and memory is never freed (this might change in the future).
.. warning::
There are some operations in Solidity that need a temporary memory area larger than 64 bytes and therefore will not fit into the scratch space. They will be placed where the free memory points to, but given their short lifecycle, the pointer is not updated. The memory may or may not be zeroed out. Because of this, one shouldn't expect the free memory to be zeroed out.
.. index: memory layout
***************** *****************
Esoteric Features Esoteric Features
@ -281,7 +299,7 @@ The following is the order of precedence for operators, listed in order of evalu
| *16* | Comma operator | ``,`` | | *16* | Comma operator | ``,`` |
+------------+-------------------------------------+--------------------------------------------+ +------------+-------------------------------------+--------------------------------------------+
.. index:: block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, now, gas price, origin, sha3, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send .. index:: block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, now, gas price, origin, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
Global Variables Global Variables
================ ================
@ -299,7 +317,8 @@ Global Variables
- ``now`` (``uint``): current block timestamp (alias for ``block.timestamp``) - ``now`` (``uint``): current block timestamp (alias for ``block.timestamp``)
- ``tx.gasprice`` (``uint``): gas price of the transaction - ``tx.gasprice`` (``uint``): gas price of the transaction
- ``tx.origin`` (``address``): sender of the transaction (full call chain) - ``tx.origin`` (``address``): sender of the transaction (full call chain)
- ``sha3(...) returns (bytes32)``: compute the Ethereum-SHA-3 (KECCAK-256) hash of the (tightly packed) arguments - ``keccak256(...) returns (bytes32)``: compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments
- ``sha3(...) returns (bytes32)``: an alias to `keccak256()`
- ``sha256(...) returns (bytes32)``: compute the SHA-256 hash of the (tightly packed) arguments - ``sha256(...) returns (bytes32)``: compute the SHA-256 hash of the (tightly packed) arguments
- ``ripemd160(...) returns (bytes20)``: compute the RIPEMD-160 hash of the (tightly packed) arguments - ``ripemd160(...) returns (bytes20)``: compute the RIPEMD-160 hash of the (tightly packed) arguments
- ``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``: recover address associated with the public key from elliptic curve signature, return zero on error - ``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``: recover address associated with the public key from elliptic curve signature, return zero on error
@ -338,3 +357,16 @@ Modifiers
- ``anonymous`` for events: Does not store event signature as topic. - ``anonymous`` for events: Does not store event signature as topic.
- ``indexed`` for event parameters: Stores the parameter as topic. - ``indexed`` for event parameters: Stores the parameter as topic.
- ``payable`` for functions: Allows them to receive Ether together with a call. - ``payable`` for functions: Allows them to receive Ether together with a call.
Reserved Keywords
=================
These keywords are reserved in Solidity. They might become part of the syntax in the future:
``abstract``, ``after``, ``case``, ``catch``, ``final``, ``in``, ``inline``, ``interface``, ``let``, ``match``,
``of``, ``pure``, ``relocatable``, ``static``, ``switch``, ``try``, ``type``, ``typeof``, ``view``.
Language Grammar
================
The entire language grammar is `available here <https://github.com/ethereum/solidity/blob/release/libsolidity/grammar.txt>`_.

View File

@ -123,7 +123,7 @@ Sending and Receiving Ether
``addr.call.value(x)()``. This is essentially the same as ``addr.send(x)``, ``addr.call.value(x)()``. This is essentially the same as ``addr.send(x)``,
only that it forwards all remaining gas and opens up the ability for the only that it forwards all remaining gas and opens up the ability for the
recipient to perform more expensive actions. This might include calling back recipient to perform more expensive actions. This might include calling back
into the sending contract or other state changes you might not have though of. into the sending contract or other state changes you might not have thought of.
So it allows for great flexibility for honest users but also for malicious actors. So it allows for great flexibility for honest users but also for malicious actors.
- If you want to send Ether using ``address.send``, there are certain details to be aware of: - If you want to send Ether using ``address.send``, there are certain details to be aware of:
@ -207,7 +207,7 @@ Minor Details
You can craft transactions that call a function ``f(uint8 x)`` with a raw byte argument You can craft transactions that call a function ``f(uint8 x)`` with a raw byte argument
of ``0xff000001`` and with ``0x00000001``. Both are fed to the contract and both will of ``0xff000001`` and with ``0x00000001``. Both are fed to the contract and both will
look like the number ``1`` as far as ``x`` is concerned, but ``msg.data`` will look like the number ``1`` as far as ``x`` is concerned, but ``msg.data`` will
be different, so if you use ``sha3(msg.data)`` for anything, you will get different results. be different, so if you use ``keccak256(msg.data)`` for anything, you will get different results.
*************** ***************
Recommendations Recommendations

View File

@ -415,7 +415,7 @@ high or low invalid bids.
revealEnd = biddingEnd + _revealTime; revealEnd = biddingEnd + _revealTime;
} }
/// Place a blinded bid with `_blindedBid` = sha3(value, /// Place a blinded bid with `_blindedBid` = keccak256(value,
/// fake, secret). /// fake, secret).
/// The sent ether is only refunded if the bid is correctly /// The sent ether is only refunded if the bid is correctly
/// revealed in the revealing phase. The bid is valid if the /// revealed in the revealing phase. The bid is valid if the
@ -459,7 +459,7 @@ high or low invalid bids.
var bid = bids[msg.sender][i]; var bid = bids[msg.sender][i];
var (value, fake, secret) = var (value, fake, secret) =
(_values[i], _fake[i], _secret[i]); (_values[i], _fake[i], _secret[i]);
if (bid.blindedBid != sha3(value, fake, secret)) { if (bid.blindedBid != keccak256(value, fake, secret)) {
// Bid was not actually revealed. // Bid was not actually revealed.
// Do not refund deposit. // Do not refund deposit.
continue; continue;

View File

@ -106,7 +106,7 @@ the function ``call`` is provided which takes an arbitrary number of arguments o
address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2; address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2;
nameReg.call("register", "MyName"); nameReg.call("register", "MyName");
nameReg.call(bytes4(sha3("fun(uint256)")), a); nameReg.call(bytes4(keccak256("fun(uint256)")), a);
``call`` returns a boolean indicating whether the invoked function terminated (``true``) or caused an EVM exception (``false``). It is not possible to access the actual data returned (for this we would need to know the encoding and size in advance). ``call`` returns a boolean indicating whether the invoked function terminated (``true``) or caused an EVM exception (``false``). It is not possible to access the actual data returned (for this we would need to know the encoding and size in advance).
@ -186,7 +186,7 @@ the type ``ufixed0x256`` because ``1/3`` is not finitely representable in binary
approximated. approximated.
Any operator that can be applied to integers can also be applied to literal expressions as Any operator that can be applied to integers can also be applied to literal expressions as
long as the operators are integers. If any of the two is fractional, bit operations are disallowed long as the operands are integers. If any of the two is fractional, bit operations are disallowed
and exponentiation is disallowed if the exponent is fractional (because that might result in and exponentiation is disallowed if the exponent is fractional (because that might result in
a non-rational number). a non-rational number).
@ -371,6 +371,9 @@ So ``bytes`` should always be preferred over ``byte[]`` because it is cheaper.
that you are accessing the low-level bytes of the UTF-8 representation, that you are accessing the low-level bytes of the UTF-8 representation,
and not the individual characters! and not the individual characters!
It is possible to mark arrays ``public`` and have Solidity create an accessor.
The numeric index will become a required parameter for the accessor.
.. index:: ! array;allocating, new .. index:: ! array;allocating, new
Allocating Memory Arrays Allocating Memory Arrays
@ -610,13 +613,43 @@ can actually be any type, including mappings.
Mappings can be seen as hashtables which are virtually initialized such that Mappings can be seen as hashtables which are virtually initialized such that
every possible key exists and is mapped to a value whose byte-representation is every possible key exists and is mapped to a value whose byte-representation is
all zeros: a type's :ref:`default value <default-value>`. The similarity ends here, though: The key data is not actually stored all zeros: a type's :ref:`default value <default-value>`. The similarity ends here, though: The key data is not actually stored
in a mapping, only its ``sha3`` hash used to look up the value. in a mapping, only its ``keccak256`` hash used to look up the value.
Because of this, mappings do not have a length or a concept of a key or value being "set". Because of this, mappings do not have a length or a concept of a key or value being "set".
Mappings are only allowed for state variables (or as storage reference types Mappings are only allowed for state variables (or as storage reference types
in internal functions). in internal functions).
It is possible to mark mappings ``public`` and have Solidity create an accessor.
The ``_KeyType`` will become a required parameter for the accessor and it will
return ``_ValueType``.
The ``_ValueType`` can be a mapping too. The accessor will have one parameter
for each ``_KeyType``, recursively.
::
pragma solidity ^0.4.0;
contract MappingExample {
mapping(address => uint) public balances;
function update(uint newBalance) {
balances[msg.sender] = newBalance;
}
}
contract MappingUser {
function f() returns (uint) {
return MappingExample(<address>).balances(this);
}
}
.. note::
Mappings are not iterable, but it is possible to implement a data structure on top of them.
For an example, see `iterable mapping <https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol>`_.
.. index:: assignment, ! delete, lvalue .. index:: assignment, ! delete, lvalue
Operators Involving LValues Operators Involving LValues

View File

@ -79,7 +79,7 @@ Block and Transaction Properties
You can only access the hashes of the most recent 256 blocks, all other You can only access the hashes of the most recent 256 blocks, all other
values will be zero. values will be zero.
.. index:: sha3, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send .. index:: keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
Mathematical and Cryptographic Functions Mathematical and Cryptographic Functions
---------------------------------------- ----------------------------------------
@ -88,8 +88,10 @@ Mathematical and Cryptographic Functions
compute ``(x + y) % k`` where the addition is performed with arbitrary precision and does not wrap around at ``2**256``. compute ``(x + y) % k`` where the addition is performed with arbitrary precision and does not wrap around at ``2**256``.
``mulmod(uint x, uint y, uint k) returns (uint)``: ``mulmod(uint x, uint y, uint k) returns (uint)``:
compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``. compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``.
``keccak256(...) returns (bytes32)``:
compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments
``sha3(...) returns (bytes32)``: ``sha3(...) returns (bytes32)``:
compute the Ethereum-SHA-3 (KECCAK-256) hash of the (tightly packed) arguments alias to `keccak256()`
``sha256(...) returns (bytes32)``: ``sha256(...) returns (bytes32)``:
compute the SHA-256 hash of the (tightly packed) arguments compute the SHA-256 hash of the (tightly packed) arguments
``ripemd160(...) returns (bytes20)``: ``ripemd160(...) returns (bytes20)``:
@ -100,18 +102,18 @@ Mathematical and Cryptographic Functions
In the above, "tightly packed" means that the arguments are concatenated without padding. In the above, "tightly packed" means that the arguments are concatenated without padding.
This means that the following are all identical:: This means that the following are all identical::
sha3("ab", "c") keccak256("ab", "c")
sha3("abc") keccak256("abc")
sha3(0x616263) keccak256(0x616263)
sha3(6382179) keccak256(6382179)
sha3(97, 98, 99) keccak256(97, 98, 99)
If padding is needed, explicit type conversions can be used: ``sha3("\x00\x12")`` is the If padding is needed, explicit type conversions can be used: ``keccak256("\x00\x12")`` is the
same as ``sha3(uint16(0x12))``. same as ``keccak256(uint16(0x12))``.
Note that constants will be packed using the minimum number of bytes required to store them. Note that constants will be packed using the minimum number of bytes required to store them.
This means that, for example, ``sha3(0) == sha3(uint8(0))`` and This means that, for example, ``keccak256(0) == keccak256(uint8(0))`` and
``sha3(0x12345678) == sha3(uint32(0x12345678))``. ``keccak256(0x12345678) == keccak256(uint32(0x12345678))``.
It might be that you run into Out-of-Gas for ``sha256``, ``ripemd160`` or ``ecrecover`` on a *private blockchain*. The reason for this is that those are implemented as so-called precompiled contracts and these contracts only really exist after they received the first message (although their contract code is hardcoded). Messages to non-existing contracts are more expensive and thus the execution runs into an Out-of-Gas error. A workaround for this problem is to first send e.g. 1 Wei to each of the contracts before you use them in your actual contracts. This is not an issue on the official or test net. It might be that you run into Out-of-Gas for ``sha256``, ``ripemd160`` or ``ecrecover`` on a *private blockchain*. The reason for this is that those are implemented as so-called precompiled contracts and these contracts only really exist after they received the first message (although their contract code is hardcoded). Messages to non-existing contracts are more expensive and thus the execution runs into an Out-of-Gas error. A workaround for this problem is to first send e.g. 1 Wei to each of the contracts before you use them in your actual contracts. This is not an issue on the official or test net.

View File

@ -63,7 +63,7 @@ template <class T, class ... U> bytes abiInAux(T const& _t, U const& ... _u)
template <class ... T> bytes abiIn(std::string _id, T const& ... _t) template <class ... T> bytes abiIn(std::string _id, T const& ... _t)
{ {
return sha3(_id).ref().cropped(0, 4).toBytes() + abiInAux(_t ...); return keccak256(_id).ref().cropped(0, 4).toBytes() + abiInAux(_t ...);
} }
template <class T> struct ABIDeserialiser {}; template <class T> struct ABIDeserialiser {};

View File

@ -87,47 +87,6 @@ using bytes = std::vector<byte>;
using bytesRef = vector_ref<byte>; using bytesRef = vector_ref<byte>;
using bytesConstRef = vector_ref<byte const>; using bytesConstRef = vector_ref<byte const>;
template <class T>
class secure_vector
{
public:
secure_vector() {}
secure_vector(secure_vector<T> const& /*_c*/) = default; // See https://github.com/ethereum/libweb3core/pull/44
explicit secure_vector(unsigned _size): m_data(_size) {}
explicit secure_vector(unsigned _size, T _item): m_data(_size, _item) {}
explicit secure_vector(std::vector<T> const& _c): m_data(_c) {}
explicit secure_vector(vector_ref<T> _c): m_data(_c.data(), _c.data() + _c.size()) {}
explicit secure_vector(vector_ref<const T> _c): m_data(_c.data(), _c.data() + _c.size()) {}
~secure_vector() { ref().cleanse(); }
secure_vector<T>& operator=(secure_vector<T> const& _c)
{
if (&_c == this)
return *this;
ref().cleanse();
m_data = _c.m_data;
return *this;
}
std::vector<T>& writable() { clear(); return m_data; }
std::vector<T> const& makeInsecure() const { return m_data; }
void clear() { ref().cleanse(); }
vector_ref<T> ref() { return vector_ref<T>(&m_data); }
vector_ref<T const> ref() const { return vector_ref<T const>(&m_data); }
size_t size() const { return m_data.size(); }
bool empty() const { return m_data.empty(); }
void swap(secure_vector<T>& io_other) { m_data.swap(io_other.m_data); }
private:
std::vector<T> m_data;
};
using bytesSec = secure_vector<byte>;
// Numeric types. // Numeric types.
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>; using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
using u64 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<64, 64, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; using u64 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<64, 64, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;

View File

@ -20,13 +20,6 @@
*/ */
#include "CommonData.h" #include "CommonData.h"
#include <random>
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4724) // potential mod by 0, line 78 of boost/random/uniform_int_distribution.hpp (boost 1.55)
#endif
#include <boost/random/uniform_int_distribution.hpp>
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(pop) #pragma warning(pop)
#endif #endif

View File

@ -47,41 +47,15 @@ private:
#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { const char* what() const noexcept override { return #X; } } #define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { const char* what() const noexcept override { return #X; } }
/// Base class for all RLP exceptions.
struct RLPException: virtual Exception { RLPException(std::string _message = std::string()): Exception(_message) {} };
#define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { const char* what() const noexcept override { return #X; } }
DEV_SIMPLE_EXCEPTION_RLP(BadCast);
DEV_SIMPLE_EXCEPTION_RLP(BadRLP);
DEV_SIMPLE_EXCEPTION_RLP(OversizeRLP);
DEV_SIMPLE_EXCEPTION_RLP(UndersizeRLP);
DEV_SIMPLE_EXCEPTION(BadHexCharacter); DEV_SIMPLE_EXCEPTION(BadHexCharacter);
DEV_SIMPLE_EXCEPTION(NoNetworking);
DEV_SIMPLE_EXCEPTION(NoUPnPDevice);
DEV_SIMPLE_EXCEPTION(RootNotFound);
struct BadRoot: virtual Exception { public: BadRoot(h256 const& _root): Exception("BadRoot " + _root.hex()), root(_root) {} h256 root; };
DEV_SIMPLE_EXCEPTION(FileError); DEV_SIMPLE_EXCEPTION(FileError);
DEV_SIMPLE_EXCEPTION(Overflow);
DEV_SIMPLE_EXCEPTION(FailedInvariant);
DEV_SIMPLE_EXCEPTION(ValueTooLarge);
struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): Exception("Interface " + _f + " not supported.") {} };
struct ExternalFunctionFailure: virtual Exception { public: ExternalFunctionFailure(std::string _f): Exception("Function " + _f + "() failed.") {} };
// error information to be added to exceptions // error information to be added to exceptions
using errinfo_invalidSymbol = boost::error_info<struct tag_invalidSymbol, char>; using errinfo_invalidSymbol = boost::error_info<struct tag_invalidSymbol, char>;
using errinfo_wrongAddress = boost::error_info<struct tag_address, std::string>;
using errinfo_comment = boost::error_info<struct tag_comment, std::string>; using errinfo_comment = boost::error_info<struct tag_comment, std::string>;
using errinfo_required = boost::error_info<struct tag_required, bigint>; using errinfo_required = boost::error_info<struct tag_required, bigint>;
using errinfo_got = boost::error_info<struct tag_got, bigint>; using errinfo_got = boost::error_info<struct tag_got, bigint>;
using errinfo_min = boost::error_info<struct tag_min, bigint>;
using errinfo_max = boost::error_info<struct tag_max, bigint>;
using RequirementError = boost::tuple<errinfo_required, errinfo_got>;
using errinfo_hash256 = boost::error_info<struct tag_hash, h256>;
using errinfo_required_h256 = boost::error_info<struct tag_required_h256, h256>; using errinfo_required_h256 = boost::error_info<struct tag_required_h256, h256>;
using errinfo_got_h256 = boost::error_info<struct tag_get_h256, h256>; using errinfo_got_h256 = boost::error_info<struct tag_get_h256, h256>;
using Hash256RequirementError = boost::tuple<errinfo_required_h256, errinfo_got_h256>;
using errinfo_extraData = boost::error_info<struct tag_extraData, bytes>;
} }

View File

@ -24,7 +24,7 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include "picosha2.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -49,12 +49,19 @@ namespace keccak
#define decsha3(bits) \ #define decsha3(bits) \
int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t); int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t);
#define deckeccak(bits) \
int keccak##bits(uint8_t*, size_t, const uint8_t*, size_t);
decshake(128) decshake(128)
decshake(256) decshake(256)
decsha3(224) decsha3(224)
decsha3(256) decsha3(256)
decsha3(384) decsha3(384)
decsha3(512) decsha3(512)
deckeccak(224)
deckeccak(256)
deckeccak(384)
deckeccak(512)
/******** The Keccak-f[1600] permutation ********/ /******** The Keccak-f[1600] permutation ********/
@ -192,6 +199,14 @@ static inline int hash(uint8_t* out, size_t outlen,
if (outlen > (bits/8)) { \ if (outlen > (bits/8)) { \
return -1; \ return -1; \
} \ } \
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x06); \
}
#define defkeccak(bits) \
int keccak##bits(uint8_t* out, size_t outlen, \
const uint8_t* in, size_t inlen) { \
if (outlen > (bits/8)) { \
return -1; \
} \
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
} }
@ -205,17 +220,20 @@ defsha3(256)
defsha3(384) defsha3(384)
defsha3(512) defsha3(512)
/*** KECCAK FOFs ***/
defkeccak(224)
defkeccak(256)
defkeccak(384)
defkeccak(512)
} }
unsigned g_sha3Counter = 0; bool keccak256(bytesConstRef _input, bytesRef o_output)
bool sha3(bytesConstRef _input, bytesRef o_output)
{ {
// FIXME: What with unaligned memory? // FIXME: What with unaligned memory?
if (o_output.size() != 32) if (o_output.size() != 32)
return false; return false;
++g_sha3Counter; keccak::keccak256(o_output.data(), 32, _input.data(), _input.size());
keccak::sha3_256(o_output.data(), 32, _input.data(), _input.size());
// keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size()); // keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size());
return true; return true;
} }

View File

@ -25,7 +25,6 @@
#include <string> #include <string>
#include "FixedHash.h" #include "FixedHash.h"
#include "vector_ref.h"
namespace dev namespace dev
{ {
@ -34,26 +33,24 @@ namespace dev
/// Calculate SHA3-256 hash of the given input and load it into the given output. /// Calculate SHA3-256 hash of the given input and load it into the given output.
/// @returns false if o_output.size() != 32. /// @returns false if o_output.size() != 32.
bool sha3(bytesConstRef _input, bytesRef o_output); bool keccak256(bytesConstRef _input, bytesRef o_output);
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytesConstRef _input) { h256 ret; sha3(_input, ret.ref()); return ret; } inline h256 keccak256(bytesConstRef _input) { h256 ret; keccak256(_input, ret.ref()); return ret; }
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); } inline h256 keccak256(bytes const& _input) { return keccak256(bytesConstRef(&_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } inline h256 keccak256(std::string const& _input) { return keccak256(bytesConstRef(_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. /// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash.
template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); } template<unsigned N> inline h256 keccak256(FixedHash<N> const& _input) { return keccak256(_input.ref()); }
/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. /// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data.
inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); } inline std::string keccak256(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? keccak256(fromHex(_input)) : keccak256(bytesConstRef(&_input))).asBytes()); }
/// Calculate SHA3-256 MAC /// Calculate SHA3-256 MAC
inline void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { sha3(_secret.toBytes() + _plain.toBytes()).ref().populate(_output); } inline void keccak256mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { keccak256(_secret.toBytes() + _plain.toBytes()).ref().populate(_output); }
extern unsigned g_sha3Counter;
} }

View File

@ -93,6 +93,13 @@ static void __inline__ trap_instruction(void)
/* Has same known problem and workaround /* Has same known problem and workaround
* as Thumb mode */ * as Thumb mode */
} }
#elif defined(ETH_EMSCRIPTEN)
enum { HAVE_TRAP_INSTRUCTION = 1, };
__attribute__((gnu_inline, always_inline))
static void __inline__ trap_instruction(void)
{
asm("debugger");
}
#else #else
enum { HAVE_TRAP_INSTRUCTION = 0, }; enum { HAVE_TRAP_INSTRUCTION = 0, };
#endif #endif
@ -101,11 +108,7 @@ __attribute__((gnu_inline, always_inline))
static void __inline__ debug_break(void) static void __inline__ debug_break(void)
{ {
if (HAVE_TRAP_INSTRUCTION) { if (HAVE_TRAP_INSTRUCTION) {
#if defined(ETH_EMSCRIPTEN)
asm("debugger");
#else
trap_instruction(); trap_instruction();
#endif
} else if (DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP) { } else if (DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP) {
/* raises SIGILL on Linux x86{,-64}, to continue in gdb: /* raises SIGILL on Linux x86{,-64}, to continue in gdb:
* (gdb) handle SIGILL stop nopass * (gdb) handle SIGILL stop nopass

View File

@ -1,360 +0,0 @@
/*
The MIT License (MIT)
Copyright (C) 2014 okdshin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef PICOSHA2_H
#define PICOSHA2_H
//picosha2:20140213
#include <cstdint>
#include <iostream>
#include <vector>
#include <iterator>
#include <cassert>
#include <sstream>
#include <algorithm>
namespace picosha2
{
namespace detail
{
inline uint8_t mask_8bit(uint8_t x){
return x&0xff;
}
inline uint32_t mask_32bit(uint32_t x){
return x&0xffffffff;
}
static const uint32_t add_constant[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
static const uint32_t initial_message_digest[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z){
return (x&y)^((~x)&z);
}
inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z){
return (x&y)^(x&z)^(y&z);
}
inline uint32_t rotr(uint32_t x, std::size_t n){
assert(n < 32);
return mask_32bit((x>>n)|(x<<(32-n)));
}
inline uint32_t bsig0(uint32_t x){
return rotr(x, 2)^rotr(x, 13)^rotr(x, 22);
}
inline uint32_t bsig1(uint32_t x){
return rotr(x, 6)^rotr(x, 11)^rotr(x, 25);
}
inline uint32_t shr(uint32_t x, std::size_t n){
assert(n < 32);
return x >> n;
}
inline uint32_t ssig0(uint32_t x){
return rotr(x, 7)^rotr(x, 18)^shr(x, 3);
}
inline uint32_t ssig1(uint32_t x){
return rotr(x, 17)^rotr(x, 19)^shr(x, 10);
}
template<typename RaIter1, typename RaIter2>
void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last){
(void)last; // FIXME: check this is valid
uint32_t w[64];
std::fill(w, w+64, 0);
for(std::size_t i = 0; i < 16; ++i){
w[i] = (static_cast<uint32_t>(mask_8bit(*(first+i*4)))<<24)
|(static_cast<uint32_t>(mask_8bit(*(first+i*4+1)))<<16)
|(static_cast<uint32_t>(mask_8bit(*(first+i*4+2)))<<8)
|(static_cast<uint32_t>(mask_8bit(*(first+i*4+3))));
}
for(std::size_t i = 16; i < 64; ++i){
w[i] = mask_32bit(ssig1(w[i-2])+w[i-7]+ssig0(w[i-15])+w[i-16]);
}
uint32_t a = *message_digest;
uint32_t b = *(message_digest+1);
uint32_t c = *(message_digest+2);
uint32_t d = *(message_digest+3);
uint32_t e = *(message_digest+4);
uint32_t f = *(message_digest+5);
uint32_t g = *(message_digest+6);
uint32_t h = *(message_digest+7);
for(std::size_t i = 0; i < 64; ++i){
uint32_t temp1 = h+bsig1(e)+ch(e,f,g)+add_constant[i]+w[i];
uint32_t temp2 = bsig0(a)+maj(a,b,c);
h = g;
g = f;
f = e;
e = mask_32bit(d+temp1);
d = c;
c = b;
b = a;
a = mask_32bit(temp1+temp2);
}
*message_digest += a;
*(message_digest+1) += b;
*(message_digest+2) += c;
*(message_digest+3) += d;
*(message_digest+4) += e;
*(message_digest+5) += f;
*(message_digest+6) += g;
*(message_digest+7) += h;
for(std::size_t i = 0; i < 8; ++i){
*(message_digest+i) = mask_32bit(*(message_digest+i));
}
}
}//namespace detail
template<typename InIter>
void output_hex(InIter first, InIter last, std::ostream& os){
os.setf(std::ios::hex, std::ios::basefield);
while(first != last){
os.width(2);
os.fill('0');
os << static_cast<unsigned int>(*first);
++first;
}
os.setf(std::ios::dec, std::ios::basefield);
}
template<typename InIter>
void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str){
std::ostringstream oss;
output_hex(first, last, oss);
hex_str.assign(oss.str());
}
template<typename InContainer>
void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str){
bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str);
}
template<typename InIter>
std::string bytes_to_hex_string(InIter first, InIter last){
std::string hex_str;
bytes_to_hex_string(first, last, hex_str);
return hex_str;
}
template<typename InContainer>
std::string bytes_to_hex_string(const InContainer& bytes){
std::string hex_str;
bytes_to_hex_string(bytes, hex_str);
return hex_str;
}
class hash256_one_by_one {
public:
hash256_one_by_one(){
init();
}
void init(){
buffer_.clear();
std::fill(data_length_digits_, data_length_digits_+4, 0);
std::copy(detail::initial_message_digest, detail::initial_message_digest+8, h_);
}
template<typename RaIter>
void process(RaIter first, RaIter last){
add_to_data_length(std::distance(first, last));
std::copy(first, last, std::back_inserter(buffer_));
std::size_t i = 0;
for(;i+64 <= buffer_.size(); i+=64){
detail::hash256_block(h_, buffer_.begin()+i, buffer_.begin()+i+64);
}
buffer_.erase(buffer_.begin(), buffer_.begin()+i);
}
void finish(){
uint8_t temp[64];
std::fill(temp, temp+64, 0);
std::size_t remains = buffer_.size();
std::copy(buffer_.begin(), buffer_.end(), temp);
temp[remains] = 0x80;
if(remains > 55){
std::fill(temp+remains+1, temp+64, 0);
detail::hash256_block(h_, temp, temp+64);
std::fill(temp, temp+64-4, 0);
}
else {
std::fill(temp+remains+1, temp+64-4, 0);
}
write_data_bit_length(&(temp[56]));
detail::hash256_block(h_, temp, temp+64);
}
template<typename OutIter>
void get_hash_bytes(OutIter first, OutIter last)const{
for(const uint32_t* iter = h_; iter != h_+8; ++iter){
for(std::size_t i = 0; i < 4 && first != last; ++i){
*(first++) = detail::mask_8bit(static_cast<uint8_t>((*iter >> (24-8*i))));
}
}
}
private:
void add_to_data_length(uint32_t n) {
uint32_t carry = 0;
data_length_digits_[0] += n;
for(std::size_t i = 0; i < 4; ++i) {
data_length_digits_[i] += carry;
if(data_length_digits_[i] >= 65536u) {
data_length_digits_[i] -= 65536u;
carry = 1;
}
else {
break;
}
}
}
void write_data_bit_length(uint8_t* begin) {
uint32_t data_bit_length_digits[4];
std::copy(
data_length_digits_, data_length_digits_+4,
data_bit_length_digits
);
// convert byte length to bit length (multiply 8 or shift 3 times left)
uint32_t carry = 0;
for(std::size_t i = 0; i < 4; ++i) {
uint32_t before_val = data_bit_length_digits[i];
data_bit_length_digits[i] <<= 3;
data_bit_length_digits[i] |= carry;
data_bit_length_digits[i] &= 65535u;
carry = (before_val >> (16-3)) & 65535u;
}
// write data_bit_length
for(int i = 3; i >= 0; --i) {
(*begin++) = static_cast<uint8_t>(data_bit_length_digits[i] >> 8);
(*begin++) = static_cast<uint8_t>(data_bit_length_digits[i]);
}
}
std::vector<uint8_t> buffer_;
uint32_t data_length_digits_[4]; //as 64bit integer (16bit x 4 integer)
uint32_t h_[8];
};
inline void get_hash_hex_string(const hash256_one_by_one& hasher, std::string& hex_str){
uint8_t hash[32];
hasher.get_hash_bytes(hash, hash+32);
return bytes_to_hex_string(hash, hash+32, hex_str);
}
inline std::string get_hash_hex_string(const hash256_one_by_one& hasher){
std::string hex_str;
get_hash_hex_string(hasher, hex_str);
return hex_str;
}
template<typename RaIter, typename OutIter>
void hash256(RaIter first, RaIter last, OutIter first2, OutIter last2){
hash256_one_by_one hasher;
//hasher.init();
hasher.process(first, last);
hasher.finish();
hasher.get_hash_bytes(first2, last2);
}
template<typename RaIter, typename OutContainer>
void hash256(RaIter first, RaIter last, OutContainer& dst){
hash256(first, last, dst.begin(), dst.end());
}
template<typename RaContainer, typename OutIter>
void hash256(const RaContainer& src, OutIter first, OutIter last){
hash256(src.begin(), src.end(), first, last);
}
template<typename RaContainer, typename OutContainer>
void hash256(const RaContainer& src, OutContainer& dst){
hash256(src.begin(), src.end(), dst.begin(), dst.end());
}
template<typename RaIter>
void hash256_hex_string(RaIter first, RaIter last, std::string& hex_str){
uint8_t hashed[32];
hash256(first, last, hashed, hashed+32);
std::ostringstream oss;
output_hex(hashed, hashed+32, oss);
hex_str.assign(oss.str());
}
template<typename RaIter>
std::string hash256_hex_string(RaIter first, RaIter last){
std::string hex_str;
hash256_hex_string(first, last, hex_str);
return hex_str;
}
inline void hash256_hex_string(const std::string& src, std::string& hex_str){
hash256_hex_string(src.begin(), src.end(), hex_str);
}
template<typename RaContainer>
void hash256_hex_string(const RaContainer& src, std::string& hex_str){
hash256_hex_string(src.begin(), src.end(), hex_str);
}
template<typename RaContainer>
std::string hash256_hex_string(const RaContainer& src){
return hash256_hex_string(src.begin(), src.end());
}
}//namespace picosha2
#endif //PICOSHA2_H

View File

@ -69,26 +69,6 @@ public:
void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); }
/// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t.
void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); }
/// Securely overwrite the memory.
/// @note adapted from OpenSSL's implementation.
void cleanse()
{
static unsigned char s_cleanseCounter = 0;
uint8_t* p = (uint8_t*)begin();
size_t const len = (uint8_t*)end() - p;
size_t loop = len;
size_t count = s_cleanseCounter;
while (loop--)
{
*(p++) = (uint8_t)count;
count += (17 + ((size_t)p & 0xf));
}
p = (uint8_t*)memchr((uint8_t*)begin(), (uint8_t)count, len);
if (p)
count += (63 + (size_t)p);
s_cleanseCounter = (uint8_t)count;
memset((uint8_t*)begin(), 0, len);
}
_T* begin() { return m_data; } _T* begin() { return m_data; }
_T* end() { return m_data + m_count; } _T* end() { return m_data + m_count; }

View File

@ -296,7 +296,7 @@ AssemblyItem const& Assembly::append(AssemblyItem const& _i)
AssemblyItem Assembly::newPushLibraryAddress(string const& _identifier) AssemblyItem Assembly::newPushLibraryAddress(string const& _identifier)
{ {
h256 h(dev::sha3(_identifier)); h256 h(dev::keccak256(_identifier));
m_libraries[h] = _identifier; m_libraries[h] = _identifier;
return AssemblyItem(PushLibraryAddress, h); return AssemblyItem(PushLibraryAddress, h);
} }
@ -327,8 +327,10 @@ Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs)
AssemblyItems optimisedItems; AssemblyItems optimisedItems;
for (BasicBlock const& block: cfg.optimisedBlocks()) for (BasicBlock const& block: cfg.optimisedBlocks())
{ {
assertThrow(!!block.startState, OptimizerException, ""); // We used to start with the block's initial state but it caused
CommonSubexpressionEliminator eliminator(*block.startState); // too many inconsistencies.
KnownState emptyState;
CommonSubexpressionEliminator eliminator(emptyState);
auto iter = m_items.begin() + block.begin; auto iter = m_items.begin() + block.begin;
auto const end = m_items.begin() + block.end; auto const end = m_items.begin() + block.end;
while (iter < end) while (iter < end)

View File

@ -45,11 +45,11 @@ public:
AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); }
AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); }
AssemblyItem newData(bytes const& _data) { h256 h(sha3(asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); } AssemblyItem newData(bytes const& _data) { h256 h(dev::keccak256(asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); }
AssemblyItem newSub(Assembly const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); } AssemblyItem newSub(Assembly const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); }
Assembly const& sub(size_t _sub) const { return m_subs.at(_sub); } Assembly const& sub(size_t _sub) const { return m_subs.at(_sub); }
Assembly& sub(size_t _sub) { return m_subs.at(_sub); } Assembly& sub(size_t _sub) { return m_subs.at(_sub); }
AssemblyItem newPushString(std::string const& _data) { h256 h(sha3(_data)); m_strings[h] = _data; return AssemblyItem(PushString, h); } AssemblyItem newPushString(std::string const& _data) { h256 h(dev::keccak256(_data)); m_strings[h] = _data; return AssemblyItem(PushString, h); }
AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); }
AssemblyItem newPushLibraryAddress(std::string const& _identifier); AssemblyItem newPushLibraryAddress(std::string const& _identifier);

View File

@ -257,6 +257,7 @@ Rules::Rules()
{{Instruction::MOD, {0, X}}, [=]{ return u256(0); }}, {{Instruction::MOD, {0, X}}, [=]{ return u256(0); }},
{{Instruction::AND, {X, 0}}, [=]{ return u256(0); }}, {{Instruction::AND, {X, 0}}, [=]{ return u256(0); }},
{{Instruction::OR, {X, ~u256(0)}}, [=]{ return ~u256(0); }}, {{Instruction::OR, {X, ~u256(0)}}, [=]{ return ~u256(0); }},
{{Instruction::EQ, {X, 0}}, [=]() -> Pattern { return {Instruction::ISZERO, {X}}; } },
// operations involving an expression and itself // operations involving an expression and itself
{{Instruction::AND, {X, X}}, [=]{ return X; }}, {{Instruction::AND, {X, X}}, [=]{ return X; }},
{{Instruction::OR, {X, X}}, [=]{ return X; }}, {{Instruction::OR, {X, X}}, [=]{ return X; }},

View File

@ -378,7 +378,7 @@ KnownState::Id KnownState::applySha3(
for (Id a: arguments) for (Id a: arguments)
data += toBigEndian(*m_expressionClasses->knownConstant(a)); data += toBigEndian(*m_expressionClasses->knownConstant(a));
data.resize(size_t(*l)); data.resize(size_t(*l));
v = m_expressionClasses->find(AssemblyItem(u256(sha3(data)), _location)); v = m_expressionClasses->find(AssemblyItem(u256(dev::keccak256(data)), _location));
} }
else else
v = m_expressionClasses->find(sha3Item, {_start, _length}, true, m_sequenceNumber); v = m_expressionClasses->find(sha3Item, {_start, _length}, true, m_sequenceNumber);

View File

@ -52,17 +52,18 @@ void CodeFragment::finalise(CompilerState const& _cs)
CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM) CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM)
{ {
/* cdebug << "CodeFragment. Locals:"; /*
std::cout << "CodeFragment. Locals:";
for (auto const& i: _s.defs) for (auto const& i: _s.defs)
cdebug << i.first << ":" << toHex(i.second.m_code); std::cout << i.first << ":" << i.second.m_asm.out();
cdebug << "Args:"; std::cout << "Args:";
for (auto const& i: _s.args) for (auto const& i: _s.args)
cdebug << i.first << ":" << toHex(i.second.m_code); std::cout << i.first << ":" << i.second.m_asm.out();
cdebug << "Outers:"; std::cout << "Outers:";
for (auto const& i: _s.outers) for (auto const& i: _s.outers)
cdebug << i.first << ":" << toHex(i.second.m_code); std::cout << i.first << ":" << i.second.m_asm.out();
debugOutAST(cout, _t); debugOutAST(std::cout, _t);
cout << endl << flush; std::cout << endl << flush;
*/ */
switch (_t.which()) switch (_t.which())
{ {

View File

@ -45,13 +45,21 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _error
if (_errors) if (_errors)
{ {
_errors->push_back("Parse error."); _errors->push_back("Parse error.");
_errors->push_back(diagnostic_information(_e)); _errors->push_back(boost::diagnostic_information(_e));
} }
} }
catch (std::exception) catch (std::exception const& _e)
{ {
if (_errors) if (_errors)
_errors->push_back("Parse error."); {
_errors->push_back("Parse exception.");
_errors->push_back(boost::diagnostic_information(_e));
}
}
catch (...)
{
if (_errors)
_errors->push_back("Internal parse exception.");
} }
return bytes(); return bytes();
} }
@ -70,12 +78,22 @@ std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::v
catch (Exception const& _e) catch (Exception const& _e)
{ {
if (_errors) if (_errors)
_errors->push_back(diagnostic_information(_e)); {
_errors->push_back("Parse error.");
_errors->push_back(boost::diagnostic_information(_e));
}
} }
catch (std::exception) catch (std::exception const& _e)
{
if (_errors) {
_errors->push_back("Parse exception.");
_errors->push_back(boost::diagnostic_information(_e));
}
}
catch (...)
{ {
if (_errors) if (_errors)
_errors->push_back("Parse error."); _errors->push_back("Internal parse exception.");
} }
return string(); return string();
} }

View File

@ -45,8 +45,6 @@ CodeFragment const& CompilerState::getDef(std::string const& _s)
void CompilerState::populateStandard() void CompilerState::populateStandard()
{ {
static const string s = "{" static const string s = "{"
"(def 'gav 0x51ba59315b3a95761d0863b05ccc7a7f54703d99)"
"(def 'config 0x661005d2720d855f1d9976f88bb10c1a3398c77f)"
"(def 'allgas (- (gas) 21))" "(def 'allgas (- (gas) 21))"
"(def 'send (to value) (call allgas to value 0 0 0 0))" "(def 'send (to value) (call allgas to value 0 0 0 0))"
"(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))"
@ -60,23 +58,21 @@ void CompilerState::populateStandard()
"(def 'sha3 (val) { [0]:val (sha3 0 32) })" "(def 'sha3 (val) { [0]:val (sha3 0 32) })"
"(def 'sha3pair (a b) { [0]:a [32]:b (sha3 0 64) })" "(def 'sha3pair (a b) { [0]:a [32]:b (sha3 0 64) })"
"(def 'sha3trip (a b c) { [0]:a [32]:b [64]:c (sha3 0 96) })" "(def 'sha3trip (a b c) { [0]:a [32]:b [64]:c (sha3 0 96) })"
"(def 'keccak256 (loc len) (sha3 loc len))"
"(def 'return (val) { [0]:val (return 0 32) })" "(def 'return (val) { [0]:val (return 0 32) })"
"(def 'returnlll (code) (return 0 (lll code 0)) )" "(def 'returnlll (code) (return 0 (lll code 0)) )"
"(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )" "(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )"
"(def 'permcount 0)" "(def 'permcount 0)"
"(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } )" "(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } )"
"(def 'namereg (msg config 0))"
"(def 'coinreg (msg config 1))"
"(def 'gavcoin (msg config 2))"
"(def 'sendgavcoin (to value) { [32]'send [64]:to [96]:value (call allgas gavcoin 0 32 96 0 0) })"
"(def 'regname (name) { [32]'register [64]name (call allgas namereg 0 32 64 0 0) })"
"(def 'regcoin (name) { [32]name (call allgas coinreg 0 32 32 0 0) })"
"(def 'regcoin (name denom) { [32]name [64]denom (call allgas coinreg 0 32 64 0 0) })"
"(def 'ecrecover (r s v hash) { [0] r [32] s [64] v [96] hash (msg allgas 1 0 0 128) })" "(def 'ecrecover (r s v hash) { [0] r [32] s [64] v [96] hash (msg allgas 1 0 0 128) })"
"(def 'sha256 (data datasize) (msg allgas 2 0 data datasize))" "(def 'sha256 (data datasize) (msg allgas 2 0 data datasize))"
"(def 'ripemd160 (data datasize) (msg allgas 3 0 data datasize))" "(def 'ripemd160 (data datasize) (msg allgas 3 0 data datasize))"
"(def 'sha256 (val) { [0]:val (sha256 0 32) })" "(def 'sha256 (val) { [0]:val (sha256 0 32) })"
"(def 'ripemd160 (val) { [0]:val (ripemd160 0 32) })" "(def 'ripemd160 (val) { [0]:val (ripemd160 0 32) })"
"(def 'wei 1)"
"(def 'szabo 1000000000000)"
"(def 'finney 1000000000000000)"
"(def 'ether 1000000000000000000)"
"}"; "}";
CodeFragment::compile(s, *this); CodeFragment::compile(s, *this);
} }

View File

@ -39,6 +39,7 @@ class InvalidName: public CompilerException {};
class InvalidMacroArgs: public CompilerException {}; class InvalidMacroArgs: public CompilerException {};
class InvalidLiteral: public CompilerException {}; class InvalidLiteral: public CompilerException {};
class BareSymbol: public CompilerException {}; class BareSymbol: public CompilerException {};
class ParserException: public CompilerException {};
} }
} }

View File

@ -96,19 +96,13 @@ void dev::eth::parseTreeLLL(string const& _s, sp::utree& o_out)
using symbol_type = sp::basic_string<std::string, sp::utree_type::symbol_type>; using symbol_type = sp::basic_string<std::string, sp::utree_type::symbol_type>;
using it = string::const_iterator; using it = string::const_iterator;
static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;
qi::rule<it, space_type, sp::utree()> element; qi::rule<it, space_type, sp::utree()> element;
qi::rule<it, string()> str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"'; qi::rule<it, string()> str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"';
qi::rule<it, string()> strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;$@()[]{}:\n\t") + '\0'))]; qi::rule<it, string()> strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;$@()[]{}:\n\t") + '\0'))];
qi::rule<it, symbol_type()> symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))]; qi::rule<it, symbol_type()> symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))];
qi::rule<it, string()> intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]]; qi::rule<it, string()> intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]];
qi::rule<it, bigint()> integer = intstr; qi::rule<it, bigint()> integer = intstr;
qi::rule<it, bigint()> multiplier = qi::lit("wei")[qi::_val = 1] | qi::lit("szabo")[qi::_val = szabo] | qi::lit("finney")[qi::_val = finney] | qi::lit("ether")[qi::_val = ether]; qi::rule<it, space_type, sp::utree()> atom = integer[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
qi::rule<it, space_type, bigint()> quantity = integer[qi::_val = qi::_1] >> -multiplier[qi::_val *= qi::_1];
qi::rule<it, space_type, sp::utree()> atom = quantity[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
qi::rule<it, space_type, sp::utree::list_type()> seq = '{' > *element > '}'; qi::rule<it, space_type, sp::utree::list_type()> seq = '{' > *element > '}';
qi::rule<it, space_type, sp::utree::list_type()> mload = '@' > element; qi::rule<it, space_type, sp::utree::list_type()> mload = '@' > element;
qi::rule<it, space_type, sp::utree::list_type()> sload = qi::lit("@@") > element; qi::rule<it, space_type, sp::utree::list_type()> sload = qi::lit("@@") > element;
@ -143,7 +137,8 @@ void dev::eth::parseTreeLLL(string const& _s, sp::utree& o_out)
auto ret = s.cbegin(); auto ret = s.cbegin();
qi::phrase_parse(ret, s.cend(), element, space, qi::skip_flag::dont_postskip, o_out); qi::phrase_parse(ret, s.cend(), element, space, qi::skip_flag::dont_postskip, o_out);
for (auto i = ret; i != s.cend(); ++i) for (auto i = ret; i != s.cend(); ++i)
if (!isspace(*i)) if (!isspace(*i)) {
BOOST_THROW_EXCEPTION(std::exception()); BOOST_THROW_EXCEPTION(ParserException() << errinfo_comment("Non-whitespace left in parser"));
}
} }

View File

@ -24,6 +24,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include "Exceptions.h"
namespace boost { namespace spirit { class utree; } } namespace boost { namespace spirit { class utree; } }
namespace sp = boost::spirit; namespace sp = boost::spirit;

View File

@ -48,6 +48,8 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared<
make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Location::MulMod)), make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Location::MulMod)),
make_shared<MagicVariableDeclaration>("sha3", make_shared<MagicVariableDeclaration>("sha3",
make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Location::SHA3, true)), make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Location::SHA3, true)),
make_shared<MagicVariableDeclaration>("keccak256",
make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Location::SHA3, true)),
make_shared<MagicVariableDeclaration>("log0", make_shared<MagicVariableDeclaration>("log0",
make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Location::Log0)), make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Location::Log0)),
make_shared<MagicVariableDeclaration>("log1", make_shared<MagicVariableDeclaration>("log1",

View File

@ -40,6 +40,12 @@ struct SemVerVersion
std::string prerelease; std::string prerelease;
std::string build; std::string build;
unsigned major() const { return numbers[0]; }
unsigned minor() const { return numbers[1]; }
unsigned patch() const { return numbers[2]; }
bool isPrerelease() const { return !prerelease.empty(); }
explicit SemVerVersion(std::string const& _versionString = "0.0.0"); explicit SemVerVersion(std::string const& _versionString = "0.0.0");
}; };

View File

@ -52,13 +52,22 @@ void SyntaxChecker::endVisit(SourceUnit const& _sourceUnit)
{ {
if (!m_versionPragmaFound) if (!m_versionPragmaFound)
{ {
string errorString("Source file does not specify required compiler version!");
SemVerVersion recommendedVersion{string(VersionString)};
if (!recommendedVersion.isPrerelease())
errorString +=
"Consider adding \"pragma solidity ^" +
to_string(recommendedVersion.major()) +
string(".") +
to_string(recommendedVersion.minor()) +
string(".") +
to_string(recommendedVersion.patch());
string(";\"");
auto err = make_shared<Error>(Error::Type::Warning); auto err = make_shared<Error>(Error::Type::Warning);
*err << *err <<
errinfo_sourceLocation(_sourceUnit.location()) << errinfo_sourceLocation(_sourceUnit.location()) <<
errinfo_comment( errinfo_comment(errorString);
string("Source file does not specify required compiler version! ") +
string("Consider adding \"pragma solidity ^") + VersionNumber + string(";\".")
);
m_errors.push_back(err); m_errors.push_back(err);
} }
} }
@ -67,7 +76,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma)
{ {
solAssert(!_pragma.tokens().empty(), ""); solAssert(!_pragma.tokens().empty(), "");
solAssert(_pragma.tokens().size() == _pragma.literals().size(), ""); solAssert(_pragma.tokens().size() == _pragma.literals().size(), "");
if (_pragma.tokens()[0] != Token::Identifier && _pragma.literals()[0] != "solidity") if (_pragma.tokens()[0] != Token::Identifier || _pragma.literals()[0] != "solidity")
syntaxError(_pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\""); syntaxError(_pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\"");
else else
{ {

View File

@ -609,6 +609,8 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
return false; return false;
pushes = 1; pushes = 1;
} }
else
return false;
for (unsigned i = 0; i < pushes; ++i) for (unsigned i = 0; i < pushes; ++i)
_assembly.append(u256(0)); // just to verify the stack height _assembly.append(u256(0)); // just to verify the stack height
} }
@ -716,11 +718,10 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
{ {
if (ref->dataStoredIn(DataLocation::Storage)) if (ref->dataStoredIn(DataLocation::Storage))
{ {
auto err = make_shared<Error>(Error::Type::Warning); warning(
*err << varDecl.location(),
errinfo_sourceLocation(varDecl.location()) << "Uninitialized storage pointer. Did you mean '<type> memory " + varDecl.name() + "'?"
errinfo_comment("Uninitialized storage pointer. Did you mean '<type> memory " + varDecl.name() + "'?"); );
m_errors.push_back(err);
} }
} }
varDecl.accept(*this); varDecl.accept(*this);
@ -879,6 +880,10 @@ bool TypeChecker::visit(Conditional const& _conditional)
TypePointer trueType = type(_conditional.trueExpression())->mobileType(); TypePointer trueType = type(_conditional.trueExpression())->mobileType();
TypePointer falseType = type(_conditional.falseExpression())->mobileType(); TypePointer falseType = type(_conditional.falseExpression())->mobileType();
if (!trueType)
fatalTypeError(_conditional.trueExpression().location(), "Invalid mobile type.");
if (!falseType)
fatalTypeError(_conditional.falseExpression().location(), "Invalid mobile type.");
TypePointer commonType = Type::commonType(trueType, falseType); TypePointer commonType = Type::commonType(trueType, falseType);
if (!commonType) if (!commonType)
@ -985,10 +990,16 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
types.push_back(type(*components[i])); types.push_back(type(*components[i]));
if (_tuple.isInlineArray()) if (_tuple.isInlineArray())
solAssert(!!types[i], "Inline array cannot have empty components"); solAssert(!!types[i], "Inline array cannot have empty components");
if (i == 0 && _tuple.isInlineArray()) if (_tuple.isInlineArray())
inlineArrayType = types[i]->mobileType(); {
else if (_tuple.isInlineArray() && inlineArrayType) if ((i == 0 || inlineArrayType) && !types[i]->mobileType())
inlineArrayType = Type::commonType(inlineArrayType, types[i]->mobileType()); fatalTypeError(components[i]->location(), "Invalid mobile type.");
if (i == 0)
inlineArrayType = types[i]->mobileType();
else if (inlineArrayType)
inlineArrayType = Type::commonType(inlineArrayType, types[i]->mobileType());
}
} }
else else
types.push_back(TypePointer()); types.push_back(TypePointer());
@ -1375,6 +1386,11 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
} }
else if (exprType->category() == Type::Category::FixedBytes) else if (exprType->category() == Type::Category::FixedBytes)
annotation.isLValue = false; annotation.isLValue = false;
else if (TypeType const* typeType = dynamic_cast<decltype(typeType)>(exprType.get()))
{
if (ContractType const* contractType = dynamic_cast<decltype(contractType)>(typeType->actualType().get()))
annotation.isLValue = annotation.referencedDeclaration->isLValue();
}
return false; return false;
} }

View File

@ -151,7 +151,7 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter
if (signaturesSeen.count(functionSignature) == 0) if (signaturesSeen.count(functionSignature) == 0)
{ {
signaturesSeen.insert(functionSignature); signaturesSeen.insert(functionSignature);
FixedHash<4> hash(dev::sha3(functionSignature)); FixedHash<4> hash(dev::keccak256(functionSignature));
m_interfaceFunctionList->push_back(make_pair(hash, fun)); m_interfaceFunctionList->push_back(make_pair(hash, fun));
} }
} }
@ -189,6 +189,7 @@ vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
m_inheritableMembers.reset(new vector<Declaration const*>()); m_inheritableMembers.reset(new vector<Declaration const*>());
auto addInheritableMember = [&](Declaration const* _decl) auto addInheritableMember = [&](Declaration const* _decl)
{ {
solAssert(_decl, "addInheritableMember got a nullpointer.");
if (memberSeen.count(_decl->name()) == 0 && _decl->isVisibleInDerivedContracts()) if (memberSeen.count(_decl->name()) == 0 && _decl->isVisibleInDerivedContracts())
{ {
memberSeen.insert(_decl->name()); memberSeen.insert(_decl->name());
@ -204,6 +205,9 @@ vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
for (StructDefinition const* s: definedStructs()) for (StructDefinition const* s: definedStructs())
addInheritableMember(s); addInheritableMember(s);
for (EnumDefinition const* e: definedEnums())
addInheritableMember(e);
} }
return *m_inheritableMembers; return *m_inheritableMembers;
} }

View File

@ -623,7 +623,7 @@ public:
virtual bool isLValue() const override; virtual bool isLValue() const override;
virtual bool isPartOfExternalInterface() const override { return isPublic(); } virtual bool isPartOfExternalInterface() const override { return isPublic(); }
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(scope()); } bool isLocalVariable() const { return !!dynamic_cast<CallableDeclaration const*>(scope()); }
/// @returns true if this variable is a parameter or return parameter of a function. /// @returns true if this variable is a parameter or return parameter of a function.
bool isCallableParameter() const; bool isCallableParameter() const;
/// @returns true if this variable is a parameter (not return parameter) of an external function. /// @returns true if this variable is a parameter (not return parameter) of an external function.

View File

@ -23,6 +23,7 @@
#include <libsolidity/ast/Types.h> #include <libsolidity/ast/Types.h>
#include <limits> #include <limits>
#include <boost/range/adaptor/reversed.hpp> #include <boost/range/adaptor/reversed.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
@ -197,7 +198,9 @@ TypePointer Type::forLiteral(Literal const& _literal)
TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b) TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b)
{ {
if (_b->isImplicitlyConvertibleTo(*_a)) if (!_a || !_b)
return TypePointer();
else if (_b->isImplicitlyConvertibleTo(*_a))
return _a; return _a;
else if (_a->isImplicitlyConvertibleTo(*_b)) else if (_a->isImplicitlyConvertibleTo(*_b))
return _b; return _b;
@ -241,7 +244,8 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
seenFunctions.insert(function); seenFunctions.insert(function);
FunctionType funType(*function, false); FunctionType funType(*function, false);
if (auto fun = funType.asMemberFunction(true, true)) if (auto fun = funType.asMemberFunction(true, true))
members.push_back(MemberList::Member(function->name(), fun, function)); if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
members.push_back(MemberList::Member(function->name(), fun, function));
} }
} }
return members; return members;
@ -481,7 +485,7 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal
!all_of(radixPoint + 1, _literal.value().end(), ::isdigit) || !all_of(radixPoint + 1, _literal.value().end(), ::isdigit) ||
!all_of(_literal.value().begin(), radixPoint, ::isdigit) !all_of(_literal.value().begin(), radixPoint, ::isdigit)
) )
throw; return make_tuple(false, rational(0));
//Only decimal notation allowed here, leading zeros would switch to octal. //Only decimal notation allowed here, leading zeros would switch to octal.
auto fractionalBegin = find_if_not( auto fractionalBegin = find_if_not(
radixPoint + 1, radixPoint + 1,
@ -574,7 +578,11 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{ {
FixedBytesType const& fixedBytes = dynamic_cast<FixedBytesType const&>(_convertTo); FixedBytesType const& fixedBytes = dynamic_cast<FixedBytesType const&>(_convertTo);
if (!isFractional()) if (!isFractional())
return fixedBytes.numBytes() * 8 >= integerType()->numBits(); {
if (integerType())
return fixedBytes.numBytes() * 8 >= integerType()->numBits();
return false;
}
else else
return false; return false;
} }
@ -700,6 +708,34 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
value = rational(denominator, numerator); value = rational(denominator, numerator);
break; break;
} }
case Token::SHL:
{
using boost::multiprecision::pow;
if (fractional)
return TypePointer();
else if (other.m_value < 0)
return TypePointer();
else if (other.m_value > numeric_limits<uint32_t>::max())
return TypePointer();
uint32_t exponent = other.m_value.numerator().convert_to<uint32_t>();
value = m_value.numerator() * pow(bigint(2), exponent);
break;
}
// NOTE: we're using >> (SAR) to denote right shifting. The type of the LValue
// determines the resulting type and the type of shift (SAR or SHR).
case Token::SAR:
{
using boost::multiprecision::pow;
if (fractional)
return TypePointer();
else if (other.m_value < 0)
return TypePointer();
else if (other.m_value > numeric_limits<uint32_t>::max())
return TypePointer();
uint32_t exponent = other.m_value.numerator().convert_to<uint32_t>();
value = rational(m_value.numerator() / pow(bigint(2), exponent), 1);
break;
}
default: default:
return TypePointer(); return TypePointer();
} }
@ -1291,7 +1327,10 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) con
if (m_super) if (m_super)
{ {
// add the most derived of all functions which are visible in derived contracts // add the most derived of all functions which are visible in derived contracts
for (ContractDefinition const* base: m_contract.annotation().linearizedBaseContracts) auto bases = m_contract.annotation().linearizedBaseContracts;
solAssert(bases.size() >= 1, "linearizedBaseContracts should at least contain the most derived contract.");
// `sliced(1, ...)` ignores the most derived contract, which should not be searchable from `super`.
for (ContractDefinition const* base: bases | boost::adaptors::sliced(1, bases.size()))
for (FunctionDefinition const* function: base->definedFunctions()) for (FunctionDefinition const* function: base->definedFunctions())
{ {
if (!function->isVisibleInDerivedContracts()) if (!function->isVisibleInDerivedContracts())
@ -1624,7 +1663,17 @@ TypePointer TupleType::mobileType() const
{ {
TypePointers mobiles; TypePointers mobiles;
for (auto const& c: components()) for (auto const& c: components())
mobiles.push_back(c ? c->mobileType() : TypePointer()); {
if (c)
{
auto mt = c->mobileType();
if (!mt)
return TypePointer();
mobiles.push_back(mt);
}
else
mobiles.push_back(TypePointer());
}
return make_shared<TupleType>(mobiles); return make_shared<TupleType>(mobiles);
} }
@ -2033,7 +2082,7 @@ string FunctionType::externalSignature() const
u256 FunctionType::externalIdentifier() const u256 FunctionType::externalIdentifier() const
{ {
return FixedHash<4>::Arith(FixedHash<4>(dev::sha3(externalSignature()))); return FixedHash<4>::Arith(FixedHash<4>(dev::keccak256(externalSignature())));
} }
TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) TypePointers FunctionType::parseElementaryTypeVector(strings const& _types)
@ -2065,6 +2114,9 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con
FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound) const FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound) const
{ {
if (_bound && m_parameterTypes.empty())
return FunctionTypePointer();
TypePointers parameterTypes; TypePointers parameterTypes;
for (auto const& t: m_parameterTypes) for (auto const& t: m_parameterTypes)
{ {

View File

@ -623,6 +623,7 @@ public:
} }
virtual unsigned storageBytes() const override { return 20; } virtual unsigned storageBytes() const override { return 20; }
virtual bool canLiveOutsideStorage() const override { return true; } virtual bool canLiveOutsideStorage() const override { return true; }
virtual unsigned sizeOnStack() const override { return m_super ? 0 : 1; }
virtual bool isValueType() const override { return true; } virtual bool isValueType() const override { return true; }
virtual std::string toString(bool _short) const override; virtual std::string toString(bool _short) const override;
virtual std::string canonicalName(bool _addDataLocation) const override; virtual std::string canonicalName(bool _addDataLocation) const override;
@ -871,7 +872,12 @@ public:
m_isConstant(_isConstant), m_isConstant(_isConstant),
m_isPayable(_isPayable), m_isPayable(_isPayable),
m_declaration(_declaration) m_declaration(_declaration)
{} {
solAssert(
!m_bound || !m_parameterTypes.empty(),
"Attempted construction of bound function without self type"
);
}
TypePointers parameterTypes() const; TypePointers parameterTypes() const;
std::vector<std::string> parameterNames() const; std::vector<std::string> parameterNames() const;
@ -939,8 +945,9 @@ public:
/// removed and the location of reference types is changed from CallData to Memory. /// removed and the location of reference types is changed from CallData to Memory.
/// This is needed if external functions are called on other contracts, as they cannot return /// This is needed if external functions are called on other contracts, as they cannot return
/// dynamic values. /// dynamic values.
/// Returns empty shared pointer on a failure. Namely, if a bound function has no parameters.
/// @param _inLibrary if true, uses DelegateCall as location. /// @param _inLibrary if true, uses DelegateCall as location.
/// @param _bound if true, the argumenst are placed as `arg1.functionName(arg2, ..., argn)`. /// @param _bound if true, the arguments are placed as `arg1.functionName(arg2, ..., argn)`.
FunctionTypePointer asMemberFunction(bool _inLibrary, bool _bound = false) const; FunctionTypePointer asMemberFunction(bool _inLibrary, bool _bound = false) const;
private: private:

View File

@ -368,8 +368,11 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << Instruction::MUL; m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << Instruction::MUL;
} }
else if (targetTypeCategory == Type::Category::Enum) else if (targetTypeCategory == Type::Category::Enum)
{
solAssert(_typeOnStack.mobileType(), "");
// just clean // just clean
convertType(_typeOnStack, *_typeOnStack.mobileType(), true); convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
}
else if (targetTypeCategory == Type::Category::FixedPoint) else if (targetTypeCategory == Type::Category::FixedPoint)
{ {
solAssert( solAssert(

View File

@ -575,7 +575,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
return true; return true;
} }
); );
solAssert(errors.empty(), "Code generation for inline assembly with errors requested."); solAssert(Error::containsOnlyWarnings(errors), "Code generation for inline assembly with errors requested.");
m_context.setStackOffset(startStackHeight); m_context.setStackOffset(startStackHeight);
return false; return false;
} }

View File

@ -56,8 +56,10 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
if (_varDecl.annotation().type->dataStoredIn(DataLocation::Storage)) if (_varDecl.annotation().type->dataStoredIn(DataLocation::Storage))
{ {
// reference type, only convert value to mobile type and do final conversion in storeValue. // reference type, only convert value to mobile type and do final conversion in storeValue.
utils().convertType(*type, *type->mobileType()); auto mt = type->mobileType();
type = type->mobileType(); solAssert(mt, "");
utils().convertType(*type, *mt);
type = mt;
} }
else else
{ {
@ -670,7 +672,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
} }
if (!event.isAnonymous()) if (!event.isAnonymous())
{ {
m_context << u256(h256::Arith(dev::sha3(function.externalSignature()))); m_context << u256(h256::Arith(dev::keccak256(function.externalSignature())));
++numIndexed; ++numIndexed;
} }
solAssert(numIndexed <= 4, "Too many indexed arguments."); solAssert(numIndexed <= 4, "Too many indexed arguments.");
@ -861,11 +863,12 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
} }
// Special processing for TypeType because we do not want to visit the library itself // Special processing for TypeType because we do not want to visit the library itself
// for internal functions. // for internal functions, or enum/struct definitions.
if (TypeType const* type = dynamic_cast<TypeType const*>(_memberAccess.expression().annotation().type.get())) if (TypeType const* type = dynamic_cast<TypeType const*>(_memberAccess.expression().annotation().type.get()))
{ {
if (dynamic_cast<ContractType const*>(type->actualType().get())) if (dynamic_cast<ContractType const*>(type->actualType().get()))
{ {
solAssert(_memberAccess.annotation().type, "_memberAccess has no type");
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get())) if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
{ {
if (funType->location() != FunctionType::Location::Internal) if (funType->location() != FunctionType::Location::Internal)
@ -883,6 +886,12 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
m_context << m_context.functionEntryLabel(*function).pushTag(); m_context << m_context.functionEntryLabel(*function).pushTag();
} }
} }
else if (dynamic_cast<TypeType const*>(_memberAccess.annotation().type.get()))
{
// no-op
}
else if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
appendVariable(*variable, static_cast<Expression const&>(_memberAccess));
else else
_memberAccess.expression().accept(*this); _memberAccess.expression().accept(*this);
} }
@ -1196,15 +1205,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration)) else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
m_context << m_context.virtualFunctionEntryLabel(*functionDef).pushTag(); m_context << m_context.virtualFunctionEntryLabel(*functionDef).pushTag();
else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration)) else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration))
{ appendVariable(*variable, static_cast<Expression const&>(_identifier));
if (!variable->isConstant())
setLValueFromDeclaration(*declaration, _identifier);
else
{
variable->value()->accept(*this);
utils().convertType(*variable->value()->annotation().type, *variable->annotation().type);
}
}
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration)) else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
{ {
if (contract->isLibrary()) if (contract->isLibrary())
@ -1432,11 +1433,17 @@ void ExpressionCompiler::appendExternalFunctionCall(
// Evaluate arguments. // Evaluate arguments.
TypePointers argumentTypes; TypePointers argumentTypes;
TypePointers parameterTypes = _functionType.parameterTypes(); TypePointers parameterTypes = _functionType.parameterTypes();
bool manualFunctionId = bool manualFunctionId = false;
if (
(funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode || funKind == FunctionKind::BareDelegateCall) && (funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode || funKind == FunctionKind::BareDelegateCall) &&
!_arguments.empty() && !_arguments.empty()
_arguments.front()->annotation().type->mobileType()->calldataEncodedSize(false) == )
{
solAssert(_arguments.front()->annotation().type->mobileType(), "");
manualFunctionId =
_arguments.front()->annotation().type->mobileType()->calldataEncodedSize(false) ==
CompilerUtils::dataStartOffset; CompilerUtils::dataStartOffset;
}
if (manualFunctionId) if (manualFunctionId)
{ {
// If we have a Bare* and the first type has exactly 4 bytes, use it as // If we have a Bare* and the first type has exactly 4 bytes, use it as
@ -1633,6 +1640,17 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
utils().storeInMemoryDynamic(_expectedType); utils().storeInMemoryDynamic(_expectedType);
} }
void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Expression const& _expression)
{
if (!_variable.isConstant())
setLValueFromDeclaration(_variable, _expression);
else
{
_variable.value()->accept(*this);
utils().convertType(*_variable.value()->annotation().type, *_variable.annotation().type);
}
}
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression)
{ {
if (m_context.isLocalVariable(&_declaration)) if (m_context.isLocalVariable(&_declaration))

View File

@ -103,6 +103,8 @@ private:
/// expected to be on the stack and is updated by this call. /// expected to be on the stack and is updated by this call.
void appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression); void appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression);
/// Appends code for a variable that might be a constant or not
void appendVariable(VariableDeclaration const& _variable, Expression const& _expression);
/// Sets the current LValue to a new one (of the appropriate type) from the given declaration. /// Sets the current LValue to a new one (of the appropriate type) from the given declaration.
/// Also retrieves the value if it was not requested by @a _expression. /// Also retrieves the value if it was not requested by @a _expression.
void setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression); void setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression);

View File

@ -757,6 +757,20 @@ bool Why3Translator::visit(Literal const& _literal)
return false; return false;
} }
bool Why3Translator::visit(PragmaDirective const& _pragma)
{
if (_pragma.tokens().empty())
error(_pragma, "Not supported");
else if (_pragma.literals().empty())
error(_pragma, "Not supported");
else if (_pragma.literals()[0] != "solidity")
error(_pragma, "Not supported");
else if (_pragma.tokens()[0] != Token::Identifier)
error(_pragma, "A literal 'solidity' is not an identifier. Strange");
return false;
}
bool Why3Translator::isStateVariable(VariableDeclaration const* _var) const bool Why3Translator::isStateVariable(VariableDeclaration const* _var) const
{ {
return contains(m_currentContract.stateVariables, _var); return contains(m_currentContract.stateVariables, _var);

View File

@ -94,6 +94,7 @@ private:
virtual bool visit(IndexAccess const& _node) override; virtual bool visit(IndexAccess const& _node) override;
virtual bool visit(Identifier const& _node) override; virtual bool visit(Identifier const& _node) override;
virtual bool visit(Literal const& _node) override; virtual bool visit(Literal const& _node) override;
virtual bool visit(PragmaDirective const& _node) override;
virtual bool visitNode(ASTNode const& _node) override virtual bool visitNode(ASTNode const& _node) override
{ {

View File

@ -77,7 +77,7 @@ Expression =
| Expression? (',' Expression) | Expression? (',' Expression)
| PrimaryExpression | PrimaryExpression
PrimaryExpression = Identifier | BooleanLiteral | NumberLiteral | StringLiteral PrimaryExpression = Identifier | BooleanLiteral | NumberLiteral | HexLiteral | StringLiteral
FunctionCall = ( PrimaryExpression | NewExpression | TypeName ) ( ( '.' Identifier ) | ( '[' Expression ']' ) )* '(' Expression? ( ',' Expression )* ')' FunctionCall = ( PrimaryExpression | NewExpression | TypeName ) ( ( '.' Identifier ) | ( '[' Expression ']' ) )* '(' Expression? ( ',' Expression )* ')'
NewExpression = 'new' Identifier NewExpression = 'new' Identifier
@ -88,8 +88,8 @@ BooleanLiteral = 'true' | 'false'
NumberLiteral = '0x'? [0-9]+ (' ' NumberUnit)? NumberLiteral = '0x'? [0-9]+ (' ' NumberUnit)?
NumberUnit = 'wei' | 'szabo' | 'finney' | 'ether' NumberUnit = 'wei' | 'szabo' | 'finney' | 'ether'
| 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years'
HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')
StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"' StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"'
Identifier = [a-zA-Z_] [a-zA-Z_0-9]* Identifier = [a-zA-Z_] [a-zA-Z_0-9]*
ElementaryTypeName = 'address' | 'bool' | 'string' | 'var' ElementaryTypeName = 'address' | 'bool' | 'string' | 'var'

View File

@ -23,6 +23,7 @@
#include <libsolidity/inlineasm/AsmCodeGen.h> #include <libsolidity/inlineasm/AsmCodeGen.h>
#include <memory> #include <memory>
#include <functional> #include <functional>
#include <libdevcore/CommonIO.h>
#include <libevmasm/Assembly.h> #include <libevmasm/Assembly.h>
#include <libevmasm/SourceLocation.h> #include <libevmasm/SourceLocation.h>
#include <libevmasm/Instruction.h> #include <libevmasm/Instruction.h>
@ -213,10 +214,31 @@ public:
void operator()(assembly::Block const& _block) void operator()(assembly::Block const& _block)
{ {
size_t numVariables = m_state.variables.size(); size_t numVariables = m_state.variables.size();
int deposit = m_state.assembly.deposit();
std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this)); std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this));
// pop variables deposit = m_state.assembly.deposit() - deposit;
// we deliberately do not check stack height
m_state.assembly.setSourceLocation(_block.location); m_state.assembly.setSourceLocation(_block.location);
// issue warnings for stack height discrepancies
if (deposit < 0)
{
m_state.addError(
Error::Type::Warning,
"Inline assembly block is not balanced. It takes " + toString(-deposit) + " item(s) from the stack.",
_block.location
);
}
else if (deposit > 0)
{
m_state.addError(
Error::Type::Warning,
"Inline assembly block is not balanced. It leaves " + toString(deposit) + " item(s) on the stack.",
_block.location
);
}
// pop variables
while (m_state.variables.size() > numVariables) while (m_state.variables.size() > numVariables)
{ {
m_state.assembly.append(solidity::Instruction::POP); m_state.assembly.append(solidity::Instruction::POP);

View File

@ -95,7 +95,9 @@ assembly::Statement Parser::parseStatement()
fatalParserError("Label name / variable name must precede \":\"."); fatalParserError("Label name / variable name must precede \":\".");
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement); assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
m_scanner->next(); m_scanner->next();
if (m_scanner->currentToken() == Token::Assign) // identifier:=: should be parsed as identifier: =: (i.e. a label),
// while identifier:= (being followed by a non-colon) as identifier := (assignment).
if (m_scanner->currentToken() == Token::Assign && m_scanner->peekNextToken() != Token::Colon)
{ {
// functional assignment // functional assignment
FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location); FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location);
@ -133,6 +135,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
// Allowed instructions, lowercase names. // Allowed instructions, lowercase names.
static map<string, dev::solidity::Instruction> s_instructions; static map<string, dev::solidity::Instruction> s_instructions;
if (s_instructions.empty()) if (s_instructions.empty())
{
for (auto const& instruction: solidity::c_instructions) for (auto const& instruction: solidity::c_instructions)
{ {
if ( if (
@ -141,24 +144,29 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
) )
continue; continue;
string name = instruction.first; string name = instruction.first;
if (instruction.second == solidity::Instruction::SUICIDE)
name = "selfdestruct";
transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); }); transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
s_instructions[name] = instruction.second; s_instructions[name] = instruction.second;
} }
// add alias for selfdestruct
s_instructions["selfdestruct"] = solidity::Instruction::SUICIDE;
}
Statement ret; Statement ret;
switch (m_scanner->currentToken()) switch (m_scanner->currentToken())
{ {
case Token::Identifier: case Token::Identifier:
case Token::Return: case Token::Return:
case Token::Byte: case Token::Byte:
case Token::Address:
{ {
string literal; string literal;
if (m_scanner->currentToken() == Token::Return) if (m_scanner->currentToken() == Token::Return)
literal = "return"; literal = "return";
else if (m_scanner->currentToken() == Token::Byte) else if (m_scanner->currentToken() == Token::Byte)
literal = "byte"; literal = "byte";
else if (m_scanner->currentToken() == Token::Address)
literal = "address";
else else
literal = m_scanner->currentLiteral(); literal = m_scanner->currentLiteral();
// first search the set of instructions. // first search the set of instructions.

View File

@ -21,8 +21,10 @@
* Full-stack compiler that converts a source code string to bytecode. * Full-stack compiler that converts a source code string to bytecode.
*/ */
#include <boost/algorithm/string.hpp> #include <libsolidity/interface/CompilerStack.h>
#include <boost/filesystem.hpp>
#include <libsolidity/interface/Version.h>
#include <libsolidity/analysis/SemVerHandler.h>
#include <libsolidity/ast/AST.h> #include <libsolidity/ast/AST.h>
#include <libsolidity/parsing/Scanner.h> #include <libsolidity/parsing/Scanner.h>
#include <libsolidity/parsing/Parser.h> #include <libsolidity/parsing/Parser.h>
@ -32,12 +34,15 @@
#include <libsolidity/analysis/DocStringAnalyser.h> #include <libsolidity/analysis/DocStringAnalyser.h>
#include <libsolidity/analysis/SyntaxChecker.h> #include <libsolidity/analysis/SyntaxChecker.h>
#include <libsolidity/codegen/Compiler.h> #include <libsolidity/codegen/Compiler.h>
#include <libsolidity/interface/CompilerStack.h>
#include <libsolidity/interface/InterfaceHandler.h> #include <libsolidity/interface/InterfaceHandler.h>
#include <libsolidity/formal/Why3Translator.h> #include <libsolidity/formal/Why3Translator.h>
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::solidity; using namespace dev::solidity;
@ -100,6 +105,13 @@ bool CompilerStack::parse()
m_errors.clear(); m_errors.clear();
m_parseSuccessful = false; m_parseSuccessful = false;
if (SemVerVersion{string(VersionString)}.isPrerelease())
{
auto err = make_shared<Error>(Error::Type::Warning);
*err << errinfo_comment("This is a pre-release compiler version, please do not use it in production.");
m_errors.push_back(err);
}
vector<string> sourcesToParse; vector<string> sourcesToParse;
for (auto const& s: m_sources) for (auto const& s: m_sources)
sourcesToParse.push_back(s.first); sourcesToParse.push_back(s.first);
@ -302,7 +314,7 @@ dev::h256 CompilerStack::contractCodeHash(string const& _contractName) const
if (obj.bytecode.empty() || !obj.linkReferences.empty()) if (obj.bytecode.empty() || !obj.linkReferences.empty())
return dev::h256(); return dev::h256();
else else
return dev::sha3(obj.bytecode); return dev::keccak256(obj.bytecode);
} }
Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const

View File

@ -136,7 +136,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
ExpressionClasses& classes = state->expressionClasses(); ExpressionClasses& classes = state->expressionClasses();
using Id = ExpressionClasses::Id; using Id = ExpressionClasses::Id;
using Ids = vector<Id>; using Ids = vector<Id>;
Id hashValue = classes.find(u256(FixedHash<4>::Arith(FixedHash<4>(dev::sha3(_signature))))); Id hashValue = classes.find(u256(FixedHash<4>::Arith(FixedHash<4>(dev::keccak256(_signature)))));
Id calldata = classes.find(Instruction::CALLDATALOAD, Ids{classes.find(u256(0))}); Id calldata = classes.find(Instruction::CALLDATALOAD, Ids{classes.find(u256(0))});
classes.forceEqual(hashValue, Instruction::DIV, Ids{ classes.forceEqual(hashValue, Instruction::DIV, Ids{
calldata, calldata,

0
prerelease.txt Normal file
View File

View File

@ -29,7 +29,12 @@
set -e set -e
if [[ "$OSTYPE" != "darwin"* ]]; then if [[ "$OSTYPE" != "darwin"* ]]; then
date -u +"nightly.%Y.%-m.%-d" > prerelease.txt if [ "$TRAVIS_BRANCH" = release ]
then
echo -n > prerelease.txt
else
date -u +"nightly.%Y.%-m.%-d" > prerelease.txt
fi
./scripts/travis-emscripten/install_deps.sh ./scripts/travis-emscripten/install_deps.sh
docker run -v $(pwd):/src trzeci/emscripten:sdk-tag-1.35.4-64bit ./scripts/travis-emscripten/build_emscripten.sh docker run -v $(pwd):/src trzeci/emscripten:sdk-tag-1.35.4-64bit ./scripts/travis-emscripten/build_emscripten.sh
fi fi

24
scripts/isolateTests.py Executable file
View File

@ -0,0 +1,24 @@
#!/usr/bin/python
#
# This script reads C++ source files and writes all
# multi-line strings into individual files.
# This can be used to extract the Solidity test cases
# into files for e.g. fuzz testing as
# scripts/isolateTests.py tests/libsolidity/SolidityEndToEndTest.cpp
import sys
lines = sys.stdin.read().split('\n')
inside = False
tests = []
for l in lines:
if inside:
if l.strip().endswith(')";'):
inside = False
else:
tests[-1] += l + '\n'
else:
if l.strip().endswith('R"('):
inside = True
tests += ['']
for i in range(len(tests)):
open('test%d.sol' % i, 'w').write(tests[i])

View File

@ -59,7 +59,7 @@ commitdate=`git show --format=%ci HEAD | head -n 1 | cut - -b1-10 | sed -e 's/-0
echo "$commithash" > commit_hash.txt echo "$commithash" > commit_hash.txt
if [ $branch = develop ] if [ $branch = develop ]
then then
debversion="$version-nightly-$commitdate-$commithash" debversion="$version-develop-$commitdate-$commithash"
else else
debversion="$version" debversion="$version"
echo -n > prerelease.txt # proper release echo -n > prerelease.txt # proper release

View File

@ -54,21 +54,45 @@ git config user.name "travis"
git config user.email "chris@ethereum.org" git config user.email "chris@ethereum.org"
git checkout -B gh-pages origin/gh-pages git checkout -B gh-pages origin/gh-pages
git clean -f -d -x git clean -f -d -x
# We only want one release per day and we do not want to push the same commit twice.
if ls ./bin/soljson-"$VER-nightly.$DATE"-*.js || ls ./bin/soljson-*"commit.$COMMIT.js"
FULLVERSION=INVALID
if [ "$TRAVIS_BRANCH" = release ]
then then
echo "Not publishing, we already published this version today." # We only want one file with this version
exit 0 if ls ./bin/soljson-"$VER+"*.js
then
echo "Not publishing, we already published this version."
exit 0
fi
FULLVERSION="$VER+commit.$COMMIT"
elif [ "$TRAVIS_BRANCH" = develop ]
then
# We only want one release per day and we do not want to push the same commit twice.
if ls ./bin/soljson-"$VER-nightly.$DATE"*.js || ls ./bin/soljson-*"commit.$COMMIT.js"
then
echo "Not publishing, we already published this version today."
exit 0
fi
FULLVERSION="$VER-nightly.$DATE+commit.$COMMIT"
else
echo "Not publishing, wrong branch."
exit 0
fi fi
NEWFILE=./bin/"soljson-$FULLVERSION.js"
# Prepare for update script
npm install
# This file is assumed to be the product of the build_emscripten.sh script. # This file is assumed to be the product of the build_emscripten.sh script.
cp ../soljson.js ./bin/"soljson-$VER-nightly.$DATE+commit.$COMMIT.js" cp ../soljson.js "$NEWFILE"
node ./update
cd bin # Run update script
LATEST=$(ls -r soljson-v* | head -n 1) npm run update
cp "$LATEST" soljson-latest.js
cp soljson-latest.js ../soljson.js # Publish updates
git add . git add "$NEWFILE"
git add ../soljson.js git commit -a -m "Added compiler version $FULLVERSION"
git commit -m "Added compiler version $LATEST"
git push origin gh-pages git push origin gh-pages

View File

@ -401,7 +401,10 @@ Usage: solc [options] [input_file...]
Compiles the given Solidity input files (or the standard input if none given or Compiles the given Solidity input files (or the standard input if none given or
"-" is used as a file name) and outputs the components specified in the options "-" is used as a file name) and outputs the components specified in the options
at standard output or in files in the output directory, if specified. at standard output or in files in the output directory, if specified.
Example: solc --bin -o /tmp/solcoutput contract.sol Imports are automatically read from the filesystem, but it is also possible to
remap paths using the context:prefix=path syntax.
Example:
solc --bin -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol
Allowed options)", Allowed options)",
po::options_description::m_default_line_length, po::options_description::m_default_line_length,
@ -471,7 +474,7 @@ Allowed options)",
try try
{ {
po::command_line_parser cmdLineParser(_argc, _argv); po::command_line_parser cmdLineParser(_argc, _argv);
cmdLineParser.options(allOptions).positional(filesPositions).allow_unregistered(); cmdLineParser.options(allOptions).positional(filesPositions);
po::store(cmdLineParser.run(), m_args); po::store(cmdLineParser.run(), m_args);
} }
catch (po::error const& _exception) catch (po::error const& _exception)

View File

@ -2,10 +2,10 @@ contract Token {
event Transfer(address indexed _from, address indexed _to, uint256 _value); event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value);
function totalSupply() constant returns (uint256 supply) {} function totalSupply() constant returns (uint256 supply);
function balanceOf(address _owner) constant returns (uint256 balance) {} function balanceOf(address _owner) constant returns (uint256 balance);
function transfer(address _to, uint256 _value) returns (bool success) {} function transfer(address _to, uint256 _value) returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {} function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
function approve(address _spender, uint256 _value) returns (bool success) {} function approve(address _spender, uint256 _value) returns (bool success);
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {} function allowance(address _owner, address _spender) constant returns (uint256 remaining);
} }

View File

@ -588,7 +588,7 @@ BOOST_AUTO_TEST_CASE(revoke_addOwner)
BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
// add a new owner // add a new owner
Address deployer = m_sender; Address deployer = m_sender;
h256 opHash = sha3(FixedHash<4>(dev::sha3("addOwner(address)")).asBytes() + h256(0x33).asBytes()); h256 opHash = dev::keccak256(FixedHash<4>(dev::keccak256("addOwner(address)")).asBytes() + h256(0x33).asBytes());
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x33)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x33)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x33)) == encodeArgs(false)); BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x33)) == encodeArgs(false));
m_sender = account(0); m_sender = account(0);

View File

@ -82,7 +82,7 @@ public:
{ {
u256 gasUsed = 0; u256 gasUsed = 0;
GasMeter::GasConsumption gas; GasMeter::GasConsumption gas;
FixedHash<4> hash(dev::sha3(_sig)); FixedHash<4> hash(dev::keccak256(_sig));
for (bytes const& arguments: _argumentVariants) for (bytes const& arguments: _argumentVariants)
{ {
sendMessage(hash.asBytes() + arguments, false, 0); sendMessage(hash.asBytes() + arguments, false, 0);

View File

@ -51,7 +51,7 @@ bool successParse(std::string const& _source, bool _assemble = false)
if (_assemble) if (_assemble)
{ {
stack.assemble(); stack.assemble();
if (!stack.errors().empty()) if (!stack.errors().empty() && !Error::containsOnlyWarnings(stack.errors()))
return false; return false;
} }
} }
@ -87,9 +87,14 @@ BOOST_AUTO_TEST_CASE(simple_instructions)
BOOST_CHECK(successParse("{ dup1 dup1 mul dup1 sub }")); BOOST_CHECK(successParse("{ dup1 dup1 mul dup1 sub }"));
} }
BOOST_AUTO_TEST_CASE(suicide_selfdestruct)
{
BOOST_CHECK(successParse("{ suicide selfdestruct }"));
}
BOOST_AUTO_TEST_CASE(keywords) BOOST_AUTO_TEST_CASE(keywords)
{ {
BOOST_CHECK(successParse("{ byte return }")); BOOST_CHECK(successParse("{ byte return address }"));
} }
BOOST_AUTO_TEST_CASE(constants) BOOST_AUTO_TEST_CASE(constants)
@ -152,6 +157,18 @@ BOOST_AUTO_TEST_CASE(oversize_string_literals)
BOOST_CHECK(!successAssemble("{ let x := \"123456789012345678901234567890123\" }")); BOOST_CHECK(!successAssemble("{ let x := \"123456789012345678901234567890123\" }"));
} }
BOOST_AUTO_TEST_CASE(assignment_after_tag)
{
BOOST_CHECK(successParse("{ let x := 1 { tag: =: x } }"));
}
BOOST_AUTO_TEST_CASE(magic_variables)
{
BOOST_CHECK(!successAssemble("{ this }"));
BOOST_CHECK(!successAssemble("{ ecrecover }"));
BOOST_CHECK(successAssemble("{ let ecrecover := 1 ecrecover }"));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

View File

@ -1260,7 +1260,7 @@ BOOST_AUTO_TEST_CASE(multiple_elementary_accessors)
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("data()") == encodeArgs(8)); BOOST_CHECK(callContractFunction("data()") == encodeArgs(8));
BOOST_CHECK(callContractFunction("name()") == encodeArgs("Celina")); BOOST_CHECK(callContractFunction("name()") == encodeArgs("Celina"));
BOOST_CHECK(callContractFunction("a_hash()") == encodeArgs(dev::sha3(bytes(1, 0x7b)))); BOOST_CHECK(callContractFunction("a_hash()") == encodeArgs(dev::keccak256(bytes(1, 0x7b))));
BOOST_CHECK(callContractFunction("an_address()") == encodeArgs(toBigEndian(u160(0x1337)))); BOOST_CHECK(callContractFunction("an_address()") == encodeArgs(toBigEndian(u160(0x1337))));
BOOST_CHECK(callContractFunction("super_secret_data()") == bytes()); BOOST_CHECK(callContractFunction("super_secret_data()") == bytes());
} }
@ -1342,7 +1342,7 @@ BOOST_AUTO_TEST_CASE(msg_sig)
} }
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("foo(uint256)") == encodeArgs(asString(FixedHash<4>(dev::sha3("foo(uint256)")).asBytes()))); BOOST_CHECK(callContractFunction("foo(uint256)") == encodeArgs(asString(FixedHash<4>(dev::keccak256("foo(uint256)")).asBytes())));
} }
BOOST_AUTO_TEST_CASE(msg_sig_after_internal_call_is_same) BOOST_AUTO_TEST_CASE(msg_sig_after_internal_call_is_same)
@ -1358,7 +1358,7 @@ BOOST_AUTO_TEST_CASE(msg_sig_after_internal_call_is_same)
} }
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("foo(uint256)") == encodeArgs(asString(FixedHash<4>(dev::sha3("foo(uint256)")).asBytes()))); BOOST_CHECK(callContractFunction("foo(uint256)") == encodeArgs(asString(FixedHash<4>(dev::keccak256("foo(uint256)")).asBytes())));
} }
BOOST_AUTO_TEST_CASE(now) BOOST_AUTO_TEST_CASE(now)
@ -1686,7 +1686,7 @@ BOOST_AUTO_TEST_CASE(sha3)
compileAndRun(sourceCode); compileAndRun(sourceCode);
auto f = [&](u256 const& _x) -> u256 auto f = [&](u256 const& _x) -> u256
{ {
return dev::sha3(toBigEndian(_x)); return dev::keccak256(toBigEndian(_x));
}; };
testSolidityAgainstCpp("a(bytes32)", f, u256(4)); testSolidityAgainstCpp("a(bytes32)", f, u256(4));
testSolidityAgainstCpp("a(bytes32)", f, u256(5)); testSolidityAgainstCpp("a(bytes32)", f, u256(5));
@ -2513,6 +2513,15 @@ BOOST_AUTO_TEST_CASE(super_in_constructor)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(1 | 2 | 4 | 8)); BOOST_CHECK(callContractFunction("f()") == encodeArgs(1 | 2 | 4 | 8));
} }
BOOST_AUTO_TEST_CASE(super_alone)
{
char const* sourceCode = R"(
contract A { function f() { super; } }
)";
compileAndRun(sourceCode, 0, "A");
BOOST_CHECK(callContractFunction("f()") == encodeArgs());
}
BOOST_AUTO_TEST_CASE(fallback_function) BOOST_AUTO_TEST_CASE(fallback_function)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(
@ -2582,7 +2591,7 @@ BOOST_AUTO_TEST_CASE(event)
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(value))); BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(value)));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,bytes32,uint256)"))); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,bytes32,uint256)")));
BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(m_sender, h256::AlignRight)); BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(m_sender, h256::AlignRight));
BOOST_CHECK_EQUAL(m_logs[0].topics[2], h256(id)); BOOST_CHECK_EQUAL(m_logs[0].topics[2], h256(id));
} }
@ -2604,7 +2613,7 @@ BOOST_AUTO_TEST_CASE(event_no_arguments)
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data.empty()); BOOST_CHECK(m_logs[0].data.empty());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit()"))); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit()")));
} }
BOOST_AUTO_TEST_CASE(event_anonymous) BOOST_AUTO_TEST_CASE(event_anonymous)
@ -2664,7 +2673,7 @@ BOOST_AUTO_TEST_CASE(event_lots_of_data)
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs((u160)m_sender, id, value, true)); BOOST_CHECK(m_logs[0].data == encodeArgs((u160)m_sender, id, value, true));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,bytes32,uint256,bool)"))); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,bytes32,uint256,bool)")));
} }
BOOST_AUTO_TEST_CASE(event_really_lots_of_data) BOOST_AUTO_TEST_CASE(event_really_lots_of_data)
@ -2681,9 +2690,9 @@ BOOST_AUTO_TEST_CASE(event_really_lots_of_data)
callContractFunction("deposit()"); callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 4) + FixedHash<4>(dev::sha3("deposit()")).asBytes()); BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 4) + FixedHash<4>(dev::keccak256("deposit()")).asBytes());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(uint256,bytes,uint256)"))); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)")));
} }
BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage) BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage)
@ -2707,7 +2716,7 @@ BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage)
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 3, string("ABC"))); BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 3, string("ABC")));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(uint256,bytes,uint256)"))); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)")));
} }
BOOST_AUTO_TEST_CASE(event_indexed_string) BOOST_AUTO_TEST_CASE(event_indexed_string)
@ -2738,11 +2747,11 @@ BOOST_AUTO_TEST_CASE(event_indexed_string)
dynx[i] = i; dynx[i] = i;
BOOST_CHECK(m_logs[0].data == bytes()); BOOST_CHECK(m_logs[0].data == bytes());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3);
BOOST_CHECK_EQUAL(m_logs[0].topics[1], dev::sha3(dynx)); BOOST_CHECK_EQUAL(m_logs[0].topics[1], dev::keccak256(dynx));
BOOST_CHECK_EQUAL(m_logs[0].topics[2], dev::sha3( BOOST_CHECK_EQUAL(m_logs[0].topics[2], dev::keccak256(
encodeArgs(u256(4), u256(5), u256(6), u256(7)) encodeArgs(u256(4), u256(5), u256(6), u256(7))
)); ));
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("E(string,uint256[4])"))); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(string,uint256[4])")));
} }
BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
@ -2784,7 +2793,7 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments)
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10, 12, 13) == encodeArgs( BOOST_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10, 12, 13) == encodeArgs(
dev::sha3( dev::keccak256(
toBigEndian(u256(10)) + toBigEndian(u256(10)) +
toBigEndian(u256(12)) + toBigEndian(u256(12)) +
toBigEndian(u256(13))))); toBigEndian(u256(13)))));
@ -2802,7 +2811,7 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_numeric_literals)
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("foo(uint256,uint16)", 10, 12) == encodeArgs( BOOST_CHECK(callContractFunction("foo(uint256,uint16)", 10, 12) == encodeArgs(
dev::sha3( dev::keccak256(
toBigEndian(u256(10)) + toBigEndian(u256(10)) +
bytes{0x0, 0xc} + bytes{0x0, 0xc} +
bytes(1, 0x91)))); bytes(1, 0x91))));
@ -2823,10 +2832,10 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_string_literals)
})"; })";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("foo()") == encodeArgs(dev::sha3("foo"))); BOOST_CHECK(callContractFunction("foo()") == encodeArgs(dev::keccak256("foo")));
BOOST_CHECK(callContractFunction("bar(uint256,uint16)", 10, 12) == encodeArgs( BOOST_CHECK(callContractFunction("bar(uint256,uint16)", 10, 12) == encodeArgs(
dev::sha3( dev::keccak256(
toBigEndian(u256(10)) + toBigEndian(u256(10)) +
bytes{0x0, 0xc} + bytes{0x0, 0xc} +
bytes(1, 0x91) + bytes(1, 0x91) +
@ -2868,7 +2877,27 @@ BOOST_AUTO_TEST_CASE(iterated_sha3_with_bytes)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("foo()") == encodeArgs( BOOST_CHECK(callContractFunction("foo()") == encodeArgs(
u256(dev::sha3(bytes{'b'} + dev::sha3("xyz").asBytes() + bytes{'a'})) u256(dev::keccak256(bytes{'b'} + dev::keccak256("xyz").asBytes() + bytes{'a'}))
));
}
BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments)
{
char const* sourceCode = R"(
contract c {
function foo(uint a, uint b, uint c) returns (bytes32 d)
{
d = keccak256(a, b, c);
}
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10, 12, 13) == encodeArgs(
dev::keccak256(
toBigEndian(u256(10)) +
toBigEndian(u256(12)) +
toBigEndian(u256(13))
)
)); ));
} }
@ -3013,9 +3042,9 @@ BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory)
} }
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
bytes calldata1 = FixedHash<4>(dev::sha3("f()")).asBytes() + bytes(61, 0x22) + bytes(12, 0x12); bytes calldata1 = FixedHash<4>(dev::keccak256("f()")).asBytes() + bytes(61, 0x22) + bytes(12, 0x12);
sendMessage(calldata1, false); sendMessage(calldata1, false);
BOOST_CHECK(m_output == encodeArgs(dev::sha3(bytes{'a', 'b', 'c'} + calldata1))); BOOST_CHECK(m_output == encodeArgs(dev::keccak256(bytes{'a', 'b', 'c'} + calldata1)));
} }
BOOST_AUTO_TEST_CASE(call_forward_bytes) BOOST_AUTO_TEST_CASE(call_forward_bytes)
@ -3285,6 +3314,57 @@ BOOST_AUTO_TEST_CASE(using_enums)
BOOST_CHECK(callContractFunction("getChoice()") == encodeArgs(2)); BOOST_CHECK(callContractFunction("getChoice()") == encodeArgs(2));
} }
BOOST_AUTO_TEST_CASE(using_contract_enums_with_explicit_contract_name)
{
char const* sourceCode = R"(
contract test {
enum Choice { A, B, C }
function answer () returns (test.Choice _ret)
{
_ret = test.Choice.B;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("answer()") == encodeArgs(1));
}
BOOST_AUTO_TEST_CASE(using_inherited_enum)
{
char const* sourceCode = R"(
contract base {
enum Choice { A, B, C }
}
contract test is base {
function answer () returns (Choice _ret)
{
_ret = Choice.B;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("answer()") == encodeArgs(1));
}
BOOST_AUTO_TEST_CASE(using_inherited_enum_excplicitly)
{
char const* sourceCode = R"(
contract base {
enum Choice { A, B, C }
}
contract test is base {
function answer () returns (base.Choice _ret)
{
_ret = base.Choice.B;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("answer()") == encodeArgs(1));
}
BOOST_AUTO_TEST_CASE(constructing_enums_from_ints) BOOST_AUTO_TEST_CASE(constructing_enums_from_ints)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(
@ -3389,8 +3469,8 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
string innercalldata1 = asString(FixedHash<4>(dev::sha3("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); string innercalldata1 = asString(FixedHash<4>(dev::keccak256("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9));
string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3)); string innercalldata2 = asString(FixedHash<4>(dev::keccak256("g(uint256)")).asBytes() + encodeArgs(3));
bytes calldata = encodeArgs( bytes calldata = encodeArgs(
12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13, 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13,
u256(innercalldata1.length()), innercalldata1, u256(innercalldata1.length()), innercalldata1,
@ -4668,7 +4748,7 @@ BOOST_AUTO_TEST_CASE(reusing_memory)
} }
)"; )";
compileAndRun(sourceCode, 0, "Main"); compileAndRun(sourceCode, 0, "Main");
BOOST_REQUIRE(callContractFunction("f(uint256)", 0x34) == encodeArgs(dev::sha3(dev::toBigEndian(u256(0x34))))); BOOST_REQUIRE(callContractFunction("f(uint256)", 0x34) == encodeArgs(dev::keccak256(dev::toBigEndian(u256(0x34)))));
} }
BOOST_AUTO_TEST_CASE(return_string) BOOST_AUTO_TEST_CASE(return_string)
@ -5586,6 +5666,120 @@ BOOST_AUTO_TEST_CASE(accessor_for_const_state_variable)
BOOST_CHECK(callContractFunction("ticketPrice()") == encodeArgs(u256(555))); BOOST_CHECK(callContractFunction("ticketPrice()") == encodeArgs(u256(555)));
} }
BOOST_AUTO_TEST_CASE(state_variable_under_contract_name)
{
char const* text = R"(
contract Scope {
uint stateVar = 42;
function getStateVar() constant returns (uint stateVar) {
stateVar = Scope.stateVar;
}
}
)";
compileAndRun(text);
BOOST_CHECK(callContractFunction("getStateVar()") == encodeArgs(u256(42)));
}
BOOST_AUTO_TEST_CASE(state_variable_local_variable_mixture)
{
char const* sourceCode = R"(
contract A {
uint x = 1;
uint y = 2;
function a() returns (uint x) {
x = A.y;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(2)));
}
BOOST_AUTO_TEST_CASE(inherited_function) {
char const* sourceCode = R"(
contract A { function f() internal returns (uint) { return 1; } }
contract B is A {
function f() internal returns (uint) { return 2; }
function g() returns (uint) {
return A.f();
}
}
)";
compileAndRun(sourceCode, 0, "B");
BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(1)));
}
BOOST_AUTO_TEST_CASE(inherited_function_from_a_library) {
char const* sourceCode = R"(
library A { function f() internal returns (uint) { return 1; } }
contract B {
function f() internal returns (uint) { return 2; }
function g() returns (uint) {
return A.f();
}
}
)";
compileAndRun(sourceCode, 0, "B");
BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(1)));
}
BOOST_AUTO_TEST_CASE(inherited_constant_state_var)
{
char const* sourceCode = R"(
contract A {
uint constant x = 7;
}
contract B is A {
function f() returns (uint) {
return A.x;
}
}
)";
compileAndRun(sourceCode, 0, "B");
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
}
BOOST_AUTO_TEST_CASE(multiple_inherited_state_vars)
{
char const* sourceCode = R"(
contract A {
uint x = 7;
}
contract B {
uint x = 9;
}
contract C is A, B {
function a() returns (uint) {
return A.x;
}
function b() returns (uint) {
return B.x;
}
function a_set(uint _x) returns (uint) {
A.x = _x;
return 1;
}
function b_set(uint _x) returns (uint) {
B.x = _x;
return 1;
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(7)));
BOOST_CHECK(callContractFunction("b()") == encodeArgs(u256(9)));
BOOST_CHECK(callContractFunction("a_set(uint256)", u256(1)) == encodeArgs(u256(1)));
BOOST_CHECK(callContractFunction("b_set(uint256)", u256(3)) == encodeArgs(u256(1)));
BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(1)));
BOOST_CHECK(callContractFunction("b()") == encodeArgs(u256(3)));
}
BOOST_AUTO_TEST_CASE(constant_string_literal) BOOST_AUTO_TEST_CASE(constant_string_literal)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(
@ -5825,6 +6019,48 @@ BOOST_AUTO_TEST_CASE(using_library_structs)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7), u256(8))); BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7), u256(8)));
} }
BOOST_AUTO_TEST_CASE(library_struct_as_an_expression)
{
char const* sourceCode = R"(
library Arst {
struct Foo {
int Things;
int Stuff;
}
}
contract Tsra {
function f() returns(uint) {
Arst.Foo;
return 1;
}
}
)";
compileAndRun(sourceCode, 0, "Tsra");
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1)));
}
BOOST_AUTO_TEST_CASE(library_enum_as_an_expression)
{
char const* sourceCode = R"(
library Arst {
enum Foo {
Things,
Stuff
}
}
contract Tsra {
function f() returns(uint) {
Arst.Foo;
return 1;
}
}
)";
compileAndRun(sourceCode, 0, "Tsra");
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1)));
}
BOOST_AUTO_TEST_CASE(short_strings) BOOST_AUTO_TEST_CASE(short_strings)
{ {
// This test verifies that the byte array encoding that combines length and data works // This test verifies that the byte array encoding that combines length and data works
@ -7231,6 +7467,72 @@ BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call)
BOOST_CHECK(callContractFunction("f(address)", cAddrOpt) == encodeArgs(u256(7))); BOOST_CHECK(callContractFunction("f(address)", cAddrOpt) == encodeArgs(u256(7)));
} }
BOOST_AUTO_TEST_CASE(shift_constant_left)
{
char const* sourceCode = R"(
contract C {
uint public a = 0x42 << 8;
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(0x4200)));
}
BOOST_AUTO_TEST_CASE(shift_negative_constant_left)
{
char const* sourceCode = R"(
contract C {
int public a = -0x42 << 8;
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(-0x4200)));
}
BOOST_AUTO_TEST_CASE(shift_constant_right)
{
char const* sourceCode = R"(
contract C {
uint public a = 0x4200 >> 8;
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(0x42)));
}
BOOST_AUTO_TEST_CASE(shift_negative_constant_right)
{
char const* sourceCode = R"(
contract C {
int public a = -0x4200 >> 8;
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(-0x42)));
}
BOOST_AUTO_TEST_CASE(inline_assembly_in_modifiers)
{
char const* sourceCode = R"(
contract C {
modifier m {
uint a = 1;
assembly {
a := 2
}
if (a != 2)
throw;
_;
}
function f() m returns (bool) {
return true;
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("f()") == encodeArgs(true));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

View File

@ -39,6 +39,7 @@ namespace dev
{ {
namespace solidity namespace solidity
{ {
using rational = boost::rational<dev::bigint>;
/// An Ethereum address: 20 bytes. /// An Ethereum address: 20 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Address = h160; using Address = h160;
@ -105,7 +106,7 @@ public:
template <class... Args> template <class... Args>
bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments)
{ {
FixedHash<4> hash(dev::sha3(_sig)); FixedHash<4> hash(dev::keccak256(_sig));
sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value);
return m_output; return m_output;
} }
@ -155,6 +156,14 @@ public:
static bytes encode(char const* _value) { return encode(std::string(_value)); } static bytes encode(char const* _value) { return encode(std::string(_value)); }
static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; }
static bytes encode(u256 const& _value) { return toBigEndian(_value); } static bytes encode(u256 const& _value) { return toBigEndian(_value); }
/// @returns the fixed-point encoding of a rational number with a given
/// number of fractional bits.
static bytes encode(std::pair<rational, int> const& _valueAndPrecision)
{
rational const& value = _valueAndPrecision.first;
int fractionalBits = _valueAndPrecision.second;
return encode(u256((value.numerator() << fractionalBits) / value.denominator()));
}
static bytes encode(h256 const& _value) { return _value.asBytes(); } static bytes encode(h256 const& _value) { return _value.asBytes(); }
static bytes encode(bytes const& _value, bool _padLeft = true) static bytes encode(bytes const& _value, bool _padLeft = true)
{ {
@ -186,7 +195,6 @@ public:
{ {
return encodeArgs(u256(0x20), u256(_arg.size()), _arg); return encodeArgs(u256(0x20), u256(_arg.size()), _arg);
} }
class ContractInterface class ContractInterface
{ {
public: public:

View File

@ -154,7 +154,7 @@ static FunctionTypePointer retrieveFunctionBySignature(
std::string const& _signature std::string const& _signature
) )
{ {
FixedHash<4> hash(dev::sha3(_signature)); FixedHash<4> hash(dev::keccak256(_signature));
return _contract->interfaceFunctions()[hash]; return _contract->interfaceFunctions()[hash];
} }
@ -854,6 +854,23 @@ BOOST_AUTO_TEST_CASE(implicit_base_to_derived_conversion)
BOOST_CHECK(expectError(text) == Error::Type::TypeError); BOOST_CHECK(expectError(text) == Error::Type::TypeError);
} }
BOOST_AUTO_TEST_CASE(super_excludes_current_contract)
{
char const* text = R"(
contract A {
function b() {}
}
contract B is A {
function f() {
super.f();
}
}
)";
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(function_modifier_invocation) BOOST_AUTO_TEST_CASE(function_modifier_invocation)
{ {
char const* text = R"( char const* text = R"(
@ -1019,6 +1036,19 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist"); BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist");
} }
BOOST_AUTO_TEST_CASE(missing_state_variable)
{
char const* text = R"(
contract Scope {
function getStateVar() constant returns (uint stateVar) {
stateVar = Scope.stateVar; // should fail.
}
}
)";
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor) BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor)
{ {
// test for issue #1126 https://github.com/ethereum/cpp-ethereum/issues/1126 // test for issue #1126 https://github.com/ethereum/cpp-ethereum/issues/1126
@ -1439,6 +1469,21 @@ BOOST_AUTO_TEST_CASE(enum_invalid_member_access)
BOOST_CHECK(expectError(text) == Error::Type::TypeError); BOOST_CHECK(expectError(text) == Error::Type::TypeError);
} }
BOOST_AUTO_TEST_CASE(enum_invalid_direct_member_access)
{
char const* text = R"(
contract test {
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
function test()
{
choices = Sit;
}
ActionChoices choices;
}
)";
BOOST_CHECK(expectError(text) == Error::Type::DeclarationError);
}
BOOST_AUTO_TEST_CASE(enum_explicit_conversion_is_okay) BOOST_AUTO_TEST_CASE(enum_explicit_conversion_is_okay)
{ {
char const* text = R"( char const* text = R"(
@ -1500,6 +1545,23 @@ BOOST_AUTO_TEST_CASE(enum_duplicate_values)
BOOST_CHECK(expectError(text) == Error::Type::DeclarationError); BOOST_CHECK(expectError(text) == Error::Type::DeclarationError);
} }
BOOST_AUTO_TEST_CASE(enum_name_resolution_under_current_contract_name)
{
char const* text = R"(
contract A {
enum Foo {
First,
Second
}
function a() {
A.Foo;
}
}
)";
BOOST_CHECK(success(text));
}
BOOST_AUTO_TEST_CASE(private_visibility) BOOST_AUTO_TEST_CASE(private_visibility)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(
@ -4020,6 +4082,169 @@ BOOST_AUTO_TEST_CASE(invalid_array_as_statement)
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError); BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
} }
BOOST_AUTO_TEST_CASE(using_directive_for_missing_selftype)
{
char const* text = R"(
library B {
function b() {}
}
contract A {
using B for bytes;
function a() {
bytes memory x;
x.b();
}
}
)";
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(invalid_fixed_point_literal)
{
char const* text = R"(
contract A {
function a() {
.8E0;
}
}
)";
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(shift_constant_left_negative_rvalue)
{
char const* text = R"(
contract C {
uint public a = 0x42 << -8;
}
)";
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(shift_constant_right_negative_rvalue)
{
char const* text = R"(
contract C {
uint public a = 0x42 >> -8;
}
)";
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(shift_constant_left_excessive_rvalue)
{
char const* text = R"(
contract C {
uint public a = 0x42 << 0x100000000;
}
)";
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(shift_constant_right_excessive_rvalue)
{
char const* text = R"(
contract C {
uint public a = 0x42 >> 0x100000000;
}
)";
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_positive_stack)
{
char const* text = R"(
contract test {
function f() {
assembly {
1
}
}
}
)";
BOOST_CHECK(expectError(text, true) == Error::Type::Warning);
}
BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_negative_stack)
{
char const* text = R"(
contract test {
function f() {
assembly {
pop
}
}
}
)";
BOOST_CHECK(expectError(text, true) == Error::Type::Warning);
}
BOOST_AUTO_TEST_CASE(inline_assembly_in_modifier)
{
char const* text = R"(
contract test {
modifier m {
uint a = 1;
assembly {
a := 2
}
_;
}
function f() m {
}
}
)";
BOOST_CHECK(success(text));
}
BOOST_AUTO_TEST_CASE(inline_assembly_storage)
{
char const* text = R"(
contract test {
uint x = 1;
function f() {
assembly {
x := 2
}
}
}
)";
BOOST_CHECK(expectError(text, false) == Error::Type::DeclarationError);
}
BOOST_AUTO_TEST_CASE(inline_assembly_storage_in_modifiers)
{
char const* text = R"(
contract test {
uint x = 1;
modifier m {
assembly {
x := 2
}
_;
}
function f() m {
}
}
)";
BOOST_CHECK(expectError(text, false) == Error::Type::DeclarationError);
}
BOOST_AUTO_TEST_CASE(invalid_mobile_type)
{
char const* text = R"(
contract C {
function f() {
// Invalid number
[1, 78901234567890123456789012345678901234567890123456789345678901234567890012345678012345678901234567];
}
}
)";
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

View File

@ -805,7 +805,7 @@ BOOST_AUTO_TEST_CASE(cse_empty_sha3)
Instruction::SHA3 Instruction::SHA3
}; };
checkCSE(input, { checkCSE(input, {
u256(sha3(bytesConstRef())) u256(dev::keccak256(bytesConstRef()))
}); });
} }
@ -823,7 +823,7 @@ BOOST_AUTO_TEST_CASE(cse_partial_sha3)
u256(0xabcd) << (256 - 16), u256(0xabcd) << (256 - 16),
u256(0), u256(0),
Instruction::MSTORE, Instruction::MSTORE,
u256(sha3(bytes{0xab, 0xcd})) u256(dev::keccak256(bytes{0xab, 0xcd}))
}); });
} }