learnxinyminutes-docs/solidity.html.markdown

486 lines
16 KiB
Markdown
Raw Normal View History

2015-11-23 21:02:00 +00:00
---
language: Solidity
filename: learnSolidity.sol
contributors:
- ["Nemil Dalal", "https://www.nemil.com"]
---
2015-12-11 18:07:01 +00:00
Solidity lets you program on [Ethereum](https://www.ethereum.org/), a blockchain-based virtual machine that allows the creation and computation of smart contracts, without needing centralized or trusted parties.
2015-11-23 21:02:00 +00:00
2015-12-11 18:07:01 +00:00
Solidity is a statically typed, contract programming language that has similarities to Javascript and C. Like an object in object-oriented languages, each contract contains state variables, functions, and common data types. Contract-specific features include modifier (guard) clauses, event notifiers, and custom variables.
2015-11-23 21:02:00 +00:00
As Solidity and Ethereum are under active development, experimental or beta features are explicitly marked, and subject to change. Pull requests welcome.
```javascript
// Let's start with a simple Bank contract, before diving into to the key components of the language
2015-11-30 21:51:53 +00:00
// This bank has three main capabilities:
// - deposit
// - withdrawal
// - check balance
2015-11-23 21:02:00 +00:00
2015-11-30 20:45:03 +00:00
// ** START EXAMPLE **
2015-11-23 21:02:00 +00:00
// Start with a Natspec comment (the three slashes) that can be used
// for documentation - and as descriptive data for UI elements
/// @title A simple deposit/withdrawal bank built on Bitcoin
// All contracts are declared and named (in CamelCase)
2015-11-24 05:09:10 +00:00
// They are similar to 'class' in other languages (and allow capabilities like inheritance)
2015-11-23 21:02:00 +00:00
contract AcmeBank {
2015-11-30 20:45:03 +00:00
// Declare state variables outside a function,
2015-11-23 21:02:00 +00:00
// these are persistent throughout the life of the contract
// a dictionary that maps addresses to balances
2015-11-30 22:23:41 +00:00
// the private means that other contracts can't see balances
// but the data is still available to all other parties on the
// blockchain
mapping (address => uint) private balances;
2015-11-30 20:45:03 +00:00
// the 'public' makes 'owner' externally readable by users or contracts
2015-11-30 22:23:41 +00:00
// (but not writeable)
2015-11-30 20:45:03 +00:00
address public owner;
2015-11-23 21:02:00 +00:00
// Constructor, can receive one or many variables here
function AcmeBank() {
2015-11-30 20:45:03 +00:00
// msg is a default variable that provides both the
2015-11-23 21:02:00 +00:00
// contract messager's address and amount
2015-11-24 05:09:10 +00:00
owner = msg.sender; // msg.sender refers to the address of the contract creator
2015-11-23 21:02:00 +00:00
}
2015-11-30 20:45:03 +00:00
2015-12-11 18:07:01 +00:00
function deposit(uint balance) public returns (uint) {
2015-11-23 21:02:00 +00:00
balances[msg.sender] += msg.value; // no need for "this." or "self." in front of the state variable
2015-11-23 21:39:05 +00:00
return balances[msg.sender]; // msg.sender refers to the contract caller
2015-11-23 21:02:00 +00:00
}
2015-11-30 20:45:03 +00:00
function withdraw(uint withdrawAmount) public returns (uint remainingBalance) {
2015-11-23 21:02:00 +00:00
if(balances[msg.sender] >= withdrawAmount) {
balances[msg.sender] -= withdrawAmount;
2015-11-23 21:07:17 +00:00
2015-11-24 05:09:10 +00:00
if (!msg.sender.send(withdrawAmount)) {
2015-11-23 21:07:17 +00:00
balances[msg.sender] += withdrawAmount;
}
2015-11-23 21:02:00 +00:00
return balances[msg.sender];
}
}
// The 'constant' prevents the function from editing state variables
2015-12-11 18:07:01 +00:00
function balance() constant returns (uint) {
2015-11-23 21:02:00 +00:00
return balances[msg.sender];
}
// Fallback function
2015-11-30 20:45:03 +00:00
// The fallback function is called if none of the other functions matches the given function identifier.
2015-11-30 21:01:51 +00:00
// Typically, called when invalid data is sent to the contract or ether without data.
2015-11-23 21:02:00 +00:00
// Added so that ether sent to this contract is reverted if the contract fails
// otherwise, the sender loses their money; you should add this in most contracts
function () { throw; }
}
2015-11-30 20:45:03 +00:00
// ** END EXAMPLE **
2015-11-23 21:02:00 +00:00
// Now let's go through the basics of Solidity
2015-11-30 20:48:47 +00:00
// 1. DATA TYPES AND ASSOCIATED METHODS
2015-11-23 21:02:00 +00:00
// uint is the data type typically used for currency (there are no doubles
// or floats) and for dates
2015-11-30 20:45:03 +00:00
uint x;
2015-11-30 21:01:51 +00:00
// with 'constant', the compiler replaces each occurrence with the actual value
2015-11-30 20:45:03 +00:00
// int of 256 bits, cannot be changed after instantiation
int constant a = 8;
2015-11-30 21:01:51 +00:00
int256 constant a = 8; // same effect as line above, here the 256 is explicit
2015-12-11 18:07:01 +00:00
uint constant VERSION_ID = 0x123A1; // A hex constant
2015-11-30 20:45:03 +00:00
// For both int and uint, you can explicitly set space in steps of 8
// e.g., int8, int16
2015-11-23 21:02:00 +00:00
uint8 b;
int64 c;
uint248 e;
// Type casting
2015-11-30 20:45:03 +00:00
int x = int(b);
2015-11-23 21:02:00 +00:00
bool b = true; // or do 'var b = true;' for inferred typing
// Addresses - holds 20 byte/160 bit Ethereum addresses to another contract
// ('Contract Account)') or person/external entity ('External Account')
address public owner; // Add 'public' field to indicate publicly/externally accessible, a getter is automatically created, but NOT a setter
// All addresses can be sent ether in the following way:
owner.send(SOME_BALANCE); // returns false on failure
owner.balance; // the balance of the owner
// Bytes are provided from 1 to 32
byte a; // byte is same as bytes1
bytes32 b;
// Dynamically sized
bytes m; // A special array, same as byte[] (but packed tightly)
// same as bytes, but does not allow length or index access (for now)
string n = 'hello';
// Type inference
2015-11-30 20:45:03 +00:00
// var does inferred typing based on first assignment,
2015-11-23 21:02:00 +00:00
// can't be used in functions parameters
var a = true;
2015-11-30 20:45:03 +00:00
// there are edge cases where inference leads to a value being set (e.g., an uint 8)
2015-11-23 21:02:00 +00:00
// that is different from what the user wanted (uint16), so use carefully
// by default, all values are set to 0 on instantiation
2015-11-30 22:23:41 +00:00
// Delete can be called on most types
// (it does NOT destroy the value, but rather sets the value to 0 by assignment)
2015-11-23 21:02:00 +00:00
uint x = 5;
2015-11-30 22:23:41 +00:00
delete x; // x is now 0
2015-11-23 21:02:00 +00:00
2015-11-30 20:48:47 +00:00
2015-11-23 21:02:00 +00:00
// 2. DATA STRUCTURES
// Arrays
2015-11-30 20:45:03 +00:00
bytes32[5] nicknames; // static array
bytes32[] names; // dynamic array
2015-11-23 21:02:00 +00:00
uint newLength = names.push("John"); // adding returns new length of the array
// Length
names.length; // get length
names.length = 1; // lengths can also be set, unlike many other languages
// Dictionaries (any type to any other type)
2015-11-24 05:09:10 +00:00
mapping (string => uint) public balances;
2015-11-23 21:02:00 +00:00
balances["john"] = 1;
console.log(balances[jill]); // is 0, all non-set key values return zeroes
// The 'public' lets you do the following from another contract
contractName.balances("john"); // returns 1
// The 'public' keyword here created a getter (but not setter) that behaves like the following:
function balances(address _account) returns (uint balance) {
return balances[_account];
}
// To delete
2015-11-30 22:23:41 +00:00
delete balances["John"];
delete balances; // deletes all elements
2015-11-23 21:02:00 +00:00
// Unlike languages like Javascript, you cannot iterate through all elements in
// a map, without knowing the source keys
2015-11-30 20:45:03 +00:00
// Structs and enums
2015-11-23 21:02:00 +00:00
struct Bank { // note the capital
address owner;
uint balance;
}
Bank b = Bank({
2015-11-30 20:45:03 +00:00
owner: msg.sender,
2015-11-23 21:02:00 +00:00
balance: 5
});
2015-11-30 22:23:41 +00:00
delete b; // set all variables in struct to 0, except any mappings
2015-11-23 21:02:00 +00:00
// Enums
enum State { Created, Locked, Inactive };
State public state; // Declare variable from enum
state = State.Created;
2015-11-30 20:45:03 +00:00
// enums can be explicitly converted to ints
2015-11-23 21:02:00 +00:00
2015-11-30 20:45:03 +00:00
// Data locations: Memory vs. storage - all complex types (arrays, structs) have a data location
// 'memory' does not persist, 'storage' does
// Default is 'storage' for local and state variables; 'memory' for function parameters
2015-11-23 21:02:00 +00:00
2015-11-30 20:48:47 +00:00
2015-11-30 20:45:03 +00:00
// 3. Variables of note
// ** this **
this; // the address of the current contract
// 'balance' often used at the end of a contracts life to send the
// remaining balance to a party
this.balance;
this.someFunction(); // calls a function externally (via a message call, not via an internal jump)
2015-11-23 21:02:00 +00:00
2015-11-30 20:45:03 +00:00
// ** msg - The current message received by the contract ** **
2015-11-23 21:02:00 +00:00
msg.sender; // address, The address of the sender
msg.value; // uint, The amount of gas provided to this contract in wei
2015-11-30 20:45:03 +00:00
msg.data; // bytes, complete call data
msg.gas; // remaining gas
2015-11-23 21:02:00 +00:00
2015-11-30 20:45:03 +00:00
// ** tx - This transaction **
tx.origin; // address, sender of the transaction
tx.gasprice; // uint, gas price of the transaction
// ** block - Information about the current block **
2015-11-23 21:02:00 +00:00
now // uint, current time, alias for block.timestamp
2015-11-30 20:45:03 +00:00
block.number; // uint, current block number
block.difficulty; // uint, current block difficulty
block.blockhash(1); // returns bytes32, only provides for most recent 256 blocks
block.gasLimit();
// ** storage - A persistent storage hash (does not need to be declared) **
storage['abc'] = 'def'; // maps 256 bit words to 256 bit words
2015-11-23 21:02:00 +00:00
2015-11-30 20:48:47 +00:00
2015-11-23 21:02:00 +00:00
// 4. FUNCTIONS AND MORE
// A. Functions
// Simple function
function increment(uint x) returns (uint) {
x += 1;
return x;
}
// Functions can return many arguments, and by specifying the returned arguments
2015-11-30 21:01:51 +00:00
// you don't need to explicitly return
2015-11-23 21:02:00 +00:00
function increment(uint x, uint y) returns (uint x, uint y) {
x += 1;
y += 1;
}
// This function would have been called like this, and assigned to a tuple
uint (a,b) = increment(1,1);
// The 'constant' indicates and ensures that a function does not/cannot change the persistent variables
2015-11-30 22:23:41 +00:00
// Constant function execute locally, not on the blockchain
2015-11-23 21:02:00 +00:00
uint y;
function increment(uint x) constant returns (uint x) {
x += 1;
y += 1; // this line would fail
// as y is a state variable, and can't be changed in a constant function
}
// There are a few 'function visibility specifiers' that can be placed where 'constant'
// is, which include:
// internal (can only be called by an internal function, not one external to the contract)
2015-11-30 21:01:51 +00:00
// public - visible externally and internally
2015-11-23 21:02:00 +00:00
// private - only visible in the current contract
// Functions are hoisted (so you can call a function, even if it is declared later) - and you can assign a function to a variable
function a() {
var z = b;
b();
}
function b() {
}
// B. Events
// Events are an easy way to notify external listeners that something changed
2015-11-30 20:45:03 +00:00
// You typically declare them after your contract parameters
2015-11-23 21:02:00 +00:00
event Sent(address from, address to, uint amount);
// You then call it in a function, when you want to trigger it
sent(from, to, amount);
2015-11-30 20:45:03 +00:00
// For an external party (a contract or external entity), to watch
2015-11-23 21:02:00 +00:00
// for an event, you write the following:
Coin.Sent().watch({}, '', function(error, result) {
if (!error) {
console.log("Coin transfer: " + result.args.amount +
" coins were sent from " + result.args.from +
" to " + result.args.to + ".");
console.log("Balances now:\n" +
"Sender: " + Coin.balances.call(result.args.from) +
"Receiver: " + Coin.balances.call(result.args.to));
}
}
2015-11-30 20:45:03 +00:00
// This is a common paradigm for one contract to depend on another (e.g., a
2015-11-23 21:02:00 +00:00
// contract that depends on the current exchange rate provided by another
// contract)
// C. Modifiers
2015-11-30 20:45:03 +00:00
// Modifiers let you validate inputs to functions such as a minimal balance or user authentication
// It's similar to a guard clause in other languages
// The '_' (underscore) must be included as the last line in the function body, and is an indicator that the
2015-11-23 21:02:00 +00:00
// function being called should be placed there
2015-12-11 18:07:01 +00:00
modifier onlyAfter(uint _time) { if (now <= _time) throw; _ }
modifier onlyOwner { if (msg.sender == owner) _ }
2015-11-23 21:02:00 +00:00
// You can then append it right after the function declaration
2015-11-30 20:45:03 +00:00
function changeOwner(newOwner)
2015-12-11 18:07:01 +00:00
onlyAfter(someTime)
onlyOwner()
{
2015-11-30 20:45:03 +00:00
owner = newOwner;
2015-11-23 21:02:00 +00:00
}
2015-11-30 20:48:47 +00:00
2015-11-23 21:02:00 +00:00
// 5. BRANCHING AND LOOPS
// All basic logic blocks work - including if/else, for, while, break, continue, return
2015-12-11 18:07:01 +00:00
// Unlike other languages, the 'switch' statement is NOT provided
2015-11-23 21:02:00 +00:00
2015-11-30 20:45:03 +00:00
// Syntax is the same as javascript, but there is no type conversion from
// non-boolean to boolean, so comparison operators must be used to get the boolean value
2015-11-30 20:48:47 +00:00
2015-11-30 20:45:03 +00:00
// 6. OBJECTS/CONTRACTS
2015-11-23 21:02:00 +00:00
2015-11-30 20:45:03 +00:00
// A. Calling an external contract
2015-11-23 21:02:00 +00:00
contract infoFeed {
function info() returns (uint ret) { return 42; }
}
contract Consumer {
InfoFeed feed; // create a variable that will point to a contract on the blockchain
2015-11-30 20:45:03 +00:00
// Set feed to an existing contract
function setFeed(address addr) {
2015-11-23 21:02:00 +00:00
// Link to the contract by creating on the address
2015-11-30 20:45:03 +00:00
feed = InfoFeed(addr);
2015-11-23 21:02:00 +00:00
}
2015-11-30 20:45:03 +00:00
// Set feed based to a new instance of the contract
function createNewFeed() {
feed = new InfoFeed();
}
function callFeed() {
// T final parentheses call the contract, optionally adding
2015-11-23 21:02:00 +00:00
// custom value or gas numbers
feed.info.value(10).gas(800)();
}
}
2015-11-30 20:45:03 +00:00
// B. Inheritance
// Order matters, last inherited contract (i.e., 'def') can override parts of the previously
// inherited contracts
contact MyContract is abc, def("a custom argument to def") {
// Override function
function z() {
if (msg.sender == owner) {
def.z(); // call overridden function
}
}
};
// C. Import
import "filename";
import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol";
// Importing is under active development and will change
// Importing cannot currently be done at the command line
2015-11-30 20:48:47 +00:00
2015-11-23 21:02:00 +00:00
// 7. CONTRACT DESIGN PATTERNS
// A. Obfuscation
2015-11-30 20:45:03 +00:00
// Remember that all variables are publicly viewable on the blockchain, so
2015-11-23 21:02:00 +00:00
// anything that needs some privacy needs to be obfuscated (e.g., hashed)
// B. Throwing
// Throwing
throw; // throwing is easily done, and reverts unused money to the sender
// You can't currently catch
// A common design pattern is:
if (!addr.send(123)) {
throw;
}
// C. Suicide
// Suicide
suicide(SOME_ADDRESS); // suicide the current contract, sending funds to the address (often the creator)
2015-12-11 18:07:01 +00:00
// This is a common contract pattern that lets the owner end the contract, and receive remaining funds
2015-11-30 20:45:03 +00:00
function remove() {
if(msg.sender == owner) { // Only let the contract creator do this
suicide(owner); // suicide makes this contract inactive, and returns funds to the owner
}
}
2015-11-23 21:02:00 +00:00
// D. Storage optimization
2015-11-30 20:45:03 +00:00
// Reading and writing can be expensive, as data needs to be stored in the
// blockchain forever - this encourages smart ways to use memory (eventually,
// compilation may better handle this, but for now there are benefits to
2015-11-23 21:02:00 +00:00
// planning your data structures)
2015-11-30 20:48:47 +00:00
2015-11-23 21:02:00 +00:00
// *** EXAMPLE: Let's do a more complex example ***
2015-11-30 20:45:03 +00:00
// ** START EXAMPLE **
2015-11-24 05:09:10 +00:00
// [TODO: Decide what a more complex example looks like, needs a few characteristics:
2015-11-23 21:02:00 +00:00
// - has a 'constant' state variable
2015-11-30 20:45:03 +00:00
// - has a state machine (and uses modifier)
2015-11-23 21:02:00 +00:00
// - sends money to an address
// - gets information from another contract (we'll show code for both contracts)
// - Shows inheritance
// - show variables being passed in on instantiation (and guard code to throw if variables not provided)
2015-11-30 20:45:03 +00:00
// - Shows the swapping out of a contract address
2015-11-23 21:02:00 +00:00
// Ideas:
// - crowdfunding?
// - Peer to peer insurance
// ]
2015-11-30 21:51:53 +00:00
// It's good practice to have a remove function, which disables this
// contract - but does mean that users have to trust the owner
// For a decentralized bank without a trusted part
function remove() {
if(msg.sender == owner) { // Only let the contract creator do this
suicide(owner); // suicide makes this contract inactive, and returns funds to the owner
}
}
2015-11-23 21:02:00 +00:00
// *** END EXAMPLE ***
2015-11-30 20:48:47 +00:00
2015-11-23 21:02:00 +00:00
// 7. NATIVE FUNCTIONS
// Currency units
// By default, currency is defined using wei, the smallest unit of Ether
uint minAmount = 1 wei;
uint a = 1 finney; // 1 ether = 1000 finney
// There are a number of other units, see: http://ether.fund/tool/converter
// Time units
1 == 1 second
1 minutes == 60 seconds
2015-11-30 20:45:03 +00:00
// You typically multiply a variable times the unit, as these units are not
2015-11-23 21:02:00 +00:00
// directly stored in a variable
uint x = 5;
(x * 1 days); // 5 days
// Be careful about leap seconds and leap years when using equality statements for time (instead, prefer greater than/less than)
// Cryptography
// All strings passed are concatenated before the hash is run
sha3("ab", "cd");
ripemd160("abc");
sha256("def");
2015-11-30 20:48:47 +00:00
2015-11-30 20:45:03 +00:00
// 8. COMMON MISTAKES/MISCONCEPTIONS
// A few common mistakes and misconceptions:
2015-11-23 21:02:00 +00:00
2015-11-30 20:45:03 +00:00
// A. You cannot restrict a human or computer from reading the content of
2015-11-23 21:02:00 +00:00
// your transaction or a transaction's state
2015-11-30 20:45:03 +00:00
// All data to the start of time is stored in the blockchain, so you and
// anyone can observe all previous data stats
2015-11-23 21:02:00 +00:00
2015-11-30 20:45:03 +00:00
// When you don't specify public on a variable, you are indicating that other *contracts* can't
// read the data - but any person can still read the data
2015-11-24 05:09:10 +00:00
2015-11-30 20:45:03 +00:00
// TODO
2015-11-30 20:48:47 +00:00
2015-11-30 20:45:03 +00:00
// 9. STYLE NOTES
// Use 4 spaces for indentation
2015-11-23 21:02:00 +00:00
// (Python's PEP8 is used as the baseline style guide, including its general philosophy)
```
## Additional resources
- [Solidity Docs](https://ethereum.github.io/solidity/docs/home/)
- [Solidity Style Guide](https://ethereum.github.io/solidity//docs/style-guide/): Ethereum's style guide is heavily derived from Python's [pep8](https://www.python.org/dev/peps/pep-0008/) style guide.
- [Browser-based Solidity Editor](http://chriseth.github.io/browser-solidity/)
- [Gitter Chat room](https://gitter.im/ethereum/go-ethereum)
2015-11-30 21:14:26 +00:00
## Sample contracts
2015-12-11 18:07:01 +00:00
- [Dapp Bin](https://github.com/ethereum/dapp-bin)
2015-11-30 21:14:26 +00:00
- [Solidity Baby Step Contracts](https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts)
- [Consensys Contracts](https://github.com/ConsenSys/dapp-store-contracts)
2015-11-30 22:23:41 +00:00
- [State of Dapps](http://dapps.ethercasts.com/)
2015-11-30 21:14:26 +00:00
2015-11-30 20:45:03 +00:00
## Information purposefully excluded
- Libraries
Feel free to send a pull request with any edits - or email nemild -/at-/ gmail