Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve interface of ContractInstance.__call__ #7

Merged
merged 2 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions examples/ram/ram.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,10 @@ def execute_command(input_line: str):
)
)

R_inst("withdraw",
outputs=outputs,
merkle_root=mt.root, merkle_proof=mt.prove_leaf(leaf_index))
R_inst("withdraw", outputs=outputs)(
merkle_root=mt.root,
merkle_proof=mt.prove_leaf(leaf_index)
)

print("Done")
elif action == "write":
Expand All @@ -174,11 +175,11 @@ def execute_command(input_line: str):
if leaf_index not in range(len(R_inst.data_expanded)):
raise ValueError("Invalid leaf index")

result = R_inst("write",
merkle_root=mt.root,
new_value=new_value,
merkle_proof=mt.prove_leaf(leaf_index)
)
result = R_inst("write")(
merkle_root=mt.root,
new_value=new_value,
merkle_proof=mt.prove_leaf(leaf_index)
)

assert len(result) == 1

Expand All @@ -189,7 +190,8 @@ def execute_command(input_line: str):
amount = int(args_dict["amount"])
content = [sha256(i.to_bytes(1, byteorder='little')) for i in range(8)]

R_inst = manager.fund_instance(RAM(len(content)), amount, data=MerkleTree(content).root)
R = RAM(len(content))
R_inst = manager.fund_instance(R, amount, data=R.State(content))

R_inst.data_expanded = content

Expand Down
4 changes: 2 additions & 2 deletions examples/rps/rps.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def start_session(self, m_a: int):
print(f"Game result: {outcome}")

self.env.prompt("Broadcasting adjudication transaction")
C2(outcome, m_a=m_a, m_b=m_b, r_a=r_a)
C2(outcome)(m_a=m_a, m_b=m_b, r_a=r_a)

s.close()

Expand Down Expand Up @@ -178,7 +178,7 @@ def join_session(self, m_b: int):

self.env.prompt("Broadcasting Bob's move transaction")

[C2] = C("bob_move", signer=SchnorrSigner(self.priv_key), m_b=m_b)
[C2] = C("bob_move", SchnorrSigner(self.priv_key))(m_b=m_b)

txid = C.spending_tx.hash
print(f"Bob's move broadcasted: {m_b}. txid: {txid}")
Expand Down
2 changes: 1 addition & 1 deletion examples/vault/vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def execute_command(input_line: str):
if not isinstance(instance.contract, (Vault, Unvaulting)):
raise ValueError("Only Vault or Unvaulting instances can be recovered")

instance("recover", out_i=0)
instance("recover")(out_i=0)

elif action == "withdraw":
item_idx = int(args_dict["item"])
Expand Down
17 changes: 10 additions & 7 deletions matt/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# There are no bad people here, though, so we keep it simple for now.
from enum import Enum
from io import BytesIO
from typing import Dict, List, Optional, Tuple, Union
from typing import Callable, Dict, List, Optional, Tuple, Union

from .argtypes import SignerType
from .btctools import script
Expand Down Expand Up @@ -102,14 +102,17 @@ def __repr__(self):
value = self.funding_tx.vout[self.outpoint.n].nValue
return f"{self.__class__.__name__}(contract={self.contract}, data={self.data if self.data is None else self.data.hex()}, value={value}, status={self.status}, outpoint={self.outpoint})"

def __call__(self, clause_name: str, *, signer: Optional[SchnorrSigner] = None, outputs: List[CTxOut] = [], **kwargs) -> List['ContractInstance']:
if self.manager is None:
raise ValueError("Direct invocation is only allowed after adding the instance to a ContractManager")
def __call__(self, clause_name: str, signer: Optional[SchnorrSigner] = None, outputs: List[CTxOut] = []) -> Callable[..., List['ContractInstance']]:
def callable_instance(**kwargs) -> List['ContractInstance']:
if self.manager is None:
raise ValueError("Direct invocation is only allowed after adding the instance to a ContractManager")

if self.status != ContractInstanceStatus.FUNDED:
raise ValueError("Only implemented for FUNDED instances")
if self.status != ContractInstanceStatus.FUNDED:
raise ValueError("Only implemented for FUNDED instances")

return self.manager.spend_instance(self, clause_name, kwargs, signer=signer, outputs=outputs)
return self.manager.spend_instance(self, clause_name, kwargs, signer=signer, outputs=outputs)

return callable_instance


class ContractManager:
Expand Down
185 changes: 90 additions & 95 deletions tests/test_fraud.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ def test_leaf_reveal_alice(manager: ContractManager):
)
]

out_instances = L_inst("alice_reveal",
signer=SchnorrSigner(alice_key),
outputs=outputs,
x=x_start,
h_y_b=h_end_bob)
out_instances = L_inst("alice_reveal", SchnorrSigner(alice_key), outputs)(
x=x_start,
h_y_b=h_end_bob
)

assert len(out_instances) == 0

Expand All @@ -69,11 +68,10 @@ def test_leaf_reveal_bob(manager: ContractManager):
)
]

out_instances = L_inst("bob_reveal",
signer=SchnorrSigner(bob_key),
outputs=outputs,
x=x_start,
h_y_a=h_end_alice)
out_instances = L_inst("bob_reveal", SchnorrSigner(bob_key), outputs)(
x=x_start,
h_y_a=h_end_alice
)

assert len(out_instances) == 0

Expand Down Expand Up @@ -126,7 +124,7 @@ def t_node_b(i, j) -> bytes:
inst = manager.fund_instance(G, AMOUNT)

