mirror of
https://github.com/fluencelabs/js-libp2p-interfaces
synced 2025-04-24 16:32:32 +00:00
feat: record interface (#52)
* feat: record interface * chore: add readme reference * chore: address review
This commit is contained in:
parent
4adedcc4bf
commit
1cc943e1b2
@ -18,6 +18,7 @@
|
||||
- [Crypto](./src/crypto)
|
||||
- [Peer Discovery](./src/peer-discovery)
|
||||
- [Peer Routing](./src/peer-routing)
|
||||
- [Record](./src/record)
|
||||
- [Stream Muxer](./src/stream-muxer)
|
||||
- [Topology](./src/topology)
|
||||
- [Transport](./src/transport)
|
||||
|
75
src/record/README.md
Normal file
75
src/record/README.md
Normal file
@ -0,0 +1,75 @@
|
||||
interface-record
|
||||
==================
|
||||
|
||||
A libp2p node needs to store data in a public location (e.g. a DHT), or rely on potentially untrustworthy intermediaries to relay information. Libp2p provides an all-purpose data container called **envelope**, which includes a signature of the data, so that it its authenticity can be verified.
|
||||
|
||||
The record represents the data that will be stored inside the **envelope** when distributing records across the network. The `interface-record` aims to guarantee that any type of record created is compliant with the libp2p **envelope**.
|
||||
|
||||
Taking into account that a record might be used in different contexts, an **envelope** signature made for a specific purpose **must not** be considered valid for a different purpose. Accordingly, each record has a short and descriptive string representing the record use case, known as **domain**. The data to be signed will be prepended with the domain string, in order to create a domain signature.
|
||||
|
||||
A record can also contain a Buffer codec (ideally registered as a [multicodec](https://github.com/multiformats/multicodec)). This codec will prefix the record data in the **envelope** , so that it can be deserialized deterministically.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const tests = require('libp2p-interfaces/src/record/tests')
|
||||
describe('your record', () => {
|
||||
tests({
|
||||
async setup () {
|
||||
return YourRecord
|
||||
},
|
||||
async teardown () {
|
||||
// cleanup resources created by setup()
|
||||
}
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## Create Record
|
||||
|
||||
```js
|
||||
const multicodec = require('multicodec')
|
||||
const Record = require('libp2p-interfaces/src/record')
|
||||
// const Protobuf = require('./record.proto')
|
||||
|
||||
const ENVELOPE_DOMAIN_PEER_RECORD = 'libp2p-peer-record'
|
||||
const ENVELOPE_PAYLOAD_TYPE_PEER_RECORD = Buffer.from('0301', 'hex')
|
||||
|
||||
class PeerRecord extends Record {
|
||||
constructor (peerId, multiaddrs, seqNumber) {
|
||||
super (ENVELOPE_DOMAIN_PEER_RECORD, ENVELOPE_PAYLOAD_TYPE_PEER_RECORD)
|
||||
}
|
||||
|
||||
marshal () {
|
||||
// Implement and return using Protobuf
|
||||
}
|
||||
|
||||
equals (other) {
|
||||
// Verify
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### marshal
|
||||
|
||||
- `record.marshal()`
|
||||
|
||||
Marshal a record to be used in a libp2p envelope.
|
||||
|
||||
**Returns**
|
||||
|
||||
It returns a `Protobuf` containing the record data.
|
||||
|
||||
### equals
|
||||
|
||||
- `record.equals(other)`
|
||||
|
||||
Verifies if the other Record is identical to this one.
|
||||
|
||||
**Parameters**
|
||||
- other is a `Record` to compare with the current instance.
|
||||
|
||||
**Returns**
|
||||
- `boolean`
|
35
src/record/index.js
Normal file
35
src/record/index.js
Normal file
@ -0,0 +1,35 @@
|
||||
'use strict'
|
||||
|
||||
const errcode = require('err-code')
|
||||
|
||||
/**
|
||||
* Record is the base implementation of a record that can be used as the payload of a libp2p envelope.
|
||||
*/
|
||||
class Record {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {String} domain signature domain
|
||||
* @param {Buffer} codec identifier of the type of record
|
||||
*/
|
||||
constructor (domain, codec) {
|
||||
this.domain = domain
|
||||
this.codec = codec
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal a record to be used in an envelope.
|
||||
*/
|
||||
marshal () {
|
||||
throw errcode(new Error('marshal must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if the other provided Record is identical to this one.
|
||||
* @param {Record} other
|
||||
*/
|
||||
equals (other) {
|
||||
throw errcode(new Error('equals must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Record
|
35
src/record/tests/index.js
Normal file
35
src/record/tests/index.js
Normal file
@ -0,0 +1,35 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
const expect = chai.expect
|
||||
chai.use(require('dirty-chai'))
|
||||
|
||||
module.exports = (test) => {
|
||||
describe('record', () => {
|
||||
let record
|
||||
|
||||
beforeEach(async () => {
|
||||
record = await test.setup()
|
||||
if (!record) throw new Error('missing record')
|
||||
})
|
||||
|
||||
afterEach(() => test.teardown())
|
||||
|
||||
it('has domain and codec', () => {
|
||||
expect(record.domain).to.exist()
|
||||
expect(record.codec).to.exist()
|
||||
})
|
||||
|
||||
it('is able to marshal', () => {
|
||||
const rawData = record.marshal()
|
||||
expect(Buffer.isBuffer(rawData)).to.eql(true)
|
||||
})
|
||||
|
||||
it('is able to compare two records', () => {
|
||||
const equals = record.equals(record)
|
||||
expect(equals).to.eql(true)
|
||||
})
|
||||
})
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user