Upload
nicholas-lin
View
64
Download
3
Embed Size (px)
Citation preview
ethereum smart contract
林修平
online compiler
• online compiler :https://ethereum.github.io/browser-solidity/
MANUAL COMPILE(using geth)
• connect to console
• set up a chain
• connect to main chain: go-ethereum/build/bin/geth console
• connect to testnet: go-ethereum/build/bin/geth --testnet console
• build a private net: go-ethereum/build/bin/geth --datadir “your_directory" --rpc --rpcport port --rpccorsdomain "*" --port "30303" --nodiscover --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --rpcapi "db,eth,net,web3" --autodag --networkid number --nat "any" console
MANUAL COMPILE(using geth)
• in console
• var contractABI = web3.eth.contract([{contractABI}]);
• var contract123 = contractABI.new( parameters, {from: address, data: bytecode, gas: gas }, callback_function)
Quick Intro
• price unit: ether
• address: you can withdraw from or save ether to it.
• it can represent an user account
• no code
• or represent a contract
• tied with a code
• NOTE: same code on different address is different contract
• transaction:• send ether
• or to execute function in a contract
• or both
Quick Intro
• contract: comprised of state and function
• state: used by user to keep information regarding the contract
• function: change state of a contract
• NOTE: Ethereum discourage users from using state to preserve information, so it cost a lot of gas to either create or change the state.
• WHY? Since every node(miner) needs to keep a full copy of the blockchain, they have to be compensated for storage cost of every contract.
• gas
• every function comprised of many operations and there’s a price to every type of operation
• there’s a fixed amount of gas cost to function you design and you have to pay for it when you want to execute a function
• you can decide how much ether you want to pay per gas and that becomes transaction fee needed for this execution
Quick Intro
• If you are on a public chain, every storage cost matters.
• But what if you are on a private chain?
• you can have ether as many as you want so you don’t need to worry about transaction fee
• but does it mean that you can use as many storage as you want?
• YES! but still, the costs of storing these states are to be taken by all nodes in your private chain
Quick Intro
How it work
• state• function: operate on states
• design logic: use functions to make your contract work
How it work
How it work
contract Count123{uint counts(0);function incre(){
counts = count + 1;
}}
Transaction(Deploy)
How it work
contract Count123{uint counts(0);function incre(){
counts = count + 1;
}}
How it work
Transaction(Invoke)
Count123.incre()contract Count123{
uint counts(0);function incre(){
counts = count + 1;
}}
let’s take slock.it for example and write a simple bike renting contract!
slock.it
How it work
state declaration
state declaration
contract bikeRenting {
address public owner;
address public currentRenter;
uint public expireTime;
…
}
• type , visibility , variable_name
state declaration
contract bikeRenting {
address public owner;
address public currentRenter;
uint public expireTime;
…
}
• type , visibility , variable_name
• type : bool, int, uint, address, mapping, bytes, string, struct
• visibility : public or private(default)
• public: accessible externally(declare in your contract) uint public totalCount = 3;(access in a console) mycontract.totalCount(); //3(access from other contract) thatcontract.totalCount() //3
• variable_name
state declaration
• Array in solidity :
• address[] owners; address[3] threeOwners;
• push item into array: owners.push(address)
• delete item: delete owners[2]
• pitfall: only changes the value of specified item to zero instead of erase the item
state declaration
• mapping :
• mapping(typeA => typeB) variable_name;
• example
• declare a mapping:
• mapping(address => uint) deposits;
• map address 0x123456789abcdef to integer 10:
• deposits[0x123456789abcdef] = 10;
• uninitialized or undeclared values are zero instead of NULL
• NOTE: there’s no NULL in Solidity
state declaration
• Units and Globally available variables
• Ether unit: ether、 finney、wei
• time unit: seconds、weeks、 years、 now
• now: present time
• more specifically, the time when this block is mined, i.e, the time_stamp parameter in the block header
state declaration
• Special variables and functions
• msg: information regarding this transaction
• msg.sender: address who send the transaction
• msg.value: value sent with the transaction
• address related functions
• address.balance
• address.send(amount): send ether to address
state declaration
• Special variables and functions
• throw
• reverts all changes made so far by the underlying transaction
• confiscate all gas provided by underlying transaction
state declaration
initialization
initialization
contract bikeRenting {address public owner;address public currentRenter;uint public expireTime;uint public unitPrice;
function bikeRenting(uint _unitPrice){
owner = msg.sender;
currentRenter = 0x0;
expireTime = now;
unitPrice = _unitPrice;
}
}
• constructor function
• it’s name is exactly the same as contract’s
• executed when the contract is been deployed to blockchain
• executed only once
• not necessary
initialization
function
contract bikeRenting {address public owner;address public currentRenter;uint public expireTime;uint public unitPrice;function bikeRenting(uint _unitPrice){
…}
function rent() payable returns(bool){if(currentRenter != 0x0) return false;else{
if( (msg.value/1 ether) / unitPrice < 1) return false; else {
expireTime = now + 15 minutes * (msg.value/1 ether)/unitPrice; currentRenter = msg.sender; rentingRecord(msg.sender, now, (msg.value/1 ether)/unitPrice);
}}
}
}
check if it’s been rented
how much time you getfor one unit
check if paid more than a unit price
functionhow many ether per unit
function functionName(parameter1, parameter2, …) returns(type) {
…
}
• declare parameters: bool a, uint b, address c, …
• returns:
• not necessary
• function foo() returns(uint, address, bool) { … return (1, 0x0, true);}
function
• visibility of a function
• public(default)
• private: only accessible by this contract
• internal: only accessible by this contract and contracts inherited from this one
• external: exactly the opposite of internal
• payable:
• decide if people can send ether while they execute this function, in other words, if you create a transaction to execute this function, you will be able to send the transaction along with some ether only if this function is a payable function
function
contract bikeRenting {address public owner;address public currentRenter;uint public expireTime;uint public unitPrice;function bikeRenting(uint _unitPrice){…}function rent() payable returns(bool){…}
function isInUse(bool ifWantToRent) payable returns(bool){if( expireTime > now ) return true;else{
currentRenter = 0x0;if( ifWantToRent == true) rent();
}}
}
this function checks if the bike is rented
ifWantToRent is a parameter sent byperson who execute this transaction,
indicating if he/she wants to rent this bike
not expired yet, it is rented
function
function
• we have to make sure person who executes isInUse function has the priority to rent if the bike is available because he/she pays transaction fee to execute this function
• why we need someone else to check if the bike is been rented or not?• because a smart contract is not a robot, it won’t execute a
command actively• it won’t lock the bike itself even time is up, it needs to be triggered
• but if there are more than two people execute the same function in the same time, there’s no guarantee on the order of the execution
• so we have to make sure person who gets to execute isInUse function first will have the priority to rent the bike because he/she pays for this execution
contract bikeRenting {address public owner;address public currentRenter;uint public expireTime;uint public unitPrice;function bikeRenting(uint _unitPrice){…}function rent() payable returns(bool){…}function isInUse(bool ifWantToRent) payable returns(bool){…}
function collectMoney() {if( msg.sender == owner){
owner.send(this.balance) ;}
}
}
make sure only owner can execute this function
function
privilege
privilege
• there’s no built-in mechanism to restrict execution privilege, you have to check if person who executes the function has the right to
• HOW?
• using msg.sender to compare with addresses which have the right to execute
function collectMoney() {
if(msg.sender == owner){
…
}
}
repetitive actions
• modifier
• attach to modifier: function bar() foo1() {…}
• attach to multiple modifiers: function bar() foo1() foo2() foo3(){…}
repetitive actions
modifier foo1 { do_something _; or_do_something_here}
a place holder for code of attaching function
contract foo1 {
…
modifier ownerCheck { if(msg.sender == owner ) _;}function collectMoney() ownerCheck {
owner.send(this.balance) ;}
…
}
repetitive actions
contract modifierTest{modifier foo1(){
foo1before;_;foo1after;
}modifier foo2(){
foo2before;_;foo2after;
}function bar() foo1() foo2() {
bar;}
}
repetitive actions
execution order:foo1beforefoo2beforebarfoo2afterfoo1after
contract creation in a contract
contract creation in a contract
contract foo{ … }
address newFooAddr = new foo();
• returns an address
foo foo1 = foo(newFooAddr);
• returns a contract
• NOTE: contract creation usually cost a lot of gas so remember to supply enough gas if you execute a function which creates new contracts
fallback function
fallback function
• it’s executed only when someone executes a function not existed in the contract or someone simply sends some ether to this contract
• not necessary
• pitfall:
• person who owns this contract gets to decide what to do in a fallback function
• if you simply sends some ether to this contract, you also have to pay for the execution of fallback function if there is one
function () {…
} function with no name
pitfalls
pitfalls
• throw when address.send() fails
• throw will revert all changes and confiscate all gas even if you are halfway there
for(uint i=0; i<investorsCount; i++) {
if( inverstors[i].send(100) == false )
throw;}
pitfalls
• throw when address.send() fails
• why address.send() fail?
• 1. out of gas
• supply enough gas
• 2. callstack
• 1024 layer
pitfalls
• throw when address.send() fails
• mitigation: use a withdraw pattern
• still, this solution leaves the problems mentioned to the msg sender
function withdraw(amount) {if( balances[msg.sender] >=
amount ) {msg.sender.send(amount);
balances[msg.sender] -= amount;}
}
pitfalls
• shared state between external call and external callable functionsfunction extCall() {
…external_call();…if(shared_state) {
…}…
}
function extCallable(){do_something_on_shared_state…
}
execute function ofsome other contract
then that function executethis function
pitfalls
• state corruption
• 1. sum of sizes of 1st and 2nd state variables are less than 256 bytes
• 2. first variable is not a signed interger or bytesXX typefunction extCall() {
uint32 a;uint32 b;function run() returns(uint32){
a--;return b;
}}
fixed after compiler version 0.4.4
Misc
• selfdestruct(recipient)
• terminate the contract, destroy code and storage, then transfer the remaining ether to recipient
• event: writes data into transaction receipt
• example: event paymentRecord(address indexed buyer, uint value)
• indexed: write data into topics field
• if data is more than 32 bytes, hash of data is written into topics instead
• transaction receipt
• data
• topics: can be used as a condition filter
Misc
• contract inheritance : contract Final is most-base-like, …, most-derived {…}
Misc
tips
• use delete on array to delete all elements
• --vmdebug, --verbosity
• --targetgaslimit