1struct NativeContractDescriptor {
12 hash: [u8; 20],
13 name: &'static str,
14}
15
16const NATIVE_CONTRACTS: [NativeContractDescriptor; 11] = [
17 NativeContractDescriptor {
18 hash: [
19 0xf5, 0x63, 0xea, 0x40, 0xbc, 0x28, 0x3d, 0x4d, 0x0e, 0x05, 0xc4, 0x8e, 0xa3, 0x05,
20 0xb3, 0xf2, 0xa0, 0x73, 0x40, 0xef,
21 ],
22 name: "NeoToken",
23 },
24 NativeContractDescriptor {
25 hash: [
26 0xcf, 0x76, 0xe2, 0x8b, 0xd0, 0x06, 0x2c, 0x4a, 0x47, 0x8e, 0xe3, 0x55, 0x61, 0x01,
27 0x13, 0x19, 0xf3, 0xcf, 0xa4, 0xd2,
28 ],
29 name: "GasToken",
30 },
31 NativeContractDescriptor {
32 hash: [
33 0xfd, 0xa3, 0xfa, 0x43, 0x46, 0xea, 0x53, 0x2a, 0x25, 0x8f, 0xc4, 0x97, 0xdd, 0xad,
34 0xdb, 0x64, 0x37, 0xc9, 0xfd, 0xff,
35 ],
36 name: "ContractManagement",
37 },
38 NativeContractDescriptor {
39 hash: [
40 0x7b, 0xc6, 0x81, 0xc0, 0xa1, 0xf7, 0x1d, 0x54, 0x34, 0x57, 0xb6, 0x8b, 0xba, 0x8d,
41 0x5f, 0x9f, 0xdd, 0x4e, 0x5e, 0xcc,
42 ],
43 name: "PolicyContract",
44 },
45 NativeContractDescriptor {
46 hash: [
47 0x58, 0x87, 0x17, 0x11, 0x7e, 0x0a, 0xa8, 0x10, 0x72, 0xaf, 0xab, 0x71, 0xd2, 0xdd,
48 0x89, 0xfe, 0x7c, 0x4b, 0x92, 0xfe,
49 ],
50 name: "OracleContract",
51 },
52 NativeContractDescriptor {
53 hash: [
54 0xe2, 0x95, 0xe3, 0x91, 0x54, 0x4c, 0x17, 0x8a, 0xd9, 0x4f, 0x03, 0xec, 0x4d, 0xcd,
55 0xff, 0x78, 0x53, 0x4e, 0xcf, 0x49,
56 ],
57 name: "RoleManagement",
58 },
59 NativeContractDescriptor {
60 hash: [
61 0x3b, 0xec, 0x35, 0x31, 0x11, 0x9b, 0xba, 0xd7, 0x6d, 0xd0, 0x44, 0x92, 0x0b, 0x0d,
62 0xe6, 0xc3, 0x19, 0x4f, 0xe1, 0xc1,
63 ],
64 name: "Notary",
65 },
66 NativeContractDescriptor {
67 hash: [
68 0xc1, 0x3a, 0x56, 0xc9, 0x83, 0x53, 0xa7, 0xea, 0x6a, 0x32, 0x4d, 0x9a, 0x83, 0x5d,
69 0x1b, 0x5b, 0xf2, 0x26, 0x63, 0x15,
70 ],
71 name: "Treasury",
72 },
73 NativeContractDescriptor {
74 hash: [
75 0xbe, 0xf2, 0x04, 0x31, 0x40, 0x36, 0x2a, 0x77, 0xc1, 0x50, 0x99, 0xc7, 0xe6, 0x4c,
76 0x12, 0xf7, 0x00, 0xb6, 0x65, 0xda,
77 ],
78 name: "LedgerContract",
79 },
80 NativeContractDescriptor {
81 hash: [
82 0x1b, 0xf5, 0x75, 0xab, 0x11, 0x89, 0x68, 0x84, 0x13, 0x61, 0x0a, 0x35, 0xa1, 0x28,
83 0x86, 0xcd, 0xe0, 0xb6, 0x6c, 0x72,
84 ],
85 name: "CryptoLib",
86 },
87 NativeContractDescriptor {
88 hash: [
89 0xc0, 0xef, 0x39, 0xce, 0xe0, 0xe4, 0xe9, 0x25, 0xc6, 0xc2, 0xa0, 0x6a, 0x79, 0xe1,
90 0x44, 0x0d, 0xd8, 0x6f, 0xce, 0xac,
91 ],
92 name: "StdLib",
93 },
94];
95
96fn emit_throw_with_message(instructions: &mut Vec<Instruction>, message: &str) {
97 instructions.push(Instruction::PushLiteral(LiteralValue::String(
98 message.as_bytes().to_vec(),
99 )));
100 instructions.push(Instruction::Throw);
101}
102
103fn emit_is_native_contract_check(
104 ctx: &mut LoweringContext,
105 instructions: &mut Vec<Instruction>,
106 contract_slot: usize,
107) {
108 let done_label = ctx.next_label();
109
110 for contract in NATIVE_CONTRACTS.iter() {
111 let next_label = ctx.next_label();
112 instructions.push(Instruction::LoadLocal(contract_slot));
113 instructions.push(Instruction::PushLiteral(LiteralValue::Address(
114 contract.hash.to_vec(),
115 )));
116 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
117 instructions.push(Instruction::JumpIf { target: next_label });
118 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(true)));
119 instructions.push(Instruction::Jump { target: done_label });
120 instructions.push(Instruction::Label(next_label));
121 }
122
123 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(false)));
124 instructions.push(Instruction::Label(done_label));
125}
126
127fn emit_native_contract_name(
128 ctx: &mut LoweringContext,
129 instructions: &mut Vec<Instruction>,
130 contract_slot: usize,
131) {
132 let done_label = ctx.next_label();
133
134 for contract in NATIVE_CONTRACTS.iter() {
135 let next_label = ctx.next_label();
136 instructions.push(Instruction::LoadLocal(contract_slot));
137 instructions.push(Instruction::PushLiteral(LiteralValue::Address(
138 contract.hash.to_vec(),
139 )));
140 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
141 instructions.push(Instruction::JumpIf { target: next_label });
142 instructions.push(Instruction::PushLiteral(LiteralValue::String(
143 contract.name.as_bytes().to_vec(),
144 )));
145 instructions.push(Instruction::Jump { target: done_label });
146 instructions.push(Instruction::Label(next_label));
147 }
148
149 instructions.push(Instruction::PushLiteral(LiteralValue::String(
150 b"Unknown".to_vec(),
151 )));
152 instructions.push(Instruction::Label(done_label));
153}
154
155fn try_lower_nativecalls_member_builtin(
156 base: &Identifier,
157 member: &Identifier,
158 args: &[Expression],
159 ctx: &mut LoweringContext,
160 instructions: &mut Vec<Instruction>,
161) -> Option<bool> {
162 if base.name != "NativeCalls" {
163 return None;
164 }
165
166 match member.name.as_str() {
167 "getCommittee" => {
168 if !args.is_empty() {
169 ctx.record_error(format!(
170 "NativeCalls.getCommittee requires 0 argument(s), got {}",
171 args.len()
172 ));
173 return Some(false);
174 }
175
176 let tmp_id = ctx.next_label();
180 let committee_keys_slot = ctx.allocate_local(
181 format!("__native_calls_committee_keys_{tmp_id}"),
182 Some(ValueType::Any),
183 );
184 let committee_addrs_slot = ctx.allocate_local(
185 format!("__native_calls_committee_addrs_{tmp_id}"),
186 Some(ValueType::Array(Box::new(ValueType::Address))),
187 );
188 let index_slot = ctx.allocate_local(
189 format!("__native_calls_committee_index_{tmp_id}"),
190 Some(ValueType::Integer {
191 signed: false,
192 bits: 256,
193 }),
194 );
195
196 instructions.push(Instruction::CallBuiltin {
197 builtin: BuiltinCall::NativeCall {
198 contract: NativeContract::Neo,
199 method: "getCommittee".to_string(),
200 },
201 arg_count: 0,
202 });
203 instructions.push(Instruction::StoreLocal(committee_keys_slot));
204
205 instructions.push(Instruction::LoadLocal(committee_keys_slot));
206 instructions.push(Instruction::GetSize);
207 instructions.push(Instruction::NewArray {
208 element_type: ValueType::Address,
209 });
210 instructions.push(Instruction::StoreLocal(committee_addrs_slot));
211
212 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
213 BigInt::zero(),
214 )));
215 instructions.push(Instruction::StoreLocal(index_slot));
216
217 let loop_label = ctx.next_label();
218 let done_label = ctx.next_label();
219 instructions.push(Instruction::Label(loop_label));
220 instructions.push(Instruction::LoadLocal(index_slot));
221 instructions.push(Instruction::LoadLocal(committee_keys_slot));
222 instructions.push(Instruction::GetSize);
223 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
224 instructions.push(Instruction::JumpIf { target: done_label });
225
226 instructions.push(Instruction::LoadLocal(committee_addrs_slot));
228 instructions.push(Instruction::LoadLocal(index_slot));
229 instructions.push(Instruction::LoadLocal(committee_keys_slot));
230 instructions.push(Instruction::LoadLocal(index_slot));
231 instructions.push(Instruction::ArrayGet);
232 instructions.push(Instruction::CallBuiltin {
233 builtin: BuiltinCall::Syscall("System.Contract.CreateStandardAccount".to_string()),
234 arg_count: 1,
235 });
236 instructions.push(Instruction::ArraySet);
237
238 instructions.push(Instruction::LoadLocal(index_slot));
239 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
240 BigInt::one(),
241 )));
242 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
243 instructions.push(Instruction::StoreLocal(index_slot));
244 instructions.push(Instruction::Jump { target: loop_label });
245
246 instructions.push(Instruction::Label(done_label));
247 instructions.push(Instruction::LoadLocal(committee_addrs_slot));
248 Some(true)
249 }
250 "isCommittee" => {
251 if args.len() != 1 {
252 ctx.record_error(format!(
253 "NativeCalls.isCommittee requires 1 argument(s), got {}",
254 args.len()
255 ));
256 return Some(false);
257 }
258
259 let tmp_id = ctx.next_label();
263 let account_slot = ctx.allocate_local(
264 format!("__native_calls_is_committee_account_{tmp_id}"),
265 Some(ValueType::Address),
266 );
267 let committee_slot = ctx.allocate_local(
268 format!("__native_calls_is_committee_committee_{tmp_id}"),
269 Some(ValueType::Any),
270 );
271 let index_slot = ctx.allocate_local(
272 format!("__native_calls_is_committee_index_{tmp_id}"),
273 Some(ValueType::Integer {
274 signed: false,
275 bits: 256,
276 }),
277 );
278
279 if !lower_expression(&args[0], ctx, instructions) {
280 return Some(false);
281 }
282 instructions.push(Instruction::StoreLocal(account_slot));
283
284 instructions.push(Instruction::CallBuiltin {
285 builtin: BuiltinCall::NativeCall {
286 contract: NativeContract::Neo,
287 method: "getCommittee".to_string(),
288 },
289 arg_count: 0,
290 });
291 instructions.push(Instruction::StoreLocal(committee_slot));
292
293 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
294 BigInt::zero(),
295 )));
296 instructions.push(Instruction::StoreLocal(index_slot));
297
298 let loop_label = ctx.next_label();
299 let advance_label = ctx.next_label();
300 let done_label = ctx.next_label();
301 let end_label = ctx.next_label();
302
303 instructions.push(Instruction::Label(loop_label));
304 instructions.push(Instruction::LoadLocal(index_slot));
305 instructions.push(Instruction::LoadLocal(committee_slot));
306 instructions.push(Instruction::GetSize);
307 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
308 instructions.push(Instruction::JumpIf { target: done_label });
309
310 instructions.push(Instruction::LoadLocal(committee_slot));
311 instructions.push(Instruction::LoadLocal(index_slot));
312 instructions.push(Instruction::ArrayGet);
313 instructions.push(Instruction::CallBuiltin {
314 builtin: BuiltinCall::Syscall("System.Contract.CreateStandardAccount".to_string()),
315 arg_count: 1,
316 });
317 instructions.push(Instruction::LoadLocal(account_slot));
318 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
319 instructions.push(Instruction::JumpIf {
320 target: advance_label,
321 });
322
323 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(true)));
324 instructions.push(Instruction::Jump { target: end_label });
325
326 instructions.push(Instruction::Label(advance_label));
327 instructions.push(Instruction::LoadLocal(index_slot));
328 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
329 BigInt::one(),
330 )));
331 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
332 instructions.push(Instruction::StoreLocal(index_slot));
333 instructions.push(Instruction::Jump { target: loop_label });
334
335 instructions.push(Instruction::Label(done_label));
336 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(false)));
337 instructions.push(Instruction::Label(end_label));
338 Some(true)
339 }
340 "getNextBlockValidators" => {
341 if !args.is_empty() {
342 ctx.record_error(format!(
343 "NativeCalls.getNextBlockValidators requires 0 argument(s), got {}",
344 args.len()
345 ));
346 return Some(false);
347 }
348
349 let tmp_id = ctx.next_label();
353 let validator_keys_slot = ctx.allocate_local(
354 format!("__native_calls_validator_keys_{tmp_id}"),
355 Some(ValueType::Any),
356 );
357 let validator_addrs_slot = ctx.allocate_local(
358 format!("__native_calls_validator_addrs_{tmp_id}"),
359 Some(ValueType::Array(Box::new(ValueType::Address))),
360 );
361 let index_slot = ctx.allocate_local(
362 format!("__native_calls_validator_index_{tmp_id}"),
363 Some(ValueType::Integer {
364 signed: false,
365 bits: 256,
366 }),
367 );
368
369 instructions.push(Instruction::CallBuiltin {
370 builtin: BuiltinCall::NativeCall {
371 contract: NativeContract::Neo,
372 method: "getNextBlockValidators".to_string(),
373 },
374 arg_count: 0,
375 });
376 instructions.push(Instruction::StoreLocal(validator_keys_slot));
377
378 instructions.push(Instruction::LoadLocal(validator_keys_slot));
379 instructions.push(Instruction::GetSize);
380 instructions.push(Instruction::NewArray {
381 element_type: ValueType::Address,
382 });
383 instructions.push(Instruction::StoreLocal(validator_addrs_slot));
384
385 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
386 BigInt::zero(),
387 )));
388 instructions.push(Instruction::StoreLocal(index_slot));
389
390 let loop_label = ctx.next_label();
391 let done_label = ctx.next_label();
392 instructions.push(Instruction::Label(loop_label));
393 instructions.push(Instruction::LoadLocal(index_slot));
394 instructions.push(Instruction::LoadLocal(validator_keys_slot));
395 instructions.push(Instruction::GetSize);
396 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
397 instructions.push(Instruction::JumpIf { target: done_label });
398
399 instructions.push(Instruction::LoadLocal(validator_addrs_slot));
401 instructions.push(Instruction::LoadLocal(index_slot));
402 instructions.push(Instruction::LoadLocal(validator_keys_slot));
403 instructions.push(Instruction::LoadLocal(index_slot));
404 instructions.push(Instruction::ArrayGet);
405 instructions.push(Instruction::CallBuiltin {
406 builtin: BuiltinCall::Syscall("System.Contract.CreateStandardAccount".to_string()),
407 arg_count: 1,
408 });
409 instructions.push(Instruction::ArraySet);
410
411 instructions.push(Instruction::LoadLocal(index_slot));
412 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
413 BigInt::one(),
414 )));
415 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
416 instructions.push(Instruction::StoreLocal(index_slot));
417 instructions.push(Instruction::Jump { target: loop_label });
418
419 instructions.push(Instruction::Label(done_label));
420 instructions.push(Instruction::LoadLocal(validator_addrs_slot));
421 Some(true)
422 }
423 "isValidator" => {
424 if args.len() != 1 {
425 ctx.record_error(format!(
426 "NativeCalls.isValidator requires 1 argument(s), got {}",
427 args.len()
428 ));
429 return Some(false);
430 }
431
432 let tmp_id = ctx.next_label();
433 let account_slot = ctx.allocate_local(
434 format!("__native_calls_is_validator_account_{tmp_id}"),
435 Some(ValueType::Address),
436 );
437 let validators_slot = ctx.allocate_local(
438 format!("__native_calls_is_validator_keys_{tmp_id}"),
439 Some(ValueType::Any),
440 );
441 let index_slot = ctx.allocate_local(
442 format!("__native_calls_is_validator_index_{tmp_id}"),
443 Some(ValueType::Integer {
444 signed: false,
445 bits: 256,
446 }),
447 );
448
449 if !lower_expression(&args[0], ctx, instructions) {
450 return Some(false);
451 }
452 instructions.push(Instruction::StoreLocal(account_slot));
453
454 instructions.push(Instruction::CallBuiltin {
455 builtin: BuiltinCall::NativeCall {
456 contract: NativeContract::Neo,
457 method: "getNextBlockValidators".to_string(),
458 },
459 arg_count: 0,
460 });
461 instructions.push(Instruction::StoreLocal(validators_slot));
462
463 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
464 BigInt::zero(),
465 )));
466 instructions.push(Instruction::StoreLocal(index_slot));
467
468 let loop_label = ctx.next_label();
469 let advance_label = ctx.next_label();
470 let done_label = ctx.next_label();
471 let end_label = ctx.next_label();
472
473 instructions.push(Instruction::Label(loop_label));
474 instructions.push(Instruction::LoadLocal(index_slot));
475 instructions.push(Instruction::LoadLocal(validators_slot));
476 instructions.push(Instruction::GetSize);
477 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
478 instructions.push(Instruction::JumpIf { target: done_label });
479
480 instructions.push(Instruction::LoadLocal(validators_slot));
481 instructions.push(Instruction::LoadLocal(index_slot));
482 instructions.push(Instruction::ArrayGet);
483 instructions.push(Instruction::CallBuiltin {
484 builtin: BuiltinCall::Syscall("System.Contract.CreateStandardAccount".to_string()),
485 arg_count: 1,
486 });
487 instructions.push(Instruction::LoadLocal(account_slot));
488 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
489 instructions.push(Instruction::JumpIf {
490 target: advance_label,
491 });
492
493 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(true)));
494 instructions.push(Instruction::Jump { target: end_label });
495
496 instructions.push(Instruction::Label(advance_label));
497 instructions.push(Instruction::LoadLocal(index_slot));
498 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
499 BigInt::one(),
500 )));
501 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
502 instructions.push(Instruction::StoreLocal(index_slot));
503 instructions.push(Instruction::Jump { target: loop_label });
504
505 instructions.push(Instruction::Label(done_label));
506 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(false)));
507 instructions.push(Instruction::Label(end_label));
508 Some(true)
509 }
510 "isNativeContract" => {
511 if args.len() != 1 {
512 ctx.record_error(format!(
513 "NativeCalls.isNativeContract requires 1 argument(s), got {}",
514 args.len()
515 ));
516 return Some(false);
517 }
518
519 let tmp_id = ctx.next_label();
520 let contract_slot = ctx.allocate_local(
521 format!("__native_calls_is_native_contract_{tmp_id}"),
522 Some(ValueType::Address),
523 );
524
525 if !lower_expression(&args[0], ctx, instructions) {
526 return Some(false);
527 }
528 instructions.push(Instruction::StoreLocal(contract_slot));
529
530 emit_is_native_contract_check(ctx, instructions, contract_slot);
531 Some(true)
532 }
533 "getNativeContractName" => {
534 if args.len() != 1 {
535 ctx.record_error(format!(
536 "NativeCalls.getNativeContractName requires 1 argument(s), got {}",
537 args.len()
538 ));
539 return Some(false);
540 }
541
542 let tmp_id = ctx.next_label();
543 let contract_slot = ctx.allocate_local(
544 format!("__native_calls_contract_name_{tmp_id}"),
545 Some(ValueType::Address),
546 );
547
548 if !lower_expression(&args[0], ctx, instructions) {
549 return Some(false);
550 }
551 instructions.push(Instruction::StoreLocal(contract_slot));
552
553 emit_native_contract_name(ctx, instructions, contract_slot);
554 Some(true)
555 }
556 "getAllNativeContracts" => {
557 if !args.is_empty() {
558 ctx.record_error(format!(
559 "NativeCalls.getAllNativeContracts requires 0 argument(s), got {}",
560 args.len()
561 ));
562 return Some(false);
563 }
564
565 let tmp_id = ctx.next_label();
566 let contracts_slot = ctx.allocate_local(
567 format!("__native_calls_all_contracts_{tmp_id}"),
568 Some(ValueType::Array(Box::new(ValueType::Address))),
569 );
570
571 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
572 BigInt::from(NATIVE_CONTRACTS.len() as u64),
573 )));
574 instructions.push(Instruction::NewArray {
575 element_type: ValueType::Address,
576 });
577 instructions.push(Instruction::StoreLocal(contracts_slot));
578
579 for (index, contract) in NATIVE_CONTRACTS.iter().enumerate() {
580 instructions.push(Instruction::LoadLocal(contracts_slot));
581 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
582 BigInt::from(index as u64),
583 )));
584 instructions.push(Instruction::PushLiteral(LiteralValue::Address(
585 contract.hash.to_vec(),
586 )));
587 instructions.push(Instruction::ArraySet);
588 }
589
590 instructions.push(Instruction::LoadLocal(contracts_slot));
591 Some(true)
592 }
593 "estimateNativeCallGas" => {
594 if args.len() != 3 {
595 ctx.record_error(format!(
596 "NativeCalls.estimateNativeCallGas requires 3 argument(s), got {}",
597 args.len()
598 ));
599 return Some(false);
600 }
601
602 let tmp_id = ctx.next_label();
603 let contract_slot = ctx.allocate_local(
604 format!("__native_calls_estimate_contract_{tmp_id}"),
605 Some(ValueType::Address),
606 );
607 let method_slot = ctx.allocate_local(
608 format!("__native_calls_estimate_method_{tmp_id}"),
609 Some(ValueType::String),
610 );
611 let params_slot = ctx.allocate_local(
612 format!("__native_calls_estimate_params_{tmp_id}"),
613 Some(ValueType::ByteArray { fixed_len: None }),
614 );
615 let result_slot = ctx.allocate_local(
616 format!("__native_calls_estimate_result_{tmp_id}"),
617 Some(ValueType::Integer {
618 signed: false,
619 bits: 256,
620 }),
621 );
622
623 if !lower_expression(&args[0], ctx, instructions) {
624 return Some(false);
625 }
626 instructions.push(Instruction::StoreLocal(contract_slot));
627
628 if !lower_expression(&args[1], ctx, instructions) {
629 return Some(false);
630 }
631 instructions.push(Instruction::StoreLocal(method_slot));
632
633 if !lower_expression(&args[2], ctx, instructions) {
634 return Some(false);
635 }
636 instructions.push(Instruction::StoreLocal(params_slot));
637
638 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
639 BigInt::from(1_000_000u64),
640 )));
641 instructions.push(Instruction::StoreLocal(result_slot));
642
643 let end_label = ctx.next_label();
644
645 let neo_skip_label = ctx.next_label();
647 let neo_register_label = ctx.next_label();
648 instructions.push(Instruction::LoadLocal(contract_slot));
649 instructions.push(Instruction::PushLiteral(LiteralValue::Address(
650 NATIVE_CONTRACTS[0].hash.to_vec(),
651 )));
652 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
653 instructions.push(Instruction::JumpIf {
654 target: neo_skip_label,
655 });
656
657 instructions.push(Instruction::LoadLocal(method_slot));
658 instructions.push(Instruction::PushLiteral(LiteralValue::String(
659 b"vote".to_vec(),
660 )));
661 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
662 instructions.push(Instruction::JumpIf {
663 target: neo_register_label,
664 });
665 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
666 BigInt::from(100_000_000u64),
667 )));
668 instructions.push(Instruction::StoreLocal(result_slot));
669 instructions.push(Instruction::Jump { target: end_label });
670
671 instructions.push(Instruction::Label(neo_register_label));
672 instructions.push(Instruction::LoadLocal(method_slot));
673 instructions.push(Instruction::PushLiteral(LiteralValue::String(
674 b"registerCandidate".to_vec(),
675 )));
676 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
677 instructions.push(Instruction::JumpIf {
678 target: neo_skip_label,
679 });
680 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
681 BigInt::from(1_000_000_000u64),
682 )));
683 instructions.push(Instruction::StoreLocal(result_slot));
684 instructions.push(Instruction::Jump { target: end_label });
685
686 instructions.push(Instruction::Label(neo_skip_label));
687
688 let cm_skip_label = ctx.next_label();
690 let cm_update_label = ctx.next_label();
691 instructions.push(Instruction::LoadLocal(contract_slot));
692 instructions.push(Instruction::PushLiteral(LiteralValue::Address(
693 NATIVE_CONTRACTS[2].hash.to_vec(),
694 )));
695 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
696 instructions.push(Instruction::JumpIf {
697 target: cm_skip_label,
698 });
699
700 instructions.push(Instruction::LoadLocal(method_slot));
701 instructions.push(Instruction::PushLiteral(LiteralValue::String(
702 b"deploy".to_vec(),
703 )));
704 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
705 instructions.push(Instruction::JumpIf {
706 target: cm_update_label,
707 });
708 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
709 BigInt::from(500_000_000u64),
710 )));
711 instructions.push(Instruction::StoreLocal(result_slot));
712 instructions.push(Instruction::Jump { target: end_label });
713
714 instructions.push(Instruction::Label(cm_update_label));
715 instructions.push(Instruction::LoadLocal(method_slot));
716 instructions.push(Instruction::PushLiteral(LiteralValue::String(
717 b"update".to_vec(),
718 )));
719 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
720 instructions.push(Instruction::JumpIf {
721 target: cm_skip_label,
722 });
723 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
724 BigInt::from(300_000_000u64),
725 )));
726 instructions.push(Instruction::StoreLocal(result_slot));
727 instructions.push(Instruction::Jump { target: end_label });
728
729 instructions.push(Instruction::Label(cm_skip_label));
730
731 let oracle_skip_label = ctx.next_label();
733 instructions.push(Instruction::LoadLocal(contract_slot));
734 instructions.push(Instruction::PushLiteral(LiteralValue::Address(
735 NATIVE_CONTRACTS[4].hash.to_vec(),
736 )));
737 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
738 instructions.push(Instruction::JumpIf {
739 target: oracle_skip_label,
740 });
741
742 instructions.push(Instruction::LoadLocal(method_slot));
743 instructions.push(Instruction::PushLiteral(LiteralValue::String(
744 b"request".to_vec(),
745 )));
746 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
747 instructions.push(Instruction::JumpIf {
748 target: oracle_skip_label,
749 });
750 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
751 BigInt::from(50_000_000u64),
752 )));
753 instructions.push(Instruction::StoreLocal(result_slot));
754 instructions.push(Instruction::Jump { target: end_label });
755
756 instructions.push(Instruction::Label(oracle_skip_label));
757 instructions.push(Instruction::Label(end_label));
758 instructions.push(Instruction::LoadLocal(result_slot));
759 Some(true)
760 }
761 "batchNativeCalls" => {
762 if args.len() != 3 {
763 ctx.record_error(format!(
764 "NativeCalls.batchNativeCalls requires 3 argument(s), got {}",
765 args.len()
766 ));
767 return Some(false);
768 }
769
770 let tmp_id = ctx.next_label();
771 let contracts_slot = ctx.allocate_local(
772 format!("__native_calls_batch_contracts_{tmp_id}"),
773 Some(ValueType::Any),
774 );
775 let methods_slot = ctx.allocate_local(
776 format!("__native_calls_batch_methods_{tmp_id}"),
777 Some(ValueType::Any),
778 );
779 let params_slot = ctx.allocate_local(
780 format!("__native_calls_batch_params_{tmp_id}"),
781 Some(ValueType::Any),
782 );
783 let length_slot = ctx.allocate_local(
784 format!("__native_calls_batch_length_{tmp_id}"),
785 Some(ValueType::Integer {
786 signed: false,
787 bits: 256,
788 }),
789 );
790
791 if !lower_expression(&args[0], ctx, instructions) {
792 return Some(false);
793 }
794 instructions.push(Instruction::StoreLocal(contracts_slot));
795
796 if !lower_expression(&args[1], ctx, instructions) {
797 return Some(false);
798 }
799 instructions.push(Instruction::StoreLocal(methods_slot));
800
801 if !lower_expression(&args[2], ctx, instructions) {
802 return Some(false);
803 }
804 instructions.push(Instruction::StoreLocal(params_slot));
805
806 instructions.push(Instruction::LoadLocal(contracts_slot));
807 instructions.push(Instruction::GetSize);
808 instructions.push(Instruction::StoreLocal(length_slot));
809
810 let methods_fail = ctx.next_label();
812 let methods_ok = ctx.next_label();
813 instructions.push(Instruction::LoadLocal(methods_slot));
814 instructions.push(Instruction::GetSize);
815 instructions.push(Instruction::LoadLocal(length_slot));
816 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
817 instructions.push(Instruction::JumpIf {
818 target: methods_fail,
819 });
820 instructions.push(Instruction::Jump { target: methods_ok });
821 instructions.push(Instruction::Label(methods_fail));
822 emit_throw_with_message(instructions, "NativeCalls: array length mismatch");
823 instructions.push(Instruction::Label(methods_ok));
824
825 let params_fail = ctx.next_label();
827 let params_ok = ctx.next_label();
828 instructions.push(Instruction::LoadLocal(params_slot));
829 instructions.push(Instruction::GetSize);
830 instructions.push(Instruction::LoadLocal(length_slot));
831 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
832 instructions.push(Instruction::JumpIf {
833 target: params_fail,
834 });
835 instructions.push(Instruction::Jump { target: params_ok });
836 instructions.push(Instruction::Label(params_fail));
837 emit_throw_with_message(instructions, "NativeCalls: array length mismatch");
838 instructions.push(Instruction::Label(params_ok));
839
840 let non_empty_label = ctx.next_label();
842 instructions.push(Instruction::LoadLocal(length_slot));
843 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
844 BigInt::zero(),
845 )));
846 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
847 instructions.push(Instruction::JumpIf {
848 target: non_empty_label,
849 });
850 emit_throw_with_message(instructions, "NativeCalls: empty arrays");
851 instructions.push(Instruction::Label(non_empty_label));
852
853 let length_fail = ctx.next_label();
855 let length_ok_label = ctx.next_label();
856 instructions.push(Instruction::LoadLocal(length_slot));
857 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
858 BigInt::from(10u8),
859 )));
860 instructions.push(Instruction::BinaryOp(BinaryOperator::Le));
861 instructions.push(Instruction::JumpIf {
862 target: length_fail,
863 });
864 instructions.push(Instruction::Jump {
865 target: length_ok_label,
866 });
867 instructions.push(Instruction::Label(length_fail));
868 emit_throw_with_message(instructions, "NativeCalls: too many calls");
869 instructions.push(Instruction::Label(length_ok_label));
870
871 let results_slot = ctx.allocate_local(
872 format!("__native_calls_batch_results_{tmp_id}"),
873 Some(ValueType::Array(Box::new(ValueType::ByteArray {
874 fixed_len: None,
875 }))),
876 );
877 let index_slot = ctx.allocate_local(
878 format!("__native_calls_batch_index_{tmp_id}"),
879 Some(ValueType::Integer {
880 signed: false,
881 bits: 256,
882 }),
883 );
884 let contract_slot = ctx.allocate_local(
885 format!("__native_calls_batch_contract_{tmp_id}"),
886 Some(ValueType::Address),
887 );
888
889 instructions.push(Instruction::LoadLocal(length_slot));
890 instructions.push(Instruction::NewArray {
891 element_type: ValueType::ByteArray { fixed_len: None },
892 });
893 instructions.push(Instruction::StoreLocal(results_slot));
894
895 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
896 BigInt::zero(),
897 )));
898 instructions.push(Instruction::StoreLocal(index_slot));
899
900 let loop_label = ctx.next_label();
901 let done_label = ctx.next_label();
902 instructions.push(Instruction::Label(loop_label));
903 instructions.push(Instruction::LoadLocal(index_slot));
904 instructions.push(Instruction::LoadLocal(length_slot));
905 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
906 instructions.push(Instruction::JumpIf { target: done_label });
907
908 instructions.push(Instruction::LoadLocal(contracts_slot));
910 instructions.push(Instruction::LoadLocal(index_slot));
911 instructions.push(Instruction::ArrayGet);
912 instructions.push(Instruction::StoreLocal(contract_slot));
913
914 let native_ok = ctx.next_label();
916 emit_is_native_contract_check(ctx, instructions, contract_slot);
917 instructions.push(Instruction::JumpIf { target: native_ok });
918 emit_throw_with_message(instructions, "NativeCalls: not a native contract");
919 instructions.push(Instruction::Label(native_ok));
920
921 instructions.push(Instruction::LoadLocal(results_slot));
923 instructions.push(Instruction::LoadLocal(index_slot));
924 instructions.push(Instruction::LoadLocal(contract_slot));
925 instructions.push(Instruction::LoadLocal(methods_slot));
926 instructions.push(Instruction::LoadLocal(index_slot));
927 instructions.push(Instruction::ArrayGet);
928 instructions.push(Instruction::LoadLocal(params_slot));
929 instructions.push(Instruction::LoadLocal(index_slot));
930 instructions.push(Instruction::ArrayGet);
931
932 if ctx.is_safe {
933 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
934 BigInt::from(0x05u8),
935 )));
936 instructions.push(Instruction::CallBuiltin {
937 builtin: BuiltinCall::ContractCallWithFlags,
938 arg_count: 4,
939 });
940 } else {
941 instructions.push(Instruction::CallBuiltin {
942 builtin: BuiltinCall::ContractCall,
943 arg_count: 3,
944 });
945 }
946
947 instructions.push(Instruction::ArraySet);
948
949 instructions.push(Instruction::LoadLocal(index_slot));
950 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
951 BigInt::one(),
952 )));
953 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
954 instructions.push(Instruction::StoreLocal(index_slot));
955 instructions.push(Instruction::Jump { target: loop_label });
956
957 instructions.push(Instruction::Label(done_label));
958 instructions.push(Instruction::LoadLocal(results_slot));
959 Some(true)
960 }
961 "getContractById" => {
962 if args.len() != 1 {
963 ctx.record_error(format!(
964 "NativeCalls.getContractById requires 1 argument(s), got {}",
965 args.len()
966 ));
967 return Some(false);
968 }
969
970 let tmp_id = ctx.next_label();
971 let state_slot = ctx.allocate_local(
972 format!("__native_calls_contract_state_{tmp_id}"),
973 Some(ValueType::Any),
974 );
975 let result_slot = ctx.allocate_local(
976 format!("__native_calls_contract_state_result_{tmp_id}"),
977 Some(ValueType::Array(Box::new(ValueType::Any))),
978 );
979
980 if !lower_expression(&args[0], ctx, instructions) {
981 return Some(false);
982 }
983
984 instructions.push(Instruction::CallBuiltin {
985 builtin: BuiltinCall::NativeCall {
986 contract: NativeContract::ContractManagement,
987 method: "getContractById".to_string(),
988 },
989 arg_count: 1,
990 });
991 instructions.push(Instruction::StoreLocal(state_slot));
992
993 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
994 BigInt::from(4u8),
995 )));
996 instructions.push(Instruction::NewArray {
997 element_type: ValueType::Any,
998 });
999 instructions.push(Instruction::StoreLocal(result_slot));
1000
1001 instructions.push(Instruction::LoadLocal(result_slot));
1003 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1004 BigInt::zero(),
1005 )));
1006 instructions.push(Instruction::LoadLocal(state_slot));
1007 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1008 BigInt::from(2u8),
1009 )));
1010 instructions.push(Instruction::ArrayGet);
1011 instructions.push(Instruction::ArraySet);
1012
1013 instructions.push(Instruction::LoadLocal(result_slot));
1015 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1016 BigInt::one(),
1017 )));
1018 instructions.push(Instruction::LoadLocal(state_slot));
1019 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1020 BigInt::from(3u8),
1021 )));
1022 instructions.push(Instruction::ArrayGet);
1023 instructions.push(Instruction::ArraySet);
1024
1025 instructions.push(Instruction::LoadLocal(result_slot));
1027 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1028 BigInt::from(2u8),
1029 )));
1030 instructions.push(Instruction::LoadLocal(state_slot));
1031 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1032 BigInt::from(4u8),
1033 )));
1034 instructions.push(Instruction::ArrayGet);
1035 instructions.push(Instruction::CallBuiltin {
1036 builtin: BuiltinCall::NativeCall {
1037 contract: NativeContract::StdLib,
1038 method: "serialize".to_string(),
1039 },
1040 arg_count: 1,
1041 });
1042 instructions.push(Instruction::ArraySet);
1043
1044 instructions.push(Instruction::LoadLocal(result_slot));
1046 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1047 BigInt::from(3u8),
1048 )));
1049 instructions.push(Instruction::LoadLocal(state_slot));
1050 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1051 BigInt::one(),
1052 )));
1053 instructions.push(Instruction::ArrayGet);
1054 instructions.push(Instruction::ArraySet);
1055
1056 instructions.push(Instruction::LoadLocal(result_slot));
1057 Some(true)
1058 }
1059 "getNetworkConfiguration" => {
1060 if !args.is_empty() {
1061 ctx.record_error(format!(
1062 "NativeCalls.getNetworkConfiguration requires 0 argument(s), got {}",
1063 args.len()
1064 ));
1065 return Some(false);
1066 }
1067
1068 let tmp_id = ctx.next_label();
1069 let config_slot = ctx.allocate_local(
1070 format!("__native_calls_network_config_{tmp_id}"),
1071 Some(ValueType::Array(Box::new(ValueType::Any))),
1072 );
1073
1074 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1075 BigInt::from(6u8),
1076 )));
1077 instructions.push(Instruction::NewArray {
1078 element_type: ValueType::Any,
1079 });
1080 instructions.push(Instruction::StoreLocal(config_slot));
1081
1082 instructions.push(Instruction::LoadLocal(config_slot));
1084 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1085 BigInt::zero(),
1086 )));
1087 instructions.push(Instruction::CallBuiltin {
1088 builtin: BuiltinCall::NativeCall {
1089 contract: NativeContract::Policy,
1090 method: "getFeePerByte".to_string(),
1091 },
1092 arg_count: 0,
1093 });
1094 instructions.push(Instruction::ArraySet);
1095
1096 instructions.push(Instruction::LoadLocal(config_slot));
1098 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1099 BigInt::one(),
1100 )));
1101 instructions.push(Instruction::CallBuiltin {
1102 builtin: BuiltinCall::NativeCall {
1103 contract: NativeContract::Policy,
1104 method: "getExecFeeFactor".to_string(),
1105 },
1106 arg_count: 0,
1107 });
1108 instructions.push(Instruction::ArraySet);
1109
1110 instructions.push(Instruction::LoadLocal(config_slot));
1112 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1113 BigInt::from(2u8),
1114 )));
1115 instructions.push(Instruction::CallBuiltin {
1116 builtin: BuiltinCall::NativeCall {
1117 contract: NativeContract::Policy,
1118 method: "getStoragePrice".to_string(),
1119 },
1120 arg_count: 0,
1121 });
1122 instructions.push(Instruction::ArraySet);
1123
1124 instructions.push(Instruction::LoadLocal(config_slot));
1126 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1127 BigInt::from(3u8),
1128 )));
1129 instructions.push(Instruction::CallBuiltin {
1130 builtin: BuiltinCall::NativeCall {
1131 contract: NativeContract::Neo,
1132 method: "getGasPerBlock".to_string(),
1133 },
1134 arg_count: 0,
1135 });
1136 instructions.push(Instruction::ArraySet);
1137
1138 instructions.push(Instruction::LoadLocal(config_slot));
1140 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1141 BigInt::from(4u8),
1142 )));
1143 instructions.push(Instruction::CallBuiltin {
1144 builtin: BuiltinCall::NativeCall {
1145 contract: NativeContract::Oracle,
1146 method: "getPrice".to_string(),
1147 },
1148 arg_count: 0,
1149 });
1150 instructions.push(Instruction::ArraySet);
1151
1152 instructions.push(Instruction::LoadLocal(config_slot));
1154 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1155 BigInt::from(5u8),
1156 )));
1157 instructions.push(Instruction::CallBuiltin {
1158 builtin: BuiltinCall::NativeCall {
1159 contract: NativeContract::ContractManagement,
1160 method: "getMinimumDeploymentFee".to_string(),
1161 },
1162 arg_count: 0,
1163 });
1164 instructions.push(Instruction::ArraySet);
1165
1166 instructions.push(Instruction::LoadLocal(config_slot));
1167 Some(true)
1168 }
1169 "getNativeContractManifest" => {
1170 if args.len() != 1 {
1171 ctx.record_error(format!(
1172 "NativeCalls.getNativeContractManifest requires 1 argument(s), got {}",
1173 args.len()
1174 ));
1175 return Some(false);
1176 }
1177
1178 if !lower_expression(&args[0], ctx, instructions) {
1179 return Some(false);
1180 }
1181 instructions.push(Instruction::CallBuiltin {
1182 builtin: BuiltinCall::GetContract,
1183 arg_count: 1,
1184 });
1185 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1186 BigInt::from(2u8),
1187 )));
1188 instructions.push(Instruction::ArrayGet);
1189 Some(true)
1190 }
1191 "safeNativeCall" => {
1192 if args.len() != 3 {
1193 ctx.record_error(format!(
1194 "NativeCalls.safeNativeCall requires 3 argument(s), got {}",
1195 args.len()
1196 ));
1197 return Some(false);
1198 }
1199
1200 let tmp_id = ctx.next_label();
1201 let contract_slot = ctx.allocate_local(
1202 format!("__native_calls_safe_contract_{tmp_id}"),
1203 Some(ValueType::Address),
1204 );
1205 let method_slot = ctx.allocate_local(
1206 format!("__native_calls_safe_method_{tmp_id}"),
1207 Some(ValueType::String),
1208 );
1209 let params_slot = ctx.allocate_local(
1210 format!("__native_calls_safe_params_{tmp_id}"),
1211 Some(ValueType::ByteArray { fixed_len: None }),
1212 );
1213 let data_slot = ctx.allocate_local(
1214 format!("__native_calls_safe_data_{tmp_id}"),
1215 Some(ValueType::ByteArray { fixed_len: None }),
1216 );
1217 let tuple_slot = ctx.allocate_local(
1218 format!("__native_calls_safe_tuple_{tmp_id}"),
1219 Some(ValueType::Any),
1220 );
1221
1222 if !lower_expression(&args[0], ctx, instructions) {
1223 return Some(false);
1224 }
1225 instructions.push(Instruction::StoreLocal(contract_slot));
1226
1227 if !lower_expression(&args[1], ctx, instructions) {
1228 return Some(false);
1229 }
1230 instructions.push(Instruction::StoreLocal(method_slot));
1231
1232 if !lower_expression(&args[2], ctx, instructions) {
1233 return Some(false);
1234 }
1235 instructions.push(Instruction::StoreLocal(params_slot));
1236
1237 let native_ok = ctx.next_label();
1239 emit_is_native_contract_check(ctx, instructions, contract_slot);
1240 instructions.push(Instruction::JumpIf { target: native_ok });
1241 emit_throw_with_message(instructions, "NativeCalls: not a native contract");
1242 instructions.push(Instruction::Label(native_ok));
1243
1244 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1245 BigInt::from(2u8),
1246 )));
1247 instructions.push(Instruction::NewArray {
1248 element_type: ValueType::Any,
1249 });
1250 instructions.push(Instruction::StoreLocal(tuple_slot));
1251
1252 let catch_label = ctx.next_label();
1253 let end_label = ctx.next_label();
1254 instructions.push(Instruction::Try {
1255 catch_target: catch_label,
1256 });
1257
1258 instructions.push(Instruction::LoadLocal(contract_slot));
1259 instructions.push(Instruction::LoadLocal(method_slot));
1260 instructions.push(Instruction::LoadLocal(params_slot));
1261
1262 if ctx.is_safe {
1263 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1264 BigInt::from(0x05u8),
1265 )));
1266 instructions.push(Instruction::CallBuiltin {
1267 builtin: BuiltinCall::ContractCallWithFlags,
1268 arg_count: 4,
1269 });
1270 } else {
1271 instructions.push(Instruction::CallBuiltin {
1272 builtin: BuiltinCall::ContractCall,
1273 arg_count: 3,
1274 });
1275 }
1276
1277 instructions.push(Instruction::StoreLocal(data_slot));
1278
1279 instructions.push(Instruction::LoadLocal(tuple_slot));
1280 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1281 BigInt::zero(),
1282 )));
1283 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(true)));
1284 instructions.push(Instruction::ArraySet);
1285
1286 instructions.push(Instruction::LoadLocal(tuple_slot));
1287 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1288 BigInt::one(),
1289 )));
1290 instructions.push(Instruction::LoadLocal(data_slot));
1291 instructions.push(Instruction::ArraySet);
1292
1293 instructions.push(Instruction::EndTry { target: end_label });
1294
1295 instructions.push(Instruction::Label(catch_label));
1296 instructions.push(Instruction::Drop(ValueType::Any));
1297
1298 instructions.push(Instruction::LoadLocal(tuple_slot));
1299 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1300 BigInt::zero(),
1301 )));
1302 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(false)));
1303 instructions.push(Instruction::ArraySet);
1304
1305 instructions.push(Instruction::LoadLocal(tuple_slot));
1306 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
1307 BigInt::one(),
1308 )));
1309 instructions.push(Instruction::PushLiteral(
1310 LiteralValue::ByteArray(Vec::new()),
1311 ));
1312 instructions.push(Instruction::ArraySet);
1313
1314 instructions.push(Instruction::EndTry { target: end_label });
1315 instructions.push(Instruction::Label(end_label));
1316 instructions.push(Instruction::LoadLocal(tuple_slot));
1317 Some(true)
1318 }
1319 _ => None,
1320 }
1321}