Skip to content

Commit

Permalink
Use automatic generation of contracts (#15)
Browse files Browse the repository at this point in the history
* A bit of tidying up, adding type hinting and better naming

* Refactor with contractsService

* Created TransactionService, 🔥 credentialregistry

* Public key example with new service

* Remove the last hardcoded contract function files

* Improving examples, adding a node envvar, more to come

* Clean old tests

* Updated CHANGELOG

* Updating README with relevant information

* Added codebeautifier link

* Fixing typos

* Remove old hardcoded addresses

* Make it easy to change parser

* Adding a new TODO

* Get addresses from contracts

* Remove config example from root directory

* delegated calls testing

* Examples working fine

* CHANGELOG updated
  • Loading branch information
javaguirre authored Jul 22, 2021
1 parent 65f05e3 commit 7a161f7
Show file tree
Hide file tree
Showing 34 changed files with 574 additions and 1,881 deletions.
2 changes: 1 addition & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[run]
branch = true
omit = */tests/*
omit = */tests/*,*/examples/*
source = .

[report]
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## v0.5.0

- Removed all the hardcoded services to make the code cleaner. This is a backwards incompatible change since
the current methods to access smart contract functions weren't PEP8 standard, didn't comply with SRP nor DRY either. **IMPORTANT**: This makes the new library incompatible backwards, check the examples to see how to implement it.

## v0.4.0

- Fix presentations registry operations to use the correct smart contract address when delegated
Expand Down
40 changes: 34 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Python version of the Alastria Identity lib

# Installing
## Installing

```bash
pip install alastria-identity
Expand All @@ -14,25 +14,53 @@ or you could use Poetry
poetry add alastria-identity
```

# Testing
## Testing

Execute tests

```bash
docker-compose run --rm identity poetry run python -m coverage run -m pytest alastria_identity -v .
```

Create and check test coverage

```bash
docker-compose run --rm identity poetry run coverage html
python -m http.server 8000
```

Open `http://localhost:8000` in your browser

# TODO
## How to use the library

You can check [the examples in this folder, we'll continue updating the documentation](https://github.com/Wealize/alastria-identity-lib-py/tree/main/alastria_identity/examples).

## Some gooodies

You can check in different files utilities that might be useful to you.

- **Types**: We use these dataclasses so it's easier to interact with the library, feel free to [use them to make it easier on yourself](https://github.com/Wealize/alastria-identity-lib-py/tree/main/alastria_identity/types). :-)
- **JWT tokens handling**: [This service](https://github.com/Wealize/alastria-identity-lib-py/blob/main/alastria_identity/services/tokens.py) makes encoding decoding jwt tokens easier.
- **Config builder**: [The config builder](https://github.com/Wealize/alastria-identity-lib-py/blob/main/alastria_identity/services/config_builder.py) receives an url and a parser class and parses the configuration so It can be read by the transaction service. You can check [the test to see how this structure ends up](https://github.com/Wealize/alastria-identity-lib-py/blob/main/alastria_identity/tests/test_parsers.py).
- **Transaction service**: [The service in charge of building a transaction](https://github.com/Wealize/alastria-identity-lib-py/tree/main/alastria_identity/services/transaction_service.py) and "talking" to the smart contract, it receives a configuration to know which parameters can use and what's available.

- This README
- Add more code examples
## Glossary

- **Provider node url**: It's the url (with `/rpc` endpoint) of the node you want to connect in which the library can interact with the Alastria identity
smart contracts.
- **Contracts info**: It's the file Alastria members created to be loaded to the identity libraries. You can't change it using the javascript library but you can set it in this one. We generate the configuration the Transaction service uses on the fly.
- **Contract names**: The contract names you need to use the library, in this case you can check the Alastria examples in the [ContractsInfo file]( 'https://raw.githubusercontent.com/alastria/alastria-identity/master/contracts/ContractInfo.md'). You can check it better formatted pasting it to [codebeautify.org](https://codebeautify.org/python-formatter-beautifier).
- **Contract addresses**: As the one above It's self-explanatory, the address of the smart contract deployed you want to use.

## TODO

- ~This README~
- ~Add more code examples~ [You can check them here](https://github.com/Wealize/alastria-identity-lib-py/tree/main/alastria_identity/examples)
- ~Create the PyPI package and push it to pypi.org~
- Test the connection with the identity Alastria network node
- Delegate calls is still a WIP, we need to finish that
- ~Delegate calls is still a WIP, we need to finish that~
- Get address from the ContractInfo data

## Contributors

Started with :heart: by the [Wealize Team](https://github.com/Wealize/alastria-identity-lib-py/graphs/contributors).
15 changes: 0 additions & 15 deletions alastria_identity/examples/alastria_contract_config_generation.py

This file was deleted.

19 changes: 19 additions & 0 deletions alastria_identity/examples/config_generation_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from alastria_identity.services import IdentityConfigBuilder, ContractParser


def main():
# We generate the config based on the markdown url
CONTRACTS_INFO_URL = 'https://raw.githubusercontent.com/alastria/alastria-identity/master/contracts/ContractInfo.md'
builder = IdentityConfigBuilder(
contracts_info_url=CONTRACTS_INFO_URL,
parser_class=ContractParser
)
config = builder.generate()

# This is the format of the config
# We'll use config['functions'] for the TransactionService
print(config)


if __name__ == '__main__':
main()
31 changes: 31 additions & 0 deletions alastria_identity/examples/contract_service_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import os

from web3 import Web3

from alastria_identity.services import (
ContractsService, IdentityConfigBuilder, ContractParser)


def main():
# We generate the config based on the markdown
CONTRACTS_INFO_URL = 'https://raw.githubusercontent.com/alastria/alastria-identity/master/contracts/ContractInfo.md'
builder = IdentityConfigBuilder(
contracts_info_url=CONTRACTS_INFO_URL,
parser_class=ContractParser
)
config = builder.generate()

# We instantiate the contract service
ALASTRIA_IDENTITY_MANAGER_CONTRACT_NAME = 'AlastriaIdentityManager'
PROVIDER_NODE_URL = os.environ.get(
'PROVIDER_NODE_URL', 'https://127.0.0.1/rpc')

endpoint = Web3(Web3.HTTPProvider(PROVIDER_NODE_URL))

contract_service = ContractsService(config)
alastria_identity_manager_contract = contract_service.get_contract_handler(
ALASTRIA_IDENTITY_MANAGER_CONTRACT_NAME, endpoint)


if __name__ == '__main__':
main()
46 changes: 46 additions & 0 deletions alastria_identity/examples/create_alastria_identity_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import os

from web3 import Web3

from alastria_identity.services import (
IdentityConfigBuilder, ContractParser, TransactionService)
from alastria_identity.types import Transaction


def main():
# We generate the config based on the markdown url
CONTRACTS_INFO_URL = 'https://raw.githubusercontent.com/alastria/alastria-identity/master/contracts/ContractInfo.md'
builder = IdentityConfigBuilder(
contracts_info_url=CONTRACTS_INFO_URL,
parser_class=ContractParser
)
config = builder.generate()

PROVIDER_NODE_URL = os.environ.get(
'PROVIDER_NODE_URL', 'https://127.0.0.1/rpc')
web3_instance = Web3(Web3.HTTPProvider(PROVIDER_NODE_URL))

# Non delegated call
PUBLIC_KEY = os.environ.get('PUBLIC_KEY', 'mykey')

transaction_service = TransactionService(
config,
'AlastriaPublicKeyRegistry',
web3_instance)
transaction_response: Transaction = transaction_service.generate_transaction(
'addKey',
[PUBLIC_KEY]
)

transaction_service = TransactionService(
config,
'AlastriaIdentityManager',
web3_instance)
transaction_response: Transaction = transaction_service.generate_transaction(
'createAlastriaIdentity',
[transaction_response.data]
)


if __name__ == '__main__':
main()
38 changes: 38 additions & 0 deletions alastria_identity/examples/credential_contract_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import os

from web3 import Web3

from alastria_identity.services import (
IdentityConfigBuilder, ContractParser, TransactionService)


def main():
# We generate the config based on the markdown url
CONTRACTS_INFO_URL = os.environ.get(
'CONTRACTS_INFO_URL',
'https://raw.githubusercontent.com/alastria/alastria-identity/master/contracts/ContractInfo.md')
builder = IdentityConfigBuilder(
contracts_info_url=CONTRACTS_INFO_URL,
parser_class=ContractParser
)
config = builder.generate()

# Non delegated call
PROVIDER_NODE_URL = os.environ.get(
'PROVIDER_NODE_URL', 'https://127.0.0.1/rpc')
web3_endpoint = Web3(Web3.HTTPProvider(PROVIDER_NODE_URL))

transaction_service = TransactionService(
config, 'AlastriaCredentialRegistry', web3_endpoint)

subject_status, issuer_status = 1, 1
transaction_service.generate_transaction(
'getCredentialStatus', [subject_status, issuer_status])

issuer_credential_hash, status = b'dummy', 1
transaction_service.enable_delegated_call().generate_transaction(
'updateCredentialStatus', [issuer_credential_hash, status])


if __name__ == '__main__':
main()
42 changes: 42 additions & 0 deletions alastria_identity/examples/identity_manager_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import os

from web3 import Web3

from alastria_identity.services import (
IdentityConfigBuilder, ContractParser, TransactionService)
from alastria_identity.types import NetworkDid


def main():
# We generate the config based on the markdown url
CONTRACTS_INFO_URL = 'https://raw.githubusercontent.com/alastria/alastria-identity/master/contracts/ContractInfo.md'
builder = IdentityConfigBuilder(
contracts_info_url=CONTRACTS_INFO_URL,
parser_class=ContractParser
)
config = builder.generate()

# Non delegated call
PROVIDER_NODE_URL = os.environ.get(
'PROVIDER_NODE_URL', 'https://127.0.0.1/rpc')
web3_endpoint = Web3(Web3.HTTPProvider(PROVIDER_NODE_URL))

transaction_service = TransactionService(
config,
'AlastriaIdentityManager',
web3_endpoint)

SIGN_DID = os.environ.get(
'SIGN_DID',
'did:ala:quor:redT:ee2d1fe7b0d4571155c93497a7a9bde56fb87b40')

# We can use NetworkDid to get the proxy_address out of a did
sign_address = NetworkDid.from_did(SIGN_DID).proxy_address
checksum = Web3.toChecksumAddress(sign_address)

transaction_service.enable_delegated_call().generate_transaction(
'prepareAlastriaID', [checksum])


if __name__ == '__main__':
main()
33 changes: 33 additions & 0 deletions alastria_identity/examples/presentation_registry_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import os

from web3 import Web3

from alastria_identity.services import (
IdentityConfigBuilder, ContractParser, TransactionService)


def main():
# We generate the config based on the markdown url
CONTRACTS_INFO_URL = 'https://raw.githubusercontent.com/alastria/alastria-identity/master/contracts/ContractInfo.md'
builder = IdentityConfigBuilder(
contracts_info_url=CONTRACTS_INFO_URL,
parser_class=ContractParser
)
config = builder.generate()

# Non delegated call
PROVIDER_NODE_URL = os.environ.get(
'PROVIDER_NODE_URL', 'https://127.0.0.1/rpc')
web3_endpoint = Web3(Web3.HTTPProvider(PROVIDER_NODE_URL))

transaction_service = TransactionService(
config,
'AlastriaPresentationRegistry',
web3_endpoint)

receiver_presentation_hash, status = b'myhash', 1
transaction_service.enable_delegated_call().generate_transaction(
'updateReceiverPresentation', [receiver_presentation_hash, status])

if __name__ == '__main__':
main()
37 changes: 37 additions & 0 deletions alastria_identity/examples/public_key_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os

from web3 import Web3

from alastria_identity.services import (
IdentityConfigBuilder, ContractParser, TransactionService)


def main():
# We generate the config based on the markdown url
CONTRACTS_INFO_URL = 'https://raw.githubusercontent.com/alastria/alastria-identity/master/contracts/ContractInfo.md'
builder = IdentityConfigBuilder(
contracts_info_url=CONTRACTS_INFO_URL,
parser_class=ContractParser
)
config = builder.generate()

# Non delegated call
PROVIDER_NODE_URL = os.environ.get(
'PROVIDER_NODE_URL', 'https://127.0.0.1/rpc')
web3_endpoint = Web3(Web3.HTTPProvider(PROVIDER_NODE_URL))

transaction_service = TransactionService(
config,
'AlastriaPublicKeyRegistry',
web3_endpoint)

subject_address = Web3.toChecksumAddress('0xee2d1fe7b0d4571155c93497a7a9bde56fb87b40')
public_key = b'12345'
transaction_service.generate_transaction(
'getPublicKeyStatus', [subject_address, public_key])

transaction_service.enable_delegated_call().generate_transaction(
'deletePublicKey', [subject_address])

if __name__ == '__main__':
main()
1 change: 1 addition & 0 deletions alastria_identity/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
class ContractNameError(Exception): pass
13 changes: 2 additions & 11 deletions alastria_identity/services/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
from .config_builder import IdentityConfigBuilder
from .contracts import (
IDENTITY_MANAGER_ADDRESS,
ContractsService,
PUBLIC_KEY_REGISTRY_ADDRESS,
PRESENTATION_REGISTRY_ADDRESS,
CREDENTIAL_REGISTRY_ADDRESS
)
from .credential_registry import CredentialRegistryService
from .contracts import ContractsService
from .identity import UserIdentityService
from .identity_manager import IdentityManagerService
from .parsers import ContractParser
from .presentation_registry import PresentationRegistryService
from .tokens import TokenService
from .public_key import PublicKeyService
from .transaction_service import TransactionService
Loading

0 comments on commit 7a161f7

Please sign in to comment.