README ¶
Monetha: Decentralized Reputation Framework
Reputation Layer: go-sdk
- Building the source
- Contributing
- Bootstrap reputation layer
- Usage
- Deploying passport
- Passport list
- Writing facts
- Reading facts
- Changing passport permissions
- Reading facts history
- Passport scanner (sample web application)
- Private data
- Private data exchange
- Proposing private data exchange
- Getting status of private data exchange
- Accepting private data exchange
- Reading private data after private data exchange acceptance
- Closing private data exchange proposition when timed out
- Closing private data exchange after acceptance
- Opening dispute after private data exchange acceptance
- Permissioned blockchains support
Building the source
Prerequisites
- Make sure you have Git installed.
- Install Go 1.12
- Setup
$GOPATH
environment variable as described here. - Clone the repository:
mkdir -p $GOPATH/src/github.com/monetha cd $GOPATH/src/github.com/monetha git clone git@github.com:monetha/go-verifiable-data.git cd go-verifiable-data
Note: You can skip steps 2-3 on Linux and use the official docker image for Go after step 4 to build the project:
docker run -it --rm \
-v "$PWD":/go/src/github.com/monetha/go-verifiable-data \
-w /go/src/github.com/monetha/go-verifiable-data \
golang:1.12 \
/bin/bash
Build
Install dependencies:
make dependencies
Once the dependencies are installed, run
make cmd
to build the full suite of utilities. After the executable files are built, they can be found in the directory ./bin/
.
Executables
The go-verifiable-data project comes with several executables found in the cmd
directory.
Tool | Description |
---|---|
passport |
Utility tool for working with passports: deploy needed passport contracts, create passports, write/read data facts, etc. |
privatedata-exchange |
Utility tool for exchanging private data |
passport-scanner |
Web application (WebAssembly module) to get the list of deployed passports and the history of passport changes in a web browser. |
provider-registry |
Utility tool for fact provider information registration in fact provider registry. |
Contributing
Making changes
Make your changes, then ensure that the tests and the linters pass:
make lint
make test
To get the test coverage report for all packages, run the command:
make cover
Тest coverage results (cover.out
, cover.html
) will be put in ./.cover
directory.
Contracts update
After Ethereum contracts code is updated and artifacts are created:
- Copy all artifacts to
contracts/code
folder. - Run
go generate
command incontracts
folder to convert Ethereum contracts into Go package. - Commit new/updated files.
Formatting source code
make fmt
command automatically formats Go source code of the entire project.
Bootstrap reputation layer
Monetha has already deployed this set of auxiliary reputation layer contracts on Ropsten test network and Mainnet network.
The contract addresses deployed on Ropsten:
Contract | Address |
---|---|
PassportLogic |
0xaa8e71D8Fb521eaEdE9F11d8fd5182920Cb03229 |
PassportLogicRegistry |
0x11C96d40244d37ad3Bb788c15F6376cEfA28CF7c |
PassportFactory |
0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2 |
FactProviderRegistry |
0xf9dbC37BBdC68E0Ba03185F1877059C595DcF083 |
The contract addresses deployed on Mainnet:
Contract | Address |
---|---|
PassportLogic |
0xA9068B8E0D0a5B2c77dF601be3bB3d168c7fc3e2 |
PassportLogicRegistry |
0x41c32A8387ff178659ED9B04190613623F545657 |
PassportFactory |
0x53b21DC502b163Bcf3bD9a68d5db5e8E6110E1CC |
FactProviderRegistry |
0xD4666f08A40dFD0945Cac5aB83fF04625a60664C |
Consider the process of deploying your own set of auxiliary repoutation layer contracts to experiment with our implementation. If you are going to deploy your contracts, then you will have to support them yourself.
This means that if the reputation layer logic of the passport is updated by Monetha developers, you'll need to deploy a new PassportLogic
contract, register it
in an existing PassportLogicRegistry
contract (by calling addPassportLogic
method) and finally make it active (by calling setCurrentPassportLogic
).
If you use a set of Monetha deployed reputation layer contracts, then the reputation passport logic is always up-to-date with latest fixes and features.
Prepare in advance the address that will be the owner of the deployed contracts. Make sure that it has enough funds to deploy contracts (1 ETH should be enough).
Store the private key of this address in the file named ./owner.key
.
To deploy all contracts in Rospten network using Ethereum private key stored in file ./owner.key
, run the command:
./bin/passport bootstrap --ownerkey ./owner.key \
--backendurl https://ropsten.infura.io
After running the command, you should see something like the following output:
WARN [03-19|10:29:04.273] Loaded configuration owner_address=0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55 backend_url=https://ropsten.infura.io
WARN [03-19|10:29:05.038] Getting balance address=0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55
WARN [03-19|10:29:05.172] Deploying PassportLogic owner_address=0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55
WARN [03-19|10:29:05.759] Waiting for transaction hash=0xaa4149349dc9856289cacdb9158d6d215124f7a9b3d182c3b31429004a908bc8
WARN [03-19|10:29:18.216] Transaction successfully mined tx_hash=0xaa4149349dc9856289cacdb9158d6d215124f7a9b3d182c3b31429004a908bc8 cumulative_gas_used=2412986
WARN [03-19|10:29:18.216] PassportLogic deployed contract_address=0xEf95422e66761A5a468FE72c1fD3C946884d5E50
WARN [03-19|10:29:18.216] Deploying PassportLogicRegistry owner_address=0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55 impl_version=0.1 impl_address=0xEf95422e66761A5a468FE72c1fD3C946884d5E50
WARN [03-19|10:29:18.704] Waiting for transaction hash=0x1b0174592e60e8e7f8619b6e1d9bceb498530feb405c7f8f6715c26d68445ebb
WARN [03-19|10:29:39.585] Transaction successfully mined tx_hash=0x1b0174592e60e8e7f8619b6e1d9bceb498530feb405c7f8f6715c26d68445ebb cumulative_gas_used=2157734
WARN [03-19|10:29:39.585] PassportLogicRegistry deployed contract_address=0x11C96d40244d37ad3Bb788c15F6376cEfA28CF7c
WARN [03-19|10:29:39.585] Deploying PassportFactory owner_address=0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55 registry=0x11C96d40244d37ad3Bb788c15F6376cEfA28CF7c
WARN [03-19|10:29:40.275] Waiting for transaction hash=0x984b1df10640a5fe3005aea593b1cbb7af59682469564063a490820c8a8cb6f0
WARN [03-19|10:29:48.602] Transaction successfully mined tx_hash=0x984b1df10640a5fe3005aea593b1cbb7af59682469564063a490820c8a8cb6f0 cumulative_gas_used=1446005
WARN [03-19|10:29:48.602] PassportFactory deployed contract_address=0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2
WARN [03-19|10:29:48.602] Done.
In the output you can find the addresses of all the deployed contracts.
Usage
In order to create a passport and start using it, you need to use auxiliary reputation layer contracts: PassportLogic, PassportLogicRegistry, PassportFactory.
Deploying passport
Before creating a passport for a specific Ethereum address, store the private key of this Ethereum address in the file pass_owner.key
.
Make sure that the passport owner has enough money to create a passport contract. Usually passport contract deployment takes 425478
gas.
To create a passport contract you need to know address of the PassportFactory
contract. Let's try to create a passport in Ropsten
using the PassportFactory
contract deployed by Monetha (0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2
):
./bin/passport create --ownerkey ./pass_owner.key \
--factoryaddr 0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2 \
--backendurl https://ropsten.infura.io
Below you can see the output of the command to create a passport for the address 0x5b2AE3b3A801469886Bb8f5349fc3744cAa6348d
.
WARN [03-19|10:41:59.024] Loaded configuration owner_address=0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55 backend_url=https://ropsten.infura.io factory=0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2
WARN [03-19|10:41:59.798] Getting balance address=0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55
WARN [03-19|10:41:59.933] Initializing PassportFactory contract factory=0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2
WARN [03-19|10:41:59.940] Deploying Passport contract owner_address=0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55
WARN [03-19|10:42:00.692] Waiting for transaction hash=0x33e7d5dc34f5e8597859c319c34ef4f613238defbadcc2fda3ae65f508b45884
WARN [03-19|10:42:08.980] Transaction successfully mined tx_hash=0x33e7d5dc34f5e8597859c319c34ef4f613238defbadcc2fda3ae65f508b45884 cumulative_gas_used=6130011
WARN [03-19|10:42:08.987] Passport deployed contract_address=0x1C3A76a9A27470657BcBE7BfB47820457E4DB682
WARN [03-19|10:42:08.987] Initializing Passport contract passport=0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2
WARN [03-19|10:42:08.987] Claiming ownership owner_address=0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55
WARN [03-19|10:42:09.550] Waiting for transaction hash=0xae51f2769db4bb7d5c8c651cfa78b8048f5fcd6bc949ac3d6b220aa7c2d5255e
WARN [03-19|10:42:22.061] Transaction successfully mined tx_hash=0xae51f2769db4bb7d5c8c651cfa78b8048f5fcd6bc949ac3d6b220aa7c2d5255e cumulative_gas_used=2220151
WARN [03-19|10:42:22.061] Done.
As you can see in the line Passport deployed
, a passport contract was created at address 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682
.
Passport list
The passport factory allows you to get a list of all the passports that have been created.
Let's try to get a list of all passports using the address of PassportFactory
contract deployed by Monetha (0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2
)
in Ropsten network:
./bin/passport list --out /dev/stdout \
--backendurl https://ropsten.infura.io \
--factoryaddr 0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2
You should see something like this:
WARN [03-19|10:44:48.830] Loaded configuration factory_provider=0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2 backend_url=https://ropsten.infura.io
WARN [03-19|10:44:49.579] Initialising passport factory contract passport_factory=0x35Cb95Db8E6d56D1CF8D5877EB13e9EE74e457F2
WARN [03-19|10:44:49.579] FilterPassportCreated start_block=0
WARN [03-19|10:44:49.841] Writing collected passports to file
passport_address,first_owner,block_number,tx_hash
0x1C3A76a9A27470657BcBE7BfB47820457E4DB682,0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55,5233845,0x33e7d5dc34f5e8597859c319c34ef4f613238defbadcc2fda3ae65f508b45884
WARN [03-19|10:44:49.841] Done.
The output can be saved to a file and converted to the table. Currently one passport is deployed:
passport_address | first_owner | block_number | tx_hash |
---|---|---|---|
0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 | 0xDdD9b3Ea9d65cfD12b18ceA4E6f7Df4948ec4C55 | 5233845 | 0x33e7d5dc34f5e8597859c319c34ef4f613238defbadcc2fda3ae65f508b45884 |
The block number and transaction hash indicate the transaction in which the passport was created.
All passports use the same passport logic contract. Once a new passport logic is added to the passport logic registry and is activated, it will be immediately used by all passports created by this factory. How cool is that!
Writing facts
After the passport is created, any fact provider can start writing data to the passport.
Before we start writing facts to a passport, let's store the private key of the fact provider to the file fact_provider.key
.
Make sure that the fact provider has enough funds to write the facts. Check gas usage table to estimate the required amount of funds.
You can write up to 100KB of data in passport under one key when txdata
data type is used. Supported data types that
can be written to the passport: string
, bytes
, address
, uint
, int
, bool
, txdata
. All types except txdata
use Ethereum storage to store the data. txdata
uses Ethereum storage only to save the block number, the data itself
remains in the transaction input data and can be read later using the SDK. Therefore, if you need to save a large amount
of data, it is better to use txdata
type of data. The disadvantage of the txdata
type of data is the data can only be read
using the SDK, within the contracts this data is not available.
Let's try to store image from the file ~/Downloads/monetha.jpg
under the key monetha.jpg
as txdata
in passport
0x1C3A76a9A27470657BcBE7BfB47820457E4DB682
:
./bin/passport write-fact --factproviderkey fact_provider.key \
--fkey monetha.jpg \
--ftype txdata \
--passaddr 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 \
--backendurl https://ropsten.infura.io < ~/Downloads/monetha.jpg
Similarly, you can store the same image from the file ~/Downloads/monetha.jpg
under the key monetha.jpg
as ipfs
in the same passport.
Keep in mind, the data will be stored in IPFS, only IPFS hash will be stored in the Ethereum storage:
./bin/passport write-fact --factproviderkey fact_provider.key \
--fkey monetha.jpg \
--ftype ipfs \
--passaddr 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 \
--backendurl https://ropsten.infura.io < ~/Downloads/monetha.jpg
Reading facts
After the fact provider has written the public data to the passport, the data can be read by anyone. To read the data you need to know: the address of the passport, the address of the fact provider who stored the data, the key under which the data was stored and the type of data.
Let's try to retrieve image from passport 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682
that was stored by the fact provider
0x5b2ae3b3a801469886bb8f5349fc3744caa6348d
under the key monetha.jpg
as txdata
data type and write it to the file
./fact_image.jpg
:
./bin/passport read-fact --out ./fact_image.jpg \
--passaddr 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 \
--factprovideraddr 0x5b2ae3b3a801469886bb8f5349fc3744caa6348d \
--fkey monetha.jpg \
--ftype txdata \
--backendurl https://ropsten.infura.io
After the data has been read from the Ethereum blockchain and written to the file ./fact_image.jpg
, try to open the image.
To get the same file that was previously saved in IPFS, just change the parameter --ftype
to ipfs
:
./bin/passport read-fact --out ./ipfs_fact_image.jpg \
--passaddr 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 \
--factprovideraddr 0x5b2ae3b3a801469886bb8f5349fc3744caa6348d \
--fkey monetha.jpg \
--ftype ipfs \
--backendurl https://ropsten.infura.io
Тhe data will be written to the file ./ipfs_fact_image.jpg
.
Changing passport permissions
By default any fact provider can write to a passport, but a passport owner can change permissions that allow only fact providers from the whitelist to write to a passport. To do this, the passport owner must add the authorized fact providers to the whitelist and then allow to store the facts only to fact providers from the whitelist.
Consider an example of how owner of a passport 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682
adds fact provider
0x5b2AE3b3A801469886Bb8f5349fc3744cAa6348d
to the whitelist in Ropsten network:
./bin/passport permission --ownerkey pass_owner.key \
--passaddr 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 \
--add 0x5b2AE3b3A801469886Bb8f5349fc3744cAa6348d \
--backendurl https://ropsten.infura.io
Please note that the passport owner’s private key is stored in the file pass_owner.key
.
After executing the command, any fact provider is still allowed to store the facts in the passport. Let's fix it!
Owner of a passport 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682
may allow to store the facts only to fact providers
from the whitelist by running the command:
./bin/passport permission --ownerkey pass_owner.key \
--passaddr 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 \
--enablewhitelist \
--backendurl https://ropsten.infura.io
More examples can be found here.
Reading facts history
The SDK allows you to see the history of absolutely all changes of facts in the passport.
Let's try to retrieve the entire change history for the passport 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682
in Ropsten
block-chain and write it to the file /dev/stdout
(outputs to the screen, but you can change this to the file name to write to the file):
./bin/passport history --out /dev/stdout \
--passaddr 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 \
--backendurl https://ropsten.infura.io
After running the command you should see something like this:
WARN [03-19|11:00:42.836] Loaded configuration backend_url=https://ropsten.infura.io passport=0x1C3A76a9A27470657BcBE7BfB47820457E4DB682
fact_provider,key,data_type,change_type,block_number,tx_hash
0x5b2AE3b3A801469886Bb8f5349fc3744cAa6348d,monetha.jpg,TxData,Updated,5233914,0xd43201d6b23a18b90a53bf7ef1fffad0b04af603c039b6617601a225a129c632
0x5b2AE3b3A801469886Bb8f5349fc3744cAa6348d,monetha.jpg,IPFS,Updated,5233917,0xf069012520c55d293595654805f3f2b1ff032c1395ddd37cd1366fc1ac67114e
0x5b2AE3b3A801469886Bb8f5349fc3744cAa6348d,Monetha_WP.pdf,IPFS,Updated,5233930,0xbc8a86f54a467edbec32fbf27c08e7077221dd69bbea79707889ac6f787fe0ca
WARN [03-19|11:00:44.497] Done.
The CSV output can be saved to a file and converted to the table:
fact_provider | key | data_type | change_type | block_number | tx_hash |
---|---|---|---|---|---|
0x5b2AE3b3A801469886Bb8f5349fc3744cAa6348d | monetha.jpg | TxData | Updated | 5233914 | 0xd43201d6b23a18b90a53bf7ef1fffad0b04af603c039b6617601a225a129c632 |
0x5b2AE3b3A801469886Bb8f5349fc3744cAa6348d | monetha.jpg | IPFS | Updated | 5233917 | 0xf069012520c55d293595654805f3f2b1ff032c1395ddd37cd1366fc1ac67114e |
0x5b2AE3b3A801469886Bb8f5349fc3744cAa6348d | Monetha_WP.pdf | IPFS | Updated | 5233930 | 0xbc8a86f54a467edbec32fbf27c08e7077221dd69bbea79707889ac6f787fe0ca |
As we can see, there were two fact updates of type TxData
(under the same key monetha.jpg
) by the same data provider 0x5b2AE3b3A801469886Bb8f5349fc3744cAa6348d
,
and one update of type IPFS
by the same data provider.
The block_number
and tx_hash
columns allow us to understand in which block and in which transaction the changes were made.
The change_type
column may contain either Updated
or Deleted
values. Even if the value of a fact has been deleted, we can read its value as it was before the deletion.
Let's read what the value of the fact was during the first update. To do this, we need to run command read-fact-tx
, specify the transaction hash 0xd43201d6b23a18b90a53bf7ef1fffad0b04af603c039b6617601a225a129c632
and the type of data txdata
:
./bin/passport read-fact-tx --out monetha1.jpg \
--passaddr 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 \
--ftype txdata \
--txhash 0xd43201d6b23a18b90a53bf7ef1fffad0b04af603c039b6617601a225a129c632 \
--backendurl https://ropsten.infura.io
Similarly, we can read what fact value was written in the second transaction 0xf069012520c55d293595654805f3f2b1ff032c1395ddd37cd1366fc1ac67114e
:
./bin/passport read-fact-tx --out monetha2.jpg \
--passaddr 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 \
--ftype ipfs \
--txhash 0xf069012520c55d293595654805f3f2b1ff032c1395ddd37cd1366fc1ac67114e \
--backendurl https://ropsten.infura.io
Now you can compare pictures monetha1.jpg
and monetha2.jpg
to see what changes have been made.
To read fact value of type TxData
in the third transaction parameter --ftype
should be changed to ipfs
and --txhash
to 0xbc8a86f54a467edbec32fbf27c08e7077221dd69bbea79707889ac6f787fe0ca
:
./bin/passport read-fact-tx --out Monetha_WP.pdf \
--passaddr 0x1C3A76a9A27470657BcBE7BfB47820457E4DB682 \
--ftype ipfs \
--txhash 0xbc8a86f54a467edbec32fbf27c08e7077221dd69bbea79707889ac6f787fe0ca \
--backendurl https://ropsten.infura.io
Тhe value will be written to the file Monetha_WP.pdf
.
Passport scanner
After the go-ethereum community recently accepted our changes,
it became possible to compile Go SDK of reputation layer into WebAssembly module and run it in a browser.
We have prepared a sample web application that has the same functionality as list
, read-fact-tx
and
history
utilities provide, i.e. it allows you to get the list of deployed passports and
the history of passport changes directly in your web browser.
To play with the web application, run the command
./bin/passport-scanner
and open http://localhost:8080 in your browser. More details can be found here.
The latest version of passport scanner is also uploaded to IPFS: https://ipfs.io/ipfs/QmNyHrzkD5RpxmxJyJKg9QraUYtGJ48KhskWjnGPfudhoy/
Happy scanning!
Private data
Private data is stored in encrypted form in IPFS, only the IPFS hash and hash of data encryption key are saved in the blockchain.
Reading/writing private data is as simple as reading/writing public data. The only difference is that only the person who is the passport owner at the time of writing private data can read the private data. The private data provider can read private data only if it has saved the data encryption key. The passport owner does not need to know the data encryption key, as he can decrypt all private data using his Ethereum private key.
Writing private data
In order for the fact provider to write private data, it needs to specify the private data type: --ftype privatedata
.
If the fact provider specifies a --datakey
parameter, the encryption key will be saved to a file, which will allow
the fact provider to read the private data later (for verification purposes, for example).
Let's try to store text this is a very secret message
under the key secret_message
as privatedata
in passport
0x4026a67a2C4746b94F168bd4d082708f78d7b29f
, and also save the data encryption key in the file data_enc.key
:
echo -n "this is a very secret message" | \
./bin/passport write-fact --factproviderkey fact_provider.key \
--fkey secret_message \
--ftype privatedata \
--passaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--datakey data_enc.key \
--backendurl https://ropsten.infura.io
As a result, you can see something like the following output:
WARN [05-13|16:51:53.823] Loaded configuration fact_provider=0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E backend_url=https://ropsten.infura.io passport=0x4026a67a2C4746b94F168bd4d082708f78d7b29f
WARN [05-13|16:51:54.820] Filtering OwnershipTransferred newOwner=0xD101709569D2dEc41f88d874Badd9c7CF1106AF7
WARN [05-13|16:51:54.975] Getting transaction by hash tx_hash=0x40768efcf3e6254216bed543433eaeac586fe0ed25b9de04d22e7677cfc980f1
WARN [05-13|16:51:55.115] Writing ephemeral public key to IPFS...
WARN [05-13|16:52:05.050] Ephemeral public key added to IPFS hash=QmPDZpSfsbU1DKquxhZxEZ6JmWZ61RSa1UiHaqZHDdqMZV size=73
WARN [05-13|16:52:05.050] Writing encrypted message to IPFS...
WARN [05-13|16:52:16.885] Encrypted message added to IPFS hash=QmfJuqBT7Kqd8Fb4omSDZWQMTpLkj2Gw81uYJm7wDz3Cpt size=53
WARN [05-13|16:52:16.885] Writing message HMAC to IPFS...
WARN [05-13|16:52:17.664] Message HMAC added to IPFS hash=QmcqcwppRyKc8yQWrkECuixsBgpwyjiirfYUP4Y3TVKYgf size=40
WARN [05-13|16:52:17.664] Creating directory in IPFS...
WARN [05-13|16:52:29.507] Directory created in IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm
WARN [05-13|16:52:29.507] Writing private data hashes to Ethereum passport=0x4026a67a2C4746b94F168bd4d082708f78d7b29f fact_key="[115 101 99 114 101 116 95 109 101 115 115 97 103 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]" ipfs_hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm data_key_hash=0x07bbab23c88ec28c3ddf46ebb8de1a24a278f1c27789cdb0b4fdfd7c5773f2ab
WARN [05-13|16:52:29.652] Writing IPFS private data hashes to passport fact_provider=0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E key="[115 101 99 114 101 116 95 109 101 115 115 97 103 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]"
WARN [05-13|16:52:30.323] Waiting for transaction hash=0x52dcfb7591be53cac31bd81fc2c297eb634b79607328969c7375fb481b02dea6
WARN [05-13|16:52:34.496] Transaction successfully mined tx_hash=0x52dcfb7591be53cac31bd81fc2c297eb634b79607328969c7375fb481b02dea6 gas_used=136031
WARN [05-13|16:52:34.496] Writing data encryption key to file file_name=data_enc.key
WARN [05-13|16:52:34.497] Done.
From the output, you can see that private data was saved in IPFS: QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm
However, despite the fact that the private data is stored publicly, only the passport owner or the fact provider (only if he's saved the data encryption key) can decrypt it.
Reading private data
After the fact provider has written the private data to the passport, the data can be read either by passport owner or by fact provider (only if he's saved the data encryption key). To read private data, the following data should be provided:
- the address of the passport (
--passaddr
parameter) - the address of the fact provider who stored the private data (
--factprovideraddr
parameter) - the key under which the private data was stored (
--fkey
parameter) - if the data is read by the fact provider, he need to specify data encryption key (
--datakey
parameter) - if the data is read by the owner of the passport, he need to specify his private key (
--ownerkey
parameter)
Let's try to retrieve private data as fact provider using data encryption key stored in file data_enc.key
from passport 0x4026a67a2C4746b94F168bd4d082708f78d7b29f
that was stored by the fact provider 0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E
under the key secret_message
as privatedata
data type and write it to the standard output:
./bin/passport read-fact --out /dev/stdout \
--passaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--factprovideraddr 0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E \
--fkey secret_message \
--ftype privatedata \
--datakey data_enc.key \
--backendurl https://ropsten.infura.io
You should see something like the following output:
WARN [05-13|17:00:27.686] Loaded configuration fact_provider=0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E fact_key="[115 101 99 114 101 116 95 109 101 115 115 97 103 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]" backend_url=https://ropsten.infura.io passport=0x4026a67a2C4746b94F168bd4d082708f78d7b29f
WARN [05-13|17:00:28.549] Reading private data hashes from Ethereum passport=0x4026a67a2C4746b94F168bd4d082708f78d7b29f fact_provider=0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E fact_key="[115 101 99 114 101 116 95 109 101 115 115 97 103 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]"
WARN [05-13|17:00:28.549] Getting IPFS private data hashes fact_provider=0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E key="[115 101 99 114 101 116 95 109 101 115 115 97 103 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]"
WARN [05-13|17:00:28.681] Reading encrypted message from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=encrypted_message
WARN [05-13|17:00:29.230] Reading message HMAC from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=hmac
WARN [05-13|17:00:29.816] Writing data to file
this is a very secret message
Now let's try to read the same private data as passport owner. Instead of parameter --datakey data_enc.key
, parameter --ownerkey pass_owner.key
is provided:
./bin/passport read-fact --out /dev/stdout \
--passaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--factprovideraddr 0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E \
--fkey secret_message \
--ftype privatedata \
--ownerkey pass_owner.key \
--backendurl https://ropsten.infura.io
After running the command passport owner should see something like this:
WARN [05-13|17:01:32.755] Loaded configuration fact_provider=0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E fact_key="[115 101 99 114 101 116 95 109 101 115 115 97 103 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]" backend_url=https://ropsten.infura.io passport=0x4026a67a2C4746b94F168bd4d082708f78d7b29f
WARN [05-13|17:01:33.632] Reading private data hashes from Ethereum passport=0x4026a67a2C4746b94F168bd4d082708f78d7b29f fact_provider=0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E fact_key="[115 101 99 114 101 116 95 109 101 115 115 97 103 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]"
WARN [05-13|17:01:33.632] Getting IPFS private data hashes fact_provider=0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E key="[115 101 99 114 101 116 95 109 101 115 115 97 103 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]"
WARN [05-13|17:01:33.771] Reading ephemeral public key from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=public_key
WARN [05-13|17:01:34.342] Reading encrypted message from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=encrypted_message
WARN [05-13|17:01:34.835] Reading message HMAC from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=hmac
WARN [05-13|17:01:35.314] Writing data to file
this is a very secret message
As you can see from the output, the passport owner additionally reads the ephemeral public key from IPFS, which allows him to recover the data encryption key using his Ethereum private key.
Reading history of private data
Reading the history of private data works for private data in the same way as for public data. You only need to additionally
specify the data type --ftype privatedata
, and specify either a data encryption key (--datakey
parameter) or a
passport owner’s Ethereum private key (--ownerkey
parameter).
Let's try to retrieve the entire change history for the passport 0x4026a67a2C4746b94F168bd4d082708f78d7b29f
in Ropsten blockchain:
./bin/passport history --out /dev/stdout \
--passaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--backendurl https://ropsten.infura.io
The output (converted to the table form):
fact_provider | key | data_type | change_type | block_number | tx_hash |
---|---|---|---|---|---|
0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E | secret_message | PrivateData | Updated | 5590046 | 0x52dcfb7591be53cac31bd81fc2c297eb634b79607328969c7375fb481b02dea6 |
0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E | some_text | TxData | Updated | 5590236 | 0xc792c69fd59a4146c06ee524262ab929b2af4a895a04df56d7cd1b0bb20af28b |
From the output, you can see that private data was saved in transaction 0x52dcfb7591be53cac31bd81fc2c297eb634b79607328969c7375fb481b02dea6
.
Let's try to read the private data from this transaction using data encryption key stored in file data_enc.key
:
./bin/passport read-fact-tx --out /dev/stdout \
--passaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--txhash 0x52dcfb7591be53cac31bd81fc2c297eb634b79607328969c7375fb481b02dea6 \
--ftype privatedata \
--datakey data_enc.key \
--backendurl https://ropsten.infura.io
The output:
WARN [05-13|17:05:03.014] Loaded configuration backend_url=https://ropsten.infura.io passport=0x4026a67a2C4746b94F168bd4d082708f78d7b29f
WARN [05-13|17:05:03.766] Reading data hashes from Ethereum transaction passport=0x4026a67a2C4746b94F168bd4d082708f78d7b29f tx_hash=52dcfb…02dea6
WARN [05-13|17:05:03.766] Getting transaction by hash tx_hash=0x52dcfb7591be53cac31bd81fc2c297eb634b79607328969c7375fb481b02dea6
WARN [05-13|17:05:03.918] Reading encrypted message from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=encrypted_message
WARN [05-13|17:05:04.464] Reading message HMAC from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=hmac
this is a very secret message
Keep in mind that every time a fact provider writes private data, a random data encryption key is used, so you need to specify the encryption key that was used in that particular transaction. The passport owner does not need to know all the data encryption keys, because he can restore them with his Ethereum private key.
Reading private data from the same transaction by the passport owner looks very similar (instead of --datakey
parameter --ownerkey
parameter is specified):
./bin/passport read-fact-tx -out /dev/stdout \
--passaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--txhash 0x52dcfb7591be53cac31bd81fc2c297eb634b79607328969c7375fb481b02dea6 \
--ftype privatedata \
--ownerkey ./pass_owner.key \
--backendurl https://ropsten.infura.io
The output:
WARN [05-13|17:04:00.042] Loaded configuration backend_url=https://ropsten.infura.io passport=0x4026a67a2C4746b94F168bd4d082708f78d7b29f
WARN [05-13|17:04:00.798] Reading data hashes from Ethereum transaction passport=0x4026a67a2C4746b94F168bd4d082708f78d7b29f tx_hash=52dcfb…02dea6
WARN [05-13|17:04:00.798] Getting transaction by hash tx_hash=0x52dcfb7591be53cac31bd81fc2c297eb634b79607328969c7375fb481b02dea6
WARN [05-13|17:04:00.957] Reading ephemeral public key from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=public_key
WARN [05-13|17:04:01.500] Reading encrypted message from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=encrypted_message
WARN [05-13|17:04:02.038] Reading message HMAC from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=hmac
this is a very secret message
Private data exchange
Private data exchange engine enables participants to exchange private data via Passports in a secure manner. Anyone can request private data from the passport of user. This is achieved by running an interactive protocol between the passport owner and the data requester.
How it works:
-
The data requester initiates retrieval of private data from a passport by calling
propose
command. When executing this command, the data requester specifies which fact provider data he wants to read, encrypts exchange key with the passport owner's public key and transfers to the passport the funds that he is willing to pay for the private data. -
The passport owner receives an event from the Ethereum blockchain or directly from the data requester for the data exchange proposition. If he is satisfied with the proposal, he executes the
accept
command. When executing this command, the passport owner encrypts the data encryption key with the exchange key of data requester and transfers the same amount of funds as the data requester to the passport as a guarantee of the validity of the data encryption key.The passport owner has 24 hours to accept private data exchange. 24 hours after the exchange proposition, the data requester can close the proposition and return staked funds back by calling
timeout
command. -
The data requester receives an event from the Ethereum blockchain or directly from the passport owner about accepted private data exchange. It decrypts the data access key using exchange key and reads private data using
read
command. After thatfinish
command is called, which returns all staked funds to the passport owner.During the first 24 hours, the
finish
command can only be called by the data requester, after 24 hours anyone can call this command. -
If it is not possible to decrypt the data, the data requester calls the
dispute
command, revealing the exchange key. The Ethereum contract code identifies the cheater and transfers all staked funds to the party who behaved honestly. The data requester has 24 hours to open a dispute, otherwise the exchange is considered valid and the passport owner can get all staked funds.
This is how it looks in the state diagram:
At any time, the status
command can be used to get detailed information about the private data exchange.
At all steps of the interactive protocol, the utility privatedata-exchange
is used.
Proposing private data exchange
To initiate the exchange of private data, the data requester must specify the following parameters:
- the passport address (
--passportaddr
parameter) - the address of the data provider who stored the private data (
--factprovideraddr
parameter) - key under which private data was stored (
--fkey
parameter) - the name of the file with the Ethereum private key of data requester (
--requesterkey
parameter) - the amount of funds (in wei) that the requester is willing to pay for private data (
--stake
parameter) - the name of the file where the exchange key will be saved (
--exchangekey
parameter), used later both for accessing private data and for resolving a possible dispute
In the example below, the data requester attempts to initiate the retrieval of private data that was stored by the fact provider
0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E
in passport 0x4026a67a2C4746b94F168bd4d082708f78d7b29f
under the key secret_message
by staking 10000000000000000 wei
(which is equal to 0.01 ETH
).
./bin/privatedata-exchange propose \
--passportaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--factprovideraddr 0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E \
--fkey secret_message \
--requesterkey ./data_requester.key \
--stake 10000000000000000 \
--exchangekey ./exchange.key \
--backendurl https://ropsten.infura.io
As a result of the command, you can see that the private data exchange proposition was created under index 1
(the index
is simply the data exchange identifier to refer it in all subsequent commands), and the exchange key was written to file exchange.key
:
WARN [05-16|13:56:31.944] Filtering OwnershipTransferred newOwner=0xD101709569D2dEc41f88d874Badd9c7CF1106AF7
WARN [05-16|13:56:32.091] Getting transaction by hash tx_hash=0x40768efcf3e6254216bed543433eaeac586fe0ed25b9de04d22e7677cfc980f1
WARN [05-16|13:56:32.223] Proposing private data exchange fact_provider=0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E fact_key="[115 101 99 114 101 116 95 109 101 115 115 97 103 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]" encrypted_key="[4 206 42 209 27 210 127 104 62 239 227 22 238 102 255 172 187 19 208 6 48 131 70 132 255 136 108 110 176 192 115 160 205 184 242 144 94 240 142 123 21 166 118 215 100 68 146 194 23 163 41 128 240 212 150 188 107 50 216 9 129 110 136 112 25]" key_hash=e86ec7…d8e4b9
WARN [05-16|13:56:32.980] Waiting for transaction hash=0xd353c8d21f44a3f17ebe7782bedf03a3b6d4456721f24192bb9813e916977526
WARN [05-16|13:56:37.123] Transaction successfully mined tx_hash=0xd353c8d21f44a3f17ebe7782bedf03a3b6d4456721f24192bb9813e916977526 gas_used=398976
WARN [05-16|13:56:37.123] PrivateDataExchangeProposed exchange_index=1 data_requester=0xd2Bb3Aa3F2c0bdA6D8020f3228EabD4A89d8B951 passport_owner=0xD101709569D2dEc41f88d874Badd9c7CF1106AF7
WARN [05-16|13:56:37.123] Private data exchange proposed exchange_index=1
WARN [05-16|13:56:37.123] Writing exchange key to file file_name=./exchange.key
Getting status of private data exchange
status
command allows to get more detailed information about the private data exchange. To get the information the following parameters should be specified:
- the passport address (
--passportaddr
parameter) - the private data exchange index (
--exchidx
parameter)
Let's try to get this information about private data exchange referred by the index 1
from passport 0x4026a67a2C4746b94F168bd4d082708f78d7b29f
:
./bin/privatedata-exchange status \
--passportaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--exchidx 1 \
--backendurl https://ropsten.infura.io
Immediately after creating the private data exchange proposition, you can see that it's in Proposed
state, data
requester staked 0.01 ETH
, and the passport owner has one day left to accept it:
Private data exchange: 1 (Proposed, expires in 1 day)
Data requester address: 0xd2Bb3Aa3F2c0bdA6D8020f3228EabD4A89d8B951
Data requester staked: 0.01 ETH
Passport owner address: 0xD101709569D2dEc41f88d874Badd9c7CF1106AF7
Passport owner staked: 0 ETH
Private data fact provider: 0xd8CD4f4640D9Df7ae39aDdF08AE2c6871FcFf77E
Private data fact key: secret_message
Private data IPFS hash: QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm
Accepting private data exchange
To accept the private data exchange after proposition, passport owner should execute accept
command providing the following parameters:
- the passport address (
--passportaddr
parameter) - the private data exchange index (
--exchidx
parameter) - the passport owner's Ethereum private key (
--ownerkey
parameter)
Thus, to accept a private exchange proposition referred by the index 1
from the passport 0x4026a67a2C4746b94F168bd4d082708f78d7b29f
,
the passport owner should execute the following command using it's Ethereum private key stored in file pass_owner.key
:
./bin/privatedata-exchange accept \
--passportaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--exchidx 1 \
--ownerkey ./pass_owner.key \
--backendurl https://ropsten.infura.io
This is how the output looks like:
WARN [05-16|14:01:18.257] Reading ephemeral public key from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=public_key
WARN [05-16|14:01:18.773] Accepting private data exchange exchange_index=1 encrypted_key="[12 201 213 144 184 166 215 0 173 4 39 228 62 198 102 75 221 245 254 31 183 117 86 152 34 68 218 152 49 76 233 214]"
WARN [05-16|14:01:19.771] Waiting for transaction hash=0x51fb2ae16e6796bcdb6025b468ffcb3d045fc7ced359db88f64ee1cb7e0ab4dd
WARN [05-16|14:01:32.305] Transaction successfully mined tx_hash=0x51fb2ae16e6796bcdb6025b468ffcb3d045fc7ced359db88f64ee1cb7e0ab4dd gas_used=81836
Reading private data after private data exchange acceptance
After a private data exchange proposition is accepted, the data requester can read the private data by providing the following parameters:
- the passport address (
--passportaddr
parameter) - the private data exchange index (
--exchidx
parameter) - the name of the file with the exchange key (
--exchangekey
parameter), that was created as result ofpropose
command - the name of the file where the decrypted private data will be saved (
--datafile
parameter)
Here is the command to read private data from a passport 0x4026a67a2C4746b94F168bd4d082708f78d7b29f
for the private
data exchange referred by the index 1
, using exchange key from file exchange.key
and writing result to standard output:
./bin/privatedata-exchange read \
--passportaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--exchidx 1 \
--exchangekey ./exchange.key \
--datafile /dev/stdout \
--backendurl https://ropsten.infura.io
Below you can see how the data was read, decrypted and output to the console:
WARN [05-16|14:02:20.619] Reading encrypted message from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=encrypted_message
WARN [05-16|14:02:21.103] Reading message HMAC from IPFS hash=QmPXKoz1jy16oHWApn5MmWgf2BcNtZTsTEAnbTtd8tw1xm filename=hmac
WARN [05-16|14:02:21.633] Writing private data to file file_name=/dev/stdout
this is a very secret message
Closing private data exchange proposition when timed out
If the passport owner ignored the request for the private data exchange, then after 24 hours, the data requester may
close the request and return the staked funds by calling timeout
command.
Here's how to close the private data exchange referred by the index 2
in the passport 0x4026a67a2C4746b94F168bd4d082708f78d7b29f
using the Ethereum private key of data requester stored in the data_requester.key
file:
./bin/privatedata-exchange timeout \
--passportaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--exchidx 2 \
--requesterkey ./data_requester.key \
--backendurl https://ropsten.infura.io
The output:
WARN [05-17|14:01:11.231] Timeout private data exchange exchange_index=2
WARN [05-17|14:01:11.988] Waiting for transaction hash=0xfa1d7f4fb5cc82c3270e123cfd2a56e0577b91d1dc56e667e66e193e5dfb57d4
WARN [05-17|14:01:41.140] Transaction successfully mined tx_hash=0xfa1d7f4fb5cc82c3270e123cfd2a56e0577b91d1dc56e667e66e193e5dfb57d4 gas_used=23030
Closing private data exchange after acceptance
After the data requester successfully read the private data, it can confirm this by invoking the finish
command.
When executing the command, the funds staked by the data requester and passport owner will be transferred to the passport owner.
If the data requester doesn't send the finalization request withing a predefined timespan (24 hours), the passport owner
is allowed to finalize private data exchange, preventing the escrow being locked-up indefinitely.
This is how private data exchange referred by the index 1
in passport 0x4026a67a2C4746b94F168bd4d082708f78d7b29f
may
be finalized by the data requester using she's Ethereum private key from file data_requester.key
:
./bin/privatedata-exchange finish \
--passportaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--exchidx 1 \
--requesterkey ./data_requester.key \
--backendurl https://ropsten.infura.io
The output:
WARN [05-16|14:03:24.275] Waiting for transaction hash=0x544c5b51c167efd7a1d50d26bffd706dbe2a13daefdf087afcfac6940f19b725
WARN [05-16|14:03:45.061] Transaction successfully mined tx_hash=0x544c5b51c167efd7a1d50d26bffd706dbe2a13daefdf087afcfac6940f19b725 gas_used=31348
Opening dispute after private data exchange acceptance
If it is not possible to decrypt the data, the data requester calls the dispute
command within 24 hours after acceptance,
revealing the exchange key. The logic of the passport is the arbitrator who determines who the cheater is.
This is possible due to the fact that in the passport the hashes of both the data encryption key and the exchange key are saved, and
the data encryption key is XORed with the exchange key during the private data exchange acceptance by the passport owner.
When resolving a dispute, all staked funds are transferred to the side that behaved honestly.
Below you can see how the data requester tries to pretend that he could not read the private data from exchange referred
by the index 3
from the passport 0x4026a67a2C4746b94F168bd4d082708f78d7b29f
providing valid exchange key in file exchange3.key
and
valid Ethereum private key of data requester stored in file data_requester.key
:
./bin/privatedata-exchange dispute \
--passportaddr 0x4026a67a2C4746b94F168bd4d082708f78d7b29f \
--exchidx 3 \
--exchangekey ./exchange3.key \
--requesterkey ./data_requester.key \
--backendurl https://ropsten.infura.io
However, as a result, we see that the contract makes the only right decision that the dispute is opened unfairly
(Dispute result: successful=false
) and the data requester is cheater (cheater_address=0xd2Bb3Aa3F2c0bdA6D8020f3228EabD4A89d8B951
):
WARN [05-16|14:38:05.921] Dispute private data exchange exchange_index=3
WARN [05-16|14:38:06.617] Waiting for transaction hash=0x2770518215a20bd2d339499c2c225b430b3d6b6e10c80fb681b3e3758da92001
WARN [05-16|14:38:14.886] Transaction successfully mined tx_hash=0x2770518215a20bd2d339499c2c225b430b3d6b6e10c80fb681b3e3758da92001 gas_used=38461
WARN [05-16|14:38:14.886] Dispute result successful=false cheater_address=0xd2Bb3Aa3F2c0bdA6D8020f3228EabD4A89d8B951
Permissioned blockchains support
Quorum
Quorum™ is an enterprise-focused version of Ethereum. It's ideal for any application requiring high speed and high throughput processing of private transactions within a permissioned group of known participants.
In order to play with our SDK on Quorum network, you need to run Quorum network somewhere. The easiest way to run Quorum network of 7 nodes locally is by running a preconfigured Vagrant environment. Follow the instructions below to do this:
-
Install VirtualBox
-
Install Vagrant
-
Download and start the Vagrant instance (note: running
vagrant up
takes approx 5 mins):$ git clone https://github.com/jpmorganchase/quorum-examples $ cd quorum-examples $ vagrant up $ vagrant ssh
After executing these commands, you will be inside a virtual machine with all the tools to start the Quorum network.
NOTE: To shutdown the Vagrant instance later, run
vagrant suspend
. To delete it, runvagrant destroy
. To start from scratch, runvagrant up
after destroying the instance. (you should run allvagrant
commands from the host machine, not from the virtual machine) -
Once inside the virtual machine, run the blockchain nodes using Raft consensus:
$ cd quorum-examples/7nodes/ $ ./raft-init.sh $ ./raft-start.sh
Make sure 7 processes of
geth
are up and running by executingps aux | grep geth
command.Genesis block contains 5 addresses, each of which has 1000000000 ETH:
Address Private key 0xed9d02e382b34818e88B88a309c7fe71E65f419d e6181caaffff94a09d7e332fc8da9884d99902c7874eb74354bdcadf411929f1 0xcA843569e3427144cEad5e4d5999a3D0cCF92B8e 4762e04d10832808a0aebdaa79c12de54afbe006bfffd228b3abcc494fe986f9 0x0fBDc686b912d7722dc86510934589E0AAf3b55A 61dced5af778942996880120b303fc11ee28cc8e5036d2fdff619b5675ded3f0 0x9186eb3d20Cbd1F5f992a950d808C4495153ABd5 794392ba288a24092030badaadfee71e3fa55ccef1d70c708baf55c07ed538a8 0x0638E1574728b6D862dd5d3A3E0942c3be47D996 30bee17b2b8b1e774115f785e92474027d45d900a12a9d5d99af637c2d1a61bd -
When all nodes are up and running it's safe to exit from virtual machine and start reputation layer bootstrap. Run
exit
, to leave Vagrant environment:$ exit
Now you're on the host machine. Vagrant environment exposes ports 22000-22007, on which Ethereum JSON RPC is available. You can check it's working by running command:
$ curl -H "Content-Type: application/json" \ -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ http://localhost:22000
You should see the output:
{"jsonrpc":"2.0","id":1,"result":"0x0"}
-
Now follow Building the source steps to build the full suite of reputation SDK utilities, if you haven't done it yet. Use private keys from the table above and specify one of the Quorum node (like
http://localhost:22000
) as--backendurl
parameter to make transactions.For example:
$ echo e6181caaffff94a09d7e332fc8da9884d99902c7874eb74354bdcadf411929f1 > bootstrap_owner.key $ echo 4762e04d10832808a0aebdaa79c12de54afbe006bfffd228b3abcc494fe986f9 > passport_owner.key $ echo 61dced5af778942996880120b303fc11ee28cc8e5036d2fdff619b5675ded3f0 > data_provider.key $ ./bin/passport bootstrap --ownerkey ./bootstrap_owner.key --backendurl http://localhost:22000 $ ./bin/passport create --ownerkey ./passport_owner.key \ --factoryaddr 0x9d13C6D3aFE1721BEef56B55D303B09E021E27ab \ --backendurl http://localhost:22000 $ echo Johny | ./bin/passport write-fact --fkey name --ftype string \ --factproviderkey ./data_provider.key \ --passaddr 0x4AEb3678b689DbB3F502D927580f9829001C4BB6 \ --backendurl http://localhost:22000 $ ./bin/passport read-fact --out /dev/stdout --fkey name --ftype string \ --factprovideraddr 0x0fBDc686b912d7722dc86510934589E0AAf3b55A \ --passaddr 0x4AEb3678b689DbB3F502D927580f9829001C4BB6 \ --backendurl http://localhost:22000 ...
NOTE: SDK support Quorum's private transactions. For commands that send transactions, use these additional parameters:
--quorum_enclave "<url of enclave for transaction encryption>" --quorum_privatefor "<comma separated public keys of Quorum nodes to make this tx visible to>"
For example:
./bin/passport bootstrap --ownerkey ./bootstrap_owner.key \ --backendurl http://localhost:22000 \ --quorum_enclave "http://127.0.0.1:9081" \ --quorum_privatefor "BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo=,QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc="
For commands that read transactions, only
--quorum_enclave
is needed (to decrypt transaction data in some cases).Exceptions: private data exchange commands
read
andstatus
do not require any additional parameters at all.
Documentation ¶
There is no documentation for this package.