Aller au contenu principal

Manage rules with Prolog

Welcome, Axone builders, to an exciting journey at the crossroads of Prolog and blockchain!

This tutorial delves into the fascinating realm of logic programming and its profound impact on the "law" governing off-chain resources usages. Whether you're interested in developing using the protocol or are intrigued by one of the core Axone concepts, this tutorial will equip you with the knowledge of programming rules with Prolog and how to use it to set up and enforce rules without trusting a central authority.

Why use Prolog on the Axone blockchain?

What is the Axone protocol?

Axone is a governance infrastructure for off-chain digital resources. Axone is a Cosmos-based blockchain that allows anyone to define on-chain rules, intending to share any resource and create a new generation of applications on top of them without exposing the data and without the need to trust a party.

The rules define access conditions and the revenue-sharing model, for example. But how can we define programmatically these terms? Here comes Prolog.

What is the Prolog language?

Prolog (short for Programming in Logic) is a high-level programming language associated with artificial intelligence and computational linguistics. It's unique for its usage of formal logic and the concept of predicate calculus.

The declarative nature of Prolog makes it an excellent choice for establishing governance rules in decentralized systems where rules can be explicitly stated and enforced. Unlike procedural languages, where the control flow is explicitly coded, Prolog uses a declarative approach where you declare the facts and rules.

How does the Axone protocol leverage Prolog language?

The Axone blockchain has a Prolog interpreter built-in, the "logic module", which enables the definition of complex business logic and agreement conditions using a concise and human-readable syntax.

Decentralized programs (smart contracts executions) operated by the Axone blockchain nodes are thus able to load and query Prolog code.

Using Prolog improves the readability and understandability of smart contracts, making them easier to audit, verify, and maintain.

Your first Prolog program

Understanding Prolog

Prolog programs are .pl files containing facts, rules, and queries.

Facts

Facts in Prolog are basic assertions about your world. For instance:

memberOf(alice, council).
memberOf(bob, council).

This states the facts that alice and bob are members of the council.

Rules

Rules are logical formulas that define relationships between facts. For example:

can_vote(X) :- memberOf(X, council).

This rule states that someone X can vote if X is a council member.

Queries

Queries are how you ask questions about the facts and rules. For example:

?- can_vote(alice).

This query asks if alice can vote. Given our facts and rules, it would answer true.

Prolog predicates

Predicates are logical units that encompass facts and rules related to a specific concept or relationship. They provide a way to group related facts and rules under a common name. Predicates are defined by one or more clauses, where each clause specifies a condition or set of conditions that must be satisfied for the predicate to be true. Predicates can consist of facts only, rules only, or a combination of both.

Predicates have a name and a fixed number of arguments. The number of arguments a predicate takes is called its "arity".

Here are some examples of predicates:

  • parent(john, jim).: This predicate, named parent, has arity 2. It states a relationship that "John is a parent of Jim".
  • greater_than(5, 3).: The predicate, named greater_than, also has arity 2. It would be used in a Prolog program to state that 5 is greater than 3.

The SWI Prolog website gives you all its built-in predicates.

attention

The Axone blockchain uses ichiban/prolog, a different Prolog interpreter. Natively available predicates differ.

Installing Prolog

Prolog has various distributions, but SWI-Prolog is widely adopted and well-documented, which makes it a suitable choice for beginners.

On a Debian-based Linux distro, you can install SWI-Prolog using apt-get:

sudo apt-get install software-properties-common
sudo apt-add-repository ppa:swi-prolog/stable
sudo apt-get update
sudo apt-get install swi-prolog

On macOS, you can use Homebrew:

brew install swi-prolog

On Windows, you can download the installer from the official SWI-Prolog website.

Running Prolog

To load facts and rules in SWI-Prolog (SWIPL), you can follow these steps:

  1. Create a new file with a .pl extension, my_knowledgebase.pl, for example.

  2. Define your facts and rules using Prolog syntax. In this example, we have two facts (memberOf/2) and one rule (can_vote/1).

% Facts
memberOf(alice, council).
memberOf(bob, council).

% Rules
can_vote(X) :- memberOf(X, council).
  1. Start a Prolog interpreter session by typing swipl in your terminal:
swipl
  1. Load the file into SWIPL by typing [filename]. or consult('filename')., where filename is the name of your file without the .pl extension. For example, if your file is named my_knowledgebase.pl, you can use either of the following commands:
