Merge pull request #2 from status-im/whisper

WIP: Whisper transport
This commit is contained in:
Oskar Thorén 2019-02-21 14:38:03 +08:00 committed by GitHub
commit 6a002476d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 776 additions and 29 deletions

View File

@ -10,3 +10,29 @@ Initial PoC report: https://notes.status.im/THYDMxSmSSiM5ASdl-syZg
make
make run # see sync.py
```
## Whisper
Run geth node:
```
geth --testnet --syncmode=light --ws --wsport=8546 --wsaddr=localhost --wsorigins=statusjs --rpc --maxpeers=25 --shh --shh.pow=0.002 --wsapi=eth,web3,net,shh,debug,admin,personal
```
geth --testnet --rpc --maxpeers=25 --shh --shh.pow=0.002 --rpcport=8501
```
geth --testnet --rpc --maxpeers=25 --shh --shh.pow=0.002 --rpcport=8500 --datadir=/tmp/foo --port=30000
geth --testnet --rpc --maxpeers=25 --shh --shh.pow=0.002 --rpcport=8501 --datadir=/tmp/bar --port=30001
- add nodes to connect
- running whisper node on own nodes?
cp static-nodes.json ~/.ethereum/testnet/geth/
# send 1:1 chat
0x04cfc3a0f6c1cb824823164603959c639f99680485da2446dc316969faca00421b20dba3996bf99b8b5db7745eace60545a77e54784e91e440aa1af931161de3a6
geth --testnet --rpc --maxpeers=25 --shh --shh.pow=0.002 --rpcport=8501 --datadir=/tmp/bar --port=30001 --ipcpath /tmp/bar.ipc
geth --testnet --rpc --maxpeers=25 --shh --shh.pow=0.002 --rpcport=8501 --datadir=~/.ethereum/node-b --port=30001

59
data_sync/app.py Normal file
View File

@ -0,0 +1,59 @@
import networkwhisper, sync, sys, threading, time
# XXX: Ugly constants, should be elsewhere
SETTINGS = {
'a': {
'keypair': "0x57083392b29bdf24512c93cfdf45d38c87d9d882da3918c59f4406445ea976a4",
'pubkey': "0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5",
'friend' : "0x04ff921ddf78b5ed4537402f59a150caf9d96a83f2a345a1ddf9df12e99e7778f314c9ca72e8285eb213af84f5a7b01aabb62c67e46657976ded6658e1b9e83c73" #b
},
'b': {
'keypair': "0x7b5c5af9736d9f1773f2020dd0fef0bc3c8aeaf147d2bf41961e766588e086e7",
'pubkey' : "0x04ff921ddf78b5ed4537402f59a150caf9d96a83f2a345a1ddf9df12e99e7778f314c9ca72e8285eb213af84f5a7b01aabb62c67e46657976ded6658e1b9e83c73",
'friend': "0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5" #a
}
}
def tick_process(node):
while True:
#print("tick")
node.tick()
time.sleep(1)
def main():
assert len(sys.argv) > 1, "Missing node argument. Example: 'a' or 'b'"
# Assume exists
settings = SETTINGS[sys.argv[1]]
keypair = settings['keypair']
identity_pk = settings['pubkey']
friend_pk = settings['friend']
# Init node
whisper_node = networkwhisper.WhisperNodeHelper(keypair)
node = sync.Node(identity_pk, whisper_node, 'burstyMobile', 'batch')
# XXX: A bit weird? Or very weird
node.nodes = [node]
# XXX: Doesn't make sense, a doesn't have b info
#node.addPeer(friend_pk, b)
# Clients should decide policy
node.share(friend_pk)
# Start background thread
thread = threading.Thread(target=tick_process, args=[node])
thread.daemon = True
thread.start()
while True:
text = input("> ")
print("You wrote", text)
rec = sync.new_message_record(text)
node.append_message(rec)
node.print_sync_state()
main()
# Ok, can send message
# Now share with these other
# And allow b to run as a proc too

