Merge pull request #541 from Denton-L/develop

Minor Documentation Changes
This commit is contained in:
chriseth 2016-05-06 19:03:28 +02:00
commit 9e36bdda8a
6 changed files with 208 additions and 90 deletions

View File

@ -67,6 +67,7 @@ This means that cyclic creation dependencies are impossible.
TokenCreator creator; TokenCreator creator;
address owner; address owner;
bytes32 name; bytes32 name;
// This is the constructor which registers the // This is the constructor which registers the
// creator and the assigned name. // creator and the assigned name.
function OwnedToken(bytes32 _name) { function OwnedToken(bytes32 _name) {
@ -78,12 +79,14 @@ This means that cyclic creation dependencies are impossible.
creator = TokenCreator(msg.sender); creator = TokenCreator(msg.sender);
name = _name; name = _name;
} }
function changeName(bytes32 newName) { function changeName(bytes32 newName) {
// Only the creator can alter the name -- // Only the creator can alter the name --
// the comparison is possible since contracts // the comparison is possible since contracts
// are implicitly convertible to addresses. // are implicitly convertible to addresses.
if (msg.sender == creator) name = newName; if (msg.sender == creator) name = newName;
} }
function transfer(address newOwner) { function transfer(address newOwner) {
// Only the current owner can transfer the token. // Only the current owner can transfer the token.
if (msg.sender != owner) return; if (msg.sender != owner) return;
@ -107,11 +110,13 @@ This means that cyclic creation dependencies are impossible.
// the ABI. // the ABI.
return new OwnedToken(name); return new OwnedToken(name);
} }
function changeName(OwnedToken tokenAddress, bytes32 name) { function changeName(OwnedToken tokenAddress, bytes32 name) {
// Again, the external type of "tokenAddress" is // Again, the external type of "tokenAddress" is
// simply "address". // simply "address".
tokenAddress.changeName(name); tokenAddress.changeName(name);
} }
function isTokenTransferOK( function isTokenTransferOK(
address currentOwner, address currentOwner,
address newOwner address newOwner
@ -222,8 +227,7 @@ The next example is a bit more complex:
It will generate a function of the following form:: It will generate a function of the following form::
function data(uint arg1, bool arg2, uint arg3) returns (uint a, bytes3 b) function data(uint arg1, bool arg2, uint arg3) returns (uint a, bytes3 b) {
{
a = data[arg1][arg2][arg3].a; a = data[arg1][arg2][arg3].a;
b = data[arg1][arg2][arg3].b; b = data[arg1][arg2][arg3].b;
} }
@ -258,6 +262,8 @@ inheritable properties of contracts and may be overridden by derived contracts.
// thrown. // thrown.
modifier onlyowner { if (msg.sender != owner) throw; _ } modifier onlyowner { if (msg.sender != owner) throw; _ }
} }
contract mortal is owned { contract mortal is owned {
// This contract inherits the "onlyowner"-modifier from // This contract inherits the "onlyowner"-modifier from
// "owned" and applies it to the "close"-function, which // "owned" and applies it to the "close"-function, which
@ -267,10 +273,14 @@ inheritable properties of contracts and may be overridden by derived contracts.
selfdestruct(owner); selfdestruct(owner);
} }
} }
contract priced { contract priced {
// Modifiers can receive arguments: // Modifiers can receive arguments:
modifier costs(uint price) { if (msg.value >= price) _ } modifier costs(uint price) { if (msg.value >= price) _ }
} }
contract Register is priced, owned { contract Register is priced, owned {
mapping (address => bool) registeredAddresses; mapping (address => bool) registeredAddresses;
uint price; uint price;
@ -339,13 +349,15 @@ possible.
uint x; uint x;
} }
// This contract rejects any Ether sent to it. It is good // This contract rejects any Ether sent to it. It is good
// practise to include such a function for every contract // practise to include such a function for every contract
// in order not to loose Ether. // in order not to lose Ether.
contract Rejector { contract Rejector {
function() { throw; } function() { throw; }
} }
contract Caller { contract Caller {
function callTest(address testAddress) { function callTest(address testAddress) {
Test(testAddress).call(0xabcdef01); // hash does not exist Test(testAddress).call(0xabcdef01); // hash does not exist
@ -406,6 +418,7 @@ All non-indexed arguments will be stored in the data part of the log.
bytes32 indexed _id, bytes32 indexed _id,
uint _value uint _value
); );
function deposit(bytes32 _id) { function deposit(bytes32 _id) {
// Any call to this function (even deeply nested) can // Any call to this function (even deeply nested) can
// be detected from the JavaScript API by filtering // be detected from the JavaScript API by filtering
@ -497,6 +510,7 @@ Details are given in the following example.
address owner; address owner;
} }
// Use "is" to derive from another contract. Derived // Use "is" to derive from another contract. Derived
// contracts can access all non-private members including // contracts can access all non-private members including
// internal functions and state variables. These cannot be // internal functions and state variables. These cannot be
@ -507,6 +521,7 @@ Details are given in the following example.
} }
} }
// These abstract contracts are only provided to make the // These abstract contracts are only provided to make the
// interface known to the compiler. Note the function // interface known to the compiler. Note the function
// without body. If a contract does not implement all // without body. If a contract does not implement all
@ -514,11 +529,14 @@ Details are given in the following example.
contract Config { contract Config {
function lookup(uint id) returns (address adr); function lookup(uint id) returns (address adr);
} }
contract NameReg { contract NameReg {
function register(bytes32 name); function register(bytes32 name);
function unregister(); function unregister();
} }
// Multiple inheritance is possible. Note that "owned" is // Multiple inheritance is possible. Note that "owned" is
// also a base class of "mortal", yet there is only a single // also a base class of "mortal", yet there is only a single
// instance of "owned" (as for virtual inheritance in C++). // instance of "owned" (as for virtual inheritance in C++).
@ -542,6 +560,7 @@ Details are given in the following example.
} }
} }
// If a constructor takes an argument, it needs to be // If a constructor takes an argument, it needs to be
// provided in the header (or modifier-invocation-style at // provided in the header (or modifier-invocation-style at
// the constructor of the derived contract (see below)). // the constructor of the derived contract (see below)).
@ -564,12 +583,18 @@ seen in the following example::
if (msg.sender == owner) selfdestruct(owner); if (msg.sender == owner) selfdestruct(owner);
} }
} }
contract Base1 is mortal { contract Base1 is mortal {
function kill() { /* do cleanup 1 */ mortal.kill(); } function kill() { /* do cleanup 1 */ mortal.kill(); }
} }
contract Base2 is mortal { contract Base2 is mortal {
function kill() { /* do cleanup 2 */ mortal.kill(); } function kill() { /* do cleanup 2 */ mortal.kill(); }
} }
contract Final is Base1, Base2 { contract Final is Base1, Base2 {
} }
@ -583,12 +608,18 @@ derived override, but this function will bypass
if (msg.sender == owner) selfdestruct(owner); if (msg.sender == owner) selfdestruct(owner);
} }
} }
contract Base1 is mortal { contract Base1 is mortal {
function kill() { /* do cleanup 1 */ super.kill(); } function kill() { /* do cleanup 1 */ super.kill(); }
} }
contract Base2 is mortal { contract Base2 is mortal {
function kill() { /* do cleanup 2 */ super.kill(); } function kill() { /* do cleanup 2 */ super.kill(); }
} }
contract Final is Base2, Base1 { contract Final is Base2, Base1 {
} }
@ -615,6 +646,8 @@ the base constructors. This can be done at two places::
uint x; uint x;
function Base(uint _x) { x = _x; } function Base(uint _x) { x = _x; }
} }
contract Derived is Base(7) { contract Derived is Base(7) {
function Derived(uint _y) Base(_y * _y) { function Derived(uint _y) Base(_y * _y) {
} }
@ -721,6 +754,7 @@ more advanced example to implement a set).
// We define a new struct datatype that will be used to // We define a new struct datatype that will be used to
// hold its data in the calling contract. // hold its data in the calling contract.
struct Data { mapping(uint => bool) flags; } struct Data { mapping(uint => bool) flags; }
// Note that the first parameter is of type "storage // Note that the first parameter is of type "storage
// reference" and thus only its storage address and not // reference" and thus only its storage address and not
// its contents is passed as part of the call. This is a // its contents is passed as part of the call. This is a
@ -735,6 +769,7 @@ more advanced example to implement a set).
self.flags[value] = true; self.flags[value] = true;
return true; return true;
} }
function remove(Data storage self, uint value) function remove(Data storage self, uint value)
returns (bool) returns (bool)
{ {
@ -743,14 +778,18 @@ more advanced example to implement a set).
self.flags[value] = false; self.flags[value] = false;
return true; return true;
} }
function contains(Data storage self, uint value) function contains(Data storage self, uint value)
returns (bool) returns (bool)
{ {
return self.flags[value]; return self.flags[value];
} }
} }
contract C { contract C {
Set.Data knownValues; Set.Data knownValues;
function register(uint value) { function register(uint value) {
// The library functions can be called without a // The library functions can be called without a
// specific instance of the library, since the // specific instance of the library, since the
@ -783,12 +822,14 @@ custom types without the overhead of external function calls:
library bigint { library bigint {
struct bigint { struct bigint {
uint[] limbs; uint[] limbs;
} }
function fromUint(uint x) internal returns (bigint r) { function fromUint(uint x) internal returns (bigint r) {
r.limbs = new uint[](1); r.limbs = new uint[](1);
r.limbs[0] = x; r.limbs[0] = x;
} }
function add(bigint _a, bigint _b) internal returns (bigint r) { function add(bigint _a, bigint _b) internal returns (bigint r) {
r.limbs = new uint[](max(_a.limbs.length, _b.limbs.length)); r.limbs = new uint[](max(_a.limbs.length, _b.limbs.length));
uint carry = 0; uint carry = 0;
@ -820,6 +861,7 @@ custom types without the overhead of external function calls:
} }
} }
contract C { contract C {
using bigint for bigint.bigint; using bigint for bigint.bigint;
function f() { function f() {
@ -882,6 +924,7 @@ Let us rewrite the set example from the
// This is the same code as before, just without comments // This is the same code as before, just without comments
library Set { library Set {
struct Data { mapping(uint => bool) flags; } struct Data { mapping(uint => bool) flags; }
function insert(Data storage self, uint value) function insert(Data storage self, uint value)
returns (bool) returns (bool)
{ {
@ -890,6 +933,7 @@ Let us rewrite the set example from the
self.flags[value] = true; self.flags[value] = true;
return true; return true;
} }
function remove(Data storage self, uint value) function remove(Data storage self, uint value)
returns (bool) returns (bool)
{ {
@ -898,6 +942,7 @@ Let us rewrite the set example from the
self.flags[value] = false; self.flags[value] = false;
return true; return true;
} }
function contains(Data storage self, uint value) function contains(Data storage self, uint value)
returns (bool) returns (bool)
{ {
@ -905,9 +950,11 @@ Let us rewrite the set example from the
} }
} }
contract C { contract C {
using Set for Set.Data; // this is the crucial change using Set for Set.Data; // this is the crucial change
Set.Data knownValues; Set.Data knownValues;
function register(uint value) { function register(uint value) {
// Here, all variables of type Set.Data have // Here, all variables of type Set.Data have
// corresponding member functions. // corresponding member functions.
@ -928,12 +975,15 @@ It is also possible to extend elementary types in that way::
} }
} }
contract C { contract C {
using Search for uint[]; using Search for uint[];
uint[] data; uint[] data;
function append(uint value) { function append(uint value) {
data.push(value); data.push(value);
} }
function replace(uint _old, uint _new) { function replace(uint _old, uint _new) {
// This performs the library function call // This performs the library function call
uint index = data.find(_old); uint index = data.find(_old);

View File

@ -24,7 +24,7 @@ Solidity contracts can be compiled a few different ways (see below) and the
resulting output can be cut/pasted into a geth console to deploy them to the resulting output can be cut/pasted into a geth console to deploy them to the
Ethereum blockchain. Ethereum blockchain.
There are some `contract examples <https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts/>`_ by fivedogit and There are some `contract examples <https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts/>`_ by fivedogit and
there should be a `test contract <https://github.com/ethereum/solidity/blob/develop/test/libsolidity/SolidityEndToEndTest.cpp>`_ for every single feature of Solidity. there should be a `test contract <https://github.com/ethereum/solidity/blob/develop/test/libsolidity/SolidityEndToEndTest.cpp>`_ for every single feature of Solidity.
How do I compile contracts? How do I compile contracts?
@ -76,7 +76,7 @@ Does selfdestruct() free up space in the blockchain?
It removes the contract bytecode and storage from the current block It removes the contract bytecode and storage from the current block
into the future, but since the blockchain stores every single block (i.e. into the future, but since the blockchain stores every single block (i.e.
all history), this will not actually free up space on full/achive nodes. all history), this will not actually free up space on full/archive nodes.
Create a contract that can be killed and return funds Create a contract that can be killed and return funds
===================================================== =====================================================
@ -85,7 +85,7 @@ First, a word of warning: Killing contracts sounds like a good idea, because "cl
is always good, but as seen above, it does not really clean up. Furthermore, is always good, but as seen above, it does not really clean up. Furthermore,
if Ether is sent to removed contracts, the Ether will be forever lost. if Ether is sent to removed contracts, the Ether will be forever lost.
If you want to deactivate your contracts, rather **disable** them by changing some If you want to deactivate your contracts, it is preferable to **disable** them by changing some
internal state which causes all functions to throw. This will make it impossible internal state which causes all functions to throw. This will make it impossible
to use the contract and ether sent to the contract will be returned automatically. to use the contract and ether sent to the contract will be returned automatically.
@ -184,7 +184,9 @@ An example of this would be::
uint someNumber; uint someNumber;
string someString; string someString;
} }
mapping(uint => mapping(string => myStruct)) myDynamicMapping; mapping(uint => mapping(string => myStruct)) myDynamicMapping;
function storeInMapping() { function storeInMapping() {
myDynamicMapping[1]["Foo"] = myStruct(2, "Bar"); myDynamicMapping[1]["Foo"] = myStruct(2, "Bar");
} }
@ -351,11 +353,17 @@ should be noted that you must declare them as static memory arrays.
Examples:: Examples::
contract C { contract C {
struct S { uint a; uint b; } struct S {
uint a;
uint b;
}
S public x = S(1, 2); S public x = S(1, 2);
string name = "Ada"; string name = "Ada";
string[4] memory AdaArr = ["This", "is", "an", "array"]; string[4] memory AdaArr = ["This", "is", "an", "array"];
} }
contract D { contract D {
C c = new C(); C c = new C();
} }
@ -405,9 +413,11 @@ you should always convert it to a `bytes` first::
contract C { contract C {
string s; string s;
function append(byte c) { function append(byte c) {
bytes(s).push(c); bytes(s).push(c);
} }
function set(uint i, byte c) { function set(uint i, byte c) {
bytes(s)[i] = c; bytes(s)[i] = c;
} }
@ -448,15 +458,21 @@ If you do not want to throw, you can return a pair::
contract C { contract C {
uint[] counters; uint[] counters;
function getCounter(uint index) function getCounter(uint index)
returns (uint counter, bool error) { returns (uint counter, bool error) {
if (index >= counters.length) return (0, true); if (index >= counters.length) return (0, true);
else return (counters[index], false); else return (counters[index], false);
} }
function checkCounter(uint index) { function checkCounter(uint index) {
var (counter, error) = getCounter(index); var (counter, error) = getCounter(index);
if (error) { ... } if (error) {
else { ... } ...
}
else {
...
}
} }
} }
@ -515,12 +531,15 @@ Example::
contract C { contract C {
uint[] data1; uint[] data1;
uint[] data2; uint[] data2;
function appendOne() { function appendOne() {
append(data1); append(data1);
} }
function appendTwo() { function appendTwo() {
append(data2); append(data2);
} }
function append(uint[] storage d) { function append(uint[] storage d) {
d.push(1); d.push(1);
} }
@ -542,6 +561,7 @@ be created in memory, although it will be created in storage::
contract C { contract C {
uint someVariable; uint someVariable;
uint[] data; uint[] data;
function f() { function f() {
uint[] x; uint[] x;
x.push(2); x.push(2);
@ -565,6 +585,7 @@ The correct way to do this is the following::
contract C { contract C {
uint someVariable; uint someVariable;
uint[] data; uint[] data;
function f() { function f() {
uint[] x = data; uint[] x = data;
x.push(2); x.push(2);
@ -674,6 +695,7 @@ This is a very interesting question. Suppose that we have a contract field set u
struct user{ struct user{
mapping(string => address) usedContracts; mapping(string => address) usedContracts;
} }
function somefunction{ function somefunction{
user user1; user user1;
user1.usedContracts["Hello"] = "World"; user1.usedContracts["Hello"] = "World";
@ -694,6 +716,7 @@ In this example::
contract B {} contract B {}
contract A { contract A {
address child; address child;
function test() { function test() {
child = (new B).value(10)(); //construct a new B with 10 wei child = (new B).value(10)(); //construct a new B with 10 wei
} }
@ -735,16 +758,20 @@ independent copies will be created::
contract C { contract C {
uint[20] x; uint[20] x;
function f() { function f() {
g(x); g(x);
h(x); h(x);
} }
function g(uint[20] y) { function g(uint[20] y) {
y[2] = 3; y[2] = 3;
} }
function h(uint[20] storage y) { function h(uint[20] storage y) {
y[3] = 4; y[3] = 4;
} }
}
The call to `g(x)` will not have an effect on `x` because it needs The call to `g(x)` will not have an effect on `x` because it needs
to create an independent copy of the storage value in memory to create an independent copy of the storage value in memory
@ -765,10 +792,10 @@ contract level) with `arrayname.length = <some new length>;`. If you get the
:: ::
int8[] memory memArr; // Case 1 int8[] memory memArr; // Case 1
memArr.length++; // illegal memArr.length++; // illegal
int8[5] storageArr; // Case 2 int8[5] storageArr; // Case 2
somearray.length++; // legal somearray.length++; // legal
int8[5] storage storageArr2; // Explicit case 2 int8[5] storage storageArr2; // Explicit case 2
somearray2.length++; // legal somearray2.length++; // legal
@ -821,7 +848,8 @@ What does the following strange check do in the Custom Token contract?
:: ::
if (balanceOf[_to] + _value < balanceOf[_to]) throw; if (balanceOf[_to] + _value < balanceOf[_to])
throw;
Integers in Solidity (and most other machine-related programming languages) are restricted to a certain range. Integers in Solidity (and most other machine-related programming languages) are restricted to a certain range.
For `uint256`, this is `0` up to `2**256 - 1`. If the result of some operation on those numbers For `uint256`, this is `0` up to `2**256 - 1`. If the result of some operation on those numbers

View File

@ -39,18 +39,17 @@ of votes.
:: ::
/// @title Voting with delegation. /// @title Voting with delegation.
contract Ballot contract Ballot {
{
// This declares a new complex type which will // This declares a new complex type which will
// be used for variables later. // be used for variables later.
// It will represent a single voter. // It will represent a single voter.
struct Voter struct Voter {
{
uint weight; // weight is accumulated by delegation uint weight; // weight is accumulated by delegation
bool voted; // if true, that person already voted bool voted; // if true, that person already voted
address delegate; // person delegated to address delegate; // person delegated to
uint vote; // index of the voted proposal uint vote; // index of the voted proposal
} }
// This is a type for a single proposal. // This is a type for a single proposal.
struct Proposal struct Proposal
{ {
@ -59,21 +58,23 @@ of votes.
} }
address public chairperson; address public chairperson;
// This declares a state variable that // This declares a state variable that
// stores a `Voter` struct for each possible address. // stores a `Voter` struct for each possible address.
mapping(address => Voter) public voters; mapping(address => Voter) public voters;
// A dynamically-sized array of `Proposal` structs. // A dynamically-sized array of `Proposal` structs.
Proposal[] public proposals; Proposal[] public proposals;
/// Create a new ballot to choose one of `proposalNames`. /// Create a new ballot to choose one of `proposalNames`.
function Ballot(bytes32[] proposalNames) function Ballot(bytes32[] proposalNames) {
{
chairperson = msg.sender; chairperson = msg.sender;
voters[chairperson].weight = 1; voters[chairperson].weight = 1;
// For each of the provided proposal names, // For each of the provided proposal names,
// create a new proposal object and add it // create a new proposal object and add it
// to the end of the array. // to the end of the array.
for (uint i = 0; i < proposalNames.length; i++) for (uint i = 0; i < proposalNames.length; i++) {
// `Proposal({...})` creates a temporary // `Proposal({...})` creates a temporary
// Proposal object and `proposal.push(...)` // Proposal object and `proposal.push(...)`
// appends it to the end of `proposals`. // appends it to the end of `proposals`.
@ -81,60 +82,68 @@ of votes.
name: proposalNames[i], name: proposalNames[i],
voteCount: 0 voteCount: 0
})); }));
}
} }
// Give `voter` the right to vote on this ballot. // Give `voter` the right to vote on this ballot.
// May only be called by `chairperson`. // May only be called by `chairperson`.
function giveRightToVote(address voter) function giveRightToVote(address voter) {
{ if (msg.sender != chairperson || voters[voter].voted) {
if (msg.sender != chairperson || voters[voter].voted)
// `throw` terminates and reverts all changes to // `throw` terminates and reverts all changes to
// the state and to Ether balances. It is often // the state and to Ether balances. It is often
// a good idea to use this if functions are // a good idea to use this if functions are
// called incorrectly. But watch out, this // called incorrectly. But watch out, this
// will also consume all provided gas. // will also consume all provided gas.
throw; throw;
}
voters[voter].weight = 1; voters[voter].weight = 1;
} }
/// Delegate your vote to the voter `to`. /// Delegate your vote to the voter `to`.
function delegate(address to) function delegate(address to) {
{
// assigns reference // assigns reference
Voter sender = voters[msg.sender]; Voter sender = voters[msg.sender];
if (sender.voted) if (sender.voted)
throw; throw;
// Forward the delegation as long as // Forward the delegation as long as
// `to` also delegated. // `to` also delegated.
while (voters[to].delegate != address(0) && while (voters[to].delegate != address(0) &&
voters[to].delegate != msg.sender) voters[to].delegate != msg.sender) {
to = voters[to].delegate; to = voters[to].delegate;
}
// We found a loop in the delegation, not allowed. // We found a loop in the delegation, not allowed.
if (to == msg.sender) if (to == msg.sender) {
throw; throw;
}
// Since `sender` is a reference, this // Since `sender` is a reference, this
// modifies `voters[msg.sender].voted` // modifies `voters[msg.sender].voted`
sender.voted = true; sender.voted = true;
sender.delegate = to; sender.delegate = to;
Voter delegate = voters[to]; Voter delegate = voters[to];
if (delegate.voted) if (delegate.voted) {
// If the delegate already voted, // If the delegate already voted,
// directly add to the number of votes // directly add to the number of votes
proposals[delegate.vote].voteCount += sender.weight; proposals[delegate.vote].voteCount += sender.weight;
else }
else {
// If the delegate did not vote yet, // If the delegate did not vote yet,
// add to her weight. // add to her weight.
delegate.weight += sender.weight; delegate.weight += sender.weight;
}
} }
/// Give your vote (including votes delegated to you) /// Give your vote (including votes delegated to you)
/// to proposal `proposals[proposal].name`. /// to proposal `proposals[proposal].name`.
function vote(uint proposal) function vote(uint proposal) {
{
Voter sender = voters[msg.sender]; Voter sender = voters[msg.sender];
if (sender.voted) throw; if (sender.voted)
throw;
sender.voted = true; sender.voted = true;
sender.vote = proposal; sender.vote = proposal;
// If `proposal` is out of the range of the array, // If `proposal` is out of the range of the array,
// this will throw automatically and revert all // this will throw automatically and revert all
// changes. // changes.
@ -147,10 +156,8 @@ of votes.
returns (uint winningProposal) returns (uint winningProposal)
{ {
uint winningVoteCount = 0; uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) for (uint p = 0; p < proposals.length; p++) {
{ if (proposals[p].voteCount > winningVoteCount) {
if (proposals[p].voteCount > winningVoteCount)
{
winningVoteCount = proposals[p].voteCount; winningVoteCount = proposals[p].voteCount;
winningProposal = p; winningProposal = p;
} }
@ -223,8 +230,10 @@ activate themselves.
/// Create a simple auction with `_biddingTime` /// Create a simple auction with `_biddingTime`
/// seconds bidding time on behalf of the /// seconds bidding time on behalf of the
/// beneficiary address `_beneficiary`. /// beneficiary address `_beneficiary`.
function SimpleAuction(uint _biddingTime, function SimpleAuction(
address _beneficiary) { uint _biddingTime,
address _beneficiary
) {
beneficiary = _beneficiary; beneficiary = _beneficiary;
auctionStart = now; auctionStart = now;
biddingTime = _biddingTime; biddingTime = _biddingTime;
@ -238,16 +247,19 @@ activate themselves.
// No arguments are necessary, all // No arguments are necessary, all
// information is already part of // information is already part of
// the transaction. // the transaction.
if (now > auctionStart + biddingTime) if (now > auctionStart + biddingTime) {
// Revert the call if the bidding // Revert the call if the bidding
// period is over. // period is over.
throw; throw;
if (msg.value <= highestBid) }
if (msg.value <= highestBid) {
// If the bid is not higher, send the // If the bid is not higher, send the
// money back. // money back.
throw; throw;
if (highestBidder != 0) }
if (highestBidder != 0) {
highestBidder.send(highestBid); highestBidder.send(highestBid);
}
highestBidder = msg.sender; highestBidder = msg.sender;
highestBid = msg.value; highestBid = msg.value;
HighestBidIncreased(msg.sender, msg.value); HighestBidIncreased(msg.sender, msg.value);
@ -261,6 +273,7 @@ activate themselves.
if (ended) if (ended)
throw; // this function has already been called throw; // this function has already been called
AuctionEnded(highestBidder, highestBid); AuctionEnded(highestBidder, highestBid);
// We send all the money we have, because some // We send all the money we have, because some
// of the refunds might have failed. // of the refunds might have failed.
beneficiary.send(this.balance); beneficiary.send(this.balance);
@ -319,13 +332,12 @@ high or low invalid bids.
:: ::
contract BlindAuction contract BlindAuction {
{ struct Bid {
struct Bid
{
bytes32 blindedBid; bytes32 blindedBid;
uint deposit; uint deposit;
} }
address public beneficiary; address public beneficiary;
uint public auctionStart; uint public auctionStart;
uint public biddingEnd; uint public biddingEnd;
@ -346,10 +358,11 @@ high or low invalid bids.
modifier onlyBefore(uint _time) { if (now >= _time) throw; _ } modifier onlyBefore(uint _time) { if (now >= _time) throw; _ }
modifier onlyAfter(uint _time) { if (now <= _time) throw; _ } modifier onlyAfter(uint _time) { if (now <= _time) throw; _ }
function BlindAuction(uint _biddingTime, function BlindAuction(
uint _revealTime, uint _biddingTime,
address _beneficiary) uint _revealTime,
{ address _beneficiary
) {
beneficiary = _beneficiary; beneficiary = _beneficiary;
auctionStart = now; auctionStart = now;
biddingEnd = now + _biddingTime; biddingEnd = now + _biddingTime;
@ -377,29 +390,38 @@ high or low invalid bids.
/// Reveal your blinded bids. You will get a refund for all /// Reveal your blinded bids. You will get a refund for all
/// correctly blinded invalid bids and for all bids except for /// correctly blinded invalid bids and for all bids except for
/// the totally highest. /// the totally highest.
function reveal(uint[] _values, bool[] _fake, function reveal(
bytes32[] _secret) uint[] _values,
bool[] _fake,
bytes32[] _secret
)
onlyAfter(biddingEnd) onlyAfter(biddingEnd)
onlyBefore(revealEnd) onlyBefore(revealEnd)
{ {
uint length = bids[msg.sender].length; uint length = bids[msg.sender].length;
if (_values.length != length || _fake.length != length || if (
_secret.length != length) _values.length != length ||
_fake.length != length ||
_secret.length != length
) {
throw; throw;
}
uint refund; uint refund;
for (uint i = 0; i < length; i++) for (uint i = 0; i < length; i++) {
{
var bid = bids[msg.sender][i]; var bid = bids[msg.sender][i];
var (value, fake, secret) = var (value, fake, secret) =
(_values[i], _fake[i], _secret[i]); (_values[i], _fake[i], _secret[i]);
if (bid.blindedBid != sha3(value, fake, secret)) if (bid.blindedBid != sha3(value, fake, secret)) {
// Bid was not actually revealed. // Bid was not actually revealed.
// Do not refund deposit. // Do not refund deposit.
continue; continue;
}
refund += bid.deposit; refund += bid.deposit;
if (!fake && bid.deposit >= value) if (!fake && bid.deposit >= value) {
if (placeBid(msg.sender, value)) if (placeBid(msg.sender, value))
refund -= value; refund -= value;
}
// Make it impossible for the sender to re-claim // Make it impossible for the sender to re-claim
// the same deposit. // the same deposit.
bid.blindedBid = 0; bid.blindedBid = 0;
@ -413,11 +435,13 @@ high or low invalid bids.
function placeBid(address bidder, uint value) internal function placeBid(address bidder, uint value) internal
returns (bool success) returns (bool success)
{ {
if (value <= highestBid) if (value <= highestBid) {
return false; return false;
if (highestBidder != 0) }
if (highestBidder != 0) {
// Refund the previously highest bidder. // Refund the previously highest bidder.
highestBidder.send(highestBid); highestBidder.send(highestBid);
}
highestBid = value; highestBid = value;
highestBidder = bidder; highestBidder = bidder;
return true; return true;
@ -428,7 +452,8 @@ high or low invalid bids.
function auctionEnd() function auctionEnd()
onlyAfter(revealEnd) onlyAfter(revealEnd)
{ {
if (ended) throw; if (ended)
throw;
AuctionEnded(highestBidder, highestBid); AuctionEnded(highestBidder, highestBid);
// We send all the money we have, because some // We send all the money we have, because some
// of the refunds might have failed. // of the refunds might have failed.
@ -436,7 +461,9 @@ high or low invalid bids.
ended = true; ended = true;
} }
function () { throw; } function () {
throw;
}
} }
.. index:: purchase, remote purchase, escrow .. index:: purchase, remote purchase, escrow
@ -449,39 +476,39 @@ Safe Remote Purchase
:: ::
contract Purchase contract Purchase {
{
uint public value; uint public value;
address public seller; address public seller;
address public buyer; address public buyer;
enum State { Created, Locked, Inactive } enum State { Created, Locked, Inactive }
State public state; State public state;
function Purchase()
{ function Purchase() {
seller = msg.sender; seller = msg.sender;
value = msg.value / 2; value = msg.value / 2;
if (2 * value != msg.value) throw; if (2 * value != msg.value) throw;
} }
modifier require(bool _condition)
{ modifier require(bool _condition) {
if (!_condition) throw; if (!_condition) throw;
_ _
} }
modifier onlyBuyer()
{ modifier onlyBuyer() {
if (msg.sender != buyer) throw; if (msg.sender != buyer) throw;
_ _
} }
modifier onlySeller()
{ modifier onlySeller() {
if (msg.sender != seller) throw; if (msg.sender != seller) throw;
_ _
} }
modifier inState(State _state)
{ modifier inState(State _state) {
if (state != _state) throw; if (state != _state) throw;
_ _
} }
event aborted(); event aborted();
event purchaseConfirmed(); event purchaseConfirmed();
event itemReceived(); event itemReceived();
@ -497,6 +524,7 @@ Safe Remote Purchase
seller.send(this.balance); seller.send(this.balance);
state = State.Inactive; state = State.Inactive;
} }
/// Confirm the purchase as buyer. /// Confirm the purchase as buyer.
/// Transaction has to include `2 * value` ether. /// Transaction has to include `2 * value` ether.
/// The ether will be locked until confirmReceived /// The ether will be locked until confirmReceived
@ -509,6 +537,7 @@ Safe Remote Purchase
buyer = msg.sender; buyer = msg.sender;
state = State.Locked; state = State.Locked;
} }
/// Confirm that you (the buyer) received the item. /// Confirm that you (the buyer) received the item.
/// This will release the locked ether. /// This will release the locked ether.
function confirmReceived() function confirmReceived()
@ -520,7 +549,10 @@ Safe Remote Purchase
seller.send(this.balance); seller.send(this.balance);
state = State.Inactive; state = State.Inactive;
} }
function() { throw; }
function() {
throw;
}
} }
******************** ********************

View File

@ -80,7 +80,7 @@ Events are convenience interfaces with the EVM logging facilities.
:: ::
contract SimpleAuction { contract SimpleAuction {
event HighestBidIncreased(address bidder, uint amount); // Event event HighestBidIncreased(address bidder, uint amount); // Event
function bid() { function bid() {

View File

@ -25,7 +25,7 @@ solidity code. The goal of this guide is *consistency*. A quote from python's
captures this concept well. captures this concept well.
A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is most important. A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is most important.
But most importantly: know when to be inconsistent -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don't hesitate to ask! But most importantly: know when to be inconsistent -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don't hesitate to ask!
*********** ***********
@ -155,19 +155,27 @@ Whitespace in Expressions
Avoid extraneous whitespace in the following situations: Avoid extraneous whitespace in the following situations:
* Immediately inside parenthesis, brackets or braces. Immediately inside parenthesis, brackets or braces.
Yes: `spam(ham[1], Coin({name: "ham"}));` Yes::
No: `spam( ham[ 1 ], Coin( { name: "ham" } ) );` spam(ham[1], Coin({name: "ham"}));
* Immediately before a comma, semicolon: No::
Yes: `function spam(uint i, Coin coin);` spam( ham[ 1 ], Coin( { name: "ham" } ) );`
No: `function spam(uint i , Coin coin) ;` Immediately before a comma, semicolon:
* More than one space around an assignment or other operator to align with Yes::
function spam(uint i, Coin coin);
No::
function spam(uint i , Coin coin) ;
More than one space around an assignment or other operator to align with
another: another:
Yes:: Yes::

View File

@ -43,7 +43,7 @@ The operators `||` and `&&` apply the common short-circuiting rules. This means
Integers Integers
-------- --------
`int` / `uint`: Signed and unsigned integers of various sizes. Keywords `uint8` to `uint256` in steps of `8` (unsigned of 8 up to 256 bits) and `int8` to `int256`. `uint` and `int` are aliases for `uint256` and `int256`, respectively. `int` / `uint`: Signed and unsigned integers of various sizes. Keywords `uint8` to `uint256` in steps of `8` (unsigned of 8 up to 256 bits) and `int8` to `int256`. `uint` and `int` are aliases for `uint256` and `int256`, respectively.
Operators: Operators:
@ -59,7 +59,7 @@ operators are :ref:`literals<integer_literals>` (or literal expressions).
Address Address
------- -------
`address`: Holds a 20 byte value (size of an Ethereum address). Address types also have members(see [Functions on addresses](#functions-on-addresses)) and serve as base for all contracts. `address`: Holds a 20 byte value (size of an Ethereum address). Address types also have members and serve as base for all contracts.
Operators: Operators:
@ -153,7 +153,7 @@ It is even possible to temporarily exceed the maximum of 256 bits as long as onl
String Literals String Literals
--------------- ---------------
String Literals are written with double quotes (`"abc"`). As with integer literals, their type can vary, but they are implicitly convertible to `bytes` if they fit, to `bytes` and to `string`. String Literals are written with double quotes (`"abc"`). As with integer literals, their type can vary, but they are implicitly convertible to `bytes` if they fit, to `bytes` and to `string`.
.. index:: enum .. index:: enum