@@ -3,20 +3,20 @@ include "../jrnl/jrnl.s.dfy"
3
3
4
4
module Bank {
5
5
6
- import Arith
7
- import opened Machine
8
- import opened ByteSlice
9
- import opened JrnlTypes
10
- import opened JrnlSpec
11
- import opened Kinds
12
- import opened Marshal
13
- import C = Collections
14
-
15
- /*
16
- Demo of bank transfer using axiomatized journal API
17
- */
18
- class Bank
19
- {
6
+ import Arith
7
+ import opened Machine
8
+ import opened ByteSlice
9
+ import opened JrnlTypes
10
+ import opened JrnlSpec
11
+ import opened Kinds
12
+ import opened Marshal
13
+ import C = Collections
14
+
15
+ /*
16
+ Demo of bank transfer using axiomatized journal API
17
+ */
18
+ class Bank
19
+ {
20
20
ghost var accts: seq < nat >
21
21
ghost const acct_sum: nat
22
22
@@ -25,187 +25,187 @@ class Bank
25
25
static const BankKinds : map < Blkno, Kind> := map [513 as Blkno := KindUInt64 as Kind]
26
26
27
27
static function Acct (n: uint64 ): (a:Addr)
28
- requires n < 512
29
- ensures a. off as nat % kindSize (KindUInt64) == 0
28
+ requires n < 512
29
+ ensures a. off as nat % kindSize (KindUInt64) == 0
30
30
{
31
- assert kindSize (6) == 64;
32
- Arith. mul_mod (n as nat, 64);
33
- Addr (513, n*64)
31
+ assert kindSize (6) == 64;
32
+ Arith. mul_mod (n as nat, 64);
33
+ Addr (513, n*64)
34
34
}
35
35
36
36
static ghost predicate acct_val (jrnl: Jrnl , acct: uint64 , val: nat )
37
- reads jrnl
38
- requires jrnl. Valid ()
39
- requires jrnl. kinds == BankKinds
40
- requires acct < 512
37
+ reads jrnl
38
+ requires jrnl. Valid ()
39
+ requires jrnl. kinds == BankKinds
40
+ requires acct < 512
41
41
{
42
- jrnl. in_domain (Acct(acct));
43
- && val < U64. MAX
44
- && jrnl. data[Acct (acct)] == ObjData (seq_encode([EncUInt64(val as uint64)]))
42
+ jrnl. in_domain (Acct(acct));
43
+ && val < U64. MAX
44
+ && jrnl. data[Acct (acct)] == ObjData (seq_encode([EncUInt64(val as uint64)]))
45
45
}
46
46
47
47
// pure version of Valid for crash condition
48
48
static ghost predicate ValidState (jrnl: Jrnl , accts: seq <nat >, acct_sum: nat )
49
- reads jrnl
49
+ reads jrnl
50
50
{
51
- && jrnl. Valid ()
52
- && jrnl. kinds == BankKinds
53
- && |accts| == 512
54
- && (forall n: uint64 :: n < 512 ==>
55
- var acct := Acct (n);
56
- && acct in jrnl. data
57
- && jrnl. size (acct) == 64
58
- && accts[n] < U64. MAX
59
- && acct_val (jrnl, n, accts[n]))
60
- && acct_sum == C. sum_nat (accts)
51
+ && jrnl. Valid ()
52
+ && jrnl. kinds == BankKinds
53
+ && |accts| == 512
54
+ && (forall n: uint64 :: n < 512 ==>
55
+ var acct := Acct (n);
56
+ && acct in jrnl. data
57
+ && jrnl. size (acct) == 64
58
+ && accts[n] < U64. MAX
59
+ && acct_val (jrnl, n, accts[n]))
60
+ && acct_sum == C. sum_nat (accts)
61
61
}
62
62
63
63
ghost predicate Valid ()
64
- reads this , jrnl
64
+ reads this , jrnl
65
65
{
66
- && ValidState (jrnl, accts, acct_sum)
66
+ && ValidState (jrnl, accts, acct_sum)
67
67
}
68
68
69
69
static method encode_acct (x: uint64 ) returns (bs:Bytes)
70
- ensures fresh (bs)
71
- ensures bs. Valid ()
72
- ensures seq_encode ([EncUInt64(x)]) == bs. data
70
+ ensures fresh (bs)
71
+ ensures bs. Valid ()
72
+ ensures seq_encode ([EncUInt64(x)]) == bs. data
73
73
{
74
- bs := NewBytes (8);
75
- IntEncoding. UInt64Put (x, 0, bs);
74
+ bs := NewBytes (8);
75
+ IntEncoding. UInt64Put (x, 0, bs);
76
76
}
77
77
78
78
static method decode_acct (bs:Bytes , ghost x: nat ) returns (x': uint64)
79
- requires x < U64. MAX
80
- requires bs. Valid ()
81
- requires seq_encode ([EncUInt64(x as uint64)]) == bs. data
82
- ensures x' as nat == x
79
+ requires x < U64. MAX
80
+ requires bs. Valid ()
81
+ requires seq_encode ([EncUInt64(x as uint64)]) == bs. data
82
+ ensures x' as nat == x
83
83
{
84
- x' := UInt64Decode (bs, 0, x as uint64);
84
+ x' := UInt64Decode (bs, 0, x as uint64);
85
85
}
86
86
87
87
constructor Init (d: Disk , init_bal: uint64 )
88
- ensures Valid ()
89
- ensures forall n: nat :: n < 512 ==> accts[n] == init_bal as nat
90
- ensures acct_sum == 512* (init_bal as nat )
88
+ ensures Valid ()
89
+ ensures forall n: nat :: n < 512 ==> accts[n] == init_bal as nat
90
+ ensures acct_sum == 512* (init_bal as nat )
91
91
{
92
- // BUG: without the "as" operators in the next line, Dafny makes the type
93
- // of the map display expression map<int,int>.
94
- var kinds := map [513 as Blkno := KindUInt64 as Kind];
95
- var jrnl := NewJrnl (d, kinds);
96
-
97
- // help with constant calculation
98
- assert kindSize (6) == 64;
99
- assert kindSize (jrnl.kinds[513]) == 64;
100
- forall n: uint64 | n < 512
101
- ensures Acct (n) in jrnl. data
102
- ensures jrnl. size (Acct(n)) == 64
103
- {
104
- ghost var acct := Acct (n);
105
- jrnl. in_domain (acct);
106
- jrnl. has_size (acct);
107
- }
108
-
109
- var txn := jrnl. Begin ();
110
- var n := 0;
111
- while n < 512
92
+ // BUG: without the "as" operators in the next line, Dafny makes the type
93
+ // of the map display expression map<int,int>.
94
+ var kinds := map [513 as Blkno := KindUInt64 as Kind];
95
+ var jrnl := NewJrnl (d, kinds);
96
+
97
+ // help with constant calculation
98
+ assert kindSize (6) == 64;
99
+ assert kindSize (jrnl.kinds[513]) == 64;
100
+ forall n: uint64 | n < 512
101
+ ensures Acct (n) in jrnl. data
102
+ ensures jrnl. size (Acct(n)) == 64
103
+ {
104
+ ghost var acct := Acct (n);
105
+ jrnl. in_domain (acct);
106
+ jrnl. has_size (acct);
107
+ }
108
+
109
+ var txn := jrnl. Begin ();
110
+ var n := 0;
111
+ while n < 512
112
112
modifies jrnl
113
113
invariant txn. jrnl == jrnl
114
114
invariant txn. Valid ()
115
115
invariant n <= 512
116
116
invariant forall k {:trigger Acct (k)} :: 0 <= k < n ==> acct_val (jrnl, k, init_bal as nat)
117
- {
118
- var acct := Acct (n);
119
- jrnl. in_domain (acct);
120
- var init_acct := encode_acct (init_bal);
121
- txn. Write (acct, init_acct);
122
- n := n + 1;
123
- }
124
- var _ := txn. Commit (true);
125
-
126
- this . jrnl := jrnl;
127
-
128
- // NOTE: this was really annoying to figure out - turns out needed the
129
- // accounts to be a repeat of nats instead of uint64
130
- C. sum_repeat (init_bal as nat, 512);
131
- accts := C. repeat (init_bal as nat, 512);
132
- acct_sum := 512* (init_bal as nat );
133
-
134
- forall n: uint64 | n < 512
135
- ensures (var acct := Acct(n);
136
- acct in jrnl. data)
137
- {
138
- ghost var acct := Acct (n);
139
- jrnl. in_domain (acct);
140
- }
117
+ {
118
+ var acct := Acct (n);
119
+ jrnl. in_domain (acct);
120
+ var init_acct := encode_acct (init_bal);
121
+ txn. Write (acct, init_acct);
122
+ n := n + 1;
123
+ }
124
+ var _ := txn. Commit (true);
125
+
126
+ this . jrnl := jrnl;
127
+
128
+ // NOTE: this was really annoying to figure out - turns out needed the
129
+ // accounts to be a repeat of nats instead of uint64
130
+ C. sum_repeat (init_bal as nat, 512);
131
+ accts := C. repeat (init_bal as nat, 512);
132
+ acct_sum := 512* (init_bal as nat );
133
+
134
+ forall n: uint64 | n < 512
135
+ ensures (var acct := Acct(n);
136
+ acct in jrnl. data)
137
+ {
138
+ ghost var acct := Acct (n);
139
+ jrnl. in_domain (acct);
140
+ }
141
141
142
142
}
143
143
144
144
constructor Recover (jrnl: Jrnl , ghost accts: seq <nat >, ghost acct_sum: nat )
145
- requires ValidState (jrnl, accts, acct_sum)
146
- ensures Valid ()
147
- ensures this . jrnl == jrnl
148
- ensures this . accts == accts
149
- ensures this . acct_sum == acct_sum
145
+ requires ValidState (jrnl, accts, acct_sum)
146
+ ensures Valid ()
147
+ ensures this . jrnl == jrnl
148
+ ensures this . accts == accts
149
+ ensures this . acct_sum == acct_sum
150
150
{
151
- this . jrnl := jrnl;
152
- this . accts := accts;
153
- this . acct_sum := acct_sum;
151
+ this . jrnl := jrnl;
152
+ this . accts := accts;
153
+ this . acct_sum := acct_sum;
154
154
}
155
155
156
156
ghost method inc_acct (acct: uint64 , amt: int )
157
- modifies this
158
- requires acct as nat < |accts|
159
- requires no_overflow (accts[acct], amt)
160
- ensures accts == old (accts[acct as nat := accts[acct] + amt])
161
- ensures C. sum_nat (accts) == old (C. sum_nat (accts) + amt)
157
+ modifies this
158
+ requires acct as nat < |accts|
159
+ requires no_overflow (accts[acct], amt)
160
+ ensures accts == old (accts[acct as nat := accts[acct] + amt])
161
+ ensures C. sum_nat (accts) == old (C. sum_nat (accts) + amt)
162
162
{
163
- C. sum_update (accts, acct as nat, accts[acct] as nat + amt);
164
- accts := accts[acct as nat := accts[acct] + amt];
163
+ C. sum_update (accts, acct as nat, accts[acct] as nat + amt);
164
+ accts := accts[acct as nat := accts[acct] + amt];
165
165
}
166
166
167
167
method Transfer (acct1: uint64 , acct2: uint64 )
168
- requires Valid () ensures Valid ()
169
- modifies this , jrnl
170
- requires && acct1 < 512 && acct2 < 512 && acct1 != acct2
171
- requires && no_overflow (accts[acct1], -1) && no_overflow (accts[acct2], 1)
172
- ensures accts == old (accts[acct1 as nat := accts[acct1]- 1][acct2 as nat := accts[acct2]+ 1])
168
+ requires Valid () ensures Valid ()
169
+ modifies this , jrnl
170
+ requires && acct1 < 512 && acct2 < 512 && acct1 != acct2
171
+ requires && no_overflow (accts[acct1], -1) && no_overflow (accts[acct2], 1)
172
+ ensures accts == old (accts[acct1 as nat := accts[acct1]- 1][acct2 as nat := accts[acct2]+ 1])
173
173
{
174
- var txn := jrnl. Begin ();
175
- var x := txn. Read (Acct(acct1), 64);
176
- var acct1_val: uint64 := decode_acct (x, accts[acct1]);
177
- var x' := encode_acct (acct1_val-1);
178
- txn. Write (Acct(acct1), x');
179
- inc_acct (acct1, -1);
180
-
181
- x := txn. Read (Acct(acct2), 64);
182
- var acct2_val: uint64 := decode_acct (x, accts[acct2]);
183
- x' := encode_acct (acct2_val+1);
184
- txn. Write (Acct(acct2), x');
185
- inc_acct (acct2, 1);
186
- var _ := txn. Commit (true);
174
+ var txn := jrnl. Begin ();
175
+ var x := txn. Read (Acct(acct1), 64);
176
+ var acct1_val: uint64 := decode_acct (x, accts[acct1]);
177
+ var x' := encode_acct (acct1_val-1);
178
+ txn. Write (Acct(acct1), x');
179
+ inc_acct (acct1, -1);
180
+
181
+ x := txn. Read (Acct(acct2), 64);
182
+ var acct2_val: uint64 := decode_acct (x, accts[acct2]);
183
+ x' := encode_acct (acct2_val+1);
184
+ txn. Write (Acct(acct2), x');
185
+ inc_acct (acct2, 1);
186
+ var _ := txn. Commit (true);
187
187
}
188
188
189
189
method Get (acct: uint64 )
190
- returns (bal: uint64)
191
- requires Valid ()
192
- requires acct < 512
193
- ensures bal as nat == accts[acct]
190
+ returns (bal: uint64)
191
+ requires Valid ()
192
+ requires acct < 512
193
+ ensures bal as nat == accts[acct]
194
194
{
195
- var txn := jrnl. Begin ();
196
- var x := txn. Read (Acct(acct), 64);
197
- bal := decode_acct (x, accts[acct]);
198
- // need to commit or abort (even of read-only)
199
- var _ := txn. Commit (true);
195
+ var txn := jrnl. Begin ();
196
+ var x := txn. Read (Acct(acct), 64);
197
+ bal := decode_acct (x, accts[acct]);
198
+ // need to commit or abort (even of read-only)
199
+ var _ := txn. Commit (true);
200
200
}
201
201
202
202
// this is kind of silly but it gets the point across (without requiring the
203
203
// reader to understand Valid())
204
204
lemma Audit ()
205
- requires Valid ()
206
- ensures C. sum_nat (accts) == acct_sum
205
+ requires Valid ()
206
+ ensures C. sum_nat (accts) == acct_sum
207
207
{
208
208
}
209
- }
209
+ }
210
210
211
211
}
0 commit comments