I often see inline assembly in Solidity contracts. I consider this a bad practice because of the poor readability, however this is my opinion only and there must be valid reasons to use it. There are no other means to reach the same results in pure Solidity code? and if not, doesn't this show a lack in the language design?
2 Answers
I think there're some points that we need to use assembly in the documents
1. smth that cannot be done by plain Solidity
https://solidity.readthedocs.io/en/v0.5.3/assembly.html#example
pragma solidity >=0.4.0 <0.6.0;
library GetCode {
function at(address _addr) public view returns (bytes memory o_code) {
assembly {
// retrieve the size of the code, this needs assembly
let size := extcodesize(_addr)
// allocate output byte array - this could also be done without assembly
// by using o_code = new bytes(size)
o_code := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
// store length in memory
mstore(o_code, size)
// actually retrieve the code, this needs assembly
extcodecopy(_addr, add(o_code, 0x20), 0, size)
}
}
}
2. Optimize code to produce efficient code
pragma solidity >=0.4.16 <0.6.0;
library VectorSum {
// This function is less efficient because the optimizer currently fails to
// remove the bounds checks in array access.
function sumSolidity(uint[] memory _data) public pure returns (uint o_sum) {
for (uint i = 0; i < _data.length; ++i)
o_sum += _data[i];
}
// We know that we only access the array in bounds, so we can avoid the check.
// 0x20 needs to be added to an array because the first slot contains the
// array length.
function sumAsm(uint[] memory _data) public pure returns (uint o_sum) {
for (uint i = 0; i < _data.length; ++i) {
assembly {
o_sum := add(o_sum, mload(add(add(_data, 0x20), mul(i, 0x20))))
}
}
}
// Same as above, but accomplish the entire code within inline assembly.
function sumPureAsm(uint[] memory _data) public pure returns (uint o_sum) {
assembly {
// Load the length (first 32 bytes)
let len := mload(_data)
// Skip over the length field.
//
// Keep temporary variable so it can be incremented in place.
//
// NOTE: incrementing _data would result in an unusable
// _data variable after this assembly block
let data := add(_data, 0x20)
// Iterate until the bound is not met.
for
{ let end := add(data, mul(len, 0x20)) }
lt(data, end)
{ data := add(data, 0x20) }
{
o_sum := add(o_sum, mload(data))
}
}
}
}
And due to it's low level then we only use then we need and confident to use it as warning from solidity document
Inline assembly is a way to access the Ethereum Virtual Machine at a low level. This bypasses several important safety features and checks of Solidity. You should only use it for tasks that need it, and only if you are confident with using it.
-
3That's the point, the recent 0x vulnerability was caused by assembly code put there to optimize space. It seems to me that security is king and accessing to assembly code is error prone even for the top developers.– Davide CCommented Jul 15, 2019 at 22:20
-
For security critical applications assembly is not a good idea.– feritCommented Jul 16, 2019 at 18:35
-
I assume all smart contracts are security critical applications.– Davide CCommented Jul 17, 2019 at 20:09
In mainstream languages such as C++ when one needs to do something not achievable via core language, he usually calls library function, either from standard or third-party library. This function may be implemented in assembly or in a high-level language different from the language the function is called from. Whoever calls the function usually don't care about what language the function is implemented in.
For Solidity the situation should not be different. If you need something not available in core language, try to find library for this.
When we talk about optimizations, starting from version 0.5.0 Solidity permanently disabled so called loose assembly that gives developer full control over generated byte code. What is left is so called functional-style assembly, that allows developer to include sophisticated opcodes such as CREATE2
, but does not allow him to directly control stack or execution flow. Compilation output of functional style assembly is then processed by Solidity optimizer. Thus inline assembly in Solidity is not suitable for manual optimizations anymore.
-
mainstream languages are not good for smart contracts imho. This is why I think inline assembly is a poor choice.– Davide CCommented Jul 15, 2019 at 22:22
-
Sorry, but I don't get your point. How the former implies the letter? Commented Jul 16, 2019 at 19:14