133
data_sync/filter.py Normal file
View File

@ -0,0 +1,133 @@
from web3 import Web3, HTTPProvider
from threading import Thread
import time, sys
# Constant
#---------------------------------------------------------------------
#host = 'http://localhost:8545'
# XXX
a_keyPair = "0x57083392b29bdf24512c93cfdf45d38c87d9d882da3918c59f4406445ea976a4"
b_keyPair= "0x7b5c5af9736d9f1773f2020dd0fef0bc3c8aeaf147d2bf41961e766588e086e7"
# Derived, used for addressing
a_pubKey = "0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5"
b_pubKey = "0x04ff921ddf78b5ed4537402f59a150caf9d96a83f2a345a1ddf9df12e99e7778f314c9ca72e8285eb213af84f5a7b01aabb62c67e46657976ded6658e1b9e83c73"
#(def discovery-topic "0xf8946aac")
topic="0xf8946aac"
#topic = '0x00000000'
# API
#---------------------------------------------------------------------
# XXX: Hacky
def newKeyPair():
raw_keyPair = web3.shh.newKeyPair()
keyPair = "0x" + raw_keyPair
return keyPair
# privateKeyID - String: ID of private (asymmetric) key for message decryption.
def pollFilter(topic, keyPair):
kId = web3.shh.addPrivateKey(keyPair)
pubKey = web3.shh.getPublicKey(kId)
print("***PUBKEY", pubKey)
myFilter = web3.shh.newMessageFilter({'topic': topic,
'privateKeyID': kId})
myFilter.poll_interval = 600;
return myFilter
def sendMessage(address_to, topic, msg):
#print("address_to", address_to)
web3.shh.post({
'pubKey': address_to,
'topic': topic,
'powTarget': 2.01,
'powTime': 2,
'ttl': 10,
'payload': web3.toHex(text=msg)
});
def getMessages(myFilter):
filterID = myFilter.filter_id
retreived_messages = web3.shh.getMessages(filterID)
for i in range(0, len(retreived_messages)):
#print(retreived_messages[i]['payload'])
print("\nRECV " + retreived_messages[i]['payload'].decode("utf-8"))
#print(retreived_messages[i])
# Run
#---------------------------------------------------------------------
class Daemon:
def __init__(self):
self.id = "x"
def run(self):
while True:
#sendMessage(address_to, topic, "hello")
getMessages(myFilter)
#print("tick")
time.sleep(1)
# Args
#---------------------------------------------------------------------
if len(sys.argv) < 2:
print("Missing argument")
sys.exit(0)
node = sys.argv[1]
# what
oskar="0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5"
# contact code
#oskar="0x04cfc3a0f6c1cb824823164603959c639f99680485da2446dc316969faca00421b20dba3996bf99b8b5db7745eace60545a77e54784e91e440aa1af931161de3a6"
if(node == "a"):
print("a")
keyPair = a_keyPair
# XXX: Seems weird, should be b_pubkey?
#address_to = oskar
address_to = a_pubKey # Works
#address_to = b_pubKey
host = "http://localhost:8500"
elif(node == "b"):
print("b")
keyPair = b_keyPair
#address_to = oskar
# XXX
#address_to = a_pubKey
address_to = b_pubKey
#address_to = a_pubKey
host = "http://localhost:8500"
#host = "http://localhost:8501"
else:
print("Unknown node")
sys.exit(0)
# Connection
#---------------------------------------------------------------------
print("host", host)
web3 = Web3(HTTPProvider(host))
from web3.shh import Shh
Shh.attach(web3, "shh")
#kId = web3.shh.addPrivateKey(keyPair)
#pubKey = web3.shh.getPublicKey(kId)
# A sending messages to B and B then checking
# keyPair used for decryption
print("keyPair for filter", keyPair)
myFilter = pollFilter(topic, keyPair)
# Take address_to and filter as args?
threads = []
daemon = Thread(target=Daemon().run())
threads.append(daemon)
daemon.start()

