Skip to content

Commit

Permalink
fix: make algopy.arc4.Address immutable
Browse files Browse the repository at this point in the history
BREAKING CHANGE: modifying an `algopy.arc4.Address` will now raise an error
  • Loading branch information
daniel-makerx committed Oct 28, 2024
1 parent 9704011 commit ad77f29
Show file tree
Hide file tree
Showing 20 changed files with 59 additions and 103 deletions.
4 changes: 2 additions & 2 deletions examples/sizes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
application/Reference 177 167 - | 92 83 -
arc4_dynamic_arrays/DynamicArray 2695 1931 - | 1733 1138 -
arc4_numeric_comparisons/UIntNOrdering 1100 908 - | 786 597 -
arc4_types/Arc4Address 85 62 - | 37 18 -
arc4_types/Arc4Address 79 18 - | 34 11 -
arc4_types/Arc4Arrays 623 376 - | 368 182 -
arc4_types/Arc4BoolEval 751 14 - | 167 8 -
arc4_types/Arc4BoolType 381 69 - | 307 46 -
Expand Down Expand Up @@ -130,4 +130,4 @@
unssa/UnSSA 432 368 - | 241 204 -
voting/VotingRoundApp 1593 1483 - | 734 649 -
with_reentrancy/WithReentrancy 255 242 - | 132 122 -
Total 69200 53576 53517 | 32843 21764 21720
Total 69194 53532 53473 | 32840 21757 21713
2 changes: 2 additions & 0 deletions src/puya/ir/builder/arc4.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ def handle_arc4_assign(
is_mutation: bool = False,
) -> Value:
result: Value
if is_mutation and target.wtype.immutable:
raise CodeError("cannot modify an immutable value", source_location)
match target:
case awst_nodes.IndexExpression(
base=awst_nodes.Expression(
Expand Down
5 changes: 3 additions & 2 deletions test_cases/arc4_types/address.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ def approval_program(self) -> bool:
some_address = arc4.Address(SOME_ADDRESS)
assert some_address == SOME_ADDRESS

some_address[0] = arc4.Byte(123)
assert some_address != SOME_ADDRESS
address_copy = some_address

assert some_address == address_copy
return True

def clear_state_program(self) -> bool:
Expand Down
38 changes: 13 additions & 25 deletions test_cases/arc4_types/out/Arc4AddressContract.approval.mir
Original file line number Diff line number Diff line change
@@ -1,38 +1,26 @@
// Op Stack (out)
// Op Stack (out)
// test_cases.arc4_types.address.Arc4AddressContract.approval_program() -> uint64:
main_block@0:
// arc4_types/address.py:8
// address = arc4.Address(Txn.sender)
txn Sender address#0
txn Sender address#0
// arc4_types/address.py:9
// assert address == Txn.sender
txn Sender address#0,tmp%0#0
l-load-copy address#0 1 address#0,tmp%0#0,address#0 (copy)
l-load tmp%0#0 1 address#0,address#0 (copy),tmp%0#0
== address#0,tmp%1#0
assert address#0
txn Sender address#0,tmp%0#0
l-load-copy address#0 1 address#0,tmp%0#0,address#0 (copy)
l-load tmp%0#0 1 address#0,address#0 (copy),tmp%0#0
== address#0,tmp%1#0
assert address#0
// arc4_types/address.py:11
// assert address.native == Txn.sender
txn Sender address#0,tmp%3#0
l-load address#0 1 tmp%3#0,address#0
l-load tmp%3#0 1 address#0,tmp%3#0
== tmp%4#0
txn Sender address#0,tmp%3#0
l-load address#0 1 tmp%3#0,address#0
l-load tmp%3#0 1 address#0,tmp%3#0
== tmp%4#0
assert
// arc4_types/address.py:16
// some_address = arc4.Address(SOME_ADDRESS)
addr "VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA" Address(VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
// arc4_types/address.py:19
// some_address[0] = arc4.Byte(123)
byte 0x7b Address(VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA),0x7b
replace2 0 some_address#1
// arc4_types/address.py:20
// assert some_address != SOME_ADDRESS
addr "VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA" some_address#1,Address(VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
!= tmp%10#0
assert
// arc4_types/address.py:21
// arc4_types/address.py:22
// return True
int 1 1
int 1 1
return


15 changes: 1 addition & 14 deletions test_cases/arc4_types/out/Arc4AddressContract.approval.teal
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma version 10

test_cases.arc4_types.address.Arc4AddressContract.approval_program:
bytecblock base32(VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJPQ)
// arc4_types/address.py:8
// address = arc4.Address(Txn.sender)
txn Sender
Expand All @@ -15,19 +14,7 @@ test_cases.arc4_types.address.Arc4AddressContract.approval_program:
txn Sender
==
assert
// arc4_types/address.py:16
// some_address = arc4.Address(SOME_ADDRESS)
bytec_0 // addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA
// arc4_types/address.py:19
// some_address[0] = arc4.Byte(123)
pushbytes 0x7b
replace2 0
// arc4_types/address.py:20
// assert some_address != SOME_ADDRESS
bytec_0 // addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA
!=
assert
// arc4_types/address.py:21
// arc4_types/address.py:22
// return True
pushint 1 // 1
return
2 changes: 1 addition & 1 deletion test_cases/arc4_types/out/Arc4AddressContract.clear.mir
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Op Stack (out)
// test_cases.arc4_types.address.Arc4AddressContract.clear_state_program() -> uint64:
main_block@0:
// arc4_types/address.py:24
// arc4_types/address.py:25
// return True
int 1 1
return
Expand Down
2 changes: 1 addition & 1 deletion test_cases/arc4_types/out/Arc4AddressContract.clear.teal
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma version 10

test_cases.arc4_types.address.Arc4AddressContract.clear_state_program:
// arc4_types/address.py:24
// arc4_types/address.py:25
// return True
pushint 1 // 1
return
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ contract test_cases.arc4_types.address.Arc4AddressContract:
let tmp%3#0: bytes = (txn Sender)
let tmp%4#0: bool = (== address#0 tmp%3#0)
(assert tmp%4#0)
let some_address#1: bytes = ((replace2 0) addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA 0x7b)
let tmp%10#0: bool = (!= some_address#1 addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
(assert tmp%10#0)
return 1u

program clear-state:
subroutine test_cases.arc4_types.address.Arc4AddressContract.clear_state_program() -> bool:
block@0: // L23
block@0: // L24
return 1u
8 changes: 3 additions & 5 deletions test_cases/arc4_types/out/Arc4AddressContract.ssa.ir
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ contract test_cases.arc4_types.address.Arc4AddressContract:
let some_address#0: bytes = addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA
let tmp%9#0: bool = (== some_address#0 addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
(assert tmp%9#0)
let assigned_value%0#0: bytes = 0x7b
let updated_target%0#0: bytes = (replace3 some_address#0 0u assigned_value%0#0)
let some_address#1: bytes = updated_target%0#0
let tmp%10#0: bool = (!= some_address#1 addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
let address_copy#0: bytes = some_address#0
let tmp%10#0: bool = (== some_address#0 address_copy#0)
(assert tmp%10#0)
return 1u

program clear-state:
subroutine test_cases.arc4_types.address.Arc4AddressContract.clear_state_program() -> bool:
block@0: // L23
block@0: // L24
return 1u
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ contract test_cases.arc4_types.address.Arc4AddressContract:
(assert tmp%8#0)
let tmp%9#0: bool = 1u
(assert tmp%9#0)
let some_address#1: bytes = ((replace2 0) addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA 0x7b)
let tmp%10#0: bool = (!= some_address#1 addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
let tmp%10#0: bool = 1u
(assert tmp%10#0)
return 1u

program clear-state:
subroutine test_cases.arc4_types.address.Arc4AddressContract.clear_state_program() -> bool:
block@0: // L23
block@0: // L24
return 1u
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@ contract test_cases.arc4_types.address.Arc4AddressContract:
(assert tmp%4#0)
let tmp%6#0: bool = 1u
(assert tmp%6#0) // Address length is 32 bytes
let some_address#1: bytes = ((replace2 0) addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA 0x7b)
let tmp%10#0: bool = (!= some_address#1 addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
(assert tmp%10#0)
return 1u

program clear-state:
subroutine test_cases.arc4_types.address.Arc4AddressContract.clear_state_program() -> bool:
block@0: // L23
block@0: // L24
return 1u
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ contract test_cases.arc4_types.address.Arc4AddressContract:
let tmp%3#0: bytes = (txn Sender)
let tmp%4#0: bool = (== address#0 tmp%3#0)
(assert tmp%4#0)
let some_address#1: bytes = ((replace2 0) addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA 0x7b)
let tmp%10#0: bool = (!= some_address#1 addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
(assert tmp%10#0)
return 1u

program clear-state:
subroutine test_cases.arc4_types.address.Arc4AddressContract.clear_state_program() -> bool:
block@0: // L23
block@0: // L24
return 1u
4 changes: 2 additions & 2 deletions test_cases/arc4_types/out/module.awst
Original file line number Diff line number Diff line change
Expand Up @@ -667,8 +667,8 @@ contract Arc4AddressContract
assert(reinterpret_cast<bytes>(zero_address) == reinterpret_cast<bytes>(global<ZeroAddress>()))
some_address: arc4.static_array<arc4.uint8, 32> = Address("VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA")
assert(some_address == Address("VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA"))
some_address[0u]: arc4.uint8 = 123_arc4u8
assert(some_address != Address("VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA"))
address_copy: arc4.static_array<arc4.uint8, 32> = some_address
assert(some_address == address_copy)
return true
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
#pragma version 10

test_cases.arc4_types.address.Arc4AddressContract.approval_program:
bytecblock base32(VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJPQ)
txn Sender
dupn 2
==
assert
txn Sender
==
assert
bytec_0 // addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA
pushbytes 0x7b
replace2 0
bytec_0 // addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA
!=
assert
pushint 1 // 1
return
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ contract test_cases.arc4_types.address.Arc4AddressContract:
let tmp%3#0: bytes = (txn Sender)
let tmp%4#0: bool = (== address#0 tmp%3#0)
(assert tmp%4#0)
let some_address#1: bytes = ((replace2 0) addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA 0x7b)
let tmp%10#0: bool = (!= some_address#1 addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
(assert tmp%10#0)
return 1u

program clear-state:
subroutine test_cases.arc4_types.address.Arc4AddressContract.clear_state_program() -> bool:
block@0: // L23
block@0: // L24
return 1u
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,12 @@ test_cases.arc4_types.address.Arc4AddressContract.approval_program:
// arc4_types/address.py:16
// some_address = arc4.Address(SOME_ADDRESS)
bytec_0 // addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA
// arc4_types/address.py:19
// some_address[0] = arc4.Byte(123)
pushint 0 // 0
pushbytes 0x7b
replace3
// arc4_types/address.py:20
// assert some_address != SOME_ADDRESS
bytec_0 // addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA
!=
assert
dup
// arc4_types/address.py:21
// assert some_address == address_copy
==
assert
// arc4_types/address.py:22
// return True
pushint 1 // 1
return
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma version 10

test_cases.arc4_types.address.Arc4AddressContract.clear_state_program:
// arc4_types/address.py:24
// arc4_types/address.py:25
// return True
pushint 1 // 1
return
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ contract test_cases.arc4_types.address.Arc4AddressContract:
(assert tmp%8#0)
let tmp%9#0: bool = (== addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
(assert tmp%9#0)
let updated_target%0#0: bytes = (replace3 addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA 0u 0x7b)
let some_address#1: bytes = updated_target%0#0
let tmp%10#0: bool = (!= some_address#1 addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
let tmp%10#0: bool = (== addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA)
(assert tmp%10#0)
return 1u

program clear-state:
subroutine test_cases.arc4_types.address.Arc4AddressContract.clear_state_program() -> bool:
block@0: // L23
block@0: // L24
return 1u
15 changes: 5 additions & 10 deletions test_cases/arc4_types/puya.log
Original file line number Diff line number Diff line change
Expand Up @@ -982,8 +982,8 @@ debug: Sealing block@3: // after_if_else_L6
debug: Terminated block@3: // after_if_else_L6
debug: Sealing block@0: // L7
debug: Terminated block@0: // L7
debug: Sealing block@0: // L23
debug: Terminated block@0: // L23
debug: Sealing block@0: // L24
debug: Terminated block@0: // L24
debug: Sealing block@0: // L6
debug: Terminated block@0: // L6
debug: Sealing block@1: // abi_routing_L6
Expand Down Expand Up @@ -18665,19 +18665,17 @@ debug: Optimizer: Constant Replacer
debug: Optimizer: Copy Propagation
debug: Found equivalence set: awst_tmp%0#0, zero_address#0
debug: Replacing {awst_tmp%0#0} with zero_address#0 made 2 modifications
debug: Found equivalence set: updated_target%0#0, some_address#1
debug: Replacing {updated_target%0#0} with some_address#1 made 1 modifications
debug: Optimizer: Intrinsic Simplifier
debug: Simplified (== 32u 32u) to 1u
debug: Simplified (len zero_address#0) to 32u
debug: Simplified (== zero_address#0 tmp%7#0) to 1u
debug: Simplified (== addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA) to 1u
debug: Simplified (replace3 addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA 0u 0x7b) to ((replace2 0) addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA 0x7b)
debug: Simplified (== addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA addr VCMJKWOY5P5P7SKMZFFOCEROPJCZOTIJMNIYNUCKH7LRO45JMJP6UYBIJA) to 1u
debug: Optimizer: Remove Unused Variables
debug: Removing unused variable zero_address#0
debug: Removing unused variable tmp%7#0
debug: Removing unused variable some_address#0
debug: Removing unused variable assigned_value%0#0
debug: Removing unused variable address_copy#0
debug: Optimizer: Inner Txn Field Replacer
debug: Optimizer: Replace Compiled References
debug: Optimizer: Simplify Control Ops
Expand Down Expand Up @@ -18712,6 +18710,7 @@ debug: Removing unused variable tmp%2#0
debug: Removing unused variable tmp%5#0
debug: Removing unused variable tmp%8#0
debug: Removing unused variable tmp%9#0
debug: Removing unused variable tmp%10#0
debug: Optimizer: Inner Txn Field Replacer
debug: Optimizer: Replace Compiled References
debug: Optimizer: Simplify Control Ops
Expand Down Expand Up @@ -18805,10 +18804,6 @@ debug: Inserted [email protected][7]: 'l-store-copy tmp%1#0 0'
debug: Replaced [email protected][9]: 'v-load tmp%1#0' with 'l-load tmp%1#0'
debug: Inserted [email protected][16]: 'l-store-copy tmp%4#0 0'
debug: Replaced [email protected][18]: 'v-load tmp%4#0' with 'l-load tmp%4#0'
debug: Inserted [email protected][23]: 'l-store-copy some_address#1 0'
debug: Replaced [email protected][25]: 'v-load some_address#1' with 'l-load some_address#1'
debug: Inserted [email protected][28]: 'l-store-copy tmp%10#0 0'
debug: Replaced [email protected][30]: 'v-load tmp%10#0' with 'l-load tmp%10#0'
debug: Inserted [email protected][3]: 'l-store-copy tmp%0#0 0'
debug: Replaced [email protected][6]: 'v-load tmp%0#0' with 'l-load tmp%0#0'
debug: Inserted [email protected][13]: 'l-store-copy tmp%3#0 0'
Expand Down
12 changes: 12 additions & 0 deletions tests/test_expected_output/arc4.test
Original file line number Diff line number Diff line change
Expand Up @@ -541,3 +541,15 @@ def constant_bool() -> None:
assert MyStruct(x=arc4.UInt512(0)) ## E: expression is always True

assert arc4.Tuple((arc4.Bool(False),)) ## E: expression is always True

## case: test_address_immutable
from algopy import *

class MyTest(ARC4Contract):
@arc4.abimethod
def test(self) -> None:
some_address = arc4.Address()

this_is_ok = some_address[0]
assert this_is_ok == 0
some_address[0] = arc4.Byte(123) ## E: cannot modify an immutable value

0 comments on commit ad77f29

Please sign in to comment.