Select one of local, testnet, or mainnet deployment:
Fetch: when running a fetch agent (see API below), set the net parameter to local or test (test is default if no value is supplied).
Sovrin: when running setup_pool(net), set the net parameter to local, test or main (local is default if no value is supplied). Testnet and mainnet are still in development and may require some debugging.
Import each of function in the format
from sovrin.[module] import [function]Note that many functions return an actor data structure when this actor is fed in as a parameter. This is an updated structure following some interaction with the Sovrin ledger, and should always be re-assigned to the actor, i.e.
actor = function(actor)The ANVIL API encrypt and authenticates credential-related messages which can be sent in your chosen manner, for example using a basic HTTP POST:
import requests
requests.post('IP_ADDRESS', message)This can be easily combined with an async web framework like Quart (a Flask superset) to build apps. For a reference implementation, see the actor apps.
Claims.py demoes the ANVIL API's Sovrin functions. It provides a quick overview of the order of functions to be run when dealing with verifiable credentials.
Run:
python3 claims.py
setup_pool(net = 'local')Sets up the pool for the current actor. Local pools can be started with sudo ./scripts/start_sovrin.sh. For irregular home IPs (i.e. not 127.0.0.1, specify your IP with the TEST_POOL_IP environment variable).
Parameters:
net: net type, one oflocal,testormain.
Returns:
pool_namepool_handle
set_self_up(name, id_, key, pool_handle, seed = None)Sets up an actor data structure.
Parameters:
name_id: wallet address. Pass asWALLET_IDenvironment variable.key: wallet private key. Pass asWALLET_KEYenvironment variable.pool_handle: must be set according tosetup_pool().seed: optional seed for instantiating existing ledger entities. Use000000000000000000000000Steward1for the local pool Steward.
Returns:
actor: actor data structure (dictionary).
teardown(pool_name, pool_handle, actor_list = [])Tears down connections after a set of interactions.
Parameters:
pool_namepool_handleactor_list: list of actor data structures to tear down, e.g.[alice, bob]for data structuresaliceandbobcreated withset_self_up()
For a full onboarding (add an actor to the ledger), use all 5 functions below (in order). For establishing a secure channel between actors already on the ledger, you only need to use the first 3.
onboarding_anchor_send(_from, unique_onboardee_name)Constructs a connection request in JSON format which can be sent e.g. by POST to another agent. Note that existing trust anchors send connection requests to actors not yet on the ledger.
Parameters:
_from: sending actor data structure.unique_onboardee_name: unique name of receiving actor (used as a reference).
Returns:
_from: updated actor data structure.connection_request: connection request JSON to be sent e.g. by POST.
onboarding_onboardee_reply(to, connection_request, from_pool)Constructs a connection response in JSON format and encrypts it to bytes which can be sent e.g. by POST to the sender of a connection request.
Parameters:
to: receiving actor data structure.connection_request: connection request JSON.from_pool: pool handle of the sender's pool.
Returns:
to: updated actor data structure.anoncrypted_connection_response: Encrypted (but not authenticated) response packet to be sent e.g. by POST.
onboarding_anchor_receive(_from, anoncrypted_connection_reponse, unique_onboardee_name)Decrypts a connection response and establishes a secure channel with the onboardee.
Parameters:
_fromanoncrypted_connection_responseunique_onboardee_name
Returns:
_from
Note there is nothing to be sent back before calling onboarding_onboardee_create_did(to) (below) on the receiver's side.
onboarding_onboardee_create_did(to)Generates a new public DID (Verinym) and creates an authenticated and encrypted packet of bytes with this information which can be sent e.g. by POST to the sender of a connection request.
Parameters:
to
Returns:
toauthcrypted_did_info: authenticated and encrypted DID packet to be sent e.g. by POST to the sender of a connection request.
onboarding_anchor_register_onboardee_did(_from, unique_onboardee_name, authcrypted_did_info)Decrypts and validates an authcrypted DID message and registers the DID on the Sovrin ledger.
Parameters:
_fromunique_onboardee_nameauthcrypted_did_info
Returns:
_from
auth_encrypt(wallet_handle, counterparty_key, from_to_verkey, message_json)Authenticates and encrypts a message in JSON format. Requires a secure channel to be established between actors, i.e.
at least up to onboarding_anchor_receive().
Parameters:
wallet_handle: i.e.actor['wallet']counterparty_keyfrom_to_verkeymessage_json: message in JSON format
Returns:
authcrypted_message
auth_decrypt(wallet_handle, key, message)Decrypts and validates an authcrypted message.
Parameters:
wallet_handlecounterparty_keymessage
Returns:
from_verkey: verification keydecrypted_message_stringdecrypted_message_json
create_schema(schema, creator)Creates and registers a new credential schema.
Parameters:
schema: schema JSON object as shown below.creator: actor data structure for actor creating the schema.
Schema objects are JSONs in the format:
{
"name": "Outlier Ventures License to Delegate Access to Data",
"version": "1.0",
"attributes": ["bot_name", "data_source", "license", "status", "year", "id"]
}Note that version numbers must be floats, not ints.
Returns:
unique_schema_name: unique schema name (will be used as a reference).schema_idcreator
create_credential_definition(creator, schema_id, unique_schema_name, revocable = False)Applies a credential definition to an existing schema and registers this on the ledger.
Parameters:
creatorschema_idunique_schema_namerevocable: whether the credential is revocable. If set toTrueyou will need to implement a revocation registry: see this code reference and this guide. Revocation registries may be added to the ANVIL API in future.
Returns:
creator
offer_credential(issuer, unique_schema_name)Create an authcrypted credential offer object to be sent e.g. by POST to a prover. This references the credential schema / definitions stored in the issuer actor's data structure as defined in the funcctions above.
Parameters:
issuer: issuer actor data structure.unique_schema_name
Returns:
issuerauthcrypted_credential_offer: authenticated and encrypted credential offer packet to be sent e.g. by POST to a credential receiver (prover).
receive_credential_offer(prover)Decrypts a credential offer and sets up a master secret so that the offered credential can be used.
Parameters:
prover: prover actor data structure.
Returns:
prover
request_credential(prover, values)Creates an authcrypted credential request object to be sent e.g. by POST to the sender of a credential offer.
Parameters:
provervalues: credential request JSON as below formatted as string (i.e.json.dumps(credential_request))
Credential requests are JSONs in the format:
{
"bot_name": {"raw": "Sophos", "encoded": "123157160150157163"},
"data_source": {"raw": "GitHub", "encoded": "107151164110165142"},
"license": {"raw": "LDAD restricted", "encoded": "11410410110440162145163164162151143164145144"},
"status": {"raw": "active", "encoded": "141143164151166145"},
"year": {"raw": "2019", "encoded": "62606171"},
"id": {"raw": "did:ov:xb3i0s5v", "encoded": "1441511447215716672170142631516016365166"}
}Encoding is arbitrary.
Returns:
proverauthcrypted_credential_request: authenticated and encrypted credential request packet to be sent e.g. by POST to the sender of a credential offer.
create_and_send_credential(issuer)Creates an authcrypted credential packet to be sent e.g. by POST to a credential receiver (prover).
Parameters:
issuer
Returns:
issuerauthcrypted_credential: authenticated and encrypted credential packet to be sent e.g. by POST to the sender of a credential request.
store_credential(prover)Decrypts a received credential and stores it in the receiver's wallet (as specified in set_self_up() above).
Parameters:
prover
Returns:
prover
request_proof_of_credential(verifier, proof_request = {})Creates an authcrypted proof request packet to be sent e.g. by POST to a prover.
Parameters:
verifier: verifier actor data structure.proof_request: proof request JSON as below formatted as string (i.e.json.dumps(proof_request))
Proof requests are JSONs in the format:
{
"nonce": "0123456789012345678901234",
"name": "LDAD restricted proof",
"version": "0.1",
"requested_attributes": {
"attr1_referent": {
"name": "bot_name"
},
"attr2_referent": {
"name": "data_source"
},
"attr3_referent": {
"name": "license"
},
"attr4_referent": {
"name": "status"
},
"attr5_referent": {
"name": "id"
}
},
"requested_predicates": {
"predicate1_referent": {
"name": "year",
"p_type": ">=",
"p_value": 2019
}
}
}An attribute is just name = 'Sophos'. A predicate is a comparison that evaluates to true or false, e.g. age >= 18. Note that, as with all Sovrin nonces, the proof request nonce must be fully numeric (you can use ANVIL's sovrin.generate_nonce(25)).
Returns:
verifierauthcrypted_proof_request: authenticated and encrypted proof request packet to be sent e.g. by POST to a prover.
create_proof_of_credential(prover, self_attested_attrs = {}, requested_attrs = [], requested_preds = [], non_issuer_attributes = [])Decrypts a proof request and constructs a proof according to it.
Parameters:
self_attested_attrs: JSON of self-attributes.requested_attrs: list of indices of requested attributes.requested_preds: list of indices of requested predicates.non_issuer_attributes: list of indices of attributes that are not in the issued credential, and therefore can't be retrieved from the ledger.
Example proof paramters according to the above example data:
self_attested_attrs = {
"attr1_referent": "Sophos",
"attr5_referent": "did:ov:xb3i0s5v"
}
requested_attrs = [2, 3, 4]
requested_preds = [1]
non_issuer_attrs = []Returns:
proverauthcrypted_proof: authenticated and encrypted proof packet to be sent e.g. by POST to a verifier.
verify_proof(verifier, assertions_to_make)Decrypts a proof and verifies it according to your chosen assertions.
Parameters:
verifierassertions_to_make: JSON of assertions to make on proof attributes, i.e. ensure attribute X is equal to Y.
Assertions to make are a JSON in the format:
{
"revealed": {
"attr2_referent": "GitHub",
"attr3_referent": "LDAD restricted",
"attr4_referent": "active"
},
"self_attested": {
"attr1_referent": "Sophos",
"attr5_referent": "did:ov:xb3i0s5v"
}
}Returns:
verifier
write_json(data, filename)Writes to a JSON file in the current directory.
Parameters:
datafilename
read_json(filename):Reads a JSON file with the name supplied from the current directory.
Parameters:
filename
Returns:
data: the data in the file.
generate_nonce(length)Generates a Sovrin-compatible numeric nonce.
Parameters:
length: how many characters the nonce should be.
Returns:
nonce: the nonce.
generate_base58(length)Generates a base58 string.
Parameters:
length: how many characters the base58 string should be.
Returns:
base58: the base58 string.
send_data(data, channel = 0):Network simulation send function, writes to a bytes file. Useful for quick testing where agents are in separate files.
Parameters:
data: data to send.channel: network channel, useful if you want to test lots of pariwise connections at once – just run each on a different channel.
receive_data(channel = 0)Network simulation receive function, reads from a bytes file. Useful for quick testing where agents are in separate files.
Parameters:
channel
Returns:
data: received data.
The following assumers you have a running Fetch.AI node. You can start one with ./scripts/start_fetch.sh.
Imports:
from fetch.agents import [function]search(search_terms, path_to_fetch_folder = './fetch', net = 'test')Parameters:
search_terms: search terms string split with underscores, e.g.license_fetch_iota_ocean.path_to_fetch_folder: path to theANVIL/anvil/fetchfolder. If you are running agents from theanvilfolder (e.g. adapting the actor apps you don't need this paramter.)net: net type, one oflocalortest.
Result:
- Writes search results to file
search_results.json.
Alternatively, run the agent directly from bash:
python3 ./path/to/searcher.py 'search_terms_split_with_underscores'
offer_service(price, service_path, path_to_fetch_folder = './fetch', net = 'test')Parameters:
price: the price of your service in Fetch.AI tokens.service_path: path to JSON data models describing your fetch service, e.g. the Sophos data service.path_to_fetch_folder: path to theANVIL/anvil/fetchfolder. If you are running agents from theanvilfolder (e.g. adapting the actor apps you don't need this paramter.)net: net type, one oflocalortest.
Result:
- Sends data to a purchaser in exchange for Fetch.AI tokens if someone purchases the service.
Alternatively, run the agent directly from bash:
python3 ./path/to/prover.py ./service/path price
purchase_service(max_price, search_terms, path_to_fetch_folder = './fetch', net = 'test')Parameters:
max_price: the maximum price you are willing to pay for the service in Fetch.AI tokens.search_terms: search terms string split with underscores, e.g.license_fetch_iota_ocean. If running asearcheragent first for service discovery, store the terms used in a variable and feed that in as the the search string here.path_to_fetch_folder: path to theANVIL/anvil/fetchfolder. If you are running agents from theanvilfolder (e.g. adapting the actor apps you don't need this paramter.)net: net type, one oflocalortest.
Result:
- Pays a seller in Fetch tokens on a match and the AEA receives the requested data.
Alternatively, run the agent directly from bash:
python3 ./path/to/verifier.py search_terms_split_with_underscores max_price
Error: indy.error.IndyError: ErrorCode.CommonInvalidStructure or indy.error.IndyError: ErrorCode.DidAlreadyExistsError
Fix: rm ~/.indy_client and re-run.
Error: OSError: dlopen(libindy.dylib, 6): image not found or similar dlopen referencing libsodium
Fix: set LD_LIBRARY_PATH and DYLD_LIBRARY_PATH environment variables to /path/to/indy/libindy/target/debug. If that doesn't work, run ./scripts/test.sh, which will detail the failure. This is most likely due to a libsodium upgrade, where Indy will look for libsodium.XX.dyld and you have libsodium.YY.dyld. Navigate to the referenced folder and make a copy of your libsodium.YY.dyld and rename the copy to libsodium.XX.dyld.
- Nonces should be fully numeric for Hyperledger Indy. This is a common cause of the
CommonInvalidStructureerror (code 113). There is an Indy-compatible nonce generator in thesovrin/utilitiesmodule. - Schema versions must be floats to be compatible with Sovrin.
- Quart forms do not allow underscores in the
namefield.