def test_feed_collection_single_gap(self): feed = pss.Feed(self.agent, self.accounts[0], "one", True) tim = pss.now_int() timebytes = struct.pack(">I", tim) bogushsh = "" for i in range(32): bogushsh += "01" lasthsh = bogushsh.decode("hex") addr = feed.account.address acc = pss.Account() acc.set_address(addr) outfeed = pss.Feed(self.agent, acc, "one", True) print "set addr " + str(i) + " " + addr.encode("hex") for j in range(3): hsh = self.bzz.add(lasthsh + timebytes + chr(j) + hex((i*3)+j)) lasthsh = hsh.decode("hex") feed.update(hsh) self.coll.add("foo", outfeed) # \todo this is not theoretically safe on a busy node, as things may change between, but in controlled test should be ok headhsh = feed.head() ridx = self.coll.gethead(self.bzz) self.coll.retrievals.pop(ridx) #ridx = self.coll.gethead(self.bzz) #msgs = self.coll.retrievals.pop(ridx) try: self.assertEqual(self.coll.feeds['foo']['orphans'][headhsh.decode("hex")], bogushsh.decode("hex")) except Exception as e: self.fail("dict key in test assert fail: " + str(e))
def test_feed_collection_sort(self): for i in range(2): self.feeds.append(pss.Feed(self.agent, self.accounts[i], "one", True)) tim = pss.now_int() timebytes = struct.pack(">I", tim) outfeeds = [] for i in range(len(self.feeds)): lasthsh = zerohsh.decode("hex") addr = self.feeds[i].account.address acc = pss.Account() acc.set_address(addr) outfeeds.append(pss.Feed(self.agent, acc, "one", True)) print "set addr " + str(i) + " " + addr.encode("hex") for j in range(3): hsh = self.bzz.add(lasthsh + timebytes + chr(j) + hex((i*3)+j)) lasthsh = hsh.decode("hex") self.feeds[i].update(hsh) self.coll.add("foo", outfeeds[0]) self.coll.add("bar", outfeeds[1]) self.coll.gethead(self.bzz) msgs = self.coll.get() # \todo more elegance, please if msgs[0].content == "0x0": self.assertEqual(msgs[1].content, "0x3") self.assertEqual(msgs[2].content, "0x1") self.assertEqual(msgs[3].content, "0x4") if msgs[0].content == "0x3": self.assertEqual(msgs[1].content, "0x0") self.assertEqual(msgs[2].content, "0x4") self.assertEqual(msgs[3].content, "0x1")
def test_feed_collection_single_gap(self): feed = pss.Feed(self.bzz, self.accounts[0], "one") tim = pss.now_int() timebytes = struct.pack(">I", tim) # create a (most probably) non-existent hash # this will constitute a dead end on retrieval bogushsh = "" for i in range(32): bogushsh += "01" lasthsh = bogushsh.decode("hex") # set up similar as previous collection tests, but only one feed addr = feed.account.get_address() acc = pss.Account() acc.set_address(addr) outfeed = pss.Feed(self.bzz, acc, "one") for j in range(3): hsh = self.bzz.add(lasthsh + timebytes + chr(j) + hex(j)) hshbytes = hsh.decode("hex") lasthsh = hshbytes feed.update(hshbytes) self.coll.add("foo", outfeed) # retrieve the updates in the collection # we also retrieve the hash of the latest update # as this is the key for the resulting dead end entry # \todo this is not theoretically safe on a busy node, as things may change between, but in controlled test should be ok headhsh = feed.head() (ridx, fails) = self.coll.gethead(self.bzz) self.assertEqual(len(fails), 0) upd = self.coll.retrievals.pop(ridx) try: self.assertEqual(self.coll.feeds['foo'].orphans[headhsh], bogushsh.decode("hex")) except Exception as e: self.fail("dict key in test assert fail: " + str(e)) # check that we still got all the updates that we could k = self.coll.feeds['foo'].obj.account.get_address() msgs = upd[k] self.assertEqual(msgs[timebytes + "\x00"].content, "0x0") self.assertEqual(msgs[timebytes + "\x01"].content, "0x1") self.assertEqual(msgs[timebytes + "\x02"].content, "0x2")
def test_single_feed(self): self.feeds.append(pss.Feed(self.bzz, self.accounts[0], "one")) hshfirst = self.bzz.add(zerohsh + "inky") self.feeds[0].update(hshfirst) hshsecond = self.bzz.add(hshfirst.decode("hex") + "pinky") self.feeds[0].update(hshsecond) hshthird = self.bzz.add(hshsecond.decode("hex") + "blinky") self.feeds[0].update(hshthird) r = self.feeds[0].head() self.assertEqual(r, hshthird) r = self.bzz.get(hshthird) self.assertEqual(r[:32], hshsecond.decode("hex")) self.assertEqual(r[32:], "blinky") r = self.bzz.get(r[:32].encode("hex")) self.assertEqual(r[:32], hshfirst.decode("hex")) self.assertEqual(r[32:], "pinky") r = self.bzz.get(r[:32].encode("hex")) self.assertEqual(r[:32], zerohsh) self.assertEqual(r[32:], "inky")
def test_single_feed(self): global zerohsh self.feeds.append(pss.Feed(self.agent, self.accounts[0], "one", True)) hshfirst = self.bzz.add(zerohsh + "inky") self.feeds[0].update(hshfirst) hshsecond = self.bzz.add(hshfirst + "pinky") self.feeds[0].update(hshsecond) hshthird = self.bzz.add(hshsecond + "blinky") self.feeds[0].update(hshthird) r = self.feeds[0].head() self.assertEqual(r, hshthird) r = self.bzz.get(hshthird) self.assertEqual(r[:64], hshsecond) self.assertEqual(r[64:], "blinky") r = self.bzz.get(r[:64]) print r self.assertEqual(r[:64], hshfirst) self.assertEqual(r[64:], "pinky") r = self.bzz.get(r[:64]) print r self.assertEqual(r[:64], zerohsh) self.assertEqual(r[64:], "inky")
def test_feed_collection_sort(self): # same setup as previous test for i in range(2): self.feeds.append(pss.Feed(self.bzz, self.accounts[i], "one")) tim = pss.now_int() timebytes = struct.pack(">I", tim) outfeeds = [] for i in range(len(self.feeds)): lasthsh = zerohsh addr = self.feeds[i].account.get_address() acc = pss.Account() acc.set_address(addr) outfeeds.append(pss.Feed(self.bzz, acc, "one")) for j in range(3): hsh = self.bzz.add(lasthsh + timebytes + chr(j) + hex((i * 3) + j)) byteshsh = hsh.decode("hex") lasthsh = byteshsh self.feeds[i].update(byteshsh) self.coll.add("foo", outfeeds[0]) self.coll.add("bar", outfeeds[1]) (_, fails) = self.coll.gethead(self.bzz) self.assertEqual(len(fails), 0) msgs = self.coll.get() # depending on which feed comes first alphabetically # the messages should be ordered first by address # then by time+serial if msgs[0].content == "0x0": self.assertEqual(msgs[1].content, "0x3") self.assertEqual(msgs[2].content, "0x1") self.assertEqual(msgs[3].content, "0x4") self.assertEqual(msgs[4].content, "0x2") self.assertEqual(msgs[5].content, "0x5") if msgs[0].content == "0x3": self.assertEqual(msgs[1].content, "0x0") self.assertEqual(msgs[2].content, "0x4") self.assertEqual(msgs[3].content, "0x1") self.assertEqual(msgs[4].content, "0x5") self.assertEqual(msgs[5].content, "0x2")
def test_feed_room(self): nicks = [self.accounts[0].address.encode("hex")] r = pss.Room(self.bzz, "abc", self.accounts[0]) r.start("foo") for i in range(1, len(self.accounts)): addrhx = self.accounts[i].address.encode("hex") nicks.append(str(i)) pubkeyhx = "04"+self.accounts[i].publickeybytes.encode("hex") p = Participant(nicks[i], pubkeyhx, addrhx, "04"+pubkey) r.add(nicks[i], p) # get the serialized representation of room serializedroom = r.serialize() # save the room savedhsh = r.save() # retrieve the pubkey from the saved room format # and create account with retrieved public key # \todo more intuitive feed injection on load unserializedroom = json.loads(serializedroom) acc = pss.Account() cleanpub = clean_pubkey(unserializedroom['pubkey']) acc.set_public_key(cleanpub.decode("hex")) return # create feed with account from newly (re)created account recreatedownerfeed = pss.Feed(self.agent, acc, unserializedroom['name'], False) # instantiate room with feed recreated from saved state rr = pss.Room(self.bzz, recreatedownerfeed) rr.load(r.hsh, self.accounts[0]) # check that for all"cleanpub: " + in-feeds (read peer's updates) the feed user field is the address of the peer matchesleft = len(self.accounts) for f in rr.feedcollection_in.feeds.values(): matched = False for a in self.accounts: if f['obj'].account.address == a.address: matched = True matchesleft -= 1 if not matched: print "key '" + f['obj'].account.publickeybytes.encode("hex") + "'" self.fail("found unknown address " + f['obj'].account.address.encode("hex")) if matchesleft != 0: self.fail("have " + str(matchesleft) + " unmatched addresses") # for the outfeed, check that we are owner self.assertTrue(rr.feed_out.account.is_owner())
def test_feed_collection_ok(self): for i in range(2): self.feeds.append(pss.Feed(self.agent, self.accounts[i], "one", True)) tim = pss.now_int() timebytes = struct.pack(">I", tim) outfeeds = [] for i in range(len(self.feeds)): lasthsh = zerohsh.decode("hex") addr = self.feeds[i].account.address acc = pss.Account() acc.set_address(addr) outfeeds.append(pss.Feed(self.agent, acc, "one", True)) print "set addr " + str(i) + " " + addr.encode("hex") for j in range(3): hsh = self.bzz.add(lasthsh + timebytes + chr(j) + hex((i*3)+j)) lasthsh = hsh.decode("hex") self.feeds[i].update(hsh) self.coll.add("foo", outfeeds[0]) self.coll.add("bar", outfeeds[1]) ridx = self.coll.gethead(self.bzz) msgs = self.coll.retrievals.pop(ridx) i = 0 for n in ["foo", "bar"]: k = self.coll.feeds[n]['obj'].account.address print "getting addr " + k.encode("hex") v = msgs[k] timebyteshx = timebytes.encode("hex") self.assertEqual(v[timebytes + "\x00"].content, "0x" + str(i*3)) self.assertEqual(v[timebytes + "\x00"].user, k) self.assertEqual(v[timebytes + "\x01"].content, "0x" + str((i*3)+1)) self.assertEqual(v[timebytes + "\x01"].user, k) self.assertEqual(v[timebytes + "\x02"].content, "0x" + str((i*3)+2)) self.assertEqual(v[timebytes + "\x02"].user, k) i += 1
def sock_connect(pssName, status, tlsrc, sock, error, ip): if status != weechat.WEECHAT_HOOK_CONNECT_OK: wOut(PSS_BUFPFX_ERROR, [], "???", "swarm gateway connect failed (" + str(status) + "): " + error) return weechat.WEECHAT_RC_ERROR wOut(PSS_BUFPFX_INFO, [], "!!!", "swarm gateway connected on " + pssName + ", sock " + repr(sock)) agent = pss.Agent(psses[pssName].host, 8500, sock) bzzs[pssName] = pss.Bzz(agent) # provided the connection went ok # add all nicks in the plugin's memory nick map # that match the pubkey of the node to the node's recipient address book # \todo use execption instead of if/else/error # \todo adding the nicks from a node should be separate proedure, and maybe even split up for feeds and pss for c in nicks: if nicks[c].src == psses[pssName].key: if psses[pssName].add(nicks[c].nick, nicks[c].key, nicks[c].address): wOut( PSS_BUFPFX_INFO, [bufs[pssName]], "+++", "added '" + nicks[c].nick + "' to node '" + pssName + "' (key: " + pss.label(psses[pssName].key) + ", addr: " + pss.label(psses[pssName].base) + ")") # \ todo make this call more legible (public key to bytes method in pss pkg) try: feeds[buf_generate_name( pssName, "chat", nicks[c].nick)] = pss.Feed( bzzs[pssName].agent, psses[pssName].get_account(), PSS_BUFTYPE_CHAT + pss.publickey_to_account( psses[pssName].key[2:].decode("hex"))) except: wOut(PSS_BUFPFX_DEBUG, [bufs[pssName]], "", "bzz gateway for not active") else: wOut( PSS_BUFPFX_DEBUG, [bufs[pssName]], "", "nick " + c + " not added: " + psses[pssName].error()['description']) return weechat.WEECHAT_RC_OK
def test_feed_collection_ok(self): for i in range(2): self.feeds.append(pss.Feed(self.bzz, self.accounts[i], "one")) tim = pss.now_int() timebytes = struct.pack(">I", tim) # holds feeds to read from outfeeds = [] for i in range(len(self.feeds)): # first hash in linked list is zerohash lasthsh = zerohsh # create new feed with address only (no private key) for read addr = self.feeds[i].account.get_address() acc = pss.Account() acc.set_address(addr) outfeeds.append(pss.Feed(self.bzz, acc, "one")) #print "set addr " + str(i) + " " + addr.encode("hex") # create 3 updates # an update is # * previous hash (zerohash if first update) # * time of update # * sequence of update within timestamp (one byte) # * data (in this case incrementing counter in hex) for j in range(3): hsh = self.bzz.add(lasthsh + timebytes + chr(j) + hex((i * 3) + j)) hshbytes = hsh.decode("hex") lasthsh = hshbytes self.feeds[i].update(hshbytes) # put the read feeds into the collection self.coll.add("foo", outfeeds[0]) self.coll.add("bar", outfeeds[1]) # get the latest updates using the collection # it iterates all feeds, gets the latest update # and follows the linked hashes to retrieve all content (ridx, fails) = self.coll.gethead(self.bzz) self.assertEqual(len(fails), 0) # one element in retrievals array contains all updates # retrieved in one "gethead" call msgs = self.coll.retrievals.pop(ridx) # compare the results i = 0 for n in ["foo", "bar"]: k = self.coll.feeds[n].obj.account.get_address() # feed updates are indexed on user address, then time and index v = msgs[k] self.assertEqual(v[timebytes + "\x00"].content, "0x" + str(i * 3)) self.assertEqual(v[timebytes + "\x00"].user, k) self.assertEqual(v[timebytes + "\x01"].content, "0x" + str((i * 3) + 1)) self.assertEqual(v[timebytes + "\x01"].user, k) self.assertEqual(v[timebytes + "\x02"].content, "0x" + str((i * 3) + 2)) self.assertEqual(v[timebytes + "\x02"].user, k) i += 1
def buf_get(pssName, typ, name, known): haveBzz = False # \todo integrity check of input data bufname = buf_generate_name(pssName, typ, name) wOut( PSS_BUFPFX_DEBUG, [], "!!!", "generated bufname " + bufname + " for " + pssName + " / " + typ + " / " + name) try: buf = weechat.buffer_search("python", bufname) # \todo re-evaluate why exception can occur here, and which one specifically except Exception as e: return "" if pssName in bzzs: haveBzz = True elif typ == "room": raise RuntimeException("gateway needed for multiuser chats over swarm") if buf == "": shortname = "" # chat is DM between two parties if typ == "chat": ispubkey = False if known: shortname = "pss:" + name else: shortname = "pss:" + name[:8] ispubkey = True buf = weechat.buffer_new(bufname, "buf_in", pssName, "buf_close", pssName) weechat.buffer_set(buf, "short_name", shortname) weechat.buffer_set( buf, "title", name + " @ PSS '" + pssName + "' | node: " + weechat.config_get_plugin(psses[pssName].host + "_url") + ":" + weechat.config_get_plugin(psses[pssName].port + "_port") + " | key " + pss.label(psses[pssName].key) + " | address " + pss.label(psses[pssName].base)) weechat.buffer_set(buf, "hotlist", weechat.WEECHAT_HOTLIST_PRIVATE) weechat.buffer_set(buf, "display", "1") plugin = weechat.buffer_get_pointer(buf, "plugin") bufs[bufname] = buf debugstr = "have " + repr( psses[pssName].have_account()) + " + " + repr(haveBzz) wOut(PSS_BUFPFX_DEBUG, [], "have", debugstr) if psses[pssName].have_account() and haveBzz: pubkey = "" if ispubkey: pubkey = name.decode("hex") else: pubkey = remotekeys[name].decode("hex") pubkey = "\x04" + pubkey try: feeds[bufname] = pss.Feed( bzzs[pssName].agent, psses[pssName].get_account(), PSS_BUFTYPE_CHAT + pss.publickey_to_account(pubkey)) wOut( PSS_BUFPFX_DEBUG, [], "", "added feed with topic " + feeds[bufname].topic.encode("hex")) except ValueError as e: wOut(PSS_BUFPFX_ERROR, [], "???", "could not set up feed: " + str(e)) # room is multiuser conversation elif typ == "room": shortname = "pss#" + name buf = weechat.buffer_new(bufname, "buf_in", pssName, "buf_close", pssName) weechat.buffer_set(buf, "short_name", shortname) weechat.buffer_set( buf, "title", "#" + name + " @ PSS '" + pssName + "' | node: " + weechat.config_get_plugin(psses[pssName].host + "_url") + ":" + weechat.config_get_plugin(psses[pssName].port + "_port") + " | key " + pss.label(psses[pssName].key) + " | address " + pss.label(psses[pssName].base)) weechat.buffer_set(buf, "hotlist", weechat.WEECHAT_HOTLIST_PRIVATE) weechat.buffer_set(buf, "nicklist", "1") weechat.buffer_set(buf, "display", "1") #weechat.nicklist_add_group(buf, "", "me", "weechat.color.nicklist_group", 1) #weechat.nicklist_add_nick(buf, "me", psses[pssName].name, "bar_fg", "", "bar_fg", 1) plugin = weechat.buffer_get_pointer(buf, "plugin") bufs[bufname] = buf if len(rooms) == 0: hookTimers.append( weechat.hook_timer(roomPeriod, 0, 0, "roomRead", psses[pssName].name)) rooms[bufname] = pss.Room(bzzs[pssName], name, psses[pssName].get_account()) # \todo test load first, only init if not found try: roomhsh = rooms[bufname].get_state_hash() rooms[bufname].load(roomhsh, psses[pssName].get_account()) wOut( PSS_BUFPFX_DEBUG, [], "", "loaded room with topic " + rooms[bufname].feed_out.topic.encode("hex") + " account " + rooms[bufname].feed_out.account.address.encode("hex") + " roomfeed " + rooms[bufname].feed_room.topic.encode("hex")) for k, p in rooms[bufname].participants.iteritems(): nick = "" if p.key == selfs[pssName].key: nick = selfs[pssName].nick else: if not p.key in nicks: nicks[p.nick] = pss.PssContact( p.nick, p.key, p.addr, p.src) remotekeys[p.key] = p.nick nick = nicks[p.key].nick buf_room_add(buf, nick) # \todo correct expect to disambiguate unexpected fails except Exception as e: wOut(PSS_BUFPFX_DEBUG, [], "", "fail room load: " + str(e)) rooms[bufname].start(PSS_DEFAULT_NICK) wOut( PSS_BUFPFX_DEBUG, [], "", "added room with topic " + rooms[bufname].feed_out.topic.encode("hex") + " account " + rooms[bufname].feed_out.account.address.encode("hex") + " roomfeed " + rooms[bufname].feed_room.topic.encode("hex")) else: raise RuntimeError("invalid buffer type") return buf