?- [my_knowledgebase].

or

?- consult('my_knowledgebase').
  1. SWIPL will read and load the file, making the facts and rules available for querying. You can now use the loaded knowledge base in your Prolog sessions.

For example, if you type can_vote(alice)., you get the following answer:

?- can_vote(alice).
true.

can_vote(marc). returns false:

?- can_vote(marc).
false.

Here is an answer with substitutions (type ; after the first result to get another)

?- can_vote(X).
X = alice ;
X = bob.
astuce

Need to exit? Use the halt/0 predicate:

?- halt.

Here's an example of how Prolog can be used to define and enforce governance rules for accessing shared private datasets between different companies:

% Facts
company(company1).
company(company2).
company(company3).

dataset(company1, dataset1).
dataset(company2, dataset2).
dataset(company3, dataset3).

permission(company1, read, dataset2).
permission(company2, read, dataset1).
permission(company2, read, dataset3).
permission(company3, read, dataset1).

% Rules
has_permission(Company, Action, Dataset) :-
permission(Company, Action, Dataset).

In the above example, we define the companies using the company/1 fact and the datasets using the dataset/2 fact. The permission/3 fact associates a company with an action (e.g., read) and a specific dataset, indicating each company's permissions over the datasets.

Once we load this Prolog code into a Prolog interpreter or compiler, we can query the system to check if a company has permission to perform a specific action on a dataset. For example:

?- consult(sharing_resources).
true.

?- has_permission(company1, read, dataset2).
true.

The Prolog interpreter will evaluate the rules and facts and respond with true if company1 has the "read" permission for dataset2.

This example demonstrates how a Prolog code can define and enforce conditions for accessing shared private datasets between companies. By leveraging Prolog's logical inference capabilities, you can create flexible and scalable rules that control data access and permissions across multiple organizations in a secure and controlled manner.

Storing and querying a Prolog program with the Axone blockchain

info

To continue, you should:

  1. Install the Axone daemon CLI and jq
  2. Create a wallet or import one from your seed:
# Import from a mnemonic, you can replace "mywallet" with another wallet name
okp4d keys add --recover mywallet

# or create a new one, you can replace "mywallet" with another wallet name
okp4d keys add mywallet

# Get your address and name of your keys
okp4d keys list
  1. Get $KNOW test tokens

Prolog query with the okp4d CLI

The following command calls the logic module:

# load with facts and rules inline, query can_vote(X).:
okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--program "memberOf(alice, council). memberOf(bob,council). can_vote(X) :- memberOf(X, council)." \
"can_vote(X)."

# load facts and rules from a local Prolog file, query can_vote(X).:
okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--program-file my_knowledgebase.pl \
"can_vote(X)."


# Returns only one suitable substitution
: '
answer:
has_more: true
results:
- substitutions:
- term:
arguments: []
name: alice
variable: X
success: true
variables:
- X
gas_used: "12531"
height: "2637781"
'

You can optionally use the —-program flag to provide rules and facts. The query above asks for a valid substitution of X for the can_vote(X) rule. alice is the first valid substitution found.

How to store rules (a Prolog program) on-chain with the okp4d CLI

The law-stone smart contract aims to provide GaaS (i.e. Governance as a Service) in any Cosmos blockchains using the CosmWasm framework and the logic Axone module.

To store a Prolog program and be able to query it later within the Axone blockchain, you have to instantiate a new law-stone.

law-stone instantiate considerations

The identifier assigned to this smart contract once compiled and deployed on the testnet (chain-id = okp4-nemeton-1) is CODE_ID = 5.
You have to provide two parameters to instantiate:

  1. program: the base64 encoded program (Prolog code)
  2. storage_address: another smart contract, objectarium, stores unstructured data as Prolog programs. You should specify the address of an objectarium contract on which the program will be stored and pinned (pinning prevents its removal and thus ensure its availability).

You can use the following command to store the local my_knowledgebase.pl Prolog program, with okp41lppz4x9dtmccek2m6cezjlwwzup6pdqrkvxjpk95806c3dewgrfq602kgx as a deployed objectarium instance:

okp4d tx wasm instantiate 5 \
--from mywallet \
--label "rules-tutorial-ex-$(date +%s)" \
--no-admin \
--chain-id okp4-nemeton-1 \
--gas 1000000 \
--node https://api.testnet.okp4.network:443/rpc \
"{\"program\":\"$(cat my_knowledgebase.pl | base64 | tr -d '\n\r')\", \"storage_address\": \"okp41lppz4x9dtmccek2m6cezjlwwzup6pdqrkvxjpk95806c3dewgrfq602kgx\"}"

Replace the --from value by your wallet name. You can also change the --label name as you want but note it should be unique. You can replace --no-admin with --admin YOUR_OKP4_ADDR if you want to be able to "break" (to remove the stored program).

law-stone instantiate transaction results

The following command gets you the contract address of the last law-stone (CODE_ID = 5) instantiated by the Axone address okp41z4ldttn975ku764er2nvtfq47n6n7jfxnkc2k9

okp4d query txs \
--events 'message.sender=okp41z4ldttn975ku764er2nvtfq47n6n7jfxnkc2k9&instantiate.code_id=5' \
--chain-id okp4-nemeton-1 \
--node https://api.testnet.okp4.network:443/rpc \
--output json | jq '.txs[-1].logs[-1].events[] | select(.type == "instantiate").attributes[] | select(.key == "_contract_address").value'

# "okp41dey5a35ssvfulh2xud3nkwk423fp0t40nga4a8xykx9frmhm6jpqne0alf"

You may want to know the object_id of the Prolog program you stored in the objectarium contract. Here is how you can have it:

okp4d query txs --events 'message.sender=okp41z4ldttn975ku764er2nvtfq47n6n7jfxnkc2k9&instantiate.code_id=5' \
--chain-id okp4-nemeton-1 --node https://api.testnet.okp4.network:443/rpc \
--output json | jq '.txs[-1].logs[-1].events[] | select(.type == "wasm").attributes[] | select(.key == "id").value'

# "2625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3"

The objectarium smart contract has a query method to get the base64 stored data by its object id:

okp4d query wasm contract-state smart okp41lppz4x9dtmccek2m6cezjlwwzup6pdqrkvxjpk95806c3dewgrfq602kgx \
--output json \
--chain-id okp4-nemeton-1 \
--node https://api.testnet.okp4.network:443/rpc \
"{\"object_data\": {\"id\":\"2625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3\"}}" \
| jq '.data' | tr -d '"'

# JSBGYWN0cwptZW1iZXIoYWxpY2UsIGNvdW5jaWwpLgptZW1iZXIoYm9iLCBjb3VuY2lsKS4KCiUgUnVsZXMKY2FuX3ZvdGUoWCkgOi0gbWVtYmVyKFgsIGNvdW5jaWwpLg==

To get the Prolog code, you need to decode the data:

echo "JSBGYWN0cwptZW1iZXIoYWxpY2UsIGNvdW5jaWwpLgptZW1iZXIoYm9iLCBjb3VuY2lsKS4KCiUgUnVsZXMKY2FuX3ZvdGUoWCkgOi0gbWVtYmVyKFgsIGNvdW5jaWwpLg==" | base64 -d

# Returns the Prolog program
: '
% Facts
member(alice, council).
member(bob, council).

% Rules
can_vote(X) :- member(X, council).
'

Let's combine it all! Here is how to get back the Prolog code stored through the last law-stone (CODE_ID = 5) instantiation

  • instantiated by the OKP4 address okp41z4ldttn975ku764er2nvtfq47n6n7jfxnkc2k9
  • within the storage-oriented objectarium smart contract address = okp41lppz4x9dtmccek2m6cezjlwwzup6pdqrkvxjpk95806c3dewgrfq602kgx)

This command retrieves the stored Prolog program by querying the last instantiated law-stone contract, extracting the program ID, and decoding the base64-encoded Prolog code.

okp4d query wasm contract-state smart okp41lppz4x9dtmccek2m6cezjlwwzup6pdqrkvxjpk95806c3dewgrfq602kgx \
--output json \
--chain-id okp4-nemeton-1 \
--node https://api.testnet.okp4.network:443/rpc \
"{\"object_data\": {\"id\": $(okp4d query txs --events 'message.sender=okp41z4ldttn975ku764er2nvtfq47n6n7jfxnkc2k9&instantiate.code_id=5' \
--chain-id okp4-nemeton-1 --node https://api.testnet.okp4.network:443/rpc \
--output json | jq '.txs[-1].logs[-1].events[] | select(.type == "wasm").attributes[] | select(.key == "id").value')}}" \
| jq '.data' | tr -d '"' | base64 -d

# Returns the Prolog program
: '
% Facts
member(alice, council).
member(bob, council).

% Rules
can_vote(X) :- member(X, council).
'

How to ask for validation rules (Prolog program) on-chain with the okp4d CLI

Now we have instantiated a law-stone smart contract (address = okp41dey5a35ssvfulh2xud3nkwk423fp0t40nga4a8xykx9frmhm6jpqne0alf), we can use the Ask query to evaluate predicates against the underlying program:

okp4d query wasm contract-state smart okp41dey5a35ssvfulh2xud3nkwk423fp0t40nga4a8xykx9frmhm6jpqne0alf \
--node https://api.testnet.okp4.network:443/rpc \
"{\"ask\": {\"query\": \"can_vote(X).\"}}"

# Returns only one suitable substitution
: '
answer:
has_more: true
results:
- substitutions:
- term:
arguments: []
name: alice
variable: X
success: true
variables:
- X
gas_used: "12531"
height: "2637781"
'

Built-in Prolog predicates within the Axone blockchain

The logic module interpreter can handle ichiban/prolog built-in predicates and custom predicates. However, their availability depends on the interpreter's configuration. For example, the built-in predicate halt/1 is not registered in the interpreter, as its use is harmful, as it stops the node executing it.

You can get the list of all available predicates as a set of whitelist / blacklist predicates by querying the logic module parameters.

astuce

The whitelist specifies the list of predicates that are allowed, and if not specified, all supported predicates are available. The blacklist specifies the list of predicates that are excluded from the set of allowed precicates. If a predicate is included in both whitelist and blacklist, it will be excluded. This means that blacklisted predicates prevails over whitelisted ones.

To get the list of all available predicates, you can query the logic module parameters:

okp4d --node "https://api.testnet.okp4.network:443/rpc" \
query logic params -ojson \
| jq -r '.params.interpreter.predicates_filter | "whitelist: " + (.whitelist | join(", ")) + "\nblacklist: " + (.blacklist | join(", "))'

Several predicates have been specially created in the logic module to enable rules with the blockchain state or operate crypto utilities.

bank_balances/2

Use this predicate to query the balance of an account:

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
"bank_balances(okp416rry8kjuzpxezhf4g4lvjk67mkjc95lterek2u, [Unit-Nb])."

# 9,899.958232 KNOW
: '
answer:
has_more: false
results:
- substitutions:
- term:
arguments: []
name: uknow
variable: Unit
- term:
arguments: []
name: "9899958232"
variable: Nb
success: true
variables:
- Nb
- Unit
gas_used: "12814"
height: "2687300"
'

You can thus check a balance threshold with a bank_balances_has_sufficient_coin/3 rule:

# bank_balances_has_sufficient_coin(Addr, Limit, Unit) :-
# bank_balances(Addr, [Unit-Nb]),
# compare(>, Nb, Limit).

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--program "bank_balances_has_sufficient_coin(Addr, Limit, Unit) :- bank_balances(Addr, [Unit-Nb]), compare(>, Nb, Limit)." \
"bank_balances_has_sufficient_coin(okp416rry8kjuzpxezhf4g4lvjk67mkjc95lterek2u, 9899958230, uknow)."

# OK
: '
answer:
has_more: false
results:
- substitutions: []
success: true
variables: []
gas_used: "12815"
height: "2687574"
'

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--program "bank_balances_has_sufficient_coin(Addr, Limit, Unit) :- bank_balances(Addr, [Unit-Nb]), compare(>, Nb, Limit)." \
"bank_balances_has_sufficient_coin(okp416rry8kjuzpxezhf4g4lvjk67mkjc95lterek2u, 99899958239, uknow)."

# NOK
: '
answer:
has_more: false
results: []
success: false
variables: []
gas_used: "12815"
height: "2687583"
'

block_height/1

It may be useful to know the block height. Here's how to get it:

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--output json \
"block_height(X)." | jq '.answer.results | last | .substitutions | last | .term.name'

block_time/1

The following command shows you how you can have the current time (Unix Epoch Time):

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--output json \
"block_time(X)." | jq '.answer.results | last | .substitutions | last | .term.name'

consult/1, open/4

