Merge pull request #8010 from ethereum/docs_solidity_by_example

Docs Solidity by example
This commit is contained in:
chriseth 2019-12-16 11:43:26 +01:00 committed by GitHub
commit 6a065bc982
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 86 deletions

View File

@ -4,12 +4,10 @@
Blind Auction Blind Auction
************* *************
In this section, we will show how easy it is to create a In this section, we will show how easy it is to create a completely blind
completely blind auction contract on Ethereum. auction contract on Ethereum. We will start with an open auction where
We will start with an open auction where everyone everyone can see the bids that are made and then extend this contract into a
can see the bids that are made and then extend this blind auction where it is not possible to see the actual bid until the bidding
contract into a blind auction where it is not
possible to see the actual bid until the bidding
period ends. period ends.
.. _simple_auction: .. _simple_auction:
@ -17,16 +15,12 @@ period ends.
Simple Open Auction Simple Open Auction
=================== ===================
The general idea of the following simple auction contract The general idea of the following simple auction contract is that everyone can
is that everyone can send their bids during send their bids during a bidding period. The bids already include sending money
a bidding period. The bids already include sending / Ether in order to bind the bidders to their bid. If the highest bid is
money / ether in order to bind the bidders to their raised, the previously highest bidder gets their money back. After the end of
bid. If the highest bid is raised, the previously the bidding period, the contract has to be called manually for the beneficiary
highest bidder gets her money back. to receive their money - contracts cannot activate themselves.
After the end of the bidding period, the
contract has to be called manually for the
beneficiary to receive their money - contracts cannot
activate themselves.
:: ::
@ -161,38 +155,31 @@ activate themselves.
Blind Auction Blind Auction
============= =============
The previous open auction is extended to a blind auction The previous open auction is extended to a blind auction in the following. The
in the following. The advantage of a blind auction is advantage of a blind auction is that there is no time pressure towards the end
that there is no time pressure towards the end of of the bidding period. Creating a blind auction on a transparent computing
the bidding period. Creating a blind auction on a platform might sound like a contradiction, but cryptography comes to the
transparent computing platform might sound like a rescue.
contradiction, but cryptography comes to the rescue.
During the **bidding period**, a bidder does not During the **bidding period**, a bidder does not actually send their bid, but
actually send her bid, but only a hashed version of it. only a hashed version of it. Since it is currently considered practically
Since it is currently considered practically impossible impossible to find two (sufficiently long) values whose hash values are equal,
to find two (sufficiently long) values whose hash the bidder commits to the bid by that. After the end of the bidding period,
values are equal, the bidder commits to the bid by that. the bidders have to reveal their bids: They send their values unencrypted and
After the end of the bidding period, the bidders have the contract checks that the hash value is the same as the one provided during
to reveal their bids: They send their values the bidding period.
unencrypted and the contract checks that the hash value
is the same as the one provided during the bidding period.
Another challenge is how to make the auction Another challenge is how to make the auction **binding and blind** at the same
**binding and blind** at the same time: The only way to time: The only way to prevent the bidder from just not sending the money after
prevent the bidder from just not sending the money they won the auction is to make them send it together with the bid. Since value
after they won the auction is to make her send it transfers cannot be blinded in Ethereum, anyone can see the value.
together with the bid. Since value transfers cannot
be blinded in Ethereum, anyone can see the value.
The following contract solves this problem by The following contract solves this problem by accepting any value that is
accepting any value that is larger than the highest larger than the highest bid. Since this can of course only be checked during
bid. Since this can of course only be checked during the reveal phase, some bids might be **invalid**, and this is on purpose (it
the reveal phase, some bids might be **invalid**, and even provides an explicit flag to place invalid bids with high value
this is on purpose (it even provides an explicit transfers): Bidders can confuse competition by placing several high or low
flag to place invalid bids with high value transfers): invalid bids.
Bidders can confuse competition by placing several
high or low invalid bids.
:: ::
@ -296,24 +283,6 @@ high or low invalid bids.
msg.sender.transfer(refund); msg.sender.transfer(refund);
} }
// This is an "internal" function which means that it
// can only be called from the contract itself (or from
// derived contracts).
function placeBid(address bidder, uint value) internal
returns (bool success)
{
if (value <= highestBid) {
return false;
}
if (highestBidder != address(0)) {
// Refund the previously highest bidder.
pendingReturns[highestBidder] += highestBid;
}
highestBid = value;
highestBidder = bidder;
return true;
}
/// Withdraw a bid that was overbid. /// Withdraw a bid that was overbid.
function withdraw() public { function withdraw() public {
uint amount = pendingReturns[msg.sender]; uint amount = pendingReturns[msg.sender];
@ -339,4 +308,22 @@ high or low invalid bids.
ended = true; ended = true;
beneficiary.transfer(highestBid); beneficiary.transfer(highestBid);
} }
// This is an "internal" function which means that it
// can only be called from the contract itself (or from
// derived contracts).
function placeBid(address bidder, uint value) internal
returns (bool success)
{
if (value <= highestBid) {
return false;
}
if (highestBidder != address(0)) {
// Refund the previously highest bidder.
pendingReturns[highestBidder] += highestBid;
}
highestBid = value;
highestBidder = bidder;
return true;
}
} }