146
data_sync/networkwhisper.py Normal file
View File

@ -0,0 +1,146 @@
from web3 import Web3, HTTPProvider
from web3.shh import Shh
import random
# Temp
import sync_pb2
# XXX: This assumes a node is actually running - shell out to boot geth?
# At least error if proc not running
class WhisperNodeHelper():
def __init__(self, keypair):
# XXX: Whisper specific, but this host should be unique per node
self.host = "http://localhost:8500"
self.web3 = Web3(HTTPProvider(self.host))
Shh.attach(self.web3, "shh")
assert self.web3.shh.web3.isConnected(), "Node not connected, are you running it?"
self.topic="0xf8946aac" # discovery-topic
self.keyPair = keypair
# XXX: Doesn't belong here
self.kId = self.web3.shh.addPrivateKey(self.keyPair)
self.myFilter = self.poll_filter(self.topic, self.keyPair)
# XXX: Prune this
self.nodes = []
self.time = 0
#self.queue = {}
#self.peers = {}
# Global network reliability
self.reliability = 1 # 0.95? Dunno.
def poll_filter(self, topic, keyPair):
# XXX: Doesn't belong here
#kId = self.web3.shh.addPrivateKey(keyPair)
pubKey = self.web3.shh.getPublicKey(self.kId)
#print("***PUBKEY", pubKey)
myFilter = self.web3.shh.newMessageFilter({'topic': topic,
'privateKeyID': self.kId})
# Purpose of this if we do getMessages?
myFilter.poll_interval = 600;
return myFilter
def tick(self):
filterID = self.myFilter.filter_id
retreived_messages = self.web3.shh.getMessages(filterID)
# TODO: Deal with these messages similar to simulation
# receiver.on_receive(sender, msg)
for i in range(0, len(retreived_messages)):
#print(retreived_messages[i]['payload'])
#print("\nRECV TYPE", type(retreived_messages[i]['payload']))
# XXX: This parsing should probably happen elsewhere
msg = sync_pb2.Record()
#full = retreived_messages[i]
sig = retreived_messages[i]['sig']
print("***SIG", sig.hex())
payload = retreived_messages[i]['payload']
#print("\nRECV payload", payload)
msg.ParseFromString(payload)
print("\nRECV parsed", msg)
# XXX correct way to refer to MESSAGE
if msg.header.type == 1:
print("\nRECV parse", msg.payload.message.body.decode())
# XXX Only one receiver, this is a node not network
receiver = self.nodes[0]
# HEREATM
# How sender?
# TODO: Figure out how we know sender, assumes signed message
# inside payload? but if it isn't your own message then how work
# How does this currently work? How do we know from who it is?
# chat-id seems to be pubkey and some stuff
# sohuld be in signature sig
sender = sig.hex()
receiver.on_receive(sender, msg)
#print ""
print("tick", self.time + 1)
#print "-----------"
# XXX: This is ugly, why is this ticking nodes?
# NOTE: Only self is ticking
for n in self.nodes:
n.tick()
self.time += 1
# NetworkSim stub
# def tick(self):
# if self.time in self.queue:
# # XXX: Should sender be here?
# for sender, receiver, msg in self.queue[self.time]:
# if random.random() < self.reliability:
# #print "*** message ok", sender.name, "->", receiver.name
# receiver.on_receive(sender, msg)
# #else:
# #print "*** message dropped", sender.name, "->", receiver.name
# #print ""
# print "tick", self.time + 1
# #print "-----------"
# for n in self.nodes:
# n.tick()
# self.time += 1
# sender id / pubkey not needed for now
# topic assumed to be hardcoded
def send_message(self, sender_id, address_to, msg):
print("*** (whisper-network) send_message", address_to)
# XXX: Is this what we want to do?
payload = msg.SerializeToString()
print("*** (whisper-network) send_message payload", payload)
#print("*** (whisper-network) send_message hex", self.web3.toHex(payload))
topic = self.topic
self.web3.shh.post({
'pubKey': address_to,
'topic': topic,
'powTarget': 2.01,
'powTime': 2,
'ttl': 10,
'sig': self.kId,
'payload': self.web3.toHex(payload)
});
# NetworkSim stub
# def send_message(self, sender_id, receiver_id, message):
# #print "*** (network) send_message", sender_id, receiver_id
# # XXX: Assuming sender exists
# sender = self.peers[sender_id]
# receiver = self.peers[receiver_id]
# recv_time = self.time + self.latency_uniform_random()
# if recv_time not in self.queue:
# self.queue[recv_time] = []
# self.queue[recv_time].append((sender, receiver, message))
# XXX: This should be normal distribution or Poisson
# NetworkSim stub; not needed for Whisper probably
# def latency_uniform_random(self):
# # XXX: Hardcode for now, easier analyze
# latency = 1
# #latency = random.randint(1,3)
# return latency

