Skip to content

Commit

Permalink
[Fix] Pyhton unittest framework and CircleCI tests
Browse files Browse the repository at this point in the history
  • Loading branch information
iamalwaysuncomfortable authored Nov 7, 2023
2 parents 8b32cdf + a01bf9d commit f687f93
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 75 deletions.
45 changes: 45 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
version: 2.1

jobs:
build-and-test:
docker:
- image: cimg/python:3.12.0
working_directory: ~/project/sdk
steps:
- checkout
# Setting up a virtual environment for the Python project
- run: python3 -m venv .env
- run: source .env/bin/activate
# Install Rust
- run:
name: Install Rust
command: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
echo 'source $HOME/.cargo/env' >> $BASH_ENV
source $BASH_ENV
- run: rustc --version # just to confirm it's installed
# Install maturin and dependencies
- run:
name: Activate virtualenv and install dependencies
command: |
. .env/bin/activate
pip install maturin[patchelf]
- run:
name: Build and develop the package
command: |
. .env/bin/activate
cd sdk
maturin develop
# Run the unittests
- run:
name: Run tests
command: |
. .env/bin/activate
cd sdk
python3 test.py
workflows:
version: 2
build-and-test-workflow:
jobs:
- build-and-test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
sandbox/
myenv/
tmp/
.history/

.DS_Store

Expand Down
14 changes: 9 additions & 5 deletions sdk/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing

Thank you for your interest in contributing to the Aleo python-sdk! The Aleo python-sdk consists of multiple libraries, including the Aleo python library, and the zkml library. Below you can find some guidelines that the projects strive to follow.
Thank you for your interest in contributing to the Aleo sdk library of the Aleo python-sdk! Below you can find some guidelines that the projects strive to follow.

## Filing Issues

Expand All @@ -13,12 +13,17 @@ When filing a new issue:
## Development process

