Listing D.2 implements a contract modeling the seats on a plane. Passengers can buy tickets and, possibly, ask for a reimbursement. Plane defines various modifiers that are applied to its methods. To avoid the reentrancy problem that afflicted the DAO contract [47], Plane also implements the withdrawal pattern and uses the operator deleteto make tickets available again in a simple way.
1 contract Plane { 2 3 struct Ticket { 4 uint8 seat; 5 bool bought; 6 } 7
8 uint8 constant private numtickets = 5; // number of seats 9 uint8 constant private ticketprice = 50; // 50 wei 10 address public company;
11 Ticket[numtickets] public tickets; 12
13 mapping (address => uint) private pendingWithdrawals; // withdrawal pattern
14
15 mapping (address => Ticket) private boughtTickets; 16
17 // to iterate over the bought tickets 18 address[numtickets] private passengers; 19
20 uint8 private nextAvailableTicket; 21
22 modifier stillSpot() {
23 require(nextAvailableTicket < numtickets);
25 } 26
27 modifier enoughWei {
28 require(msg.value >= ticketprice);
29 pendingWithdrawals[msg.sender] += msg.value - ticketprice;
30 _;
31 }
32
33 modifier hasTicket {
34 require(boughtTickets[msg.sender].bought);
35 _;
36 }
37
38 modifier noOtherTickets {
39 require(!boughtTickets[msg.sender].bought);
40 _;
41 }
42
43 modifier companyOnly {
44 require(msg.sender == company);
45 _;
46 }
47
48 constructor() public { 49 company = msg.sender;
50 for(uint8 i = 0; i < numtickets; i++) { 51 tickets[i].seat = i;
52 }
53 }
54
55 function buyTicket() public payable stillSpot enoughWei noOtherTickets {
56 tickets[nextAvailableTicket].bought = true;
57 boughtTickets[msg.sender] = tickets[nextAvailableTicket]; 58 passengers[nextAvailableTicket] = msg.sender;
59 nextAvailableTicket = getNextAvailableTicket();
60 }
61
62 function getNextAvailableTicket() private view returns (uint8) {
63 uint8 i = 0;
64 while (i < numtickets && tickets[i].bought) {i++;}
65 return i;
66 }
67
68 function askReimbursment() public hasTicket { 69 pendingWithdrawals[msg.sender] += ticketprice/2; 70 tickets[boughtTickets[msg.sender].seat].bought = false; 71 nextAvailableTicket = boughtTickets[msg.sender].seat; 72 delete boughtTickets[msg.sender];
73 delete passengers[boughtTickets[msg.sender].seat];
74 }
75
76 function withdraw() public {
77 uint amount = pendingWithdrawals[msg.sender]; 78 pendingWithdrawals[msg.sender] = 0;
79 msg.sender.transfer(amount);
80 }
81
82 function getPassengers() public view returns(address[ numtickets]) {
83 return passengers;
85
86 function takeOff() public companyOnly { 87 for (uint8 i = 0; i < numtickets; i++) { 88 tickets[i].bought = false; 89 delete boughtTickets[passengers[i]]; 90 } 91 delete passengers; 92 } 93 }
Appendix E
Proving the properties of the
type system
In this section we prove Lemmas of Permutation (Lemma 3), Weakening (Lemma 4), and Substitution (Lemma 5), and Theorems of Progress (Theorem 3), Subject Reduc- tion (Theorem 4), and Safety for configurations (Theorem 1) and programs (Theo- rem 2).
In the proof that follows, we shall write Γ `k e : T and hβ, σ, ei −→k hβ0, σ0, e0i to indicate that the derivations of those judgments have height at most k.
E.1
Permutation Lemma
We recall Lemma 3: Lemma 3 (Permutation).
IfΓ ` e : T can be derived and ∆ is a permutation of Γ, then the judgment ∆ ` e : T can be derived and the derivation has the same height of the previous one.
Proof. We prove this lemma by induction on the height of the derivation of the judg- ment Γ ` e : T .
Base cases These cases correspond to the axioms in Section 6.3. The height of these derivations is always 1.
• REF. The judgment is Γ ` c : C. Since it can be derived, by Case 9 of Lemma 2 we know that c : C ∈ Γ. Let ∆ be a permutation of Γ. Hence, ∆ has exactly the same elements as Γ, but in a different order. This means that c : C ∈ ∆, and that ∆ ` c : C can be derived.
• VAR. This case is very similar to REF: the judgment is Γ ` x : T . Since it can be derived, by Case 10 of Lemma 2 we know that x : T ∈ Γ. Let ∆ be a permutation of Γ. Hence, ∆ has exactly the same elements as Γ, but in a different order. This means that x : T ∈ ∆, and that ∆ ` x : T can be derived.
• TRUE. The judgment is Γ ` true : bool. Since it can be derived regardless of Γ, using a permutation ∆ of Γ instead of Γ does not change anything. Hence, the judgment ∆ ` true : bool can be derived.
• FALSE. This case is very similar to TRUE: the judgment is Γ ` false : bool. Since it can be derived regardless of Γ, using a permutation ∆ of Γ instead of Γ does not change anything. Hence, the judgment ∆ ` false : bool is derivable. • NAT. This case is very similar to TRUE: the judgment is Γ ` n : uint. The only
premise is n ∈ N+, and the judgment can be derived regardless of Γ. Hence, using a permutation ∆ of Γ instead of Γ does not change anything: the judgment ∆ ` n : uint can be derived.
• ADDRESS. This case is very similar to REF: the judgment is Γ ` a : address. Since it can be derived, by Case 6 of Lemma 2 we know a : address ∈ Γ. Let ∆ be a permutation of Γ. Hence, ∆ has exactly the same elements as Γ, but in a different order. This means that a : address ∈ ∆, and that ∆ ` a : address can be derived.
• UNIT. The judgment is Γ ` u : unit. Since it can be derived regardless of Γ, using a permutation ∆ of Γ instead of Γ does not change anything. Hence, the judgment ∆ ` u : unit.
• REVERT. The judgment is Γ ` revert : T . Again, it is an axiom and can be derived regardless of Γ. Hence, using a permutation ∆ of Γ instead of Γ does not change anything: the judgment ∆ ` revert : T can be derived.
Inductive cases Given a judgment J such that its derivation has height k + 1, we prove the inductive cases on the last rule used to derive J . We assume the lemma for the judgments with height at most k and we prove it for those with height k + 1.
• FUN. In this case J = Γ `k+1 c.f : ˜T1 → T2was derived from the judgment Γ `k c : C, and the additional premise ftype(C, f ) = ˜T1 → T2. By inductive hypothesis, ∆ `k c : C, where ∆ is a permutation of Γ, can be derived. Consid- ering the judgment ∆ `k+1 c.f : ˜T1→ T2, we note that it can be derived from ∆ `k c : C, since the premise ftype(C, f ) = ˜T1→ T2is still valid.
• MAPPING. In this case J = Γ `k+1 M : mapping(T1 ⇒ T2) was derived from the judgments Γ `k ˜k : ˜T1 and Γ `k ˜v : ˜T2. By inductive hypothesis, also the judgments ∆ `k ˜k : ˜T1 and ∆ `k v : ˜˜ T2, where ∆ is a permutation of Γ, are derivable. Hence, by applying MAPPINGto the latter two judgments, ∆ `k+1M : mapping(T1⇒ T2).
• BAL. In this case J = Γ `k+1 balance(e) : uint was derived from Γ `k e : address. By inductive hypothesis, also the judgment ∆ `k e : address, where ∆ is a permutation of Γ. Hence, by applying BALto it we obtain ∆ `k+1 balance(e) : uint.
• ADDR. This case is very similar to BAL: J = Γ `k+1 address(e) : address was derived from Γ `k e : C. By inductive hypothesis, also the judgment ∆ `k e : C, where ∆ is a permutation of Γ, is derivable. Hence, by applying ADDRto it we obtain ∆ `k+1address(e) : address.
• RETURN. In this case: J = Γ `k+1 return e : T was derived from Γ `k e : T . By inductive hypothesis, also the judgment ∆ `k e : T , where ∆ is a permutation of Γ, is derivable. Hence, by applying RETURNto it we obtain ∆ `k+1return e : T .
• IF. In this case J = Γ `k+1 if e1 then e2else e3 : T was derived from Γ `k e1: bool, Γ `ke2: T , and Γ `k e3: T . By inductive hypothesis, given a permu- tation ∆ of Γ, the judgments ∆ `ke1: bool, ∆ `ke2: T , and ∆ `ke3: T can be derived. By applying IFto them we obtain ∆ `k+1if e1then e2else e2: T . • SEQ. This case is very similar to IF: J = Γ `k+1 e1; e2 : T was derived from
Γ `k e1 : T and Γ `k e2: T . By inductive hypothesis, given a permutation ∆ of Γ, the judgments ∆ `k e1: T and ∆ `k e2 : T can be derived. By applying SEQto them we obtain ∆ `k+1e1; e2: T .
• DECL. In this case J = Γ `k+1 T1 x = e1; e2 : T2 was derived from Γ `k e1 : T1and Γ, x : T1`k e2 : T2. The derivations of the latter judgments have height k. Let Γ0= Γ, x : T1, ∆ be a permutation of Γ, and ∆0be a permuta- tion of Γ0; by inductive hypothesis we can derive ∆ `k e1: T1. Nonetheless, we cannot directly apply the inductive hypothesis on Γ0 `k e2 : T2, since we have Γ0 6= Γ. Still, we know that there exists a derivation, of height k, for this judg- ment. (Otherwise J would not be derivable, but this is a contradiction, since we assumed J has a valid derivation of height k + 1.) Hence, it comes from another judgment J0having a derivation of height k − 1 where any of the rules defined in Section 6.3 was applied as a last step. We can now apply the inductive hy- pothesis on J0considering ∆0as a permutation, concluding that ∆0`k e2: T2is derivable. Lastly, applying DECLto ∆ `k e1: T1and ∆0 `k e2: T2we obtain ∆ `k+1T1x = e1; e2: T2.
• MAPPSEL. In this case J = Γ `k+1 e1[e2] : T2 was derived from Γ `k e1 : mapping(T1 ⇒ T2) and Γ `k e2 : T1. By inductive hypothesis, the judgments ∆ `k e1 : mapping(T1 ⇒ T2) and ∆ `k e2 : T1 can be derived. Hence, applying MAPPSELthe them we obtain ∆ `k+1e1[e2] : T2.
• STATESELIn this case J = Γ `k+1 e.si : Ti was derived from Γ `k e : C, with the additional premise stating si ∈ ˜s, where sv(C) = ˜T s. Provided that the height of Γ ` e : C is k, by inductive hypothesis, given a permutation ∆ of Γ, we know we can derive ∆ `ke : C. The additional premise is still valid, and applying STATESELwe obtain ∆ `k+1e.si: Ti.
• ASS. In this case J = Γ `k+1 x = e : T was derived from Γ `k x : T and Γ `k e : T . By inductive hypothesis, given a permutation ∆ of Γ, we know we can derive both ∆ `k x : T and ∆ `k e : T . Hence, by applying ASSto them we can derive ∆ `k+1x = e : T .
• MAPPASS. In this case J = Γ `k+1 e1[e2 → e3] : mapping(T1 ⇒ T2) was derived from Γ `k e1 : mapping(T1 ⇒ T2), Γ `k e2 : T1, and Γ `k e3 : T2. By inductive hypothesis, given a permutation ∆ of Γ, we can derive ∆ `k e1 : mapping(T1 ⇒ T2), ∆ `k e2 : T1, and ∆ `k e3 : T2. By the application of MAPPASSwe obtain ∆ `k+1e1[e2→ e3] : mapping(T1⇒ T2). • STATEASS. This case is very similar to ASS: J = Γ `k+1 e1.s = e2 : T was derived from Γ `k e1.s : T and Γ `k e2 : T . By inductive hypothesis, given a permutation ∆ of Γ, we know we can derive both ∆ `k e1.s : T and ∆ `k e2 : T . Hence, by applying STATEASSto them we can derive ∆ `k+1 e1.s = e2: T .
• NEW. In this case J = Γ `k+1 new C.value(e0)(˜e) : C was derived from Γ `k ˜e : ˜T and Γ `k e0 : uint, together with the additional premise |˜e| = |˜s|, where sv(C) = ˜T s. By inductive hypothesis, we know that, given a permutation ∆ of Γ, we can derive both ∆ `k e : ˜˜ T and ∆ `k e0 : uint. Provided that the additional premise checking the length of the tuples ˜e and ˜s is still valid, we can apply NEWto obtain ∆ `k+1new C.value(e0)(˜e) : C.
• CONTRRETR. In this case J = Γ `k+1 C(e) : C was derived from Γ `k e : address. By inductive hypothesis ∆ `k e : address is derivable, where ∆ is a permutation of Γ. Considering ∆ ` C(e) : C, notice it can be derived from ∆ `k e : address applying CONTRRETR, and its derivation has height k + 1. • TRANSFER. In this case J = Γ `k+1 e1.transfer(e2) : unit was derived from
Γ `k e1 : address and Γ `k e2 : uint. By inductive hypothesis, considering a permutation ∆ of Γ, we can derive ∆ `ke1: address and ∆ `k e2: uint. Lastly, we can apply TRANSFERto them to obtain ∆ `k+1e1.transfer(e2) : unit. • CALL. In this case J = Γ `k+1 e1.f.value(e2)(˜e) : T2 was derived from
Γ `k e1 : C, Γ `k e2 : uint, and Γ `k ˜e : ˜T1, together with the additional premises checking the length of the tuple ˜e (|˜e| = | ˜T1|) and the type of f in C (ftype(C, f ) = ˜T1 → T2). By inductive hypothesis on the three judgments of height k, and given a permutation ∆ of Γ, also the following judgments can be derived: ∆ `k e : C, ∆ `k e2 : uint, and ∆ `k ˜e : ˜T1. Applying CALLwe derive ∆ `k+1e1.f.value(e2)(˜e) : T2.
• CALLTOPLEVEL. In this case J = Γ `k+1 e1.f.value(e2).sender(e3)(˜e) : T2 was derived from Γ `k e3 : address and Γ `k e1.f.value(e2)(˜e) : T2. Let ∆ be a permutation of Γ; by inductive hypothesis the judgments ∆ `k e3 : address and ∆ `k e1.f.value(e2)(˜e) : T2. We then apply CALLTOPLEVELand obtain a derivation of ∆ `k+1e1.f.value(e2).sender(e3)(˜e) : T2.
• CALLVALUE. In this case J = Γ `k+1 e1.value(e2)(˜e) : T2was derived from Γ `k e1: ˜T1→ T2, Γ `k e2 : uint, and Γ `k ˜e : ˜T1, together with the premise checking the length of the tuple ˜e (|˜e| = | ˜T1|). By inductive hypothesis on the three judgments of height k, and given a permutation ∆ of Γ, also the following judgments can be derived: ∆ `ke1: ˜T1→ T2, ∆ `k e2: uint, and ∆ `ke : ˜˜ T1. Applying CALLVALUEwe derive ∆ `k+1e1.value(e2)(˜e) : T2.