Skip to content

Commit 36528ed

Browse files
authored
refactor(benches): beatify wallet v5 (#3280)
1 parent 180e990 commit 36528ed

File tree

3 files changed

+132
-111
lines changed

3 files changed

+132
-111
lines changed

src/benchmarks/wallet-v5/gas.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,16 @@
139139
"internalTransfer": "5742",
140140
"extensionTransfer": "4656"
141141
}
142+
},
143+
{
144+
"label": "1.6.11 with throw(0) instead of return",
145+
"pr": "https://github.com/tact-lang/tact/pull/3280",
146+
"gas": {
147+
"externalTransfer": "4967",
148+
"addExtension": "5630",
149+
"internalTransfer": "5724",
150+
"extensionTransfer": "4656"
151+
}
142152
}
143153
]
144154
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// exit codes
2+
const signatureDisabled: Int = 132;
3+
const invalidSeqno: Int = 133;
4+
const invalidWalletId: Int = 134;
5+
const invalidSignature: Int = 135;
6+
const expired: Int = 136;
7+
const externalSendMessageMustHaveIgnoreErrorsSendMode: Int = 137;
8+
const invalidMessageOperation: Int = 138;
9+
const addExtension: Int = 139;
10+
const removeExtension: Int = 140;
11+
const unsupportedAction: Int = 141;
12+
const disableSignatureWhenExtensionsIsEmpty: Int = 142;
13+
const thisSignatureModeAlreadySet: Int = 143;
14+
const removeLastExtensionWhenSignatureDisabled: Int = 144;
15+
const extensionWrongWorkchain: Int = 145;
16+
const onlyExtensionCanChangeSignatureMode: Int = 146;
17+
const invalidC5: Int = 147;
Lines changed: 105 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,6 @@
1-
/*
2-
actions
1+
import "./constants";
32

4-
out_list_empty$_ = OutList 0;
5-
out_list$_ {n:#} prev:^(OutList n) action:OutAction = OutList (n + 1);
6-
action_send_msg#0ec3c86d mode:(## 8) out_msg:^(MessageRelaxed Any) = OutAction;
7-
8-
// Extended actions in W5:
9-
action_list_basic$_ {n:#} actions:^(OutList n) = ActionList n 0;
10-
action_list_extended$_ {m:#} {n:#} action:ExtendedAction prev:^(ActionList n m) = ActionList n (m+1);
11-
12-
action_add_ext#02 addr:MsgAddressInt = ExtendedAction;
13-
action_delete_ext#03 addr:MsgAddressInt = ExtendedAction;
14-
action_set_signature_auth_allowed#04 allowed:(## 1) = ExtendedAction;
15-
*/
16-
17-
message(0x7369676E) ExternalSignedRequest {
3+
message(0x7369676e) ExternalSignedRequest {
184
walletId: Int as uint32;
195
validUntil: Int as uint32;
206
seqno: Int as uint32;
@@ -23,11 +9,6 @@ message(0x7369676E) ExternalSignedRequest {
239
data: Slice as remaining;
2410
}
2511

26-
// leave as example for discussion
27-
// message(0x73696e74) InternalSignedRequest {
28-
// data: Slice as remaining;
29-
// }
30-
3112
message(0x73696e74) InternalSignedRequest {
3213
walletId: Int as uint32;
3314
validUntil: Int as uint32;
@@ -42,89 +23,13 @@ message(0x6578746e) InternalExtensionRequest {
4223
actions: Slice as remaining;
4324
}
4425

45-
asm fun countTrailingZeroes(s: Slice): Int { SDCNTTRAIL0 }
46-
struct SliceFlag {
47-
data: Slice;
48-
flag: Bool;
49-
}
50-
asm extends fun beginParseExotic(self: Cell): SliceFlag { XCTOS }
51-
asm extends mutates fun enforceAndRemoveActionSendMsgPrefix(self: Slice) { x{0ec3c86d} SDBEGINS}
52-
asm fun setC5(outActions: Cell) { c5 POP }
53-
54-
asm extends mutates fun checkAndRemoveAddExtensionPrefix(self: Slice): Bool {x{02} SDBEGINSQ}
55-
asm extends mutates fun checkAndRemoveDeleteExtensionPrefix(self: Slice): Bool {x{03} SDBEGINSQ}
56-
asm extends mutates fun checkAndRemoveSetSignAllowedPrefix(self: Slice): Bool {x{04} SDBEGINSQ}
57-
58-
// as example
59-
asm fun typeCast(asd: InternalSignedRequest): ExternalSignedRequest {}
60-
6126
contract WalletV5(
6227
isSignatureAllowed: Bool,
6328
seqno: Int as uint32,
6429
walletId: Int as int32,
6530
publicKey: Int as uint256,
6631
extensions: map<Int as uint256, Bool>,
6732
) {
68-
/*
69-
actions has the following structure:
70-
71-
{
72-
outActions: Cell?;
73-
hasOtherActions: Bool;
74-
actions: Slice as remaining; // tl-b for ext actions
75-
}
76-
*/
77-
inline fun processActions(actions: Slice, isExternal: Bool, isExtension: Bool) {
78-
let outActions = actions.loadMaybeRef();
79-
if (outActions != null) {
80-
setC5(processSendMessages(outActions!!, isExternal));
81-
}
82-
83-
if (!actions.loadBool()) {
84-
return;
85-
}
86-
87-
while (true) {
88-
// check tag, process action, try to load next ref while we can
89-
let isAddExt = actions.checkAndRemoveAddExtensionPrefix();
90-
let isDeleteExt = isAddExt ? false : actions.checkAndRemoveDeleteExtensionPrefix();
91-
92-
if (isAddExt || isDeleteExt) {
93-
let addr = parseStdAddress(actions.loadAddress().asSlice());
94-
let myAddr = parseStdAddress(myAddress().asSlice());
95-
96-
throwUnless(145, addr.workchain == myAddr.workchain); // force_workchain optimization
97-
98-
if (isAddExt) {
99-
// blocked by https://github.com/tact-lang/tact/issues/2842
100-
// throwUnless(139, self.extensions.add(addr.address, true));
101-
throwIf(139, self.extensions.exists(addr.address));
102-
self.extensions.set(addr.address, true);
103-
} else if (isDeleteExt) {
104-
throwUnless(140, self.extensions.del(addr.address));
105-
throwIf(144, self.extensions.isEmpty() && !self.isSignatureAllowed);
106-
}
107-
} else if (actions.checkAndRemoveSetSignAllowedPrefix()) {
108-
throwUnless(146, isExtension);
109-
let newSignMode = actions.loadBool();
110-
throwIf(143, newSignMode == self.isSignatureAllowed);
111-
self.isSignatureAllowed = newSignMode;
112-
113-
if (!self.isSignatureAllowed && self.extensions.isEmpty()) {
114-
throw(142);
115-
}
116-
} else {
117-
throw(141);
118-
}
119-
120-
if (actions.refsEmpty()) {
121-
return;
122-
}
123-
124-
actions = actions.preloadRef().beginParse();
125-
}
126-
}
127-
12833
receive(msg: InternalExtensionRequest) {
12934
let myAddr = parseStdAddress(myAddress().asSlice());
13035
let addr = parseStdAddress(sender().asSlice());
@@ -148,13 +53,13 @@ contract WalletV5(
14853

14954
let isSignatureValid = checkSignature(signedSlice.hash(), signature, self.publicKey);
15055
if (!isSignatureValid) {
151-
return;
56+
throw(0);
15257
}
15358

154-
throwIf(132, !self.isSignatureAllowed && self.extensions.isEmpty());
155-
throwUnless(133, msg.seqno == self.seqno);
156-
throwUnless(134, msg.walletId == self.walletId);
157-
throwIf(136, msg.validUntil <= now());
59+
throwIf(signatureDisabled, !self.isSignatureAllowed && self.extensions.isEmpty());
60+
throwUnless(invalidSeqno, msg.seqno == self.seqno);
61+
throwUnless(invalidWalletId, msg.walletId == self.walletId);
62+
throwIf(expired, msg.validUntil <= now());
15863

15964
self.seqno += 1;
16065
commit();
@@ -177,10 +82,10 @@ contract WalletV5(
17782
throw(135);
17883
}
17984

180-
throwIf(132, !self.isSignatureAllowed && self.extensions.isEmpty());
181-
throwUnless(133, msg.seqno == self.seqno);
182-
throwUnless(134, msg.walletId == self.walletId);
183-
throwIf(136, msg.validUntil <= now());
85+
throwIf(signatureDisabled, !self.isSignatureAllowed && self.extensions.isEmpty());
86+
throwUnless(invalidSeqno, msg.seqno == self.seqno);
87+
throwUnless(invalidWalletId, msg.walletId == self.walletId);
88+
throwIf(expired, msg.validUntil <= now());
18489

18590
acceptMessage();
18691

@@ -192,6 +97,82 @@ contract WalletV5(
19297
self.processActions(signedSlice, true, false);
19398
}
19499

100+
/// Actions has the following structure:
101+
///
102+
/// ```tact
103+
/// struct Action {
104+
/// outActions: Cell?;
105+
/// hasOtherActions: Bool;
106+
/// actions: Slice as remaining; // tl-b for ext actions
107+
/// }
108+
/// ```
109+
///
110+
/// TL-B:
111+
///
112+
/// ```tlb
113+
/// out_list_empty$_ = OutList 0;
114+
/// out_list$_ {n:#} prev:^(OutList n) action:OutAction = OutList (n + 1);
115+
/// action_send_msg#0ec3c86d mode:(## 8) out_msg:^(MessageRelaxed Any) = OutAction;
116+
///
117+
/// // Extended actions in W5:
118+
/// action_list_basic$_ {n:#} actions:^(OutList n) = ActionList n 0;
119+
/// action_list_extended$_ {m:#} {n:#} action:ExtendedAction prev:^(ActionList n m) = ActionList n (m+1);
120+
///
121+
/// action_add_ext#02 addr:MsgAddressInt = ExtendedAction;
122+
/// action_delete_ext#03 addr:MsgAddressInt = ExtendedAction;
123+
/// action_set_signature_auth_allowed#04 allowed:(## 1) = ExtendedAction;
124+
/// ```
125+
inline fun processActions(actions: Slice, isExternal: Bool, isExtension: Bool) {
126+
let outActions = actions.loadMaybeRef();
127+
if (outActions != null) {
128+
setC5(processSendMessages(outActions!!, isExternal));
129+
}
130+
131+
if (!actions.loadBool()) {
132+
return;
133+
}
134+
135+
while (true) {
136+
// check tag, process action, try to load next ref while we can
137+
let isAddExt = actions.checkAndRemoveAddExtensionPrefix();
138+
let isDeleteExt = isAddExt ? false : actions.checkAndRemoveDeleteExtensionPrefix();
139+
140+
if (isAddExt || isDeleteExt) {
141+
let addr = parseStdAddress(actions.loadAddress().asSlice());
142+
let myAddr = parseStdAddress(myAddress().asSlice());
143+
144+
throwUnless(extensionWrongWorkchain, addr.workchain == myAddr.workchain); // force_workchain optimization
145+
146+
if (isAddExt) {
147+
// blocked by https://github.com/tact-lang/tact/issues/2842
148+
// throwUnless(139, self.extensions.add(addr.address, true));
149+
throwIf(addExtension, self.extensions.exists(addr.address));
150+
self.extensions.set(addr.address, true);
151+
} else if (isDeleteExt) {
152+
throwUnless(removeExtension, self.extensions.del(addr.address));
153+
throwIf(removeLastExtensionWhenSignatureDisabled, self.extensions.isEmpty() && !self.isSignatureAllowed);
154+
}
155+
} else if (actions.checkAndRemoveSetSignAllowedPrefix()) {
156+
throwUnless(onlyExtensionCanChangeSignatureMode, isExtension);
157+
let newSignMode = actions.loadBool();
158+
throwIf(thisSignatureModeAlreadySet, newSignMode == self.isSignatureAllowed);
159+
self.isSignatureAllowed = newSignMode;
160+
161+
if (!self.isSignatureAllowed && self.extensions.isEmpty()) {
162+
throw(disableSignatureWhenExtensionsIsEmpty);
163+
}
164+
} else {
165+
throw(unsupportedAction);
166+
}
167+
168+
if (actions.refsEmpty()) {
169+
return;
170+
}
171+
172+
actions = actions.preloadRef().beginParse();
173+
}
174+
}
175+
195176
get fun seqno(): Int {
196177
return self.seqno;
197178
}
@@ -216,16 +197,29 @@ inline fun processSendMessages(outActions: Cell, isExternal: Bool): Cell {
216197
while (!cs.empty()) {
217198
cs.enforceAndRemoveActionSendMsgPrefix();
218199

219-
throwUnless(147, cs.bits() == 8);
220-
throwUnless(147, cs.refs() == 2);
221-
throwIf(137, isExternal && (countTrailingZeroes(cs.preloadBits(7)) > 0));
200+
throwUnless(invalidC5, cs.bits() == 8);
201+
throwUnless(invalidC5, cs.refs() == 2);
202+
throwIf(externalSendMessageMustHaveIgnoreErrorsSendMode, isExternal && (countTrailingZeroes(cs.preloadBits(7)) > 0));
222203

223204
cs = cs.preloadRef().beginParseExotic().data;
224205
count += 1;
225206
}
226207

227-
throwUnless(147, count <= 255);
228-
throwUnless(147, cs.refs() == 0);
208+
throwUnless(invalidC5, count <= 255);
209+
throwUnless(invalidC5, cs.refs() == 0);
229210

230211
return outActions;
231212
}
213+
214+
asm fun countTrailingZeroes(s: Slice): Int { SDCNTTRAIL0 }
215+
struct SliceFlag {
216+
data: Slice;
217+
flag: Bool;
218+
}
219+
asm extends fun beginParseExotic(self: Cell): SliceFlag { XCTOS }
220+
asm extends mutates fun enforceAndRemoveActionSendMsgPrefix(self: Slice) { x{0ec3c86d} SDBEGINS }
221+
asm fun setC5(outActions: Cell) { c5 POP }
222+
223+
asm extends mutates fun checkAndRemoveAddExtensionPrefix(self: Slice): Bool { x{02} SDBEGINSQ }
224+
asm extends mutates fun checkAndRemoveDeleteExtensionPrefix(self: Slice): Bool { x{03} SDBEGINSQ }
225+
asm extends mutates fun checkAndRemoveSetSignAllowedPrefix(self: Slice): Bool { x{04} SDBEGINSQ }

0 commit comments

Comments
 (0)