1. Code and enhance the respective library with new/better functionalities.
2. Write test functions to test the new functionalities.
3. Ensure all of the tests run successfully.
4. If you want to generate executables, ensure `poetry` is installed and then run:
2. Write test functions to test the new functionalities into the `test.py` file, using the `unittest` library.
3. Ensure all of the tests run successfully, using the `install.sh` file.
4. Please also ensure the CircleCI tests run successfully, as these tests will be enforced on GitHub prior to merging a pull request. For this, ensure you have `circleci-cli` [installed](https://circleci.com/docs/local-cli/), and `Docker` [installed](https://docs.docker.com/engine/install/). Then, navigate to the `python-sdk` root folder of the repository and run:
```bash
circleci local execute build-and-test
```
5. If you want to generate executables for the release, ensure `poetry` is installed and then run:
```bash
poetry build
```
In the future, we aim to automate this step with automated building through CircleCI.

## Pull requests

Expand All @@ -27,4 +32,3 @@ Please follow the instructions below when filing pull requests:
- Ensure that your branch is forked from the current [master](https://github.com/AleoHQ/python-sdk/tree/master) branch.
- Provide descriptive text for the feature or proposal. Be sure to link the pull request to any issues by using keywords. Example: "closes #130".
- Write clear and concise commit messages, describing the changes you made.
- For the zkml library only: Run `pre-commit run --all-files` before you commit. You can find the installation details for pre-commit [here](https://pre-commit.com/). The pre-commit hooks, as configured in this repository, enforce PEP 8 ([PEP 8 style guide](https://peps.python.org/pep-0008/)), including docstrings for all public-facing functions and classes. For details, please refer to the `.pre-commit-config.yaml` file.
7 changes: 4 additions & 3 deletions sdk/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ bash install.sh
```
This will print out a simple aleo Private Key that is generated by the entropy present on your device.

## Contributing
If you wish to contribute, please follow the contribution guidelines outlined on [GitHub](https://github.com/AleoHQ/python-sdk/blob/master/sdk/CONTRIBUTING.md).

## Future Work Planned
This SDK will be expanded to include the following features:
* Aleo Account Management
* Aleo program deployment, execution, and management
* Leo program compilation and execution

It is also planned to integrate this SDK with Aleo's ZkML Package so that the full suite of Aleo program execution and account management capabilities can be used with ZkML.

If you wish to contribute, please follow the contribution guidelines outlined on [GitHub](https://github.com/AleoHQ/python-sdk/blob/master/sdk/CONTRIBUTING.md). For efficient workflows, we also encourage you to get in touch with the developers prior to contributing.
It is also planned to integrate this SDK with Aleo's ZkML Package so that the full suite of Aleo program execution and account management capabilities can be used with ZkML.
Binary file not shown.
138 changes: 71 additions & 67 deletions sdk/test.py
Original file line number Diff line number Diff line change
@@ -1,80 +1,84 @@
# -*- coding: utf-8 -*-
import aleo
import unittest
import json

def test_sanity():
c_private_key = "APrivateKey1zkp3dQx4WASWYQVWKkq14v3RoQDfY2kbLssUj7iifi1VUQ6"
c_view_key = "AViewKey1cxguxtKkjYnT9XDza9yTvVMxt6Ckb1Pv4ck1hppMzmCB"
c_address = "aleo184vuwr5u7u0ha5f5k44067dd2uaqewxx6pe5ltha5pv99wvhfqxqv339h4"
class TestAleo(unittest.TestCase):

private_key = aleo.PrivateKey.from_string(c_private_key)

assert str(private_key) == c_private_key
assert str(private_key.view_key()) == c_view_key
assert str(private_key.address()) == c_address
def test_sanity(self):
c_private_key = "APrivateKey1zkp3dQx4WASWYQVWKkq14v3RoQDfY2kbLssUj7iifi1VUQ6"
c_view_key = "AViewKey1cxguxtKkjYnT9XDza9yTvVMxt6Ckb1Pv4ck1hppMzmCB"
c_address = "aleo184vuwr5u7u0ha5f5k44067dd2uaqewxx6pe5ltha5pv99wvhfqxqv339h4"

view_key = aleo.ViewKey.from_string(c_view_key)
assert str(view_key) == c_view_key
assert view_key == private_key.view_key()
private_key = aleo.PrivateKey.from_string(c_private_key)

self.assertEqual(str(private_key), c_private_key)
self.assertEqual(str(private_key.view_key()), c_view_key)
self.assertEqual(str(private_key.address()), c_address)

address = aleo.Address.from_string(c_address)
assert str(address) == c_address
assert address == private_key.address()
view_key = aleo.ViewKey.from_string(c_view_key)
self.assertEqual(str(view_key), c_view_key)
self.assertEqual(view_key, private_key.view_key())

def test_decrypt_success():
c_plaintext = """{
address = aleo.Address.from_string(c_address)
self.assertEqual(str(address), c_address)
self.assertEqual(address, private_key.address())

def test_decrypt_success(self):
c_plaintext = """{
owner: aleo1j7qxyunfldj2lp8hsvy7mw5k8zaqgjfyr72x2gh3x4ewgae8v5gscf5jh3.private,
microcredits: 1500000000000000u64.private,
_nonce: 3077450429259593211617823051143573281856129402760267155982965992208217472983group.public
}"""
c_ciphertext = "record1qyqsqpe2szk2wwwq56akkwx586hkndl3r8vzdwve32lm7elvphh37rsyqyxx66trwfhkxun9v35hguerqqpqzqrtjzeu6vah9x2me2exkgege824sd8x2379scspmrmtvczs0d93qttl7y92ga0k0rsexu409hu3vlehe3yxjhmey3frh2z5pxm5cmxsv4un97q"
c_viewkey = "AViewKey1ccEt8A2Ryva5rxnKcAbn7wgTaTsb79tzkKHFpeKsm9NX"

view_key = aleo.ViewKey.from_string(c_viewkey)
ciphertext = aleo.RecordCiphertext.from_string(c_ciphertext)
plaintext = view_key.decrypt(ciphertext)
assert str(plaintext) == c_plaintext

def test_signature_verify():
address = aleo.Address.from_string("aleo16u4ecz4yqq0udtnmsy8qzvj8emnua24n27c264f2t3unekdlpy8sh4hat2")
c_signature = "sign1q366eqppwqvmsq0epddmkpqr7ul5rkkltewatf4wdwd82l5yhypdwfnrng6tkj3ryx36wz2dptfq4aev8pwl85u9u6fk48mwmqe35q7h3ptmdtcfxxlcc6ardzayk5ykn2xzp5mhv3spwl3ajgc3y8mfqdmqs7fq3w4wc6j65e3z9ttthqwfy570yef6l9f8klnskzsu9adquzsjwhw"
signature = aleo.Signature.from_string(c_signature)
message = bytes("asd", "utf-8")
bad_message = bytes("qwe", "utf-8")
assert signature.verify(address, message)
assert not signature.verify(address, bad_message)
assert signature == aleo.Signature.from_string(c_signature)

def test_account_sanity():
private_key = aleo.PrivateKey.from_string("APrivateKey1zkp3dQx4WASWYQVWKkq14v3RoQDfY2kbLssUj7iifi1VUQ6")
account = aleo.Account.from_private_key(private_key)
assert account.private_key() == private_key
assert account == aleo.Account.from_private_key(private_key)
message = bytes("asd", "utf-8")
bad_message = bytes("qwe", "utf-8")
signature = account.sign(message)
assert account.verify(signature, message)
assert not account.verify(signature, bad_message)
assert signature.verify(account.address(), message)

def test_coinbase():
address = aleo.Address.from_string("aleo16xwtrvntrfnan84sy3qg2gdkkp5u5p7sjc882lx8n06fjx2k0yqsklw8sv")
solution_json = "{\"partial_solution\":{\"address\":\"aleo16xwtrvntrfnan84sy3qg2gdkkp5u5p7sjc882lx8n06fjx2k0yqsklw8sv\",\"nonce\":5751994693410499959,\"commitment\":\"puzzle163g3gms8kle6z7pfrnelsxmt5qk88sycdxjrfd2chfrmcaa58uv28u4amjhhzyc08wr6ur2hjsusqvgm7mp\"},\"proof.w\":{\"x\":\"46184004058746376929865476153864114989216680475842020861467330568081354981230088442717116178378251337401583339204\",\"y\":\"183283507821413711045927236980084997259573867323884239590264843665205515176450368153011402822680772267880564185790\",\"infinity\":false}}"
challenge_json = "{\"epoch_number\":233,\"epoch_block_hash\":\"ab15lsq2zxsvr0am25afrvnczglagu7utpzuzn2sp94f3vyefm4558quexrn3\",\"degree\":8191}"
challenge = aleo.EpochChallenge.from_json(challenge_json)
solution = aleo.ProverSolution.from_json(solution_json)

assert solution.address() == address
assert str(challenge) == challenge_json
assert str(solution) == solution_json

# Skip it because it takes too much time to load the puzzle
# puzzle = aleo.CoinbasePuzzle.load()
# verifying_key = puzzle.verifying_key()
# assert solution.verify(verifying_key, challenge, 100)
c_ciphertext = "record1qyqsqpe2szk2wwwq56akkwx586hkndl3r8vzdwve32lm7elvphh37rsyqyxx66trwfhkxun9v35hguerqqpqzqrtjzeu6vah9x2me2exkgege824sd8x2379scspmrmtvczs0d93qttl7y92ga0k0rsexu409hu3vlehe3yxjhmey3frh2z5pxm5cmxsv4un97q"
c_viewkey = "AViewKey1ccEt8A2Ryva5rxnKcAbn7wgTaTsb79tzkKHFpeKsm9NX"

view_key = aleo.ViewKey.from_string(c_viewkey)
ciphertext = aleo.RecordCiphertext.from_string(c_ciphertext)
plaintext = view_key.decrypt(ciphertext)

self.assertEqual(str(plaintext), c_plaintext)

def test_signature_verify(self):
address = aleo.Address.from_string("aleo16u4ecz4yqq0udtnmsy8qzvj8emnua24n27c264f2t3unekdlpy8sh4hat2")
c_signature = "sign1q366eqppwqvmsq0epddmkpqr7ul5rkkltewatf4wdwd82l5yhypdwfnrng6tkj3ryx36wz2dptfq4aev8pwl85u9u6fk48mwmqe35q7h3ptmdtcfxxlcc6ardzayk5ykn2xzp5mhv3spwl3ajgc3y8mfqdmqs7fq3w4wc6j65e3z9ttthqwfy570yef6l9f8klnskzsu9adquzsjwhw"
signature = aleo.Signature.from_string(c_signature)
message = bytes("asd", "utf-8")
bad_message = bytes("qwe", "utf-8")
self.assertTrue(signature.verify(address, message))
self.assertFalse(signature.verify(address, bad_message))
self.assertEqual(signature, aleo.Signature.from_string(c_signature))

def test_account_sanity(self):
private_key = aleo.PrivateKey.from_string("APrivateKey1zkp3dQx4WASWYQVWKkq14v3RoQDfY2kbLssUj7iifi1VUQ6")
account = aleo.Account.from_private_key(private_key)

self.assertEqual(account.private_key(), private_key)
self.assertEqual(account, aleo.Account.from_private_key(private_key))

message = bytes("asd", "utf-8")
bad_message = bytes("qwe", "utf-8")
signature = account.sign(message)

self.assertTrue(account.verify(signature, message))
self.assertFalse(account.verify(signature, bad_message))
self.assertTrue(signature.verify(account.address(), message))

def test_coinbase(self):
address = aleo.Address.from_string("aleo16xwtrvntrfnan84sy3qg2gdkkp5u5p7sjc882lx8n06fjx2k0yqsklw8sv")
solution_json = "{\"partial_solution\":{\"address\":\"aleo16xwtrvntrfnan84sy3qg2gdkkp5u5p7sjc882lx8n06fjx2k0yqsklw8sv\",\"nonce\":5751994693410499959,\"commitment\":\"puzzle163g3gms8kle6z7pfrnelsxmt5qk88sycdxjrfd2chfrmcaa58uv28u4amjhhzyc08wr6ur2hjsusqvgm7mp\"},\"proof.w\":{\"x\":\"46184004058746376929865476153864114989216680475842020861467330568081354981230088442717116178378251337401583339204\",\"y\":\"183283507821413711045927236980084997259573867323884239590264843665205515176450368153011402822680772267880564185790\",\"infinity\":false}}"
challenge_json = "{\"epoch_number\":233,\"epoch_block_hash\":\"ab15lsq2zxsvr0am25afrvnczglagu7utpzuzn2sp94f3vyefm4558quexrn3\",\"degree\":8191}"
challenge = aleo.EpochChallenge.from_json(challenge_json)
solution = aleo.ProverSolution.from_json(solution_json)

self.assertEqual(solution.address(), address)
self.assertEqual(str(challenge), challenge_json)
self.assertEqual(str(solution), solution_json)

# Skip it because it takes too much time to load the puzzle
# puzzle = aleo.CoinbasePuzzle.load()
# verifying_key = puzzle.verifying_key()
# assert solution.verify(verifying_key, challenge, 100)

if __name__ == "__main__":
test_sanity()
test_decrypt_success()
test_signature_verify()
test_account_sanity()
test_coinbase()
unittest.main()

0 comments on commit f687f93

Please sign in to comment.