-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: typedef generation & type checking #261
Conversation
Thank you for submitting this PR!
Getting other community members to do a review would be great help too on complex PRs (you can ask in the chats/forums). If you are unsure about something, just leave us a comment.
We currently aim to provide initial feedback/triaging within two business days. Please keep an eye on any labelling actions, as these will indicate priorities and status of your contribution. |
@@ -112,7 +123,7 @@ class DecisionEngine { | |||
|
|||
// If there's nothing in the message, bail out | |||
if (msg.empty) { | |||
this._requestQueue.tasksDone(peerId, tasks) | |||
peerId && this._requestQueue.tasksDone(peerId, tasks) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
peerId
is obtained on line 76 via following code:
const { peerId, tasks, pendingSize } = this._requestQueue.popTasks(this._opts.targetMessageSize)
However popTasks
returns an object without peerId
in 2 code paths out of 3. At the same time tasksDone
and messageSent
below do not expect undefined
.
It was not exactly clear what made most sense here, so I just conditioned those calls on peerId
s presence, but it would be good to make sure all this makes sense.
* @returns {boolean} | ||
*/ | ||
isIdle () { | ||
return this._pending.length === 0 && this._active.length === 0 | ||
return this._pending.length === 0 && this._active.size === 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like there was a bug in the code, because _active
is a Set
instance which doesn't have length
property.
_applyOp (op) { | ||
const key = op[0] | ||
const inc = op[1] | ||
|
||
if (typeof inc !== 'number') { | ||
throw new Error('invalid increment number:', inc) | ||
throw new Error(`invalid increment number: ${inc}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seemed like a bug, so I just inlined inc
into error message.
src/types/message/index.js
Outdated
equals (other) { | ||
if (this.full !== other.full || | ||
this.pendingBytes !== other.pendingBytes || | ||
!isMapEqual(this.wantlist, other.wantlist) || | ||
!isMapEqual(this.blocks, other.blocks) || | ||
// @TODO - Is this a bug ? `isMapEqual` only compare maps of blocks and | ||
// wants | ||
// @ts-ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one seems like a bug, but maybe it is not 🙄 So isMapEqual
will compare only that keys match and will compare values if they are either Block
s or BitswapMessageEntry
s (anything that has equals
method on them actually). However blockPresences
contain numbers so two would be equal even if the actual values are different, which doesn't seems like intended behavior.
P.S.: TS not happy mostly because it's told to expect maps of blocks or entries and is passed maps of numbers below.
constructor (selfPeerId, otherPeerId, network) { | ||
this.peerId = otherPeerId | ||
this.network = network | ||
this.refcnt = 1 | ||
|
||
this._entries = [] | ||
this._log = logger(selfPeerId, 'msgqueue', otherPeerId.toB58String().slice(0, 8)) | ||
this._log = logger(selfPeerId, 'msgqueue') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what to do with the last argument here, because logger
seems to take just two. I dropped it to retain the current behavior, but maybe concatenating last two would make more sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make an issue for the all ts-ignore's ?
@hugomrdias I have addressed all of your feedback except:
|
Merging master introduced the problem with libp2p typedefs so temporarily this pull depends on libp2p/js-libp2p-interfaces#73 |
|
@hugomrdias any idea what is going on here ? For some reason |
dunno maybe because some deps arent using aegir ts yet or the eslint config |
package.json
Outdated
"uuid": "^8.0.0" | ||
"uuid": "^8.0.0", | ||
"@types/debug": "^4.1.5", | ||
"typescript": "^4.0.5" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"typescript": "^4.0.5" |
package.json
Outdated
"files": [ | ||
"dist", | ||
"src" | ||
], | ||
"scripts": { | ||
"prepare": "aegir build", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need full build here
"prepare": "aegir build", | |
"prepare": "aegir ts -p check", |
cid, | ||
{ | ||
// TODO: Should this be a timeout options insetad ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vasco-santos do you know if we should be passing timeout
instead of maxTimeout
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be timeout
- the option is passed through to whatever contenting routing modules are configured - these are either libp2p-delegated-content-routing or libp2p-kad-dht and neither of those support a maxTimeout
option, only timeout
.
* @returns {Promise<Connection>} | ||
*/ | ||
async connectTo (peer, options) { // eslint-disable-line require-await | ||
if (!this._running) { | ||
throw new Error('network isn\'t running') | ||
} | ||
|
||
return this.libp2p.dial(peer, options) | ||
// TODO: Figure out inconsistency here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vasco-santos could you please help me out understand what is expected here. Passed peer
here comes from libp2p.contentRouting.findProviders
which contains both peer id and multiaddr, but then libp2p.dial
expects either peerId
or multiaddr
and attempts to turn it back into Provider
.
I do not know all the ins and outs here, but clearly something makes wrong assumptions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libp2p.contentRouting.findProviders
should return only PeerIDs.
The idea is that libp2p manages the actual multiaddrs internally and we don't worry about them at this level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created an issue in libp2p libp2p/js-libp2p#899
equals (other) { | ||
if (this.full !== other.full || | ||
this.pendingBytes !== other.pendingBytes || | ||
!isMapEqual(this.wantlist, other.wantlist) || | ||
!isMapEqual(this.blocks, other.blocks) || | ||
// @TODO - Is this a bug ? | ||
// @ts-expect-error - isMap equals map values to be objects not numbers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hugomrdias This looks like a bug to me, could you please confirm or tell me if I'm not seeing something ?
} else { | ||
this.wantlist.remove(e.cid) | ||
} | ||
} else { | ||
this._log('adding to wl') | ||
// TODO: Figure out the wantType | ||
// @ts-expect-error - requires wantType | ||
this.wantlist.add(e.cid, e.priority) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hugomrdias do you understand why wantType
is omitted here ? Following lines make make me believe it should be provided, but I'm not sure what the value should be in this instance
js-ipfs-bitswap/src/types/wantlist/index.js
Lines 28 to 32 in 681b015
if (entry.wantType === Message.WantType.Have && wantType === Message.WantType.Block) { | |
entry.wantType = wantType | |
} | |
} else { | |
this.set.set(cidStr, new Entry(cid, priority, wantType)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the WantType ends up defaulting to Block
if it's omitted. The Have
/Block
distinction is a later optimisation, I think maybe it just got missed off here when it was implemented.
@@ -72,9 +97,16 @@ class Wantlist { | |||
} | |||
|
|||
sortedEntries () { | |||
// TODO: Figure out if this is an actual bug. | |||
// @ts-expect-error - Property 'key' does not exist on type 'WantListEntry' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@achingbrain do you have an idea what this meant to be, I'm guessing key used to be what cid is today, but I'm not sure. Nor I have a clue how this supposed to be sorted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a bug. I think this is just supposed to be a list of wantlist entries sorted by string CID, rather than insertion order which would be the default - the .key
property access is probably due to misreading the docs on the output of Map.entries()
?
I'm not sure what the value of it being sorted is, other than the output being stable - it's probably better as a set TBH.
Something we should create an issue for and maybe address later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - a few bugs and inconsistencies are well pointed out but we should get this in and address those as follow ups.
Just needs the github URLs removing from deps and it's good to go.
cid, | ||
{ | ||
// TODO: Should this be a timeout options insetad ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be timeout
- the option is passed through to whatever contenting routing modules are configured - these are either libp2p-delegated-content-routing or libp2p-kad-dht and neither of those support a maxTimeout
option, only timeout
.
* @param {Object} options | ||
* @param {AbortSignal} options.abortSignal | ||
* @returns {void} | ||
* @param {Object} [options] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nit and not a blocker but in this PR I see @param {Object}
in some places and @param {object}
in others.
I know it makes no difference functionally, but we should be consistent (and it should really be enforced by our linting rules). I think we're using @param {object}
everywhere else.
* @returns {Promise<Connection>} | ||
*/ | ||
async connectTo (peer, options) { // eslint-disable-line require-await | ||
if (!this._running) { | ||
throw new Error('network isn\'t running') | ||
} | ||
|
||
return this.libp2p.dial(peer, options) | ||
// TODO: Figure out inconsistency here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libp2p.contentRouting.findProviders
should return only PeerIDs.
The idea is that libp2p manages the actual multiaddrs internally and we don't worry about them at this level.
@@ -72,9 +97,16 @@ class Wantlist { | |||
} | |||
|
|||
sortedEntries () { | |||
// TODO: Figure out if this is an actual bug. | |||
// @ts-expect-error - Property 'key' does not exist on type 'WantListEntry' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a bug. I think this is just supposed to be a list of wantlist entries sorted by string CID, rather than insertion order which would be the default - the .key
property access is probably due to misreading the docs on the output of Map.entries()
?
I'm not sure what the value of it being sorted is, other than the output being stable - it's probably better as a set TBH.
Something we should create an issue for and maybe address later.
} else { | ||
this.wantlist.remove(e.cid) | ||
} | ||
} else { | ||
this._log('adding to wl') | ||
// TODO: Figure out the wantType | ||
// @ts-expect-error - requires wantType | ||
this.wantlist.add(e.cid, e.priority) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the WantType ends up defaulting to Block
if it's omitted. The Have
/Block
distinction is a later optimisation, I think maybe it just got missed off here when it was implemented.
Fixes up types so they align here ipfs/js-ipfs-bitswap#261 Co-authored-by: achingbrain <[email protected]>
Created an issue for all the discovered inconsistencies #303 |
This pull request makes following changes:
While making these changes I did discover certain things that are either bugs or I am misunderstanding what is going on there. I'll comment inline.
Please not that this change depends on: