The HOPR code now lives as its own GitHub organization on http://github.com/hoprnet
You can find more info on HOPR at https://hoprnet.org
Privacy-preserving messaging protocol for the web3
License: GNU General Public License v3.0
The HOPR code now lives as its own GitHub organization on http://github.com/hoprnet
You can find more info on HOPR at https://hoprnet.org
Currently we assume that users are working with Infura. Instead the default .env.example
file should connect to default Ethereum RPC endpoint http://localhost:8545
. The Infura endpoint example could be given as an alternative option.
๐ I've set up everything as described in the README, however, I'm unable to get the same sort of interaction is shown in the ETHCC presentation, particularly @robertkiel section when kickstarting the demo. I even whitelisted the ropsten contract as updated in the latest commit for the demo, but I only get the following feedback from the console:
~/Projects/validitylabs/hopr ๎ฐ ๎ dev ๎ฐ yarn demo
yarn run v1.10.1
$ node test/demo.js
Welcome to HOPR!
Please wait some time until the node is set up.
This may take some time ...
Meanwhile you can start reading the wiki at https://github.com/validitylabs/messagingProtocol/wiki
Compiling smart contract ...
Compiling your contracts...
===========================
> Compiling ./contracts/HoprChannel.sol
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/token/ERC20/IERC20.sol
> Compiling openzeppelin-solidity/contracts/math/SafeMath.sol
> Artifacts written to /Users/jjperezaguinaga/Projects/validitylabs/hopr/build/contracts
> Compiled successfully using:
- solc: 0.5.0+commit.1d4f565a.Emscripten.clang
Debug mode: using password Epo5kZTFidOCHrnL0MzsXNwN9St
Done. Using peerId QmUjhU5BKBLwNL6Cf3NFra2SLuaLcsnYzoG1oFcaeeoR6w
Debug mode: using password Epo5kZTFidOCHrnL0MzsXNwN9St
Done. Using peerId QmVQZwxiziy8YEvzSH9BvYHox8ZqnMMCkxHqGh56RgCKn7
Debug mode: using password Epo5kZTFidOCHrnL0MzsXNwN9St
Done. Using peerId QmT1wwgqpkoh4D6JYsguDLN25m7JFx3ZtEp5tpbeW644u2
Debug mode: using password Epo5kZTFidOCHrnL0MzsXNwN9St
Done. Using peerId QmSH3qQXEkCUNPxCWLzNUXp4i7PzYojvzKkCuBr4qwytyL
I tried this in the dev
branch. For the record, here are some of my environment variables:
~/Projects/validitylabs/hopr ๎ฐ ๎ dev ๎ฐ node --version
v10.12.0
and here's the format of my config/.secrets.json
{
"infuraRopstenURL": "https://ropsten.infura.io/v3/",
"infuraApiKey": "2f5...b89",
"infuraRopstenWssURL": "wss://ropsten.infura.io/ws/v3/",
"fundAccountEthAddress": "0xFD1...a96",
"fundAccountPrivateKey": "b430...ec"
}
Reading through the demo now, and I'm guessing something is getting lost accross the message as I don't get to see the Psst ... secret message from Validity Labs!
message nor any activity in the Ropsten contract.
I'll poke on the issue on my own, but thought you would be happy to know about this. An easy way to test this is to have a new isolated environment in a place like C9, Glitch.com or a new virtual machine.
The .env
file parametrizes the network (e.g. ropsten
) but the provider is fixed to ropsten: PROVIDER = ${PROVIDER_ROPSTEN}
. The provider should also be set dynamically.
Usually, we only use one or the other, as this might create some issues between contributors that use npm install
vs the ones that use yarn
.
Since yarn
is more modern, I would suggest just deleting package-lock.json
, unless there's a particular reason to keep it.
This is probably already in your scope, so I'm just going to mention it.
Although the console demo looks great, a more real-world approach would be something behind a Web3 enabled JavaScript API that allows consuming HOPR's calls. Dharma Protocol has a very good implementation for interacting with their contracts, and I'm currently working with my team on refactoring our own web3 JavaScript library for our own protocol.
If there's interest and we can get #1 to work, alongside some other tooling improvements like #2 or #3 , I'm happy to chip in here to give some MVP UI to HOPR.
Integrate Ethereum Name System to increase convenience when sending messages to other users
As done properly in the .gitignore
file, .secrets.json
is ignored in order to avoid having people committing secrets into version control. However, .secrets.json
isn't really much of a standard, and most applications use a .env
file sitting in the root directory of the project.
My suggestion is to replace .secrets.json
for an .env
file and use dotenv for setting up the environment variables, making the project fit a bit more common conventions.
Happy to implement this if agreed on doing so.
Most developers don't want to go into all the details of a wiki to understand a project (which is a pity, because in this case HOPR's is actually pretty well documented). They just want to get the hello-world example in order to test the project.
Currently, HOPR requires a bit of setup in order to be tested locally. We can probably pre-package the project into a Docker image that we can just as people to run in order to be able to get a feel of what's going on without having to do everything on the README.
We can package all the setup into an image and run a ganache-server
that forwards all the RPC calls within the container while still getting the console logs. Happy to help if seems useful.
If you do a quick grep
1 on the project for the word secrets
, as of commit 92fb03f, you will see the following output (some have already some changes I'm doing):
./truffle.js:12:let secrets = '';
./truffle.js:15: secrets = require('./config/.secrets.json');
./truffle.js:71: rinkebyProvider = new HDWalletProvider(secrets.rinkeby.mnemonic, secrets.rinkeby.host);
./truffle.js:87: ropstenProvider = new HDWalletProvider(secrets.ropsten.mnemonic, secrets.ropsten.host);
./test/utils/index.js:43: let secrets
./test/utils/index.js:45: secrets = require('../../config/.secrets.json')
./test/utils/index.js:50: if (!secrets['demoAccounts'] || secrets['demoAccounts'].length <= n)
./test/utils/index.js:53: return privKeyToPeerId(secrets.demoAccounts[n].privateKey, (err, peerId) => {
./README.md:26:Setup the configuration file below before preceding. Navigate to the `config/` folder and change the `.secrets.json` similar to the following one:
./.gitignore:23:# Exclude .secrets
./.gitignore:24:.secrets.json
./.gitignore:36:# Exclude .secrets.json and .env file
./.gitignore:37:.secrets.json
./hopr.js:70: const secrets = require('./config/.secrets.json')
./hopr.js:72: if (secrets['demoAccounts'] && secrets['demoAccounts'].length > parseInt(options._[0])) {
./hopr.js:73: privKeyToPeerId(secrets.demoAccounts[options._[0]].privateKey, (err, peerId) => {
./src/constants.js:11:const secrets = require('../config/.secrets.json')
./src/constants.js:49: INFURA_URL: `https://${NETWORK}.infura.io/v3/${secrets.infuraApiKey || process.env.INFURA_API_KEY}`,
./src/constants.js:50: INFURA_WSS_URL: `wss://${NETWORK}.infura.io/ws/v3/${secrets.infuraApiKey || process.env.INFURA_API_KEY}`,
./src/constants.js:60: HARDCODED_ETH_ADDRESS: secrets.fundAccountEthAddress || process.env.FUND_ACCOUNT_ETH_ADDRESS,
./src/constants.js:61: HARDCODED_PRIV_KEY: secrets.fundAccountPrivateKey || process.env.FUND_ACCOUNT_PRIVATE_KEY
./src/getPeerInfo.js:63: return privKeyToPeerId(require('../config/.secrets.json').fundAccountPrivateKey || process.env.FUND_ACCOUNT_PRIVATE_KEY, cb)
./src/paymentChannels/keyDerivation.js:47: static create(secrets) {
./src/paymentChannels/keyDerivation.js:50: hash(bufferXOR(Header.deriveTransactionKey(secrets[0]), Header.deriveTransactionKeyBlinding(secrets[0]))),
./src/paymentChannels/keyDerivation.js:51: hash(bufferXOR(Header.deriveTransactionKey(secrets[1]), Header.deriveTransactionKeyBlinding(secrets[0]))),
./src/paymentChannels/keyDerivation.js:52: hash(KeyDerivation.deriveKey(secrets)),
./src/paymentChannels/keyDerivation.js:62: static deriveKey(Header, secrets) {
./src/paymentChannels/keyDerivation.js:63: const k_A = Header.deriveTransactionKey(secrets[0])
./src/paymentChannels/keyDerivation.js:64: const k_B = Header.deriveTransactionKey(secrets[1])
./src/packet/message.js:55: onionEncrypt(secrets) {
./src/packet/message.js:56: if (!Array.isArray(secrets) || secrets.length <= 0)
./src/packet/message.js:59: forEachRight(secrets, (secret) => {
./src/packet/index.js:27: const { header, secrets, identifier } = Header.createHeader(path)
./src/packet/index.js:37: const fee = (new BN(secrets.length - 1, 10)).imul(new BN(RELAY_FEE, 10))
./src/packet/index.js:39: const challenge = Challenge.createChallenge(Header.deriveTransactionKey(secrets[0]), node.peerInfo.id)
./src/packet/index.js:40: const message = Message.createMessage(msg).onionEncrypt(secrets)
./src/packet/index.js:46: log(node.peerInfo.id, `Encrypting with ${hash(bufferXOR(Header.deriveTransactionKey(secrets[0]), Header.deriveTransactionKey(secrets[1]))).toString('base64')}.`)
./src/packet/index.js:47: const encryptedTx = tx.encrypt(hash(bufferXOR(Header.deriveTransactionKey(secrets[0]), Header.deriveTransactionKey(secrets[1]))))
./src/packet/header/createHeader.js:31: let done = false, secrets, privKey
./src/packet/header/createHeader.js:45: secrets = []
./src/packet/header/createHeader.js:75: secrets.push(secret)
./src/packet/header/createHeader.js:82: return secrets
./src/packet/header/createHeader.js:85: function generateFiller(secrets) {
./src/packet/header/createHeader.js:90: let { key, iv } = Header.derivePRGParameters(secrets[index])
./src/packet/header/createHeader.js:106: function createBetaAndGamma(secrets, filler, identifier) {
./src/packet/header/createHeader.js:109: forEachRight(secrets, (secret, index) => {
./src/packet/header/createHeader.js:112: let paddingLength = (c.MAX_HOPS - secrets.length) * p.PER_HOP_SIZE
./src/packet/header/createHeader.js:114: if (index === secrets.length - 1) {
./src/packet/header/createHeader.js:139: .fill(hash(Header.deriveTransactionKey(secrets[index + 1])), p.ADDRESS_SIZE + p.MAC_SIZE, p.ADDRESS_SIZE + p.MAC_SIZE + p.HASH_LENGTH)
./src/packet/header/createHeader.js:142: if (secrets.length > 2 && index < secrets.length - 2) {
./src/packet/header/createHeader.js:144: .fill(hash(deriveKey(Header, secrets.slice(index, index + 2))), p.ADDRESS_SIZE + p.MAC_SIZE + p.HASH_LENGTH, p.ADDRESS_SIZE + p.MAC_SIZE + p.HASH_LENGTH + p.HASH_LENGTH)
./src/packet/header/createHeader.js:145: .fill(deriveKey(Header, secrets.slice(index + 1, index + 3)), p.ADDRESS_SIZE + p.MAC_SIZE + p.HASH_LENGTH + p.HASH_LENGTH, p.ADDRESS_SIZE + p.MAC_SIZE + p.HASH_LENGTH + p.HASH_LENGTH + p.KEY_LENGTH)
./src/packet/header/createHeader.js:160: function printValues(header, secrets) {
./src/packet/header/createHeader.js:163: str = str + '\nsecret[' + index + ']: ' + bs58.encode(secrets[index]) + '\n' +
./src/packet/header/createHeader.js:172: const secrets = generateKeyShares(peerIds)
./src/packet/header/createHeader.js:174: const filler = generateFiller(secrets)
./src/packet/header/createHeader.js:175: createBetaAndGamma(secrets, filler, identifier)
./src/packet/header/createHeader.js:177: // printValues(header, secrets)
./src/packet/header/createHeader.js:181: secrets: secrets,
Particularly I want to bring your attention to the following lines:
in truffle.js
./truffle.js:15: secrets = require('./config/.secrets.json');
./truffle.js:71: rinkebyProvider = new HDWalletProvider(secrets.rinkeby.mnemonic, secrets.rinkeby.host);
./truffle.js:87: ropstenProvider = new HDWalletProvider(secrets.ropsten.mnemonic, secrets.ropsten.host);
in test/utils/index.js
./test/utils/index.js:45: secrets = require('../../config/.secrets.json')
./test/utils/index.js:50: if (!secrets['demoAccounts'] || secrets['demoAccounts'].length <= n)
in hopr.js
./hopr.js:70: const secrets = require('./config/.secrets.json')
./hopr.js:72: if (secrets['demoAccounts'] && secrets['demoAccounts'].length > parseInt(options._[0])) {
As you can see, we are trying to access rinkeby|ropsten.mnemonic
and demoAccounts
from secrets, even though those are not documented or shown in the documentation. I imagine those are some legacy variables, but might be related to #1 on why I can't get the demo to work.
Probably worth adding those to the documentation and/or expanding the logic behind those. All of those have fallbacks so they don't break the project, but we should at least escape rinkeby|ropsten.mnemonic
as they will fail with the current provided .secrets.json
example.
grep -rni secrets . --exclude-dir=node_modules
.A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.