mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
commit
3e3f9a472f
10
.travis.yml
10
.travis.yml
@ -40,6 +40,8 @@ env:
|
||||
- ENCRYPTION_LABEL="6d4541b72666"
|
||||
- SOLC_BUILD_TYPE=RelWithDebInfo
|
||||
- SOLC_EMSCRIPTEN=Off
|
||||
# FIXME: Pushing solcjson.js to solc-bin disabled until we fix the cause of #9261
|
||||
- SOLC_PUBLISH_EMSCRIPTEN=Off
|
||||
- SOLC_INSTALL_DEPS_TRAVIS=On
|
||||
- SOLC_RELEASE=On
|
||||
- SOLC_TESTS=On
|
||||
@ -104,12 +106,12 @@ matrix:
|
||||
sudo: required
|
||||
compiler: gcc
|
||||
node_js:
|
||||
- "8"
|
||||
- "10"
|
||||
services:
|
||||
- docker
|
||||
before_install:
|
||||
- nvm install 8
|
||||
- nvm use 8
|
||||
- nvm install 10
|
||||
- nvm use 10
|
||||
- docker pull ethereum/solidity-buildpack-deps:emsdk-1.39.15-2
|
||||
env:
|
||||
- SOLC_EMSCRIPTEN=On
|
||||
@ -213,7 +215,7 @@ deploy:
|
||||
# scripts because TravisCI doesn't provide much in the way of conditional logic.
|
||||
|
||||
- provider: script
|
||||
script: test $SOLC_EMSCRIPTEN != On || (scripts/release_emscripten.sh)
|
||||
script: test $SOLC_PUBLISH_EMSCRIPTEN != On || $SOLC_EMSCRIPTEN != On || (scripts/release_emscripten.sh)
|
||||
skip_cleanup: true
|
||||
on:
|
||||
branch:
|
||||
|
@ -26,12 +26,14 @@ Bugfixes:
|
||||
|
||||
|
||||
Language Features:
|
||||
* General: Add unit denomination ``gwei``
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* NatSpec: Add fields "kind" and "version" to the JSON output.
|
||||
* NatSpec: Inherit tags from unique base if derived function does not provide any.
|
||||
* Commandline Interface: Prevent some incompatible commandline options from being used together.
|
||||
|
||||
* NatSpec: Support NatSpec comments on events.
|
||||
|
||||
Bugfixes:
|
||||
* NatSpec: Do not consider ``////`` and ``/***`` as NatSpec comments.
|
||||
|
@ -359,10 +359,10 @@ subAssembly
|
||||
: 'assembly' identifier assemblyBlock ;
|
||||
|
||||
numberLiteral
|
||||
: (DecimalNumber | HexNumber) NumberUnit? ;
|
||||
: (DecimalNumber | HexNumber) (NumberUnit | Gwei)?;
|
||||
|
||||
identifier
|
||||
: ('from' | 'calldata' | 'address' | Identifier) ;
|
||||
: (Gwei | 'from' | 'calldata' | 'address' | Identifier) ;
|
||||
|
||||
BooleanLiteral
|
||||
: 'true' | 'false' ;
|
||||
@ -385,6 +385,8 @@ NumberUnit
|
||||
: 'wei' | 'szabo' | 'finney' | 'ether'
|
||||
| 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' ;
|
||||
|
||||
Gwei: 'gwei' ;
|
||||
|
||||
HexLiteralFragment
|
||||
: 'hex' (('"' HexDigits? '"') | ('\'' HexDigits? '\'')) ;
|
||||
|
||||
|
@ -42,10 +42,6 @@ The following example shows a contract and a function using all available tags.
|
||||
|
||||
.. note::
|
||||
|
||||
NatSpec currently does NOT apply to public state variables (see
|
||||
`solidity#3418 <https://github.com/ethereum/solidity/issues/3418>`__),
|
||||
even if they are declared public and therefore do affect the ABI.
|
||||
|
||||
The Solidity compiler only interprets tags if they are external or
|
||||
public. You are welcome to use similar comments for your internal and
|
||||
private functions, but those will not be parsed.
|
||||
@ -60,7 +56,6 @@ The following example shows a contract and a function using all available tags.
|
||||
/// @notice You can use this contract for only the most basic simulation
|
||||
/// @dev All function calls are currently implemented without side effects
|
||||
contract Tree {
|
||||
/// @author Mary A. Botanist
|
||||
/// @notice Calculate tree age in years, rounded up, for live trees
|
||||
/// @dev The Alexandr N. Tetearing algorithm could increase precision
|
||||
/// @param rings The number of rings from dendrochronological sample
|
||||
@ -84,10 +79,10 @@ in the same way as if it were tagged with ``@notice``.
|
||||
Tag Context
|
||||
=========== =============================================================================== =============================
|
||||
``@title`` A title that should describe the contract/interface contract, interface
|
||||
``@author`` The name of the author contract, interface, function
|
||||
``@notice`` Explain to an end user what this does contract, interface, function, public state variable
|
||||
``@dev`` Explain to a developer any extra details contract, interface, function, state variable
|
||||
``@param`` Documents a parameter just like in doxygen (must be followed by parameter name) function
|
||||
``@author`` The name of the author contract, interface
|
||||
``@notice`` Explain to an end user what this does contract, interface, function, public state variable, event
|
||||
``@dev`` Explain to a developer any extra details contract, interface, function, state variable, event
|
||||
``@param`` Documents a parameter just like in doxygen (must be followed by parameter name) function, event
|
||||
``@return`` Documents the return variables of a contract's function function, public state variable
|
||||
=========== =============================================================================== =============================
|
||||
|
||||
@ -127,9 +122,11 @@ documentation and you may read more at
|
||||
Inheritance Notes
|
||||
-----------------
|
||||
|
||||
Currently it is undefined whether a contract with a function having no
|
||||
NatSpec will inherit the NatSpec of a parent contract/interface for that
|
||||
same function.
|
||||
Functions without NatSpec will automatically inherit the documentation of their
|
||||
base function. Exceptions to this are:
|
||||
|
||||
* When the parameter names are different.
|
||||
* When there is more than one base function.
|
||||
|
||||
.. _header-output:
|
||||
|
||||
@ -193,7 +190,6 @@ file should also be produced and should look like this:
|
||||
{
|
||||
"age(uint256)" :
|
||||
{
|
||||
"author" : "Mary A. Botanist",
|
||||
"details" : "The Alexandr N. Tetearing algorithm could increase precision",
|
||||
"params" :
|
||||
{
|
||||
|
@ -7,11 +7,12 @@ Units and Globally Available Variables
|
||||
Ether Units
|
||||
===========
|
||||
|
||||
A literal number can take a suffix of ``wei``, ``finney``, ``szabo`` or ``ether`` to specify a subdenomination of Ether, where Ether numbers without a postfix are assumed to be Wei.
|
||||
A literal number can take a suffix of ``wei``, ``gwei``, ``finney``, ``szabo`` or ``ether`` to specify a subdenomination of Ether, where Ether numbers without a postfix are assumed to be Wei.
|
||||
|
||||
::
|
||||
|
||||
assert(1 wei == 1);
|
||||
assert(1 gwei == 1e9);
|
||||
assert(1 szabo == 1e12);
|
||||
assert(1 finney == 1e15);
|
||||
assert(1 ether == 1e18);
|
||||
|
28
docs/yul.rst
28
docs/yul.rst
@ -180,7 +180,11 @@ appropriate ``PUSHi`` instruction. In the following example,
|
||||
``3`` and ``2`` are added resulting in 5 and then the
|
||||
bitwise ``and`` with the string "abc" is computed.
|
||||
The final value is assigned to a local variable called ``x``.
|
||||
|
||||
Strings are stored left-aligned and cannot be longer than 32 bytes.
|
||||
The limit does not apply to string literals passed to builtin functions that require
|
||||
literal arguments (e.g. ``setimmutable`` or ``loadimmutable``). Those strings never end up in the
|
||||
generated bytecode.
|
||||
|
||||
.. code-block:: yul
|
||||
|
||||
@ -923,6 +927,30 @@ will store ``value`` at all points in memory that contain a call to
|
||||
``loadimmutable("name")``.
|
||||
|
||||
|
||||
linkersymbol
|
||||
^^^^^^^^^^^^
|
||||
|
||||
The function ``linkersymbol("fq_library_name")`` is a placeholder for an address literal to be
|
||||
substituted by the linker. Its first and only argument must be a string literal and represents the
|
||||
fully qualified library name used with the ``--libraries`` option.
|
||||
|
||||
For example this code
|
||||
|
||||
.. code-block:: yul
|
||||
|
||||
let a := linkersymbol("file.sol:Math")
|
||||
|
||||
is equivalent to
|
||||
|
||||
.. code-block:: yul
|
||||
|
||||
let a := 0x1234567890123456789012345678901234567890
|
||||
|
||||
when the linker is invoked with ``--libraries "file.sol:Math:0x1234567890123456789012345678901234567890``
|
||||
option.
|
||||
|
||||
See :ref:`Using the Commandline Compiler <commandline-compiler>` for details about the Solidity linker.
|
||||
|
||||
|
||||
.. _yul-object:
|
||||
|
||||
|
@ -232,6 +232,7 @@ namespace solidity::langutil
|
||||
\
|
||||
/* Identifiers (not keywords or future reserved words). */ \
|
||||
T(Identifier, nullptr, 0) \
|
||||
T(SubGwei, "gwei", 0) \
|
||||
\
|
||||
/* Keywords reserved for future use. */ \
|
||||
K(After, "after", 0) \
|
||||
|
@ -32,6 +32,33 @@ using namespace solidity;
|
||||
using namespace solidity::langutil;
|
||||
using namespace solidity::frontend;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void copyMissingTags(StructurallyDocumentedAnnotation& _target, set<CallableDeclaration const*> const& _baseFunctions)
|
||||
{
|
||||
if (_baseFunctions.size() != 1)
|
||||
return;
|
||||
|
||||
auto& sourceDoc = dynamic_cast<StructurallyDocumentedAnnotation const&>((*_baseFunctions.begin())->annotation());
|
||||
|
||||
set<string> existingTags;
|
||||
|
||||
for (auto const& iterator: _target.docTags)
|
||||
existingTags.insert(iterator.first);
|
||||
|
||||
for (auto const& [tag, content]: sourceDoc.docTags)
|
||||
if (tag != "inheritdoc" && !existingTags.count(tag))
|
||||
_target.docTags.emplace(tag, content);
|
||||
}
|
||||
|
||||
bool parameterNamesEqual(CallableDeclaration const& _a, CallableDeclaration const& _b)
|
||||
{
|
||||
return boost::range::equal(_a.parameters(), _b.parameters(), [](auto const& pa, auto const& pb) { return pa->name() == pb->name(); });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit)
|
||||
{
|
||||
auto errorWatcher = m_errorReporter.errorWatcher();
|
||||
@ -65,7 +92,24 @@ bool DocStringAnalyser::visit(VariableDeclaration const& _variable)
|
||||
if (_variable.isPublic())
|
||||
parseDocStrings(_variable, _variable.annotation(), validPublicTags, "public state variables");
|
||||
else
|
||||
{
|
||||
parseDocStrings(_variable, _variable.annotation(), validNonPublicTags, "non-public state variables");
|
||||
if (_variable.annotation().docTags.count("notice") > 0)
|
||||
m_errorReporter.warning(
|
||||
7816_error, _variable.documentation()->location(),
|
||||
"Documentation tag on non-public state variables will be disallowed in 0.7.0. "
|
||||
"You will need to use the @dev tag explicitly."
|
||||
);
|
||||
}
|
||||
if (_variable.annotation().docTags.count("title") > 0 || _variable.annotation().docTags.count("author") > 0)
|
||||
m_errorReporter.warning(
|
||||
8532_error, _variable.documentation()->location(),
|
||||
"Documentation tag @title and @author is only allowed on contract definitions. "
|
||||
"It will be disallowed in 0.7.0."
|
||||
);
|
||||
|
||||
if (_variable.annotation().docTags.empty())
|
||||
copyMissingTags(_variable.annotation(), _variable.annotation().baseFunctions);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -129,6 +173,20 @@ void DocStringAnalyser::handleCallable(
|
||||
static set<string> const validTags = set<string>{"author", "dev", "notice", "return", "param"};
|
||||
parseDocStrings(_node, _annotation, validTags, "functions");
|
||||
checkParameters(_callable, _node, _annotation);
|
||||
|
||||
if (
|
||||
_annotation.docTags.empty() &&
|
||||
_callable.annotation().baseFunctions.size() == 1 &&
|
||||
parameterNamesEqual(_callable, **_callable.annotation().baseFunctions.begin())
|
||||
)
|
||||
copyMissingTags(_annotation, _callable.annotation().baseFunctions);
|
||||
|
||||
if (_node.documentation() && _annotation.docTags.count("author") > 0)
|
||||
m_errorReporter.warning(
|
||||
9843_error, _node.documentation()->location(),
|
||||
"Documentation tag @author is only allowed on contract definitions. "
|
||||
"It will be disallowed in 0.7.0."
|
||||
);
|
||||
}
|
||||
|
||||
void DocStringAnalyser::parseDocStrings(
|
||||
|
@ -2084,6 +2084,7 @@ public:
|
||||
{
|
||||
None = static_cast<int>(Token::Illegal),
|
||||
Wei = static_cast<int>(Token::SubWei),
|
||||
Gwei = static_cast<int>(Token::SubGwei),
|
||||
Szabo = static_cast<int>(Token::SubSzabo),
|
||||
Finney = static_cast<int>(Token::SubFinney),
|
||||
Ether = static_cast<int>(Token::SubEther),
|
||||
|
@ -1002,6 +1002,8 @@ Literal::SubDenomination ASTJsonImporter::subdenomination(Json::Value const& _no
|
||||
|
||||
if (subDenStr == "wei")
|
||||
return Literal::SubDenomination::Wei;
|
||||
else if (subDenStr == "gwei")
|
||||
return Literal::SubDenomination::Gwei;
|
||||
else if (subDenStr == "szabo")
|
||||
return Literal::SubDenomination::Szabo;
|
||||
else if (subDenStr == "finney")
|
||||
|
@ -889,6 +889,9 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal
|
||||
case Literal::SubDenomination::Wei:
|
||||
case Literal::SubDenomination::Second:
|
||||
break;
|
||||
case Literal::SubDenomination::Gwei:
|
||||
value *= bigint("1000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Szabo:
|
||||
value *= bigint("1000000000000");
|
||||
break;
|
||||
|
@ -307,11 +307,6 @@ bool CompilerStack::analyze()
|
||||
if (source->ast && !syntaxChecker.checkSyntax(*source->ast))
|
||||
noErrors = false;
|
||||
|
||||
DocStringAnalyser docStringAnalyser(m_errorReporter);
|
||||
for (Source const* source: m_sourceOrder)
|
||||
if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast))
|
||||
noErrors = false;
|
||||
|
||||
m_globalContext = make_shared<GlobalContext>();
|
||||
// We need to keep the same resolver during the whole process.
|
||||
NameAndTypeResolver resolver(*m_globalContext, m_evmVersion, m_errorReporter);
|
||||
@ -367,6 +362,11 @@ bool CompilerStack::analyze()
|
||||
if (!contractLevelChecker.check(*contract))
|
||||
noErrors = false;
|
||||
|
||||
DocStringAnalyser docStringAnalyser(m_errorReporter);
|
||||
for (Source const* source: m_sourceOrder)
|
||||
if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast))
|
||||
noErrors = false;
|
||||
|
||||
// New we run full type checks that go down to the expression level. This
|
||||
// cannot be done earlier, because we need cross-contract types and information
|
||||
// about whether a contract is abstract for the `new` expression.
|
||||
|
@ -36,6 +36,7 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
||||
{
|
||||
Json::Value doc;
|
||||
Json::Value methods(Json::objectValue);
|
||||
Json::Value events(Json::objectValue);
|
||||
|
||||
doc["version"] = Json::Value(c_natspecVersion);
|
||||
doc["kind"] = Json::Value("user");
|
||||
@ -84,7 +85,17 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& event: _contractDef.events())
|
||||
{
|
||||
string value = extractDoc(event->annotation().docTags, "notice");
|
||||
if (!value.empty())
|
||||
events[event->functionType(true)->externalSignature()]["notice"] = value;
|
||||
}
|
||||
|
||||
doc["methods"] = methods;
|
||||
if (!events.empty())
|
||||
doc["events"] = events;
|
||||
|
||||
return doc;
|
||||
}
|
||||
@ -145,9 +156,16 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef)
|
||||
stateVariables[varDecl->name()]["return"] = extractDoc(varDecl->annotation().docTags, "return");
|
||||
}
|
||||
|
||||
Json::Value events(Json::objectValue);
|
||||
for (auto const& event: _contractDef.events())
|
||||
if (auto devDoc = devDocumentation(event->annotation().docTags); !devDoc.empty())
|
||||
events[event->functionType(true)->externalSignature()] = devDoc;
|
||||
|
||||
doc["methods"] = methods;
|
||||
if (!stateVariables.empty())
|
||||
doc["stateVariables"] = stateVariables;
|
||||
if (!events.empty())
|
||||
doc["events"] = events;
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
@ -1825,11 +1825,16 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
|
||||
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
|
||||
break;
|
||||
case Token::Number:
|
||||
if (TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken()))
|
||||
if (
|
||||
(m_scanner->peekNextToken() == Token::Identifier && m_scanner->peekLiteral() == "gwei") ||
|
||||
TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken())
|
||||
)
|
||||
{
|
||||
ASTPointer<ASTString> literal = getLiteralAndAdvance();
|
||||
nodeFactory.markEndPosition();
|
||||
Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(m_scanner->currentToken());
|
||||
Token actualToken = m_scanner->currentToken() == Token::Identifier ? Token::SubGwei : m_scanner->currentToken();
|
||||
|
||||
Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(actualToken);
|
||||
m_scanner->next();
|
||||
expression = nodeFactory.createNode<Literal>(token, literal, subdenomination);
|
||||
}
|
||||
|
@ -301,10 +301,15 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
||||
for (size_t i = _funCall.arguments.size(); i > 0; i--)
|
||||
{
|
||||
Expression const& arg = _funCall.arguments[i - 1];
|
||||
bool isLiteralArgument = needsLiteralArguments && (*needsLiteralArguments)[i - 1];
|
||||
bool isStringLiteral = holds_alternative<Literal>(arg) && get<Literal>(arg).kind == LiteralKind::String;
|
||||
|
||||
argTypes.emplace_back(expectExpression(arg));
|
||||
if (isLiteralArgument && isStringLiteral)
|
||||
argTypes.emplace_back(expectUnlimitedStringLiteral(get<Literal>(arg)));
|
||||
else
|
||||
argTypes.emplace_back(expectExpression(arg));
|
||||
|
||||
if (needsLiteralArguments && (*needsLiteralArguments)[i - 1])
|
||||
if (isLiteralArgument)
|
||||
{
|
||||
if (!holds_alternative<Literal>(arg))
|
||||
m_errorReporter.typeError(
|
||||
@ -433,6 +438,14 @@ YulString AsmAnalyzer::expectExpression(Expression const& _expr)
|
||||
return types.empty() ? m_dialect.defaultType : types.front();
|
||||
}
|
||||
|
||||
YulString AsmAnalyzer::expectUnlimitedStringLiteral(Literal const& _literal)
|
||||
{
|
||||
yulAssert(_literal.kind == LiteralKind::String, "");
|
||||
yulAssert(m_dialect.validTypeForLiteral(LiteralKind::String, _literal.value, _literal.type), "");
|
||||
|
||||
return {_literal.type};
|
||||
}
|
||||
|
||||
void AsmAnalyzer::expectBoolExpression(Expression const& _expr)
|
||||
{
|
||||
YulString type = expectExpression(_expr);
|
||||
@ -531,7 +544,7 @@ void AsmAnalyzer::expectType(YulString _expectedType, YulString _givenType, Sour
|
||||
bool AsmAnalyzer::warnOnInstructions(std::string const& _instructionIdentifier, langutil::SourceLocation const& _location)
|
||||
{
|
||||
auto const builtin = EVMDialect::strictAssemblyForEVM(EVMVersion{}).builtin(YulString(_instructionIdentifier));
|
||||
if (builtin)
|
||||
if (builtin && builtin->instruction.has_value())
|
||||
return warnOnInstructions(builtin->instruction.value(), _location);
|
||||
else
|
||||
return false;
|
||||
|
@ -97,6 +97,7 @@ private:
|
||||
/// Visits the expression, expects that it evaluates to exactly one value and
|
||||
/// returns the type. Reports errors on errors and returns the default type.
|
||||
YulString expectExpression(Expression const& _expr);
|
||||
YulString expectUnlimitedStringLiteral(Literal const& _literal);
|
||||
/// Vists the expression and expects it to return a single boolean value.
|
||||
/// Reports an error otherwise.
|
||||
void expectBoolExpression(Expression const& _expr);
|
||||
|
@ -124,6 +124,17 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
||||
)
|
||||
builtins.emplace(createEVMFunction(instr.first, instr.second));
|
||||
|
||||
builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {true}, [](
|
||||
FunctionCall const& _call,
|
||||
AbstractAssembly& _assembly,
|
||||
BuiltinContext&,
|
||||
function<void(Expression const&)>
|
||||
) {
|
||||
yulAssert(_call.arguments.size() == 1, "");
|
||||
Expression const& arg = _call.arguments.front();
|
||||
_assembly.appendLinkerSymbol(std::get<Literal>(arg).value.str());
|
||||
}));
|
||||
|
||||
if (_objectAccess)
|
||||
{
|
||||
builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {true}, [](
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/range/adaptor/filtered.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#ifdef _WIN32 // windows
|
||||
@ -1202,9 +1203,14 @@ bool CommandLineInterface::processInput()
|
||||
};
|
||||
if (countEnabledOptions(nonAssemblyModeOptions) >= 1)
|
||||
{
|
||||
auto optionEnabled = [&](string const& name){ return m_args.count(name) > 0; };
|
||||
auto enabledOptions = boost::copy_range<vector<string>>(nonAssemblyModeOptions | boost::adaptors::filtered(optionEnabled));
|
||||
|
||||
serr() << "The following options are invalid in assembly mode: ";
|
||||
serr() << joinOptionNames(nonAssemblyModeOptions) << ". ";
|
||||
serr() << "Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl;
|
||||
serr() << joinOptionNames(enabledOptions) << ".";
|
||||
if (m_args.count(g_strOptimizeYul) || m_args.count(g_strNoOptimizeYul))
|
||||
serr() << " Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl;
|
||||
serr() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ using Address = util::h160;
|
||||
// The various denominations; here for ease of use where needed within code.
|
||||
static const u256 wei = 1;
|
||||
static const u256 shannon = u256("1000000000");
|
||||
static const u256 gwei = shannon;
|
||||
static const u256 szabo = shannon * 1000;
|
||||
static const u256 finney = szabo * 1000;
|
||||
static const u256 ether = finney * 1000;
|
||||
|
@ -0,0 +1 @@
|
||||
--strict-assembly --optimize-yul
|
@ -0,0 +1 @@
|
||||
The following options are invalid in assembly mode: --optimize-yul. Optimization is disabled by default and can be enabled with --optimize.
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
sstore(0, 1)
|
||||
}
|
@ -1 +1 @@
|
||||
The following options are invalid in assembly mode: --output-dir, --gas, --combined-json, --optimize-yul, --no-optimize-yul. Optimization is disabled by default and can be enabled with --optimize.
|
||||
The following options are invalid in assembly mode: --output-dir.
|
||||
|
@ -221,6 +221,21 @@ BOOST_AUTO_TEST_CASE(int_with_wei_ether_subdenomination)
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(int_with_gwei_ether_subdenomination)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function test () {
|
||||
uint x = 1 gwei;
|
||||
}
|
||||
}
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation({uint8_t(Instruction::PUSH4), 0x3b, 0x9a, 0xca, 0x00});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(int_with_szabo_ether_subdenomination)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
|
@ -355,6 +355,52 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
|
||||
checkNatspec(sourceCode, "test", userDoc, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract ERC20 {
|
||||
/// @notice This event is emitted when a transfer occurs.
|
||||
/// @param from The source account.
|
||||
/// @param to The destination account.
|
||||
/// @param amount The amount.
|
||||
/// @dev A test case!
|
||||
event Transfer(address indexed from, address indexed to, uint amount);
|
||||
}
|
||||
)";
|
||||
|
||||
char const* devDoc = R"ABCDEF(
|
||||
{
|
||||
"events":
|
||||
{
|
||||
"Transfer(address,address,uint256)":
|
||||
{
|
||||
"details": "A test case!",
|
||||
"params":
|
||||
{
|
||||
"amount": "The amount.", "from": "The source account.", "to": "The destination account."
|
||||
}
|
||||
}
|
||||
},
|
||||
"methods": {}
|
||||
}
|
||||
)ABCDEF";
|
||||
checkNatspec(sourceCode, "ERC20", devDoc, false);
|
||||
|
||||
char const* userDoc = R"ABCDEF(
|
||||
{
|
||||
"events":
|
||||
{
|
||||
"Transfer(address,address,uint256)":
|
||||
{
|
||||
"notice": "This event is emitted when a transfer occurs."
|
||||
}
|
||||
},
|
||||
"methods": {}
|
||||
}
|
||||
)ABCDEF";
|
||||
checkNatspec(sourceCode, "ERC20", userDoc, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_desc_after_nl)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
@ -1218,6 +1264,263 @@ BOOST_AUTO_TEST_CASE(slash3_slash4)
|
||||
checkNatspec(sourceCode, "test", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
BOOST_AUTO_TEST_CASE(dev_default_inherit_variable)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
contract C {
|
||||
/// @notice Hello world
|
||||
/// @dev test
|
||||
function x() virtual external returns (uint) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
contract D is C {
|
||||
uint public override x;
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"x()":
|
||||
{
|
||||
"details": "test"
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
char const *natspec1 = R"ABCDEF({
|
||||
"methods" : {},
|
||||
"stateVariables" :
|
||||
{
|
||||
"x" :
|
||||
{
|
||||
"details" : "test"
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "C", natspec, false);
|
||||
checkNatspec(sourceCode, "D", natspec1, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(user_default_inherit_variable)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
contract C {
|
||||
/// @notice Hello world
|
||||
/// @dev test
|
||||
function x() virtual external returns (uint) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
contract D is C {
|
||||
uint public override x;
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"x()":
|
||||
{
|
||||
"notice": "Hello world"
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "C", natspec, true);
|
||||
checkNatspec(sourceCode, "D", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_default_inherit)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// Second line.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract Middle is ERC20 {
|
||||
function transfer(address to, uint amount) virtual override external returns (bool)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is Middle {
|
||||
function transfer(address to, uint amount) override external returns (bool)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"author": "Programmer",
|
||||
"details": "test",
|
||||
"params":
|
||||
{
|
||||
"amount": "amount to transfer",
|
||||
"to": "address to transfer to"
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, false);
|
||||
checkNatspec(sourceCode, "Middle", natspec, false);
|
||||
checkNatspec(sourceCode, "Token", natspec, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(user_default_inherit)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// Second line.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract Middle is ERC20 {
|
||||
function transfer(address to, uint amount) virtual override external returns (bool)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is Middle {
|
||||
function transfer(address to, uint amount) override external returns (bool)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``. Second line."
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, true);
|
||||
checkNatspec(sourceCode, "Middle", natspec, true);
|
||||
checkNatspec(sourceCode, "Token", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_inherit_parameter_mismatch)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract Middle is ERC20 {
|
||||
function transfer(address to, uint amount) override virtual external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is Middle {
|
||||
function transfer(address too, uint amount) override external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"author": "Programmer",
|
||||
"details": "test",
|
||||
"params":
|
||||
{
|
||||
"amount": "amount to transfer",
|
||||
"to": "address to transfer to"
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
char const *natspec2 = R"ABCDEF({
|
||||
"methods": { }
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, false);
|
||||
checkNatspec(sourceCode, "Middle", natspec, false);
|
||||
checkNatspec(sourceCode, "Token", natspec2, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(user_inherit_parameter_mismatch)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface ERC20 {
|
||||
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||
/// @author Programmer
|
||||
/// @dev test
|
||||
/// @param to address to transfer to
|
||||
/// @param amount amount to transfer
|
||||
function transfer(address to, uint amount) external returns (bool);
|
||||
}
|
||||
|
||||
contract Middle is ERC20 {
|
||||
function transfer(address to, uint amount) override virtual external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract Token is Middle {
|
||||
function transfer(address too, uint amount) override external returns (bool) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"transfer(address,uint256)":
|
||||
{
|
||||
"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
char const *natspec2 = R"ABCDEF({
|
||||
"methods": { }
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "ERC20", natspec, true);
|
||||
checkNatspec(sourceCode, "Middle", natspec, true);
|
||||
checkNatspec(sourceCode, "Token", natspec2, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
@ -428,8 +428,9 @@ BOOST_AUTO_TEST_CASE(comments_mixed_in_sequence)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ether_subdenominations)
|
||||
{
|
||||
Scanner scanner(CharStream("wei szabo finney ether", ""));
|
||||
Scanner scanner(CharStream("wei gwei szabo finney ether", ""));
|
||||
BOOST_CHECK_EQUAL(scanner.currentToken(), Token::SubWei);
|
||||
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
|
||||
BOOST_CHECK_EQUAL(scanner.next(), Token::SubSzabo);
|
||||
BOOST_CHECK_EQUAL(scanner.next(), Token::SubFinney);
|
||||
BOOST_CHECK_EQUAL(scanner.next(), Token::SubEther);
|
||||
|
10
test/libsolidity/semanticTests/literals/gwei.sol
Normal file
10
test/libsolidity/semanticTests/literals/gwei.sol
Normal file
@ -0,0 +1,10 @@
|
||||
contract C {
|
||||
uint constant gwei = 1 gwei;
|
||||
|
||||
function f() public view returns(uint) { return gwei; }
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 1000000000
|
||||
|
@ -2,5 +2,6 @@ contract C {
|
||||
uint constant a = 1 wei + 2 szabo + 3 finney + 4 ether;
|
||||
uint constant b = 1 seconds + 2 minutes + 3 hours + 4 days + 5 weeks;
|
||||
uint constant c = 2 szabo / 1 seconds + 3 finney * 3 hours;
|
||||
uint constant d = 2 gwei / 1 seconds + 3 finney * 3 hours;
|
||||
}
|
||||
// ----
|
||||
|
3
test/libsolidity/syntaxTests/denominations/gwei.sol
Normal file
3
test/libsolidity/syntaxTests/denominations/gwei.sol
Normal file
@ -0,0 +1,3 @@
|
||||
contract C {
|
||||
uint constant gwei = 1 gwei;
|
||||
}
|
4
test/libsolidity/syntaxTests/immutable/long_name.sol
Normal file
4
test/libsolidity/syntaxTests/immutable/long_name.sol
Normal file
@ -0,0 +1,4 @@
|
||||
contract C {
|
||||
uint immutable long___name___that___definitely___exceeds___the___thirty___two___byte___limit = 0;
|
||||
}
|
||||
// ----
|
@ -0,0 +1,6 @@
|
||||
contract C {
|
||||
/// @author author
|
||||
function iHaveAuthor() public pure {}
|
||||
}
|
||||
// ----
|
||||
// Warning 9843: (17-35): Documentation tag @author is only allowed on contract definitions. It will be disallowed in 0.7.0.
|
@ -1,15 +1,16 @@
|
||||
contract c {
|
||||
contract C {
|
||||
function f() public
|
||||
{
|
||||
a = 1 wei;
|
||||
b = 2 szabo;
|
||||
c = 3 finney;
|
||||
b = 4 ether;
|
||||
d = 4 ether;
|
||||
e = 5 gwei;
|
||||
}
|
||||
uint256 a;
|
||||
uint256 b;
|
||||
uint256 c;
|
||||
uint256 d;
|
||||
uint256 e;
|
||||
}
|
||||
// ----
|
||||
// Warning 2519: (170-179): This declaration shadows an existing declaration.
|
||||
|
@ -0,0 +1,17 @@
|
||||
object "a" {
|
||||
code {
|
||||
setimmutable(
|
||||
"long___name___that___definitely___exceeds___the___thirty___two___byte___limit",
|
||||
0x1234567890123456789012345678901234567890
|
||||
)
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Assembly:
|
||||
// /* "source":152:194 */
|
||||
// 0x1234567890123456789012345678901234567890
|
||||
// /* "source":32:204 */
|
||||
// assignImmutable("0x85a5b1db611c82c46f5fa18e39ae218397536256c451e5de155a86de843a9ad6")
|
||||
// Bytecode: 73123456789012345678901234567890123456789050
|
||||
// Opcodes: PUSH20 0x1234567890123456789012345678901234567890 POP
|
||||
// SourceMappings: 152:42:0:-:0;32:172
|
42
test/libyul/objectCompiler/linkersymbol.yul
Normal file
42
test/libyul/objectCompiler/linkersymbol.yul
Normal file
@ -0,0 +1,42 @@
|
||||
object "a" {
|
||||
code {
|
||||
let addr := linkersymbol("contract/test.sol:L")
|
||||
mstore(128, shl(227, 0x18530aaf))
|
||||
let success := call(gas(), addr, 0, 128, 4, 128, 0)
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Assembly:
|
||||
// linkerSymbol("f919ba91ac99f96129544b80b9516b27a80e376b9dc693819d0b18b7e0395612")
|
||||
// /* "source":109:119 */
|
||||
// 0x18530aaf
|
||||
// /* "source":104:107 */
|
||||
// 0xe3
|
||||
// /* "source":100:120 */
|
||||
// shl
|
||||
// /* "source":95:98 */
|
||||
// 0x80
|
||||
// /* "source":88:121 */
|
||||
// mstore
|
||||
// /* "source":179:180 */
|
||||
// 0x00
|
||||
// /* "source":174:177 */
|
||||
// 0x80
|
||||
// /* "source":171:172 */
|
||||
// 0x04
|
||||
// /* "source":166:169 */
|
||||
// 0x80
|
||||
// /* "source":163:164 */
|
||||
// 0x00
|
||||
// /* "source":157:161 */
|
||||
// dup6
|
||||
// /* "source":150:155 */
|
||||
// gas
|
||||
// /* "source":145:181 */
|
||||
// call
|
||||
// /* "source":22:187 */
|
||||
// pop
|
||||
// pop
|
||||
// Bytecode: 7300000000000000000000000000000000000000006318530aaf60e31b60805260006080600460806000855af15050
|
||||
// Opcodes: PUSH20 0x0 PUSH4 0x18530AAF PUSH1 0xE3 SHL PUSH1 0x80 MSTORE PUSH1 0x0 PUSH1 0x80 PUSH1 0x4 PUSH1 0x80 PUSH1 0x0 DUP6 GAS CALL POP POP
|
||||
// SourceMappings: :::-:0;109:10:0;104:3;100:20;95:3;88:33;179:1;174:3;171:1;166:3;163:1;157:4;150:5;145:36;22:165;
|
16
test/libyul/yulInterpreterTests/self_balance.yul
Normal file
16
test/libyul/yulInterpreterTests/self_balance.yul
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
mstore(0, balance(address()))
|
||||
mstore(0x20, selfbalance())
|
||||
mstore(0x40, balance(div(mul(address(), 2), 2)))
|
||||
mstore(0x60, balance(add(address(), 1)))
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=istanbul
|
||||
// ----
|
||||
// Trace:
|
||||
// Memory dump:
|
||||
// 0: 0000000000000000000000000000000000000000000000000000000022223333
|
||||
// 20: 0000000000000000000000000000000000000000000000000000000022223333
|
||||
// 40: 0000000000000000000000000000000000000000000000000000000022223333
|
||||
// 60: 0000000000000000000000000000000000000000000000000000000022222222
|
||||
// Storage dump:
|
6
test/libyul/yulSyntaxTests/byte_of_string_literal.yul
Normal file
6
test/libyul/yulSyntaxTests/byte_of_string_literal.yul
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
let x := byte(31, "11112222333344445555666677778888")
|
||||
}
|
||||
// ====
|
||||
// dialect: evm
|
||||
// ----
|
6
test/libyul/yulSyntaxTests/linkersymbol_evm.yul
Normal file
6
test/libyul/yulSyntaxTests/linkersymbol_evm.yul
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
let addr := linkersymbol("contract/library.sol:L")
|
||||
}
|
||||
// ====
|
||||
// dialect: evm
|
||||
// ----
|
6
test/libyul/yulSyntaxTests/linkersymbol_evmtyped.yul
Normal file
6
test/libyul/yulSyntaxTests/linkersymbol_evmtyped.yul
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
let addr:u256 := linkersymbol("contract/library.sol:L")
|
||||
}
|
||||
// ====
|
||||
// dialect: evmTyped
|
||||
// ----
|
7
test/libyul/yulSyntaxTests/linkersymbol_ewasm.yul
Normal file
7
test/libyul/yulSyntaxTests/linkersymbol_ewasm.yul
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
linkersymbol("contract/library.sol:L")
|
||||
}
|
||||
// ====
|
||||
// dialect: ewasm
|
||||
// ----
|
||||
// DeclarationError 4619: (6-18): Function not found.
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
let library_name := "contract/library.sol:L"
|
||||
let addr := linkersymbol(library_name)
|
||||
}
|
||||
// ====
|
||||
// dialect: evm
|
||||
// ----
|
||||
// TypeError 9114: (67-79): Function expects direct literals as arguments.
|
6
test/libyul/yulSyntaxTests/loadimmutable.yul
Normal file
6
test/libyul/yulSyntaxTests/loadimmutable.yul
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
let addr := loadimmutable("address")
|
||||
}
|
||||
// ====
|
||||
// dialect: evm
|
||||
// ----
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
setimmutable(loadimmutable("abc"), "abc")
|
||||
}
|
||||
// ====
|
||||
// dialect: evm
|
||||
// ----
|
||||
// TypeError 9114: (6-18): Function expects direct literals as arguments.
|
6
test/libyul/yulSyntaxTests/setimmutable.yul
Normal file
6
test/libyul/yulSyntaxTests/setimmutable.yul
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
setimmutable("address", 0x1234567890123456789012345678901234567890)
|
||||
}
|
||||
// ====
|
||||
// dialect: evm
|
||||
// ----
|
7
test/libyul/yulSyntaxTests/string_literal_too_long.yul
Normal file
7
test/libyul/yulSyntaxTests/string_literal_too_long.yul
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
let name := "long___name___that___definitely___exceeds___the___thirty___two___byte___limit"
|
||||
}
|
||||
// ====
|
||||
// dialect: evm
|
||||
// ----
|
||||
// TypeError 3069: (18-97): String literal too long (77 > 32)
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
let x := byte(40, "long___value__that___definitely___exceeds___the___thirty___two___byte___limit")
|
||||
}
|
||||
// ====
|
||||
// dialect: evm
|
||||
// ----
|
||||
// TypeError 3069: (24-103): String literal too long (77 > 32)
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
setimmutable(
|
||||
"long___name___that___definitely___exceeds___the___thirty___two___byte___limit",
|
||||
0x1234567890123456789012345678901234567890
|
||||
)
|
||||
}
|
||||
// ====
|
||||
// dialect: evm
|
||||
// ----
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
let addr := linkersymbol("contract/long___name___that___definitely___exceeds___the___thirty___two___byte___limit.sol:L")
|
||||
}
|
||||
// ====
|
||||
// dialect: evm
|
||||
// ----
|
@ -8,6 +8,7 @@
|
||||
" ether "
|
||||
" finney "
|
||||
" gasleft() "
|
||||
" gwei "
|
||||
" hours "
|
||||
" minutes "
|
||||
" msg.data "
|
||||
|
@ -182,7 +182,10 @@ u256 EVMInstructionInterpreter::eval(
|
||||
case Instruction::ADDRESS:
|
||||
return m_state.address;
|
||||
case Instruction::BALANCE:
|
||||
return m_state.balance;
|
||||
if (arg[0] == m_state.address)
|
||||
return m_state.selfbalance;
|
||||
else
|
||||
return m_state.balance;
|
||||
case Instruction::SELFBALANCE:
|
||||
return m_state.selfbalance;
|
||||
case Instruction::ORIGIN:
|
||||
|
Loading…
Reference in New Issue
Block a user