diff --git a/examples/merkle/contract.py b/examples/merkle/contract.py index 0998af15b5..ce85353256 100644 --- a/examples/merkle/contract.py +++ b/examples/merkle/contract.py @@ -1,37 +1,29 @@ import typing -from algopy import ( - BigUInt, - arc4, - op, - subroutine, -) +from algopy import BigUInt, Bytes, arc4, op, subroutine, urange Bytes32: typing.TypeAlias = arc4.StaticArray[arc4.Byte, typing.Literal[32]] Proof: typing.TypeAlias = arc4.DynamicArray[Bytes32] class MerkleTree(arc4.ARC4Contract): - @subroutine - def hash_pair(self, a: Bytes32, b: Bytes32) -> Bytes32: - hash_bytes = op.sha256( - a.bytes + b.bytes - if BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) - else b.bytes + a.bytes - ) - return Bytes32.from_bytes(hash_bytes) - - @subroutine - def compute_root_hash(self, proof: Proof, leaf: Bytes32) -> Bytes32: - computed = leaf.copy() - for proof_hash in proof: - computed = self.hash_pair(computed, proof_hash) - return computed - @arc4.abimethod(create=True) def create(self, root: Bytes32) -> None: - self.root = root.copy() + self.root = root.bytes @arc4.abimethod def verify(self, proof: Proof, leaf: Bytes32) -> bool: - return self.root == self.compute_root_hash(proof, leaf) + return self.root == compute_root_hash(proof, leaf.bytes) + + +@subroutine +def compute_root_hash(proof: Proof, leaf: Bytes) -> Bytes: + computed = leaf + for idx in urange(proof.length): + computed = hash_pair(computed, proof[idx].bytes) + return computed + + +@subroutine +def hash_pair(a: Bytes, b: Bytes) -> Bytes: + return op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) diff --git a/examples/merkle/out/MerkleTree.approval.mir b/examples/merkle/out/MerkleTree.approval.mir index 9f945e6de8..4062272224 100644 --- a/examples/merkle/out/MerkleTree.approval.mir +++ b/examples/merkle/out/MerkleTree.approval.mir @@ -1,204 +1,206 @@ -// Op // Op Description Stack (out) Live (out) X stack Source code Source line +// Op // Op Description Stack (out) Live (out) X stack Source code Source line #pragma version 10 // examples.merkle.contract.MerkleTree.approval_program() -> uint64: main_block@0: - txna ApplicationArgs 0 // {txna} class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - // virtual: store tmp%0#0 to l-stack (no copy) tmp%0#0 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - method "create(byte[32])void" // tmp%0#0,method<"create(byte[32])void"> class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - method "verify(byte[32][],byte[32])bool" // tmp%0#0,method<"create(byte[32])void">,method<"verify(byte[32][],byte[32])bool"> class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - uncover 2 // load tmp%0#0 from l-stack (no copy) method<"create(byte[32])void">,method<"verify(byte[32][],byte[32])bool">,tmp%0#0 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - match main_create_route@1 main_verify_route@2 // class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - err // reject transaction // class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 + txna ApplicationArgs 0 // {txna} class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + // virtual: store tmp%0#0 to l-stack (no copy) tmp%0#0 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + method "create(byte[32])void" // tmp%0#0,method<"create(byte[32])void"> class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + method "verify(byte[32][],byte[32])bool" // tmp%0#0,method<"create(byte[32])void">,method<"verify(byte[32][],byte[32])bool"> class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + uncover 2 // load tmp%0#0 from l-stack (no copy) method<"create(byte[32])void">,method<"verify(byte[32][],byte[32])bool">,tmp%0#0 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + match main_create_route@1 main_verify_route@2 // class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + err // reject transaction // class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 main_create_route@1: - txn OnCompletion // {txn} arc4.abimethod(create=True) merkle/contract.py:31 - // virtual: store tmp%1#0 to l-stack (no copy) tmp%1#0 arc4.abimethod(create=True) merkle/contract.py:31 - // virtual: load tmp%1#0 from l-stack (no copy) tmp%1#0 arc4.abimethod(create=True) merkle/contract.py:31 - ! // {!} arc4.abimethod(create=True) merkle/contract.py:31 - // virtual: store tmp%2#0 to l-stack (no copy) tmp%2#0 arc4.abimethod(create=True) merkle/contract.py:31 - // virtual: load tmp%2#0 from l-stack (no copy) tmp%2#0 arc4.abimethod(create=True) merkle/contract.py:31 - assert // OnCompletion is NoOp // arc4.abimethod(create=True) merkle/contract.py:31 - txn ApplicationID // {txn} arc4.abimethod(create=True) merkle/contract.py:31 - // virtual: store tmp%3#0 to l-stack (no copy) tmp%3#0 arc4.abimethod(create=True) merkle/contract.py:31 - // virtual: load tmp%3#0 from l-stack (no copy) tmp%3#0 arc4.abimethod(create=True) merkle/contract.py:31 - ! // {!} arc4.abimethod(create=True) merkle/contract.py:31 - // virtual: store tmp%4#0 to l-stack (no copy) tmp%4#0 arc4.abimethod(create=True) merkle/contract.py:31 - // virtual: load tmp%4#0 from l-stack (no copy) tmp%4#0 arc4.abimethod(create=True) merkle/contract.py:31 - assert // is creating // arc4.abimethod(create=True) merkle/contract.py:31 - txna ApplicationArgs 1 // {txna} class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - // virtual: store tmp%5#0 to l-stack (no copy) tmp%5#0 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - // virtual: load tmp%5#0 from l-stack (no copy) tmp%5#0 arc4.abimethod(create=True) merkle/contract.py:31 - callsub create // arc4.abimethod(create=True) merkle/contract.py:31 - int 1 // 1 arc4.abimethod(create=True) merkle/contract.py:31 - return // arc4.abimethod(create=True) merkle/contract.py:31 + txn OnCompletion // {txn} arc4.abimethod(create=True) merkle/contract.py:10 + // virtual: store tmp%1#0 to l-stack (no copy) tmp%1#0 arc4.abimethod(create=True) merkle/contract.py:10 + // virtual: load tmp%1#0 from l-stack (no copy) tmp%1#0 arc4.abimethod(create=True) merkle/contract.py:10 + ! // {!} arc4.abimethod(create=True) merkle/contract.py:10 + // virtual: store tmp%2#0 to l-stack (no copy) tmp%2#0 arc4.abimethod(create=True) merkle/contract.py:10 + // virtual: load tmp%2#0 from l-stack (no copy) tmp%2#0 arc4.abimethod(create=True) merkle/contract.py:10 + assert // OnCompletion is NoOp // arc4.abimethod(create=True) merkle/contract.py:10 + txn ApplicationID // {txn} arc4.abimethod(create=True) merkle/contract.py:10 + // virtual: store tmp%3#0 to l-stack (no copy) tmp%3#0 arc4.abimethod(create=True) merkle/contract.py:10 + // virtual: load tmp%3#0 from l-stack (no copy) tmp%3#0 arc4.abimethod(create=True) merkle/contract.py:10 + ! // {!} arc4.abimethod(create=True) merkle/contract.py:10 + // virtual: store tmp%4#0 to l-stack (no copy) tmp%4#0 arc4.abimethod(create=True) merkle/contract.py:10 + // virtual: load tmp%4#0 from l-stack (no copy) tmp%4#0 arc4.abimethod(create=True) merkle/contract.py:10 + assert // is creating // arc4.abimethod(create=True) merkle/contract.py:10 + txna ApplicationArgs 1 // {txna} class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + // virtual: store tmp%5#0 to l-stack (no copy) tmp%5#0 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + // virtual: load tmp%5#0 from l-stack (no copy) tmp%5#0 arc4.abimethod(create=True) merkle/contract.py:10 + callsub create // arc4.abimethod(create=True) merkle/contract.py:10 + int 1 // 1 arc4.abimethod(create=True) merkle/contract.py:10 + return // arc4.abimethod(create=True) merkle/contract.py:10 main_verify_route@2: - txn OnCompletion // {txn} arc4.abimethod merkle/contract.py:35 - // virtual: store tmp%6#0 to l-stack (no copy) tmp%6#0 arc4.abimethod merkle/contract.py:35 - // virtual: load tmp%6#0 from l-stack (no copy) tmp%6#0 arc4.abimethod merkle/contract.py:35 - ! // {!} arc4.abimethod merkle/contract.py:35 - // virtual: store tmp%7#0 to l-stack (no copy) tmp%7#0 arc4.abimethod merkle/contract.py:35 - // virtual: load tmp%7#0 from l-stack (no copy) tmp%7#0 arc4.abimethod merkle/contract.py:35 - assert // OnCompletion is NoOp // arc4.abimethod merkle/contract.py:35 - txn ApplicationID // {txn} arc4.abimethod merkle/contract.py:35 - // virtual: store tmp%8#0 to l-stack (no copy) tmp%8#0 arc4.abimethod merkle/contract.py:35 - // virtual: load tmp%8#0 from l-stack (no copy) tmp%8#0 arc4.abimethod merkle/contract.py:35 - assert // is not creating // arc4.abimethod merkle/contract.py:35 - txna ApplicationArgs 1 // {txna} class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - // virtual: store tmp%9#0 to l-stack (no copy) tmp%9#0 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - txna ApplicationArgs 2 // tmp%9#0,{txna} class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - // virtual: store tmp%10#0 to l-stack (no copy) tmp%9#0,tmp%10#0 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - // virtual: load tmp%9#0 from l-stack (no copy) tmp%10#0,tmp%9#0 arc4.abimethod merkle/contract.py:35 - // virtual: load tmp%10#0 from l-stack (no copy) tmp%9#0,tmp%10#0 arc4.abimethod merkle/contract.py:35 - callsub verify // {verify} arc4.abimethod merkle/contract.py:35 - // virtual: store tmp%11#0 to l-stack (no copy) tmp%11#0 arc4.abimethod merkle/contract.py:35 - byte 0x00 // tmp%11#0,0x00 arc4.abimethod merkle/contract.py:35 - int 0 // tmp%11#0,0x00,0 - uncover 2 // load tmp%11#0 from l-stack (no copy) 0x00,0,tmp%11#0 arc4.abimethod merkle/contract.py:35 - setbit // {setbit} arc4.abimethod merkle/contract.py:35 - // virtual: store tmp%12#0 to l-stack (no copy) tmp%12#0 arc4.abimethod merkle/contract.py:35 - byte 0x151f7c75 // tmp%12#0,0x151f7c75 arc4.abimethod merkle/contract.py:35 - swap // load tmp%12#0 from l-stack (no copy) 0x151f7c75,tmp%12#0 arc4.abimethod merkle/contract.py:35 - concat // {concat} arc4.abimethod merkle/contract.py:35 - // virtual: store tmp%13#0 to l-stack (no copy) tmp%13#0 arc4.abimethod merkle/contract.py:35 - // virtual: load tmp%13#0 from l-stack (no copy) tmp%13#0 arc4.abimethod merkle/contract.py:35 - log // arc4.abimethod merkle/contract.py:35 - int 1 // 1 arc4.abimethod merkle/contract.py:35 - return // arc4.abimethod merkle/contract.py:35 + txn OnCompletion // {txn} arc4.abimethod merkle/contract.py:14 + // virtual: store tmp%6#0 to l-stack (no copy) tmp%6#0 arc4.abimethod merkle/contract.py:14 + // virtual: load tmp%6#0 from l-stack (no copy) tmp%6#0 arc4.abimethod merkle/contract.py:14 + ! // {!} arc4.abimethod merkle/contract.py:14 + // virtual: store tmp%7#0 to l-stack (no copy) tmp%7#0 arc4.abimethod merkle/contract.py:14 + // virtual: load tmp%7#0 from l-stack (no copy) tmp%7#0 arc4.abimethod merkle/contract.py:14 + assert // OnCompletion is NoOp // arc4.abimethod merkle/contract.py:14 + txn ApplicationID // {txn} arc4.abimethod merkle/contract.py:14 + // virtual: store tmp%8#0 to l-stack (no copy) tmp%8#0 arc4.abimethod merkle/contract.py:14 + // virtual: load tmp%8#0 from l-stack (no copy) tmp%8#0 arc4.abimethod merkle/contract.py:14 + assert // is not creating // arc4.abimethod merkle/contract.py:14 + txna ApplicationArgs 1 // {txna} class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + // virtual: store tmp%9#0 to l-stack (no copy) tmp%9#0 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + txna ApplicationArgs 2 // tmp%9#0,{txna} class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + // virtual: store tmp%10#0 to l-stack (no copy) tmp%9#0,tmp%10#0 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + // virtual: load tmp%9#0 from l-stack (no copy) tmp%10#0,tmp%9#0 arc4.abimethod merkle/contract.py:14 + // virtual: load tmp%10#0 from l-stack (no copy) tmp%9#0,tmp%10#0 arc4.abimethod merkle/contract.py:14 + callsub verify // {verify} arc4.abimethod merkle/contract.py:14 + // virtual: store tmp%11#0 to l-stack (no copy) tmp%11#0 arc4.abimethod merkle/contract.py:14 + byte 0x00 // tmp%11#0,0x00 arc4.abimethod merkle/contract.py:14 + int 0 // tmp%11#0,0x00,0 + uncover 2 // load tmp%11#0 from l-stack (no copy) 0x00,0,tmp%11#0 arc4.abimethod merkle/contract.py:14 + setbit // {setbit} arc4.abimethod merkle/contract.py:14 + // virtual: store tmp%12#0 to l-stack (no copy) tmp%12#0 arc4.abimethod merkle/contract.py:14 + byte 0x151f7c75 // tmp%12#0,0x151f7c75 arc4.abimethod merkle/contract.py:14 + swap // load tmp%12#0 from l-stack (no copy) 0x151f7c75,tmp%12#0 arc4.abimethod merkle/contract.py:14 + concat // {concat} arc4.abimethod merkle/contract.py:14 + // virtual: store tmp%13#0 to l-stack (no copy) tmp%13#0 arc4.abimethod merkle/contract.py:14 + // virtual: load tmp%13#0 from l-stack (no copy) tmp%13#0 arc4.abimethod merkle/contract.py:14 + log // arc4.abimethod merkle/contract.py:14 + int 1 // 1 arc4.abimethod merkle/contract.py:14 + return // arc4.abimethod merkle/contract.py:14 // examples.merkle.contract.MerkleTree.create(root: bytes) -> void: create: - proto 1 0 // (𝕡) root#0 | @arc4.abimethod(create=True)\ndef create(self, root: Bytes32) -> None: merkle/contract.py:31-32 + proto 1 0 // (𝕡) root#0 | @arc4.abimethod(create=True)\ndef create(self, root: Bytes32) -> None: merkle/contract.py:10-11 create_block@0: - byte "root" // (𝕡) root#0 | "root" self.root merkle/contract.py:33 - frame_dig -1 // load root#0 from parameters (𝕡) root#0 | "root",root#0 self.root = root.copy() merkle/contract.py:33 - app_global_put // (𝕡) root#0 | self.root = root.copy() merkle/contract.py:33 + byte "root" // (𝕡) root#0 | "root" self.root merkle/contract.py:12 + frame_dig -1 // load root#0 from parameters (𝕡) root#0 | "root",root#0 self.root = root.bytes merkle/contract.py:12 + app_global_put // (𝕡) root#0 | self.root = root.bytes merkle/contract.py:12 retsub // // examples.merkle.contract.MerkleTree.verify(proof: bytes, leaf: bytes) -> uint64: verify: - proto 2 1 // (𝕡) proof#0,leaf#0 | @arc4.abimethod\ndef verify(self, proof: Proof, leaf: Bytes32) -> bool: merkle/contract.py:35-36 + proto 2 1 // (𝕡) proof#0,leaf#0 | @arc4.abimethod\ndef verify(self, proof: Proof, leaf: Bytes32) -> bool: merkle/contract.py:14-15 verify_block@0: - int 0 // (𝕡) proof#0,leaf#0 | 0 self.root merkle/contract.py:37 - byte "root" // (𝕡) proof#0,leaf#0 | 0,"root" self.root merkle/contract.py:37 - app_global_get_ex // (𝕡) proof#0,leaf#0 | {app_global_get_ex}.0,{app_global_get_ex}.1 self.root merkle/contract.py:37 - // virtual: store root_exists%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | root_exists%0#0,{app_global_get_ex}.0 self.root merkle/contract.py:37 - // virtual: store root_value%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,root_exists%0#0 self.root merkle/contract.py:37 - // virtual: load root_exists%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,root_exists%0#0 self.root merkle/contract.py:37 - assert // check root exists // (𝕡) proof#0,leaf#0 | root_value%0#0 self.root merkle/contract.py:37 - frame_dig -2 // load proof#0 from parameters (𝕡) proof#0,leaf#0 | root_value%0#0,proof#0 self.compute_root_hash(proof, leaf) merkle/contract.py:37 - frame_dig -1 // load leaf#0 from parameters (𝕡) proof#0,leaf#0 | root_value%0#0,proof#0,leaf#0 self.compute_root_hash(proof, leaf) merkle/contract.py:37 - callsub compute_root_hash // (𝕡) proof#0,leaf#0 | root_value%0#0,{compute_root_hash}.0,{compute_root_hash}.1,{compute_root_hash}.2 self.compute_root_hash(proof, leaf) merkle/contract.py:37 - frame_bury -1 // store leaf#0 to parameters (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,{compute_root_hash}.0,{compute_root_hash}.1 self.compute_root_hash(proof, leaf) merkle/contract.py:37 - frame_bury -2 // store proof#0 to parameters (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,{compute_root_hash}.0 self.compute_root_hash(proof, leaf) merkle/contract.py:37 - // virtual: store compute_root_hash%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,compute_root_hash%0#0 self.compute_root_hash(proof, leaf) merkle/contract.py:37 - // virtual: load root_value%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | compute_root_hash%0#0,root_value%0#0 self.root == self.compute_root_hash(proof, leaf) merkle/contract.py:37 - // virtual: load compute_root_hash%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,compute_root_hash%0#0 self.root == self.compute_root_hash(proof, leaf) merkle/contract.py:37 - == // (𝕡) proof#0,leaf#0 | {==} self.root == self.compute_root_hash(proof, leaf) merkle/contract.py:37 - // virtual: store tmp%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | tmp%0#0 self.root == self.compute_root_hash(proof, leaf) merkle/contract.py:37 - // virtual: load tmp%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | tmp%0#0 return self.root == self.compute_root_hash(proof, leaf) merkle/contract.py:37 - retsub // tmp%0#0 return self.root == self.compute_root_hash(proof, leaf) merkle/contract.py:37 - - -// examples.merkle.contract.MerkleTree.compute_root_hash(proof: bytes, leaf: bytes) -> bytes, bytes, bytes: + int 0 // (𝕡) proof#0,leaf#0 | 0 self.root merkle/contract.py:16 + byte "root" // (𝕡) proof#0,leaf#0 | 0,"root" self.root merkle/contract.py:16 + app_global_get_ex // (𝕡) proof#0,leaf#0 | {app_global_get_ex}.0,{app_global_get_ex}.1 self.root merkle/contract.py:16 + // virtual: store root_exists%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | root_exists%0#0,{app_global_get_ex}.0 self.root merkle/contract.py:16 + // virtual: store root_value%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,root_exists%0#0 self.root merkle/contract.py:16 + // virtual: load root_exists%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,root_exists%0#0 self.root merkle/contract.py:16 + assert // check root exists // (𝕡) proof#0,leaf#0 | root_value%0#0 self.root merkle/contract.py:16 + frame_dig -2 // load proof#0 from parameters (𝕡) proof#0,leaf#0 | root_value%0#0,proof#0 compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + frame_dig -1 // load leaf#0 from parameters (𝕡) proof#0,leaf#0 | root_value%0#0,proof#0,leaf#0 compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + callsub compute_root_hash // (𝕡) proof#0,leaf#0 | root_value%0#0,{compute_root_hash}.0,{compute_root_hash}.1 compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + frame_bury -2 // store proof#0 to parameters (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,{compute_root_hash}.0 compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + // virtual: store compute_root_hash%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,compute_root_hash%0#0 compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + // virtual: load root_value%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | compute_root_hash%0#0,root_value%0#0 self.root == compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + // virtual: load compute_root_hash%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | root_value%0#0,compute_root_hash%0#0 self.root == compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + == // (𝕡) proof#0,leaf#0 | {==} self.root == compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + // virtual: store tmp%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | tmp%0#0 self.root == compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + // virtual: load tmp%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | tmp%0#0 return self.root == compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + retsub // tmp%0#0 return self.root == compute_root_hash(proof, leaf.bytes) merkle/contract.py:16 + + +// examples.merkle.contract.compute_root_hash(proof: bytes, leaf: bytes) -> bytes, bytes: compute_root_hash: - proto 2 3 // (𝕡) proof#0,leaf#0 | @subroutine\ndef compute_root_hash(self, proof: Proof, leaf: Bytes32) -> Bytes32: merkle/contract.py:24-25 + proto 2 2 // (𝕡) proof#0,leaf#0 | @subroutine\ndef compute_root_hash(proof: Proof, leaf: Bytes) -> Bytes: merkle/contract.py:19-20 + byte "" // allocate 1 to stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0 | compute_root_hash_block@0: - frame_dig -2 // load proof#0 from parameters (𝕡) proof#0,leaf#0 | proof#0 for proof_hash in proof: merkle/contract.py:27 - int 0 // (𝕡) proof#0,leaf#0 | proof#0,0 for proof_hash in proof: merkle/contract.py:27 - extract_uint16 // (𝕡) proof#0,leaf#0 | {extract_uint16} for proof_hash in proof: merkle/contract.py:27 - // virtual: store array_length%0#0 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0 | for proof_hash in proof: merkle/contract.py:27 - frame_dig -2 // load proof#0 from parameters (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0 | proof#0 for proof_hash in proof: merkle/contract.py:27 - extract 2 0 // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0 | {extract} for proof_hash in proof: merkle/contract.py:27 - // virtual: store array_value%0#0 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0 | for proof_hash in proof: merkle/contract.py:27 - int 0 // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0 | 0 - // virtual: store item_index_internal%0#0 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0 | - frame_dig -1 // load leaf#0 from parameters (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0 | leaf#0 - // virtual: store computed#1 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | - // Implicit fall through to compute_root_hash_for_header@1 // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | + frame_dig -2 // load proof#0 from parameters (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0 | proof#0 proof.length merkle/contract.py:22 + int 0 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0 | proof#0,0 proof.length merkle/contract.py:22 + extract_uint16 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0 | {extract_uint16} proof.length merkle/contract.py:22 + // virtual: store tmp%0#0 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0 | proof.length merkle/contract.py:22 + int 0 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0 | 0 urange(proof.length) merkle/contract.py:22 + // virtual: store range_item%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0 | range_item%0#0 idx merkle/contract.py:22 + frame_dig -1 // load leaf#0 from parameters (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0 | range_item%0#0,leaf#0 + swap // store computed#2 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2 | range_item%0#0 + // virtual: load range_item%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2 | range_item%0#0 + // virtual: store idx#0 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | + // Implicit fall through to compute_root_hash_for_header@1 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | compute_root_hash_for_header@1: - frame_dig 2 // load item_index_internal%0#0 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0 for proof_hash in proof: merkle/contract.py:27 - frame_dig 0 // load array_length%0#0 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,array_length%0#0 for proof_hash in proof: merkle/contract.py:27 - < // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | {<} for proof_hash in proof: merkle/contract.py:27 - // virtual: store continue_looping%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | continue_looping%0#0 for proof_hash in proof: merkle/contract.py:27 - // virtual: load continue_looping%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | continue_looping%0#0 for proof_hash in proof: merkle/contract.py:27 - bz compute_root_hash_after_for@4 // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | for proof_hash in proof: merkle/contract.py:27 - // Implicit fall through to compute_root_hash_for_body@2 // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | for proof_hash in proof: merkle/contract.py:27 + frame_dig 3 // load idx#0 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0 urange(proof.length) merkle/contract.py:22 + frame_dig 1 // load tmp%0#0 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,tmp%0#0 urange(proof.length) merkle/contract.py:22 + < // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | {<} urange(proof.length) merkle/contract.py:22 + dup // store continue_looping%0#0 to l-stack (copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | continue_looping%0#0,continue_looping%0#0 urange(proof.length) merkle/contract.py:22 + frame_bury 0 // store continue_looping%0#0 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | continue_looping%0#0 urange(proof.length) merkle/contract.py:22 + // virtual: load continue_looping%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | continue_looping%0#0 for idx in urange(proof.length): merkle/contract.py:22 + bz compute_root_hash_after_for@5 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | for idx in urange(proof.length): merkle/contract.py:22 + // Implicit fall through to compute_root_hash_for_body@2 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | for idx in urange(proof.length): merkle/contract.py:22 compute_root_hash_for_body@2: - frame_dig 2 // load item_index_internal%0#0 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0 for proof_hash in proof: merkle/contract.py:27 - dup // store item_index_internal%0#0 to l-stack (copy) (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,item_index_internal%0#0 for proof_hash in proof: merkle/contract.py:27 - int 32 // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,item_index_internal%0#0,32 for proof_hash in proof: merkle/contract.py:27 - * // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,{*} for proof_hash in proof: merkle/contract.py:27 - // virtual: store item_index%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,item_index%0#0 for proof_hash in proof: merkle/contract.py:27 - frame_dig 1 // load array_value%0#0 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,item_index%0#0,array_value%0#0 proof_hash merkle/contract.py:27 - swap // load item_index%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,array_value%0#0,item_index%0#0 proof_hash merkle/contract.py:27 - int 32 // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,array_value%0#0,item_index%0#0,32 for proof_hash in proof: merkle/contract.py:27 - extract3 // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,{extract3} for proof_hash in proof: merkle/contract.py:27 - // virtual: store proof_hash#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,proof_hash#0 proof_hash merkle/contract.py:27 - frame_dig 3 // load computed#1 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,proof_hash#0,computed#1 self.hash_pair(computed, proof_hash) merkle/contract.py:28 - swap // load proof_hash#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,computed#1,proof_hash#0 self.hash_pair(computed, proof_hash) merkle/contract.py:28 - callsub hash_pair // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,{hash_pair}.0,{hash_pair}.1,{hash_pair}.2 self.hash_pair(computed, proof_hash) merkle/contract.py:28 - pop // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,{hash_pair}.0,{hash_pair}.1 self.hash_pair(computed, proof_hash) merkle/contract.py:28 - pop // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,{hash_pair}.0 self.hash_pair(computed, proof_hash) merkle/contract.py:28 - frame_bury 3 // store computed#1 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0 self.hash_pair(computed, proof_hash) merkle/contract.py:28 - // virtual: load item_index_internal%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0 - int 1 // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | item_index_internal%0#0,1 - + // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | {+} - frame_bury 2 // store item_index_internal%0#0 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | - b compute_root_hash_for_header@1 // (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | - -compute_root_hash_after_for@4: - frame_dig 3 // load computed#1 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | computed#1 return computed merkle/contract.py:29 - frame_dig -2 // load proof#0 from parameters (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | computed#1,proof#0 return computed merkle/contract.py:29 - frame_dig -1 // load leaf#0 from parameters (𝕡) proof#0,leaf#0 | (𝕗) array_length%0#0,array_value%0#0,item_index_internal%0#0,computed#1 | computed#1,proof#0,leaf#0 return computed merkle/contract.py:29 - frame_bury 2 + frame_dig 0 // load continue_looping%0#0 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | continue_looping%0#0 proof[idx] merkle/contract.py:23 + assert // Index access is out of bounds // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | proof[idx] merkle/contract.py:23 + frame_dig -2 // load proof#0 from parameters (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | proof#0 proof[idx] merkle/contract.py:23 + extract 2 0 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | {extract} proof[idx] merkle/contract.py:23 + // virtual: store array_data_sans_header%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | array_data_sans_header%0#0 proof[idx] merkle/contract.py:23 + frame_dig 3 // load idx#0 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | array_data_sans_header%0#0,idx#0 proof[idx] merkle/contract.py:23 + dup + cover 2 // store idx#0 to l-stack (copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,array_data_sans_header%0#0,idx#0 proof[idx] merkle/contract.py:23 + int 32 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,array_data_sans_header%0#0,idx#0,32 proof[idx] merkle/contract.py:23 + * // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,array_data_sans_header%0#0,{*} proof[idx] merkle/contract.py:23 + // virtual: store item_index%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,array_data_sans_header%0#0,item_index%0#0 proof[idx] merkle/contract.py:23 + // virtual: load array_data_sans_header%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,item_index%0#0,array_data_sans_header%0#0 proof[idx] merkle/contract.py:23 + // virtual: load item_index%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,array_data_sans_header%0#0,item_index%0#0 proof[idx] merkle/contract.py:23 + int 32 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,array_data_sans_header%0#0,item_index%0#0,32 proof[idx] merkle/contract.py:23 + extract3 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,{extract3} proof[idx] merkle/contract.py:23 + // virtual: store tmp%1#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,tmp%1#0 proof[idx] merkle/contract.py:23 + frame_dig 2 // load computed#2 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,tmp%1#0,computed#2 computed = hash_pair(computed, proof[idx].bytes) merkle/contract.py:23 + swap // load tmp%1#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,computed#2,tmp%1#0 computed = hash_pair(computed, proof[idx].bytes) merkle/contract.py:23 + callsub hash_pair // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,{hash_pair} hash_pair(computed, proof[idx].bytes) merkle/contract.py:23 + frame_bury 2 // store computed#2 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0 computed = hash_pair(computed, proof[idx].bytes) merkle/contract.py:23 + // virtual: load idx#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0 for idx in urange(proof.length): merkle/contract.py:22 + int 1 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | idx#0,1 urange(proof.length) merkle/contract.py:22 + + // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | {+} urange(proof.length) merkle/contract.py:22 + // virtual: store range_item%0#0 to l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | range_item%0#0 for idx in urange(proof.length): merkle/contract.py:22 + // virtual: load range_item%0#0 from l-stack (no copy) (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | range_item%0#0 + frame_bury 3 // store idx#0 to f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | + b compute_root_hash_for_header@1 // (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | + +compute_root_hash_after_for@5: + frame_dig 2 // load computed#2 from f-stack (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | computed#2 return computed merkle/contract.py:24 + frame_dig -2 // load proof#0 from parameters (𝕡) proof#0,leaf#0 | (𝕗) continue_looping%0#0,tmp%0#0,computed#2,idx#0 | computed#2,proof#0 return computed merkle/contract.py:24 frame_bury 1 frame_bury 0 - retsub // computed#1,proof#0,leaf#0 return computed merkle/contract.py:29 + retsub // computed#2,proof#0 return computed merkle/contract.py:24 -// examples.merkle.contract.MerkleTree.hash_pair(a: bytes, b: bytes) -> bytes, bytes, bytes: +// examples.merkle.contract.hash_pair(a: bytes, b: bytes) -> bytes: hash_pair: - proto 2 3 // (𝕡) a#0,b#0 | @subroutine\ndef hash_pair(self, a: Bytes32, b: Bytes32) -> Bytes32: merkle/contract.py:15-16 + proto 2 1 // (𝕡) a#0,b#0 | @subroutine\ndef hash_pair(a: Bytes, b: Bytes) -> Bytes: merkle/contract.py:27-28 hash_pair_block@0: - frame_dig -2 // load a#0 from parameters (𝕡) a#0,b#0 | a#0 BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) merkle/contract.py:19 - frame_dig -1 // load b#0 from parameters (𝕡) a#0,b#0 | a#0,b#0 BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) merkle/contract.py:19 - b< // (𝕡) a#0,b#0 | {b<} BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) merkle/contract.py:19 - // virtual: store tmp%0#0 to l-stack (no copy) (𝕡) a#0,b#0 | tmp%0#0 BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) merkle/contract.py:19 - // virtual: load tmp%0#0 from l-stack (no copy) (𝕡) a#0,b#0 | tmp%0#0 a.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes)\nelse b.bytes + a... merkle/contract.py:18-20 - bz hash_pair_ternary_false@2 // (𝕡) a#0,b#0 | a.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes)\nelse b.bytes + a... merkle/contract.py:18-20 - // Implicit fall through to hash_pair_ternary_true@1 // (𝕡) a#0,b#0 | a.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes)\nelse b.bytes + a... merkle/contract.py:18-20 + frame_dig -2 // load a#0 from parameters (𝕡) a#0,b#0 | a#0 BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) merkle/contract.py:29 + frame_dig -1 // load b#0 from parameters (𝕡) a#0,b#0 | a#0,b#0 BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) merkle/contract.py:29 + b< // (𝕡) a#0,b#0 | {b<} BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) merkle/contract.py:29 + // virtual: store tmp%0#0 to l-stack (no copy) (𝕡) a#0,b#0 | tmp%0#0 BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) merkle/contract.py:29 + // virtual: load tmp%0#0 from l-stack (no copy) (𝕡) a#0,b#0 | tmp%0#0 a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a merkle/contract.py:29 + bz hash_pair_ternary_false@2 // (𝕡) a#0,b#0 | a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a merkle/contract.py:29 + // Implicit fall through to hash_pair_ternary_true@1 // (𝕡) a#0,b#0 | a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a merkle/contract.py:29 hash_pair_ternary_true@1: - frame_dig -2 // load a#0 from parameters (𝕡) a#0,b#0 | a#0 a.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes)\nelse b.bytes + a... merkle/contract.py:18-20 - frame_dig -1 // load b#0 from parameters (𝕡) a#0,b#0 | a#0,b#0 a.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes)\nelse b.bytes + a... merkle/contract.py:18-20 - concat // (𝕡) a#0,b#0 | {concat} a.bytes + b.bytes merkle/contract.py:18 - // virtual: store ternary_result%0#0 to x-stack (no copy) (𝕡) a#0,b#0 | (𝕏) ternary_result%0#0 | a.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes)\nelse b.bytes + a... merkle/contract.py:18-20 - b hash_pair_ternary_merge@3 // (𝕡) a#0,b#0 | (𝕏) ternary_result%0#0 | ternary_result%0#0 + frame_dig -2 // load a#0 from parameters (𝕡) a#0,b#0 | a#0 a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a merkle/contract.py:29 + frame_dig -1 // load b#0 from parameters (𝕡) a#0,b#0 | a#0,b#0 a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a merkle/contract.py:29 + concat // (𝕡) a#0,b#0 | {concat} a + b merkle/contract.py:29 + // virtual: store ternary_result%0#0 to x-stack (no copy) (𝕡) a#0,b#0 | (𝕏) ternary_result%0#0 | a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a merkle/contract.py:29 + b hash_pair_ternary_merge@3 // (𝕡) a#0,b#0 | (𝕏) ternary_result%0#0 | ternary_result%0#0 hash_pair_ternary_false@2: - frame_dig -1 // load b#0 from parameters (𝕡) a#0,b#0 | b#0 a.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes)\nelse b.bytes + a... merkle/contract.py:18-20 - frame_dig -2 // load a#0 from parameters (𝕡) a#0,b#0 | b#0,a#0 a.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes)\nelse b.bytes + a... merkle/contract.py:18-20 - concat // (𝕡) a#0,b#0 | {concat} b.bytes + a.bytes merkle/contract.py:20 - // virtual: store ternary_result%0#0 to x-stack (no copy) (𝕡) a#0,b#0 | (𝕏) ternary_result%0#0 | a.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes)\nelse b.bytes + a... merkle/contract.py:18-20 - // Implicit fall through to hash_pair_ternary_merge@3 // (𝕡) a#0,b#0 | (𝕏) ternary_result%0#0 | ternary_result%0#0 + frame_dig -1 // load b#0 from parameters (𝕡) a#0,b#0 | b#0 a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a merkle/contract.py:29 + frame_dig -2 // load a#0 from parameters (𝕡) a#0,b#0 | b#0,a#0 a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a merkle/contract.py:29 + concat // (𝕡) a#0,b#0 | {concat} b + a merkle/contract.py:29 + // virtual: store ternary_result%0#0 to x-stack (no copy) (𝕡) a#0,b#0 | (𝕏) ternary_result%0#0 | a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a merkle/contract.py:29 + // Implicit fall through to hash_pair_ternary_merge@3 // (𝕡) a#0,b#0 | (𝕏) ternary_result%0#0 | ternary_result%0#0 hash_pair_ternary_merge@3: - // virtual: load ternary_result%0#0 from x-stack (𝕡) a#0,b#0 | ternary_result%0#0 ternary_result%0#0 hash_bytes = op.sha256(\na.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b... merkle/contract.py:17-21 - sha256 // (𝕡) a#0,b#0 | {sha256} op.sha256(\na.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes)\nelse... merkle/contract.py:17-21 - // virtual: store hash_bytes#0 to l-stack (no copy) (𝕡) a#0,b#0 | hash_bytes#0 hash_bytes = op.sha256(\na.bytes + b.bytes\nif BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b... merkle/contract.py:17-21 - // virtual: load hash_bytes#0 from l-stack (no copy) (𝕡) a#0,b#0 | hash_bytes#0 return Bytes32.from_bytes(hash_bytes) merkle/contract.py:22 - frame_dig -2 // load a#0 from parameters (𝕡) a#0,b#0 | hash_bytes#0,a#0 return Bytes32.from_bytes(hash_bytes) merkle/contract.py:22 - frame_dig -1 // load b#0 from parameters (𝕡) a#0,b#0 | hash_bytes#0,a#0,b#0 return Bytes32.from_bytes(hash_bytes) merkle/contract.py:22 - retsub // hash_bytes#0,a#0,b#0 return Bytes32.from_bytes(hash_bytes) merkle/contract.py:22 + // virtual: load ternary_result%0#0 from x-stack (𝕡) a#0,b#0 | ternary_result%0#0 ternary_result%0#0 op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) merkle/contract.py:29 + sha256 // (𝕡) a#0,b#0 | {sha256} op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) merkle/contract.py:29 + // virtual: store tmp%1#0 to l-stack (no copy) (𝕡) a#0,b#0 | tmp%1#0 op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) merkle/contract.py:29 + // virtual: load tmp%1#0 from l-stack (no copy) (𝕡) a#0,b#0 | tmp%1#0 return op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) merkle/contract.py:29 + retsub // tmp%1#0 return op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) merkle/contract.py:29 diff --git a/examples/merkle/out/MerkleTree.approval.teal b/examples/merkle/out/MerkleTree.approval.teal index c7d3027ab4..2a68f03572 100644 --- a/examples/merkle/out/MerkleTree.approval.teal +++ b/examples/merkle/out/MerkleTree.approval.teal @@ -1,7 +1,7 @@ #pragma version 10 examples.merkle.contract.MerkleTree.approval_program: - // merkle/contract.py:14 + // merkle/contract.py:9 // class MerkleTree(arc4.ARC4Contract): method "create(byte[32])void" method "verify(byte[32][],byte[32])bool" @@ -10,7 +10,7 @@ examples.merkle.contract.MerkleTree.approval_program: err // reject transaction main_create_route@1: - // merkle/contract.py:31 + // merkle/contract.py:10 // @arc4.abimethod(create=True) txn OnCompletion ! @@ -18,28 +18,28 @@ main_create_route@1: txn ApplicationID ! assert // is creating - // merkle/contract.py:14 + // merkle/contract.py:9 // class MerkleTree(arc4.ARC4Contract): txna ApplicationArgs 1 - // merkle/contract.py:31 + // merkle/contract.py:10 // @arc4.abimethod(create=True) callsub create int 1 return main_verify_route@2: - // merkle/contract.py:35 + // merkle/contract.py:14 // @arc4.abimethod txn OnCompletion ! assert // OnCompletion is NoOp txn ApplicationID assert // is not creating - // merkle/contract.py:14 + // merkle/contract.py:9 // class MerkleTree(arc4.ARC4Contract): txna ApplicationArgs 1 txna ApplicationArgs 2 - // merkle/contract.py:35 + // merkle/contract.py:14 // @arc4.abimethod callsub verify byte 0x00 @@ -56,12 +56,12 @@ main_verify_route@2: // examples.merkle.contract.MerkleTree.create(root: bytes) -> void: create: - // merkle/contract.py:31-32 + // merkle/contract.py:10-11 // @arc4.abimethod(create=True) // def create(self, root: Bytes32) -> None: proto 1 0 - // merkle/contract.py:33 - // self.root = root.copy() + // merkle/contract.py:12 + // self.root = root.bytes byte "root" frame_dig -1 app_global_put @@ -70,12 +70,12 @@ create: // examples.merkle.contract.MerkleTree.verify(proof: bytes, leaf: bytes) -> uint64: verify: - // merkle/contract.py:35-36 + // merkle/contract.py:14-15 // @arc4.abimethod // def verify(self, proof: Proof, leaf: Bytes32) -> bool: proto 2 1 - // merkle/contract.py:37 - // return self.root == self.compute_root_hash(proof, leaf) + // merkle/contract.py:16 + // return self.root == compute_root_hash(proof, leaf.bytes) int 0 byte "root" app_global_get_ex @@ -83,111 +83,95 @@ verify: frame_dig -2 frame_dig -1 callsub compute_root_hash - frame_bury -1 frame_bury -2 == retsub -// examples.merkle.contract.MerkleTree.compute_root_hash(proof: bytes, leaf: bytes) -> bytes, bytes, bytes: +// examples.merkle.contract.compute_root_hash(proof: bytes, leaf: bytes) -> bytes, bytes: compute_root_hash: - // merkle/contract.py:24-25 + // merkle/contract.py:19-20 // @subroutine - // def compute_root_hash(self, proof: Proof, leaf: Bytes32) -> Bytes32: - proto 2 3 - // merkle/contract.py:27 - // for proof_hash in proof: + // def compute_root_hash(proof: Proof, leaf: Bytes) -> Bytes: + proto 2 2 + byte "" + // merkle/contract.py:22 + // for idx in urange(proof.length): frame_dig -2 int 0 extract_uint16 - frame_dig -2 - extract 2 0 - int 0 frame_dig -1 + int 0 compute_root_hash_for_header@1: - // merkle/contract.py:27 - // for proof_hash in proof: - frame_dig 2 - frame_dig 0 + // merkle/contract.py:22 + // for idx in urange(proof.length): + frame_dig 3 + frame_dig 1 < - bz compute_root_hash_after_for@4 - frame_dig 2 dup + frame_bury 0 + bz compute_root_hash_after_for@5 + // merkle/contract.py:23 + // computed = hash_pair(computed, proof[idx].bytes) + frame_dig 0 + assert // Index access is out of bounds + frame_dig -2 + extract 2 0 + frame_dig 3 + dup + cover 2 int 32 * - frame_dig 1 - swap int 32 extract3 - // merkle/contract.py:28 - // computed = self.hash_pair(computed, proof_hash) - frame_dig 3 + frame_dig 2 swap callsub hash_pair - popn 2 - frame_bury 3 + frame_bury 2 + // merkle/contract.py:22 + // for idx in urange(proof.length): int 1 + - frame_bury 2 + frame_bury 3 b compute_root_hash_for_header@1 -compute_root_hash_after_for@4: - // merkle/contract.py:29 +compute_root_hash_after_for@5: + // merkle/contract.py:24 // return computed - frame_dig 3 + frame_dig 2 frame_dig -2 - frame_dig -1 - frame_bury 2 frame_bury 1 frame_bury 0 retsub -// examples.merkle.contract.MerkleTree.hash_pair(a: bytes, b: bytes) -> bytes, bytes, bytes: +// examples.merkle.contract.hash_pair(a: bytes, b: bytes) -> bytes: hash_pair: - // merkle/contract.py:15-16 + // merkle/contract.py:27-28 // @subroutine - // def hash_pair(self, a: Bytes32, b: Bytes32) -> Bytes32: - proto 2 3 - // merkle/contract.py:19 - // if BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) + // def hash_pair(a: Bytes, b: Bytes) -> Bytes: + proto 2 1 + // merkle/contract.py:29 + // return op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) frame_dig -2 frame_dig -1 b< - // merkle/contract.py:18-20 - // a.bytes + b.bytes - // if BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) - // else b.bytes + a.bytes bz hash_pair_ternary_false@2 frame_dig -2 frame_dig -1 - // merkle/contract.py:18 - // a.bytes + b.bytes concat b hash_pair_ternary_merge@3 hash_pair_ternary_false@2: - // merkle/contract.py:18-20 - // a.bytes + b.bytes - // if BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) - // else b.bytes + a.bytes + // merkle/contract.py:29 + // return op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) frame_dig -1 frame_dig -2 - // merkle/contract.py:20 - // else b.bytes + a.bytes concat hash_pair_ternary_merge@3: - // merkle/contract.py:17-21 - // hash_bytes = op.sha256( - // a.bytes + b.bytes - // if BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) - // else b.bytes + a.bytes - // ) + // merkle/contract.py:29 + // return op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) sha256 - // merkle/contract.py:22 - // return Bytes32.from_bytes(hash_bytes) - frame_dig -2 - frame_dig -1 retsub diff --git a/examples/merkle/out/MerkleTree.arc32.json b/examples/merkle/out/MerkleTree.arc32.json index b5fc90dd4c..36460793b8 100644 --- a/examples/merkle/out/MerkleTree.arc32.json +++ b/examples/merkle/out/MerkleTree.arc32.json @@ -12,8 +12,8 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5hcHByb3ZhbF9wcm9ncmFtOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE0CiAgICAvLyBjbGFzcyBNZXJrbGVUcmVlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIG1ldGhvZCAiY3JlYXRlKGJ5dGVbMzJdKXZvaWQiCiAgICBtZXRob2QgInZlcmlmeShieXRlWzMyXVtdLGJ5dGVbMzJdKWJvb2wiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBtYWluX2NyZWF0ZV9yb3V0ZUAxIG1haW5fdmVyaWZ5X3JvdXRlQDIKICAgIGVyciAvLyByZWplY3QgdHJhbnNhY3Rpb24KCm1haW5fY3JlYXRlX3JvdXRlQDE6CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MzEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChjcmVhdGU9VHJ1ZSkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgICEKICAgIGFzc2VydCAvLyBpcyBjcmVhdGluZwogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE0CiAgICAvLyBjbGFzcyBNZXJrbGVUcmVlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weTozMQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGNyZWF0ZT1UcnVlKQogICAgY2FsbHN1YiBjcmVhdGUKICAgIGludCAxCiAgICByZXR1cm4KCm1haW5fdmVyaWZ5X3JvdXRlQDI6CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MzUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGlzIG5vdCBjcmVhdGluZwogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE0CiAgICAvLyBjbGFzcyBNZXJrbGVUcmVlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDIKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weTozNQogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICBjYWxsc3ViIHZlcmlmeQogICAgYnl0ZSAweDAwCiAgICBpbnQgMAogICAgdW5jb3ZlciAyCiAgICBzZXRiaXQKICAgIGJ5dGUgMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludCAxCiAgICByZXR1cm4KCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5jcmVhdGUocm9vdDogYnl0ZXMpIC0+IHZvaWQ6CmNyZWF0ZToKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weTozMS0zMgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGNyZWF0ZT1UcnVlKQogICAgLy8gZGVmIGNyZWF0ZShzZWxmLCByb290OiBCeXRlczMyKSAtPiBOb25lOgogICAgcHJvdG8gMSAwCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MzMKICAgIC8vIHNlbGYucm9vdCA9IHJvb3QuY29weSgpCiAgICBieXRlICJyb290IgogICAgZnJhbWVfZGlnIC0xCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgcmV0c3ViCgoKLy8gZXhhbXBsZXMubWVya2xlLmNvbnRyYWN0Lk1lcmtsZVRyZWUudmVyaWZ5KHByb29mOiBieXRlcywgbGVhZjogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5OgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjM1LTM2CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIC8vIGRlZiB2ZXJpZnkoc2VsZiwgcHJvb2Y6IFByb29mLCBsZWFmOiBCeXRlczMyKSAtPiBib29sOgogICAgcHJvdG8gMiAxCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MzcKICAgIC8vIHJldHVybiBzZWxmLnJvb3QgPT0gc2VsZi5jb21wdXRlX3Jvb3RfaGFzaChwcm9vZiwgbGVhZikKICAgIGludCAwCiAgICBieXRlICJyb290IgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayByb290IGV4aXN0cwogICAgZnJhbWVfZGlnIC0yCiAgICBmcmFtZV9kaWcgLTEKICAgIGNhbGxzdWIgY29tcHV0ZV9yb290X2hhc2gKICAgIGZyYW1lX2J1cnkgLTEKICAgIGZyYW1lX2J1cnkgLTIKICAgID09CiAgICByZXRzdWIKCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5jb21wdXRlX3Jvb3RfaGFzaChwcm9vZjogYnl0ZXMsIGxlYWY6IGJ5dGVzKSAtPiBieXRlcywgYnl0ZXMsIGJ5dGVzOgpjb21wdXRlX3Jvb3RfaGFzaDoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyNC0yNQogICAgLy8gQHN1YnJvdXRpbmUKICAgIC8vIGRlZiBjb21wdXRlX3Jvb3RfaGFzaChzZWxmLCBwcm9vZjogUHJvb2YsIGxlYWY6IEJ5dGVzMzIpIC0+IEJ5dGVzMzI6CiAgICBwcm90byAyIDMKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyNwogICAgLy8gZm9yIHByb29mX2hhc2ggaW4gcHJvb2Y6CiAgICBmcmFtZV9kaWcgLTIKICAgIGludCAwCiAgICBleHRyYWN0X3VpbnQxNgogICAgZnJhbWVfZGlnIC0yCiAgICBleHRyYWN0IDIgMAogICAgaW50IDAKICAgIGZyYW1lX2RpZyAtMQoKY29tcHV0ZV9yb290X2hhc2hfZm9yX2hlYWRlckAxOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjI3CiAgICAvLyBmb3IgcHJvb2ZfaGFzaCBpbiBwcm9vZjoKICAgIGZyYW1lX2RpZyAyCiAgICBmcmFtZV9kaWcgMAogICAgPAogICAgYnogY29tcHV0ZV9yb290X2hhc2hfYWZ0ZXJfZm9yQDQKICAgIGZyYW1lX2RpZyAyCiAgICBkdXAKICAgIGludCAzMgogICAgKgogICAgZnJhbWVfZGlnIDEKICAgIHN3YXAKICAgIGludCAzMgogICAgZXh0cmFjdDMKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyOAogICAgLy8gY29tcHV0ZWQgPSBzZWxmLmhhc2hfcGFpcihjb21wdXRlZCwgcHJvb2ZfaGFzaCkKICAgIGZyYW1lX2RpZyAzCiAgICBzd2FwCiAgICBjYWxsc3ViIGhhc2hfcGFpcgogICAgcG9wbiAyCiAgICBmcmFtZV9idXJ5IDMKICAgIGludCAxCiAgICArCiAgICBmcmFtZV9idXJ5IDIKICAgIGIgY29tcHV0ZV9yb290X2hhc2hfZm9yX2hlYWRlckAxCgpjb21wdXRlX3Jvb3RfaGFzaF9hZnRlcl9mb3JANDoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyOQogICAgLy8gcmV0dXJuIGNvbXB1dGVkCiAgICBmcmFtZV9kaWcgMwogICAgZnJhbWVfZGlnIC0yCiAgICBmcmFtZV9kaWcgLTEKICAgIGZyYW1lX2J1cnkgMgogICAgZnJhbWVfYnVyeSAxCiAgICBmcmFtZV9idXJ5IDAKICAgIHJldHN1YgoKCi8vIGV4YW1wbGVzLm1lcmtsZS5jb250cmFjdC5NZXJrbGVUcmVlLmhhc2hfcGFpcihhOiBieXRlcywgYjogYnl0ZXMpIC0+IGJ5dGVzLCBieXRlcywgYnl0ZXM6Cmhhc2hfcGFpcjoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxNS0xNgogICAgLy8gQHN1YnJvdXRpbmUKICAgIC8vIGRlZiBoYXNoX3BhaXIoc2VsZiwgYTogQnl0ZXMzMiwgYjogQnl0ZXMzMikgLT4gQnl0ZXMzMjoKICAgIHByb3RvIDIgMwogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE5CiAgICAvLyBpZiBCaWdVSW50LmZyb21fYnl0ZXMoYS5ieXRlcykgPCBCaWdVSW50LmZyb21fYnl0ZXMoYi5ieXRlcykKICAgIGZyYW1lX2RpZyAtMgogICAgZnJhbWVfZGlnIC0xCiAgICBiPAogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE4LTIwCiAgICAvLyBhLmJ5dGVzICsgYi5ieXRlcwogICAgLy8gaWYgQmlnVUludC5mcm9tX2J5dGVzKGEuYnl0ZXMpIDwgQmlnVUludC5mcm9tX2J5dGVzKGIuYnl0ZXMpCiAgICAvLyBlbHNlIGIuYnl0ZXMgKyBhLmJ5dGVzCiAgICBieiBoYXNoX3BhaXJfdGVybmFyeV9mYWxzZUAyCiAgICBmcmFtZV9kaWcgLTIKICAgIGZyYW1lX2RpZyAtMQogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE4CiAgICAvLyBhLmJ5dGVzICsgYi5ieXRlcwogICAgY29uY2F0CiAgICBiIGhhc2hfcGFpcl90ZXJuYXJ5X21lcmdlQDMKCmhhc2hfcGFpcl90ZXJuYXJ5X2ZhbHNlQDI6CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MTgtMjAKICAgIC8vIGEuYnl0ZXMgKyBiLmJ5dGVzCiAgICAvLyBpZiBCaWdVSW50LmZyb21fYnl0ZXMoYS5ieXRlcykgPCBCaWdVSW50LmZyb21fYnl0ZXMoYi5ieXRlcykKICAgIC8vIGVsc2UgYi5ieXRlcyArIGEuYnl0ZXMKICAgIGZyYW1lX2RpZyAtMQogICAgZnJhbWVfZGlnIC0yCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MjAKICAgIC8vIGVsc2UgYi5ieXRlcyArIGEuYnl0ZXMKICAgIGNvbmNhdAoKaGFzaF9wYWlyX3Rlcm5hcnlfbWVyZ2VAMzoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxNy0yMQogICAgLy8gaGFzaF9ieXRlcyA9IG9wLnNoYTI1NigKICAgIC8vICAgICBhLmJ5dGVzICsgYi5ieXRlcwogICAgLy8gICAgIGlmIEJpZ1VJbnQuZnJvbV9ieXRlcyhhLmJ5dGVzKSA8IEJpZ1VJbnQuZnJvbV9ieXRlcyhiLmJ5dGVzKQogICAgLy8gICAgIGVsc2UgYi5ieXRlcyArIGEuYnl0ZXMKICAgIC8vICkKICAgIHNoYTI1NgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjIyCiAgICAvLyByZXR1cm4gQnl0ZXMzMi5mcm9tX2J5dGVzKGhhc2hfYnl0ZXMpCiAgICBmcmFtZV9kaWcgLTIKICAgIGZyYW1lX2RpZyAtMQogICAgcmV0c3ViCg==", - "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5jbGVhcl9zdGF0ZV9wcm9ncmFtOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE0CiAgICAvLyBjbGFzcyBNZXJrbGVUcmVlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIGludCAxCiAgICByZXR1cm4K" + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5hcHByb3ZhbF9wcm9ncmFtOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjkKICAgIC8vIGNsYXNzIE1lcmtsZVRyZWUoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgbWV0aG9kICJjcmVhdGUoYnl0ZVszMl0pdm9pZCIKICAgIG1ldGhvZCAidmVyaWZ5KGJ5dGVbMzJdW10sYnl0ZVszMl0pYm9vbCIKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDAKICAgIG1hdGNoIG1haW5fY3JlYXRlX3JvdXRlQDEgbWFpbl92ZXJpZnlfcm91dGVAMgogICAgZXJyIC8vIHJlamVjdCB0cmFuc2FjdGlvbgoKbWFpbl9jcmVhdGVfcm91dGVAMToKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxMAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGNyZWF0ZT1UcnVlKQogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgIQogICAgYXNzZXJ0IC8vIGlzIGNyZWF0aW5nCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6OQogICAgLy8gY2xhc3MgTWVya2xlVHJlZShhcmM0LkFSQzRDb250cmFjdCk6CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MTAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChjcmVhdGU9VHJ1ZSkKICAgIGNhbGxzdWIgY3JlYXRlCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9yb3V0ZUAyOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE0CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBpcyBub3QgY3JlYXRpbmcKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weTo5CiAgICAvLyBjbGFzcyBNZXJrbGVUcmVlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDIKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICBjYWxsc3ViIHZlcmlmeQogICAgYnl0ZSAweDAwCiAgICBpbnQgMAogICAgdW5jb3ZlciAyCiAgICBzZXRiaXQKICAgIGJ5dGUgMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludCAxCiAgICByZXR1cm4KCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5jcmVhdGUocm9vdDogYnl0ZXMpIC0+IHZvaWQ6CmNyZWF0ZToKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxMC0xMQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGNyZWF0ZT1UcnVlKQogICAgLy8gZGVmIGNyZWF0ZShzZWxmLCByb290OiBCeXRlczMyKSAtPiBOb25lOgogICAgcHJvdG8gMSAwCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MTIKICAgIC8vIHNlbGYucm9vdCA9IHJvb3QuYnl0ZXMKICAgIGJ5dGUgInJvb3QiCiAgICBmcmFtZV9kaWcgLTEKICAgIGFwcF9nbG9iYWxfcHV0CiAgICByZXRzdWIKCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS52ZXJpZnkocHJvb2Y6IGJ5dGVzLCBsZWFmOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnk6CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MTQtMTUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgLy8gZGVmIHZlcmlmeShzZWxmLCBwcm9vZjogUHJvb2YsIGxlYWY6IEJ5dGVzMzIpIC0+IGJvb2w6CiAgICBwcm90byAyIDEKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxNgogICAgLy8gcmV0dXJuIHNlbGYucm9vdCA9PSBjb21wdXRlX3Jvb3RfaGFzaChwcm9vZiwgbGVhZi5ieXRlcykKICAgIGludCAwCiAgICBieXRlICJyb290IgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayByb290IGV4aXN0cwogICAgZnJhbWVfZGlnIC0yCiAgICBmcmFtZV9kaWcgLTEKICAgIGNhbGxzdWIgY29tcHV0ZV9yb290X2hhc2gKICAgIGZyYW1lX2J1cnkgLTIKICAgID09CiAgICByZXRzdWIKCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuY29tcHV0ZV9yb290X2hhc2gocHJvb2Y6IGJ5dGVzLCBsZWFmOiBieXRlcykgLT4gYnl0ZXMsIGJ5dGVzOgpjb21wdXRlX3Jvb3RfaGFzaDoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxOS0yMAogICAgLy8gQHN1YnJvdXRpbmUKICAgIC8vIGRlZiBjb21wdXRlX3Jvb3RfaGFzaChwcm9vZjogUHJvb2YsIGxlYWY6IEJ5dGVzKSAtPiBCeXRlczoKICAgIHByb3RvIDIgMgogICAgYnl0ZSAiIgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjIyCiAgICAvLyBmb3IgaWR4IGluIHVyYW5nZShwcm9vZi5sZW5ndGgpOgogICAgZnJhbWVfZGlnIC0yCiAgICBpbnQgMAogICAgZXh0cmFjdF91aW50MTYKICAgIGZyYW1lX2RpZyAtMQogICAgaW50IDAKCmNvbXB1dGVfcm9vdF9oYXNoX2Zvcl9oZWFkZXJAMToKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyMgogICAgLy8gZm9yIGlkeCBpbiB1cmFuZ2UocHJvb2YubGVuZ3RoKToKICAgIGZyYW1lX2RpZyAzCiAgICBmcmFtZV9kaWcgMQogICAgPAogICAgZHVwCiAgICBmcmFtZV9idXJ5IDAKICAgIGJ6IGNvbXB1dGVfcm9vdF9oYXNoX2FmdGVyX2ZvckA1CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MjMKICAgIC8vIGNvbXB1dGVkID0gaGFzaF9wYWlyKGNvbXB1dGVkLCBwcm9vZltpZHhdLmJ5dGVzKQogICAgZnJhbWVfZGlnIDAKICAgIGFzc2VydCAvLyBJbmRleCBhY2Nlc3MgaXMgb3V0IG9mIGJvdW5kcwogICAgZnJhbWVfZGlnIC0yCiAgICBleHRyYWN0IDIgMAogICAgZnJhbWVfZGlnIDMKICAgIGR1cAogICAgY292ZXIgMgogICAgaW50IDMyCiAgICAqCiAgICBpbnQgMzIKICAgIGV4dHJhY3QzCiAgICBmcmFtZV9kaWcgMgogICAgc3dhcAogICAgY2FsbHN1YiBoYXNoX3BhaXIKICAgIGZyYW1lX2J1cnkgMgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjIyCiAgICAvLyBmb3IgaWR4IGluIHVyYW5nZShwcm9vZi5sZW5ndGgpOgogICAgaW50IDEKICAgICsKICAgIGZyYW1lX2J1cnkgMwogICAgYiBjb21wdXRlX3Jvb3RfaGFzaF9mb3JfaGVhZGVyQDEKCmNvbXB1dGVfcm9vdF9oYXNoX2FmdGVyX2ZvckA1OgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjI0CiAgICAvLyByZXR1cm4gY29tcHV0ZWQKICAgIGZyYW1lX2RpZyAyCiAgICBmcmFtZV9kaWcgLTIKICAgIGZyYW1lX2J1cnkgMQogICAgZnJhbWVfYnVyeSAwCiAgICByZXRzdWIKCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuaGFzaF9wYWlyKGE6IGJ5dGVzLCBiOiBieXRlcykgLT4gYnl0ZXM6Cmhhc2hfcGFpcjoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyNy0yOAogICAgLy8gQHN1YnJvdXRpbmUKICAgIC8vIGRlZiBoYXNoX3BhaXIoYTogQnl0ZXMsIGI6IEJ5dGVzKSAtPiBCeXRlczoKICAgIHByb3RvIDIgMQogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjI5CiAgICAvLyByZXR1cm4gb3Auc2hhMjU2KGEgKyBiIGlmIEJpZ1VJbnQuZnJvbV9ieXRlcyhhKSA8IEJpZ1VJbnQuZnJvbV9ieXRlcyhiKSBlbHNlIGIgKyBhKQogICAgZnJhbWVfZGlnIC0yCiAgICBmcmFtZV9kaWcgLTEKICAgIGI8CiAgICBieiBoYXNoX3BhaXJfdGVybmFyeV9mYWxzZUAyCiAgICBmcmFtZV9kaWcgLTIKICAgIGZyYW1lX2RpZyAtMQogICAgY29uY2F0CiAgICBiIGhhc2hfcGFpcl90ZXJuYXJ5X21lcmdlQDMKCmhhc2hfcGFpcl90ZXJuYXJ5X2ZhbHNlQDI6CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MjkKICAgIC8vIHJldHVybiBvcC5zaGEyNTYoYSArIGIgaWYgQmlnVUludC5mcm9tX2J5dGVzKGEpIDwgQmlnVUludC5mcm9tX2J5dGVzKGIpIGVsc2UgYiArIGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGZyYW1lX2RpZyAtMgogICAgY29uY2F0CgpoYXNoX3BhaXJfdGVybmFyeV9tZXJnZUAzOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjI5CiAgICAvLyByZXR1cm4gb3Auc2hhMjU2KGEgKyBiIGlmIEJpZ1VJbnQuZnJvbV9ieXRlcyhhKSA8IEJpZ1VJbnQuZnJvbV9ieXRlcyhiKSBlbHNlIGIgKyBhKQogICAgc2hhMjU2CiAgICByZXRzdWIK", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5jbGVhcl9zdGF0ZV9wcm9ncmFtOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjkKICAgIC8vIGNsYXNzIE1lcmtsZVRyZWUoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgaW50IDEKICAgIHJldHVybgo=" }, "state": { "global": { diff --git a/examples/merkle/out/MerkleTree.clear.mir b/examples/merkle/out/MerkleTree.clear.mir index 1f959fdbfa..6d8791268c 100644 --- a/examples/merkle/out/MerkleTree.clear.mir +++ b/examples/merkle/out/MerkleTree.clear.mir @@ -4,6 +4,6 @@ // examples.merkle.contract.MerkleTree.clear_state_program() -> uint64: main_block@0: - int 1 // 1 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 - return // class MerkleTree(arc4.ARC4Contract): merkle/contract.py:14 + int 1 // 1 class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 + return // class MerkleTree(arc4.ARC4Contract): merkle/contract.py:9 diff --git a/examples/merkle/out/MerkleTree.clear.teal b/examples/merkle/out/MerkleTree.clear.teal index d969f46258..aeaf7e4c8b 100644 --- a/examples/merkle/out/MerkleTree.clear.teal +++ b/examples/merkle/out/MerkleTree.clear.teal @@ -1,7 +1,7 @@ #pragma version 10 examples.merkle.contract.MerkleTree.clear_state_program: - // merkle/contract.py:14 + // merkle/contract.py:9 // class MerkleTree(arc4.ARC4Contract): int 1 return diff --git a/examples/merkle/out/MerkleTree.destructured.ir b/examples/merkle/out/MerkleTree.destructured.ir index c54d2a70e8..5dea0ad114 100644 --- a/examples/merkle/out/MerkleTree.destructured.ir +++ b/examples/merkle/out/MerkleTree.destructured.ir @@ -1,10 +1,10 @@ contract examples.merkle.contract.MerkleTree: program approval: subroutine examples.merkle.contract.MerkleTree.approval_program() -> uint64: - block@0: // L14 + block@0: // L9 let tmp%0#0: bytes = (txna ApplicationArgs 0) switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => fail // reject transaction} - block@1: // create_route_L31 + block@1: // create_route_L10 let tmp%1#0: uint64 = (txn OnCompletion) let tmp%2#0: uint64 = (! tmp%1#0) (assert tmp%2#0) // OnCompletion is NoOp @@ -14,7 +14,7 @@ contract examples.merkle.contract.MerkleTree: let tmp%5#0: bytes = (txna ApplicationArgs 1) examples.merkle.contract.MerkleTree.create(tmp%5#0) return 1u - block@2: // verify_route_L35 + block@2: // verify_route_L14 let tmp%6#0: uint64 = (txn OnCompletion) let tmp%7#0: uint64 = (! tmp%6#0) (assert tmp%7#0) // OnCompletion is NoOp @@ -29,52 +29,55 @@ contract examples.merkle.contract.MerkleTree: return 1u subroutine examples.merkle.contract.MerkleTree.create(root: bytes) -> void: - block@0: // L31 + block@0: // L10 (app_global_put "root" root#0) return subroutine examples.merkle.contract.MerkleTree.verify(proof: bytes, leaf: bytes) -> uint64: - block@0: // L35 + block@0: // L14 let (root_value%0#0: bytes, root_exists%0#0: uint64) = (app_global_get_ex 0u "root") (assert root_exists%0#0) // check root exists - let (compute_root_hash%0#0: bytes, proof#0: bytes, leaf#0: bytes) = examples.merkle.contract.MerkleTree.compute_root_hash(proof#0, leaf#0) + let (compute_root_hash%0#0: bytes, proof#0: bytes) = examples.merkle.contract.compute_root_hash(proof#0, leaf#0) let tmp%0#0: uint64 = (== root_value%0#0 compute_root_hash%0#0) return tmp%0#0 - subroutine examples.merkle.contract.MerkleTree.compute_root_hash(proof: bytes, leaf: bytes) -> : - block@0: // L24 - let array_length%0#0: uint64 = (extract_uint16 proof#0 0u) - let array_value%0#0: bytes = ((extract 2 0) proof#0) - let item_index_internal%0#0: uint64 = 0u - let computed#1: bytes = leaf#0 + subroutine examples.merkle.contract.compute_root_hash(proof: bytes, leaf: bytes) -> : + block@0: // L19 + let tmp%0#0: uint64 = (extract_uint16 proof#0 0u) + let range_item%0#0: uint64 = 0u + let computed#2: bytes = leaf#0 + let idx#0: uint64 = range_item%0#0 goto block@1 - block@1: // for_header_L27 - let continue_looping%0#0: uint64 = (< item_index_internal%0#0 array_length%0#0) - goto continue_looping%0#0 ? block@2 : block@4 - block@2: // for_body_L27 - let item_index%0#0: uint64 = (* item_index_internal%0#0 32u) - let proof_hash#0: bytes = (extract3 array_value%0#0 item_index%0#0 32u) - let (computed#1: bytes, computed#2: bytes, proof_hash#0: bytes) = examples.merkle.contract.MerkleTree.hash_pair(computed#1, proof_hash#0) - let item_index_internal%0#0: uint64 = (+ item_index_internal%0#0 1u) + block@1: // for_header_L22 + let continue_looping%0#0: uint64 = (< idx#0 tmp%0#0) + goto continue_looping%0#0 ? block@2 : block@5 + block@2: // for_body_L22 + (assert continue_looping%0#0) // Index access is out of bounds + let array_data_sans_header%0#0: bytes = ((extract 2 0) proof#0) + let item_index%0#0: uint64 = (* idx#0 32u) + let tmp%1#0: bytes = (extract3 array_data_sans_header%0#0 item_index%0#0 32u) + let computed#2: bytes = examples.merkle.contract.hash_pair(computed#2, tmp%1#0) + let range_item%0#0: uint64 = (+ idx#0 1u) + let idx#0: uint64 = range_item%0#0 goto block@1 - block@4: // after_for_L27 - return computed#1 proof#0 leaf#0 + block@5: // after_for_L22 + return computed#2 proof#0 - subroutine examples.merkle.contract.MerkleTree.hash_pair(a: bytes, b: bytes) -> : - block@0: // L15 + subroutine examples.merkle.contract.hash_pair(a: bytes, b: bytes) -> bytes: + block@0: // L27 let tmp%0#0: uint64 = (b< a#0 b#0) goto tmp%0#0 ? block@1 : block@2 - block@1: // ternary_true_L18 + block@1: // ternary_true_L29 let ternary_result%0#0: bytes = (concat a#0 b#0) goto block@3 - block@2: // ternary_false_L18 + block@2: // ternary_false_L29 let ternary_result%0#0: bytes = (concat b#0 a#0) goto block@3 - block@3: // ternary_merge_L18 - let hash_bytes#0: bytes = (sha256 ternary_result%0#0) - return hash_bytes#0 a#0 b#0 + block@3: // ternary_merge_L29 + let tmp%1#0: bytes = (sha256 ternary_result%0#0) + return tmp%1#0 program clear-state: subroutine examples.merkle.contract.MerkleTree.clear_state_program() -> uint64: - block@0: // L14 + block@0: // L9 return 1u \ No newline at end of file diff --git a/examples/merkle/out/MerkleTree.ssa.ir b/examples/merkle/out/MerkleTree.ssa.ir index 94974e95cf..584e3bc99a 100644 --- a/examples/merkle/out/MerkleTree.ssa.ir +++ b/examples/merkle/out/MerkleTree.ssa.ir @@ -1,10 +1,10 @@ contract examples.merkle.contract.MerkleTree: program approval: subroutine examples.merkle.contract.MerkleTree.approval_program() -> uint64: - block@0: // L14 + block@0: // L9 let tmp%0#0: bytes = (txna ApplicationArgs 0) switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => block@3} - block@1: // create_route_L31 + block@1: // create_route_L10 let tmp%1#0: uint64 = (txn OnCompletion) let tmp%2#0: uint64 = (== tmp%1#0 NoOp) (assert tmp%2#0) // OnCompletion is NoOp @@ -14,7 +14,7 @@ contract examples.merkle.contract.MerkleTree: let tmp%5#0: bytes = (txna ApplicationArgs 1) examples.merkle.contract.MerkleTree.create(tmp%5#0) return 1u - block@2: // verify_route_L35 + block@2: // verify_route_L14 let tmp%6#0: uint64 = (txn OnCompletion) let tmp%7#0: uint64 = (== tmp%6#0 NoOp) (assert tmp%7#0) // OnCompletion is NoOp @@ -27,71 +27,71 @@ contract examples.merkle.contract.MerkleTree: let tmp%13#0: bytes = (concat 0x151f7c75 tmp%12#0) (log tmp%13#0) return 1u - block@3: // switch_case_default_L14 + block@3: // switch_case_default_L9 goto block@4 - block@4: // switch_case_next_L14 + block@4: // switch_case_next_L9 fail // reject transaction subroutine examples.merkle.contract.MerkleTree.create(root: bytes) -> void: - block@0: // L31 - let copy%0#0: bytes = root#0 - (app_global_put "root" copy%0#0) + block@0: // L10 + (app_global_put "root" root#0) return subroutine examples.merkle.contract.MerkleTree.verify(proof: bytes, leaf: bytes) -> uint64: - block@0: // L35 + block@0: // L14 let (root_value%0#0: bytes, root_exists%0#0: uint64) = (app_global_get_ex 0u "root") (assert root_exists%0#0) // check root exists - let (compute_root_hash%0#0: bytes, compute_root_hash%1#0: bytes, compute_root_hash%2#0: bytes) = examples.merkle.contract.MerkleTree.compute_root_hash(proof#0, leaf#0) - let leaf#1: bytes = compute_root_hash%2#0 + let (compute_root_hash%0#0: bytes, compute_root_hash%1#0: bytes) = examples.merkle.contract.compute_root_hash(proof#0, leaf#0) let proof#1: bytes = compute_root_hash%1#0 let tmp%0#0: uint64 = (== root_value%0#0 compute_root_hash%0#0) return tmp%0#0 - subroutine examples.merkle.contract.MerkleTree.compute_root_hash(proof: bytes, leaf: bytes) -> : - block@0: // L24 - let copy%0#0: bytes = leaf#0 - let computed#0: bytes = copy%0#0 - let array_length%0#0: uint64 = (extract_uint16 proof#0 0u) - let array_value%0#0: bytes = ((extract 2 0) proof#0) - let item_index_internal%0#0: uint64 = 0u - let reverse_index_internal%0#0: uint64 = array_length%0#0 + subroutine examples.merkle.contract.compute_root_hash(proof: bytes, leaf: bytes) -> : + block@0: // L19 + let computed#0: bytes = leaf#0 + let tmp%0#0: uint64 = (extract_uint16 proof#0 0u) + (assert 1u) // Step cannot be zero + let range_item%0#0: uint64 = 0u goto block@1 - block@1: // for_header_L27 - let item_index_internal%0#1: uint64 = φ(item_index_internal%0#0 <- block@0, item_index_internal%0#2 <- block@3) - let computed#1: bytes = φ(computed#0 <- block@0, computed#3 <- block@3) - let continue_looping%0#0: uint64 = (< item_index_internal%0#1 array_length%0#0) - goto continue_looping%0#0 ? block@2 : block@4 - block@2: // for_body_L27 - let item_index%0#0: uint64 = (* item_index_internal%0#1 32u) - let proof_hash#0: bytes = (extract3 array_value%0#0 item_index%0#0 32u) - let (hash_pair%0#0: bytes, hash_pair%1#0: bytes, hash_pair%2#0: bytes) = examples.merkle.contract.MerkleTree.hash_pair(computed#1, proof_hash#0) - let proof_hash#1: bytes = hash_pair%2#0 - let computed#2: bytes = hash_pair%1#0 - let computed#3: bytes = (hash_pair%0#0) + block@1: // for_header_L22 + let range_item%0#1: uint64 = φ(range_item%0#0 <- block@0, range_item%0#3 <- block@4) + let computed#3: bytes = φ(computed#0 <- block@0, computed#2 <- block@4) + let continue_looping%0#0: uint64 = (< range_item%0#1 tmp%0#0) + goto continue_looping%0#0 ? block@2 : block@5 + block@2: // for_body_L22 + let idx#0: uint64 = range_item%0#1 + let array_length%0#0: uint64 = (extract_uint16 proof#0 0u) + let index_is_in_bounds%0#0: uint64 = (< idx#0 array_length%0#0) + (assert index_is_in_bounds%0#0) // Index access is out of bounds + let array_data_sans_header%0#0: bytes = ((extract 2 0) proof#0) + let item_index%0#0: uint64 = (* idx#0 32u) + let tmp%1#0: bytes = (extract3 array_data_sans_header%0#0 item_index%0#0 32u) + let computed#2: bytes = examples.merkle.contract.hash_pair(computed#3, tmp%1#0) goto block@3 - block@3: // for_footer_L27 - let item_index_internal%0#2: uint64 = (+ item_index_internal%0#1 1u) + block@3: // for_footer_L22 + goto block@4 + block@4: // for_increment_L22 + let range_item%0#3: uint64 = (+ range_item%0#1 1u) goto block@1 - block@4: // after_for_L27 - return computed#1 proof#0 leaf#0 + block@5: // after_for_L22 + return computed#3 proof#0 - subroutine examples.merkle.contract.MerkleTree.hash_pair(a: bytes, b: bytes) -> : - block@0: // L15 + subroutine examples.merkle.contract.hash_pair(a: bytes, b: bytes) -> bytes: + block@0: // L27 let tmp%0#0: uint64 = (b< a#0 b#0) goto tmp%0#0 ? block@1 : block@2 - block@1: // ternary_true_L18 + block@1: // ternary_true_L29 let ternary_result%0#0: bytes = (concat a#0 b#0) goto block@3 - block@2: // ternary_false_L18 + block@2: // ternary_false_L29 let ternary_result%0#1: bytes = (concat b#0 a#0) goto block@3 - block@3: // ternary_merge_L18 + block@3: // ternary_merge_L29 let ternary_result%0#2: bytes = φ(ternary_result%0#0 <- block@1, ternary_result%0#1 <- block@2) - let hash_bytes#0: bytes = (sha256 ternary_result%0#2) - return hash_bytes#0 a#0 b#0 + let tmp%1#0: bytes = (sha256 ternary_result%0#2) + return tmp%1#0 program clear-state: subroutine examples.merkle.contract.MerkleTree.clear_state_program() -> uint64: - block@0: // L14 + block@0: // L9 return 1u \ No newline at end of file diff --git a/examples/merkle/out/MerkleTree.ssa.opt_pass_1.ir b/examples/merkle/out/MerkleTree.ssa.opt_pass_1.ir index 9cb3af9fd6..78ed5ec552 100644 --- a/examples/merkle/out/MerkleTree.ssa.opt_pass_1.ir +++ b/examples/merkle/out/MerkleTree.ssa.opt_pass_1.ir @@ -1,10 +1,10 @@ contract examples.merkle.contract.MerkleTree: program approval: subroutine examples.merkle.contract.MerkleTree.approval_program() -> uint64: - block@0: // L14 + block@0: // L9 let tmp%0#0: bytes = (txna ApplicationArgs 0) switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => fail // reject transaction} - block@1: // create_route_L31 + block@1: // create_route_L10 let tmp%1#0: uint64 = (txn OnCompletion) let tmp%2#0: uint64 = (! tmp%1#0) (assert tmp%2#0) // OnCompletion is NoOp @@ -14,7 +14,7 @@ contract examples.merkle.contract.MerkleTree: let tmp%5#0: bytes = (txna ApplicationArgs 1) examples.merkle.contract.MerkleTree.create(tmp%5#0) return 1u - block@2: // verify_route_L35 + block@2: // verify_route_L14 let tmp%6#0: uint64 = (txn OnCompletion) let tmp%7#0: uint64 = (! tmp%6#0) (assert tmp%7#0) // OnCompletion is NoOp @@ -29,54 +29,55 @@ contract examples.merkle.contract.MerkleTree: return 1u subroutine examples.merkle.contract.MerkleTree.create(root: bytes) -> void: - block@0: // L31 + block@0: // L10 (app_global_put "root" root#0) return subroutine examples.merkle.contract.MerkleTree.verify(proof: bytes, leaf: bytes) -> uint64: - block@0: // L35 + block@0: // L14 let (root_value%0#0: bytes, root_exists%0#0: uint64) = (app_global_get_ex 0u "root") (assert root_exists%0#0) // check root exists - let (compute_root_hash%0#0: bytes, proof#1: bytes, leaf#1: bytes) = examples.merkle.contract.MerkleTree.compute_root_hash(proof#0, leaf#0) + let (compute_root_hash%0#0: bytes, proof#1: bytes) = examples.merkle.contract.compute_root_hash(proof#0, leaf#0) let tmp%0#0: uint64 = (== root_value%0#0 compute_root_hash%0#0) return tmp%0#0 - subroutine examples.merkle.contract.MerkleTree.compute_root_hash(proof: bytes, leaf: bytes) -> : - block@0: // L24 - let array_length%0#0: uint64 = (extract_uint16 proof#0 0u) - let array_value%0#0: bytes = ((extract 2 0) proof#0) - let item_index_internal%0#0: uint64 = 0u + subroutine examples.merkle.contract.compute_root_hash(proof: bytes, leaf: bytes) -> : + block@0: // L19 + let tmp%0#0: uint64 = (extract_uint16 proof#0 0u) + let range_item%0#0: uint64 = 0u goto block@1 - block@1: // for_header_L27 - let item_index_internal%0#1: uint64 = φ(item_index_internal%0#0 <- block@0, item_index_internal%0#2 <- block@2) - let computed#1: bytes = φ(leaf#0 <- block@0, computed#3 <- block@2) - let continue_looping%0#0: uint64 = (< item_index_internal%0#1 array_length%0#0) - goto continue_looping%0#0 ? block@2 : block@4 - block@2: // for_body_L27 - let item_index%0#0: uint64 = (* item_index_internal%0#1 32u) - let proof_hash#0: bytes = (extract3 array_value%0#0 item_index%0#0 32u) - let (computed#3: bytes, computed#2: bytes, proof_hash#1: bytes) = examples.merkle.contract.MerkleTree.hash_pair(computed#1, proof_hash#0) - let item_index_internal%0#2: uint64 = (+ item_index_internal%0#1 1u) + block@1: // for_header_L22 + let idx#0: uint64 = φ(range_item%0#0 <- block@0, range_item%0#3 <- block@2) + let computed#3: bytes = φ(leaf#0 <- block@0, computed#2 <- block@2) + let continue_looping%0#0: uint64 = (< idx#0 tmp%0#0) + goto continue_looping%0#0 ? block@2 : block@5 + block@2: // for_body_L22 + (assert continue_looping%0#0) // Index access is out of bounds + let array_data_sans_header%0#0: bytes = ((extract 2 0) proof#0) + let item_index%0#0: uint64 = (* idx#0 32u) + let tmp%1#0: bytes = (extract3 array_data_sans_header%0#0 item_index%0#0 32u) + let computed#2: bytes = examples.merkle.contract.hash_pair(computed#3, tmp%1#0) + let range_item%0#3: uint64 = (+ idx#0 1u) goto block@1 - block@4: // after_for_L27 - return computed#1 proof#0 leaf#0 + block@5: // after_for_L22 + return computed#3 proof#0 - subroutine examples.merkle.contract.MerkleTree.hash_pair(a: bytes, b: bytes) -> : - block@0: // L15 + subroutine examples.merkle.contract.hash_pair(a: bytes, b: bytes) -> bytes: + block@0: // L27 let tmp%0#0: uint64 = (b< a#0 b#0) goto tmp%0#0 ? block@1 : block@2 - block@1: // ternary_true_L18 + block@1: // ternary_true_L29 let ternary_result%0#0: bytes = (concat a#0 b#0) goto block@3 - block@2: // ternary_false_L18 + block@2: // ternary_false_L29 let ternary_result%0#1: bytes = (concat b#0 a#0) goto block@3 - block@3: // ternary_merge_L18 + block@3: // ternary_merge_L29 let ternary_result%0#2: bytes = φ(ternary_result%0#0 <- block@1, ternary_result%0#1 <- block@2) - let hash_bytes#0: bytes = (sha256 ternary_result%0#2) - return hash_bytes#0 a#0 b#0 + let tmp%1#0: bytes = (sha256 ternary_result%0#2) + return tmp%1#0 program clear-state: subroutine examples.merkle.contract.MerkleTree.clear_state_program() -> uint64: - block@0: // L14 + block@0: // L9 return 1u \ No newline at end of file diff --git a/examples/merkle/out/contract.awst b/examples/merkle/out/contract.awst index 3e5c7934dd..fb10025bc8 100644 --- a/examples/merkle/out/contract.awst +++ b/examples/merkle/out/contract.awst @@ -1,31 +1,30 @@ contract MerkleTree { globals { - ['root']: algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]] - } - - subroutine hash_pair(a: algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]], b: algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]]): algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]] - { - hash_bytes: algopy.Bytes = sha256((reinterpret_cast(reinterpret_cast(a)) < reinterpret_cast(reinterpret_cast(b))) ? (reinterpret_cast(a) + reinterpret_cast(b)) : (reinterpret_cast(b) + reinterpret_cast(a))) - return reinterpret_cast(hash_bytes) - } - - subroutine compute_root_hash(proof: algopy.arc4.DynamicArray[algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]]], leaf: algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]]): algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]] - { - computed: algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]] = leaf.copy() - for proof_hash in proof { - computed: algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]] = this::hash_pair(computed, proof_hash) - } - return computed + ['root']: algopy.Bytes } abimethod create(root: algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]]): None { - this.root: algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]] = root.copy() + this.root: algopy.Bytes = reinterpret_cast(root) } abimethod verify(proof: algopy.arc4.DynamicArray[algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]]], leaf: algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]]): bool { - return reinterpret_cast(this.root) == reinterpret_cast(this::compute_root_hash(proof, leaf)) + return this.root == examples.merkle.contract::compute_root_hash(proof, reinterpret_cast(leaf)) + } +} + +subroutine compute_root_hash(proof: algopy.arc4.DynamicArray[algopy.arc4.StaticArray[algopy.arc4.Byte, typing.Literal[32]]], leaf: algopy.Bytes): algopy.Bytes +{ + computed: algopy.Bytes = leaf + for idx in range(0u, extract_uint16(proof, 0u), 1u) { + computed: algopy.Bytes = examples.merkle.contract::hash_pair(computed, reinterpret_cast(proof[idx])) } + return computed +} + +subroutine hash_pair(a: algopy.Bytes, b: algopy.Bytes): algopy.Bytes +{ + return sha256((reinterpret_cast(a) < reinterpret_cast(b)) ? (a + b) : (b + a)) } \ No newline at end of file diff --git a/examples/merkle/out_O2/MerkleTree.approval.teal b/examples/merkle/out_O2/MerkleTree.approval.teal index 1abf537334..90e3bec419 100644 --- a/examples/merkle/out_O2/MerkleTree.approval.teal +++ b/examples/merkle/out_O2/MerkleTree.approval.teal @@ -59,59 +59,59 @@ verify: frame_dig -2 frame_dig -1 callsub compute_root_hash - frame_bury -1 frame_bury -2 == retsub -// examples.merkle.contract.MerkleTree.compute_root_hash(proof: bytes, leaf: bytes) -> bytes, bytes, bytes: +// examples.merkle.contract.compute_root_hash(proof: bytes, leaf: bytes) -> bytes, bytes: compute_root_hash: - proto 2 3 + proto 2 2 + byte "" frame_dig -2 int 0 extract_uint16 - frame_dig -2 - extract 2 0 - int 0 frame_dig -1 + int 0 compute_root_hash_for_header@1: - frame_dig 2 - frame_dig 0 + frame_dig 3 + frame_dig 1 < - bz compute_root_hash_after_for@4 - frame_dig 2 dup + frame_bury 0 + bz compute_root_hash_after_for@5 + frame_dig 0 + assert // Index access is out of bounds + frame_dig -2 + extract 2 0 + frame_dig 3 + dup + cover 2 int 32 * - frame_dig 1 - swap int 32 extract3 - frame_dig 3 + frame_dig 2 swap callsub hash_pair - popn 2 - frame_bury 3 + frame_bury 2 int 1 + - frame_bury 2 + frame_bury 3 b compute_root_hash_for_header@1 -compute_root_hash_after_for@4: - frame_dig 3 +compute_root_hash_after_for@5: + frame_dig 2 frame_dig -2 - frame_dig -1 - frame_bury 2 frame_bury 1 frame_bury 0 retsub -// examples.merkle.contract.MerkleTree.hash_pair(a: bytes, b: bytes) -> bytes, bytes, bytes: +// examples.merkle.contract.hash_pair(a: bytes, b: bytes) -> bytes: hash_pair: - proto 2 3 + proto 2 1 frame_dig -2 frame_dig -1 b< @@ -128,6 +128,4 @@ hash_pair_ternary_false@2: hash_pair_ternary_merge@3: sha256 - frame_dig -2 - frame_dig -1 retsub diff --git a/examples/merkle/out_O2/MerkleTree.destructured.ir b/examples/merkle/out_O2/MerkleTree.destructured.ir index c54d2a70e8..5dea0ad114 100644 --- a/examples/merkle/out_O2/MerkleTree.destructured.ir +++ b/examples/merkle/out_O2/MerkleTree.destructured.ir @@ -1,10 +1,10 @@ contract examples.merkle.contract.MerkleTree: program approval: subroutine examples.merkle.contract.MerkleTree.approval_program() -> uint64: - block@0: // L14 + block@0: // L9 let tmp%0#0: bytes = (txna ApplicationArgs 0) switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => fail // reject transaction} - block@1: // create_route_L31 + block@1: // create_route_L10 let tmp%1#0: uint64 = (txn OnCompletion) let tmp%2#0: uint64 = (! tmp%1#0) (assert tmp%2#0) // OnCompletion is NoOp @@ -14,7 +14,7 @@ contract examples.merkle.contract.MerkleTree: let tmp%5#0: bytes = (txna ApplicationArgs 1) examples.merkle.contract.MerkleTree.create(tmp%5#0) return 1u - block@2: // verify_route_L35 + block@2: // verify_route_L14 let tmp%6#0: uint64 = (txn OnCompletion) let tmp%7#0: uint64 = (! tmp%6#0) (assert tmp%7#0) // OnCompletion is NoOp @@ -29,52 +29,55 @@ contract examples.merkle.contract.MerkleTree: return 1u subroutine examples.merkle.contract.MerkleTree.create(root: bytes) -> void: - block@0: // L31 + block@0: // L10 (app_global_put "root" root#0) return subroutine examples.merkle.contract.MerkleTree.verify(proof: bytes, leaf: bytes) -> uint64: - block@0: // L35 + block@0: // L14 let (root_value%0#0: bytes, root_exists%0#0: uint64) = (app_global_get_ex 0u "root") (assert root_exists%0#0) // check root exists - let (compute_root_hash%0#0: bytes, proof#0: bytes, leaf#0: bytes) = examples.merkle.contract.MerkleTree.compute_root_hash(proof#0, leaf#0) + let (compute_root_hash%0#0: bytes, proof#0: bytes) = examples.merkle.contract.compute_root_hash(proof#0, leaf#0) let tmp%0#0: uint64 = (== root_value%0#0 compute_root_hash%0#0) return tmp%0#0 - subroutine examples.merkle.contract.MerkleTree.compute_root_hash(proof: bytes, leaf: bytes) -> : - block@0: // L24 - let array_length%0#0: uint64 = (extract_uint16 proof#0 0u) - let array_value%0#0: bytes = ((extract 2 0) proof#0) - let item_index_internal%0#0: uint64 = 0u - let computed#1: bytes = leaf#0 + subroutine examples.merkle.contract.compute_root_hash(proof: bytes, leaf: bytes) -> : + block@0: // L19 + let tmp%0#0: uint64 = (extract_uint16 proof#0 0u) + let range_item%0#0: uint64 = 0u + let computed#2: bytes = leaf#0 + let idx#0: uint64 = range_item%0#0 goto block@1 - block@1: // for_header_L27 - let continue_looping%0#0: uint64 = (< item_index_internal%0#0 array_length%0#0) - goto continue_looping%0#0 ? block@2 : block@4 - block@2: // for_body_L27 - let item_index%0#0: uint64 = (* item_index_internal%0#0 32u) - let proof_hash#0: bytes = (extract3 array_value%0#0 item_index%0#0 32u) - let (computed#1: bytes, computed#2: bytes, proof_hash#0: bytes) = examples.merkle.contract.MerkleTree.hash_pair(computed#1, proof_hash#0) - let item_index_internal%0#0: uint64 = (+ item_index_internal%0#0 1u) + block@1: // for_header_L22 + let continue_looping%0#0: uint64 = (< idx#0 tmp%0#0) + goto continue_looping%0#0 ? block@2 : block@5 + block@2: // for_body_L22 + (assert continue_looping%0#0) // Index access is out of bounds + let array_data_sans_header%0#0: bytes = ((extract 2 0) proof#0) + let item_index%0#0: uint64 = (* idx#0 32u) + let tmp%1#0: bytes = (extract3 array_data_sans_header%0#0 item_index%0#0 32u) + let computed#2: bytes = examples.merkle.contract.hash_pair(computed#2, tmp%1#0) + let range_item%0#0: uint64 = (+ idx#0 1u) + let idx#0: uint64 = range_item%0#0 goto block@1 - block@4: // after_for_L27 - return computed#1 proof#0 leaf#0 + block@5: // after_for_L22 + return computed#2 proof#0 - subroutine examples.merkle.contract.MerkleTree.hash_pair(a: bytes, b: bytes) -> : - block@0: // L15 + subroutine examples.merkle.contract.hash_pair(a: bytes, b: bytes) -> bytes: + block@0: // L27 let tmp%0#0: uint64 = (b< a#0 b#0) goto tmp%0#0 ? block@1 : block@2 - block@1: // ternary_true_L18 + block@1: // ternary_true_L29 let ternary_result%0#0: bytes = (concat a#0 b#0) goto block@3 - block@2: // ternary_false_L18 + block@2: // ternary_false_L29 let ternary_result%0#0: bytes = (concat b#0 a#0) goto block@3 - block@3: // ternary_merge_L18 - let hash_bytes#0: bytes = (sha256 ternary_result%0#0) - return hash_bytes#0 a#0 b#0 + block@3: // ternary_merge_L29 + let tmp%1#0: bytes = (sha256 ternary_result%0#0) + return tmp%1#0 program clear-state: subroutine examples.merkle.contract.MerkleTree.clear_state_program() -> uint64: - block@0: // L14 + block@0: // L9 return 1u \ No newline at end of file diff --git a/examples/merkle/out_unoptimized/MerkleTree.approval.teal b/examples/merkle/out_unoptimized/MerkleTree.approval.teal index c3c751af24..33049ea40d 100644 --- a/examples/merkle/out_unoptimized/MerkleTree.approval.teal +++ b/examples/merkle/out_unoptimized/MerkleTree.approval.teal @@ -1,7 +1,7 @@ #pragma version 10 examples.merkle.contract.MerkleTree.approval_program: - // merkle/contract.py:14 + // merkle/contract.py:9 // class MerkleTree(arc4.ARC4Contract): txna ApplicationArgs 0 method "create(byte[32])void" @@ -11,7 +11,7 @@ examples.merkle.contract.MerkleTree.approval_program: b main_switch_case_default@3 main_create_route@1: - // merkle/contract.py:31 + // merkle/contract.py:10 // @arc4.abimethod(create=True) txn OnCompletion int NoOp @@ -20,17 +20,17 @@ main_create_route@1: txn ApplicationID ! assert // is creating - // merkle/contract.py:14 + // merkle/contract.py:9 // class MerkleTree(arc4.ARC4Contract): txna ApplicationArgs 1 - // merkle/contract.py:31 + // merkle/contract.py:10 // @arc4.abimethod(create=True) callsub create int 1 return main_verify_route@2: - // merkle/contract.py:35 + // merkle/contract.py:14 // @arc4.abimethod txn OnCompletion int NoOp @@ -38,11 +38,11 @@ main_verify_route@2: assert // OnCompletion is NoOp txn ApplicationID assert // is not creating - // merkle/contract.py:14 + // merkle/contract.py:9 // class MerkleTree(arc4.ARC4Contract): txna ApplicationArgs 1 txna ApplicationArgs 2 - // merkle/contract.py:35 + // merkle/contract.py:14 // @arc4.abimethod callsub verify byte 0x00 @@ -57,34 +57,33 @@ main_verify_route@2: return main_switch_case_default@3: - // merkle/contract.py:14 + // merkle/contract.py:9 // class MerkleTree(arc4.ARC4Contract): err // reject transaction // examples.merkle.contract.MerkleTree.create(root: bytes) -> void: create: - // merkle/contract.py:31-32 + // merkle/contract.py:10-11 // @arc4.abimethod(create=True) // def create(self, root: Bytes32) -> None: proto 1 0 - // merkle/contract.py:33 - // self.root = root.copy() - frame_dig -1 + // merkle/contract.py:12 + // self.root = root.bytes byte "root" - swap + frame_dig -1 app_global_put retsub // examples.merkle.contract.MerkleTree.verify(proof: bytes, leaf: bytes) -> uint64: verify: - // merkle/contract.py:35-36 + // merkle/contract.py:14-15 // @arc4.abimethod // def verify(self, proof: Proof, leaf: Bytes32) -> bool: proto 2 1 - // merkle/contract.py:37 - // return self.root == self.compute_root_hash(proof, leaf) + // merkle/contract.py:16 + // return self.root == compute_root_hash(proof, leaf.bytes) int 0 byte "root" app_global_get_ex @@ -93,113 +92,100 @@ verify: frame_dig -1 callsub compute_root_hash pop - pop == retsub -// examples.merkle.contract.MerkleTree.compute_root_hash(proof: bytes, leaf: bytes) -> bytes, bytes, bytes: +// examples.merkle.contract.compute_root_hash(proof: bytes, leaf: bytes) -> bytes, bytes: compute_root_hash: - // merkle/contract.py:24-25 + // merkle/contract.py:19-20 // @subroutine - // def compute_root_hash(self, proof: Proof, leaf: Bytes32) -> Bytes32: - proto 2 3 - // merkle/contract.py:26 - // computed = leaf.copy() + // def compute_root_hash(proof: Proof, leaf: Bytes) -> Bytes: + proto 2 2 + // merkle/contract.py:21 + // computed = leaf frame_dig -1 - // merkle/contract.py:27 - // for proof_hash in proof: + // merkle/contract.py:22 + // for idx in urange(proof.length): frame_dig -2 int 0 extract_uint16 - frame_dig -2 - extract 2 0 + int 1 + assert // Step cannot be zero int 0 compute_root_hash_for_header@1: - // merkle/contract.py:27 - // for proof_hash in proof: - frame_dig 3 + // merkle/contract.py:22 + // for idx in urange(proof.length): + frame_dig 2 frame_dig 1 < - bz compute_root_hash_after_for@4 - frame_dig 3 - int 32 - * + bz compute_root_hash_after_for@5 frame_dig 2 + // merkle/contract.py:23 + // computed = hash_pair(computed, proof[idx].bytes) + frame_dig -2 + int 0 + extract_uint16 + dig 1 swap + < + assert // Index access is out of bounds + frame_dig -2 + extract 2 0 + swap + int 32 + * int 32 extract3 - // merkle/contract.py:28 - // computed = self.hash_pair(computed, proof_hash) frame_dig 0 swap callsub hash_pair - pop - pop frame_bury 0 - frame_dig 3 + // merkle/contract.py:22 + // for idx in urange(proof.length): + frame_dig 2 int 1 + - frame_bury 3 + frame_bury 2 b compute_root_hash_for_header@1 -compute_root_hash_after_for@4: - // merkle/contract.py:29 +compute_root_hash_after_for@5: + // merkle/contract.py:24 // return computed frame_dig 0 frame_dig -2 - frame_dig -1 - frame_bury 2 frame_bury 1 frame_bury 0 retsub -// examples.merkle.contract.MerkleTree.hash_pair(a: bytes, b: bytes) -> bytes, bytes, bytes: +// examples.merkle.contract.hash_pair(a: bytes, b: bytes) -> bytes: hash_pair: - // merkle/contract.py:15-16 + // merkle/contract.py:27-28 // @subroutine - // def hash_pair(self, a: Bytes32, b: Bytes32) -> Bytes32: - proto 2 3 - // merkle/contract.py:19 - // if BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) + // def hash_pair(a: Bytes, b: Bytes) -> Bytes: + proto 2 1 + // merkle/contract.py:29 + // return op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) frame_dig -2 frame_dig -1 b< - // merkle/contract.py:18-20 - // a.bytes + b.bytes - // if BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) - // else b.bytes + a.bytes bz hash_pair_ternary_false@2 frame_dig -2 frame_dig -1 - // merkle/contract.py:18 - // a.bytes + b.bytes concat b hash_pair_ternary_merge@3 hash_pair_ternary_false@2: - // merkle/contract.py:18-20 - // a.bytes + b.bytes - // if BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) - // else b.bytes + a.bytes + // merkle/contract.py:29 + // return op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) frame_dig -1 frame_dig -2 - // merkle/contract.py:20 - // else b.bytes + a.bytes concat hash_pair_ternary_merge@3: - // merkle/contract.py:17-21 - // hash_bytes = op.sha256( - // a.bytes + b.bytes - // if BigUInt.from_bytes(a.bytes) < BigUInt.from_bytes(b.bytes) - // else b.bytes + a.bytes - // ) + // merkle/contract.py:29 + // return op.sha256(a + b if BigUInt.from_bytes(a) < BigUInt.from_bytes(b) else b + a) sha256 - // merkle/contract.py:22 - // return Bytes32.from_bytes(hash_bytes) - frame_dig -2 - frame_dig -1 retsub diff --git a/examples/merkle/out_unoptimized/MerkleTree.clear.teal b/examples/merkle/out_unoptimized/MerkleTree.clear.teal index d969f46258..aeaf7e4c8b 100644 --- a/examples/merkle/out_unoptimized/MerkleTree.clear.teal +++ b/examples/merkle/out_unoptimized/MerkleTree.clear.teal @@ -1,7 +1,7 @@ #pragma version 10 examples.merkle.contract.MerkleTree.clear_state_program: - // merkle/contract.py:14 + // merkle/contract.py:9 // class MerkleTree(arc4.ARC4Contract): int 1 return diff --git a/examples/merkle/out_unoptimized/MerkleTree.destructured.ir b/examples/merkle/out_unoptimized/MerkleTree.destructured.ir index d752aea381..9183782815 100644 --- a/examples/merkle/out_unoptimized/MerkleTree.destructured.ir +++ b/examples/merkle/out_unoptimized/MerkleTree.destructured.ir @@ -1,10 +1,10 @@ contract examples.merkle.contract.MerkleTree: program approval: subroutine examples.merkle.contract.MerkleTree.approval_program() -> uint64: - block@0: // L14 + block@0: // L9 let tmp%0#0: bytes = (txna ApplicationArgs 0) switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => block@3} - block@1: // create_route_L31 + block@1: // create_route_L10 let tmp%1#0: uint64 = (txn OnCompletion) let tmp%2#0: uint64 = (== tmp%1#0 NoOp) (assert tmp%2#0) // OnCompletion is NoOp @@ -14,7 +14,7 @@ contract examples.merkle.contract.MerkleTree: let tmp%5#0: bytes = (txna ApplicationArgs 1) examples.merkle.contract.MerkleTree.create(tmp%5#0) return 1u - block@2: // verify_route_L35 + block@2: // verify_route_L14 let tmp%6#0: uint64 = (txn OnCompletion) let tmp%7#0: uint64 = (== tmp%6#0 NoOp) (assert tmp%7#0) // OnCompletion is NoOp @@ -27,63 +27,67 @@ contract examples.merkle.contract.MerkleTree: let tmp%13#0: bytes = (concat 0x151f7c75 tmp%12#0) (log tmp%13#0) return 1u - block@3: // switch_case_default_L14 + block@3: // switch_case_default_L9 goto block@4 - block@4: // switch_case_next_L14 + block@4: // switch_case_next_L9 fail // reject transaction subroutine examples.merkle.contract.MerkleTree.create(root: bytes) -> void: - block@0: // L31 - let copy%0#0: bytes = root#0 - (app_global_put "root" copy%0#0) + block@0: // L10 + (app_global_put "root" root#0) return subroutine examples.merkle.contract.MerkleTree.verify(proof: bytes, leaf: bytes) -> uint64: - block@0: // L35 + block@0: // L14 let (root_value%0#0: bytes, root_exists%0#0: uint64) = (app_global_get_ex 0u "root") (assert root_exists%0#0) // check root exists - let (compute_root_hash%0#0: bytes, compute_root_hash%1#0: bytes, compute_root_hash%2#0: bytes) = examples.merkle.contract.MerkleTree.compute_root_hash(proof#0, leaf#0) + let (compute_root_hash%0#0: bytes, compute_root_hash%1#0: bytes) = examples.merkle.contract.compute_root_hash(proof#0, leaf#0) let tmp%0#0: uint64 = (== root_value%0#0 compute_root_hash%0#0) return tmp%0#0 - subroutine examples.merkle.contract.MerkleTree.compute_root_hash(proof: bytes, leaf: bytes) -> : - block@0: // L24 - let copy%0#0: bytes = leaf#0 - let computed#0: bytes = copy%0#0 - let array_length%0#0: uint64 = (extract_uint16 proof#0 0u) - let array_value%0#0: bytes = ((extract 2 0) proof#0) - let item_index_internal%0#0: uint64 = 0u + subroutine examples.merkle.contract.compute_root_hash(proof: bytes, leaf: bytes) -> : + block@0: // L19 + let computed#0: bytes = leaf#0 + let tmp%0#0: uint64 = (extract_uint16 proof#0 0u) + (assert 1u) // Step cannot be zero + let range_item%0#0: uint64 = 0u goto block@1 - block@1: // for_header_L27 - let continue_looping%0#0: uint64 = (< item_index_internal%0#0 array_length%0#0) - goto continue_looping%0#0 ? block@2 : block@4 - block@2: // for_body_L27 - let item_index%0#0: uint64 = (* item_index_internal%0#0 32u) - let proof_hash#0: bytes = (extract3 array_value%0#0 item_index%0#0 32u) - let (hash_pair%0#0: bytes, hash_pair%1#0: bytes, hash_pair%2#0: bytes) = examples.merkle.contract.MerkleTree.hash_pair(computed#0, proof_hash#0) - let computed#0: bytes = hash_pair%0#0 + block@1: // for_header_L22 + let continue_looping%0#0: uint64 = (< range_item%0#0 tmp%0#0) + goto continue_looping%0#0 ? block@2 : block@5 + block@2: // for_body_L22 + let idx#0: uint64 = range_item%0#0 + let array_length%0#0: uint64 = (extract_uint16 proof#0 0u) + let index_is_in_bounds%0#0: uint64 = (< idx#0 array_length%0#0) + (assert index_is_in_bounds%0#0) // Index access is out of bounds + let array_data_sans_header%0#0: bytes = ((extract 2 0) proof#0) + let item_index%0#0: uint64 = (* idx#0 32u) + let tmp%1#0: bytes = (extract3 array_data_sans_header%0#0 item_index%0#0 32u) + let computed#0: bytes = examples.merkle.contract.hash_pair(computed#0, tmp%1#0) goto block@3 - block@3: // for_footer_L27 - let item_index_internal%0#0: uint64 = (+ item_index_internal%0#0 1u) + block@3: // for_footer_L22 + goto block@4 + block@4: // for_increment_L22 + let range_item%0#0: uint64 = (+ range_item%0#0 1u) goto block@1 - block@4: // after_for_L27 - return computed#0 proof#0 leaf#0 + block@5: // after_for_L22 + return computed#0 proof#0 - subroutine examples.merkle.contract.MerkleTree.hash_pair(a: bytes, b: bytes) -> : - block@0: // L15 + subroutine examples.merkle.contract.hash_pair(a: bytes, b: bytes) -> bytes: + block@0: // L27 let tmp%0#0: uint64 = (b< a#0 b#0) goto tmp%0#0 ? block@1 : block@2 - block@1: // ternary_true_L18 + block@1: // ternary_true_L29 let ternary_result%0#0: bytes = (concat a#0 b#0) goto block@3 - block@2: // ternary_false_L18 + block@2: // ternary_false_L29 let ternary_result%0#0: bytes = (concat b#0 a#0) goto block@3 - block@3: // ternary_merge_L18 - let hash_bytes#0: bytes = (sha256 ternary_result%0#0) - return hash_bytes#0 a#0 b#0 + block@3: // ternary_merge_L29 + let tmp%1#0: bytes = (sha256 ternary_result%0#0) + return tmp%1#0 program clear-state: subroutine examples.merkle.contract.MerkleTree.clear_state_program() -> uint64: - block@0: // L14 + block@0: // L9 return 1u \ No newline at end of file diff --git a/examples/merkle/puya.log b/examples/merkle/puya.log index cb6d63b9ce..34f34db670 100644 --- a/examples/merkle/puya.log +++ b/examples/merkle/puya.log @@ -285,75 +285,76 @@ debug: Deleting Phi assignment: let sequence#1: bytes = φ(sequence#0 <- block@0 debug: Replaced trivial Phi node: let sequence#1: bytes = φ(sequence#0 <- block@0, sequence#1 <- block@4) (sequence#1) with sequence#0 in current definition for 3 blocks debug: Sealing block@None: // after_while_L11 debug: Terminated block@5: // after_while_L11 -debug: Sealing block@0: // L31 -debug: Terminated block@0: // L31 -debug: Sealing block@0: // L35 -debug: Terminated block@0: // L35 -debug: Sealing block@0: // L24 -debug: Terminated block@0: // L24 -debug: Looking for 'item_index_internal%0' in an unsealed block creating an incomplete Phi: block@1: // for_header_L27 -debug: Created Phi assignment: let item_index_internal%0#1: uint64 = undefined while trying to resolve 'item_index_internal%0' in block@1: // for_header_L27 -debug: Terminated block@1: // for_header_L27 -debug: Sealing block@None: // for_body_L27 -debug: Looking for 'computed' in an unsealed block creating an incomplete Phi: block@1: // for_header_L27 -debug: Created Phi assignment: let computed#1: bytes = undefined while trying to resolve 'computed' in block@1: // for_header_L27 -debug: Terminated block@2: // for_body_L27 -debug: Sealing block@3: // for_footer_L27 -debug: Sealing block@None: // after_for_L27 -debug: Terminated block@3: // for_footer_L27 -debug: Sealing block@1: // for_header_L27 -debug: Added item_index_internal%0#0 to Phi node: let item_index_internal%0#1: uint64 = φ(item_index_internal%0#0 <- block@0) in block@0: // L24 -debug: Added item_index_internal%0#2 to Phi node: let item_index_internal%0#1: uint64 = φ(item_index_internal%0#0 <- block@0, item_index_internal%0#2 <- block@3) in block@3: // for_footer_L27 -debug: Added computed#0 to Phi node: let computed#1: bytes = φ(computed#0 <- block@0) in block@0: // L24 -debug: Added computed#3 to Phi node: let computed#1: bytes = φ(computed#0 <- block@0, computed#3 <- block@3) in block@3: // for_footer_L27 -debug: Created Phi assignment: let proof#1: bytes = undefined while trying to resolve 'proof' in block@1: // for_header_L27 -debug: Added proof#0 to Phi node: let proof#1: bytes = φ(proof#0 <- block@0) in block@0: // L24 -debug: Added proof#1 to Phi node: let proof#1: bytes = φ(proof#0 <- block@0, proof#1 <- block@3) in block@3: // for_footer_L27 -debug: Replacing trivial Phi node: let proof#1: bytes = φ(proof#0 <- block@0, proof#1 <- block@3) (proof#1) with proof#0 -debug: Deleting Phi assignment: let proof#1: bytes = φ(proof#0 <- block@0, proof#1 <- block@3) -debug: Replaced trivial Phi node: let proof#1: bytes = φ(proof#0 <- block@0, proof#1 <- block@3) (proof#1) with proof#0 in current definition for 3 blocks -debug: Created Phi assignment: let leaf#1: bytes = undefined while trying to resolve 'leaf' in block@1: // for_header_L27 -debug: Added leaf#0 to Phi node: let leaf#1: bytes = φ(leaf#0 <- block@0) in block@0: // L24 -debug: Added leaf#1 to Phi node: let leaf#1: bytes = φ(leaf#0 <- block@0, leaf#1 <- block@3) in block@3: // for_footer_L27 -debug: Replacing trivial Phi node: let leaf#1: bytes = φ(leaf#0 <- block@0, leaf#1 <- block@3) (leaf#1) with leaf#0 -debug: Deleting Phi assignment: let leaf#1: bytes = φ(leaf#0 <- block@0, leaf#1 <- block@3) -debug: Replaced trivial Phi node: let leaf#1: bytes = φ(leaf#0 <- block@0, leaf#1 <- block@3) (leaf#1) with leaf#0 in current definition for 3 blocks -debug: Terminated block@4: // after_for_L27 -debug: Sealing block@0: // L15 -debug: Terminated block@0: // L15 -debug: Sealing block@None: // ternary_true_L18 -debug: Sealing block@None: // ternary_false_L18 -debug: Terminated block@1: // ternary_true_L18 -debug: Terminated block@2: // ternary_false_L18 -debug: Sealing block@3: // ternary_merge_L18 -debug: Created Phi assignment: let ternary_result%0#2: bytes = undefined while trying to resolve 'ternary_result%0' in block@3: // ternary_merge_L18 -debug: Added ternary_result%0#0 to Phi node: let ternary_result%0#2: bytes = φ(ternary_result%0#0 <- block@1) in block@1: // ternary_true_L18 -debug: Added ternary_result%0#1 to Phi node: let ternary_result%0#2: bytes = φ(ternary_result%0#0 <- block@1, ternary_result%0#1 <- block@2) in block@2: // ternary_false_L18 -debug: Created Phi assignment: let a#1: bytes = undefined while trying to resolve 'a' in block@3: // ternary_merge_L18 -debug: Added a#0 to Phi node: let a#1: bytes = φ(a#0 <- block@1) in block@1: // ternary_true_L18 -debug: Added a#0 to Phi node: let a#1: bytes = φ(a#0 <- block@1, a#0 <- block@2) in block@2: // ternary_false_L18 -debug: Replacing trivial Phi node: let a#1: bytes = φ(a#0 <- block@1, a#0 <- block@2) (a#1) with a#0 -debug: Deleting Phi assignment: let a#1: bytes = φ(a#0 <- block@1, a#0 <- block@2) -debug: Replaced trivial Phi node: let a#1: bytes = φ(a#0 <- block@1, a#0 <- block@2) (a#1) with a#0 in current definition for 1 blocks -debug: Created Phi assignment: let b#1: bytes = undefined while trying to resolve 'b' in block@3: // ternary_merge_L18 -debug: Added b#0 to Phi node: let b#1: bytes = φ(b#0 <- block@1) in block@1: // ternary_true_L18 -debug: Added b#0 to Phi node: let b#1: bytes = φ(b#0 <- block@1, b#0 <- block@2) in block@2: // ternary_false_L18 -debug: Replacing trivial Phi node: let b#1: bytes = φ(b#0 <- block@1, b#0 <- block@2) (b#1) with b#0 -debug: Deleting Phi assignment: let b#1: bytes = φ(b#0 <- block@1, b#0 <- block@2) -debug: Replaced trivial Phi node: let b#1: bytes = φ(b#0 <- block@1, b#0 <- block@2) (b#1) with b#0 in current definition for 1 blocks -debug: Terminated block@3: // ternary_merge_L18 -debug: Sealing block@0: // L14 -debug: Terminated block@0: // L14 -debug: Sealing block@None: // switch_case_default_L14 -debug: Sealing block@None: // create_route_L31 -debug: Sealing block@None: // verify_route_L35 -debug: Terminated block@1: // create_route_L31 -debug: Terminated block@2: // verify_route_L35 -debug: Terminated block@3: // switch_case_default_L14 -debug: Sealing block@4: // switch_case_next_L14 -debug: Terminated block@4: // switch_case_next_L14 +debug: Sealing block@0: // L10 +debug: Terminated block@0: // L10 debug: Sealing block@0: // L14 debug: Terminated block@0: // L14 +debug: Sealing block@0: // L19 +debug: Terminated block@0: // L19 +debug: Looking for 'range_item%0' in an unsealed block creating an incomplete Phi: block@1: // for_header_L22 +debug: Created Phi assignment: let range_item%0#1: uint64 = undefined while trying to resolve 'range_item%0' in block@1: // for_header_L22 +debug: Terminated block@1: // for_header_L22 +debug: Looking for 'range_item%0' in an unsealed block creating an incomplete Phi: block@2: // for_body_L22 +debug: Created Phi assignment: let range_item%0#2: uint64 = undefined while trying to resolve 'range_item%0' in block@2: // for_body_L22 +debug: Looking for 'computed' in an unsealed block creating an incomplete Phi: block@2: // for_body_L22 +debug: Created Phi assignment: let computed#1: bytes = undefined while trying to resolve 'computed' in block@2: // for_body_L22 +debug: Looking for 'proof' in an unsealed block creating an incomplete Phi: block@2: // for_body_L22 +debug: Created Phi assignment: let proof#1: bytes = undefined while trying to resolve 'proof' in block@2: // for_body_L22 +debug: Terminated block@2: // for_body_L22 +debug: Sealing block@3: // for_footer_L22 +debug: Terminated block@3: // for_footer_L22 +debug: Sealing block@4: // for_increment_L22 +debug: Terminated block@4: // for_increment_L22 +debug: Sealing block@1: // for_header_L22 +debug: Added range_item%0#0 to Phi node: let range_item%0#1: uint64 = φ(range_item%0#0 <- block@0) in block@0: // L19 +debug: Added range_item%0#3 to Phi node: let range_item%0#1: uint64 = φ(range_item%0#0 <- block@0, range_item%0#3 <- block@4) in block@4: // for_increment_L22 +debug: Sealing block@2: // for_body_L22 +debug: Added range_item%0#1 to Phi node: let range_item%0#2: uint64 = φ(range_item%0#1 <- block@1) in block@1: // for_header_L22 +debug: Replacing trivial Phi node: let range_item%0#2: uint64 = φ(range_item%0#1 <- block@1) (range_item%0#2) with range_item%0#1 +debug: Deleting Phi assignment: let range_item%0#2: uint64 = φ(range_item%0#1 <- block@1) +debug: Replaced trivial Phi node: let range_item%0#2: uint64 = φ(range_item%0#1 <- block@1) (range_item%0#2) with range_item%0#1 in current definition for 2 blocks +debug: Created Phi assignment: let computed#3: bytes = undefined while trying to resolve 'computed' in block@1: // for_header_L22 +debug: Added computed#0 to Phi node: let computed#3: bytes = φ(computed#0 <- block@0) in block@0: // L19 +debug: Added computed#2 to Phi node: let computed#3: bytes = φ(computed#0 <- block@0, computed#2 <- block@4) in block@4: // for_increment_L22 +debug: Added computed#3 to Phi node: let computed#1: bytes = φ(computed#3 <- block@1) in block@1: // for_header_L22 +debug: Replacing trivial Phi node: let computed#1: bytes = φ(computed#3 <- block@1) (computed#1) with computed#3 +debug: Deleting Phi assignment: let computed#1: bytes = φ(computed#3 <- block@1) +debug: Replaced trivial Phi node: let computed#1: bytes = φ(computed#3 <- block@1) (computed#1) with computed#3 in current definition for 0 blocks +debug: Created Phi assignment: let proof#2: bytes = undefined while trying to resolve 'proof' in block@1: // for_header_L22 +debug: Added proof#0 to Phi node: let proof#2: bytes = φ(proof#0 <- block@0) in block@0: // L19 +debug: Added proof#1 to Phi node: let proof#2: bytes = φ(proof#0 <- block@0, proof#1 <- block@4) in block@4: // for_increment_L22 +debug: Added proof#2 to Phi node: let proof#1: bytes = φ(proof#2 <- block@1) in block@1: // for_header_L22 +debug: Replacing trivial Phi node: let proof#1: bytes = φ(proof#2 <- block@1) (proof#1) with proof#2 +debug: Deleting Phi assignment: let proof#1: bytes = φ(proof#2 <- block@1) +debug: Replacing trivial Phi node: let proof#2: bytes = φ(proof#0 <- block@0, proof#2 <- block@4) (proof#2) with proof#0 +debug: Deleting Phi assignment: let proof#2: bytes = φ(proof#0 <- block@0, proof#2 <- block@4) +debug: Replaced trivial Phi node: let proof#1: bytes = φ(proof#2 <- block@1) (proof#1) with proof#2 in current definition for 3 blocks +debug: Replaced trivial Phi node: let proof#2: bytes = φ(proof#0 <- block@0, proof#2 <- block@4) (proof#2) with proof#0 in current definition for 4 blocks +debug: Sealing block@None: // after_for_L22 +debug: Terminated block@5: // after_for_L22 +debug: Sealing block@0: // L27 +debug: Terminated block@0: // L27 +debug: Sealing block@None: // ternary_true_L29 +debug: Sealing block@None: // ternary_false_L29 +debug: Terminated block@1: // ternary_true_L29 +debug: Terminated block@2: // ternary_false_L29 +debug: Sealing block@3: // ternary_merge_L29 +debug: Created Phi assignment: let ternary_result%0#2: bytes = undefined while trying to resolve 'ternary_result%0' in block@3: // ternary_merge_L29 +debug: Added ternary_result%0#0 to Phi node: let ternary_result%0#2: bytes = φ(ternary_result%0#0 <- block@1) in block@1: // ternary_true_L29 +debug: Added ternary_result%0#1 to Phi node: let ternary_result%0#2: bytes = φ(ternary_result%0#0 <- block@1, ternary_result%0#1 <- block@2) in block@2: // ternary_false_L29 +debug: Terminated block@3: // ternary_merge_L29 +debug: Sealing block@0: // L9 +debug: Terminated block@0: // L9 +debug: Sealing block@None: // switch_case_default_L9 +debug: Sealing block@None: // create_route_L10 +debug: Sealing block@None: // verify_route_L14 +debug: Terminated block@1: // create_route_L10 +debug: Terminated block@2: // verify_route_L14 +debug: Terminated block@3: // switch_case_default_L9 +debug: Sealing block@4: // switch_case_next_L9 +debug: Terminated block@4: // switch_case_next_L9 +debug: Sealing block@0: // L9 +debug: Terminated block@0: // L9 debug: Output IR to merkle/out/MerkleTree.ssa.ir info: Optimizing examples.merkle.contract.MerkleTree at level 1 debug: Begin optimization pass 1/100 @@ -367,22 +368,20 @@ debug: Simplified (== tmp%6#0 NoOp) to (! tmp%6#0) debug: Optimizer: Remove Unused Variables debug: Optimizer: Simplify Control Ops debug: inlining the default target of a switch/goto nth -debug: adding block@0: // L14 as a predecessor of block@4: // switch_case_next_L14 due to inlining of block@3: // switch_case_default_L14 -debug: simplified terminator of block@0: // L14 from switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => block@3} to switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => block@4} +debug: adding block@0: // L9 as a predecessor of block@4: // switch_case_next_L9 due to inlining of block@3: // switch_case_default_L9 +debug: simplified terminator of block@0: // L9 from switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => block@3} to switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => block@4} debug: inlining the default target of a switch/goto nth -debug: simplified terminator of block@0: // L14 from switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => block@4} to switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => fail // reject transaction} +debug: simplified terminator of block@0: // L9 from switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => block@4} to switch tmp%0#0 {method "create(byte[32])void" => block@1, method "verify(byte[32][],byte[32])bool" => block@2, * => fail // reject transaction} debug: Optimizer: Remove Linear Jump -debug: Merged linear block@4: // switch_case_next_L14 into block@3: // switch_case_default_L14 +debug: Merged linear block@4: // switch_case_next_L9 into block@3: // switch_case_default_L9 debug: Optimizer: Remove Empty Blocks debug: Optimizer: Remove Unreachable Blocks -debug: Removing unreachable blocks: block@3: // switch_case_default_L14 +debug: Removing unreachable blocks: block@3: // switch_case_default_L9 debug: Optimizer: Repeated Expression Elimination debug: Optimizing subroutine examples.merkle.contract.MerkleTree.create debug: Splitting parallel copies prior to optimization debug: Optimizer: Constant Replacer debug: Optimizer: Copy Propagation -debug: Found equivalence set: root#0, copy%0#0 -debug: Replacing {copy%0#0} with root#0 made 1 modifications debug: Optimizer: Intrinsic Simplifier debug: Optimizer: Remove Unused Variables debug: Optimizer: Simplify Control Ops @@ -394,8 +393,6 @@ debug: Optimizing subroutine examples.merkle.contract.MerkleTree.verify debug: Splitting parallel copies prior to optimization debug: Optimizer: Constant Replacer debug: Optimizer: Copy Propagation -debug: Found equivalence set: compute_root_hash%2#0, leaf#1 -debug: Replacing {compute_root_hash%2#0} with leaf#1 made 1 modifications debug: Found equivalence set: compute_root_hash%1#0, proof#1 debug: Replacing {compute_root_hash%1#0} with proof#1 made 1 modifications debug: Optimizer: Intrinsic Simplifier @@ -405,29 +402,32 @@ debug: Optimizer: Remove Linear Jump debug: Optimizer: Remove Empty Blocks debug: Optimizer: Remove Unreachable Blocks debug: Optimizer: Repeated Expression Elimination -debug: Optimizing subroutine examples.merkle.contract.MerkleTree.compute_root_hash +debug: Optimizing subroutine examples.merkle.contract.compute_root_hash debug: Splitting parallel copies prior to optimization debug: Optimizer: Constant Replacer debug: Optimizer: Copy Propagation -debug: Found equivalence set: leaf#0, copy%0#0, computed#0 -debug: Replacing {copy%0#0, computed#0} with leaf#0 made 1 modifications -debug: Found equivalence set: array_length%0#0, reverse_index_internal%0#0 -debug: Found equivalence set: hash_pair%2#0, proof_hash#1 -debug: Replacing {hash_pair%2#0} with proof_hash#1 made 1 modifications -debug: Found equivalence set: hash_pair%1#0, computed#2 -debug: Replacing {hash_pair%1#0} with computed#2 made 1 modifications -debug: Found equivalence set: hash_pair%0#0, computed#3 -debug: Replacing {hash_pair%0#0} with computed#3 made 1 modifications +debug: Found equivalence set: leaf#0, computed#0 +debug: Replacing {computed#0} with leaf#0 made 1 modifications +debug: Found equivalence set: range_item%0#1, idx#0 +debug: Replacing {range_item%0#1} with idx#0 made 3 modifications debug: Optimizer: Intrinsic Simplifier debug: Optimizer: Remove Unused Variables debug: Optimizer: Simplify Control Ops debug: Optimizer: Remove Linear Jump -debug: Replaced predecessor block@3: // for_footer_L27 with block@2: // for_body_L27 in block@1: // for_header_L27 -debug: Merged linear block@3: // for_footer_L27 into block@2: // for_body_L27 +debug: Replaced predecessor block@3: // for_footer_L22 with block@2: // for_body_L22 in block@4: // for_increment_L22 +debug: Merged linear block@3: // for_footer_L22 into block@2: // for_body_L22 +debug: Replaced predecessor block@4: // for_increment_L22 with block@2: // for_body_L22 in block@1: // for_header_L22 +debug: Merged linear block@4: // for_increment_L22 into block@2: // for_body_L22 debug: Optimizer: Remove Empty Blocks debug: Optimizer: Remove Unreachable Blocks debug: Optimizer: Repeated Expression Elimination -debug: Optimizing subroutine examples.merkle.contract.MerkleTree.hash_pair +debug: Replacing redundant declaration let array_length%0#0: uint64 = (extract_uint16 proof#0 0u) with copy of existing registers [Register(atype=uint64, name='tmp%0', version=0, source_location=merkle/contract.py:22:22-34)] +debug: Found equivalence set: tmp%0#0, array_length%0#0 +debug: Replacing {array_length%0#0} with tmp%0#0 made 1 modifications +debug: Replacing redundant declaration let index_is_in_bounds%0#0: uint64 = (< idx#0 tmp%0#0) with copy of existing registers [Register(atype=uint64, name='continue_looping%0', version=0, source_location=merkle/contract.py:22:15-35)] +debug: Found equivalence set: continue_looping%0#0, index_is_in_bounds%0#0 +debug: Replacing {index_is_in_bounds%0#0} with continue_looping%0#0 made 1 modifications +debug: Optimizing subroutine examples.merkle.contract.hash_pair debug: Splitting parallel copies prior to optimization debug: Optimizer: Constant Replacer debug: Optimizer: Copy Propagation @@ -481,7 +481,7 @@ debug: Optimizer: Remove Linear Jump debug: Optimizer: Remove Empty Blocks debug: Optimizer: Remove Unreachable Blocks debug: Optimizer: Repeated Expression Elimination -debug: Optimizing subroutine examples.merkle.contract.MerkleTree.compute_root_hash +debug: Optimizing subroutine examples.merkle.contract.compute_root_hash debug: Optimizer: Constant Replacer debug: Optimizer: Copy Propagation debug: Optimizer: Intrinsic Simplifier @@ -491,7 +491,7 @@ debug: Optimizer: Remove Linear Jump debug: Optimizer: Remove Empty Blocks debug: Optimizer: Remove Unreachable Blocks debug: Optimizer: Repeated Expression Elimination -debug: Optimizing subroutine examples.merkle.contract.MerkleTree.hash_pair +debug: Optimizing subroutine examples.merkle.contract.hash_pair debug: Optimizer: Constant Replacer debug: Optimizer: Copy Propagation debug: Optimizer: Intrinsic Simplifier @@ -515,8 +515,8 @@ debug: No optimizations performed in pass 2, ending loop debug: Removing Phis from examples.merkle.contract.MerkleTree.approval_program debug: Removing Phis from examples.merkle.contract.MerkleTree.create debug: Removing Phis from examples.merkle.contract.MerkleTree.verify -debug: Removing Phis from examples.merkle.contract.MerkleTree.compute_root_hash -debug: Removing Phis from examples.merkle.contract.MerkleTree.hash_pair +debug: Removing Phis from examples.merkle.contract.compute_root_hash +debug: Removing Phis from examples.merkle.contract.hash_pair debug: Removing Phis from examples.merkle.contract.MerkleTree.clear_state_program debug: Coalescing local variables in examples.merkle.contract.MerkleTree.approval_program using strategy RootOperandGrouping debug: Coalescing resulted in 0 replacement/s @@ -524,14 +524,13 @@ debug: Coalescing local variables in examples.merkle.contract.MerkleTree.create debug: Coalescing resulted in 0 replacement/s debug: Coalescing local variables in examples.merkle.contract.MerkleTree.verify using strategy RootOperandGrouping debug: Coalescing proof#0 with [proof#1] -debug: Coalescing leaf#0 with [leaf#1] -debug: Coalescing resulted in 2 replacement/s -debug: Coalescing local variables in examples.merkle.contract.MerkleTree.compute_root_hash using strategy RootOperandGrouping -debug: Coalescing item_index_internal%0#0 with [item_index_internal%0#5, item_index_internal%0#1, item_index_internal%0#2] -debug: Coalescing computed#1 with [computed#5, computed#3] -debug: Coalescing proof_hash#0 with [proof_hash#1] -debug: Coalescing resulted in 15 replacement/s -debug: Coalescing local variables in examples.merkle.contract.MerkleTree.hash_pair using strategy RootOperandGrouping +debug: Coalescing resulted in 1 replacement/s +debug: Coalescing local variables in examples.merkle.contract.compute_root_hash using strategy RootOperandGrouping +debug: Coalescing range_item%0#0 with [range_item%0#3] +debug: Coalescing idx#0 with [idx#1] +debug: Coalescing computed#2 with [computed#5, computed#3] +debug: Coalescing resulted in 11 replacement/s +debug: Coalescing local variables in examples.merkle.contract.hash_pair using strategy RootOperandGrouping debug: Coalescing ternary_result%0#0 with [ternary_result%0#5, ternary_result%0#1, ternary_result%0#2] debug: Coalescing resulted in 7 replacement/s debug: Coalescing local variables in examples.merkle.contract.MerkleTree.clear_state_program using strategy RootOperandGrouping @@ -539,28 +538,32 @@ debug: Coalescing resulted in 0 replacement/s debug: Sequentializing parallel copies in examples.merkle.contract.MerkleTree.approval_program debug: Sequentializing parallel copies in examples.merkle.contract.MerkleTree.create debug: Sequentializing parallel copies in examples.merkle.contract.MerkleTree.verify -debug: Sequentializing parallel copies in examples.merkle.contract.MerkleTree.compute_root_hash -debug: loc: {item_index_internal%0#0=item_index_internal%0#0, computed#1=None, leaf#0=leaf#0} -debug: pred: {item_index_internal%0#0=item_index_internal%0#0, computed#1=leaf#0} -debug: ready: computed#1 -debug: to_do: item_index_internal%0#0, computed#1 -debug: * avail computed#1 +debug: Sequentializing parallel copies in examples.merkle.contract.compute_root_hash +debug: loc: {idx#0=None, computed#2=None, range_item%0#0=range_item%0#0, leaf#0=leaf#0} +debug: pred: {idx#0=range_item%0#0, computed#2=leaf#0} +debug: ready: idx#0, computed#2 +debug: to_do: idx#0, computed#2 +debug: * avail computed#2 debug: * avail leaf#0 -debug: * to_do computed#1 -debug: * to_do item_index_internal%0#0 -debug: loc: {item_index_internal%0#0=item_index_internal%0#0, computed#1=computed#1} -debug: pred: {item_index_internal%0#0=item_index_internal%0#0, computed#1=computed#1} -debug: ready: -debug: to_do: item_index_internal%0#0, computed#1 -debug: * to_do computed#1 -debug: * to_do item_index_internal%0#0 -debug: loc: {item_index_internal%0#0=item_index_internal%0#0, computed#1=computed#1} -debug: pred: {item_index_internal%0#0=item_index_internal%0#0, computed#1=computed#1} +debug: * avail idx#0 +debug: * avail range_item%0#0 +debug: * to_do computed#2 +debug: * to_do idx#0 +debug: loc: {idx#0=idx#0, computed#2=computed#2} +debug: pred: {idx#0=idx#0, computed#2=computed#2} debug: ready: -debug: to_do: item_index_internal%0#0, computed#1 -debug: * to_do computed#1 -debug: * to_do item_index_internal%0#0 -debug: Sequentializing parallel copies in examples.merkle.contract.MerkleTree.hash_pair +debug: to_do: idx#0, computed#2 +debug: * to_do computed#2 +debug: * to_do idx#0 +debug: loc: {idx#0=None, computed#2=computed#2, range_item%0#0=range_item%0#0} +debug: pred: {idx#0=range_item%0#0, computed#2=computed#2} +debug: ready: idx#0 +debug: to_do: idx#0, computed#2 +debug: * avail idx#0 +debug: * avail range_item%0#0 +debug: * to_do computed#2 +debug: * to_do idx#0 +debug: Sequentializing parallel copies in examples.merkle.contract.hash_pair debug: Sequentializing parallel copies in examples.merkle.contract.MerkleTree.clear_state_program debug: Performing post-SSA optimizations debug: Output IR to merkle/out/MerkleTree.destructured.ir @@ -593,30 +596,36 @@ debug: Replaced main_verify_route@2.ops[20]: 'load tmp%9#0' with 'load tmp%9#0 f debug: Inserted main_verify_route@2.ops[23]: 'store tmp%11#0 to l-stack (copy)' debug: Replaced main_verify_route@2.ops[27]: 'load tmp%11#0' with 'load tmp%11#0 from l-stack (no copy)' debug: Found 1 edge set/s for examples.merkle.contract.MerkleTree.approval_program -debug: Inserted verify_block@0.ops[16]: 'store tmp%0#0 to l-stack (copy)' -debug: Replaced verify_block@0.ops[18]: 'load tmp%0#0' with 'load tmp%0#0 from l-stack (no copy)' +debug: Inserted verify_block@0.ops[15]: 'store tmp%0#0 to l-stack (copy)' +debug: Replaced verify_block@0.ops[17]: 'load tmp%0#0' with 'load tmp%0#0 from l-stack (no copy)' debug: Inserted verify_block@0.ops[3]: 'store root_exists%0#0 to l-stack (copy)' debug: Replaced verify_block@0.ops[6]: 'load root_exists%0#0' with 'load root_exists%0#0 from l-stack (no copy)' -debug: Inserted verify_block@0.ops[13]: 'store compute_root_hash%0#0 to l-stack (copy)' -debug: Replaced verify_block@0.ops[16]: 'load compute_root_hash%0#0' with 'load compute_root_hash%0#0 from l-stack (no copy)' +debug: Inserted verify_block@0.ops[12]: 'store compute_root_hash%0#0 to l-stack (copy)' +debug: Replaced verify_block@0.ops[15]: 'load compute_root_hash%0#0' with 'load compute_root_hash%0#0 from l-stack (no copy)' debug: Inserted verify_block@0.ops[5]: 'store root_value%0#0 to l-stack (copy)' -debug: Replaced verify_block@0.ops[16]: 'load root_value%0#0' with 'load root_value%0#0 from l-stack (no copy)' +debug: Replaced verify_block@0.ops[15]: 'load root_value%0#0' with 'load root_value%0#0 from l-stack (no copy)' +debug: Inserted compute_root_hash_block@0.ops[5]: 'store range_item%0#0 to l-stack (copy)' +debug: Replaced compute_root_hash_block@0.ops[9]: 'load range_item%0#0' with 'load range_item%0#0 from l-stack (no copy)' debug: Inserted compute_root_hash_for_header@1.ops[3]: 'store continue_looping%0#0 to l-stack (copy)' debug: Replaced compute_root_hash_for_header@1.ops[5]: 'load continue_looping%0#0' with 'load continue_looping%0#0 from l-stack (no copy)' -debug: Inserted compute_root_hash_for_body@2.ops[3]: 'store item_index%0#0 to l-stack (copy)' -debug: Replaced compute_root_hash_for_body@2.ops[6]: 'load item_index%0#0' with 'load item_index%0#0 from l-stack (no copy)' -debug: Inserted compute_root_hash_for_body@2.ops[9]: 'store proof_hash#0 to l-stack (copy)' -debug: Replaced compute_root_hash_for_body@2.ops[12]: 'load proof_hash#0' with 'load proof_hash#0 from l-stack (no copy)' -debug: Inserted compute_root_hash_for_body@2.ops[1]: 'store item_index_internal%0#0 to l-stack (copy)' -debug: Replaced compute_root_hash_for_body@2.ops[18]: 'load item_index_internal%0#0' with 'load item_index_internal%0#0 from l-stack (no copy)' -debug: Found 2 edge set/s for examples.merkle.contract.MerkleTree.compute_root_hash -debug: examples.merkle.contract.MerkleTree.compute_root_hash f-stack entry: [] -debug: examples.merkle.contract.MerkleTree.compute_root_hash f-stack on first store: ['array_length%0#0', 'array_value%0#0', 'item_index_internal%0#0', 'computed#1'] +debug: Inserted compute_root_hash_for_body@2.ops[21]: 'store range_item%0#0 to l-stack (copy)' +debug: Replaced compute_root_hash_for_body@2.ops[23]: 'load range_item%0#0' with 'load range_item%0#0 from l-stack (no copy)' +debug: Inserted compute_root_hash_for_body@2.ops[8]: 'store item_index%0#0 to l-stack (copy)' +debug: Replaced compute_root_hash_for_body@2.ops[11]: 'load item_index%0#0' with 'load item_index%0#0 from l-stack (no copy)' +debug: Inserted compute_root_hash_for_body@2.ops[14]: 'store tmp%1#0 to l-stack (copy)' +debug: Replaced compute_root_hash_for_body@2.ops[17]: 'load tmp%1#0' with 'load tmp%1#0 from l-stack (no copy)' +debug: Inserted compute_root_hash_for_body@2.ops[4]: 'store array_data_sans_header%0#0 to l-stack (copy)' +debug: Replaced compute_root_hash_for_body@2.ops[11]: 'load array_data_sans_header%0#0' with 'load array_data_sans_header%0#0 from l-stack (no copy)' +debug: Inserted compute_root_hash_for_body@2.ops[7]: 'store idx#0 to l-stack (copy)' +debug: Replaced compute_root_hash_for_body@2.ops[22]: 'load idx#0' with 'load idx#0 from l-stack (no copy)' +debug: Found 2 edge set/s for examples.merkle.contract.compute_root_hash +debug: examples.merkle.contract.compute_root_hash f-stack entry: ['continue_looping%0#0'] +debug: examples.merkle.contract.compute_root_hash f-stack on first store: ['tmp%0#0', 'computed#2', 'idx#0'] debug: Inserted hash_pair_block@0.ops[3]: 'store tmp%0#0 to l-stack (copy)' debug: Replaced hash_pair_block@0.ops[5]: 'load tmp%0#0' with 'load tmp%0#0 from l-stack (no copy)' -debug: Inserted hash_pair_ternary_merge@3.ops[2]: 'store hash_bytes#0 to l-stack (copy)' -debug: Replaced hash_pair_ternary_merge@3.ops[4]: 'load hash_bytes#0' with 'load hash_bytes#0 from l-stack (no copy)' -debug: Found 2 edge set/s for examples.merkle.contract.MerkleTree.hash_pair +debug: Inserted hash_pair_ternary_merge@3.ops[2]: 'store tmp%1#0 to l-stack (copy)' +debug: Replaced hash_pair_ternary_merge@3.ops[4]: 'load tmp%1#0' with 'load tmp%1#0 from l-stack (no copy)' +debug: Found 2 edge set/s for examples.merkle.contract.hash_pair debug: Allocated 1 variable/s to x-stack: ternary_result%0#0 debug: shared x-stack for hash_pair_ternary_true@1 -> hash_pair_ternary_merge@3: ternary_result%0#0 debug: shared x-stack for hash_pair_ternary_false@2 -> hash_pair_ternary_merge@3: ternary_result%0#0 diff --git a/examples/sizes.txt b/examples/sizes.txt index 25021569f0..e794ac024a 100644 --- a/examples/sizes.txt +++ b/examples/sizes.txt @@ -54,7 +54,7 @@ logic_signature/always_allow 4 4 0 4 0 logic_signature/pre_approved_sale 136 136 0 136 0 match 490 455 35 455 0 - merkle/MerkleTree 217 210 7 210 0 + merkle/MerkleTree 214 205 9 205 0 nested_loops/Nested 243 201 42 201 0 regression_118 135 100 35 100 0 reversed_iteration 765 547 218 547 0 diff --git a/src/puya/awst_build/eb/arc4/arrays.py b/src/puya/awst_build/eb/arc4/arrays.py index 33063b9821..05bc0f4036 100644 --- a/src/puya/awst_build/eb/arc4/arrays.py +++ b/src/puya/awst_build/eb/arc4/arrays.py @@ -297,6 +297,12 @@ class ARC4ArrayExpressionBuilder(ValueExpressionBuilder, ABC): wtype: wtypes.ARC4DynamicArray | wtypes.ARC4StaticArray def iterate(self) -> Iteration: + if not self.wtype.element_type.immutable: + logger.error( + "Cannot directly iterate an ARC4 array of mutable objects," + " construct a for-loop over the indexes via urange(.length) instead", + location=self.source_location, + ) return self.rvalue() def index( diff --git a/src/puya/ir/builder/iteration.py b/src/puya/ir/builder/iteration.py index 780bf78d73..c13cfefc14 100644 --- a/src/puya/ir/builder/iteration.py +++ b/src/puya/ir/builder/iteration.py @@ -138,6 +138,13 @@ def get_byte_at_index(index_register: Register) -> ValueProvider: reverse_index=reverse_index, reverse_items=reverse_items, ) + case awst_nodes.Expression( + wtype=wtypes.ARC4Array(element_type=wtypes.WType(immutable=False)) + ): + raise InternalError( + "Attempted iteration of an ARC4 array of mutable objects", + sequence.source_location, + ) case awst_nodes.Expression( wtype=wtypes.ARC4DynamicArray() as dynamic_array_wtype ) as arc4_dynamic_array_expression: diff --git a/tests/test_expected_output/expected_errors.test b/tests/test_expected_output/expected_errors.test index 1e6318a872..3e982dd22f 100644 --- a/tests/test_expected_output/expected_errors.test +++ b/tests/test_expected_output/expected_errors.test @@ -1,3 +1,7 @@ +# ruff: noqa +# fmt: off +# type: ignore + ## case: test_typing_interactions import typing @@ -66,3 +70,36 @@ class ContractWithUndefinedVariable(Contract): def clear_state_program(self) -> bool: return True + + + +## case: test_arc4_mutable_iteration + +from algopy import * + +@subroutine +def okay1() -> None: + arr = arc4.DynamicBytes() + for b in arr: + assert b + +@subroutine +def baddie1() -> None: + arr_of_arr = arc4.DynamicArray[arc4.DynamicBytes]() + for arr in arr_of_arr: ## E: Cannot directly iterate an ARC4 array of mutable objects, construct a for-loop over the indexes via urange(.length) instead + arr.append(arc4.Byte(1)) + + +@subroutine +def okay2() -> None: + arr_of_tup = arc4.DynamicArray[arc4.Tuple[arc4.UInt64, arc4.UInt64]]() + for tup in arr_of_tup: + assert tup[0] == tup[1] + + +@subroutine +def baddie2() -> None: + arr_of_tup_with_arr = arc4.DynamicArray[arc4.Tuple[arc4.DynamicBytes, arc4.UInt64]]() + for tup in arr_of_tup_with_arr: ## E: Cannot directly iterate an ARC4 array of mutable objects, construct a for-loop over the indexes via urange(.length) instead + tup[0].append(arc4.Byte(1)) +