Skip to content

Commit bc7c158

Browse files
committed
feat: use libp2p component logger
Refactors code to use the component logger from libp2p to allow more flexible logging patterns. Nb. adds a `NoiseComponents` interface separate from `NoiseInit` that contains the `Metrics` instance - this is consistent with every other libp2p module. Refs: https://github.com/libp2p/js-libp2p/issue/2105 Refs: libp2p/js-libp2p#2198 Refs: https://github.com/libp2p/js-libp2p/issue/378
1 parent e4796ed commit bc7c158

File tree

17 files changed

+126
-104
lines changed

17 files changed

+126
-104
lines changed

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,9 @@
6969
"dependencies": {
7070
"@chainsafe/as-chacha20poly1305": "^0.1.0",
7171
"@chainsafe/as-sha256": "^0.4.1",
72-
"@libp2p/crypto": "next",
73-
"@libp2p/interface": "next",
74-
"@libp2p/logger": "next",
75-
"@libp2p/peer-id": "next",
72+
"@libp2p/crypto": "^3.0.0",
73+
"@libp2p/interface": "^1.0.0",
74+
"@libp2p/peer-id": "^4.0.0",
7675
"@noble/ciphers": "^0.4.0",
7776
"@noble/curves": "^1.1.0",
7877
"@noble/hashes": "^1.3.1",
@@ -88,13 +87,14 @@
8887
"wherearewe": "^2.0.1"
8988
},
9089
"devDependencies": {
91-
"@chainsafe/libp2p-yamux": "^5.0.0",
90+
"@chainsafe/libp2p-yamux": "^6.0.0",
9291
"@libp2p/daemon-client": "^7.0.0",
9392
"@libp2p/daemon-server": "^6.0.0",
94-
"@libp2p/interface-compliance-tests": "next",
93+
"@libp2p/interface-compliance-tests": "^5.0.0",
9594
"@libp2p/interop": "^9.0.0",
96-
"@libp2p/peer-id-factory": "next",
97-
"@libp2p/tcp": "8.0.13-4a474d54d",
95+
"@libp2p/logger": "^4.0.0",
96+
"@libp2p/peer-id-factory": "^3.0.9",
97+
"@libp2p/tcp": "^9.0.0",
9898
"@multiformats/multiaddr": "^12.1.0",
9999
"@types/sinon": "^17.0.1",
100100
"aegir": "^40.0.8",

src/@types/handshake-interface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { NoiseSession } from './handshake.js'
22
import type { NoiseExtensions } from '../proto/payload.js'
3-
import type { PeerId } from '@libp2p/interface/peer-id'
3+
import type { PeerId } from '@libp2p/interface'
44
import type { Uint8ArrayList } from 'uint8arraylist'
55

66
export interface IHandshake {

src/@types/libp2p.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { bytes32 } from './basic.js'
22
import type { NoiseExtensions } from '../proto/payload.js'
3-
import type { ConnectionEncrypter } from '@libp2p/interface/connection-encrypter'
3+
import type { ConnectionEncrypter } from '@libp2p/interface'
44

55
export interface KeyPair {
66
publicKey: bytes32

src/errors.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export class UnexpectedPeerError extends Error {
2+
public code: string
3+
4+
constructor (message = 'Unexpected Peer') {
5+
super(message)
6+
this.code = UnexpectedPeerError.code
7+
}
8+
9+
static readonly code = 'ERR_UNEXPECTED_PEER'
10+
}
11+
12+
export class InvalidCryptoExchangeError extends Error {
13+
public code: string
14+
15+
constructor (message = 'Invalid crypto exchange') {
16+
super(message)
17+
this.code = InvalidCryptoExchangeError.code
18+
}
19+
20+
static readonly code = 'ERR_INVALID_CRYPTO_EXCHANGE'
21+
}

src/handshake-xx.ts

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import { InvalidCryptoExchangeError, UnexpectedPeerError } from '@libp2p/interface/errors'
21
import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc'
32
import { decode0, decode1, decode2, encode0, encode1, encode2 } from './encoder.js'
3+
import { InvalidCryptoExchangeError, UnexpectedPeerError } from './errors.js'
44
import { XX } from './handshakes/xx.js'
55
import {
6-
logger,
76
logLocalStaticKeys,
87
logLocalEphemeralKeys,
98
logRemoteEphemeralKey,
@@ -20,8 +19,9 @@ import type { IHandshake } from './@types/handshake-interface.js'
2019
import type { CipherState, NoiseSession } from './@types/handshake.js'
2120
import type { KeyPair } from './@types/libp2p.js'
2221
import type { ICryptoInterface } from './crypto.js'
22+
import type { NoiseComponents } from './index.js'
2323
import type { NoiseExtensions } from './proto/payload.js'
24-
import type { PeerId } from '@libp2p/interface/peer-id'
24+
import type { Logger, PeerId } from '@libp2p/interface'
2525
import type { LengthPrefixedStream } from 'it-length-prefixed-stream'
2626
import type { Uint8ArrayList } from 'uint8arraylist'
2727

@@ -37,8 +37,10 @@ export class XXHandshake implements IHandshake {
3737
protected staticKeypair: KeyPair
3838

3939
private readonly prologue: bytes32
40+
private readonly log: Logger
4041

4142
constructor (
43+
components: NoiseComponents,
4244
isInitiator: boolean,
4345
payload: bytes,
4446
prologue: bytes32,
@@ -48,6 +50,7 @@ export class XXHandshake implements IHandshake {
4850
remotePeer?: PeerId,
4951
handshake?: XX
5052
) {
53+
this.log = components.logger.forComponent('libp2p:noise:xxhandshake')
5154
this.isInitiator = isInitiator
5255
this.payload = payload
5356
this.prologue = prologue
@@ -56,45 +59,45 @@ export class XXHandshake implements IHandshake {
5659
if (remotePeer) {
5760
this.remotePeer = remotePeer
5861
}
59-
this.xx = handshake ?? new XX(crypto)
62+
this.xx = handshake ?? new XX(components, crypto)
6063
this.session = this.xx.initSession(this.isInitiator, this.prologue, this.staticKeypair)
6164
}
6265

6366
// stage 0
6467
public async propose (): Promise<void> {
65-
logLocalStaticKeys(this.session.hs.s)
68+
logLocalStaticKeys(this.session.hs.s, this.log)
6669
if (this.isInitiator) {
67-
logger.trace('Stage 0 - Initiator starting to send first message.')
70+
this.log.trace('Stage 0 - Initiator starting to send first message.')
6871
const messageBuffer = this.xx.sendMessage(this.session, uint8ArrayAlloc(0))
6972
await this.connection.write(encode0(messageBuffer))
70-
logger.trace('Stage 0 - Initiator finished sending first message.')
71-
logLocalEphemeralKeys(this.session.hs.e)
73+
this.log.trace('Stage 0 - Initiator finished sending first message.')
74+
logLocalEphemeralKeys(this.session.hs.e, this.log)
7275
} else {
73-
logger.trace('Stage 0 - Responder waiting to receive first message...')
76+
this.log.trace('Stage 0 - Responder waiting to receive first message...')
7477
const receivedMessageBuffer = decode0((await this.connection.read()).subarray())
7578
const { valid } = this.xx.recvMessage(this.session, receivedMessageBuffer)
7679
if (!valid) {
7780
throw new InvalidCryptoExchangeError('xx handshake stage 0 validation fail')
7881
}
79-
logger.trace('Stage 0 - Responder received first message.')
80-
logRemoteEphemeralKey(this.session.hs.re)
82+
this.log.trace('Stage 0 - Responder received first message.')
83+
logRemoteEphemeralKey(this.session.hs.re, this.log)
8184
}
8285
}
8386

8487
// stage 1
8588
public async exchange (): Promise<void> {
8689
if (this.isInitiator) {
87-
logger.trace('Stage 1 - Initiator waiting to receive first message from responder...')
90+
this.log.trace('Stage 1 - Initiator waiting to receive first message from responder...')
8891
const receivedMessageBuffer = decode1((await this.connection.read()).subarray())
8992
const { plaintext, valid } = this.xx.recvMessage(this.session, receivedMessageBuffer)
9093
if (!valid) {
9194
throw new InvalidCryptoExchangeError('xx handshake stage 1 validation fail')
9295
}
93-
logger.trace('Stage 1 - Initiator received the message.')
94-
logRemoteEphemeralKey(this.session.hs.re)
95-
logRemoteStaticKey(this.session.hs.rs)
96+
this.log.trace('Stage 1 - Initiator received the message.')
97+
logRemoteEphemeralKey(this.session.hs.re, this.log)
98+
logRemoteStaticKey(this.session.hs.rs, this.log)
9699

97-
logger.trace("Initiator going to check remote's signature...")
100+
this.log.trace("Initiator going to check remote's signature...")
98101
try {
99102
const decodedPayload = decodePayload(plaintext)
100103
this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload)
@@ -104,31 +107,31 @@ export class XXHandshake implements IHandshake {
104107
const err = e as Error
105108
throw new UnexpectedPeerError(`Error occurred while verifying signed payload: ${err.message}`)
106109
}
107-
logger.trace('All good with the signature!')
110+
this.log.trace('All good with the signature!')
108111
} else {
109-
logger.trace('Stage 1 - Responder sending out first message with signed payload and static key.')
112+
this.log.trace('Stage 1 - Responder sending out first message with signed payload and static key.')
110113
const messageBuffer = this.xx.sendMessage(this.session, this.payload)
111114
await this.connection.write(encode1(messageBuffer))
112-
logger.trace('Stage 1 - Responder sent the second handshake message with signed payload.')
113-
logLocalEphemeralKeys(this.session.hs.e)
115+
this.log.trace('Stage 1 - Responder sent the second handshake message with signed payload.')
116+
logLocalEphemeralKeys(this.session.hs.e, this.log)
114117
}
115118
}
116119

117120
// stage 2
118121
public async finish (): Promise<void> {
119122
if (this.isInitiator) {
120-
logger.trace('Stage 2 - Initiator sending third handshake message.')
123+
this.log.trace('Stage 2 - Initiator sending third handshake message.')
121124
const messageBuffer = this.xx.sendMessage(this.session, this.payload)
122125
await this.connection.write(encode2(messageBuffer))
123-
logger.trace('Stage 2 - Initiator sent message with signed payload.')
126+
this.log.trace('Stage 2 - Initiator sent message with signed payload.')
124127
} else {
125-
logger.trace('Stage 2 - Responder waiting for third handshake message...')
128+
this.log.trace('Stage 2 - Responder waiting for third handshake message...')
126129
const receivedMessageBuffer = decode2((await this.connection.read()).subarray())
127130
const { plaintext, valid } = this.xx.recvMessage(this.session, receivedMessageBuffer)
128131
if (!valid) {
129132
throw new InvalidCryptoExchangeError('xx handshake stage 2 validation fail')
130133
}
131-
logger.trace('Stage 2 - Responder received the message, finished handshake.')
134+
this.log.trace('Stage 2 - Responder received the message, finished handshake.')
132135

133136
try {
134137
const decodedPayload = decodePayload(plaintext)
@@ -140,7 +143,7 @@ export class XXHandshake implements IHandshake {
140143
throw new UnexpectedPeerError(`Error occurred while verifying signed payload: ${err.message}`)
141144
}
142145
}
143-
logCipherState(this.session)
146+
logCipherState(this.session, this.log)
144147
}
145148

146149
public encrypt (plaintext: Uint8Array | Uint8ArrayList, session: NoiseSession): Uint8Array | Uint8ArrayList {

src/handshakes/abstract-handshake.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import { Uint8ArrayList } from 'uint8arraylist'
22
import { fromString as uint8ArrayFromString } from 'uint8arrays'
33
import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc'
44
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
5-
import { logger } from '../logger.js'
65
import { Nonce } from '../nonce.js'
76
import type { bytes, bytes32 } from '../@types/basic.js'
87
import type { CipherState, MessageBuffer, SymmetricState } from '../@types/handshake.js'
98
import type { ICryptoInterface } from '../crypto.js'
9+
import type { NoiseComponents } from '../index.js'
10+
import type { Logger } from '@libp2p/interface'
1011

1112
export interface DecryptedResult {
1213
plaintext: Uint8ArrayList | Uint8Array
@@ -20,8 +21,10 @@ export interface SplitState {
2021

2122
export abstract class AbstractHandshake {
2223
public crypto: ICryptoInterface
24+
private readonly log: Logger
2325

24-
constructor (crypto: ICryptoInterface) {
26+
constructor (components: NoiseComponents, crypto: ICryptoInterface) {
27+
this.log = components.logger.forComponent('libp2p:noise:abstract-handshake')
2528
this.crypto = crypto
2629
}
2730

@@ -113,7 +116,7 @@ export abstract class AbstractHandshake {
113116
return derivedU8.subarray(0, 32)
114117
} catch (e) {
115118
const err = e as Error
116-
logger.error(err)
119+
this.log.error('error deriving shared key', err)
117120
return uint8ArrayAlloc(32)
118121
}
119122
}

src/index.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import { Noise } from './noise.js'
22
import type { NoiseInit } from './noise.js'
33
import type { NoiseExtensions } from './proto/payload.js'
4-
import type { ConnectionEncrypter } from '@libp2p/interface/connection-encrypter'
4+
import type { ComponentLogger, ConnectionEncrypter, Metrics } from '@libp2p/interface'
55
export type { ICryptoInterface } from './crypto.js'
66
export { pureJsCrypto } from './crypto/js.js'
77

8-
export function noise (init: NoiseInit = {}): () => ConnectionEncrypter<NoiseExtensions> {
9-
return () => new Noise(init)
8+
export interface NoiseComponents {
9+
logger: ComponentLogger
10+
metrics?: Metrics
11+
}
12+
13+
export function noise (init: NoiseInit = {}): (components: NoiseComponents) => ConnectionEncrypter<NoiseExtensions> {
14+
return (components: NoiseComponents) => new Noise(components, init)
1015
}

src/logger.ts

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,21 @@
1-
import { type Logger, logger } from '@libp2p/logger'
21
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
32
import { DUMP_SESSION_KEYS } from './constants.js'
43
import type { NoiseSession } from './@types/handshake.js'
54
import type { KeyPair } from './@types/libp2p.js'
5+
import type { Logger } from '@libp2p/interface'
66
import type { Uint8ArrayList } from 'uint8arraylist'
77

8-
const log = logger('libp2p:noise')
9-
10-
export { log as logger }
11-
12-
let keyLogger: Logger
13-
if (DUMP_SESSION_KEYS) {
14-
keyLogger = log
15-
} else {
16-
keyLogger = Object.assign(() => { /* do nothing */ }, {
17-
enabled: false,
18-
trace: () => {},
19-
error: () => {}
20-
})
21-
}
22-
23-
export function logLocalStaticKeys (s: KeyPair): void {
24-
if (!keyLogger.enabled) {
8+
export function logLocalStaticKeys (s: KeyPair, keyLogger: Logger): void {
9+
if (!keyLogger.enabled || !DUMP_SESSION_KEYS) {
2510
return
2611
}
2712

2813
keyLogger(`LOCAL_STATIC_PUBLIC_KEY ${uint8ArrayToString(s.publicKey, 'hex')}`)
2914
keyLogger(`LOCAL_STATIC_PRIVATE_KEY ${uint8ArrayToString(s.privateKey, 'hex')}`)
3015
}
3116

32-
export function logLocalEphemeralKeys (e: KeyPair | undefined): void {
33-
if (!keyLogger.enabled) {
17+
export function logLocalEphemeralKeys (e: KeyPair | undefined, keyLogger: Logger): void {
18+
if (!keyLogger.enabled || !DUMP_SESSION_KEYS) {
3419
return
3520
}
3621

@@ -42,24 +27,24 @@ export function logLocalEphemeralKeys (e: KeyPair | undefined): void {
4227
}
4328
}
4429

45-
export function logRemoteStaticKey (rs: Uint8Array | Uint8ArrayList): void {
46-
if (!keyLogger.enabled) {
30+
export function logRemoteStaticKey (rs: Uint8Array | Uint8ArrayList, keyLogger: Logger): void {
31+
if (!keyLogger.enabled || !DUMP_SESSION_KEYS) {
4732
return
4833
}
4934

5035
keyLogger(`REMOTE_STATIC_PUBLIC_KEY ${uint8ArrayToString(rs.subarray(), 'hex')}`)
5136
}
5237

53-
export function logRemoteEphemeralKey (re: Uint8Array | Uint8ArrayList): void {
54-
if (!keyLogger.enabled) {
38+
export function logRemoteEphemeralKey (re: Uint8Array | Uint8ArrayList, keyLogger: Logger): void {
39+
if (!keyLogger.enabled || !DUMP_SESSION_KEYS) {
5540
return
5641
}
5742

5843
keyLogger(`REMOTE_EPHEMERAL_PUBLIC_KEY ${uint8ArrayToString(re.subarray(), 'hex')}`)
5944
}
6045

61-
export function logCipherState (session: NoiseSession): void {
62-
if (!keyLogger.enabled) {
46+
export function logCipherState (session: NoiseSession, keyLogger: Logger): void {
47+
if (!keyLogger.enabled || !DUMP_SESSION_KEYS) {
6348
return
6449
}
6550

src/metrics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Counter, Metrics } from '@libp2p/interface/metrics'
1+
import type { Counter, Metrics } from '@libp2p/interface'
22

33
export type MetricsRegistry = Record<string, Counter>
44

src/noise.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@ import type { bytes } from './@types/basic.js'
1414
import type { IHandshake } from './@types/handshake-interface.js'
1515
import type { INoiseConnection, KeyPair } from './@types/libp2p.js'
1616
import type { ICryptoInterface } from './crypto.js'
17+
import type { NoiseComponents } from './index.js'
1718
import type { NoiseExtensions } from './proto/payload.js'
18-
import type { MultiaddrConnection } from '@libp2p/interface/connection'
19-
import type { SecuredConnection } from '@libp2p/interface/connection-encrypter'
20-
import type { Metrics } from '@libp2p/interface/metrics'
21-
import type { PeerId } from '@libp2p/interface/peer-id'
19+
import type { MultiaddrConnection, SecuredConnection, PeerId } from '@libp2p/interface'
2220
import type { Duplex } from 'it-stream-types'
2321
import type { Uint8ArrayList } from 'uint8arraylist'
2422

@@ -37,7 +35,6 @@ export interface NoiseInit {
3735
extensions?: NoiseExtensions
3836
crypto?: ICryptoInterface
3937
prologueBytes?: Uint8Array
40-
metrics?: Metrics
4138
}
4239

4340
export class Noise implements INoiseConnection {
@@ -48,10 +45,13 @@ export class Noise implements INoiseConnection {
4845
private readonly staticKeys: KeyPair
4946
private readonly extensions?: NoiseExtensions
5047
private readonly metrics?: MetricsRegistry
48+
private readonly components: NoiseComponents
5149

52-
constructor (init: NoiseInit = {}) {
53-
const { staticNoiseKey, extensions, crypto, prologueBytes, metrics } = init
50+
constructor (components: NoiseComponents, init: NoiseInit = {}) {
51+
const { staticNoiseKey, extensions, crypto, prologueBytes } = init
52+
const { metrics } = components
5453

54+
this.components = components
5555
this.crypto = crypto ?? defaultCrypto
5656
this.extensions = extensions
5757
this.metrics = metrics ? registerMetrics(metrics) : undefined
@@ -154,6 +154,7 @@ export class Noise implements INoiseConnection {
154154
): Promise<XXHandshake> {
155155
const { isInitiator, remotePeer, connection } = params
156156
const handshake = new XXHandshake(
157+
this.components,
157158
isInitiator,
158159
payload,
159160
this.prologue,

0 commit comments

Comments
 (0)