Fix various Linter issues and mispelling

This commit is contained in:
Charles-Edouard de la Vergne
2024-03-18 17:28:51 +01:00
parent 36ae183a1c
commit f5ea9c51c2
100 changed files with 229 additions and 220 deletions

View File

@@ -22,4 +22,4 @@ pytestdebug.log
.mypy_cache
.coverage
.coverage.*
coverage.xml
coverage.xml

View File

@@ -8,6 +8,7 @@ These tests are implemented in Python with the `SpeculosClient` interface which
- [pip](https://pip.pypa.io/en/stable/installation/)
### Dependencies
Python dependencies are listed in [requirements.txt](requirements.txt)
```shell
@@ -19,6 +20,7 @@ python3 -m pip install -r requirements.txt
### Compilation app
Go to the root of the repository:
```sh
make DEBUG=1 NFT_TESTING_KEY=1 BOLOS_SDK=$NANOX_SDK
mv bin/app.elf tests/speculos/<some name>.elf
@@ -26,12 +28,13 @@ mv bin/app.elf tests/speculos/<some name>.elf
Given the requirements are installed, just do (by default command):
```
```shell
cd tests/speculos/
pytest
```
### Custom options
- **--model:** "nanos", "nanox", "nanosp" | default: "nanos"
- **--display:** "qt", "headless" | default: "qt"
- **--path:** the path of the binary app | default: path of makefile compilation
@@ -39,6 +42,7 @@ pytest
## Example
With `nanox` binary app:
```sh
# the --path is variable to where you put your binary

View File

@@ -32,6 +32,7 @@
## Ethereum_client
### Ethereum_cmd_builder
```py
def chunked(size, source)
@@ -49,6 +50,7 @@ class EthereumCommandBuilder:
```
### Ethereum_cmd
```py
class EthereumCommand:
# Sending apdu and parsing the response in the right form
@@ -61,16 +63,14 @@ class EthereumCommand:
def simple_sign_tx(self, bip32_path: str, transaction: Transaction, result: List = list()) -> None:
def sign_eip712(self, bip32_path: str, transaction: EIP712, result: List = list()) -> None:
def personal_sign_tx(self, bip32_path: str, transaction: PersonalTransaction, result: List = list()) -> None:
# Allows to send an apdu without return of speculos
def send_apdu(self, apdu: bytes) -> bytes:
# Allows to send an apdu with return of speculos
def send_apdu_context(self, apdu: bytes, result: List = list()) -> bytes:
```
### Utils
```py
def save_screenshot(cmd, path: str):
def compare_screenshot(cmd, path: str):
@@ -80,21 +80,23 @@ def packed_bip32_path_from_string(path: str) -> bytes:
def write_varint(n: int) -> bytes:
def read_varint(buf: BytesIO, prefix: Optional[bytes] = None) -> int:
def read(buf: BytesIO, size: int) -> bytes:
def read_uint(buf: BytesIO,
def read_uint(buf: BytesIO, bit_len: int, byteorder: Literal['big', 'little'] = 'little') -> int:
```
## Tests new apdu
If a new instruction is programmed it will be necessary to create 2 new functions.
one in `ethereum_cmd_builder` :
If a new instruction is programmed it will be necessary to create 2 new functions.
one in `ethereum_cmd_builder`:
- Creation of the raw apdu you can find some examples in this same file
and one in `ethereum_cmd`:
and one in `ethereum_cmd`:
- Send the apdu to speculos and parse the answer in a `list` named result you can find some examples in this same file
## Example for write new tests
To send several apdu and get the return
To send several apdu and get the return
```py
FIRST = bytes.fromhex("{YourAPDU}")
@@ -130,4 +132,3 @@ def test_some_error(cmd):
pass
assert error.args[0] == '0x6a80'
```

View File

@@ -22,7 +22,7 @@ class EthereumCommand:
self.builder = EthereumCommandBuilder(debug=debug)
self.debug = debug
self.model = model
def get_configuration(self) -> Tuple[int, int, int, int]:
try:
response = self.client._apdu_exchange(
@@ -46,7 +46,7 @@ class EthereumCommand:
self.client._apdu_exchange(
self.builder.set_plugin(plugin=plugin)
)
except ApduException as error:
raise DeviceException(error_code=error.sw, ins=InsType.INS_SET_PLUGIN)
@@ -79,7 +79,7 @@ class EthereumCommand:
data=chunk[5:]) as exchange:
yield exchange
response: bytes = exchange.receive()
except ApduException as error:
raise DeviceException(error_code=error.sw, ins=InsType.INS_GET_PUBLIC_KEY)
@@ -94,17 +94,17 @@ class EthereumCommand:
uncompressed_addr_len: bytes = response[offset:offset + pub_key_len]
offset += pub_key_len
eth_addr_len: int = response[offset]
offset += 1
eth_addr: bytes = response[offset:offset + eth_addr_len]
offset += eth_addr_len
chain_code: bytes = response[offset:]
assert len(response) == 1 + pub_key_len + 1 + eth_addr_len + 32 # 32 -> chain_code_len
result.append(uncompressed_addr_len)
result.append(eth_addr)
result.append(chain_code)
@@ -120,7 +120,7 @@ class EthereumCommand:
data=chunk[5:]) as exchange:
yield exchange
response: bytes = exchange.receive()
except ApduException as error:
raise DeviceException(error_code=error.sw, ins=InsType.INS_PERFORM_PRIVACY_OPERATION)
@@ -146,7 +146,7 @@ class EthereumCommand:
data=apdu[5:]) as exchange:
yield exchange
result.append(exchange.receive())
except ApduException as error:
raise DeviceException(error_code=error.sw, ins=InsType.INS_SIGN_TX)
@@ -162,14 +162,14 @@ class EthereumCommand:
data=chunk[5:]) as exchange:
yield exchange
response: bytes = exchange.receive()
except ApduException as error:
raise DeviceException(error_code=error.sw, ins=InsType.INS_SIGN_TX)
# response = V (1) || R (32) || S (32)
assert len(response) == 65
v, r, s = parse_sign_response(response)
result.append(v)
result.append(r)
result.append(s)
@@ -185,14 +185,14 @@ class EthereumCommand:
data=chunk[5:]) as exchange:
yield exchange
response: bytes = exchange.receive()
except ApduException as error:
raise DeviceException(error_code=error.sw, ins=InsType.INS_SIGN_EIP712)
# response = V (1) || R (32) || S (32)
assert len(response) == 65
v, r, s = parse_sign_response(response)
result.append(v)
result.append(r)
result.append(s)
@@ -211,16 +211,13 @@ class EthereumCommand:
response: bytes = exchange.receive()
else:
self.send_apdu(apdu)
except ApduException as error:
raise DeviceException(error_code=error.sw, ins=InsType.INS_SIGN_TX)
# response = V (1) || R (32) || S (32)
v, r, s = parse_sign_response(response)
result.append(v)
result.append(r)
result.append(s)