View File

@ -0,0 +1,6 @@
# What would a private messaging client look like?
# It should allow a node to send PRIVATE_MESSAGE
# Is this the most important thing to work on? Vs writing presentation for 30 people

View File

@ -0,0 +1,6 @@
#!/usr/bin/env sh
# Should probably be a subprocess in python and print to some logger
# Or Docker compose or whatever.
geth --testnet --syncmode=light --rpc --maxpeers=25 --shh --shh.pow=0.002 --rpcport=8500 --datadir=/tmp/node-a --port=30000

View File

@ -0,0 +1,6 @@
#!/usr/bin/env sh
# Should probably be a subprocess in python and print to some logger
# Or Docker compose or whatever.
geth --testnet --syncmode=light --rpc --maxpeers=25 --shh --shh.pow=0.002 --rpcport=8501 --datadir=/tmp/node-b --port=30001

View File

@ -0,0 +1,14 @@
[
"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"
]

View File

@ -2,6 +2,7 @@
import hashlib
import networksim
import networkwhisper
import random
import sync_pb2
import time
@ -225,6 +226,7 @@ class Node():
def append_message(self, message):
message_id = get_message_id(message)
#print("*** append", message)
self.log.append({"id": message_id,
"message": message})
# XXX: Ugly but easier access while keeping log order
@ -243,6 +245,8 @@ class Node():
"send_time": self.time + 1
}
# TODO: Probably something more here for message parsing
# TODO: Need to switch from object to pubkey here with name etc
def on_receive(self, sender, message):
if random.random() < self.reliability:
#print "*** {} received message from {}".format(self.name, sender.name)
@ -259,17 +263,19 @@ class Node():
else:
log("*** node {} offline, dropping message".format(self.name))
def on_receive_message(self, sender, message):
# TODO: Problem: It assumes there's a name, as opposed to a pubkey
def on_receive_message(self, sender_pubkey, message):
message_id = get_message_id(message)
log('MESSAGE ({} -> {}): {} received'.format(sender.name, self.name, message_id[:4]))
log('MESSAGE ({} -> {}): {} received'.format(sender_pubkey, self.name, message_id[:4]))
if message_id not in self.sync_state:
self.sync_state[message_id] = {}
if sender.name in self.sync_state[message_id]:
self.sync_state[message_id][sender.name]['hold_flag'] == 1
self.sync_state[message_id][sender.name]['ack_flag'] == 1
if sender_pubkey in self.sync_state[message_id]:
self.sync_state[message_id][sender_pubkey]['hold_flag'] == 1
self.sync_state[message_id][sender_pubkey]['ack_flag'] == 1
# XXX: ACK again here?
self.sync_state[message_id][sender.name] = {
# XXX: This is bad, sender here with Whisper is only pbukey
self.sync_state[message_id][sender_pubkey] = {
"hold_flag": 1,
"ack_flag": 1,
"request_flag": 0,
@ -290,47 +296,47 @@ class Node():
self.messages[message_id] = message
def on_receive_ack(self, sender, message):
def on_receive_ack(self, sender_pubkey, message):
for ack in message.payload.ack.id:
log(' ACK ({} -> {}): {} received'.format(sender.name, self.name, ack[:4]))
self.sync_state[ack][sender.name]["hold_flag"] = 1
log(' ACK ({} -> {}): {} received'.format(sender_pubkey, self.name, ack[:4]))
self.sync_state[ack][sender_pubkey]["hold_flag"] = 1
def on_receive_offer(self, sender, message):
def on_receive_offer(self, sender_pubkey, message):
for message_id in message.payload.offer.id:
log(' OFFER ({} -> {}): {} received'.format(sender.name, self.name, message_id[:4]))
log(' OFFER ({} -> {}): {} received'.format(sender_pubkey, self.name, message_id[:4]))
if (message_id in self.sync_state and
sender.name in self.sync_state[message_id] and
self.sync_state[message_id][sender.name]['ack_flag'] == 1):
print("Have message, not ACKED yet, add to list", sender.name, message_id)
if sender.name not in self.offeredMessages:
self.offeredMessages[sender.name] = []
self.offeredMessages[sender.name].append(message_id)
sender_pubkey in self.sync_state[message_id] and
self.sync_state[message_id][sender_pubkey]['ack_flag'] == 1):
print("Have message, not ACKED yet, add to list", sender_pubkey, message_id)
if sender_pubkey not in self.offeredMessages:
self.offeredMessages[sender_pubkey] = []
self.offeredMessages[sender_pubkey].append(message_id)
elif message_id not in self.sync_state:
#print "*** {} on_receive_offer from {} not holding {}".format(self.name, sender.name, message_id)
if sender.name not in self.offeredMessages:
self.offeredMessages[sender.name] = []
self.offeredMessages[sender.name].append(message_id)
#print "*** {} on_receive_offer from {} not holding {}".format(self.name, sender_pubkey, message_id)
if sender_pubkey not in self.offeredMessages:
self.offeredMessages[sender_pubkey] = []
self.offeredMessages[sender_pubkey].append(message_id)
#else:
# print "*** {} on_receive_offer have {} and ACKd OR peer {} unknown".format(self.name, message_id, sender.name)
# print "*** {} on_receive_offer have {} and ACKd OR peer {} unknown".format(self.name, message_id, sender_pubkey)
# XXX: Init fn to wrap updates
if message_id not in self.sync_state:
self.sync_state[message_id] = {}
if sender.name not in self.sync_state[message_id]:
self.sync_state[message_id][sender.name] = {
if sender_pubkey not in self.sync_state[message_id]:
self.sync_state[message_id][sender_pubkey] = {
"hold_flag": 1,
"ack_flag": 0,
"request_flag": 0,
"send_count": 0,
"send_time": 0
}
self.sync_state[message_id][sender.name]['hold_flag'] = 1
self.sync_state[message_id][sender_pubkey]['hold_flag'] = 1
#print "*** {} offeredMessages {}".format(self.name, self.offeredMessages)
def on_receive_request(self, sender, message):
def on_receive_request(self, sender_pubkey, message):
for req in message.payload.request.id:
log('REQUEST ({} -> {}): {} received'.format(sender.name, self.name, req[:4]))
self.sync_state[req][sender.name]["request_flag"] = 1
log('REQUEST ({} -> {}): {} received'.format(sender_pubkey, self.name, req[:4]))
self.sync_state[req][sender_pubkey]["request_flag"] = 1
def print_sync_state(self):
log("\n{} POV @{}".format(self.name, self.time))
@ -353,6 +359,28 @@ class Node():
log(line)
#log("-" * 60)
# Shorter names for pubkey
def print_sync_state2(self):
log("\n{} POV @{}".format(self.name[-4:], self.time))
log("-" * 60)
n = self.name[-4:]
for message_id, x in self.sync_state.items():
line = message_id[:4] + " | "
for peer, flags in x.items():
line += peer[-4:] + ": "
if flags['hold_flag']:
line += "hold "
if flags['ack_flag']:
line += "ack "
if flags['request_flag']:
line += "req "
line += "@" + str(flags['send_time'])
line += "(" + str(flags['send_count']) + ")"
line += " | "
log(line)
#log("-" * 60)
def update_availability(self):
#arr = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
arr = [1, 1, 0, 0, 1, 1, 0, 0]
@ -437,6 +465,9 @@ def new_req_record(ids):
# Mocking
################################################################################
# TODO: For whisper nodes should be public keys
# What about keypair to try to decrypt? should be in node
def run(steps=10):
n = networksim.NetworkSimulator()
@ -502,4 +533,63 @@ def run(steps=10):
c.print_sync_state()
d.print_sync_state()
run(30)
def whisperRun(steps=10):
a_keyPair = "0x57083392b29bdf24512c93cfdf45d38c87d9d882da3918c59f4406445ea976a4"
b_keyPair= "0x7b5c5af9736d9f1773f2020dd0fef0bc3c8aeaf147d2bf41961e766588e086e7"
# TODO: should be node names
# Derived, used for addressing
a_pubKey = "0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5"
b_pubKey = "0x04ff921ddf78b5ed4537402f59a150caf9d96a83f2a345a1ddf9df12e99e7778f314c9ca72e8285eb213af84f5a7b01aabb62c67e46657976ded6658e1b9e83c73"
aNode = networkwhisper.WhisperNodeHelper(a_keyPair)
bNode = networkwhisper.WhisperNodeHelper(b_keyPair)
# XXX: Not clear to me what's best here
# Interactive: less BW, Batch: less coordination
a = Node(a_pubKey, aNode, 'burstyMobile', 'batch')
b = Node(b_pubKey, bNode, 'burstyMobile', 'batch')
# XXX: Not clear this is needed for Whisper, since all nodes should be part of network
# Possibly analog with topics?
#n.peers["A"] = a
#n.peers["B"] = b
aNode.nodes = [a]
bNode.nodes = [b]
a.addPeer(b_pubKey, b)
b.addPeer(a_pubKey, a)
# NOTE: Client should decide policy, implict group
a.share(b_pubKey)
b.share(a_pubKey)
print("\nAssuming one group context (A-B) share):")
# XXX: Conditional append to get message graph?
# TODO: Actually need to encode graph, client concern
local_appends = {
1: [[a, "A: hello world"]],
2: [[b, "B: hello!"]],
}
# XXX: what is this again? should be for both nodes
for i in range(steps):
# NOTE: include signature and parent message
if aNode.time in local_appends:
for peer, msg in local_appends[aNode.time]:
rec = new_message_record(msg)
peer.append_message(rec)
# XXX: Why discrete time model here?
aNode.tick()
bNode.tick()
#a.print_sync_state()
#b.print_sync_state()
a.print_sync_state2()
b.print_sync_state2()
# TODO: With Whisper branch this one breaks, probably due to sender{,.name} => sender_pubkey mismatch.
#run(30)
#whisperRun(30)

1
data_sync/test.json Normal file
View File

@ -0,0 +1 @@
["~#c4",["Hello","text/plain","~:user-message",154938955408101,1549389554080,["^ ","~:chat-id","0x04d94a1a01872b598c7 cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5","~:text","Hello"]]]

200
data_sync/whisper.py Normal file
View File

@ -0,0 +1,200 @@
from web3 import Web3, HTTPProvider
from threading import Thread
import time, sys
# Constant
#---------------------------------------------------------------------
#host = 'http://localhost:8545'
# XXX
a_keyPair = "0x57083392b29bdf24512c93cfdf45d38c87d9d882da3918c59f4406445ea976a4"
b_keyPair= "0x7b5c5af9736d9f1773f2020dd0fef0bc3c8aeaf147d2bf41961e766588e086e7"
# Derived, used for addressing
a_pubKey = "0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5"
b_pubKey = "0x04ff921ddf78b5ed4537402f59a150caf9d96a83f2a345a1ddf9df12e99e7778f314c9ca72e8285eb213af84f5a7b01aabb62c67e46657976ded6658e1b9e83c73"
#(def discovery-topic "0xf8946aac")
topic="0xf8946aac"
#topic = '0x00000000'
# API
#---------------------------------------------------------------------
# XXX: Hacky
def newKeyPair():
raw_keyPair = web3.shh.newKeyPair()
keyPair = "0x" + raw_keyPair
return keyPair
# privateKeyID - String: ID of private (asymmetric) key for message decryption.
def pollFilter(topic, keyPair):
kId = web3.shh.addPrivateKey(keyPair)
pubKey = web3.shh.getPublicKey(kId)
print("***PUBKEY", pubKey)
myFilter = web3.shh.newMessageFilter({'topic': topic,
'privateKeyID': kId})
myFilter.poll_interval = 600;
return myFilter
def sendMessage(address_to, topic, msg):
#print("address_to", address_to)
web3.shh.post({
'pubKey': address_to,
'topic': topic,
'powTarget': 2.01,
'powTime': 2,
'ttl': 10,
'payload': web3.toHex(text=msg)
});
def getMessages(myFilter):
filterID = myFilter.filter_id
retreived_messages = web3.shh.getMessages(filterID)
for i in range(0, len(retreived_messages)):
#print(retreived_messages[i]['payload'])
print("\nRECV " + retreived_messages[i]['payload'].decode("utf-8"))
#print(retreived_messages[i])
# Run
#---------------------------------------------------------------------
class Daemon:
def __init__(self):
self.id = "x"
def run(self):
while True:
#sendMessage(address_to, topic, "hello")
getMessages(myFilter)
#print("tick")
time.sleep(1)
# Args
#---------------------------------------------------------------------
if len(sys.argv) < 2:
print("Missing argument")
sys.exit(0)
node = sys.argv[1]
# what
oskar="0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5"
# contact code
#oskar="0x04cfc3a0f6c1cb824823164603959c639f99680485da2446dc316969faca00421b20dba3996bf99b8b5db7745eace60545a77e54784e91e440aa1af931161de3a6"
if(node == "a"):
print("a")
keyPair = a_keyPair
# XXX: Seems weird, should be b_pubkey?
#address_to = oskar
address_to = a_pubKey # Works
#address_to = b_pubKey
host = "http://localhost:8500"
elif(node == "b"):
print("b")
keyPair = b_keyPair
#address_to = oskar
# XXX
#address_to = a_pubKey
address_to = b_pubKey
#address_to = a_pubKey
host = "http://localhost:8500"
#host = "http://localhost:8501"
else:
print("Unknown node")
sys.exit(0)
# Connection
#---------------------------------------------------------------------
print("host", host)
web3 = Web3(HTTPProvider(host))
from web3.shh import Shh
Shh.attach(web3, "shh")
#kId = web3.shh.addPrivateKey(keyPair)
#pubKey = web3.shh.getPublicKey(kId)
# A sending messages to B and B then checking
# keyPair used for decryption
print("keyPair for filter", keyPair)
myFilter = pollFilter(topic, keyPair)
print("yo sending")
sendMessage(address_to, topic, "hello")
sendMessage(address_to, topic, "hi also")
# XXX this works, well hell a does
# Separate node?
# XXX: Would expect keypair to be sender and pubkey in sendmsg to b receiver
# Are they flipped somehow?
#myFilter = pollFilter(topic, a_keyPair)
#sendMessage(b_pubKey, topic, "hello b")
#sendMessage(a_pubKey, topic, "hello a")
getMessages(myFilter)
#lol="\[\"~#c4\",\[\"Helloaa\",\"text/plain\",\"~:user-message\",154938955408101,1549389554080,\[\"^ \",\"~:chat-id\",\"0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5\",\"~:text\",\"Hellbaro\"]]]"
#raw = b'["~#c4",["Test","text/plain","~:user-message",154939130505401,1549391305053,["^ ","~:chat-id","0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5","~:text","Test"]]]'
#raw = b'["~#c4",["Test2","text/plain","~:user-message",154939130605401,1549391306053,["^ ","~:chat-id","0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5","~:text","Test2"]]]'
#json = ['~#c4', ['Test', 'text/plain', '~:user-message', 154939130505401, 1549391305053, ['^ ', '~:chat-id', '0x04d94a1a01872b598c7cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5', '~:text', 'Test']]]
#import json
#json_str = json.loads(raw.decode('utf-8'))
#print(json_str)
def run():
while True:
# lol
time.sleep(0.5)
text = input("> ")
#sendMessage(oskar, topic, lol)
#test = raw.decode('utf-8')
print("SEND " + text)
# Sending to A over discovery topic
# something wrong here
sendMessage(a_pubKey, topic, text)
#sendMessage(oskar, topic, test)
#sendMessage(a_pubKey, topic, "hello" + text)
#sendMessage(oskar, topic, "hello" + text)
# Take address_to and filter as args?
#threads = []
#daemon = Thread(target=Daemon().run())
#repl = Thread(target=run())
#threads.append(daemon)
#threads.append(repl)
#daemon.start()
#repl.start()
#b = Thread(name='background', target=Daemon().run)
#f = Thread(name='foreground', target=run)
# TODO
# Usage:
# ./whisper a
# => type to send message
# => see incoming messages (poll regularly)
# Vice versa for b
# Then:
# - check discovery topic listen
# - try to get end to end e.g. mobile phone
# - hook up to sync
# - consider subscribe instead?
# Connect to nodes
# listen to public channel all channels?
# Can receive messages from mobile, just not send

60
data_sync/whisper.py.old Normal file
View File

@ -0,0 +1,60 @@
from web3 import shh
from web3 import HTTPProvider, Web3
from web3.personal import Personal
import time
# Run geth repo with <OPTIONS>
# Ensure there's a private key ~
# Pubkey
# 0x040cb9373bf8cd9dcbca4b75ccbfad52bbc66d1aaca8095adb2a7dcf8504146f0abde4ca22adf77b5062f113585befbf37e06dcadd0ce1093695e53d00d2109528
# XXX: Message not sent, due to threads?
status_host = 'http://127.0.0.1:8545'
# XXX: Hardcoded
privatekey = "0x633f01b2b607d4e777db626d876d04613decb5145ec7faeae3e57bf8f008c994"
connect = Web3(HTTPProvider(status_host))
print('connect status ===> ', connect.isConnected())
ms = shh.Shh(connect)
print('info ===>>>> ', ms.info)
id = ms.addPrivateKey(key=privatekey)
print('id ===>>>> ', id)
user_address = ms.getPublicKey(id)
print('user_address ===>>> ', user_address)
privkey = ms.getPrivateKey(id)
print("privkey => ", privkey)
# XXX
#topic = Web3.toHex(b'AAAA')
topic = '0x00000000'
print("topic => ", topic)
text = 'test message'
# XXX
#address_to = '0x0487be55c072702a0e4da72158a7432281e8c26aca9501cd0bfeea726dc85f2611e96884e8fc4807c95c04c04af3387b83350a27cc18b96c37543e0f9a41ae47b5'
# Copy pasted
address_to = '0x04bbfb9fbe8239c2fb1895511f306d731c283ba3070d8642d4fbb4da1e4923454b8de6d82b671a4787c8e24d2cf2cf947d6da5ff6d12bf7147d1c0c5d2acbaf8ba'
# nice works
# address too is who?
mes_send = ms.post(
{
'ttl': 20,
'payload': Web3.toHex(text=text),
'pubKey': address_to,
'topic': topic,
'powTarget': 2.5,
'powTime': 2,
}
)
# How check status?
print(mes_send)