Skip to content

Commit

Permalink
Tests: add tests for multiple operations signing
Browse files Browse the repository at this point in the history
Only operation batches with at most one delegation (not including reveals) are authorised to be signed.
  • Loading branch information
spalmer25 committed Feb 6, 2024
1 parent d20af84 commit 2881082
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 4 deletions.
136 changes: 134 additions & 2 deletions test/python/test_instructions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Module gathering the baking app instruction tests."""

from pathlib import Path
from typing import Callable, Tuple
from typing import Callable, Optional, Tuple
import pytest
from pytezos import pytezos
from ragger.firmware import Firmware
Expand All @@ -22,7 +22,7 @@
Block,
DEFAULT_CHAIN_ID
)
from utils.navigator import TezosNavigator
from utils.navigator import TezosNavigator, send_and_navigate
from common import (
DEFAULT_ACCOUNT,
DEFAULT_ACCOUNT_2,
Expand Down Expand Up @@ -838,6 +838,138 @@ def test_sign_transaction(
client.sign_message(account_1, transaction)


def build_reveal(account: Account) -> Reveal:
"""Build a reveal."""
return Reveal(
public_key=account.public_key,
source=account.public_key_hash,
)
def build_delegation(account: Account) -> Delegation:
"""Build a delegation."""
return Delegation(
delegate=account.public_key_hash,
source=account.public_key_hash,
)
def build_transaction(account: Account) -> UnsafeOp:
"""Build a transaction."""
ctxt = pytezos.using()
return UnsafeOp(
ctxt.transaction(
source=account.public_key_hash,
destination=DEFAULT_ACCOUNT_2.public_key_hash,
amount=10_000,
)
)
def build_bad_reveal_1(account: Account) -> Reveal:
"""Build a bad reveal."""
return Reveal(
public_key=account.public_key,
source=DEFAULT_ACCOUNT_2.public_key_hash,
)
def build_bad_reveal_2(account: Account) -> Reveal:
"""Build an other bad reveal."""
return Reveal(
public_key=DEFAULT_ACCOUNT_2.public_key,
source=account.public_key_hash,
)
def build_bad_delegation_1(account: Account) -> Delegation:
"""Build a bad delegation."""
return Delegation(
delegate=account.public_key_hash,
source=DEFAULT_ACCOUNT_2.public_key_hash,
)
def build_bad_delegation_2(account: Account) -> Delegation:
"""Build a other bad delegation."""
return Delegation(
delegate=DEFAULT_ACCOUNT_2.public_key_hash,
source=account.public_key_hash,
)


# Warning: operation PARSE_ERROR are not available on DEBUG-mode
PARAMETERS_SIGN_MULTIPLE_OPERATIONS = [
(build_reveal, build_reveal, None, False, StatusCode.OK ),
(build_reveal, build_delegation, None, True, StatusCode.OK ),
(build_delegation, build_reveal, None, True, StatusCode.OK ),
(build_reveal, build_delegation, build_reveal, True, StatusCode.OK ),
] + [
(build_bad_reveal_1, build_reveal, None, False, StatusCode.OK ),
(build_bad_reveal_1, build_delegation, None, True, StatusCode.OK ),
(build_bad_reveal_2, build_reveal, None, False, StatusCode.PARSE_ERROR),
(build_bad_reveal_2, build_delegation, None, True, StatusCode.PARSE_ERROR),
(build_reveal, build_bad_reveal_1, None, False, StatusCode.SECURITY ),
(build_delegation, build_bad_reveal_1, None, True, StatusCode.SECURITY ),
(build_reveal, build_bad_reveal_2, None, False, StatusCode.PARSE_ERROR),
(build_delegation, build_bad_reveal_2, None, True, StatusCode.PARSE_ERROR),
(build_reveal, build_bad_delegation_1, None, True, StatusCode.PARSE_ERROR),
(build_reveal, build_bad_delegation_2, None, True, StatusCode.SECURITY ),
(build_bad_delegation_1, build_reveal, None, True, StatusCode.PARSE_ERROR),
(build_bad_delegation_2, build_reveal, None, True, StatusCode.SECURITY ),
(build_reveal, build_transaction, None, False, StatusCode.PARSE_ERROR),
(build_transaction, build_reveal, None, False, StatusCode.PARSE_ERROR),
(build_delegation, build_delegation, None, True, StatusCode.PARSE_ERROR),
(build_delegation, build_delegation, None, True, StatusCode.PARSE_ERROR),
(build_reveal, build_delegation, build_delegation, True, StatusCode.PARSE_ERROR),
(build_delegation, build_delegation, build_reveal, True, StatusCode.PARSE_ERROR),
(build_reveal, build_delegation, build_transaction, True, StatusCode.PARSE_ERROR),
(build_transaction, build_delegation, build_reveal, True, StatusCode.PARSE_ERROR),
]

@pytest.mark.parametrize(
"operation_builder_1," \
"operation_builder_2," \
"operation_builder_3," \
"operation_display," \
"status_code",
PARAMETERS_SIGN_MULTIPLE_OPERATIONS
)
def test_sign_multiple_operation(
operation_builder_1: Callable[[Account], UnsafeOp],
operation_builder_2: Callable[[Account], UnsafeOp],
operation_builder_3: Optional[Callable[[Account], UnsafeOp]],
status_code: StatusCode,
operation_display: bool,
client: TezosClient,
tezos_navigator: TezosNavigator) -> None:
"""Test multiple operations signing constraints."""

account = DEFAULT_ACCOUNT

tezos_navigator.setup_app_context(
account,
DEFAULT_CHAIN_ID,
main_hwm=Hwm(0),
test_hwm=Hwm(0)
)

operation = operation_builder_1(account)
operation = operation.merge(
operation_builder_2(account)
)
if operation_builder_3 is not None:
operation = operation.merge(
operation_builder_3(account)
)

message = operation.forge()

with status_code.expected():
if operation_display:
signature = send_and_navigate(
send=lambda: client.sign_message(
account,
message
),
navigate=tezos_navigator.accept_sign_navigate
)
else:
signature = client.sign_message(
account,
message
)
account.check_signature(signature, bytes(message))


def test_sign_when_no_chain_setup(
client: TezosClient,
tezos_navigator: TezosNavigator) -> None:
Expand Down
3 changes: 2 additions & 1 deletion test/python/utils/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ def expected(self) -> Generator[None, None, None]:
"""Fail if the right RAPDU code exception is not raise."""
try:
yield
assert False, f"Expect fail with { self.name } but succeed"
assert self == StatusCode.OK, \
f"Expect fail with { self.name } but succeed"
except ExceptionRAPDU as e:
try:
name = f"{StatusCode(e.status).name}"
Expand Down
6 changes: 6 additions & 0 deletions test/python/utils/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ def forge(self, branch: str = DEFAULT_BLOCK_HASH) -> Message:
raw = watermark + bytes.fromhex(self.operation.forge())
return RawMessage(raw)

def merge(self, unsafe_op: 'UnsafeOp') -> 'UnsafeOp':
res = self.operation
for content in unsafe_op.operation.contents:
res = res.operation(content)
return UnsafeOp(res)

class Delegation(UnsafeOp):
"""Class representing a delegation."""

Expand Down
2 changes: 1 addition & 1 deletion test/python/utils/navigator.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ def sign_delegation_with_hash(self,
account: Account,
delegation: Delegation,
branch: str = DEFAULT_BLOCK_HASH,
navigate: Optional[Callable] = None,
navigate: Optional[Callable] = None,
**kwargs) -> Tuple[bytes, Signature]:
"""Send a sign and get hash request on delegation and navigate until accept"""
if navigate is None:
Expand Down

0 comments on commit 2881082

Please sign in to comment.