Updated the documentation. Needs to be proofread

This commit is contained in:
Richard Ramos 2018-09-13 11:59:41 -04:00
parent 4236ae0cf6
commit 1ea9aaca32
8 changed files with 440 additions and 314 deletions

322
README.md
View File

@ -3,317 +3,17 @@ Gas relayer mplementation for economic abstraction. This project consists of two
- `gas-relayer`: nodejs service that listens to whisper on a symmetric key, with specific topics, and processes any transaction. - `gas-relayer`: nodejs service that listens to whisper on a symmetric key, with specific topics, and processes any transaction.
- `test-dapp`: DApp created for testing purposes. It allows the easy creation of the messages expected by the service. - `test-dapp`: DApp created for testing purposes. It allows the easy creation of the messages expected by the service.
## Installation
- `geth` is required for installation
- Install the latest develop version of embark: `npm install -g https://github.com/embark-framework/embark.git`
- If running a development version of the gas relay
```
cd test-dapp
chmod a+x setup_dev_env.sh
npm install
embark reset
embark blockchain
```
- When Embark finishes loading, execute `embark run` && `./setup_dev_env.sh` to create the test account
## Node ## Documentation
1. [Installation - testnet/mainnet](installation-testnet-mainnet.md)
Before executing this program, `config/config.json` must be setup and `npm install` needs to be executed. Important values to verify are related to the node configuration, just like: 2. [Installation - development environment](installation-development.md)
- Host, port and protocol to connect to the geth node 3. [Gas relayer protocol](relayer-protocol.md)
- Host, port and protocol Ganache will use when forking the blockchain for gas estimations and other operations 4. [Javascript library](javascript-library.md)
- Wallet account used for processing the transactions 5. Status Extensions (TODO)
- Symmetric key used to receive the Whisper messages
- Accepted tokens information
- Contract configuration
This program is configured with the default values for a embark installation run from 0
A `geth` node running whisper (via `-shh` option) is required. To execute the gas-relayer, you may use any of the following three methods.
```
npm start
node src/service.js
nodemon src/service.js
```
## Test DApp
To run the test dapp, use `embark run` and then browse `http://localhost:8000/index.html`.
The gas relayer service needs to be running, and configured correctly to process the transactions. Things to take in account are: the account used in embark, and the contract addresses.
(TODO: update testnet configuration to guarantee the contract addresses don't change)
## The relayer
A node that wants to act as a relayer only needs to have a geth node with whisper enabled, and an account with ether to process the transactions. This account and node need to be configured in `./config/config.js`.
The relayer will be subscribed to receive messages in a specific symkey (this will change in the future to use ENS), and will reply back to both availability and transaction requests
## Using the gas relayer
### The protocol
#### Sending a message to the gas relayer network (all accounts and privatekeys should be replaced by your own test data)
```
shh.post({
symKeyID: SYM_KEY, // If requesting availability
pubKey: PUBLIC_KEY_ID, // If sending a transaction
sig: WHISPER_KEY_ID,
ttl: 1000,
powTarget: 1,
powTime: 20,
topic: TOPIC_NAME,
payload: PAYLOAD_BYTES
}).then(......)
```
- `symKeyID: SYM_KEY` must contain the whisper symmetric key used. It is shown on the console when running the service with `node`. With the provided configuration you can use the symmetric key `0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b`. Only used when asking for relayer availability.
- `pubKey: PUBLIC_KEY_ID`. After asking for availability, once the user decides on a relayer, it needs to set the `pubKey` attribute with the relayer public key (received in the availability reply in the `sig` attribute of the message).
- `WHISPER_KEY_ID` represents a keypair registered on your node, that will be used to sign the message. Can be generated with `web3W.shh.newKeyPair()`
- `TOPIC_NAME` must contain one of the topic names generated based on converting the contract name to hex, and taking the first 8 bytes. For the provided configuration the following topics are available:
- - IdentityGasRelay: `0x4964656e`
- - SNTController: `0x534e5443`
- `PAYLOAD_BYTES` a hex string that contains details on the operation to perform.
#### Polling for gas relayers ## Deployment Details
The first step is asking the relayers for their availability. The message payload needs to be the hex string representation of a JSON object with a specific structure: | Contract | Ropsten Address | Mainnet Address |
| ---------------------------|------------------------------------------- | ------------------------------------------ |
``` | status/SNTController | 0xA77A1014F55157c3119FB3f53E653E42f8fa634c | - |
const payload = web3.utils.toHex({ | identity/IdentityFactory | 0x7F106A1Bc637AC4AAed3DC72582749c4562D4323 | - |
'contract': "0xContractToInvoke",
'address': web3.eth.defaultAccount,
'action': 'availability',
'token': "0xGasTokenAddress",
'gasPrice': 1234
});
```
- `contract` is the address of the contract that will perform the operation, in this case it can be an Identity, or the SNTController.
- `address` The address that will sign the transactions. Normally it's `web3.eth.defaultAccount`
- `gasToken`: token used for paying the gas cost
- `gasPrice`: The gas price used for the transaction
This is a example code of how to send an 'availability' message:
```
const whisperKeyPairID = await web3W.shh.newKeyPair();
const msgObj = {
symKeyId: "0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b",
sig: whisperKeyPairID,
ttl: 1000,
powTarget: 1,
powTime: 20,
topic: "0x4964656e",
payload: web3.utils.toHex({
'contract': "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
'address': web3.eth.defaultAccount
'action': 'availability',
'gasToken': "0x744d70fdbe2ba4cf95131626614a1763df805b9e",
'gasPrice': 40000000000 // 40 gwei equivalent in SNT
})
};
web3.shh.post(msgObj)
.then((err, result) => {
console.log(result);
console.log(err);
});
```
When it replies, you need to extract the `sig` attribute to obtain the relayer's public key
#### Sending transaction details
Sending a transaction is similar to the previous operation, except that we send the message to an specific node, we use the action `transaction`, and also we send a `encodedFunctionCall` with the details of the transaction to execute.
From the list of relayers received via whisper messages, you need to extract the `message.sig` to obtain the `pubKey`. This value is used to send the transaction to that specific relayer.
`encodedFunCall` is the hex data used obtained from `web3.eth.abi.encodeFunctionCall` for the specific function we want to invoke.
If we were to execute `callGasRelayed(address,uint256,bytes,uint256,uint256,uint256,address,bytes)` (part of the IdentityGasRelay) in contract `0x692a70d2e424a56d2c6c27aa97d1a86395877b3a`, with these values: `"0x11223344556677889900998877665544332211",100,"0x00",1,10,20,"0x1122334455112233445511223344551122334455"`, "0x1122334455", `PAYLOAD_BYTES` can be prepared as follows:
```
// The following values are created obtained when polling for relayers
const whisperKeyPairID = await web3W.shh.newKeyPair();
const relayerPubKey = "0xRELAYER_PUBLIC_KEY_HERE";
// ...
// ...
const jsonAbi = ABIOfIdentityGasRelay.find(x => x.name == "callGasRelayed");
const funCall = web3.eth.abi.encodeFunctionCall(jsonAbi,
[
"0x11223344556677889900998877665544332211",
100,
"0x00",
1,
10,
20,
"0x1122334455112233445511223344551122334455",
"0x1122334455"
]);
const msgObj = {
pubKey: relayerPubKey,
sig: whisperKeyPairID,
ttl: 1000,
powTarget: 1,
powTime: 20,
topic: "0x4964656e",
payload: web3.utils.toHex({
'contract': "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
'address': web3.eth.defaultAccount
'action': 'transaction',
'encodedFunctionCall': funCall,
})
};
web3.shh.post(msgObj)
.then((err, result) => {
console.log(result);
console.log(err);
});
```
### Javascript Library
Using the file `status-gas-relayer.js`, setup connection to geth, and required keypairs and symkeys
```
import StatusGasRelayer, {Contracts, Functions, Messages} from 'status-gas-relayer';
// Connecting to web3
const web3 = new Web3('ws://localhost:8546');
const kid = await web3js.shh.newKeyPair()
const skid = await web3.shh.addSymKey("0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b");
```
#### Subscribing to messages
General message subscription. Special handling is needed for relayer availability. The `sig` property is the relayer's public key that needs to be sent when sending a transaction message. More than 1 relayer can reply, so it's recommended to save these keys in a list/array.
```
StatusGasRelayer.subscribe(web3js, (error, msgObj) => {
if(error) {
console.error(error);
return;
}
if(msgObj.message == Messages.available){
// Relayer availability message
console.log("Relayer available: " + msgObj.sig);
} else {
// Normal message
console.log(msgObj);
}
}, {
privateKeyID: kid
});
```
#### Polling for relayers
```
const identityAddress = this.props.identityAddress; // Identity contract
const accountAddress = web3.eth.defaultAccount;
const gasToken = SNT.options.address;
const gasPrice = 1000000000000; // In wei equivalent to the token
const s = new StatusGasRelayer.AvailableRelayers(Contracts.Identity, identityAddress, accountAddress)
.setRelayersSymKeyID(skid)
.setAsymmetricKeyID(kid)
.setGas(gasToken, gasPrice);
await s.post(web3);
```
#### Signing a message
Signing a message is similar to invoking a function. Both use mostly the same functions. The difference is that when you invoke a function, you need to specify the relayer and asymmetric key Id.
```
try {
const s = new StatusGasRelayer.Identity(identityAddress, accountAddress)
.setContractFunction(Functions.Identity.call)
.setTransaction(to, value, data)
.setGas(gasToken, gasPrice, gasLimit);
const signature = await s.sign(web3);
} catch(error){
console.log(error);
}
```
#### Using Identity contract `call` function
This functionality is used when a Identity will invoke a contract function or transfer ether without paying fees
```
try {
const s = new StatusGasRelayer.Identity(identityAddress, accountAddress)
.setContractFunction(Functions.Identity.call)
.setTransaction(to, value, data) // 'value' is in wei, and 'data' must be a hex string
.setGas(gasToken, gasPrice, gasLimit)
.setRelayer(relayer)
.setAsymmetricKeyID(kid);
await s.post(signature, web3);
} catch(error){
console.log(error);
}
```
#### Using Identity contract `approveAndCall` function
This functionality is used when a Identity will invoke a contract function that requires a transfer of Tokens
```
try {
const s = new StatusGasRelayer.Identity(identityAddress, accountAddress)
.setContractFunction(Functions.Identity.approveAndCall)
.setTransaction(to, value, data)
.setBaseToken(baseToken)
.setGas(gasToken, gasPrice, gasLimit)
.setRelayer(relayer)
.setAsymmetricKeyID(kid);
await s.post(signature, web3);
} catch(error){
console.log(error);
}
```
#### Using SNTController transferSNT function
This functionality is used for simple wallets to perform SNT transfers without paying ETH fees
```
try {
const accounts = await web3.eth.getAccounts();
const s = new StatusGasRelayer.SNTController(SNTController.options.address, accounts[2])
.transferSNT(to, amount)
.setGas(gasPrice)
.setRelayer(relayer)
.setAsymmetricKeyID(kid);
await s.post(signature, web3);
} catch(error){
console.log(error);
}
```
#### Using SNTController execute function
```
try {
const accounts = await web3.eth.getAccounts();
const s = new StatusGasRelayer.SNTController(SNTController.options.address, accounts[2])
.execute(allowedContract, data)
.setGas(gasPrice, gasMinimal)
.setRelayer(relayer)
.setAsymmetricKeyID(kid);
await s.post(signature, web3);
} catch(error){
console.log(error);
}
```
### Status Extensions
- TODO

View File

@ -12,7 +12,7 @@ module.exports = {
"port": 8545 "port": 8545
}, },
"blockchain": { "blockchain": {
"account": "d13c733f32970e5282981fa4a738682ba3c1e2d0" "account": "0xb8d851486d1c953e31a44374aca11151d49b8bb3"
}, },
"whisper": { "whisper": {
"symKey": "0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b", "symKey": "0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b",

View File

@ -0,0 +1,2 @@
#!/bin/bash
geth --testnet --syncmode=light --password=../testnet_password --port=30303 --rpc --rpcport=8545 --rpcaddr=localhost --rpccorsdomain=http://localhost:8000 --ws --wsport=8546 --wsaddr=localhost --wsorigins="gas-relayer" --shh --shh.pow=0.002 --rpcapi=eth,web3,net,shh --wsapi=eth,web3,net,shh --unlock=d13c733f32970e5282981fa4a738682ba3c1e2d0

View File

@ -0,0 +1,40 @@
# Installation - Development Environment
- Install the latest develop version of embark: `npm install -g https://github.com/embark-framework/embark.git`
- Install `geth`
- Clone the repository
`git clone https://github.com/status-im/snt-gas-relay.git`
- Execute the following commands
```
cd snt-gas-relay/test-dapp
chmod +x setup_dev_env.sh
npm install
embark reset
embark blockchain
```
- When Embark finishes loading, execute `embark run` to deploy the contracts.
- After the contracts are deployed and the test dapp is available, execute `./setup_dev_env.sh` to create the test account
## Test DApp
To run the test dapp, use `embark run` and then browse `http://localhost:8000/index.html`.
The gas relayer service needs to be running, and configured correctly to process the transactions. Things to take in account are: the account used in embark, and the contract addresses.
You may use the test dapp to generate SNT and fund the relayer account before running the gas relayer, as it requires ether to start.
## Relayer Node
- `cd snt-gas-relay/gas-relayer`
- This program is configured with the default values on `config/config.json` for a embark installation run from 0. To execute the gas-relayer, you may use any of the following three commands.
```
npm start
node src/service.js
nodemon src/service.js
```

View File

@ -0,0 +1,115 @@
# Installation - Testnet
### Notes
1. This installation assumes you're using Ubuntu or similar
2. You need a non-root user that belongs to the sudo group.
### Required software install procedure
1. Install Ethereum
```
sudo apt install software-properties-common
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt install ethereum
```
2. Install NodeJS using NVM (Check NVM repo for updated procedure)
```
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
source .bashrc
nvm install --lts
```
3. Install Python and other software
```
sudo apt install python build-essential
```
### Clone the repo
```
git clone https://github.com/status-im/snt-gas-relay.git
npm install
```
### Setup geth for Whisper
1. Verify `geth` light mode starts successfully. Exit geth when you see everything is ok
```
geth --testnet --syncmode=light console
Ctrl + C
```
2. Create an account (at the moment, this install procedure has only been tested with Ropsten testnet). It will ask you for a password
```
geth account new
```
3. Create a file `geth_pass` that will contain the password. Ensure the permissions are read/write for the owner. This file can be put in any secure folder you determine. YOu need access to this file from the folder where the gas-relayer will execute
```
echo "MyPassword" > snt-gas-relay\gas-relayer\testnet_password
chmod 600 snt-gas-relay\gas-relayer\testnet_password
```
4. There aren't enough geth peers with Whisper enabled to guarantee that messages will arrive from one node to other. We need to create a `static-nodes.json` file in `~/.ethereum/testnet/geth/`.
This file needs to contain the following array:
```
[
"enode://436cc6f674928fdc9a9f7990f2944002b685d1c37f025c1be425185b5b1f0900feaf1ccc2a6130268f9901be4a7d252f37302c8335a2c1a62736e9232691cc3a@174.138.105.243:30404",
"enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@206.189.243.57:30404",
"enode://7427dfe38bd4cf7c58bb96417806fab25782ec3e6046a8053370022cbaa281536e8d64ecd1b02e1f8f72768e295d06258ba43d88304db068e6f2417ae8bcb9a6@104.154.88.123:30404",
"enode://ebefab39b69bbbe64d8cd86be765b3be356d8c4b24660f65d493143a0c44f38c85a257300178f7845592a1b0332811542e9a58281c835babdd7535babb64efc1@35.202.99.224:30404",
"enode://a6a2a9b3a7cbb0a15da74301537ebba549c990e3325ae78e1272a19a3ace150d03c184b8ac86cc33f1f2f63691e467d49308f02d613277754c4dccd6773b95e8@206.189.243.176:30304",
"enode://207e53d9bf66be7441e3daba36f53bfbda0b6099dba9a865afc6260a2d253fb8a56a72a48598a4f7ba271792c2e4a8e1a43aaef7f34857f520c8c820f63b44c8@35.224.15.65:30304",
"enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@206.189.243.162:30504",
"enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@206.189.243.169:30504",
"enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@206.189.243.168:30504",
"enode://7de99e4cb1b3523bd26ca212369540646607c721ad4f3e5c821ed9148150ce6ce2e72631723002210fac1fd52dfa8bbdf3555e05379af79515e1179da37cc3db@35.188.19.210:30504",
"enode://015e22f6cd2b44c8a51bd7a23555e271e0759c7d7f52432719665a74966f2da456d28e154e836bee6092b4d686fe67e331655586c57b718be3997c1629d24167@35.226.21.19:30504",
"enode://531e252ec966b7e83f5538c19bf1cde7381cc7949026a6e499b6e998e695751aadf26d4c98d5a4eabfb7cefd31c3c88d600a775f14ed5781520a88ecd25da3c6@35.225.227.79:30504"
]
```
These enodes were extracted from https://github.com/status-im/status-go/blob/develop/params/cluster.go.
### Setup the gas relayer
Before executing this program, `config/config.json` must be setup and `npm install` needs to be executed. Important values to verify are related to the node configuration, just like:
- Host, port and protocol to connect to the geth node
- Host, port and protocol Ganache will use when forking the blockchain for gas estimations and other operations
- Wallet account used for processing the transactions
- Symmetric key used to receive the Whisper messages
- Accepted tokens information
- Contract configuration
1. For testnet, a config file is provided with the required configuration.
```
cd snt-gas-relay/config
rm config.js
mv config.testnet.js config.js
```
2. A node that wants to act as a relayer only needs to have a geth node with whisper enabled, and an account with ether to process the transactions. This account needs to be configured in `./config/config.js`. Edit this file and set the account:
```
"blockchain": {
"account": "your account here"
},
```
### Launching the relayer
A `launch-geth-testnet.sh` script is provided. You need to edit this file and set the `--unlock` option with the address used for procesing the transactions, and also the `--password` with the path to the password file. This script assumes the password file is called `testnet_password` and it's located in the same folder of the gas-relayer service.
After editing the file, assuming your account has eth, you may use any of the following three commands to launch the relayer.
```
npm start
node src/service.js
nodemon src/service.js
```
### Using the testdapp with testnet
The test dapp may be used for testnet from your computer. It requires a provider that allows websockets:
1. Start by executing `launch-geth-testnet.sh` in the test dapp folder to start the geth node with the required config to communicate with the status cluster via whisper.
2. Execute `embark run testnet` to launch the dapp connected to testnet
3. Navigate in your browser to http://localhost:8000. In metamask connect to your local node thru the port 8546 to use websockets.
4. You're now able to use the dapp normally. The status for the relayer that can be seen in the footer of the dapp won't reflect accurate information, since the relayers account are not deterministic anymore since you're not in a development environment

140
javascript-library.md Normal file
View File

@ -0,0 +1,140 @@
# Javascript Library
To simplify the process of building the whisper messages, a js file `status-gas-relayer.js` was created in the test-dapp. It only requires to setup connection to geth, and required keypairs and symkeys. This file might be expanded upon in the future and converted to a npm package.
## Use
```
import StatusGasRelayer, {Contracts, Functions, Messages} from 'status-gas-relayer';
// Connecting to web3
const web3 = new Web3('ws://localhost:8546');
const kid = await web3js.shh.newKeyPair()
const skid = await web3.shh.addSymKey("0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b");
```
#### Subscribing to messages
General message subscription. Special handling is needed for handling relayer availability messages. The `sig` property is the relayer's public key that needs to be sent when sending a transaction message. More than 1 relayer can reply, so it's recommended to save these keys in a list/array.
```
StatusGasRelayer.subscribe(web3js, (error, msgObj) => {
if(error) {
console.error(error);
return;
}
if(msgObj.message == Messages.available){
// Relayer availability message
console.log("Relayer available: " + msgObj.sig);
} else {
// Normal message
console.log(msgObj);
}
}, {
privateKeyID: kid
});
```
#### Polling for relayers
```
const identityAddress = this.props.identityAddress; // Identity contract
const accountAddress = web3.eth.defaultAccount;
const gasToken = SNT.options.address;
const gasPrice = 1000000000000; // In wei equivalent to the used token
const s = new StatusGasRelayer.AvailableRelayers(Contracts.Identity, identityAddress, accountAddress)
.setRelayersSymKeyID(skid)
.setAsymmetricKeyID(kid)
.setGas(gasToken, gasPrice);
await s.post(web3);
```
#### Signing a message
Signing a message is similar to invoking a function. Both use mostly the same functions. The difference is that when you invoke a function, you need to specify the relayer and asymmetric key Id.
```
try {
const s = new StatusGasRelayer.Identity(identityAddress, accountAddress)
.setContractFunction(Functions.Identity.call)
.setTransaction(to, value, data)
.setGas(gasToken, gasPrice, gasLimit);
const signature = await s.sign(web3);
} catch(error){
console.log(error);
}
```
#### Using Identity contract `call` function
This functionality is used when a Identity will invoke a contract function or transfer ether without paying fees
```
try {
const s = new StatusGasRelayer.Identity(identityAddress, accountAddress)
.setContractFunction(Functions.Identity.call)
.setTransaction(to, value, data) // 'value' is in wei, and 'data' must be a hex string
.setGas(gasToken, gasPrice, gasLimit)
.setRelayer(relayer)
.setAsymmetricKeyID(kid);
await s.post(signature, web3);
} catch(error){
console.log(error);
}
```
#### Using Identity contract `approveAndCall` function
This functionality is used when a Identity will invoke a contract function that requires a transfer of Tokens
```
try {
const s = new StatusGasRelayer.Identity(identityAddress, accountAddress)
.setContractFunction(Functions.Identity.approveAndCall)
.setTransaction(to, value, data)
.setBaseToken(baseToken)
.setGas(gasToken, gasPrice, gasLimit)
.setRelayer(relayer)
.setAsymmetricKeyID(kid);
await s.post(signature, web3);
} catch(error){
console.log(error);
}
```
#### Using SNTController `transferSNT` function
This functionality is used for simple wallets to perform SNT transfers without paying ETH fees
```
try {
const accounts = await web3.eth.getAccounts();
const s = new StatusGasRelayer.SNTController(SNTController.options.address, accounts[2])
.transferSNT(to, amount)
.setGas(gasPrice)
.setRelayer(relayer)
.setAsymmetricKeyID(kid);
await s.post(signature, web3);
} catch(error){
console.log(error);
}
```
#### Using SNTController `execute` function
```
try {
const accounts = await web3.eth.getAccounts();
const s = new StatusGasRelayer.SNTController(SNTController.options.address, accounts[2])
.execute(allowedContract, data)
.setGas(gasPrice, gasMinimal)
.setRelayer(relayer)
.setAsymmetricKeyID(kid);
await s.post(signature, web3);
} catch(error){
console.log(error);
}
```

131
relayer-protocol.md Normal file
View File

@ -0,0 +1,131 @@
# Gas relayer protocol
Current implementation of gas relayers use whisper as a communication medium to broadcast availability, and transaction details. As such, the messages require specific settings and format to be interpreted correctly by the relayer network.
#### Sending a message to the gas relayer network (all accounts and private keys should be replaced by your own)
```
shh.post({
symKeyID: SYM_KEY, // If requesting availability
pubKey: PUBLIC_KEY_ID, // If sending a transaction
sig: WHISPER_KEY_ID,
ttl: 10,
powTarget: 0.002,
powTime: 1,
topic: TOPIC_NAME,
payload: PAYLOAD_BYTES
}).then(......)
```
- `symKeyID: SYM_KEY` must contain the whisper symmetric key used. It is shown on the console when running the service with `node`. With the provided configuration you can use the symmetric key `0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b`. Only used when asking for relayer availability.
- `pubKey: PUBLIC_KEY_ID`. After asking for availability, once the user decides on a relayer, it needs to set the `pubKey` attribute with the relayer public key (received in the availability reply in the `sig` attribute of the message).
- `WHISPER_KEY_ID` represents a keypair registered on your node, that will be used to sign the message. Can be generated with `web3W.shh.newKeyPair()`
- `TOPIC_NAME` must contain one of the topic names generated based on converting the contract name to hex, and taking the first 8 bytes. For the provided configuration the following topics are available:
- - IdentityGasRelay: `0x4964656e`
- - SNTController: `0x534e5443`
- `PAYLOAD_BYTES` a hex string that contains details on the operation to perform.
#### Polling for gas relayers
The first step is asking the relayers for their availability. The message payload needs to be the hex string representation of a JSON object with a specific structure:
```
const payload = web3.utils.toHex({
'contract': "0xContractToInvoke",
'address': web3.eth.defaultAccount,
'action': 'availability',
'token': "0xGasTokenAddress",
'gasPrice': 1234
});
```
- `contract` is the address of the contract that will perform the operation, in this case it can be an Identity, or the SNTController.
- `address` The address that will sign the transactions. Normally it's `web3.eth.defaultAccount`
- `gasToken`: token used for paying the gas cost
- `gasPrice`: The gas price used for the transaction
This is a example code of how to send an 'availability' message:
```
const whisperKeyPairID = await web3W.shh.newKeyPair();
const msgObj = {
symKeyId: "0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b",
sig: whisperKeyPairID,
ttl: 10,
powTarget: 0.002,
powTime: 1,
topic: "0x4964656e",
payload: web3.utils.toHex({
'contract': "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
'address': web3.eth.defaultAccount
'action': 'availability',
'gasToken': "0x744d70fdbe2ba4cf95131626614a1763df805b9e",
'gasPrice': 40000000000 // 40 gwei equivalent in SNT
})
};
web3.shh.post(msgObj)
.then((err, result) => {
console.log(result);
console.log(err);
});
```
When it replies, you need to extract the `sig` attribute to obtain the relayer's public key
#### Sending transaction details
Sending a transaction is similar to the previous operation, except that we send the message to an specific node, we use the action `transaction`, and also we send a `encodedFunctionCall` with the details of the transaction to execute.
From the list of relayers received via whisper messages, you need to extract the `message.sig` to obtain the `pubKey`. This value is used to send the transaction to that specific relayer.
`encodedFunCall` is the hex data used obtained from `web3.eth.abi.encodeFunctionCall` for the specific function we want to invoke.
If we were to execute `callGasRelayed(address,uint256,bytes,uint256,uint256,uint256,address,bytes)` (part of the IdentityGasRelay) in contract `0x692a70d2e424a56d2c6c27aa97d1a86395877b3a`, with these values: `"0x11223344556677889900998877665544332211",100,"0x00",1,10,20,"0x1122334455112233445511223344551122334455"`, "0x1122334455", `PAYLOAD_BYTES` can be prepared as follows:
```
// The following values are created obtained when polling for relayers
const whisperKeyPairID = await web3W.shh.newKeyPair();
const relayerPubKey = "0xRELAYER_PUBLIC_KEY_HERE";
// ...
// ...
const jsonAbi = ABIOfIdentityGasRelay.find(x => x.name == "callGasRelayed");
const funCall = web3.eth.abi.encodeFunctionCall(jsonAbi,
[
"0x11223344556677889900998877665544332211",
100,
"0x00",
1,
10,
20,
"0x1122334455112233445511223344551122334455",
"0x1122334455"
]);
const msgObj = {
pubKey: relayerPubKey,
sig: whisperKeyPairID,
ttl: 10,
powTarget: 0.002,
powTime: 1,
topic: "0x4964656e",
payload: web3.utils.toHex({
'contract': "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
'address': web3.eth.defaultAccount
'action': 'transaction',
'encodedFunctionCall': funCall,
})
};
web3.shh.post(msgObj)
.then((err, result) => {
console.log(result);
console.log(err);
});
```
Notice that sending messages use specific TTL, PoW Targets nad Time. These values specified here are those accepted by the Status.im cluster of nodes. The configuration for dev environment use greater values, since it is not expected to communicate with other nodes.

View File

@ -1,2 +0,0 @@
#!/bin/bash
geth --networkid=1337 --datadir=.embark/development/datadir --password=config/development/password --port=30303 --rpc --rpcport=8545 --rpcaddr=localhost --rpccorsdomain=* --ws --wsport=8546 --wsaddr=localhost --wsorigins=* --nodiscover --maxpeers=0 --mine --shh --shh.pow=0.002 --rpcapi=eth,web3,net,debug,shh --wsapi=eth,web3,net,shh,debug,personal --targetgaslimit=8000000 --dev