diff --git a/src/bee.ts b/src/bee.ts index 078bf8f3..4a628873 100644 --- a/src/bee.ts +++ b/src/bee.ts @@ -511,7 +511,7 @@ export class Bee { * * @param postageBatchId Postage BatchId that will be assigned to sent message * @param topic Topic name - * @param target Target message address prefix + * @param target Target message address prefix. Has a limit on length. Recommend to use `Utils.Pss.makeMaxTarget()` to get the most specific target that Bee node will accept. * @param data Message to be sent * @param recipient Recipient public key * @throws TypeError if `data`, `batchId`, `target` or `recipient` are in invalid format diff --git a/src/modules/pss.ts b/src/modules/pss.ts index 6fb02f04..771d0311 100644 --- a/src/modules/pss.ts +++ b/src/modules/pss.ts @@ -28,7 +28,7 @@ export async function send( ): Promise { await http(ky, { method: 'post', - path: `${endpoint}/send/${topic}/${target.slice(0, 4)}`, + path: `${endpoint}/send/${topic}/${target}`, body: await prepareData(data), responseType: 'json', searchParams: { recipient }, diff --git a/src/types/index.ts b/src/types/index.ts index 76ec15a1..bf9a4e55 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -21,6 +21,7 @@ export interface Dictionary { } export const ADDRESS_HEX_LENGTH = 64 +export const PSS_TARGET_HEX_LENGTH_MAX = 4 export const PUBKEY_HEX_LENGTH = 66 export const BATCH_ID_HEX_LENGTH = 64 export const REFERENCE_HEX_LENGTH = 64 diff --git a/src/utils/expose.ts b/src/utils/expose.ts index 98428eba..4500b688 100644 --- a/src/utils/expose.ts +++ b/src/utils/expose.ts @@ -45,3 +45,4 @@ export { } from './stream' export { keccak256Hash } from './hash' +export { makeMaxTarget } from './pss' diff --git a/src/utils/pss.ts b/src/utils/pss.ts new file mode 100644 index 00000000..de382cfd --- /dev/null +++ b/src/utils/pss.ts @@ -0,0 +1,16 @@ +import { AddressPrefix, PSS_TARGET_HEX_LENGTH_MAX } from '../types' + +/** + * Utility function that for given strings/reference takes the most specific + * target that Bee node will except. + * + * @param target is a non-prefixed hex string Bee address + * @see [Bee docs - PSS](https://docs.ethswarm.org/docs/dapps-on-swarm/pss) + */ +export function makeMaxTarget(target: string): AddressPrefix { + if (typeof target !== 'string') { + throw new TypeError('target has to be an string!') + } + + return target.slice(0, PSS_TARGET_HEX_LENGTH_MAX) +} diff --git a/src/utils/type.ts b/src/utils/type.ts index e1ac6bd6..9070243f 100644 --- a/src/utils/type.ts +++ b/src/utils/type.ts @@ -18,6 +18,7 @@ import { Tag, TAGS_LIMIT_MAX, TAGS_LIMIT_MIN, + PSS_TARGET_HEX_LENGTH_MAX, UploadOptions, TransactionHash, } from '../types' @@ -191,9 +192,9 @@ export function assertTag(value: unknown): asserts value is Tag { export function assertAddressPrefix(value: unknown): asserts value is AddressPrefix { assertHexString(value, undefined, 'AddressPrefix') - if (value.length > ADDRESS_HEX_LENGTH) { + if (value.length > PSS_TARGET_HEX_LENGTH_MAX) { throw new BeeArgumentError( - `AddressPrefix must have length of ${ADDRESS_HEX_LENGTH} at most! Got string with ${value.length}`, + `AddressPrefix must have length of ${PSS_TARGET_HEX_LENGTH_MAX} at most! Got string with ${value.length}`, value, ) } diff --git a/test/integration/bee-class.browser.spec.ts b/test/integration/bee-class.browser.spec.ts index 16aa9314..a5d8d2e7 100644 --- a/test/integration/bee-class.browser.spec.ts +++ b/test/integration/bee-class.browser.spec.ts @@ -203,7 +203,7 @@ describe('Bee class - in browser', () => { const beePeer = new window.BeeJs.Bee(BEE_PEER_URL) const receive = bee.pssReceive(topic) - await beePeer.pssSend(batchIdPeer, topic, overlay, message) + await beePeer.pssSend(batchIdPeer, topic, window.BeeJs.Utils.makeMaxTarget(overlay), message) const msg = await receive @@ -242,7 +242,13 @@ describe('Bee class - in browser', () => { const beePeer = new window.BeeJs.Bee(BEE_PEER_URL) const receive = bee.pssReceive(topic) - await beePeer.pssSend(batchIdPeer, topic, overlay, message, pssPublicKey) + await beePeer.pssSend( + batchIdPeer, + topic, + window.BeeJs.Utils.makeMaxTarget(overlay), + message, + pssPublicKey, + ) const msg = await receive diff --git a/test/integration/bee-class.spec.ts b/test/integration/bee-class.spec.ts index 63a6a391..bd69432d 100644 --- a/test/integration/bee-class.spec.ts +++ b/test/integration/bee-class.spec.ts @@ -1,4 +1,4 @@ -import { Bee, BeeArgumentError, BeeDebug, Collection } from '../../src' +import { Bee, BeeArgumentError, BeeDebug, Collection, PssSubscription } from '../../src' import { makeSigner } from '../../src/chunk/signer' import { makeSOCAddress, uploadSingleOwnerChunkData } from '../../src/chunk/soc' import { ChunkReference } from '../../src/feed' @@ -30,6 +30,7 @@ import { } from '../utils' import { Readable } from 'stream' import { TextEncoder } from 'util' +import { makeMaxTarget } from '../../src/utils/pss' commonMatchers() @@ -300,7 +301,7 @@ describe('Bee class', () => { }) const { overlay } = await beeDebug.getNodeAddresses() - await beePeer.pssSend(getPostageBatch(BEE_DEBUG_PEER_URL), topic, overlay, message) + await beePeer.pssSend(getPostageBatch(BEE_DEBUG_PEER_URL), topic, makeMaxTarget(overlay), message) })().catch(reject) }) }, @@ -323,7 +324,13 @@ describe('Bee class', () => { }) const { overlay, pssPublicKey } = await beeDebug.getNodeAddresses() - await beePeer.pssSend(getPostageBatch(BEE_DEBUG_PEER_URL), topic, overlay, message, pssPublicKey) + await beePeer.pssSend( + getPostageBatch(BEE_DEBUG_PEER_URL), + topic, + makeMaxTarget(overlay), + message, + pssPublicKey, + ) })().catch(reject) }) }, @@ -334,15 +341,16 @@ describe('Bee class', () => { 'should subscribe to topic', async () => { return new Promise((resolve, reject) => { + let subscription: PssSubscription ;(async () => { const topic = 'bee-class-subscribe-topic' const message = new Uint8Array([1, 2, 3]) const beeDebug = new BeeDebug(beeDebugUrl()) - const subscription = bee.pssSubscribe(topic, { + subscription = bee.pssSubscribe(topic, { onMessage: receivedMessage => { // without cancel jest complains for leaking handles and may hang - subscription.cancel() + subscription?.cancel() expect(receivedMessage).toEqual(message) resolve() @@ -353,8 +361,12 @@ describe('Bee class', () => { }) const { overlay } = await beeDebug.getNodeAddresses() - await beePeer.pssSend(getPostageBatch(BEE_DEBUG_PEER_URL), topic, overlay, message) - })().catch(reject) + await beePeer.pssSend(getPostageBatch(BEE_DEBUG_PEER_URL), topic, makeMaxTarget(overlay), message) + })().catch(e => { + // without cancel jest complains for leaking handles and may hang + subscription?.cancel() + reject(e) + }) }) }, PSS_TIMEOUT, diff --git a/test/integration/modules/pss.spec.ts b/test/integration/modules/pss.spec.ts index 8816106d..8811e209 100644 --- a/test/integration/modules/pss.spec.ts +++ b/test/integration/modules/pss.spec.ts @@ -1,6 +1,7 @@ import * as pss from '../../../src/modules/pss' import * as connectivity from '../../../src/modules/debug/connectivity' import { beeDebugKy, beeKy, beePeerDebugUrl, beePeerKy, beeUrl, getPostageBatch, PSS_TIMEOUT } from '../../utils' +import { makeMaxTarget } from '../../../src/utils/pss' const BEE_KY = beeKy() const BEE_URL = beeUrl() @@ -20,7 +21,7 @@ describe('modules/pss', () => { expect(peers.length).toBeGreaterThan(0) const target = peers[0].address - await pss.send(BEE_KY, topic, target, message, getPostageBatch()) // Nothing is asserted as nothing is returned, will throw error if something is wrong + await pss.send(BEE_KY, topic, makeMaxTarget(target), message, getPostageBatch()) // Nothing is asserted as nothing is returned, will throw error if something is wrong }, PSS_TIMEOUT, ) @@ -48,7 +49,7 @@ describe('modules/pss', () => { const addresses = await connectivity.getNodeAddresses(BEE_DEBUG_KY) const target = addresses.overlay - await pss.send(BEE_PEER_KY, topic, target, message, getPostageBatch(BEE_DEBUG_PEER_URL)) + await pss.send(BEE_PEER_KY, topic, makeMaxTarget(target), message, getPostageBatch(BEE_DEBUG_PEER_URL)) })().catch(reject) }) }, @@ -80,7 +81,14 @@ describe('modules/pss', () => { const addresses = await connectivity.getNodeAddresses(BEE_DEBUG_KY) const target = addresses.overlay const recipient = addresses.pssPublicKey - await pss.send(BEE_PEER_KY, topic, target, message, getPostageBatch(BEE_DEBUG_PEER_URL), recipient) + await pss.send( + BEE_PEER_KY, + topic, + makeMaxTarget(target), + message, + getPostageBatch(BEE_DEBUG_PEER_URL), + recipient, + ) })().catch(reject) }) }, diff --git a/test/unit/assertions.ts b/test/unit/assertions.ts index 82f6602e..1bd49186 100644 --- a/test/unit/assertions.ts +++ b/test/unit/assertions.ts @@ -141,19 +141,13 @@ export function testAddressPrefixAssertions(executor: (input: unknown) => void): await expect(() => executor('')).rejects.toThrow(TypeError) // Not an valid hexstring (ZZZ) - await expect(() => executor('ZZZfb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( - TypeError, - ) + await expect(() => executor('ZZZf')).rejects.toThrow(TypeError) // Prefixed hexstring is not accepted - await expect(() => executor('0x634fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( - TypeError, - ) + await expect(() => executor('0x634f')).rejects.toThrow(TypeError) // Too long hexstring - await expect(() => executor('123634fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( - BeeArgumentError, - ) + await expect(() => executor('12364')).rejects.toThrow(BeeArgumentError) }) }