Skip to content

Commit 02a3b66

Browse files
authored
feat(docs): add a real-world example for the commit() function in the Reference and the Cookbook (#3370)
1 parent 61689cf commit 02a3b66

File tree

4 files changed

+85
-11
lines changed

4 files changed

+85
-11
lines changed

docs/src/content/docs/cookbook/single-communication.mdx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,48 @@ contract Example {
120120

121121
:::
122122

123+
## How to commit the state for the sequence number
124+
125+
To prevent the possibility of replay attacks, you can use unique identifiers, such as `seqno`. Yet, the changes made to it must persist. To do so, the [`commit(){:tact}`](/ref/core-contextstate#commit) function is used.
126+
127+
```tact {20}
128+
message MsgWithSignedData {
129+
bundle: SignedBundle;
130+
seqno: Int as uint64;
131+
someExtraData: Cell;
132+
}
133+
134+
contract Sample(
135+
publicKey: Int as uint256,
136+
seqno: Int as uint64,
137+
) {
138+
external(msg: MsgWithSignedData) {
139+
// Various checks with accepting the external message processing afterwards
140+
require(msg.bundle.verifySignature(self.publicKey), "Invalid signature");
141+
require(msg.seqno == self.seqno, "Invalid seqno");
142+
acceptMessage();
143+
144+
// Since we have done all the checks we can now safely increase the number,
145+
// then commit the state of persistent data and output actions,
146+
// and, finally, save that state early, before any further actions take place.
147+
self.seqno += 1;
148+
commit();
149+
setData(self.toCell());
150+
151+
// And now you can safely do something with the rest of the message,
152+
// knowing that the `self.seqno` change will not be reverted in case of errors
153+
throw(42); // this will prevent subsequent code from executing,
154+
// but will not fail the transaction!
155+
}
156+
157+
// Empty receiver for the deployment,
158+
// which forwards the remaining value back to the sender
159+
receive() { cashback(sender()) }
160+
}
161+
162+
asm fun setData(data: Cell) { c4 POP }
163+
```
164+
123165
:::tip[Hey there!]
124166

125167
Didn't find your favorite example of single-contract communication? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)

docs/src/content/docs/ref/core-contextstate.mdx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,24 @@ Commits the current state of [registers][registers] `c4` (persistent data) and `
372372

373373
Usage example:
374374

375-
```tact {1}
376-
commit(); // now, transaction is considered "successful"
377-
throw(42); // and this won't fail it
375+
```tact {12}
376+
contract WalletV4(
377+
seqno: Int as uint32,
378+
// ...other parameters...
379+
) {
380+
// ...
381+
external(_: Slice) {
382+
// ...various prior checks...
383+
384+
acceptMessage();
385+
self.seqno += 1;
386+
setData(self.toCell());
387+
commit(); // now, transaction is considered "successful"
388+
throw(42); // and this won't fail it
389+
}
390+
}
391+
392+
asm fun setData(data: Cell) { c4 POP }
378393
```
379394

380395
## Blockchain state

src/stdlib/stdlib.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,10 +1915,14 @@ files["std/internal/send.tact"] =
19151915
"Ly8vICAgICB9Ci8vLyB9Ci8vLyBgYGAKLy8vCi8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL3JlZi9jb3JlLWdhcyNhY2NlcHRtZXNzYWdlCi8vLwph" +
19161916
"c20gZnVuIGFjY2VwdE1lc3NhZ2UoKSB7IEFDQ0VQVCB9CgovLy8gR2xvYmFsIGZ1bmN0aW9uLgovLy8KLy8vIENvbW1pdHMgdGhlIGN1cnJlbnQgc3RhdGUgb2YgcmVn" +
19171917
"aXN0ZXJzIGBjNGAgKHBlcnNpc3RlbnQgZGF0YSkgYW5kIGBjNWAgKGFjdGlvbnMpLCBzbyB0aGF0IHRoZSBjdXJyZW50IGV4ZWN1dGlvbiBpcyBjb25zaWRlcmVkICJz" +
1918-
"dWNjZXNzZnVsIiB3aXRoIHRoZSBzYXZlZCB2YWx1ZXMgZXZlbiBpZiBhbiBleGNlcHRpb24gaW4gY29tcHV0ZSBwaGFzZSBpcyB0aHJvd24gbGF0ZXIuCi8vCi8vLyBg" +
1919-
"YGB0YWN0Ci8vLyBmdW4gZXhhbXBsZSgpIHsKLy8vICAgICBjb21taXQoKTsgIC8vIG5vdywgdHJhbnNhY3Rpb24gaXMgY29uc2lkZXJlZCAic3VjY2Vzc2Z1bCIKLy8v" +
1920-
"ICAgICB0aHJvdyg0Mik7IC8vIGFuZCB0aGlzIHdvbid0IGZhaWwgaXQKLy8vIH0KLy8vIGBgYAovLy8KLy8vIFNlZTogaHR0cHM6Ly9kb2NzLnRhY3QtbGFuZy5vcmcv" +
1921-
"cmVmL2NvcmUtY29udGV4dHN0YXRlI2NvbW1pdAovLy8KYXNtIGZ1biBjb21taXQoKSB7IENPTU1JVCB9Cg==";
1918+
"dWNjZXNzZnVsIiB3aXRoIHRoZSBzYXZlZCB2YWx1ZXMgZXZlbiBpZiBhbiBleGNlcHRpb24gaW4gY29tcHV0ZSBwaGFzZSBpcyB0aHJvd24gbGF0ZXIuCi8vLwovLy8g" +
1919+
"YGBgdGFjdAovLy8gY29udHJhY3QgV2FsbGV0VjQoCi8vLyAgICAgc2Vxbm86IEludCBhcyB1aW50MzIsCi8vLyAgICAgLy8gLi4ub3RoZXIgcGFyYW1ldGVycy4uLgov" +
1920+
"Ly8gKSB7Ci8vLyAgICAgLy8gLi4uCi8vLyAgICAgZXh0ZXJuYWwoXzogU2xpY2UpIHsKLy8vICAgICAgICAgLy8gLi4udmFyaW91cyBwcmlvciBjaGVja3MuLi4KLy8v" +
1921+
"Ci8vLyAgICAgICAgIGFjY2VwdE1lc3NhZ2UoKTsKLy8vICAgICAgICAgc2VsZi5zZXFubyArPSAxOwovLy8gICAgICAgICBzZXREYXRhKHNlbGYudG9DZWxsKCkpOwov" +
1922+
"Ly8gICAgICAgICBjb21taXQoKTsgLy8gIG5vdywgdHJhbnNhY3Rpb24gaXMgY29uc2lkZXJlZCAic3VjY2Vzc2Z1bCIKLy8vICAgICAgICAgdGhyb3coNDIpOyAvLyBh" +
1923+
"bmQgdGhpcyB3b24ndCBmYWlsIGl0Ci8vLyAgICAgfQovLy8gfQovLy8KLy8vIGFzbSBmdW4gc2V0RGF0YShkYXRhOiBDZWxsKSB7IGM0IFBPUCB9Ci8vLyBgYGAKLy8v" +
1924+
"Ci8vLyBTZWU6IGh0dHBzOi8vZG9jcy50YWN0LWxhbmcub3JnL3JlZi9jb3JlLWNvbnRleHRzdGF0ZSNjb21taXQKLy8vCmFzbSBmdW4gY29tbWl0KCkgeyBDT01NSVQg" +
1925+
"fQo=";
19221926
files["std/internal/text.tact"] =
19231927
"Ly8KLy8gU3RyaW5nIGJ1aWxkZXIKLy8KCi8vLyBHbG9iYWwgZnVuY3Rpb24uCi8vLwovLy8gQ3JlYXRlcyBhbmQgcmV0dXJucyBhbiBlbXB0eSBgU3RyaW5nQnVpbGRl" +
19241928
"cmAuCi8vLwovLy8gYGBgdGFjdAovLy8gZnVuIGV4YW1wbGUoKTogU3RyaW5nIHsKLy8vICAgICBsZXQgZml6ejogU3RyaW5nQnVpbGRlciA9IGJlZ2luU3RyaW5nKCk7" +

src/stdlib/stdlib/std/internal/send.tact

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -610,12 +610,25 @@ asm fun acceptMessage() { ACCEPT }
610610
/// Global function.
611611
///
612612
/// Commits the current state of registers `c4` (persistent data) and `c5` (actions), so that the current execution is considered "successful" with the saved values even if an exception in compute phase is thrown later.
613-
//
613+
///
614614
/// ```tact
615-
/// fun example() {
616-
/// commit(); // now, transaction is considered "successful"
617-
/// throw(42); // and this won't fail it
615+
/// contract WalletV4(
616+
/// seqno: Int as uint32,
617+
/// // ...other parameters...
618+
/// ) {
619+
/// // ...
620+
/// external(_: Slice) {
621+
/// // ...various prior checks...
622+
///
623+
/// acceptMessage();
624+
/// self.seqno += 1;
625+
/// setData(self.toCell());
626+
/// commit(); // now, transaction is considered "successful"
627+
/// throw(42); // and this won't fail it
628+
/// }
618629
/// }
630+
///
631+
/// asm fun setData(data: Cell) { c4 POP }
619632
/// ```
620633
///
621634
/// See: https://docs.tact-lang.org/ref/core-contextstate#commit

0 commit comments

Comments
 (0)