# Bob chooses its input
[inst] = inst('choose', signer=bob_signer, x=x)
[inst] = inst('choose', bob_signer)(x=x)

assert isinstance(inst.contract, G256_S1)
assert isinstance(inst.data_expanded, G256_S1.State) and inst.data_expanded.x == x
Expand All @@ -135,56 +133,54 @@ def t_node_b(i, j) -> bytes:
t_b = t_node_b(0, n - 1) # trace root according to Bob

# Alice reveals her answer
[inst] = inst('reveal', signer=alice_signer,
x=x,
y=y,
t_a=t_a)
[inst] = inst('reveal', alice_signer)(x=x, y=y, t_a=t_a)

assert isinstance(inst.contract, G256_S2)
assert inst.data_expanded == G256_S2.State(t_a=t_a, x=x, y=y)

# Bob disagrees and starts the challenge
[inst] = inst('start_challenge', signer=bob_signer,
t_a=t_a,
x=x,
y=y,
z=z,
t_b=t_b)
[inst] = inst('start_challenge', bob_signer)(
t_a=t_a,
x=x,
y=y,
z=z,
t_b=t_b
)

# inst now represents a step in the bisection protocol corresponding to the root of the computation

assert isinstance(inst.contract, Bisect_1)
assert inst.contract.i == 0 and inst.contract.j == 7
i, j = inst.contract.i, inst.contract.j
m = (j - i + 1) // 2
[inst] = inst('alice_reveal', signer=alice_signer,
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j)
)
[inst] = inst('alice_reveal', alice_signer)(
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j)
)
report.write("Fraud proof", format_tx_markdown(inst.funding_tx, "Bisection (Alice)"))

assert isinstance(inst.contract, Bisect_2)
assert inst.contract.i == 0 and inst.contract.j == 7

[inst] = inst('bob_reveal_right', signer=bob_signer,
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j),
h_mid_b=h_b[i + m],
trace_left_b=t_node_b(i, i + m - 1),
trace_right_b=t_node_b(i + m, j),
)
[inst] = inst('bob_reveal_right', bob_signer)(
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j),
h_mid_b=h_b[i + m],
trace_left_b=t_node_b(i, i + m - 1),
trace_right_b=t_node_b(i + m, j),
)
report.write("Fraud proof", format_tx_markdown(inst.funding_tx, "Bisection (Bob, right child)"))

assert isinstance(inst.contract, Bisect_1)
Expand All @@ -193,34 +189,34 @@ def t_node_b(i, j) -> bytes:
assert i == 4 and j == 7

# Bisection repeats on the node covering from index 4 to index 7
[inst] = inst('alice_reveal', signer=alice_signer,
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j)
)
[inst] = inst('alice_reveal', alice_signer)(
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j)
)
report.write("Fraud proof", format_tx_markdown(inst.funding_tx, "Bisection (Alice)"))

assert isinstance(inst.contract, Bisect_2)
assert inst.contract.i == 4 and inst.contract.j == 7

[inst] = inst('bob_reveal_left', signer=bob_signer,
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j),
h_mid_b=h_b[i + m],
trace_left_b=t_node_b(i, i + m - 1),
trace_right_b=t_node_b(i + m, j),
)
[inst] = inst('bob_reveal_left', bob_signer)(
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j),
h_mid_b=h_b[i + m],
trace_left_b=t_node_b(i, i + m - 1),
trace_right_b=t_node_b(i + m, j),
)
report.write("Fraud proof", format_tx_markdown(inst.funding_tx, "Bisection (Bob, left child)"))

assert isinstance(inst.contract, Bisect_1)
Expand All @@ -230,34 +226,34 @@ def t_node_b(i, j) -> bytes:

# Bisection repeats on the node covering from index 4 to index 5 (last bisection step)

[inst] = inst('alice_reveal', signer=alice_signer,
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j)
)
[inst] = inst('alice_reveal', alice_signer)(
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j)
)
report.write("Fraud proof", format_tx_markdown(inst.funding_tx, "Bisection (Alice)"))

assert isinstance(inst.contract, Bisect_2)
assert inst.contract.i == 4 and inst.contract.j == 5

[inst] = inst('bob_reveal_right', signer=bob_signer,
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j),
h_mid_b=h_b[i + m],
trace_left_b=t_node_b(i, i + m - 1),
trace_right_b=t_node_b(i + m, j),
)
[inst] = inst('bob_reveal_right', bob_signer)(
h_start=h_a[i],
h_end_a=h_a[j + 1],
h_end_b=h_b[j + 1],
trace_a=t_node_a(i, j),
trace_b=t_node_b(i, j),
h_mid_a=h_a[i + m],
trace_left_a=t_node_a(i, i + m - 1),
trace_right_a=t_node_a(i + m, j),
h_mid_b=h_b[i + m],
trace_left_b=t_node_b(i, i + m - 1),
trace_right_b=t_node_b(i + m, j),
)
report.write("Fraud proof", format_tx_markdown(inst.funding_tx, "Bisection (Bob, right child)"))

# We reached a leaf. Only who was doubling correctly can withdraw
Expand All @@ -272,11 +268,10 @@ def t_node_b(i, j) -> bytes:
scriptPubKey=bytes([0, 0x20, *[0x42]*32])
)
]
out_instances = inst("bob_reveal",
signer=SchnorrSigner(bob_key),
outputs=outputs,
x=bob_trace[5],
h_y_a=h_a[6])
out_instances = inst("bob_reveal", bob_signer, outputs)(
x=bob_trace[5],
h_y_a=h_a[6]
)

assert len(out_instances) == 0

Expand Down
Loading
Loading