Gun: Networked NACK on deep put

Created on 15 Jan 2019  路  17Comments  路  Source: amark/gun

First noticed: 0.9.999993
Observed behavior: Missing acknowledgement in the NodeJS console and missing data

Behavior in 0.9.999997: Missing data without warning of any kind.

When I put data on a path which is not known to the super peer, data is not saved over the network. To showcase the issue, I've created some stand-alone code which reproduces the unexpected behavior: finwo/gun-issues/687.

In short, this is broken:

// client.js
// The server simply runs Gun.serve on a bare http server

const Gun = require('gun');
const gun = Gun( 'ws://localhost');

gun.get('user').get('admin').put({
  username: 'admin'
});

All 17 comments

@finwo thanks for investigating issues!

I just want to double check something tho:

Gun( 'ws://localhost:port/gun')

I think you have to add the port and /gun, if you do that does it fix anything?

Even if not, you are right, some sort of peer error failure would be good indication something is still wrong. Thanks!

Just checked: neither ws://localhost:1332 nor ws://localhost:1332/gun works.

For reference, copied Mark's message from gitter

The path of messages related to this issue:

  1. wire message heard at https://github.com/amark/gun/blob/master/src/adapters/mesh.js#L33
  2. emit in to middleware adapters a few lines down at https://github.com/amark/gun/blob/master/src/adapters/mesh.js#L61
  3. Eventually that makes it way to GUN core event loop https://github.com/amark/gun/blob/master/gun.js#L698
  4. Gun.on.put processes/verifies the graph and applies HAM (conflict resolution) and eventually the diff is emit on put https://github.com/amark/gun/blob/master/gun.js#L739
  5. Middleware adapters handle it, one of which is the now default lib/store which uses RAD https://github.com/amark/gun/blob/master/lib/store.js#L18
  6. Iterates over it and saves it as a radisk https://github.com/amark/gun/blob/master/lib/radisk.js#L36 which batches/thrashes it and
  7. performs the radix fractal split algorithm https://github.com/amark/gun/blob/master/lib/radisk.js#L87

According to that path, I should see a message containing put when I place a console.log before https://github.com/amark/gun/blob/master/gun.js#L711

Just did that & the only put I see is the following message:

{ '@': 'ltSvjhoWI',
  put: undefined,
  err: undefined,
  rad: { [Function: Radix] map: [Function: map] },
  '#': 'M8Elauy1d' }

At the request of @bugs181, here's the first captured output of the run including some extra logs within gun: https://github.com/finwo/gun-issues/blob/master/687/output-00.log

In this output, the client tries to connect to ws://localhost:1332/gun

Another run was made, monitoring the mesh.hear function. https://github.com/finwo/gun-issues/blob/master/687/output-01.log

The peers do seem to be connected to eachother. Changing ws://localhost:1332/gun to ws://localhost:1332 prevents mesh.hear from being called.

Using more-and-more console.log within gun. Here's some findings in order:

  • mesh.hear never received the put
  • websocket.onmessage never received the put
  • the above 2 indicate the client never sends the put over the network
  • Gun.chain.put generates the root graph (as.soul || root === gun)
  • the data is deemed an object by obj_is
  • the root graph put contains a soul (no further recursion)
  • ify is called (within Gun.chain.put)
  • New graph data is actually generated (logged within ify)

I'm now looking at the batch function

It looks like ify stops because obj_map( as.stun, no ) returns true, which results in the batch not being sent.

obj_map is a link to Type.obj.map, which can be read here: https://github.com/amark/gun/blob/master/src/type.js#L105

Now trying to figure out what that function actually does.

Type.obj.map works like it's supposed to. The stun it receives contains { admin: true } instead of { admin: false }. This stun is generated inside ify by Gun.graph.ify.

Continuing down the rabbit hole.

CHANGED BEHAVIOR IN 0.9.999998

Now, an actual 'invalid graph' error is being thrown, in both the expected & unexpected behavior examples

Just checked on my laptop again. the latest version produces the same behavior as the one yesterday.

A.k.a. the original issue is still the current behavior.

Sad news.. I focused on the graph being incomplete, but the generated graph for the expected & unexpected behavior are the same..

Still searching where the as.stun is actually generated.

Looking at map (gun.js:1470) inside the put file, it tries to fetch the object to place everything on first (gun.js:1487), using the stun variable to indicate if it is still fetching.

Because user does not exist yet on the super peer, the path is never marked as loaded by solve because soul is never called by the chain.get( fn, true, as )

Just added code to test the issue in the browser as well.

The browser test can be run by just running the server (cd /path/to/repo/687 ; node server.js) & the browsing to http://localhost:1332

I just ran a test where I replaced line 1445 as follows:

-  if (!as.graph || obj_map(as.stun, no)){ return }
+  if (!as.graph) { return; }

This test ran the expected behavior when tested locally, I'll try to simulate network latency now.

Emulated a slow network in both firefox & chrome with the browser-based example.

Both are fully functional with line 1445 replaced!!

Awesome. Thanks for investigating @finwo! Really helpful.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nolotus picture nolotus  路  3Comments

linonetwo picture linonetwo  路  4Comments

bugs181 picture bugs181  路  3Comments

danfinlay picture danfinlay  路  3Comments

terrybleger picture terrybleger  路  5Comments