Skip to content
This repository has been archived by the owner on Jun 26, 2023. It is now read-only.

Commit

Permalink
feat: record interface
Browse files Browse the repository at this point in the history
  • Loading branch information
vasco-santos committed Jun 15, 2020
1 parent 9fbf9d0 commit 0affd45
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 0 deletions.
75 changes: 75 additions & 0 deletions src/record/README.md
Original file line number Diff line number Diff line change
@@ -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
}

isEqual (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.

### isEqual

- `record.isEqual(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 changes: 35 additions & 0 deletions src/record/index.js
Original file line number Diff line number Diff line change
@@ -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
*/
isEqual (other) {
throw errcode(new Error('isEqual must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
}
}

module.exports = Record
35 changes: 35 additions & 0 deletions src/record/tests/index.js
Original file line number Diff line number Diff line change
@@ -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 isEqual = record.isEqual(record)
expect(isEqual).to.eql(true)
})
})
}

0 comments on commit 0affd45

Please sign in to comment.