mirror of https://github.com/vacp2p/research.git
commit
6a002476d0
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
||||
]
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
["~#c4",["Hello","text/plain","~:user-message",154938955408101,1549389554080,["^ ","~:chat-id","0x04d94a1a01872b598c7 cdc5aca2358d35eb91cd8a91eaea8da277451bb71d45c0d1eb87a31ea04e32f537e90165c870b3e115a12438c754d507ac75bddd6ecacd5","~:text","Hello"]]]
|
|
@ -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
|
|
@ -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)
|
Loading…
Reference in New Issue