View File

@ -354,17 +354,6 @@ The full contract
expiration = now + duration; expiration = now + duration;
} }
function isValidSignature(uint256 amount, bytes memory signature)
internal
view
returns (bool)
{
bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount)));
// check that the signature is from the payment sender
return recoverSigner(message, signature) == sender;
}
/// the recipient can close the channel at any time by presenting a /// the recipient can close the channel at any time by presenting a
/// signed amount from the sender. the recipient will be sent that amount, /// signed amount from the sender. the recipient will be sent that amount,
/// and the remainder will go back to the sender /// and the remainder will go back to the sender
@ -391,6 +380,17 @@ The full contract
selfdestruct(sender); selfdestruct(sender);
} }
function isValidSignature(uint256 amount, bytes memory signature)
internal
view
returns (bool)
{
bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount)));
// check that the signature is from the payment sender
return recoverSigner(message, signature) == sender;
}
/// All functions below this are just taken from the chapter /// All functions below this are just taken from the chapter
/// 'creating and verifying signatures' chapter. /// 'creating and verifying signatures' chapter.

View File

@ -38,9 +38,6 @@ and the sum of all balances is an invariant across the lifetime of the contract.
event Transfer(address from, address to, uint amount); event Transfer(address from, address to, uint amount);
event Approval(address owner, address spender, uint amount); event Approval(address owner, address spender, uint amount);
function balanceOf(address tokenOwner) public view returns (uint balance) {
return balances[tokenOwner];
}
function transfer(address to, uint amount) public returns (bool success) { function transfer(address to, uint amount) public returns (bool success) {
balances.move(msg.sender, to, amount); balances.move(msg.sender, to, amount);
emit Transfer(msg.sender, to, amount); emit Transfer(msg.sender, to, amount);
@ -62,4 +59,8 @@ and the sum of all balances is an invariant across the lifetime of the contract.
emit Approval(msg.sender, spender, tokens); emit Approval(msg.sender, spender, tokens);
return true; return true;
} }
function balanceOf(address tokenOwner) public view returns (uint balance) {
return balances[tokenOwner];
}
} }

View File

@ -31,19 +31,11 @@ you can use state machine-like constructs inside a contract.
uint public value; uint public value;
address payable public seller; address payable public seller;
address payable public buyer; address payable public buyer;
enum State { Created, Locked, Release, Inactive } enum State { Created, Locked, Release, Inactive }
// The state variable has a default value of the first member, `State.created` // The state variable has a default value of the first member, `State.created`
State public state; State public state;
// Ensure that `msg.value` is an even number.
// Division will truncate if it is an odd number.
// Check via multiplication that it wasn't an odd number.
constructor() public payable {
seller = msg.sender;
value = msg.value / 2;
require((2 * value) == msg.value, "Value has to be even.");
}
modifier condition(bool _condition) { modifier condition(bool _condition) {
require(_condition); require(_condition);
_; _;
@ -78,6 +70,15 @@ you can use state machine-like constructs inside a contract.
event ItemReceived(); event ItemReceived();
event SellerRefunded(); event SellerRefunded();
// Ensure that `msg.value` is an even number.
// Division will truncate if it is an odd number.
// Check via multiplication that it wasn't an odd number.
constructor() public payable {
seller = msg.sender;
value = msg.value / 2;
require((2 * value) == msg.value, "Value has to be even.");
}
/// Abort the purchase and reclaim the ether. /// Abort the purchase and reclaim the ether.
/// Can only be called by the seller before /// Can only be called by the seller before
/// the contract is locked. /// the contract is locked.