View File

@@ -156,7 +156,7 @@ class EthereumCommandBuilder:
"""
cdata = packed_bip32_path_from_string(bip32_path)
return self.serialize(cla=self.CLA,
ins=InsType.INS_GET_PUBLIC_KEY,
p1=0x01 if display else 0x00,
@@ -171,11 +171,11 @@ class EthereumCommandBuilder:
bip32_path : str
String representation of BIP32 path.
Third party public key on Curve25519 : 32 bytes
Optionnal if returning the shared secret
Optional if returning the shared secret
"""
cdata = packed_bip32_path_from_string(bip32_path)
return self.serialize(cla=self.CLA,
ins=InsType.INS_PERFORM_PRIVACY_OPERATION,
p1=0x01 if display else 0x00,
@@ -200,7 +200,7 @@ class EthereumCommandBuilder:
"""
cdata = packed_bip32_path_from_string(bip32_path)
tx: bytes = transaction.serialize()
cdata = cdata + tx
@@ -230,7 +230,7 @@ class EthereumCommandBuilder:
"""
cdata = packed_bip32_path_from_string(bip32_path)
tx: bytes = transaction.serialize()
cdata = cdata + tx
@@ -259,12 +259,12 @@ class EthereumCommandBuilder:
"""
cdata = packed_bip32_path_from_string(bip32_path)
tx: bytes = transaction.serialize()
cdata = cdata + tx
last_chunk = len(cdata) // MAX_APDU_LEN
# The generator allows to send apdu frames because we can't send an apdu > 255
for i, (chunk) in enumerate(chunked(MAX_APDU_LEN, cdata)):
if i == 0 and i == last_chunk:
@@ -290,4 +290,4 @@ class EthereumCommandBuilder:
ins=InsType.INS_SIGN_PERSONAL_TX,
p1=0x80,
p2=0x00,
cdata=chunk)
cdata=chunk)

View File

@@ -10,7 +10,7 @@ class ERC20Information:
self.nb_decimals: int = nb_decimals
self.chainID: int = chainID
self.sign: bytes = bytes.fromhex(sign)
def serialize(self) -> bytes:
return b"".join([
write_varint(len(self.erc20_ticker)),
@@ -67,4 +67,4 @@ class Plugin:
write_varint(len(self.sign)),
self.sign,
])
])

View File

@@ -88,9 +88,9 @@ class EIP712:
def __init__(self, domain_hash: str, msg_hash: str) -> None:
self.domain_hash = bytes.fromhex(domain_hash)
self.msg_hash = bytes.fromhex(msg_hash)
def serialize(self) -> bytes:
return b"".join([
self.domain_hash,
self.msg_hash
])
])

View File

@@ -54,7 +54,7 @@ def bip32_path_from_string(path: str) -> List[bytes]:
def packed_bip32_path_from_string(path: str) -> bytes:
bip32_paths = bip32_path_from_string(path)
return b"".join([
len(bip32_paths).to_bytes(1, byteorder="big"),
*bip32_paths
@@ -98,7 +98,7 @@ def read(buf: BytesIO, size: int) -> bytes:
b: bytes = buf.read(size)
if len(b) < size:
raise ValueError(f"Cant read {size} bytes in buffer!")
raise ValueError(f"Can't read {size} bytes in buffer!")
return b

View File

@@ -16,7 +16,7 @@ def test_personal_sign_metamask(cmd):
with cmd.personal_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
sleep(0.5)
if cmd.model == "nanos":
# Sign message
compare_screenshot(cmd, f"screenshots/eip191/{PATH_IMG[cmd.model]}/personal_sign_metamask/00000.png")
@@ -49,7 +49,7 @@ def test_personal_sign_metamask(cmd):
assert v == 0x1c # 28
assert r.hex() == "916099cf0d9c21911c85f0770a47a9696a8189e78c259cf099749748c507baae"
assert s.hex() == "0d72234bc0ac2e94c5f7a5f4f9cd8610a52be4ea55515a85b9703f1bb158415c"
def test_personal_sign_reject(cmd):
result: list = []
@@ -109,7 +109,7 @@ def test_personal_sign_non_ascii(cmd):
with cmd.personal_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
sleep(0.5)
if cmd.model == "nanos":
# Sign message
compare_screenshot(cmd, f"screenshots/eip191/{PATH_IMG[cmd.model]}/personal_sign_non_ascii/00000.png")
@@ -159,7 +159,7 @@ def test_personal_sign_opensea(cmd):
with cmd.personal_sign_tx(bip32_path, transaction, result) as ex:
sleep(0.5)
if cmd.model == "nanos":
# Sign message
compare_screenshot(cmd, f"screenshots/eip191/{PATH_IMG[cmd.model]}/personal_sign_opensea/00000.png")

View File

@@ -9,7 +9,7 @@ def test_sign_eip_1559(cmd):
with cmd.send_apdu_context(apdu_sign_eip_1559, result) as ex:
sleep(0.5)
if cmd.model == "nanos":
# Review transaction
compare_screenshot(cmd, f"screenshots/eip1559/{PATH_IMG[cmd.model]}/sign_eip_1559/00000.png")
@@ -47,7 +47,7 @@ def test_sign_eip_1559(cmd):
# Address
compare_screenshot(cmd, f"screenshots/eip1559/{PATH_IMG[cmd.model]}/sign_eip_1559/00002.png")
cmd.client.press_and_release('right')
# Max Fees
compare_screenshot(cmd, f"screenshots/eip1559/{PATH_IMG[cmd.model]}/sign_eip_1559/00003.png")
cmd.client.press_and_release('right')

View File

@@ -176,4 +176,4 @@ def test_sign_eip_712_bad_msg(cmd):
with cmd.sign_eip712(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
pass
assert error.args[0] == '0x6a80'
assert error.args[0] == '0x6a80'

View File

@@ -38,7 +38,7 @@ def test_transfer_erc1155(cmd):
if cmd.model == "nanox" or cmd.model == "nanosp":
cmd.set_plugin(plugin=PLUGIN)
cmd.provide_nft_information(plugin=PROVIDE_NFT_INFORMATION)
cmd.send_apdu(SIGN_FIRST)
with cmd.send_apdu_context(SIGN_MORE, result) as ex:
@@ -46,8 +46,8 @@ def test_transfer_erc1155(cmd):
# Review transaction
compare_screenshot(cmd, f"screenshots/erc1155/{PATH_IMG[cmd.model]}/transfer_erc1155/00000.png")
cmd.client.press_and_release('right')
# NFT Transfert
# NFT Transfer
compare_screenshot(cmd, f"screenshots/erc1155/{PATH_IMG[cmd.model]}/transfer_erc1155/00001.png")
cmd.client.press_and_release('right')
@@ -98,7 +98,7 @@ def test_transfer_erc1155_without_nft_provide_info(cmd):
cmd.set_plugin(plugin=PLUGIN)
cmd.send_apdu(SIGN_FIRST)
with cmd.send_apdu_context(SIGN_MORE, result) as ex:
@@ -114,7 +114,7 @@ def test_transfer_erc1155_without_set_plugin(cmd):
with pytest.raises(ethereum_client.exception.errors.DenyError) as error:
cmd.provide_nft_information(plugin=PROVIDE_NFT_INFORMATION)
cmd.send_apdu(SIGN_FIRST)
with cmd.send_apdu_context(SIGN_MORE, result) as ex:
@@ -161,7 +161,7 @@ def test_transfer_batch_erc1155(cmd):
if cmd.model == "nanox" or cmd.model == "nanosp":
cmd.set_plugin(plugin=PLUGIN_BATCH)
cmd.provide_nft_information(plugin=PROVIDE_NFT_INFORMATION_BATCH)
cmd.send_apdu(SIGN_FIRST_BATCH)
cmd.send_apdu(SIGN_MORE_1_BATCH)
cmd.send_apdu(SIGN_MORE_2_BATCH)

View File

@@ -28,4 +28,4 @@ def test_provide_erc20_token_error(cmd):
with pytest.raises(ethereum_client.exception.errors.UnknownDeviceError) as error:
cmd.provide_erc20_token_information(info=erc20_info)
assert error.args[0] == '0x6a80'
assert error.args[0] == '0x6a80'

View File

@@ -38,7 +38,7 @@ def test_transfer_erc721(cmd):
if cmd.model == "nanox" or cmd.model == "nanosp":
cmd.set_plugin(plugin=PLUGIN)
cmd.provide_nft_information(plugin=PROVIDE_NFT_INFORMATION)
cmd.send_apdu(SIGN_FIRST)
with cmd.send_apdu_context(SIGN_MORE, result) as ex:
@@ -46,7 +46,7 @@ def test_transfer_erc721(cmd):
# Review transaction
compare_screenshot(cmd, f"screenshots/erc721/{PATH_IMG[cmd.model]}/transfer_erc721/00000.png")
cmd.client.press_and_release('right')
# NFT Transfer
compare_screenshot(cmd, f"screenshots/erc721/{PATH_IMG[cmd.model]}/transfer_erc721/00001.png")
cmd.client.press_and_release('right')
@@ -97,7 +97,7 @@ def test_transfer_erc721_without_nft_provide_info(cmd):
pass
assert error.args[0] == '0x6a80'
def test_transfer_erc721_without_set_plugin(cmd):
@@ -106,10 +106,10 @@ def test_transfer_erc721_without_set_plugin(cmd):
if cmd.model == "nanox" or cmd.model == "nanosp":
with pytest.raises(ethereum_client.exception.errors.DenyError) as error:
cmd.provide_nft_information(plugin=PROVIDE_NFT_INFORMATION)
cmd.send_apdu(SIGN_FIRST)
with cmd.send_apdu_context(SIGN_MORE, result) as ex:
pass
assert error.args[0] == '0x6985'
assert error.args[0] == '0x6985'

View File

@@ -92,11 +92,11 @@ def test_reject_get_public_key(cmd):
# Approve
compare_screenshot(cmd, f"screenshots/pubkey/{PATH_IMG[cmd.model]}/reject_get_public_key/00004.png")
cmd.client.press_and_release('right')
# Reject
compare_screenshot(cmd, f"screenshots/pubkey/{PATH_IMG[cmd.model]}/reject_get_public_key/00005.png")
cmd.client.press_and_release('both')
if cmd.model == "nanox" or cmd.model == "nanosp":
# Verify address
compare_screenshot(cmd, f"screenshots/pubkey/{PATH_IMG[cmd.model]}/reject_get_public_key/00000.png")

View File

@@ -27,7 +27,7 @@ def test_sign_simple(cmd):
with cmd.simple_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
sleep(0.5)
if cmd.model == "nanos":
# Review transaction
compare_screenshot(cmd, f"screenshots/sign/{PATH_IMG[cmd.model]}/simple/00000.png")
@@ -87,7 +87,7 @@ def test_sign_simple(cmd):
def test_sign_reject(cmd):
result: list = []
# Ether coin type
bip32_path="44'/60'/1'/0/0"
@@ -134,7 +134,7 @@ def test_sign_reject(cmd):
# Accept and send
compare_screenshot(cmd, f"screenshots/sign/{PATH_IMG[cmd.model]}/reject/00008.png")
cmd.client.press_and_release('right')
# Reject
compare_screenshot(cmd, f"screenshots/sign/{PATH_IMG[cmd.model]}/reject/00009.png")
cmd.client.press_and_release('both')
@@ -169,7 +169,7 @@ def test_sign_reject(cmd):
def test_sign_limit_nonce(cmd):
result: list = []
# Ether coin type
bip32_path="44'/60'/1'/0/0"
@@ -246,7 +246,7 @@ def test_sign_limit_nonce(cmd):
def test_sign_error_transaction_type(cmd):
result: list = []
# Ether coin type
bip32_path="44'/60'/1'/0/0"
@@ -311,7 +311,7 @@ def test_sign_nonce_display(cmd):
with cmd.simple_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
sleep(0.5)
if cmd.model == "nanos":
# Review transaction
compare_screenshot(cmd, f"screenshots/sign/{PATH_IMG[cmd.model]}/nonce_display/00000.png")
@@ -413,7 +413,7 @@ def test_sign_blind_simple(cmd):
with cmd.simple_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
sleep(0.5)
if cmd.model == "nanos":
# Review transaction
compare_screenshot(cmd, f"screenshots/sign/{PATH_IMG[cmd.model]}/blind_simple/00000.png")
@@ -546,7 +546,7 @@ def test_sign_blind_and_nonce_display(cmd):
with cmd.simple_sign_tx(bip32_path=bip32_path, transaction=transaction, result=result) as ex:
sleep(0.5)
if cmd.model == "nanos":
# Review transaction
compare_screenshot(cmd, f"screenshots/sign/{PATH_IMG[cmd.model]}/blind_and_nonce_display/00000.png")

View File

@@ -19,4 +19,4 @@ build/
# Coverage file
coverage.info
coverage
coverage

View File

@@ -62,4 +62,4 @@ add_library(demo SHARED ./demo_tu.c)
target_link_libraries(test_demo PUBLIC cmocka gcov demo)
add_test(test_demo test_demo)
add_test(test_demo test_demo)

View File

@@ -39,4 +39,4 @@ clean:
@if [ -d coverage ]; then $(ECHO) -e "${RED}[ RM ]${RESET}" coverage && $(RM) -r coverage ; fi;
@if [ -f coverage.info ]; then $(ECHO) -e "${RED}[ RM ]${RESET}" coverage.info && $(RM) -r coverage.info ; fi;
.PHONY: all coverage clean
.PHONY: all coverage clean

View File

@@ -1,7 +1,7 @@
# Unit tests
It is important to unit test your functions.
This also allows you to document how your functions work.
It is important to unit test your functions.
This also allows you to document how your functions work.
We use the library [**cmocka**](https://cmocka.org/#features)
## Requirement
@@ -9,11 +9,12 @@ We use the library [**cmocka**](https://cmocka.org/#features)
- [CMake >= 3.10](https://cmake.org/download/)
- [lcov >= 1.14](http://ltp.sourceforge.net/coverage/lcov.php)
Don't worry, you don't necessarily need to install the `cmocka library` because the **cmakelist automatically fetches** the library
Don't worry, you don't necessarily need to install the `cmocka library`
because the **cmakelist automatically fetches** the library
## Add new test
Create new file into `tests` folder and follow [this initiation](https://cmocka.org/talks/cmocka_unit_testing_and_mocking.pdf)
Create new file into `tests` folder and follow [this initiation](https://cmocka.org/talks/cmocka_unit_testing_and_mocking.pdf)
Now go to the `CMakeLists.txt` file and add your test with the specific file you want to test.
@@ -27,12 +28,15 @@ The `default rules` of makefile will compile the tests and run them.
make
```
The `coverage rule` will launch the default rules and generate the coverage and you will be **automatically redirected** to the generated .html
The `coverage rule` will launch the default rules and generate the coverage
and you will be **automatically redirected** to the generated .html
```sh
make coverage
```
The `clean rule` will delete the folders and files generated
```sh
make clean
```
```

View File

@@ -9,4 +9,4 @@ int local_strchr_demo(char *string, char ch) {
}
}
return -1;
}
}

View File

@@ -15,4 +15,4 @@ int main(void) {
cmocka_unit_test(null_test_success),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
}

View File

@@ -1,4 +1,4 @@
/node_modules
/snapshots-tmp
/elfs
/lib
/lib

View File

@@ -5,4 +5,4 @@ all:
yarn install
yarn test
.PHONY: all
.PHONY: all

View File

@@ -14,4 +14,4 @@ module.exports = async () => {
await Zemu.checkAndPullImage();
await Zemu.stopAllEmuContainers();
fsExtra.emptyDirSync("snapshots/tmp")
};
};

View File

@@ -34,6 +34,6 @@ module.exports = {
// Path of the file where tests can be """decorated"""
setupFilesAfterEnv: ['<rootDir>/setupTests.js'],
// Stop immediatly when a test fail
// Stop immediately when a test fail
bail: true,
};

View File

@@ -19,4 +19,4 @@ export const sim_options_x = {
export const Resolve = require("path").resolve;
export const NANOS_ELF_PATH = Resolve("elfs/ethereum_nanos.elf");
export const NANOX_ELF_PATH = Resolve("elfs/ethereum_nanox.elf");
export const NANOX_ELF_PATH = Resolve("elfs/ethereum_nanox.elf");

View File

@@ -16,4 +16,4 @@ expect.extend({
}
}
},
});
});