Skip to content

Commit 1f9578c

Browse files
committed
Merge pull request #429 from chriseth/keywords
Breaking changes for version 0.3.0
2 parents 60a21c6 + 1bf87c6 commit 1f9578c

21 files changed

+217
-121
lines changed

Diff for: CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ include(EthPolicy)
88
eth_policy()
99

1010
# project name and version should be set after cmake_policy CMP0048
11-
set(PROJECT_VERSION "0.2.2")
11+
set(PROJECT_VERSION "0.3.0")
1212
project(solidity VERSION ${PROJECT_VERSION})
1313

1414
# Let's find our dependencies

Diff for: docs/contracts.rst

+8-35
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ Such contracts cannot be compiled (even if they contain implemented functions al
679679

680680
If a contract inherits from an abstract contract and does not implement all non-implemented functions by overriding, it will itself be abstract.
681681

682-
.. index:: ! library, callcode
682+
.. index:: ! library, callcode, delegatecall
683683

684684
.. _libraries:
685685

@@ -688,7 +688,8 @@ Libraries
688688
************
689689

690690
Libraries are similar to contracts, but their purpose is that they are deployed
691-
only once at a specific address and their code is reused using the `CALLCODE`
691+
only once at a specific address and their code is reused using the `DELEGATECALL`
692+
(`CALLCODE` until homestead)
692693
feature of the EVM. This means that if library functions are called, their code
693694
is executed in the context of the calling contract, i.e. `this` points to the
694695
calling contract and especially the storage from the calling contract can be
@@ -755,12 +756,12 @@ reference parameters, can have multiple storage reference
755756
parameters and in any position.
756757

757758
The calls to `Set.contains`, `Set.insert` and `Set.remove`
758-
are all compiled as calls (`CALLCODE`s) to an external
759+
are all compiled as calls (`DELEGATECALL`s) to an external
759760
contract/library. If you use libraries, take care that an
760-
actual external function call is performed, so `msg.sender`
761-
does not point to the original sender anymore but to the the
762-
calling contract and also `msg.value` contains the funds
763-
sent during the call to the library function.
761+
actual external function call is performed.
762+
`msg.sender`, `msg.value` and `this` will retain their values
763+
in this call, though (prior to Homestead, `msg.sender` and
764+
`msg.value` changed, though).
764765

765766
As the compiler cannot know where the library will be
766767
deployed at, these addresses have to be filled into the
@@ -780,34 +781,6 @@ Restrictions for libraries in comparison to contracts:
780781

781782
(these might be lifted at a later point)
782783

783-
Common pitfalls for libraries
784-
=============================
785-
786-
.. index:: msg;sender
787-
788-
The value of `msg.sender`
789-
-------------------------
790-
791-
The value for `msg.sender` will be that of the contract which is calling the library function.
792-
793-
For example, if A calls contract B which internally calls library C, then within the function call of library C, `msg.sender` will be the address of contract B.
794-
795-
The reason for this is that the expression `LibraryName.functionName()`
796-
performs an external function call using `CALLCODE`, which maps to a real EVM
797-
call just like `otherContract.functionName()` or `this.functionName()`. This
798-
call extends the call depth by one (limited to 1024), stores the caller (the
799-
current contract) as `msg.sender`, and then executes the library contract's
800-
code against the current contracts storage. This execution occurs in a
801-
completely new memory context meaning that memory types will be copied and
802-
cannot be passed by reference.
803-
804-
Transferring Ether
805-
-------------------------
806-
807-
It is *in principle* possible to transfer ether using
808-
`LibraryName.functionName.value(x)()`, but as `CALLCODE` is used, the Ether
809-
will just end up at the current contract.
810-
811784
.. index:: ! using for, library
812785

813786
.. _using-for:

Diff for: docs/control-structures.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ Assigning *to* a state variable always creates an independent copy. On the other
145145
Exceptions
146146
==========
147147

148-
There are some cases where exceptions are thrown automatically (see below). You can use the `throw` instruction to throw an exception manually. The effect of an exception is that the currently executing call is stopped and reverted (i.e. all changes to the state and balances are undone) and the exception is also "bubbled up" through Solidity function calls (exceptions are `send` and the low-level functions `call` and `callcode`, those return `false` in case of an exception).
148+
There are some cases where exceptions are thrown automatically (see below). You can use the `throw` instruction to throw an exception manually. The effect of an exception is that the currently executing call is stopped and reverted (i.e. all changes to the state and balances are undone) and the exception is also "bubbled up" through Solidity function calls (exceptions are `send` and the low-level functions `call`, `delegatecall` and `callcode`, those return `false` in case of an exception).
149149

150150
Catching exceptions is not yet possible.
151151

Diff for: docs/introduction-to-smart-contracts.rst

+6-6
Original file line numberDiff line numberDiff line change
@@ -406,15 +406,15 @@ a location in the caller's memory preallocated by the caller.
406406
Calls are **limited** to a depth of 1024, which means that for more complex
407407
operations, loops should be preferred over recursive calls.
408408

409-
.. index:: callcode, library
409+
.. index:: delegatecall, callcode, library
410410

411-
Callcode and Libraries
412-
======================
411+
Delegatecall / Callcode and Libraries
412+
=====================================
413413

414-
There exists a special variant of a message call, named **callcode**
414+
There exists a special variant of a message call, named **delegatecall**
415415
which is identical to a message call apart from the fact that
416416
the code at the target address is executed in the context of the calling
417-
contract.
417+
contract and `msg.sender` and `msg.value` do not change their values.
418418

419419
This means that a contract can dynamically load code from a different
420420
address at runtime. Storage, current address and balance still
@@ -461,4 +461,4 @@ The remaining Ether stored at that address is sent to a designated
461461
target and then the storage and code is removed.
462462

463463
Note that even if a contract's code does not contain the `SELFDESTRUCT`
464-
opcode, it can still perform that operation using callcode.
464+
opcode, it can still perform that operation using delegatecall or callcode.

Diff for: docs/types.rst

+4-4
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Operators:
5454
Division always truncates (it just maps to the DIV opcode of the EVM), but it does not truncate if both
5555
operators are :ref:`literals<integer_literals>` (or literal expressions).
5656

57-
.. index:: address, balance, send, call, callcode
57+
.. index:: address, balance, send, call, callcode, delegatecall
5858

5959
Address
6060
-------
@@ -82,7 +82,7 @@ and to send Ether (in units of wei) to an address using the `send` function:
8282
.. note::
8383
If `x` is a contract address, its code (more specifically: its fallback function, if present) will be executed together with the `send` call (this is a limitation of the EVM and cannot be prevented). If that execution runs out of gas or fails in any way, the Ether transfer will be reverted. In this case, `send` returns `false`.
8484

85-
* `call` and `callcode`
85+
* `call`, `callcode` and `delegatecall`
8686

8787
Furthermore, to interface with contracts that do not adhere to the ABI,
8888
the function `call` is provided which takes an arbitrary number of arguments of any type. These arguments are padded to 32 bytes and concatenated. One exception is the case where the first argument is encoded to exactly four bytes. In this case, it is not padded to allow the use of function signatures here.
@@ -95,9 +95,9 @@ the function `call` is provided which takes an arbitrary number of arguments of
9595

9696
`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).
9797

98-
In a similar way, the function `callcode` can be used: The difference is that only the code of the given address is used, all other aspects (storage, balance, ...) are taken from the current contract. The purpose of `callcode` is to use library code which is stored in another contract. The user has to ensure that the layout of storage in both contracts is suitable for callcode to be used.
98+
In a similar way, the function `delegatecall` can be used: The difference is that only the code of the given address is used, all other aspects (storage, balance, ...) are taken from the current contract. The purpose of `delegatecall` is to use library code which is stored in another contract. The user has to ensure that the layout of storage in both contracts is suitable for delegatecall to be used. Prior to homestead, only a limited variant called `callcode` was available that did not provide access to the original `msg.sender` and `msg.value` values.
9999

100-
Both `call` and `callcode` are very low-level functions and should only be used as a *last resort* as they break the type-safety of Solidity.
100+
All three functions `call`, `delegatecall` and `callcode` are very low-level functions and should only be used as a *last resort* as they break the type-safety of Solidity.
101101

102102
.. note::
103103
All contracts inherit the members of address, so it is possible to query the balance of the

Diff for: libsolidity/ast/Types.cpp

+24-23
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons
333333
{"balance", make_shared<IntegerType >(256)},
334334
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::Bare, true)},
335335
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true)},
336+
{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareDelegateCall, true)},
336337
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)}
337338
};
338339
else
@@ -1561,9 +1562,9 @@ unsigned FunctionType::sizeOnStack() const
15611562
}
15621563

15631564
unsigned size = 0;
1564-
if (location == Location::External || location == Location::CallCode)
1565+
if (location == Location::External || location == Location::CallCode || location == Location::DelegateCall)
15651566
size = 2;
1566-
else if (location == Location::Bare || location == Location::BareCallCode)
1567+
else if (location == Location::Bare || location == Location::BareCallCode || location == Location::BareDelegateCall)
15671568
size = 1;
15681569
else if (location == Location::Internal)
15691570
size = 1;
@@ -1619,9 +1620,11 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
16191620
case Location::RIPEMD160:
16201621
case Location::Bare:
16211622
case Location::BareCallCode:
1623+
case Location::BareDelegateCall:
16221624
{
1623-
MemberList::MemberMap members{
1624-
{
1625+
MemberList::MemberMap members;
1626+
if (m_location != Location::BareDelegateCall && m_location != Location::DelegateCall)
1627+
members.push_back(MemberList::Member(
16251628
"value",
16261629
make_shared<FunctionType>(
16271630
parseElementaryTypeVector({"uint"}),
@@ -1634,25 +1637,22 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
16341637
m_gasSet,
16351638
m_valueSet
16361639
)
1637-
}
1638-
};
1640+
));
16391641
if (m_location != Location::Creation)
1640-
members.push_back(
1641-
MemberList::Member(
1642-
"gas",
1643-
make_shared<FunctionType>(
1644-
parseElementaryTypeVector({"uint"}),
1645-
TypePointers{copyAndSetGasOrValue(true, false)},
1646-
strings(),
1647-
strings(),
1648-
Location::SetGas,
1649-
false,
1650-
nullptr,
1651-
m_gasSet,
1652-
m_valueSet
1653-
)
1642+
members.push_back(MemberList::Member(
1643+
"gas",
1644+
make_shared<FunctionType>(
1645+
parseElementaryTypeVector({"uint"}),
1646+
TypePointers{copyAndSetGasOrValue(true, false)},
1647+
strings(),
1648+
strings(),
1649+
Location::SetGas,
1650+
false,
1651+
nullptr,
1652+
m_gasSet,
1653+
m_valueSet
16541654
)
1655-
);
1655+
));
16561656
return members;
16571657
}
16581658
default:
@@ -1700,6 +1700,7 @@ bool FunctionType::isBareCall() const
17001700
{
17011701
case Location::Bare:
17021702
case Location::BareCallCode:
1703+
case Location::BareDelegateCall:
17031704
case Location::ECRecover:
17041705
case Location::SHA256:
17051706
case Location::RIPEMD160:
@@ -1785,7 +1786,7 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound)
17851786
returnParameterTypes,
17861787
m_parameterNames,
17871788
returnParameterNames,
1788-
_inLibrary ? Location::CallCode : m_location,
1789+
_inLibrary ? Location::DelegateCall : m_location,
17891790
m_arbitraryParameters,
17901791
m_declaration,
17911792
m_gasSet,
@@ -1884,7 +1885,7 @@ MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _current
18841885
for (auto const& it: contract.interfaceFunctions())
18851886
members.push_back(MemberList::Member(
18861887
it.second->declaration().name(),
1887-
it.second->asMemberFunction(true), // use callcode
1888+
it.second->asMemberFunction(true),
18881889
&it.second->declaration()
18891890
));
18901891
if (isBase)

Diff for: libsolidity/ast/Types.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -732,8 +732,10 @@ class FunctionType: public Type
732732
Internal, ///< stack-call using plain JUMP
733733
External, ///< external call using CALL
734734
CallCode, ///< extercnal call using CALLCODE, i.e. not exchanging the storage
735+
DelegateCall, ///< extercnal call using DELEGATECALL, i.e. not exchanging the storage
735736
Bare, ///< CALL without function hash
736737
BareCallCode, ///< CALLCODE without function hash
738+
BareDelegateCall, ///< DELEGATECALL without function hash
737739
Creation, ///< external call using CREATE
738740
Send, ///< CALL, but without data and gas
739741
SHA3, ///< SHA3
@@ -824,7 +826,7 @@ class FunctionType: public Type
824826
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an
825827
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
826828
/// current function.
827-
/// Returns an empty shared pointer if one of the input/return parameters does not have an
829+
/// @returns an empty shared pointer if one of the input/return parameters does not have an
828830
/// external type.
829831
FunctionTypePointer interfaceFunctionType() const;
830832

@@ -869,7 +871,7 @@ class FunctionType: public Type
869871
/// removed and the location of reference types is changed from CallData to Memory.
870872
/// This is needed if external functions are called on other contracts, as they cannot return
871873
/// dynamic values.
872-
/// @param _inLibrary if true, uses CallCode as location.
874+
/// @param _inLibrary if true, uses DelegateCall as location.
873875
/// @param _bound if true, the argumenst are placed as `arg1.functionName(arg2, ..., argn)`.
874876
FunctionTypePointer asMemberFunction(bool _inLibrary, bool _bound = false) const;
875877

Diff for: libsolidity/codegen/Compiler.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -773,15 +773,13 @@ eth::Assembly Compiler::cloneRuntime()
773773
a << u256(0) << eth::Instruction::DUP1 << eth::Instruction::CALLDATACOPY;
774774
//@todo adjust for larger return values, make this dynamic.
775775
a << u256(0x20) << u256(0) << eth::Instruction::CALLDATASIZE;
776-
// unfortunately, we have to send the value again, so that CALLVALUE returns the correct value
777-
// in the callcoded contract.
778-
a << u256(0) << eth::Instruction::CALLVALUE;
776+
a << u256(0);
779777
// this is the address which has to be substituted by the linker.
780778
//@todo implement as special "marker" AssemblyItem.
781779
a << u256("0xcafecafecafecafecafecafecafecafecafecafe");
782-
a << u256(schedule.callGas + schedule.callValueTransferGas + 10) << eth::Instruction::GAS << eth::Instruction::SUB;
783-
a << eth::Instruction::CALLCODE;
784-
//Propagate error condition (if CALLCODE pushes 0 on stack).
780+
a << u256(schedule.callGas + 10) << eth::Instruction::GAS << eth::Instruction::SUB;
781+
a << eth::Instruction::DELEGATECALL;
782+
//Propagate error condition (if DELEGATECALL pushes 0 on stack).
785783
a << eth::Instruction::ISZERO;
786784
a.appendJumpI(a.errorTag());
787785
//@todo adjust for larger return values, make this dynamic.

Diff for: libsolidity/codegen/Compiler.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class Compiler: private ASTConstVisitor
4444
ContractDefinition const& _contract,
4545
std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts
4646
);
47-
/// Compiles a contract that uses CALLCODE to call into a pre-deployed version of the given
47+
/// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given
4848
/// contract at runtime, but contains the full creation-time code.
4949
void compileClone(
5050
ContractDefinition const& _contract,

0 commit comments

Comments
 (0)