This document provides an overview of Solidity programming concepts for developing smart contracts on Ethereum, including how to compile contracts, basic language features like comments and data types, documentation features like NatSpec, structs, conditional expressions, variables, mappings, inheritance, and function modifiers. It also discusses gas costs and calling methods between contracts.
Software and Systems Engineering Standards: Verification and Validation of Sy...
Learn Solidity Basics Like Comments, Variables, Structs
1. Ethereum Developers
Community
Learning Solidity
Arnold Pham
Lunyr Inc.
https://www.linkedin.com/in/arnoldpham/
Unless otherwise stated, these slides are licensed under the Creative Commons Attribution-
NonCommercial 3.0 License (https://creativecommons.org/licenses/by-nc/3.0/us/)
5. Version Pragma
• Annotates source files with a prerequisite
• Comes from semantic versioning which is widely used in the JavaScript
community (https://docs.npmjs.com/misc/semver)
^pragma solidity ^0.4.0 means >= compiler version 0.4.0 but <0.5.0
6. Comments
Use // or /*...*/
pragma solidity ^0.4.0;
/*
Multisignature Wallet for requiring multiple owners to approve a transaction
*/
contract MultiSigWallet{
address[] public owners;
uint public required; // the number of owner approval required
}
7. Natspec documentation
Produced as an object when you call a contract object from eth.compile.solidity(source)
Contract objects have the following properties
• code
• info
• source
• language
• languageVersion
• compilerVersion
• abiDefinition
• userDoc
• the Natspec Doc for users
• developerDoc
• the Natspec Doc for developers
8. Natspec
@title: This is a title that should describe the contract and go above the contract
definition
@author: The name of the author of the contract. Should also go above the
contract definition.
@notice: Represents user documentation. This is the text that will appear to the
user to notify him of what the function he is about to execute is doing
@dev: Represents developer documentation. This is documentation that would
only be visible to the developer.
@param: Documents a parameter just like in doxygen. Has to be followed by the
parameter name.
@return: Documents the return type of a contract's function.
9. Structs
• Advantageous for describing a set of variables that will be repeatedly used to
describe something
• Defines a new type
• Cheaper to use than abstract contracts which require paying gas for contract
creation
10. Structs example
Imagine you have a contract that registers people, and will do that repeatedly
struct Person{
string name;
uint birthdate;
enum gender;
}
mapping (uint => Person) people;
uint personID;
11. Conditional Expressions
Uses control structures that are typical in other languages
1. if
2. else
3. while
4. do
5. for
6. break
7. continue
8. return
9. ? :
12. Warning with loops
Operations cost gas so it is best to construct loops to repeat a known number of
times if possible
13. Boolean Expressions
Widely used for throw, which reverses all side effects
function transfer(address _to, uint256 _value) returns (bool) {
var senderBalance = balances[msg.sender];
if (senderBalance >= _value && _value > 0) {
senderBalance -= _value;
balances[msg.sender] = senderBalance;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
}
return false;
}
14. Variables
State and local variables are in storage by default
contract Products {
mapping (address->uint) owned
}
15. Mappings
Only allowed for state variables
Mappings can be seen as hashtables which are virtually initialized such that
every possible key exists and is mapped to a value
16. Global variables
1. msg.sender
a. the address of the sender in the current call
2. msg.value
a. the amount of wei sent with the message
3. now
a. the current unix timestamp in seconds
17. Visibility for functions and state variables
• Public
• can be called either internally or from messages
• default for functions
• Private
• can only be called from the contract that it is defined in and not from
derived contracts
• Internal
• can be called from the contract it is defined in or in derived contracts
• default for state variables
• External
• can only be called from other contracts and via transactions
• cannot be called internally
18. Inheritance
• For contracts inheriting from multiple other contracts, only a single contract is
created on the blockchain
• The code from the base contracts is copied into the final contract
21. “super”
• Use “super” to call the next position in line in the inheritance hierarchy
• If Base1 calls a function of super, then it will call it on Base2 rather than on
Base1
23. Bytes32
• Each bytes32 can store up to 32 letters (ASCII): each character is a byte.
• The EVM has a word-size of 32 bytes, so it is "optimized" for dealing with data
in chunks of 32 bytes. (Compilers, such as Solidity, have to do more work and
generate more bytecode when data isn't in chunks of 32 bytes, which
effectively leads to higher gas cost.)
24. Gas costs
• ~20,000 gas when a value is set to non-zero from zero
• ~5,000 gas when writing to existing storage or setting a value to zero
• ~15,000 gas refund when a non-zero value is set to zero.
Solidity is a statically typed language. The type of every variable must be specified at compile-time
Allows changes that do not modify the left-most non-zero digit
http://ethereum.stackexchange.com/questions/8615/child-contract-vs-struct
Under most circumstances, data structures, even complicated ones, should be structs.
Here are some reasons to choose structs:
Contracts are more expensive. You'll have to pay for the contract's creation initially, and every time you access it, you'll need to pay for a call to another contracts. This is much, much more expensive than a sha3 for a lookup inside the contract's own storage.
Contracts must replicate code. Every contract must contain the logic for setting and altering values, which you must pay for in gas. A struct needs only set of functions.
Contracts are exposed. Anyone can send a message to a contract. If you use a contract for storing data structures, you'll have to manage access manually.
Libraries might be what you're actually looking for. If you find yourself looking for functions on a data structure (i.e. foo.bar()), you can use a library contract to do it without the additional complexity of creating contracts for every instance.
Here are some reasons where contracts would be superior:
Contracts can be polymorphic. A contract could potentially contain arbitrary code. This allows multiple types to be intermingled, or even to have users bring their own logic.
The logic will be split. In this registrar contract each Deed could have been a struct. By making Deeds their own contracts, there is less of an attack surface for the Deeds themselves, reducing the chance of another TheDAO-scale disaster.
Contracts are exposed. If users have to configure their data structures, having a unique address they can interface with directly may prove simpler.
Contracts are contracts. A child contract can do anything a contract can do. If the data structures, for some reason, would own things as an address would, then having a contract would be far superior. A contract can directly hold Ether, as opposed to a struct sharing the main contract's balance with other structs.
However, these are less common. My advice: try it with structs first, and use data structure contracts as a last resort.
Solidity is a statically typed language. The type of every variable must be specified at compile-time