The consult(:File) predicate has been extended to enable data loading from any smart contract query through the cosmwasm URI.

The Logic module expects the File variable to be a URI with the following form: cosmwasm:{contract_name}:{contract_address}?query={contract_query}

Where:

  • {contract_name}: Only informative, represents the corresponding smart contract name or type (e.g. okp4-objectarium);
  • {contract_address}: The smart contract address to query
  • {contract_query}: Url encoded JSON query to perform on the targeted smart contract.

Let's load the Prolog program stored with the objectarium instance address = okp41lppz4x9dtmccek2m6cezjlwwzup6pdqrkvxjpk95806c3dewgrfq602kgx, id = 2625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3:

Query payload details

JSON Payload:

{ "object_data": { "id": "2625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3" } }

Url encoded payload:

%7B%22object_data%22%3A%20%7B%22id%22%3A%222625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3%22%7D%7D

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--output json \
"consult('cosmwasm:okp4-objectarium:okp41lppz4x9dtmccek2m6cezjlwwzup6pdqrkvxjpk95806c3dewgrfq602kgx?query=%7B%22object_data%22%3A%7B%22id%22%3A%222625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3%22%7D%7D'), can_vote(X)."\
| jq

# "my_knowledgebase.pl" previously stored on-chain, now evaluates 'can_vote(X).' from it: X = alice
: '
{
"height": "2689546",
"gas_used": "99533",
"answer": {
"success": true,
"has_more": true,
"variables": [
"File",
"X"
],
"results": [
{
"substitutions": [
{
"variable": "X",
"term": {
"name": "alice",
"arguments": []
}
}
]
}
]
}
}
'

You can also open a stream from a cosmwasm query with the open/4 predicate. The Stream should be read as a string with a read_string/3 predicate, and then closed with the close/1 predicate.

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--output json \
"open('cosmwasm:okp4-objectarium:okp41lppz4x9dtmccek2m6cezjlwwzup6pdqrkvxjpk95806c3dewgrfq602kgx?query=%7B%22object_data%22%3A%7B%22id%22%3A%222625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3%22%7D%7D', 'read', Stream), read_string(Stream, _, Raw), close(Stream)."\
| jq

: '
{
"height": "3082671",
"gas_used": "77954",
"answer": {
"success": true,
"has_more": false,
"variables": [
"Raw",
"Stream"
],
"results": [
{
"substitutions": [
{
"variable": "Raw",
"term": {
"name": "% Facts\\nmember(alice, council).\\nmember(bob, council).\\n\\n% Rules\\ncan_vote(X) :- member(X, council).",
"arguments": []
}
},
{
"variable": "Stream",
"term": {
"name": "<stream>(0xc0f9726230)",
"arguments": []
}
}
]
}
]
},
"user_output": ""
}
'

Useful Prolog predicates in the Axone blockchain context

bech32_address/2

Want to know the Stargaze (stars) address from an Axone one? Here is an example to get it from okp416rry8kjuzpxezhf4g4lvjk67mkjc95lterek2u:

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
"bech32_address(-(Prefix, Words), okp416rry8kjuzpxezhf4g4lvjk67mkjc95lterek2u), bech32_address(-(stars, Words), StarsEncodedAddr)."

# stars address (the result we are looking for):
# stars16rry8kjuzpxezhf4g4lvjk67mkjc95ltqrtrak
: '
answer:
has_more: false
results:
- substitutions:
- term:
arguments: []
name: stars16rry8kjuzpxezhf4g4lvjk67mkjc95ltqrtrak
variable: StarsEncodedAddr
- term:
arguments: []
name: okp4
variable: Prefix
- term:
arguments: []
name: "[208,198,67,218,92,16,77,145,93,53,69,126,201,91,94,221,165,130,211,235]"
variable: Words
success: true
variables:
- Prefix
- StarsEncodedAddr
- Words
gas_used: "12533"
height: "2687799"
'

did_components/2

It breaks down a DID (decentralized identifier) into its components according to the W3C specification.

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--output json \
"did_components('did:example:123456/page?versionId=1#partTwo', did(Method, ID, Path, Query, Fragment))." \
| jq '.answer.results | last | .substitutions '

