{
"cells": [
{
"cell_type": "markdown",
"id": "3e4eb758",
"metadata": {},
"source": [
"## Hello World"
]
},
{
"cell_type": "markdown",
"id": "2460ecfc",
"metadata": {},
"source": [
"In this demo notebook we will showcase a self-sovereign data scenario:\n",
"\n",
"- we will create a table in a shared data collection, that can be read by anyone in the network\n",
"- mark some fields as personal information that is not to be shared\n",
"- write a record\n",
"- read it locally (and be able to see all fields)\n",
"- read all records from a remote server\n",
" \n",
"The default Weavechain node installation is preconfigured to support this scenario (by connecting to a public weave, having a *shared* data collection defined and mapped to a in-process SQLite instance and read rights for that collection already given)."
]
},
{
"cell_type": "markdown",
"id": "8e0dbccf",
"metadata": {},
"source": [
"### 1. Create an API session"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "d96cfcaf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"res\":\"ok\",\"data\":\"pong 1674668207181\"}\n"
]
}
],
"source": [
"import pandas as pd\n",
"\n",
"from weaveapi.records import *\n",
"from weaveapi.options import *\n",
"from weaveapi.filter import *\n",
"from weaveapi.weaveh import *\n",
"\n",
"WEAVE_CONFIG = \"config/demo_client_local.config\"\n",
"nodeApi, session = connect_weave_api(WEAVE_CONFIG)\n",
"\n",
"scope = \"shared\"\n",
"table = \"directory\""
]
},
{
"cell_type": "markdown",
"id": "ac907012",
"metadata": {},
"source": [
"### 2. Create a local table"
]
},
{
"cell_type": "markdown",
"id": "7b4a5e29",
"metadata": {},
"source": [
"- we drop the existing table if already existing and re-create it from scratch\n",
"- a weavechain node can also connect to existing tables, reading their structure, but in this case we create it via the API"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "17b212cf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'res': 'ok', 'target': {'operationType': 'CREATE_TABLE', 'organization': 'weavedemo', 'account': 'weaveyh5R1ytoUCZnr3JjqMDfhUrXwqWC2EWnZX3q7krKLPcg', 'scope': 'shared', 'table': 'directory'}}\n"
]
}
],
"source": [
"layout = { \n",
" \"columns\": { \n",
" \"id\": { \"type\": \"LONG\", \"isIndexed\": True, \"isUnique\": True, \"isNullable\": False },\n",
" \"name_nickname\": { \"type\": \"STRING\" },\n",
" \"name_last\": { \"type\": \"STRING\" },\n",
" \"name_first\": { \"type\": \"STRING\" },\n",
" \"birthday\": { \"type\": \"STRING\" },\n",
" \"email_personal\": { \"type\": \"STRING\" },\n",
" \"phone_number\": { \"type\": \"STRING\" },\n",
" \"address_country\": { \"type\": \"STRING\" },\n",
" \"address_summary\": { \"type\": \"STRING\" },\n",
" \"address_timezone\": { \"type\": \"STRING\" },\n",
" \"linkedin_url\": { \"type\": \"STRING\" },\n",
" \"discord_username\": { \"type\": \"STRING\" },\n",
" \"telegram_username\": { \"type\": \"STRING\" },\n",
" \"ethereum_wallet_address\": { \"type\": \"STRING\" }\n",
" }, \n",
" \"idColumnIndex\": 0, \n",
" \"isLocal\": False,\n",
" \"applyReadTransformations\": True\n",
"}\n",
"\n",
"nodeApi.dropTable(session, scope, table).get()\n",
"reply = nodeApi.createTable(session, scope, table, CreateOptions(False, False, layout)).get()\n",
"print(reply)"
]
},
{
"cell_type": "markdown",
"id": "03d82eca",
"metadata": {},
"source": [
"### 3. Mark some fields for erasure"
]
},
{
"cell_type": "markdown",
"id": "817c68c3",
"metadata": {},
"source": [
"- the purpose is to protect certain fields when shared"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "18be11b4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'res': 'ok', 'target': {'operationType': 'UPDATE_LAYOUT', 'organization': 'weavedemo', 'account': 'weaveyh5R1ytoUCZnr3JjqMDfhUrXwqWC2EWnZX3q7krKLPcg', 'scope': 'shared', 'table': 'directory'}}\n"
]
}
],
"source": [
"reply = nodeApi.getTableDefinition(session, scope, table).get()\n",
"#print(reply)\n",
"layout = json.loads(reply[\"data\"])[\"layout\"]\n",
"layout[\"columns\"]\n",
"\n",
"newLayout = layout.copy()\n",
"del newLayout[\"layout\"]\n",
"del newLayout[\"indexes\"]\n",
"del newLayout[\"columnNames\"]\n",
"newLayout[\"columns\"] = { i[\"columnName\"]: i for i in layout[\"columns\"]}\n",
"\n",
"newLayout[\"columns\"][\"phone_number\"][\"readTransform\"] = \"ERASURE\"\n",
"newLayout[\"columns\"][\"address_summary\"][\"readTransform\"] = \"ERASURE\"\n",
"newLayout[\"columns\"][\"ethereum_wallet_address\"][\"readTransform\"] = \"ERASURE\"\n",
"newLayout[\"columns\"][\"birthday\"][\"readTransform\"] = \"ERASURE\"\n",
"\n",
"reply = nodeApi.updateLayout(session, scope, table, newLayout).get()\n",
"print(reply)"
]
},
{
"cell_type": "markdown",
"id": "256f11bb",
"metadata": {},
"source": [
"### 4. Write a record in the local storage"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "ddea986d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'res': 'ok', 'target': {'operationType': 'WRITE', 'organization': 'weavedemo', 'account': 'weaveyh5R1ytoUCZnr3JjqMDfhUrXwqWC2EWnZX3q7krKLPcg', 'scope': 'shared', 'table': 'directory'}, 'data': 'weaveyh5R1ytoUCZnr3JjqMDfhUrXwqWC2EWnZX3q7krKLPcg,USr/yA9isOGMQ3/gNenSpZLi2VhwIP9x6UacGTkuBVc=,4YjeYJpUrcrpCf4oTEvuAspeJYiQYEy1AvTgbLsTo8UNzYbHKbNiV6jZihb7si5yc8MbXcr16kmGrieJgNW8s75e'}\n"
]
}
],
"source": [
"records = Records(table, [ \n",
" [ 1, 'Nickname', 'Last Name', 'First name', '1980-01-01', 'email@gmail.com', '+40712345678', 'US', 'Secret', 'EST', 'https://www.linkedin.com/in/linkedin/', 'discord#1234', '@telegram', '0xwallet' ]\n",
"])\n",
"reply = nodeApi.write(session, scope, records, WRITE_DEFAULT).get()\n",
"print(reply)"
]
},
{
"cell_type": "markdown",
"id": "b1c4be2c",
"metadata": {},
"source": [
"### 5. Read the local record, from the local storage"
]
},
{
"cell_type": "markdown",
"id": "996711b0",
"metadata": {},
"source": [
"- since we read with the owner key and from the local node, we expect the records to have all fields visible"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "cb2dd661",
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" name_nickname | \n",
" name_last | \n",
" name_first | \n",
" birthday | \n",
" email_personal | \n",
" phone_number | \n",
" address_country | \n",
" address_summary | \n",
" address_timezone | \n",
" linkedin_url | \n",
" discord_username | \n",
" telegram_username | \n",
" ethereum_wallet_address | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 1 | \n",
" Nickname | \n",
" Last Name | \n",
" First name | \n",
" 1980-01-01 | \n",
" email@gmail.com | \n",
" +40712345678 | \n",
" US | \n",
" Secret | \n",
" EST | \n",
" https://www.linkedin.com/in/linkedin/ | \n",
" discord#1234 | \n",
" @telegram | \n",
" 0xwallet | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id name_nickname name_last name_first birthday email_personal \\\n",
"0 1 Nickname Last Name First name 1980-01-01 email@gmail.com \n",
"\n",
" phone_number address_country address_summary address_timezone \\\n",
"0 +40712345678 US Secret EST \n",
"\n",
" linkedin_url discord_username telegram_username \\\n",
"0 https://www.linkedin.com/in/linkedin/ discord#1234 @telegram \n",
"\n",
" ethereum_wallet_address \n",
"0 0xwallet "
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"scope = \"shared\"\n",
"table = \"directory\"\n",
"\n",
"reply = nodeApi.read(session, scope, table, None, READ_DEFAULT_NO_CHAIN).get()\n",
"#print(reply)\n",
"df = pd.DataFrame(reply[\"data\"])\n",
"\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"id": "49d86941",
"metadata": {},
"source": [
"### 5. Connect to proxy server"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "6f52c82f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"res\":\"ok\",\"data\":\"pong 1674668209764\"}\n"
]
}
],
"source": [
"WEAVE_CONFIG_REMOTE = \"config/demo_client_remote.config\"\n",
"nodeApi2, session2 = connect_weave_api(WEAVE_CONFIG_REMOTE)"
]
},
{
"cell_type": "markdown",
"id": "9eb7b533",
"metadata": {},
"source": [
"### 6. Read all shared records"
]
},
{
"cell_type": "markdown",
"id": "dd6c037d",
"metadata": {},
"source": [
"- we expect the records that we don't own to have certain fields erased for privacy"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "5015c87f",
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" name_nickname | \n",
" name_last | \n",
" name_first | \n",
" birthday | \n",
" email_personal | \n",
" phone_number | \n",
" address_country | \n",
" address_summary | \n",
" address_timezone | \n",
" linkedin_url | \n",
" discord_username | \n",
" telegram_username | \n",
" ethereum_wallet_address | \n",
" _nodeKey | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 1.0 | \n",
" Nickname | \n",
" Last Name | \n",
" First name | \n",
" | \n",
" email@gmail.com | \n",
" | \n",
" US | \n",
" | \n",
" EST | \n",
" https://www.linkedin.com/in/linkedin/ | \n",
" discord#1234 | \n",
" @telegram | \n",
" | \n",
" weaveyh5R1ytoUCZnr3JjqMDfhUrXwqWC2EWnZX3q7krKLPcg | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id name_nickname name_last name_first birthday email_personal \\\n",
"0 1.0 Nickname Last Name First name email@gmail.com \n",
"\n",
" phone_number address_country address_summary address_timezone \\\n",
"0 US EST \n",
"\n",
" linkedin_url discord_username telegram_username \\\n",
"0 https://www.linkedin.com/in/linkedin/ discord#1234 @telegram \n",
"\n",
" ethereum_wallet_address _nodeKey \n",
"0 weaveyh5R1ytoUCZnr3JjqMDfhUrXwqWC2EWnZX3q7krKLPcg "
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"scope = \"shared\"\n",
"table = \"directory\"\n",
"\n",
"reply = nodeApi2.read(session2, scope, table, None, READ_DEFAULT_MUX_NO_CHAIN).get()\n",
"#print(reply)\n",
"df = pd.DataFrame(reply[\"data\"].get(\"result\"))\n",
"\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"id": "8200fb82",
"metadata": {},
"source": [
"### 7. Check the local node for all operations on the shared data"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "9532baa7",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" history | \n",
" record | \n",
" recordId | \n",
"
\n",
" \n",
" \n",
" \n",
" 1 | \n",
" [{'account': 'weaveyh5R1ytoUCZnr3JjqMDfhUrXwqW... | \n",
" [1, Nickname, Last Name, First name, 1980-01-0... | \n",
" 1 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" history \\\n",
"1 [{'account': 'weaveyh5R1ytoUCZnr3JjqMDfhUrXwqW... \n",
"\n",
" record recordId \n",
"1 [1, Nickname, Last Name, First name, 1980-01-0... 1 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" account | \n",
" operation | \n",
" timestamp | \n",
" ip | \n",
" apiKey | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" weaveyh5R1ytoUCZnr3JjqMDfhUrXwqWC2EWnZX3q7krKLPcg | \n",
" write | \n",
" 1674668207300999936 | \n",
" 127.0.0.1 | \n",
" d2f86331322b497fb644e09862b681fdc2a9aa5180d0011c | \n",
"
\n",
" \n",
" 1 | \n",
" weaveyh5R1ytoUCZnr3JjqMDfhUrXwqWC2EWnZX3q7krKLPcg | \n",
" read | \n",
" 1674668207315000064 | \n",
" 127.0.0.1 | \n",
" d2f86331322b497fb644e09862b681fdc2a9aa5180d0011c | \n",
"
\n",
" \n",
" 2 | \n",
" weavexUTKAe7J5faqmiq94DXXWntyRBA8bPwmrUbCtebxWd3f | \n",
" read | \n",
" 1674668211353999872 | \n",
" 34.28.85.136 | \n",
" 1e2f9e5e7c9f406081256bf5709dd1eae5ccf2e324469e1c | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" account operation \\\n",
"0 weaveyh5R1ytoUCZnr3JjqMDfhUrXwqWC2EWnZX3q7krKLPcg write \n",
"1 weaveyh5R1ytoUCZnr3JjqMDfhUrXwqWC2EWnZX3q7krKLPcg read \n",
"2 weavexUTKAe7J5faqmiq94DXXWntyRBA8bPwmrUbCtebxWd3f read \n",
"\n",
" timestamp ip \\\n",
"0 1674668207300999936 127.0.0.1 \n",
"1 1674668207315000064 127.0.0.1 \n",
"2 1674668211353999872 34.28.85.136 \n",
"\n",
" apiKey \n",
"0 d2f86331322b497fb644e09862b681fdc2a9aa5180d0011c \n",
"1 d2f86331322b497fb644e09862b681fdc2a9aa5180d0011c \n",
"2 1e2f9e5e7c9f406081256bf5709dd1eae5ccf2e324469e1c "
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"reply = nodeApi.history(session, scope, table, None, HISTORY_DEFAULT).get()\n",
"#print(reply)\n",
"df = pd.DataFrame(reply[\"data\"]).transpose()\n",
"display(df)\n",
"\n",
"pd.DataFrame(df.iloc[0][\"history\"])"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
}
},
"nbformat": 4,
"nbformat_minor": 5
}