mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Introduce address(...).code
This commit is contained in:
parent
4b410b8731
commit
7b347b9ec2
@ -19,6 +19,7 @@ Breaking Changes:
|
||||
* Type System: Disallow ``type(super)``.
|
||||
* Type System: Disallow enums with more than 256 members.
|
||||
* Type System: Disallow explicit conversions from negative literals and literals larger than ``type(uint160).max`` to ``address`` type.
|
||||
* Type System: Introduce ``address(...).code`` to retrieve the code as ``bytes memory``. The size can be obtained via ``address(...).code.length``, but it will currently always include copying the code.
|
||||
* Type System: Explicit conversions between two types are disallowed if it changes more than one of sign, width or kind at the same time.
|
||||
* Type System: Explicit conversions from literals to enums are only allowed if the value fits in the enum.
|
||||
* Type System: Explicit conversions from literals to integer type is as strict as implicit conversions.
|
||||
|
@ -115,6 +115,7 @@ Global Variables
|
||||
- ``super``: the contract one level higher in the inheritance hierarchy
|
||||
- ``selfdestruct(address payable recipient)``: destroy the current contract, sending its funds to the given address
|
||||
- ``<address>.balance`` (``uint256``): balance of the :ref:`address` in Wei
|
||||
- ``<address>.code`` (``bytes memory``): code at the :ref:`address` (can be empty)
|
||||
- ``<address>.codehash`` (``bytes32``): the codehash of the :ref:`address`
|
||||
- ``<address payable>.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`,
|
||||
returns ``false`` on failure
|
||||
|
@ -222,6 +222,9 @@ Members of Address Types
|
||||
``<address>.balance`` (``uint256``)
|
||||
balance of the :ref:`address` in Wei
|
||||
|
||||
``<address>.code`` (``bytes memory``)
|
||||
code at the :ref:`address` (can be empty)
|
||||
|
||||
``<address>.codehash`` (``bytes32``)
|
||||
the codehash of the :ref:`address`
|
||||
|
||||
|
@ -356,7 +356,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
|
||||
switch (_memberAccess.expression().annotation().type->category())
|
||||
{
|
||||
case Type::Category::Address:
|
||||
if (member == "balance" || member == "codehash")
|
||||
if (member == "balance" || member == "code" || member == "codehash")
|
||||
mutability = StateMutability::View;
|
||||
break;
|
||||
case Type::Category::Magic:
|
||||
|
@ -456,6 +456,7 @@ MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const
|
||||
{
|
||||
MemberList::MemberMap members = {
|
||||
{"balance", TypeProvider::uint256()},
|
||||
{"code", TypeProvider::array(DataLocation::Memory)},
|
||||
{"codehash", TypeProvider::fixedBytes(32)},
|
||||
{"call", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)},
|
||||
{"callcode", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)},
|
||||
|
@ -1508,6 +1508,39 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
);
|
||||
m_context << Instruction::BALANCE;
|
||||
}
|
||||
else if (member == "code")
|
||||
{
|
||||
// Stack: <address>
|
||||
utils().convertType(
|
||||
*_memberAccess.expression().annotation().type,
|
||||
*TypeProvider::address(),
|
||||
true
|
||||
);
|
||||
|
||||
m_context << Instruction::DUP1 << Instruction::EXTCODESIZE;
|
||||
// Stack post: <address> <size>
|
||||
|
||||
m_context << Instruction::DUP1;
|
||||
// Account for the size field of `bytes memory`
|
||||
m_context << u256(32) << Instruction::ADD;
|
||||
utils().allocateMemory();
|
||||
// Stack post: <address> <size> <mem_offset>
|
||||
|
||||
// Store size at mem_offset
|
||||
m_context << Instruction::DUP2 << Instruction::DUP2 << Instruction::MSTORE;
|
||||
|
||||
m_context << u256(0) << Instruction::SWAP1 << Instruction::DUP1;
|
||||
// Stack post: <address> <size> 0 <mem_offset> <mem_offset>
|
||||
|
||||
m_context << u256(32) << Instruction::ADD << Instruction::SWAP1;
|
||||
// Stack post: <address> <size> 0 <mem_offset_adjusted> <mem_offset>
|
||||
|
||||
m_context << Instruction::SWAP4;
|
||||
// Stack post: <mem_offset> <size> 0 <mem_offset_adjusted> <address>
|
||||
|
||||
m_context << Instruction::EXTCODECOPY;
|
||||
// Stack post: <mem_offset>
|
||||
}
|
||||
else if (member == "codehash")
|
||||
{
|
||||
utils().convertType(
|
||||
|
22
test/libsolidity/semanticTests/various/address_code.sol
Normal file
22
test/libsolidity/semanticTests/various/address_code.sol
Normal file
@ -0,0 +1,22 @@
|
||||
contract C {
|
||||
bytes public initCode;
|
||||
|
||||
constructor() {
|
||||
// This should catch problems, but lets also test the case the optimiser is buggy.
|
||||
assert(address(this).code.length == 0);
|
||||
initCode = address(this).code;
|
||||
}
|
||||
|
||||
// To avoid dependency on exact length.
|
||||
function f() public view returns (bool) { return address(this).code.length > 400; }
|
||||
function g() public view returns (uint) { return address(0).code.length; }
|
||||
function h() public view returns (uint) { return address(1).code.length; }
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: false
|
||||
// ----
|
||||
// constructor() ->
|
||||
// initCode() -> 0x20, 0
|
||||
// f() -> true
|
||||
// g() -> 0
|
||||
// h() -> 0
|
@ -0,0 +1,19 @@
|
||||
contract A {
|
||||
constructor() {
|
||||
assembly {
|
||||
// This is only 7 bytes here.
|
||||
mstore(0, 0x48aa5566000000)
|
||||
return(0, 32)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f() public returns (bytes memory) { return address(new A()).code; }
|
||||
function g() public returns (uint) { return address(new A()).code.length; }
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: false
|
||||
// ----
|
||||
// f() -> 0x20, 0x20, 0x48aa5566000000
|
||||
// g() -> 0x20
|
@ -0,0 +1,8 @@
|
||||
contract C {
|
||||
function f() public view returns (address) { return address(this); }
|
||||
function g() public view returns (uint) { return f().balance; }
|
||||
function h() public view returns (bytes memory) { return f().code; }
|
||||
function i() public view returns (uint) { return f().code.length; }
|
||||
function j() public view returns (uint) { return h().length; }
|
||||
}
|
||||
// ----
|
@ -1,6 +1,6 @@
|
||||
contract C {
|
||||
function f() public returns (C) { return this; }
|
||||
function g() public returns (uint) { return f().balance(); }
|
||||
function g() public returns (uint) { return f().balance; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 3125: (114-125): Member "balance" not found or not visible after argument-dependent lookup in contract C. Use "address(...).balance" to access this address member.
|
||||
|
Loading…
Reference in New Issue
Block a user