Skip to content

Commit

Permalink
fix: allow publish of no-sign messages (#296)
Browse files Browse the repository at this point in the history
  • Loading branch information
wemeetagain committed Jun 30, 2022
1 parent 3837e05 commit 40dadb8
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 5 deletions.
7 changes: 2 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1851,13 +1851,10 @@ export class GossipSub extends EventEmitter<GossipsubEvents> implements Initiali
// Prepare raw message with user's publishConfig
const rawMsg = await buildRawMessage(this.publishConfig, topic, transformedData)

if (rawMsg.from == null) {
throw Error('PublishError.InvalidMessage')
}

// calculate the message id from the un-transformed data
const msg: Message = {
from: peerIdFromBytes(rawMsg.from),
// TODO fix types upstream, see https://github.com/libp2p/js-libp2p-interfaces/pull/266
from: (rawMsg.from ? peerIdFromBytes(rawMsg.from) : undefined) as PeerId,
data, // the uncompressed form
sequenceNumber: rawMsg.seqno == null ? undefined : BigInt(`0x${uint8ArrayToString(rawMsg.seqno, 'base16')}`),
topic,
Expand Down
213 changes: 213 additions & 0 deletions test/signature-policy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import { expect } from 'aegir/chai'
import { pEvent } from 'p-event'
import { Components } from '@libp2p/components'
import { mockNetwork } from '@libp2p/interface-mocks'
import { stop } from '@libp2p/interfaces/startable'
import {
connectAllPubSubNodes,
connectPubsubNodes,
createComponents,
createComponentsArray
} from './utils/create-pubsub.js'

describe.only('signature policy', () => {
describe('strict-sign', () => {
const numNodes = 3
let nodes: Components[]

beforeEach(async () => {
mockNetwork.reset()
nodes = await createComponentsArray({
number: numNodes,
connected: false,
init: {
scoreParams: {
IPColocationFactorThreshold: 3
},
// crucial line
globalSignaturePolicy: 'StrictSign'
}
})
})

afterEach(async () => {
await stop(...nodes)
mockNetwork.reset()
})

it('should publish a message', async () => {
const topic = 'foo'

// add subscriptions to each node
nodes.forEach((n) => n.getPubSub().subscribe(topic))

// connect all nodes
await connectAllPubSubNodes(nodes)

// wait for subscriptions to be transmitted
await Promise.all(nodes.map(async (n) => await pEvent(n.getPubSub(), 'subscription-change')))

// await mesh rebalancing
await Promise.all(nodes.map(async (n) => await pEvent(n.getPubSub(), 'gossipsub:heartbeat')))

// publish a message on the topic
const result = await nodes[0].getPubSub().publish(topic, new Uint8Array())
expect(result.recipients).to.length(numNodes - 1)
})

it('should forward a valid message', async () => {
const topic = 'foo'

// add subscriptions to each node
nodes.forEach((n) => n.getPubSub().subscribe(topic))

// connect in a line
await Promise.all(Array.from({ length: numNodes - 1 }, (_, i) => connectPubsubNodes(nodes[i], nodes[i + 1])))

// wait for subscriptions to be transmitted
await Promise.all(nodes.map(async (n) => await pEvent(n.getPubSub(), 'subscription-change')))

// await mesh rebalancing
await Promise.all(nodes.map(async (n) => await pEvent(n.getPubSub(), 'gossipsub:heartbeat')))

// publish a message on the topic
const result = await nodes[0].getPubSub().publish(topic, new Uint8Array())
expect(result.recipients).to.length(1)

// the last node should get the message
await pEvent(nodes[nodes.length - 1].getPubSub(), 'gossipsub:message')
})

it('should not forward an strict-no-sign message', async () => {
const topic = 'foo'

// add a no-sign peer to nodes
nodes.unshift(
await createComponents({
init: {
globalSignaturePolicy: 'StrictNoSign'
}
})
)

// add subscriptions to each node
nodes.forEach((n) => n.getPubSub().subscribe(topic))

// connect in a line
await Promise.all(Array.from({ length: numNodes - 1 }, (_, i) => connectPubsubNodes(nodes[i], nodes[i + 1])))

// await mesh rebalancing
await Promise.all(nodes.map(async (n) => await pEvent(n.getPubSub(), 'gossipsub:heartbeat')))

// publish a message on the topic
const result = await nodes[0].getPubSub().publish(topic, new Uint8Array())
expect(result.recipients).to.length(1)

// the last node should NOT get the message
try {
await pEvent(nodes[nodes.length - 1].getPubSub(), 'gossipsub:message', { timeout: 200 })
expect.fail('no-sign message should not be emitted from strict-sign peer')
} catch (e) {}
})
})

describe('strict-no-sign', () => {
const numNodes = 3
let nodes: Components[]

beforeEach(async () => {
mockNetwork.reset()
nodes = await createComponentsArray({
number: numNodes,
connected: false,
init: {
scoreParams: {
IPColocationFactorThreshold: 3
},
// crucial line
globalSignaturePolicy: 'StrictNoSign'
}
})
})

afterEach(async () => {
await stop(...nodes)
mockNetwork.reset()
})

it('should publish a message', async () => {
const topic = 'foo'

// add subscriptions to each node
nodes.forEach((n) => n.getPubSub().subscribe(topic))

// connect all nodes
await connectAllPubSubNodes(nodes)

// wait for subscriptions to be transmitted
await Promise.all(nodes.map(async (n) => await pEvent(n.getPubSub(), 'subscription-change')))

// await mesh rebalancing
await Promise.all(nodes.map(async (n) => await pEvent(n.getPubSub(), 'gossipsub:heartbeat')))

// publish a message on the topic
const result = await nodes[0].getPubSub().publish(topic, new Uint8Array())
expect(result.recipients).to.length(numNodes - 1)
})

it('should forward a valid message', async () => {
const topic = 'foo'

// add subscriptions to each node
nodes.forEach((n) => n.getPubSub().subscribe(topic))

// connect in a line
await Promise.all(Array.from({ length: numNodes - 1 }, (_, i) => connectPubsubNodes(nodes[i], nodes[i + 1])))

// wait for subscriptions to be transmitted
await Promise.all(nodes.map(async (n) => await pEvent(n.getPubSub(), 'subscription-change')))

// await mesh rebalancing
await Promise.all(nodes.map(async (n) => await pEvent(n.getPubSub(), 'gossipsub:heartbeat')))

// publish a message on the topic
const result = await nodes[0].getPubSub().publish(topic, new Uint8Array())
expect(result.recipients).to.length(1)

// the last node should get the message
await pEvent(nodes[nodes.length - 1].getPubSub(), 'gossipsub:message')
})

it('should not forward an strict-sign message', async () => {
const topic = 'foo'

// add a no-sign peer to nodes
nodes.unshift(
await createComponents({
init: {
globalSignaturePolicy: 'StrictSign'
}
})
)

// add subscriptions to each node
nodes.forEach((n) => n.getPubSub().subscribe(topic))

// connect in a line
await Promise.all(Array.from({ length: numNodes - 1 }, (_, i) => connectPubsubNodes(nodes[i], nodes[i + 1])))

// await mesh rebalancing
await Promise.all(nodes.map(async (n) => await pEvent(n.getPubSub(), 'gossipsub:heartbeat')))

// publish a message on the topic
const result = await nodes[0].getPubSub().publish(topic, new Uint8Array())
expect(result.recipients).to.length(1)

// the last node should NOT get the message
try {
await pEvent(nodes[nodes.length - 1].getPubSub(), 'gossipsub:message', { timeout: 200 })
expect.fail('no-sign message should not be emitted from strict-sign peer')
} catch (e) {}
})
})
})

0 comments on commit 40dadb8

Please sign in to comment.