git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit 3f8c23e36f6d90d0c86b778fb27c24c5aa57c8a1

rewrite

Signed-off-by: wanderer <mjbecze@gmail.com>
wanderer committed on 1/19/2018, 2:14:18 AM
Parent: df84d7871808036fce1c56eaa79c0565b9b5ddb6

Files changed

actor.jschanged
benchmark/index.jschanged
inbox.jschanged
index.jschanged
package.jsonchanged
scheduler.jschanged
tests/index.jschanged
message.jsadded
actor.jsView
@@ -1,6 +1,5 @@
11 const Pipe = require('buffer-pipe')
2-const Cap = require('primea-capability')
32 const leb128 = require('leb128').unsigned
43 const Inbox = require('./inbox.js')
54
65 module.exports = class Actor {
@@ -15,9 +14,8 @@
1514 */
1615 constructor (opts) {
1716 Object.assign(this, opts)
1817
19- this.container = new opts.container.Constructor(this, opts.container.args)
2018 this.inbox = new Inbox({
2119 actor: this,
2220 hypervisor: opts.hypervisor
2321 })
@@ -26,17 +24,8 @@
2624 this.running = false
2725 }
2826
2927 /**
30- * Mints a new capabilitly with a given tag
31- * @param {*} tag - a tag which can be used to identify caps
32- * @return {Object}
33- */
34- mintCap (tag = 0, funcIndex = 0) {
35- return new Cap(this.id, tag, funcIndex)
36- }
37-
38- /**
3928 * adds a message to this actor's message queue
4029 * @param {string} portName
4130 * @param {object} message
4231 */
@@ -48,41 +37,36 @@
4837 this._startMessageLoop()
4938 }
5039 }
5140
52- /**
53- * runs the creation routine for the actor
54- * @param {object} message
55- * @returns {Promise}
56- */
57- create (message) {
58- this.running = true
59- return this.runMessage(message, 'onCreation').then(() => {
60- this._startMessageLoop()
61- })
62- }
63-
6441 // waits for the next message
6542 async _startMessageLoop () {
6643 // this ensure we only every have one loop running at a time
6744 while (!this.inbox.isEmpty) {
68- const message = await this.inbox.nextMessage(0)
45+ const message = await this.inbox.nextMessage()
6946 await this.runMessage(message)
7047 }
7148 this.running = false
7249 // wait for state ops to finish
7350 await this.state.done()
7451 setTimeout(() => {
7552 if (!this.running) {
76- this.container.onIdle()
53+ this.shutdown()
7754 }
7855 }, 0)
7956 }
8057
8158 serializeMetaData () {
8259 return Actor.serializeMetaData(this.type, this.nonce)
8360 }
8461
62+ getFuncRef (name) {
63+ return {
64+ name,
65+ destId: this.id
66+ }
67+ }
68+
8569 static serializeMetaData (type, nonce = 0) {
8670 const p = new Pipe()
8771 leb128.write(type, p)
8872 leb128.write(nonce, p)
@@ -109,21 +93,22 @@
10993
11094 /**
11195 * Runs the startup routine for the actor
11296 */
113- startup () {
114- return this.container.onStartup()
97+ async startup () {
98+ this.instance = await this.container.instance(this)
11599 }
116100
117101 /**
118102 * run the Actor with a given message
119103 * @param {object} message - the message to run
120104 * @param {String} method - which method to run
121105 * @returns {Promise}
122106 */
123- async runMessage (message, method = 'onMessage') {
107+ async runMessage (message) {
124108 try {
125- await this.container[method](message)
109+ this.currentMessage = message
110+ await this.instance.exports[message.funcRef.name](...message.funcArguments)
126111 } catch (e) {
127112 message.emit('execution:error', e)
128113 }
129114 }
@@ -141,11 +126,11 @@
141126 * creates an actor
142127 * @param {Integer} type - the type id for the container
143128 * @param {Object} message - an intial [message](https://github.com/primea/js-primea-message) to send newly created actor
144129 */
145- createActor (type, message) {
130+ createActor (type, code) {
146131 const id = this._generateNextId()
147- return this.hypervisor.createActor(type, message, id)
132+ return this.hypervisor.createActor(type, code, id)
148133 }
149134
150135 _generateNextId () {
151136 const id = {
@@ -161,11 +146,11 @@
161146 * sends a message to a given port
162147 * @param {Object} portRef - the port
163148 * @param {Message} message - the message
164149 */
165- send (cap, message) {
150+ send (message) {
166151 message._fromTicks = this.ticks
167152 message._fromId = this.id
168153
169- return this.hypervisor.send(cap, message)
154+ return this.hypervisor.send(message)
170155 }
171156 }
benchmark/index.jsView
@@ -1,6 +1,5 @@
1-const AbstractContainer = require('primea-abstract-container')
2-const Message = require('primea-message')
1+const Message = require('../message.js')
32 const Hypervisor = require('../')
43
54 const level = require('level-browserify')
65 const RadixTree = require('dfinity-radix-tree')
@@ -8,70 +7,94 @@
87
98 let numOfMsg = 0
109 const messageOrder = {}
1110
12-async function main (numOfActors, depth) {
13- class BenchmarkContainer extends AbstractContainer {
14- onCreation () {}
15- async onMessage (message) {
16- // console.log('run queue', this.actor.inbox._queue)
17- // console.log('from', message._fromId.toString('hex'), 'to: ', this.actor.id.toString('hex'), this.actor.ticks, message._fromTicks)
18- const last = messageOrder[this.actor.id.toString('hex')]
19- if (last && last > message._fromTicks) {
20- console.log(last, message._fromTicks)
21- // console.log(this.actor.hypervisor.scheduler.instances)
22- } else {
11+class BenchmarkContainer {
12+ static validate () {}
13+ static compile () {}
14+ static get typeId () {
15+ return 9
16+ }
17+
18+ static exports (m, id) {
19+ return Object.keys(this.functions()).map(name => {
20+ return {
21+ name,
22+ destId: id
2323 }
24- messageOrder[this.actor.id.toString('hex')] = message._fromTicks
25- numOfMsg++
26- this.actor.incrementTicks(1)
27- const cap = message.caps.pop()
28- if (cap) {
29- return this.actor.send(cap, message)
24+ })
25+ }
26+ static instance (actor) {
27+ return {
28+ exports: this.functions(actor)
29+ }
30+ }
31+ static functions (actor) {
32+ return {
33+ onMessage: function () {
34+ const refs = [...arguments]
35+ const ref = refs.pop()
36+ // console.log('run queue', this.actor.inbox._queue)
37+ // console.log('from', message._fromId.toString('hex'), 'to: ', this.actor.id.toString('hex'), this.actor.ticks, message._fromTicks)
38+ // const last = messageOrder[actor.id.toString('hex')]
39+ // const message = actor.currentMessage
40+ // if (last && last > message._fromTicks) {
41+ // console.log(last, message._fromTicks)
42+ // // console.log(this.actor.hypervisor.scheduler.instances)
43+ // }
44+ // messageOrder[actor.id.toString('hex')] = message._fromTicks
45+ numOfMsg++
46+ actor.incrementTicks(10)
47+ if (ref) {
48+ return actor.send(new Message({
49+ funcRef: ref,
50+ funcArguments: refs
51+ }))
52+ }
3053 }
3154 }
32- static get typeId () {
33- return 9
34- }
3555 }
56+}
3657
58+async function main (numOfActors, depth) {
3759 const tree = new RadixTree({
3860 db: db
3961 })
4062
4163 const hypervisor = new Hypervisor(tree)
4264 hypervisor.registerContainer(BenchmarkContainer)
4365
44- const caps = []
66+ const refernces = []
4567 let _numOfActors = numOfActors
4668 while (_numOfActors--) {
47- const cap = await hypervisor.createActor(BenchmarkContainer.typeId, new Message())
48- caps.push(cap)
69+ const {exports} = await hypervisor.createActor(BenchmarkContainer.typeId)
70+ refernces.push(exports[0])
4971 }
72+ // console.log(refernces)
5073 _numOfActors = numOfActors
5174 let msgs = []
5275 while (_numOfActors--) {
53- const message = new Message()
54- msgs.push(message)
5576 let _depth = depth
77+ const funcArguments = []
5678 while (_depth--) {
5779 const r = Math.floor(Math.random() * numOfActors)
58- const cap = caps[r]
59- message.caps.push(cap)
80+ const ref = refernces[r]
81+ funcArguments.push(ref)
6082 }
83+ const message = new Message({
84+ funcArguments,
85+ funcRef: refernces[_numOfActors]
86+ })
87+ msgs.push(message)
6188 }
6289
6390 let start = new Date()
64- // hypervisor.scheduler.lock(Buffer.from([0xff]))
65- msgs.forEach((msg, index) => {
66- hypervisor.send(caps[index], msg)
67- })
91+ await Promise.all(msgs.map((msg) => hypervisor.send(msg)))
6892 console.log('done sending')
6993 await hypervisor.scheduler.wait(Infinity)
70- // console.log(JSON.stringify(hypervisor.tree.root, null ,2))
7194 const end = new Date() - start
7295 console.info('Execution time: %dms', end)
7396 console.log('messages processed', numOfActors * depth + numOfActors)
7497 console.log('messages processed', numOfMsg)
7598 }
7699
77-main(55, 10)
100+main(1000, 10)
inbox.jsView
@@ -7,8 +7,9 @@
77 if (messageA._fromTicks !== messageB._fromTicks) {
88 return messageA._fromTicks > messageB._fromTicks
99 } else {
1010 // sender id
11+ // console.log('here')
1112 return Buffer.compare(messageA._fromId, messageB._fromId)
1213 }
1314 }
1415
@@ -23,9 +24,8 @@
2324 constructor (opts) {
2425 this.actor = opts.actor
2526 this.hypervisor = opts.hypervisor
2627 this._queue = []
27- this._waitingTagsQueue = []
2828 this._oldestMessagePromise = new Promise((resolve, reject) => {
2929 this._oldestMessageResolve = resolve
3030 })
3131 }
@@ -50,56 +50,18 @@
5050 }
5151 }
5252
5353 /**
54- * Waits for a message sent with a capablitly that has one of the given tags
55- * @param {Array<*>} tags
56- * @param {Integer} timeout
57- * @returns {Promise}
58- */
59- async nextTaggedMessage (tags, timeout) {
60- this._waitingTags = new Set(tags)
61- this._queue = this._queue.filter(message => !this._queueTaggedMessage(message))
62-
63- // todo: add saturation test
64- const message = await this.nextMessage(timeout)
65- delete this._waitingTags
66- this._waitingTagsQueue.forEach(message => this._queueMessage(message))
67- this._waitingTagsQueue = []
68-
69- return message
70- }
71-
72- /**
7354 * Waits for the the next message if any
7455 * @param {Integer} timeout
7556 * @returns {Promise}
7657 */
77- async nextMessage (timeout) {
78- if (!this._gettingNextMessage) {
79- this._gettingNextMessage = true
80- } else {
81- throw new Error('already waiting for next message')
82- }
83-
58+ async nextMessage () {
8459 let message = this._getOldestMessage()
85- if (message) {
86- timeout = message._fromTicks
87- } else {
88- timeout += this.actor.ticks
89- }
90-
60+ let timeout = message._fromTicks
9161 let oldestTime = this.hypervisor.scheduler.leastNumberOfTicks(this.actor.id)
9262
9363 while (true) {
94- if (message) {
95- // if there is a message that is "older" then the timeout, the lower
96- // the timeout to the oldest message
97- if (message._fromTicks < timeout) {
98- timeout = message._fromTicks
99- }
100- }
101-
10264 // if all actors are "older" then the time out then stop waiting for messages
10365 // since we konw that we can not receive one
10466 if (oldestTime >= timeout) {
10567 break
@@ -110,20 +72,23 @@
11072 message = this._getOldestMessage()
11173 }),
11274 this._olderMessage(message).then(m => {
11375 message = m
76+ // if there is a message that is "older" then the timeout, the lower
77+ // the timeout to the oldest message
78+ timeout = message._fromTicks
11479 })
11580 ])
11681 oldestTime = this.hypervisor.scheduler.leastNumberOfTicks(this.actor.id)
11782 }
118- this._gettingNextMessage = false
83+ message = this._deQueueMessage()
11984 // if the message we recived had more ticks then we currently have then
12085 // update our ticks to it, since we jumped forward in time
12186 if (message && message._fromTicks > this.actor.ticks) {
12287 this.actor.ticks = message._fromTicks
12388 this.hypervisor.scheduler.update(this.actor)
12489 }
125- return this._deQueueMessage()
90+ return message
12691 }
12792
12893 // returns a promise that resolve when a message older then the given message
12994 // is recived
@@ -131,35 +96,15 @@
13196 return this._oldestMessagePromise
13297 }
13398
13499 _getOldestMessage () {
135- if (this._waitingTags) {
136- return this._waitingTagsQueue[0]
137- } else {
138- return this._queue[0]
139- }
100+ return this._queue[0]
140101 }
141102
142103 _deQueueMessage () {
143- if (this._waitingTags) {
144- return this._waitingTagsQueue.shift()
145- } else {
146- return this._queue.shift()
147- }
104+ return this._queue.shift()
148105 }
149106
150107 _queueMessage (message) {
151- if (!(this._waitingTags && this._queueTaggedMessage(message))) {
152- binarySearchInsert(this._queue, messageArbiter, message)
153- }
108+ binarySearchInsert(this._queue, messageArbiter, message)
154109 }
155-
156- _queueTaggedMessage (message) {
157- if (this._waitingTags.has(message.tag)) {
158- this._waitingTags.delete(message.tag)
159- binarySearchInsert(this._waitingTagsQueue, messageArbiter, message)
160- return true
161- } else {
162- return false
163- }
164- }
165110 }
index.jsView
@@ -19,11 +19,10 @@
1919 * @param {Object} cap - the capabilitly used to send the message
2020 * @param {Object} message - the [message](https://github.com/primea/js-primea-message) to send
2121 * @returns {Promise} a promise that resolves once the receiving container is loaded
2222 */
23- async send (cap, message) {
24- message.tag = cap.tag
25- const id = cap.destId
23+ async send (message) {
24+ const id = message.funcRef.destId
2625 const instance = await this.getActor(id)
2726 instance.queue(message)
2827 }
2928
@@ -42,8 +41,9 @@
4241 nonce,
4342 type
4443 })
4544
45+ await actor.startup()
4646 // save the newly created instance
4747 this.scheduler.update(actor)
4848 return actor
4949 }
@@ -57,9 +57,8 @@
5757 let actor = this.scheduler.getInstance(id)
5858 if (!actor) {
5959 const resolve = this.scheduler.lock(id)
6060 actor = await this._loadActor(id)
61- await actor.startup()
6261 resolve(actor)
6362 }
6463 return actor
6564 }
@@ -69,22 +68,22 @@
6968 * @param {Integer} type - the type id for the container
7069 * @param {Object} message - an intial [message](https://github.com/primea/js-primea-message) to send newly created actor
7170 * @param {Object} id - the id for the actor
7271 */
73- async createActor (type, message, id = {nonce: this.nonce++, parent: null}) {
72+ async createActor (type, code, id = {nonce: this.nonce++, parent: null}) {
7473 const encoded = encodedID(id)
7574 const idHash = await this._getHashFromObj(encoded)
7675 const metaData = Actor.serializeMetaData(type)
7776
7877 // save the container in the state
7978 this.tree.set(idHash, metaData)
80-
81- // create the container instance
82- const instance = await this._loadActor(idHash)
83-
84- // send the intialization message
85- instance.create(message)
86- return instance.mintCap()
79+ const Container = this._containerTypes[type]
80+ await Container.validate(code)
81+ const module = await Container.compile(code)
82+ return {
83+ id: idHash,
84+ exports: Container.exports(module, idHash)
85+ }
8786 }
8887
8988 // get a hash from a POJO
9089 _getHashFromObj (obj) {
@@ -107,13 +106,10 @@
107106 * @param {Class} Constructor - a Class for instantiating the container
108107 * @param {*} args - any args that the contructor takes
109108 * @param {Integer} typeId - the container's type identification ID
110109 */
111- registerContainer (Constructor, args, typeId = Constructor.typeId) {
112- this._containerTypes[typeId] = {
113- Constructor,
114- args
115- }
110+ registerContainer (Constructor) {
111+ this._containerTypes[Constructor.typeId] = Constructor
116112 }
117113 }
118114
119115 function encodedID (id) {
package.jsonView
@@ -32,8 +32,9 @@
3232 "license": "MPL-2.0",
3333 "dependencies": {
3434 "binary-search-insert": "^1.0.3",
3535 "buffer-pipe": "0.0.2",
36+ "events": "^1.1.1",
3637 "leb128": "0.0.4",
3738 "primea-capability": "0.0.1",
3839 "primea-message": "0.6.1",
3940 "safe-buffer": "^5.1.1",
scheduler.jsView
@@ -111,8 +111,9 @@
111111 // checks outstanding waits to see if they can be resolved
112112 _checkWaits () {
113113 // if there are no instances, clear any remaining waits
114114 if (!this.instances.size) {
115+ // console.log('here', this._waits)
115116 this._waits.forEach(wait => wait.resolve())
116117 this._waits = []
117118 return
118119 }
tests/index.jsView
@@ -1,23 +1,36 @@
11 const tape = require('tape')
2-const AbstractContainer = require('primea-abstract-container')
3-const Message = require('primea-message')
2+const Message = require('../message.js')
43 const Hypervisor = require('../')
54
65 const level = require('level-browserify')
76 const RadixTree = require('dfinity-radix-tree')
87 const db = level('./testdb')
98
10-class BaseContainer extends AbstractContainer {
11- onCreation () {}
9+class BaseContainer {
10+ static validate () {}
11+ static compile () {}
1212 static get typeId () {
1313 return 9
1414 }
15+
16+ static exports (m, id) {
17+ return Object.keys(this.functions()).map(name => {
18+ return {
19+ name,
20+ destId: id
21+ }
22+ })
23+ }
24+ static instance (actor) {
25+ return {
26+ exports: this.functions(actor)
27+ }
28+ }
1529 }
1630
1731 tape('basic', async t => {
1832 t.plan(2)
19- let message
2033 const expectedState = {
2134 '/': Buffer.from('926de6b7eb39cfa8d7f8a44d1ef191d3bcb765a7', 'hex')
2235 }
2336
@@ -25,28 +38,34 @@
2538 db: db
2639 })
2740
2841 class testVMContainer extends BaseContainer {
29- onMessage (m, tag) {
30- t.true(m === message, 'should recive a message')
42+ static functions () {
43+ return {
44+ onMessage: (m) => {
45+ t.true(m === 1, 'should recive a message')
46+ }
47+ }
3148 }
3249 }
3350
3451 const hypervisor = new Hypervisor(tree)
3552 hypervisor.registerContainer(testVMContainer)
3653
37- let rootCap = await hypervisor.createActor(testVMContainer.typeId, new Message())
54+ let {exports} = await hypervisor.createActor(testVMContainer.typeId)
3855
39- message = new Message()
40- hypervisor.send(rootCap, message)
56+ const message = new Message({
57+ funcRef: exports[0],
58+ funcArguments: [1]
59+ })
60+ hypervisor.send(message)
4161
4262 const stateRoot = await hypervisor.createStateRoot()
4363 t.deepEquals(stateRoot, expectedState, 'expected root!')
4464 })
4565
4666 tape('two communicating actors', async t => {
4767 t.plan(2)
48- let message
4968 const expectedState = {
5069 '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex')
5170 }
5271
@@ -54,17 +73,28 @@
5473 db: db
5574 })
5675
5776 class testVMContainerA extends BaseContainer {
58- onCreation (m) {
59- message = new Message()
60- this.actor.send(m.caps[0], message)
77+ static functions (actor) {
78+ return {
79+ onMessage: (funcRef) => {
80+ const message = new Message({
81+ funcRef: funcRef,
82+ funcArguments: [2]
83+ })
84+ return actor.send(message)
85+ }
86+ }
6187 }
6288 }
6389
6490 class testVMContainerB extends BaseContainer {
65- onMessage (m) {
66- t.true(m === message, 'should recive a message')
91+ static functions () {
92+ return {
93+ onMessage: (args) => {
94+ t.true(args === 2, 'should recive a message')
95+ }
96+ }
6797 }
6898
6999 static get typeId () {
70100 return 8
@@ -74,20 +104,23 @@
74104 const hypervisor = new Hypervisor(tree)
75105 hypervisor.registerContainer(testVMContainerA)
76106 hypervisor.registerContainer(testVMContainerB)
77107
78- let capB = await hypervisor.createActor(testVMContainerB.typeId, new Message())
79- await hypervisor.createActor(testVMContainerA.typeId, new Message({
80- caps: [capB]
81- }))
108+ const {exports: exportsB} = await hypervisor.createActor(testVMContainerB.typeId)
109+ const {exports: exportsA} = await hypervisor.createActor(testVMContainerA.typeId)
110+ const message = new Message({
111+ funcRef: exportsA[0],
112+ funcArguments: [exportsB[0]]
113+ })
82114
115+ await hypervisor.send(message)
116+
83117 const stateRoot = await hypervisor.createStateRoot()
84118 t.deepEquals(stateRoot, expectedState, 'expected root!')
85119 })
86120
87121 tape('three communicating actors', async t => {
88122 t.plan(3)
89- let message
90123 const expectedState = {
91124 '/': Buffer.from('4633ac4b9f8212e501b6c56906039ec081fbe5a3', 'hex')
92125 }
93126
@@ -95,17 +128,28 @@
95128 db: db
96129 })
97130
98131 class testVMContainerA extends BaseContainer {
99- onCreation (m) {
100- message = new Message()
101- this.actor.send(m.caps[0], message)
132+ static functions (actor) {
133+ return {
134+ onMessage: (funcRef) => {
135+ const message = new Message({
136+ funcRef: funcRef,
137+ funcArguments: [2]
138+ })
139+ actor.send(message)
140+ }
141+ }
102142 }
103143 }
104144
105145 class testVMContainerB extends BaseContainer {
106- onMessage (m) {
107- t.true(m === message, 'should recive a message')
146+ static functions () {
147+ return {
148+ onMessage: (arg) => {
149+ t.equals(arg, 2, 'should recive a message')
150+ }
151+ }
108152 }
109153
110154 static get typeId () {
111155 return 8
@@ -115,46 +159,61 @@
115159 const hypervisor = new Hypervisor(tree)
116160 hypervisor.registerContainer(testVMContainerA)
117161 hypervisor.registerContainer(testVMContainerB)
118162
119- let capB = await hypervisor.createActor(testVMContainerB.typeId, new Message())
120- await hypervisor.createActor(testVMContainerA.typeId, new Message({
121- caps: [capB]
122- }))
163+ let {exports: exportsB} = await hypervisor.createActor(testVMContainerB.typeId)
164+ let {exports: exportsA0} = await hypervisor.createActor(testVMContainerA.typeId)
165+ let {exports: exportsA1} = await hypervisor.createActor(testVMContainerA.typeId)
123166
124- await hypervisor.createActor(testVMContainerA.typeId, new Message({
125- caps: [capB]
126- }))
167+ const message0 = new Message({
168+ funcRef: exportsA0[0],
169+ funcArguments: [exportsB[0]]
170+ })
127171
172+ const message1 = new Message({
173+ funcRef: exportsA1[0],
174+ funcArguments: [exportsB[0]]
175+ })
176+
177+ await hypervisor.send(message0)
178+ await hypervisor.send(message1)
179+
128180 const stateRoot = await hypervisor.createStateRoot()
129181 t.deepEquals(stateRoot, expectedState, 'expected root!')
130182 })
131183
132184 tape('three communicating actors, with tick counting', async t => {
133185 t.plan(3)
134- let message
135186 const expectedState = {
136187 '/': Buffer.from('4633ac4b9f8212e501b6c56906039ec081fbe5a3', 'hex')
137188 }
138189
139190 const tree = new RadixTree({
140191 db: db
141192 })
142193
143- let ticks = 1
144-
145194 class testVMContainerA extends BaseContainer {
146- async onCreation (m) {
147- this.actor.incrementTicks(ticks)
148- ticks++
149- message = new Message()
150- this.actor.send(m.caps[0], message)
195+ static functions (actor) {
196+ return {
197+ onMessage: funcRef => {
198+ actor.incrementTicks(1)
199+ const message = new Message({
200+ funcRef: funcRef,
201+ funcArguments: [2]
202+ })
203+ actor.send(message)
204+ }
205+ }
151206 }
152207 }
153208
154209 class testVMContainerB extends BaseContainer {
155- onMessage (m) {
156- t.true(m, 'should recive a message')
210+ static functions (actor) {
211+ return {
212+ onMessage: arg => {
213+ t.equals(arg, 2, 'should recive a message')
214+ }
215+ }
157216 }
158217
159218 static get typeId () {
160219 return 8
@@ -164,25 +223,31 @@
164223 const hypervisor = new Hypervisor(tree)
165224 hypervisor.registerContainer(testVMContainerA)
166225 hypervisor.registerContainer(testVMContainerB)
167226
168- let capB = await hypervisor.createActor(testVMContainerB.typeId, new Message())
169- await hypervisor.createActor(testVMContainerA.typeId, new Message({
170- caps: [capB]
171- }))
227+ let actorB = await hypervisor.createActor(testVMContainerB.typeId)
228+ let actorA0 = await hypervisor.createActor(testVMContainerA.typeId)
229+ let actorA1 = await hypervisor.createActor(testVMContainerA.typeId)
172230
173- await hypervisor.createActor(testVMContainerA.typeId, new Message({
174- caps: [capB]
175- }))
231+ const message0 = new Message({
232+ funcRef: actorA0.exports[0],
233+ funcArguments: [actorB.exports[0]]
234+ })
176235
236+ const message1 = new Message({
237+ funcRef: actorA1.exports[0],
238+ funcArguments: actorB.exports
239+ })
240+
241+ hypervisor.send(message0)
242+ hypervisor.send(message1)
243+
177244 const stateRoot = await hypervisor.createStateRoot()
178-
179245 t.deepEquals(stateRoot, expectedState, 'expected root!')
180246 })
181247
182248 tape('errors', async t => {
183249 t.plan(3)
184- let message
185250 const expectedState = {
186251 '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex')
187252 }
188253
@@ -190,21 +255,31 @@
190255 db: db
191256 })
192257
193258 class testVMContainerA extends BaseContainer {
194- onCreation (m) {
195- message = new Message()
196- message.on('execution:error', () => {
197- t.pass('should recive a exeption')
198- })
199- this.actor.send(m.caps[0], message)
259+ static functions (actor) {
260+ return {
261+ onMessage: funcRef => {
262+ const message = new Message({
263+ funcRef
264+ })
265+ message.on('execution:error', () => {
266+ t.pass('should recive a exeption')
267+ })
268+ actor.send(message)
269+ }
270+ }
200271 }
201272 }
202273
203274 class testVMContainerB extends BaseContainer {
204- onMessage (m) {
205- t.true(m === message, 'should recive a message')
206- throw new Error('test error')
275+ static functions (actor) {
276+ return {
277+ onMessage: funcRef => {
278+ t.true(true, 'should recive a message')
279+ throw new Error('test error')
280+ }
281+ }
207282 }
208283
209284 static get typeId () {
210285 return 8
@@ -214,20 +289,21 @@
214289 const hypervisor = new Hypervisor(tree)
215290 hypervisor.registerContainer(testVMContainerA)
216291 hypervisor.registerContainer(testVMContainerB)
217292
218- let capB = await hypervisor.createActor(testVMContainerB.typeId, new Message())
219- await hypervisor.createActor(testVMContainerA.typeId, new Message({
220- caps: [capB]
221- }))
222-
293+ let {exports: exportsB} = await hypervisor.createActor(testVMContainerB.typeId)
294+ let {exports: exportsA} = await hypervisor.createActor(testVMContainerA.typeId)
295+ const message = new Message({
296+ funcRef: exportsA[0],
297+ funcArguments: exportsB
298+ })
299+ hypervisor.send(message)
223300 const stateRoot = await hypervisor.createStateRoot()
224301 t.deepEquals(stateRoot, expectedState, 'expected root!')
225302 })
226303
227304 tape('actor creation', async t => {
228305 t.plan(2)
229- let message
230306 const expectedState = {
231307 '/': Buffer.from('f47377a763c91247e62138408d706a09bccaaf36', 'hex')
232308 }
233309
@@ -235,24 +311,32 @@
235311 db: db
236312 })
237313
238314 class testVMContainerA extends BaseContainer {
239- onCreation (m) {
240- message = new Message()
241- const cap = this.actor.mintCap()
242- message.caps.push(cap)
243- return this.actor.createActor(testVMContainerB.typeId, message)
315+ static functions (actor) {
316+ return {
317+ onCreation: async funcRef => {
318+ const {exports} = await actor.createActor(testVMContainerB.typeId)
319+ const message = new Message({
320+ funcRef: exports[0],
321+ funcArguments: [actor.getFuncRef('onMessage')]
322+ })
323+ actor.send(message)
324+ },
325+ onMessage: data => {
326+ t.equals(data, 'test', 'should recive a response message')
327+ }
328+ }
244329 }
245-
246- onMessage (m) {
247- t.equals(m.data, 'test', 'should recive a response message')
248- }
249330 }
250331
251332 class testVMContainerB extends BaseContainer {
252- onCreation (m) {
253- const cap = m.caps[0]
254- this.actor.send(cap, new Message({data: 'test'}))
333+ static functions (actor) {
334+ return {
335+ onCreation: funcRef => {
336+ actor.send(new Message({funcRef, funcArguments: ['test']}))
337+ }
338+ }
255339 }
256340
257341 static get typeId () {
258342 return 8
@@ -262,9 +346,10 @@
262346 const hypervisor = new Hypervisor(tree)
263347 hypervisor.registerContainer(testVMContainerA)
264348 hypervisor.registerContainer(testVMContainerB)
265349
266- await hypervisor.createActor(testVMContainerA.typeId, new Message())
350+ const {exports} = await hypervisor.createActor(testVMContainerA.typeId)
351+ await hypervisor.send(new Message({funcRef: exports[0]}))
267352
268353 const stateRoot = await hypervisor.createStateRoot()
269354 t.deepEquals(stateRoot, expectedState, 'expected root!')
270355 })
@@ -279,38 +364,50 @@
279364 db: db
280365 })
281366
282367 class testVMContainerA extends BaseContainer {
283- onCreation (m) {
284- const message1 = new Message({
285- data: 'first'
286- })
287- const message2 = new Message({
288- data: 'second'
289- })
290- const message3 = new Message({
291- data: 'third'
292- })
293- this.actor.send(m.caps[0], message1)
294- this.actor.incrementTicks(1)
295- this.actor.send(m.caps[0], message2)
296- this.actor.incrementTicks(1)
297- this.actor.send(m.caps[0], message3)
368+ static functions (actor) {
369+ return {
370+ onCreation: funcRef => {
371+ const message1 = new Message({
372+ funcArguments: ['first'],
373+ funcRef
374+ })
375+ const message2 = new Message({
376+ funcArguments: ['second'],
377+ funcRef
378+ })
379+ const message3 = new Message({
380+ funcArguments: ['third'],
381+ funcRef
382+ })
383+ actor.send(message1)
384+ actor.incrementTicks(1)
385+ actor.send(message2)
386+ actor.incrementTicks(1)
387+ actor.send(message3)
388+ }
389+ }
298390 }
299391 }
300392
301393 let recMsg = 0
302394
303395 class testVMContainerB extends BaseContainer {
304- onMessage (m) {
305- if (recMsg === 0) {
306- t.equal(m.data, 'first', 'should recive fist message')
307- } else if (recMsg === 1) {
308- t.equal(m.data, 'second', 'should recive second message')
309- } else {
310- t.equal(m.data, 'third', 'should recive third message')
396+ static functions (actor) {
397+ return {
398+ onMessage: data => {
399+ actor.incrementTicks(1)
400+ if (recMsg === 0) {
401+ t.equal(data, 'first', 'should recive fist message')
402+ } else if (recMsg === 1) {
403+ t.equal(data, 'second', 'should recive second message')
404+ } else {
405+ t.equal(data, 'third', 'should recive third message')
406+ }
407+ recMsg++
408+ }
311409 }
312- recMsg++
313410 }
314411
315412 static get typeId () {
316413 return 8
@@ -320,12 +417,15 @@
320417 const hypervisor = new Hypervisor(tree)
321418 hypervisor.registerContainer(testVMContainerA)
322419 hypervisor.registerContainer(testVMContainerB)
323420
324- let capB = await hypervisor.createActor(testVMContainerB.typeId, new Message())
325- await hypervisor.createActor(testVMContainerA.typeId, new Message({
326- caps: [capB]
327- }))
421+ const {exports: exportsB} = await hypervisor.createActor(testVMContainerB.typeId)
422+ const {exports: exportsA} = await hypervisor.createActor(testVMContainerA.typeId)
423+ const message = new Message({
424+ funcRef: exportsA[0],
425+ funcArguments: exportsB
426+ })
427+ hypervisor.send(message)
328428
329429 const stateRoot = await hypervisor.createStateRoot()
330430 t.deepEquals(stateRoot, expectedState, 'expected root!')
331431 })
@@ -341,28 +441,38 @@
341441 db: db
342442 })
343443
344444 class testVMContainerA extends BaseContainer {
345- onCreation (m) {
346- message = new Message({
347- data: m.data
348- })
349- this.actor.send(m.caps[0], message)
445+ static functions (actor) {
446+ return {
447+ onCreation: (funcRef, funcArguments) => {
448+ actor.incrementTicks(1)
449+ message = new Message({
450+ funcRef,
451+ funcArguments: [funcArguments]
452+ })
453+ return actor.send(message)
454+ }
455+ }
350456 }
351457 }
352458
353459 let recMsg = 0
354460
355461 class testVMContainerB extends BaseContainer {
356- onMessage (m) {
357- if (recMsg === 0) {
358- t.equal(m.data, 'first', 'should recive fist message')
359- } else if (recMsg === 1) {
360- t.equal(m.data, 'second', 'should recive second message')
361- } else {
362- t.equal(m.data, 'third', 'should recive third message')
462+ static functions (actor) {
463+ return {
464+ onMessage: data => {
465+ if (recMsg === 0) {
466+ t.equal(data, 'first', 'should recive fist message')
467+ } else if (recMsg === 1) {
468+ t.equal(data, 'second', 'should recive second message')
469+ } else {
470+ t.equal(data, 'third', 'should recive third message')
471+ }
472+ recMsg++
473+ }
363474 }
364- recMsg++
365475 }
366476
367477 static get typeId () {
368478 return 8
@@ -372,354 +482,93 @@
372482 const hypervisor = new Hypervisor(tree)
373483 hypervisor.registerContainer(testVMContainerA)
374484 hypervisor.registerContainer(testVMContainerB)
375485
376- let capB = await hypervisor.createActor(testVMContainerB.typeId, new Message())
377- hypervisor.send(capB, new Message({
378- data: 'first'
486+ let {exports: exportsB} = await hypervisor.createActor(testVMContainerB.typeId)
487+ hypervisor.send(new Message({
488+ funcRef: exportsB[0],
489+ funcArguments: ['first']
379490 }))
380491
381- await hypervisor.createActor(testVMContainerA.typeId, new Message({
382- caps: [capB],
383- data: 'second'
492+ const {exports: exportsA0} = await hypervisor.createActor(testVMContainerA.typeId)
493+
494+ hypervisor.send(new Message({
495+ funcRef: exportsA0[0],
496+ funcArguments: [exportsB[0], 'second']
384497 }))
385498
386- await hypervisor.createActor(testVMContainerA.typeId, new Message({
387- caps: [capB],
388- data: 'third'
499+ const {exports: exportsA1} = await hypervisor.createActor(testVMContainerA.typeId)
500+ hypervisor.send(new Message({
501+ funcRef: exportsA1[0],
502+ funcArguments: [exportsB[0], 'third']
389503 }))
390504
391505 const stateRoot = await hypervisor.createStateRoot()
392506 t.deepEquals(stateRoot, expectedState, 'expected root!')
393507 })
394508
395-tape('basic tagged caps', async t => {
396- t.plan(4)
397- const expectedState = {
398- '/': Buffer.from('b8eb399087a990e30373e954b627a9512c9af40b', 'hex')
399- }
400-
509+tape('random', async t => {
510+ const numOfActors = 10
511+ const depth = 10
512+ const messageOrder = {}
513+ let numOfMsg = 0
401514 const tree = new RadixTree({
402515 db: db
403516 })
404517
405- class testVMContainerA extends BaseContainer {
406- async onMessage (m) {
407- t.true(m, 'should recive first message')
408- const rCap = this.actor.mintCap(1)
409- const message = new Message({caps: [rCap]})
410- this.actor.send(m.caps[0], message)
411- const rMessage = await this.actor.inbox.nextTaggedMessage([1], 44)
412- t.true(rMessage, 'should recive a response message')
413- }
414- }
415-
416- class testVMContainerB extends BaseContainer {
417- onMessage (m) {
418- t.true(m, 'should recive a message')
419- this.actor.send(m.caps[0], new Message())
420- }
421-
422- static get typeId () {
423- return 8
424- }
425- }
426-
427- const hypervisor = new Hypervisor(tree)
428- hypervisor.registerContainer(testVMContainerA)
429- hypervisor.registerContainer(testVMContainerB)
430-
431- let capA = await hypervisor.createActor(testVMContainerA.typeId, new Message())
432- let capB = await hypervisor.createActor(testVMContainerB.typeId, new Message())
433-
434- hypervisor.send(capA, new Message({caps: [capB]}))
435-
436- const stateRoot = await hypervisor.createStateRoot()
437- t.deepEquals(stateRoot, expectedState, 'expected root!')
438-})
439-
440-tape('trying to listen for caps more then once', async t => {
441- t.plan(4)
442- const expectedState = {
443- '/': Buffer.from('b8eb399087a990e30373e954b627a9512c9af40b', 'hex')
444- }
445-
446- const tree = new RadixTree({
447- db: db
448- })
449-
450- class testVMContainerA extends BaseContainer {
451- async onMessage (m) {
452- t.true(m, 'should recive first message')
453- const message = new Message({data: 'first'})
454- this.actor.send(m.caps[0], message)
455- const promise = this.actor.inbox.nextTaggedMessage([1], 44)
456- try {
457- await this.actor.inbox.nextTaggedMessage([1], 44)
458- } catch (e) {
459- t.true(e, 'should error if waiting twice')
518+ class BenchmarkContainer extends BaseContainer {
519+ static functions (actor) {
520+ return {
521+ onMessage: function () {
522+ const refs = [...arguments]
523+ const ref = refs.pop()
524+ const last = messageOrder[actor.id.toString('hex')]
525+ const message = actor.currentMessage
526+ if (last) {
527+ t.ok(last <= message._fromTicks)
528+ }
529+ messageOrder[actor.id.toString('hex')] = message._fromTicks
530+ numOfMsg++
531+ actor.incrementTicks(10)
532+ if (ref) {
533+ return actor.send(new Message({
534+ funcRef: ref,
535+ funcArguments: refs
536+ }))
537+ }
538+ }
460539 }
461- return promise
462540 }
463541 }
464542
465- class testVMContainerB extends BaseContainer {
466- onMessage (m) {
467- t.true(m, 'should recive a message')
468- }
469-
470- static get typeId () {
471- return 8
472- }
473- }
474-
475543 const hypervisor = new Hypervisor(tree)
476- hypervisor.registerContainer(testVMContainerA)
477- hypervisor.registerContainer(testVMContainerB)
544+ hypervisor.registerContainer(BenchmarkContainer)
478545
479- let capA = await hypervisor.createActor(testVMContainerA.typeId, new Message())
480- let capB = await hypervisor.createActor(testVMContainerB.typeId, new Message())
481-
482- await hypervisor.send(capA, new Message({caps: [capB]}))
483-
484- const stateRoot = await hypervisor.createStateRoot()
485- t.deepEquals(stateRoot, expectedState, 'expected root!')
486-})
487-
488-tape('multple messages to restore on waiting for tags', async t => {
489- t.plan(6)
490- const expectedState = {
491- '/': Buffer.from('b2025e9430f0ce3a53767a36124fa622f782a38f', 'hex')
546+ const refernces = []
547+ let _numOfActors = numOfActors
548+ while (_numOfActors--) {
549+ const {exports} = await hypervisor.createActor(BenchmarkContainer.typeId)
550+ refernces.push(exports[0])
492551 }
493-
494- const tree = new RadixTree({
495- db: db
496- })
497-
498- class testVMContainerA extends BaseContainer {
499- async onMessage (m) {
500- t.true(m, 'should recive first message')
501- if (m.caps.length) {
502- const cap1 = this.actor.mintCap(1)
503- const cap2 = this.actor.mintCap(2)
504- const message1 = new Message({
505- data: 'first'
506- })
507- const message2 = new Message({
508- data: 'second'
509- })
510- message1.caps.push(cap1)
511- message2.caps.push(cap2)
512- this.actor.send(m.caps[0], message1)
513- this.actor.send(m.caps[1], message2)
514- const rMessage = await this.actor.inbox.nextTaggedMessage([1, 2], 44)
515- t.true(rMessage, 'should recive a response message')
516- }
552+ _numOfActors = numOfActors
553+ let msgs = []
554+ while (_numOfActors--) {
555+ let _depth = depth
556+ const funcArguments = []
557+ while (_depth--) {
558+ const r = Math.floor(Math.random() * numOfActors)
559+ const ref = refernces[r]
560+ funcArguments.push(ref)
517561 }
562+ const message = new Message({
563+ funcArguments,
564+ funcRef: refernces[_numOfActors]
565+ })
566+ msgs.push(message)
518567 }
519568
520- class testVMContainerB extends BaseContainer {
521- onMessage (m) {
522- t.true(m, 'should recive a message')
523- const cap = m.caps[0]
524- this.actor.incrementTicks(1)
525- this.actor.send(cap, new Message({data: m.data}))
526- }
527-
528- static get typeId () {
529- return 8
530- }
531- }
532-
533- const hypervisor = new Hypervisor(tree)
534- hypervisor.registerContainer(testVMContainerA)
535- hypervisor.registerContainer(testVMContainerB)
536-
537- let capA = await hypervisor.createActor(testVMContainerA.typeId, new Message())
538- let capB1 = await hypervisor.createActor(testVMContainerB.typeId, new Message())
539- let capB2 = await hypervisor.createActor(testVMContainerB.typeId, new Message())
540-
541- hypervisor.send(capA, new Message({caps: [capB1, capB2]}))
542-
543- const stateRoot = await hypervisor.createStateRoot()
544-
545- t.deepEquals(stateRoot, expectedState, 'expected root!')
569+ msgs.forEach(msg => hypervisor.send(msg))
570+ // console.log('here', numOfMsg)
571+ await hypervisor.scheduler.wait(Infinity)
572+ t.equals(numOfMsg, 110)
573+ t.end()
546574 })
547-
548-tape('multple messages to backup on waiting for tags', async t => {
549- t.plan(6)
550- const expectedState = {
551- '/': Buffer.from('b2025e9430f0ce3a53767a36124fa622f782a38f', 'hex')
552- }
553-
554- const tree = new RadixTree({
555- db: db
556- })
557-
558- class testVMContainerA extends BaseContainer {
559- async onMessage (m) {
560- t.true(m, 'should recive first message')
561- if (m.caps.length) {
562- const cap1 = this.actor.mintCap(1)
563- const cap2 = this.actor.mintCap(2)
564- const message1 = new Message({
565- data: 'first'
566- })
567- const message2 = new Message({
568- data: 'second'
569- })
570- message1.caps.push(cap1)
571- message2.caps.push(cap2)
572- this.actor.send(m.caps[0], message1)
573- this.actor.send(m.caps[1], message2)
574- const rMessage = await this.actor.inbox.nextTaggedMessage([1, 2], 44)
575- t.true(rMessage, 'should recive a response message')
576- }
577- }
578- }
579-
580- class testVMContainerB extends BaseContainer {
581- async onMessage (m) {
582- t.true(m, 'should recive a message')
583- const cap = m.caps[0]
584- this.actor.incrementTicks(1)
585- this.actor.send(cap, new Message({data: m.data}))
586- }
587-
588- static get typeId () {
589- return 8
590- }
591- }
592-
593- const hypervisor = new Hypervisor(tree)
594- hypervisor.registerContainer(testVMContainerA)
595- hypervisor.registerContainer(testVMContainerB)
596-
597- let capA = await hypervisor.createActor(testVMContainerA.typeId, new Message())
598- let capB1 = await hypervisor.createActor(testVMContainerB.typeId, new Message())
599- let capB2 = await hypervisor.createActor(testVMContainerB.typeId, new Message())
600-
601- hypervisor.send(capA, new Message({caps: [capB1, capB2]}))
602-
603- const stateRoot = await hypervisor.createStateRoot()
604- t.deepEquals(stateRoot, expectedState, 'expected root!')
605-})
606-
607-tape('multple messages, but single tag', async t => {
608- t.plan(6)
609- const expectedState = {
610- '/': Buffer.from('b2025e9430f0ce3a53767a36124fa622f782a38f', 'hex')
611- }
612-
613- const tree = new RadixTree({
614- db: db
615- })
616-
617- class testVMContainerA extends BaseContainer {
618- async onMessage (m) {
619- t.true(m, 'should recive first message')
620- if (m.caps.length) {
621- const cap1 = this.actor.mintCap(1)
622- const cap2 = this.actor.mintCap(2)
623- const message1 = new Message({
624- data: 'first'
625- })
626- const message2 = new Message({
627- data: 'second'
628- })
629- message1.caps.push(cap1)
630- message2.caps.push(cap2)
631- await this.actor.send(m.caps[0], message1)
632- await this.actor.send(m.caps[1], message2)
633- const rMessage = await this.actor.inbox.nextTaggedMessage([2], 44)
634- t.true(rMessage, 'should recive a response message')
635- }
636- }
637- }
638-
639- class testVMContainerB extends BaseContainer {
640- async onMessage (m) {
641- t.true(m, 'should recive a message')
642- const cap = m.caps[0]
643- this.actor.incrementTicks(1)
644- this.actor.send(cap, new Message({data: m.data}))
645- }
646-
647- static get typeId () {
648- return 8
649- }
650- }
651-
652- const hypervisor = new Hypervisor(tree)
653- hypervisor.registerContainer(testVMContainerA)
654- hypervisor.registerContainer(testVMContainerB)
655-
656- let capA = await hypervisor.createActor(testVMContainerA.typeId, new Message())
657- let capB1 = await hypervisor.createActor(testVMContainerB.typeId, new Message())
658- let capB2 = await hypervisor.createActor(testVMContainerB.typeId, new Message())
659-
660- hypervisor.send(capA, new Message({caps: [capB1, capB2]}))
661-
662- const stateRoot = await hypervisor.createStateRoot()
663- t.deepEquals(stateRoot, expectedState, 'expected root!')
664-})
665-
666-tape('deadlock test', async t => {
667- t.plan(7)
668- const expectedState = {
669- '/': Buffer.from('54f55756d0255d849e6878cc706f4c1565396e5c', 'hex')
670- }
671-
672- const tree = new RadixTree({
673- db: db
674- })
675-
676- class testVMContainerA extends BaseContainer {
677- async onMessage (m) {
678- t.true(m, 'should recive first message 1')
679- const rMessage = await this.actor.inbox.nextTaggedMessage([1], 50)
680- t.equals(rMessage, undefined, 'should recive a response message 1')
681- }
682- }
683-
684- class testVMContainerB extends BaseContainer {
685- async onMessage (m) {
686- t.true(m, 'should recive first message 2')
687- this.actor.incrementTicks(47)
688- const rMessage = await this.actor.inbox.nextTaggedMessage([1], 1)
689- t.equals(rMessage, undefined, 'should recive a response message 2')
690- }
691-
692- static get typeId () {
693- return 8
694- }
695- }
696-
697- class testVMContainerC extends BaseContainer {
698- async onMessage (m) {
699- t.true(m, 'should recive first message 3')
700- this.actor.incrementTicks(45)
701- const rMessage = await this.actor.inbox.nextTaggedMessage([1], 1)
702- t.equals(rMessage, undefined, 'should recive a response message 3')
703- }
704-
705- static get typeId () {
706- return 7
707- }
708- }
709-
710- const hypervisor = new Hypervisor(tree)
711- hypervisor.registerContainer(testVMContainerA)
712- hypervisor.registerContainer(testVMContainerB)
713- hypervisor.registerContainer(testVMContainerC)
714-
715- let capA = await hypervisor.createActor(testVMContainerA.typeId, new Message())
716- let capB = await hypervisor.createActor(testVMContainerB.typeId, new Message())
717- let capC = await hypervisor.createActor(testVMContainerC.typeId, new Message())
718-
719- hypervisor.send(capA, new Message())
720- hypervisor.send(capB, new Message())
721- hypervisor.send(capC, new Message())
722-
723- const stateRoot = await hypervisor.createStateRoot()
724- t.deepEquals(stateRoot, expectedState, 'expected root!')
725-})
message.jsView
@@ -1,0 +1,39 @@
1+const EventEmitter = require('events')
2+
3+/**
4+ * This implements Messages for Primea
5+ * @module primea-message
6+ */
7+module.exports = class Message extends EventEmitter {
8+ /**
9+ * @param {Object} opts
10+ * @param {ArrayBuffer} opts.data - the payload of the message
11+ * @param {Array<Object>} opts.caps - an array of capabilities to send in the message
12+ */
13+ constructor (opts) {
14+ super()
15+ const defaults = this.constructor.defaults
16+ this._opts = Object.assign(defaults, opts)
17+ Object.keys(this._opts).forEach(key => {
18+ Object.defineProperty(this, key, {
19+ get: function () {
20+ return this._opts[key]
21+ },
22+ set: function (y) {
23+ this._opts[key] = y
24+ }
25+ })
26+ })
27+ }
28+
29+ static get defaults () {
30+ return {
31+ ticks: 0,
32+ funcRef: null,
33+ funcArguments: [],
34+ funcParameters: [],
35+ _fromId: Buffer.alloc(20),
36+ _fromTicks: 0
37+ }
38+ }
39+}

Built with git-ssb-web