Skip to content

Commit

Permalink
fix: Prevent iteration of arc4 containers with mutable items
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
Direct iteration of arc4 containers with mutable items is no longer possible due to issues with the reference vs value semantics, instead use `for <index> in urange(<array>.length)` and access/update elements by index.
  • Loading branch information
achidlow committed Mar 26, 2024
1 parent 7f7a4b6 commit f857181
Show file tree
Hide file tree
Showing 20 changed files with 716 additions and 685 deletions.
40 changes: 16 additions & 24 deletions examples/merkle/contract.py
Original file line number Diff line number Diff line change
@@ -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)
324 changes: 163 additions & 161 deletions examples/merkle/out/MerkleTree.approval.mir

Large diffs are not rendered by default.

124 changes: 54 additions & 70 deletions examples/merkle/out/MerkleTree.approval.teal
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -10,36 +10,36 @@ 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
!
assert // OnCompletion is NoOp
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
Expand All @@ -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
Expand All @@ -70,124 +70,108 @@ 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
assert // check root exists
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
4 changes: 2 additions & 2 deletions examples/merkle/out/MerkleTree.arc32.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
}
},
"source": {
"approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5hcHByb3ZhbF9wcm9ncmFtOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE0CiAgICAvLyBjbGFzcyBNZXJrbGVUcmVlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIG1ldGhvZCAiY3JlYXRlKGJ5dGVbMzJdKXZvaWQiCiAgICBtZXRob2QgInZlcmlmeShieXRlWzMyXVtdLGJ5dGVbMzJdKWJvb2wiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBtYWluX2NyZWF0ZV9yb3V0ZUAxIG1haW5fdmVyaWZ5X3JvdXRlQDIKICAgIGVyciAvLyByZWplY3QgdHJhbnNhY3Rpb24KCm1haW5fY3JlYXRlX3JvdXRlQDE6CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MzEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChjcmVhdGU9VHJ1ZSkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgICEKICAgIGFzc2VydCAvLyBpcyBjcmVhdGluZwogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE0CiAgICAvLyBjbGFzcyBNZXJrbGVUcmVlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weTozMQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGNyZWF0ZT1UcnVlKQogICAgY2FsbHN1YiBjcmVhdGUKICAgIGludCAxCiAgICByZXR1cm4KCm1haW5fdmVyaWZ5X3JvdXRlQDI6CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MzUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGlzIG5vdCBjcmVhdGluZwogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE0CiAgICAvLyBjbGFzcyBNZXJrbGVUcmVlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDIKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weTozNQogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICBjYWxsc3ViIHZlcmlmeQogICAgYnl0ZSAweDAwCiAgICBpbnQgMAogICAgdW5jb3ZlciAyCiAgICBzZXRiaXQKICAgIGJ5dGUgMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludCAxCiAgICByZXR1cm4KCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5jcmVhdGUocm9vdDogYnl0ZXMpIC0+IHZvaWQ6CmNyZWF0ZToKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weTozMS0zMgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGNyZWF0ZT1UcnVlKQogICAgLy8gZGVmIGNyZWF0ZShzZWxmLCByb290OiBCeXRlczMyKSAtPiBOb25lOgogICAgcHJvdG8gMSAwCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MzMKICAgIC8vIHNlbGYucm9vdCA9IHJvb3QuY29weSgpCiAgICBieXRlICJyb290IgogICAgZnJhbWVfZGlnIC0xCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgcmV0c3ViCgoKLy8gZXhhbXBsZXMubWVya2xlLmNvbnRyYWN0Lk1lcmtsZVRyZWUudmVyaWZ5KHByb29mOiBieXRlcywgbGVhZjogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5OgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjM1LTM2CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIC8vIGRlZiB2ZXJpZnkoc2VsZiwgcHJvb2Y6IFByb29mLCBsZWFmOiBCeXRlczMyKSAtPiBib29sOgogICAgcHJvdG8gMiAxCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MzcKICAgIC8vIHJldHVybiBzZWxmLnJvb3QgPT0gc2VsZi5jb21wdXRlX3Jvb3RfaGFzaChwcm9vZiwgbGVhZikKICAgIGludCAwCiAgICBieXRlICJyb290IgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayByb290IGV4aXN0cwogICAgZnJhbWVfZGlnIC0yCiAgICBmcmFtZV9kaWcgLTEKICAgIGNhbGxzdWIgY29tcHV0ZV9yb290X2hhc2gKICAgIGZyYW1lX2J1cnkgLTEKICAgIGZyYW1lX2J1cnkgLTIKICAgID09CiAgICByZXRzdWIKCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5jb21wdXRlX3Jvb3RfaGFzaChwcm9vZjogYnl0ZXMsIGxlYWY6IGJ5dGVzKSAtPiBieXRlcywgYnl0ZXMsIGJ5dGVzOgpjb21wdXRlX3Jvb3RfaGFzaDoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyNC0yNQogICAgLy8gQHN1YnJvdXRpbmUKICAgIC8vIGRlZiBjb21wdXRlX3Jvb3RfaGFzaChzZWxmLCBwcm9vZjogUHJvb2YsIGxlYWY6IEJ5dGVzMzIpIC0+IEJ5dGVzMzI6CiAgICBwcm90byAyIDMKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyNwogICAgLy8gZm9yIHByb29mX2hhc2ggaW4gcHJvb2Y6CiAgICBmcmFtZV9kaWcgLTIKICAgIGludCAwCiAgICBleHRyYWN0X3VpbnQxNgogICAgZnJhbWVfZGlnIC0yCiAgICBleHRyYWN0IDIgMAogICAgaW50IDAKICAgIGZyYW1lX2RpZyAtMQoKY29tcHV0ZV9yb290X2hhc2hfZm9yX2hlYWRlckAxOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjI3CiAgICAvLyBmb3IgcHJvb2ZfaGFzaCBpbiBwcm9vZjoKICAgIGZyYW1lX2RpZyAyCiAgICBmcmFtZV9kaWcgMAogICAgPAogICAgYnogY29tcHV0ZV9yb290X2hhc2hfYWZ0ZXJfZm9yQDQKICAgIGZyYW1lX2RpZyAyCiAgICBkdXAKICAgIGludCAzMgogICAgKgogICAgZnJhbWVfZGlnIDEKICAgIHN3YXAKICAgIGludCAzMgogICAgZXh0cmFjdDMKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyOAogICAgLy8gY29tcHV0ZWQgPSBzZWxmLmhhc2hfcGFpcihjb21wdXRlZCwgcHJvb2ZfaGFzaCkKICAgIGZyYW1lX2RpZyAzCiAgICBzd2FwCiAgICBjYWxsc3ViIGhhc2hfcGFpcgogICAgcG9wbiAyCiAgICBmcmFtZV9idXJ5IDMKICAgIGludCAxCiAgICArCiAgICBmcmFtZV9idXJ5IDIKICAgIGIgY29tcHV0ZV9yb290X2hhc2hfZm9yX2hlYWRlckAxCgpjb21wdXRlX3Jvb3RfaGFzaF9hZnRlcl9mb3JANDoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyOQogICAgLy8gcmV0dXJuIGNvbXB1dGVkCiAgICBmcmFtZV9kaWcgMwogICAgZnJhbWVfZGlnIC0yCiAgICBmcmFtZV9kaWcgLTEKICAgIGZyYW1lX2J1cnkgMgogICAgZnJhbWVfYnVyeSAxCiAgICBmcmFtZV9idXJ5IDAKICAgIHJldHN1YgoKCi8vIGV4YW1wbGVzLm1lcmtsZS5jb250cmFjdC5NZXJrbGVUcmVlLmhhc2hfcGFpcihhOiBieXRlcywgYjogYnl0ZXMpIC0+IGJ5dGVzLCBieXRlcywgYnl0ZXM6Cmhhc2hfcGFpcjoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxNS0xNgogICAgLy8gQHN1YnJvdXRpbmUKICAgIC8vIGRlZiBoYXNoX3BhaXIoc2VsZiwgYTogQnl0ZXMzMiwgYjogQnl0ZXMzMikgLT4gQnl0ZXMzMjoKICAgIHByb3RvIDIgMwogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE5CiAgICAvLyBpZiBCaWdVSW50LmZyb21fYnl0ZXMoYS5ieXRlcykgPCBCaWdVSW50LmZyb21fYnl0ZXMoYi5ieXRlcykKICAgIGZyYW1lX2RpZyAtMgogICAgZnJhbWVfZGlnIC0xCiAgICBiPAogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE4LTIwCiAgICAvLyBhLmJ5dGVzICsgYi5ieXRlcwogICAgLy8gaWYgQmlnVUludC5mcm9tX2J5dGVzKGEuYnl0ZXMpIDwgQmlnVUludC5mcm9tX2J5dGVzKGIuYnl0ZXMpCiAgICAvLyBlbHNlIGIuYnl0ZXMgKyBhLmJ5dGVzCiAgICBieiBoYXNoX3BhaXJfdGVybmFyeV9mYWxzZUAyCiAgICBmcmFtZV9kaWcgLTIKICAgIGZyYW1lX2RpZyAtMQogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE4CiAgICAvLyBhLmJ5dGVzICsgYi5ieXRlcwogICAgY29uY2F0CiAgICBiIGhhc2hfcGFpcl90ZXJuYXJ5X21lcmdlQDMKCmhhc2hfcGFpcl90ZXJuYXJ5X2ZhbHNlQDI6CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MTgtMjAKICAgIC8vIGEuYnl0ZXMgKyBiLmJ5dGVzCiAgICAvLyBpZiBCaWdVSW50LmZyb21fYnl0ZXMoYS5ieXRlcykgPCBCaWdVSW50LmZyb21fYnl0ZXMoYi5ieXRlcykKICAgIC8vIGVsc2UgYi5ieXRlcyArIGEuYnl0ZXMKICAgIGZyYW1lX2RpZyAtMQogICAgZnJhbWVfZGlnIC0yCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MjAKICAgIC8vIGVsc2UgYi5ieXRlcyArIGEuYnl0ZXMKICAgIGNvbmNhdAoKaGFzaF9wYWlyX3Rlcm5hcnlfbWVyZ2VAMzoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxNy0yMQogICAgLy8gaGFzaF9ieXRlcyA9IG9wLnNoYTI1NigKICAgIC8vICAgICBhLmJ5dGVzICsgYi5ieXRlcwogICAgLy8gICAgIGlmIEJpZ1VJbnQuZnJvbV9ieXRlcyhhLmJ5dGVzKSA8IEJpZ1VJbnQuZnJvbV9ieXRlcyhiLmJ5dGVzKQogICAgLy8gICAgIGVsc2UgYi5ieXRlcyArIGEuYnl0ZXMKICAgIC8vICkKICAgIHNoYTI1NgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjIyCiAgICAvLyByZXR1cm4gQnl0ZXMzMi5mcm9tX2J5dGVzKGhhc2hfYnl0ZXMpCiAgICBmcmFtZV9kaWcgLTIKICAgIGZyYW1lX2RpZyAtMQogICAgcmV0c3ViCg==",
"clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5jbGVhcl9zdGF0ZV9wcm9ncmFtOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE0CiAgICAvLyBjbGFzcyBNZXJrbGVUcmVlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIGludCAxCiAgICByZXR1cm4K"
"approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5hcHByb3ZhbF9wcm9ncmFtOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjkKICAgIC8vIGNsYXNzIE1lcmtsZVRyZWUoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgbWV0aG9kICJjcmVhdGUoYnl0ZVszMl0pdm9pZCIKICAgIG1ldGhvZCAidmVyaWZ5KGJ5dGVbMzJdW10sYnl0ZVszMl0pYm9vbCIKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDAKICAgIG1hdGNoIG1haW5fY3JlYXRlX3JvdXRlQDEgbWFpbl92ZXJpZnlfcm91dGVAMgogICAgZXJyIC8vIHJlamVjdCB0cmFuc2FjdGlvbgoKbWFpbl9jcmVhdGVfcm91dGVAMToKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxMAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGNyZWF0ZT1UcnVlKQogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgIQogICAgYXNzZXJ0IC8vIGlzIGNyZWF0aW5nCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6OQogICAgLy8gY2xhc3MgTWVya2xlVHJlZShhcmM0LkFSQzRDb250cmFjdCk6CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MTAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChjcmVhdGU9VHJ1ZSkKICAgIGNhbGxzdWIgY3JlYXRlCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9yb3V0ZUAyOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjE0CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBpcyBub3QgY3JlYXRpbmcKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weTo5CiAgICAvLyBjbGFzcyBNZXJrbGVUcmVlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDIKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICBjYWxsc3ViIHZlcmlmeQogICAgYnl0ZSAweDAwCiAgICBpbnQgMAogICAgdW5jb3ZlciAyCiAgICBzZXRiaXQKICAgIGJ5dGUgMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludCAxCiAgICByZXR1cm4KCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5jcmVhdGUocm9vdDogYnl0ZXMpIC0+IHZvaWQ6CmNyZWF0ZToKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxMC0xMQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGNyZWF0ZT1UcnVlKQogICAgLy8gZGVmIGNyZWF0ZShzZWxmLCByb290OiBCeXRlczMyKSAtPiBOb25lOgogICAgcHJvdG8gMSAwCiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MTIKICAgIC8vIHNlbGYucm9vdCA9IHJvb3QuYnl0ZXMKICAgIGJ5dGUgInJvb3QiCiAgICBmcmFtZV9kaWcgLTEKICAgIGFwcF9nbG9iYWxfcHV0CiAgICByZXRzdWIKCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS52ZXJpZnkocHJvb2Y6IGJ5dGVzLCBsZWFmOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnk6CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MTQtMTUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgLy8gZGVmIHZlcmlmeShzZWxmLCBwcm9vZjogUHJvb2YsIGxlYWY6IEJ5dGVzMzIpIC0+IGJvb2w6CiAgICBwcm90byAyIDEKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxNgogICAgLy8gcmV0dXJuIHNlbGYucm9vdCA9PSBjb21wdXRlX3Jvb3RfaGFzaChwcm9vZiwgbGVhZi5ieXRlcykKICAgIGludCAwCiAgICBieXRlICJyb290IgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayByb290IGV4aXN0cwogICAgZnJhbWVfZGlnIC0yCiAgICBmcmFtZV9kaWcgLTEKICAgIGNhbGxzdWIgY29tcHV0ZV9yb290X2hhc2gKICAgIGZyYW1lX2J1cnkgLTIKICAgID09CiAgICByZXRzdWIKCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuY29tcHV0ZV9yb290X2hhc2gocHJvb2Y6IGJ5dGVzLCBsZWFmOiBieXRlcykgLT4gYnl0ZXMsIGJ5dGVzOgpjb21wdXRlX3Jvb3RfaGFzaDoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToxOS0yMAogICAgLy8gQHN1YnJvdXRpbmUKICAgIC8vIGRlZiBjb21wdXRlX3Jvb3RfaGFzaChwcm9vZjogUHJvb2YsIGxlYWY6IEJ5dGVzKSAtPiBCeXRlczoKICAgIHByb3RvIDIgMgogICAgYnl0ZSAiIgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjIyCiAgICAvLyBmb3IgaWR4IGluIHVyYW5nZShwcm9vZi5sZW5ndGgpOgogICAgZnJhbWVfZGlnIC0yCiAgICBpbnQgMAogICAgZXh0cmFjdF91aW50MTYKICAgIGZyYW1lX2RpZyAtMQogICAgaW50IDAKCmNvbXB1dGVfcm9vdF9oYXNoX2Zvcl9oZWFkZXJAMToKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyMgogICAgLy8gZm9yIGlkeCBpbiB1cmFuZ2UocHJvb2YubGVuZ3RoKToKICAgIGZyYW1lX2RpZyAzCiAgICBmcmFtZV9kaWcgMQogICAgPAogICAgZHVwCiAgICBmcmFtZV9idXJ5IDAKICAgIGJ6IGNvbXB1dGVfcm9vdF9oYXNoX2FmdGVyX2ZvckA1CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MjMKICAgIC8vIGNvbXB1dGVkID0gaGFzaF9wYWlyKGNvbXB1dGVkLCBwcm9vZltpZHhdLmJ5dGVzKQogICAgZnJhbWVfZGlnIDAKICAgIGFzc2VydCAvLyBJbmRleCBhY2Nlc3MgaXMgb3V0IG9mIGJvdW5kcwogICAgZnJhbWVfZGlnIC0yCiAgICBleHRyYWN0IDIgMAogICAgZnJhbWVfZGlnIDMKICAgIGR1cAogICAgY292ZXIgMgogICAgaW50IDMyCiAgICAqCiAgICBpbnQgMzIKICAgIGV4dHJhY3QzCiAgICBmcmFtZV9kaWcgMgogICAgc3dhcAogICAgY2FsbHN1YiBoYXNoX3BhaXIKICAgIGZyYW1lX2J1cnkgMgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjIyCiAgICAvLyBmb3IgaWR4IGluIHVyYW5nZShwcm9vZi5sZW5ndGgpOgogICAgaW50IDEKICAgICsKICAgIGZyYW1lX2J1cnkgMwogICAgYiBjb21wdXRlX3Jvb3RfaGFzaF9mb3JfaGVhZGVyQDEKCmNvbXB1dGVfcm9vdF9oYXNoX2FmdGVyX2ZvckA1OgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjI0CiAgICAvLyByZXR1cm4gY29tcHV0ZWQKICAgIGZyYW1lX2RpZyAyCiAgICBmcmFtZV9kaWcgLTIKICAgIGZyYW1lX2J1cnkgMQogICAgZnJhbWVfYnVyeSAwCiAgICByZXRzdWIKCgovLyBleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuaGFzaF9wYWlyKGE6IGJ5dGVzLCBiOiBieXRlcykgLT4gYnl0ZXM6Cmhhc2hfcGFpcjoKICAgIC8vIG1lcmtsZS9jb250cmFjdC5weToyNy0yOAogICAgLy8gQHN1YnJvdXRpbmUKICAgIC8vIGRlZiBoYXNoX3BhaXIoYTogQnl0ZXMsIGI6IEJ5dGVzKSAtPiBCeXRlczoKICAgIHByb3RvIDIgMQogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjI5CiAgICAvLyByZXR1cm4gb3Auc2hhMjU2KGEgKyBiIGlmIEJpZ1VJbnQuZnJvbV9ieXRlcyhhKSA8IEJpZ1VJbnQuZnJvbV9ieXRlcyhiKSBlbHNlIGIgKyBhKQogICAgZnJhbWVfZGlnIC0yCiAgICBmcmFtZV9kaWcgLTEKICAgIGI8CiAgICBieiBoYXNoX3BhaXJfdGVybmFyeV9mYWxzZUAyCiAgICBmcmFtZV9kaWcgLTIKICAgIGZyYW1lX2RpZyAtMQogICAgY29uY2F0CiAgICBiIGhhc2hfcGFpcl90ZXJuYXJ5X21lcmdlQDMKCmhhc2hfcGFpcl90ZXJuYXJ5X2ZhbHNlQDI6CiAgICAvLyBtZXJrbGUvY29udHJhY3QucHk6MjkKICAgIC8vIHJldHVybiBvcC5zaGEyNTYoYSArIGIgaWYgQmlnVUludC5mcm9tX2J5dGVzKGEpIDwgQmlnVUludC5mcm9tX2J5dGVzKGIpIGVsc2UgYiArIGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGZyYW1lX2RpZyAtMgogICAgY29uY2F0CgpoYXNoX3BhaXJfdGVybmFyeV9tZXJnZUAzOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjI5CiAgICAvLyByZXR1cm4gb3Auc2hhMjU2KGEgKyBiIGlmIEJpZ1VJbnQuZnJvbV9ieXRlcyhhKSA8IEJpZ1VJbnQuZnJvbV9ieXRlcyhiKSBlbHNlIGIgKyBhKQogICAgc2hhMjU2CiAgICByZXRzdWIK",
"clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpleGFtcGxlcy5tZXJrbGUuY29udHJhY3QuTWVya2xlVHJlZS5jbGVhcl9zdGF0ZV9wcm9ncmFtOgogICAgLy8gbWVya2xlL2NvbnRyYWN0LnB5OjkKICAgIC8vIGNsYXNzIE1lcmtsZVRyZWUoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgaW50IDEKICAgIHJldHVybgo="
},
"state": {
"global": {
Expand Down
Loading

0 comments on commit f857181

Please sign in to comment.