: '
[
{
"variable": "Method",
"term": {
"name": "example",
"arguments": []
}
},
{
"variable": "ID",
"term": {
"name": "'123456'",
"arguments": []
}
},
{
"variable": "Path",
"term": {
"name": "page",
"arguments": []
}
},
{
"variable": "Query",
"term": {
"name": "'versionId=1'",
"arguments": []
}
},
{
"variable": "Fragment",
"term": {
"name": "partTwo",
"arguments": []
}
}
]
'

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--output json \
"did_components('did:example:123456?versionId=1', did(Method, ID, Path, Query, Fragment))." \
| jq '.answer.results | last | .substitutions '

: '
[
{
"variable": "Method",
"term": {
"name": "example",
"arguments": []
}
},
{
"variable": "ID",
"term": {
"name": "'123456'",
"arguments": []
}
},
{
"variable": "Path",
"term": {
"name": "''",
"arguments": []
}
},
{
"variable": "Query",
"term": {
"name": "'versionId=1'",
"arguments": []
}
},
{
"variable": "Fragment",
"term": {
"name": "''",
"arguments": []
}
}
]
'

json/1, json_prolog/2

You can create JSON-like elements with a key-value list as argument of a json predicate. Use json_prolog/2 to parse JSON strings.

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--output json \
"json_prolog(JsonString,json([select-json([query-json([select-'el1, el2',limit-5,prefix-[core,mdata]])])]))." \
| jq '.answer.results[0].substitutions[0].term.name' | tr -d "'" | tr -d "\\" | sed 's/^.\(.*\).$/\1/' | jq '.'

: '
{
"select": {
"query": {
"limit": 5,
"prefix": [
"core",
"mdata"
],
"select": "el1, el2"
}
}
}
'
okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--output json \
"json_prolog('{\"select\":{\"query\":{\"limit\":5,\"prefix\":[\"core\",\"mdata\"],\"select\":\"el1, el2\"}}}',JsonEl)." \
| jq '.answer.results[0].substitutions[0].term.name'

# "json([select-json([query-json([limit-5,prefix-[core,mdata],select-'el1, el2'])])])"

hex_bytes/2, sha_hash/2

Compute the hash (and the hexa value) of a given data:

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
"sha_hash('OKP4 rocks', Hash), hex_bytes(ResHex, Hash)."

# ResHex = "'01235249e3708ac819526bf602b2ec2ed98266a6b98b386dc02e6e6b9ed4709d'"
# Hash = "[1,35,82,73,227,112,138,200,25,82,107,246,2,178,236,46,217,130,102,166,185,139,56,109,192,46,110,107,158,212,112,157]"

uri_encoded/3

You can manipulate string and get it encoded, or, inversely, have encoded strings and want a human-readable version.

The first argument of the predicate is the Composant and can be query, fragment, path or segment, the second argument is the decoded string, and the third is the encoded string.

okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--output json \
"uri_encoded(query, '{\"object_data\": {\"id\":\"2625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3\"}}', Encoded)." \
| jq '.answer.results[0].substitutions[0].term.name'

# "'%7B%22object_data%22%3A%20%7B%22id%22%3A%222625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3%22%7D%7D'"
okp4d query logic ask \
--node https://api.testnet.okp4.network:443/rpc \
--output json \
"uri_encoded(query, Decoded, '%7B%22object_data%22%3A%20%7B%22id%22%3A%222625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3%22%7D%7D')." \
| jq '.answer.results[0].substitutions[0].term.name'

# "'{\"object_data\": {\"id\":\"2625337e6025495a87cb32eb7f5a042f31e4385fd7e34c90d661bfc94dd539e3\"}}'"

Recap'

  • Axone protocol orchestrates off-chain resources with on-chain governance rules.
  • These rules are written in Prolog, and the Axone blockchain can interpret Prolog code via a logic module. Thus any smart contract instantiated on the Axone blockchain can evaluate Prolog queries.
  • Custom implementations make blockchain states and crypto utilities usable with any Prolog program queried on-chain.
  • One has to store its Prolog program with a law-stone smart contract instantiation. The instantiated smart contract can be queried for a Prolog evaluation.

Utilizing Prolog to enforce governance rules via the Axone blockchain paves the way for transparent and trustless sharing interactions and promotes interoperability without limits.

With this tutorial, you gain proficiency in Prolog and gain deeper insights into how you can implement advanced governance rules via the Axone protocol. A whole new field of possibilities opens up and everything remains to be created! Seize the opportunity to apply your newfound knowledge to real-world challenges 🚀