Skip to content

Commit

Permalink
fix: use logging component everywhere (#2228)
Browse files Browse the repository at this point in the history
Refactors all components to accept a `ComponentLogger` that lets us
prefix log lines with peer ids/arbitrary strings, etc.
  • Loading branch information
achingbrain committed Nov 15, 2023
1 parent 1034416 commit e5dfde0
Show file tree
Hide file tree
Showing 187 changed files with 1,819 additions and 1,263 deletions.
2 changes: 1 addition & 1 deletion packages/connection-encrypter-plaintext/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
},
"devDependencies": {
"@libp2p/interface-compliance-tests": "^4.1.5",
"@libp2p/logger": "^3.0.2",
"@libp2p/logger": "^3.1.0",
"@libp2p/peer-id-factory": "^3.0.8",
"aegir": "^41.0.2",
"protons": "^7.3.0",
Expand Down
148 changes: 78 additions & 70 deletions packages/connection-encrypter-plaintext/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,17 @@
*/

import { UnexpectedPeerError, InvalidCryptoExchangeError } from '@libp2p/interface/errors'
import { logger } from '@libp2p/logger'
import { peerIdFromBytes, peerIdFromKeys } from '@libp2p/peer-id'
import { handshake } from 'it-handshake'
import * as lp from 'it-length-prefixed'
import map from 'it-map'
import { Exchange, KeyType } from './pb/proto.js'
import type { ComponentLogger, Logger } from '@libp2p/interface'
import type { ConnectionEncrypter, SecuredConnection } from '@libp2p/interface/connection-encrypter'
import type { PeerId } from '@libp2p/interface/peer-id'
import type { Duplex, Source } from 'it-stream-types'
import type { Uint8ArrayList } from 'uint8arraylist'

const log = logger('libp2p:plaintext')
const PROTOCOL = '/plaintext/2.0.0'

function lpEncodeExchange (exchange: Exchange): Uint8ArrayList {
Expand All @@ -41,96 +40,105 @@ function lpEncodeExchange (exchange: Exchange): Uint8ArrayList {
return lp.encode.single(pb)
}

/**
* Encrypt connection
*/
async function encrypt (localId: PeerId, conn: Duplex<AsyncGenerator<Uint8Array>, Source<Uint8Array>, Promise<void>>, remoteId?: PeerId): Promise<SecuredConnection> {
const shake = handshake(conn)
export interface PlaintextComponents {
logger: ComponentLogger
}

let type = KeyType.RSA
class Plaintext implements ConnectionEncrypter {
public protocol: string = PROTOCOL
private readonly log: Logger

if (localId.type === 'Ed25519') {
type = KeyType.Ed25519
} else if (localId.type === 'secp256k1') {
type = KeyType.Secp256k1
constructor (components: PlaintextComponents) {
this.log = components.logger.forComponent('libp2p:plaintext')
}

// Encode the public key and write it to the remote peer
shake.write(
lpEncodeExchange({
id: localId.toBytes(),
pubkey: {
Type: type,
Data: localId.publicKey ?? new Uint8Array(0)
}
}).subarray()
)

log('write pubkey exchange to peer %p', remoteId)

// Get the Exchange message
const response = (await lp.decode.fromReader(shake.reader).next()).value
async secureInbound (localId: PeerId, conn: Duplex<AsyncGenerator<Uint8Array>, Source<Uint8Array>, Promise<void>>, remoteId?: PeerId): Promise<SecuredConnection> {
return this._encrypt(localId, conn, remoteId)
}

if (response == null) {
throw new Error('Did not read response')
async secureOutbound (localId: PeerId, conn: Duplex<AsyncGenerator<Uint8Array>, Source<Uint8Array>, Promise<void>>, remoteId?: PeerId): Promise<SecuredConnection> {
return this._encrypt(localId, conn, remoteId)
}

const id = Exchange.decode(response)
log('read pubkey exchange from peer %p', remoteId)
/**
* Encrypt connection
*/
async _encrypt (localId: PeerId, conn: Duplex<AsyncGenerator<Uint8Array>, Source<Uint8Array>, Promise<void>>, remoteId?: PeerId): Promise<SecuredConnection> {
const shake = handshake(conn)

let peerId
try {
if (id.pubkey == null) {
throw new Error('Public key missing')
}
let type = KeyType.RSA

if (id.pubkey.Data.length === 0) {
throw new Error('Public key data too short')
if (localId.type === 'Ed25519') {
type = KeyType.Ed25519
} else if (localId.type === 'secp256k1') {
type = KeyType.Secp256k1
}

if (id.id == null) {
throw new Error('Remote id missing')
}
// Encode the public key and write it to the remote peer
shake.write(
lpEncodeExchange({
id: localId.toBytes(),
pubkey: {
Type: type,
Data: localId.publicKey ?? new Uint8Array(0)
}
}).subarray()
)

peerId = await peerIdFromKeys(id.pubkey.Data)
this.log('write pubkey exchange to peer %p', remoteId)

if (!peerId.equals(peerIdFromBytes(id.id))) {
throw new Error('Public key did not match id')
// Get the Exchange message
const response = (await lp.decode.fromReader(shake.reader).next()).value

if (response == null) {
throw new Error('Did not read response')
}
} catch (err: any) {
log.error(err)
throw new InvalidCryptoExchangeError('Remote did not provide its public key')
}

if (remoteId != null && !peerId.equals(remoteId)) {
throw new UnexpectedPeerError()
}
const id = Exchange.decode(response)
this.log('read pubkey exchange from peer %p', remoteId)

log('plaintext key exchange completed successfully with peer %p', peerId)
let peerId
try {
if (id.pubkey == null) {
throw new Error('Public key missing')
}

shake.rest()
if (id.pubkey.Data.length === 0) {
throw new Error('Public key data too short')
}

return {
conn: {
sink: shake.stream.sink,
source: map(shake.stream.source, (buf) => buf.subarray())
},
remotePeer: peerId
}
}
if (id.id == null) {
throw new Error('Remote id missing')
}

class Plaintext implements ConnectionEncrypter {
public protocol: string = PROTOCOL
peerId = await peerIdFromKeys(id.pubkey.Data)

async secureInbound (localId: PeerId, conn: Duplex<AsyncGenerator<Uint8Array>, Source<Uint8Array>, Promise<void>>, remoteId?: PeerId): Promise<SecuredConnection> {
return encrypt(localId, conn, remoteId)
}
if (!peerId.equals(peerIdFromBytes(id.id))) {
throw new Error('Public key did not match id')
}
} catch (err: any) {
this.log.error(err)
throw new InvalidCryptoExchangeError('Remote did not provide its public key')
}

async secureOutbound (localId: PeerId, conn: Duplex<AsyncGenerator<Uint8Array>, Source<Uint8Array>, Promise<void>>, remoteId?: PeerId): Promise<SecuredConnection> {
return encrypt(localId, conn, remoteId)
if (remoteId != null && !peerId.equals(remoteId)) {
throw new UnexpectedPeerError()
}

this.log('plaintext key exchange completed successfully with peer %p', peerId)

shake.rest()

return {
conn: {
sink: shake.stream.sink,
source: map(shake.stream.source, (buf) => buf.subarray())
},
remotePeer: peerId
}
}
}

export function plaintext (): () => ConnectionEncrypter {
return () => new Plaintext()
export function plaintext (): (components: PlaintextComponents) => ConnectionEncrypter {
return (components) => new Plaintext(components)
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
/* eslint-env mocha */

import suite from '@libp2p/interface-compliance-tests/connection-encryption'
import { defaultLogger } from '@libp2p/logger'
import { plaintext } from '../src/index.js'

describe('plaintext compliance', () => {
suite({
async setup () {
return plaintext()()
return plaintext()({
logger: defaultLogger()
})
},
async teardown () {

Expand Down
5 changes: 4 additions & 1 deletion packages/connection-encrypter-plaintext/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
UnexpectedPeerError
} from '@libp2p/interface/errors'
import { mockMultiaddrConnPair } from '@libp2p/interface-compliance-tests/mocks'
import { defaultLogger } from '@libp2p/logger'
import { peerIdFromBytes } from '@libp2p/peer-id'
import { createEd25519PeerId, createRSAPeerId } from '@libp2p/peer-id-factory'
import { multiaddr } from '@multiformats/multiaddr'
Expand All @@ -27,7 +28,9 @@ describe('plaintext', () => {
createEd25519PeerId()
])

encrypter = plaintext()()
encrypter = plaintext()({
logger: defaultLogger()
})
})

afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { PeerMap } from '@libp2p/peer-collections'
import { peerIdFromString } from '@libp2p/peer-id'
import { isMultiaddr, type Multiaddr } from '@multiformats/multiaddr'
import { connectionPair } from './connection.js'
import type { Libp2pEvents, PendingDial } from '@libp2p/interface'
import type { ComponentLogger, Libp2pEvents, PendingDial } from '@libp2p/interface'
import type { Connection } from '@libp2p/interface/connection'
import type { TypedEventTarget } from '@libp2p/interface/events'
import type { PubSub } from '@libp2p/interface/pubsub'
Expand All @@ -18,6 +18,7 @@ export interface MockNetworkComponents {
connectionManager: ConnectionManager
events: TypedEventTarget<Libp2pEvents>
pubsub?: PubSub
logger: ComponentLogger
}

class MockNetwork {
Expand Down
22 changes: 15 additions & 7 deletions packages/interface-compliance-tests/src/mocks/connection.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CodeError } from '@libp2p/interface/errors'
import { logger } from '@libp2p/logger'
import { defaultLogger } from '@libp2p/logger'
import * as mss from '@libp2p/multistream-select'
import { peerIdFromString } from '@libp2p/peer-id'
import { duplexPair } from 'it-pair/duplex'
Expand All @@ -8,20 +8,19 @@ import { Uint8ArrayList } from 'uint8arraylist'
import { mockMultiaddrConnection } from './multiaddr-connection.js'
import { mockMuxer } from './muxer.js'
import { mockRegistrar } from './registrar.js'
import type { AbortOptions } from '@libp2p/interface'
import type { AbortOptions, ComponentLogger } from '@libp2p/interface'
import type { MultiaddrConnection, Connection, Stream, Direction, ConnectionTimeline, ConnectionStatus } from '@libp2p/interface/connection'
import type { PeerId } from '@libp2p/interface/peer-id'
import type { StreamMuxer, StreamMuxerFactory } from '@libp2p/interface/stream-muxer'
import type { Registrar } from '@libp2p/interface-internal/registrar'
import type { Multiaddr } from '@multiformats/multiaddr'
import type { Duplex, Source } from 'it-stream-types'

const log = logger('libp2p:mock-connection')

export interface MockConnectionOptions {
direction?: Direction
registrar?: Registrar
muxerFactory?: StreamMuxerFactory
logger?: ComponentLogger
}

interface MockConnectionInit {
Expand All @@ -30,6 +29,7 @@ interface MockConnectionInit {
direction: Direction
maConn: MultiaddrConnection
muxer: StreamMuxer
logger: ComponentLogger
}

class MockConnection implements Connection {
Expand All @@ -47,9 +47,10 @@ class MockConnection implements Connection {

private readonly muxer: StreamMuxer
private readonly maConn: MultiaddrConnection
private readonly logger: ComponentLogger

constructor (init: MockConnectionInit) {
const { remoteAddr, remotePeer, direction, maConn, muxer } = init
const { remoteAddr, remotePeer, direction, maConn, muxer, logger } = init

this.id = `mock-connection-${Math.random()}`
this.remoteAddr = remoteAddr
Expand All @@ -65,6 +66,7 @@ class MockConnection implements Connection {
this.muxer = muxer
this.maConn = maConn
this.transient = false
this.logger = logger
}

async newStream (protocols: string | string[], options?: AbortOptions): Promise<Stream> {
Expand All @@ -82,7 +84,10 @@ class MockConnection implements Connection {

const id = `${Math.random()}`
const stream = await this.muxer.newStream(id)
const result = await mss.select(stream, protocols, options)
const result = await mss.select(stream, protocols, {
...options,
log: this.logger.forComponent('libp2p:mock-connection:stream:mss:select')
})

stream.protocol = result.protocol
stream.direction = 'outbound'
Expand Down Expand Up @@ -118,6 +123,7 @@ class MockConnection implements Connection {
export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectionOptions = {}): Connection {
const remoteAddr = maConn.remoteAddr
const remotePeerIdStr = remoteAddr.getPeerId() ?? '12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq'
const logger = opts.logger ?? defaultLogger()

if (remotePeerIdStr == null) {
throw new Error('Remote multiaddr must contain a peer id')
Expand All @@ -127,6 +133,7 @@ export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectio
const direction = opts.direction ?? 'inbound'
const registrar = opts.registrar ?? mockRegistrar()
const muxerFactory = opts.muxerFactory ?? mockMuxer()
const log = logger.forComponent('libp2p:mock-muxer')

const muxer = muxerFactory.createStreamMuxer({
direction,
Expand Down Expand Up @@ -164,7 +171,8 @@ export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectio
remotePeer,
direction,
maConn,
muxer
muxer,
logger
})

return connection
Expand Down
2 changes: 2 additions & 0 deletions packages/interface-compliance-tests/src/pubsub/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import messagesTest from './messages.js'
import multipleNodesTest from './multiple-nodes.js'
import twoNodesTest from './two-nodes.js'
import type { TestSetup } from '../index.js'
import type { ComponentLogger } from '@libp2p/interface'
import type { PeerId } from '@libp2p/interface/peer-id'
import type { PubSub, PubSubInit } from '@libp2p/interface/pubsub'
import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager'
Expand All @@ -15,6 +16,7 @@ export interface PubSubComponents {
registrar: Registrar
connectionManager: ConnectionManager
pubsub?: PubSub
logger: ComponentLogger
}

export interface PubSubArgs {
Expand Down
4 changes: 3 additions & 1 deletion packages/interface-compliance-tests/src/pubsub/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TypedEventEmitter } from '@libp2p/interface/events'
import { defaultLogger } from '@libp2p/logger'
import { createEd25519PeerId } from '@libp2p/peer-id-factory'
import { pEvent } from 'p-event'
import pWaitFor from 'p-wait-for'
Expand All @@ -19,7 +20,8 @@ export async function createComponents (): Promise<MockNetworkComponents> {
const components: any = {
peerId: await createEd25519PeerId(),
registrar: mockRegistrar(),
events: new TypedEventEmitter()
events: new TypedEventEmitter(),
logger: defaultLogger()
}
components.connectionManager = mockConnectionManager(components)

Expand Down
2 changes: 1 addition & 1 deletion packages/kad-dht/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"@libp2p/crypto": "^2.0.8",
"@libp2p/interface": "^0.1.6",
"@libp2p/interface-internal": "^0.1.9",
"@libp2p/logger": "^3.1.0",
"@libp2p/peer-collections": "^4.0.8",
"@libp2p/peer-id": "^3.0.6",
"@multiformats/multiaddr": "^12.1.10",
Expand Down Expand Up @@ -90,6 +89,7 @@
},
"devDependencies": {
"@libp2p/interface-compliance-tests": "^4.1.5",
"@libp2p/logger": "^3.1.0",
"@libp2p/peer-id-factory": "^3.0.8",
"@libp2p/peer-store": "^9.0.9",
"@types/lodash.random": "^3.2.6",
Expand Down
Loading

0 comments on commit e5dfde0

Please sign in to comment.