-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #86 from xmtp/jazzz/keybundle-network-store
Keybundle network store
- Loading branch information
Showing
5 changed files
with
159 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// This creates an interface for storing data to the storage network. | ||
import { Store } from './Store' | ||
import { Waku, WakuMessage, PageDirection } from 'js-waku' | ||
import { buildUserPrivateStoreTopic } from '../utils' | ||
|
||
export default class NetworkStore implements Store { | ||
private waku: Waku | ||
|
||
constructor(waku: Waku) { | ||
this.waku = waku | ||
} | ||
|
||
// Returns the first record in a topic if it is present. | ||
async get(key: string): Promise<Buffer | null> { | ||
const contents = ( | ||
await this.waku.store.queryHistory([buildUserPrivateStoreTopic(key)], { | ||
pageSize: 1, | ||
pageDirection: PageDirection.FORWARD, | ||
callback: function (msgs: WakuMessage[]): boolean { | ||
return Boolean(msgs[0].payload) | ||
}, | ||
}) | ||
) | ||
.filter((msg: WakuMessage) => msg.payload) | ||
.map((msg: WakuMessage) => msg.payload as Uint8Array) | ||
return contents.length > 0 ? Buffer.from(contents[0]) : null | ||
} | ||
|
||
async set(key: string, value: Buffer): Promise<void> { | ||
const keys = Uint8Array.from(value) | ||
await this.waku.relay.send( | ||
await WakuMessage.fromBytes(keys, this.buildTopic(key)) | ||
) | ||
} | ||
|
||
private buildTopic(key: string): string { | ||
return buildUserPrivateStoreTopic(key) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export { default as LocalStorageStore } from './LocalStorageStore' | ||
export { default as EncryptedStore } from './EncryptedStore' | ||
export { default as PrivateTopicStore } from './PrivateTopicStore' | ||
export { Store } from './Store' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { Wallet } from 'ethers' | ||
import { Waku } from 'js-waku' | ||
|
||
import { newWallet, sleep } from '../helpers' | ||
import { createWaku } from '../../src/Client' | ||
import { PrivateTopicStore } from '../../src/store' | ||
|
||
const newLocalDockerWaku = (): Promise<Waku> => | ||
createWaku({ | ||
bootstrapAddrs: [ | ||
'/ip4/127.0.0.1/tcp/9001/ws/p2p/16Uiu2HAmNCxLZCkXNbpVPBpSSnHj9iq4HZQj7fxRzw2kj1kKSHHA', | ||
], | ||
}) | ||
|
||
const newTestnetWaku = (): Promise<Waku> => createWaku({ env: 'testnet' }) | ||
|
||
describe('PrivateTopicStore', () => { | ||
jest.setTimeout(10000) | ||
const tests = [ | ||
{ | ||
name: 'local docker node', | ||
newWaku: newLocalDockerWaku, | ||
}, | ||
] | ||
if (process.env.CI || process.env.TESTNET) { | ||
tests.push({ | ||
name: 'testnet', | ||
newWaku: newTestnetWaku, | ||
}) | ||
} | ||
tests.forEach((testCase) => { | ||
describe(testCase.name, () => { | ||
let waku: Waku | ||
let wallet: Wallet | ||
let store: PrivateTopicStore | ||
beforeAll(async () => { | ||
waku = await testCase.newWaku() | ||
}) | ||
afterAll(async () => { | ||
if (waku) await waku.stop() | ||
}) | ||
|
||
beforeEach(async () => { | ||
wallet = newWallet() | ||
store = new PrivateTopicStore(waku) | ||
}) | ||
|
||
it('roundtrip', async () => { | ||
const key = wallet.address | ||
|
||
const value = new TextEncoder().encode('hello') | ||
const empty = await store.get(key) | ||
expect(empty).toBeNull() | ||
|
||
await store.set(key, Buffer.from(value)) | ||
const full = await store.get(key) | ||
|
||
expect(full).toBeDefined() | ||
expect(full).toEqual(Buffer.from(value)) | ||
}) | ||
|
||
it('distinct topics', async () => { | ||
const valueA = Buffer.from(new TextEncoder().encode('helloA')) | ||
const valueB = Buffer.from(new TextEncoder().encode('helloB')) | ||
const keyA = wallet.address + 'A' | ||
const keyB = wallet.address + 'B' | ||
|
||
store.set(keyA, valueA) | ||
store.set(keyB, valueB) | ||
const responseA = await store.get(keyA) | ||
const responseB = await store.get(keyB) | ||
|
||
expect(responseA).toEqual(valueA) | ||
expect(responseB).toEqual(valueB) | ||
expect(responseA).not.toEqual(responseB) | ||
}) | ||
|
||
it('over write safety', async () => { | ||
const key = wallet.address | ||
|
||
const firstValue = new TextEncoder().encode('a') | ||
const secondValue = new TextEncoder().encode('bb') | ||
|
||
await store.set(key, Buffer.from(firstValue)) | ||
await sleep(10) // Add wait to enforce a consistent order of messages | ||
await store.set(key, Buffer.from(secondValue)) | ||
await sleep(10) // Add wait to enforce a consistent order of messages | ||
const returnedValue = await store.get(key) | ||
|
||
expect(returnedValue).toEqual(Buffer.from(firstValue)) | ||
}) | ||
}) | ||
}) | ||
}) |