git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: dad0605968a7466f0c3307f31815166ff013d286

Files: dad0605968a7466f0c3307f31815166ff013d286 / tests / index.js

17946 bytesRaw
1const tape = require('tape')
2const Hypervisor = require('../')
3const errors = require('../errors.json')
4const {Message, FunctionRef, ModuleRef} = require('primea-objects')
5
6const level = require('level-browserify')
7const EgressDriver = require('../egressDriver')
8const RadixTree = require('dfinity-radix-tree')
9const db = level('./testdb')
10
11class BaseContainer {
12 constructor (actor) {
13 this.actor = actor
14 }
15 onStartup () {}
16 static onCreation (code, id) {
17 const exp = {}
18 Object.getOwnPropertyNames(this.prototype).filter(name => name !== 'constructor').forEach(name => {
19 exp[name] = {}
20 })
21 return new ModuleRef(exp, id)
22 }
23 onMessage (message) {
24 return this[message.funcRef.identifier[1]](...message.funcArguments)
25 }
26 static get typeId () {
27 return 9
28 }
29}
30
31tape('system objects', async t => {
32 t.plan(4)
33 const tree = new RadixTree({
34 db
35 })
36
37 let id
38 let mod
39 let funcref
40
41 class testVMContainer extends BaseContainer {
42 store () {
43 id = this.actor.id.id.toString('hex')
44 mod = new ModuleRef({'test': ['i32', 'i64']}, this.actor.id)
45 funcref = mod.getFuncRef('test')
46 this.actor.storage = [this.actor.id, {'/': 'test'}, mod, funcref]
47 }
48 load () {
49 const loadedID = this.actor.storage[0].id.toString('hex')
50 const link = this.actor.storage[1]
51 const loadedMod = this.actor.storage[2]
52 const loadedFuncref = this.actor.storage[3]
53 t.equals(id, loadedID, 'should load id correctly')
54 t.equals(link['/'].toString('hex'), '6fe3180f700090697285ac1e0e8dc400259373d7', 'should load link correctly')
55 t.deepEquals(loadedMod, mod)
56 t.deepEquals(funcref, loadedFuncref)
57 }
58 }
59
60 const hypervisor = new Hypervisor({tree, containers: [testVMContainer]})
61 const {module} = hypervisor.createActor(testVMContainer.typeId)
62 const message = new Message({
63 funcRef: module.getFuncRef('store')
64 })
65
66 hypervisor.send(message)
67 await hypervisor.createStateRoot()
68
69 const message2 = new Message({
70 funcRef: module.getFuncRef('load')
71 })
72 hypervisor.send(message2)
73 await hypervisor.createStateRoot()
74 t.end()
75})
76
77tape('basic', async t => {
78 t.plan(2)
79 const expectedState = Buffer.from('32b919149345b74e431c42a1b7dd65c30c625284', 'hex')
80 const tree = new RadixTree({
81 db
82 })
83
84 class testVMContainer extends BaseContainer {
85 main (m) {
86 t.equals(m, 1, 'should recive a message')
87 }
88 }
89
90 const hypervisor = new Hypervisor({tree, containers: [testVMContainer]})
91 await hypervisor.createStateRoot()
92
93 const {module} = hypervisor.createActor(testVMContainer.typeId)
94
95 const message = new Message({
96 funcRef: module.getFuncRef('main'),
97 funcArguments: [1]
98 })
99 hypervisor.send(message)
100
101 const stateRoot2 = await hypervisor.createStateRoot()
102 t.deepEquals(stateRoot2, expectedState, 'expected root!')
103})
104
105tape('two communicating actors', async t => {
106 t.plan(2)
107 const expectedState = Buffer.from('7f638e41261bc0238c3e9b34fce11827b6a3cb61', 'hex')
108
109 const tree = new RadixTree({
110 db
111 })
112
113 class testVMContainerA extends BaseContainer {
114 main (funcRef) {
115 const message = new Message({
116 funcRef,
117 funcArguments: [2]
118 })
119 return this.actor.send(message)
120 }
121 }
122
123 class testVMContainerB extends BaseContainer {
124 main (args) {
125 t.equals(args, 2, 'should recive a message')
126 }
127
128 static get typeId () {
129 return 8
130 }
131 }
132
133 const hypervisor = new Hypervisor({tree, containers: [testVMContainerA, testVMContainerB]})
134
135 const {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId)
136 const {module: moduleA} = hypervisor.createActor(testVMContainerA.typeId)
137
138 const message = new Message({
139 funcRef: moduleA.getFuncRef('main'),
140 funcArguments: [moduleB.getFuncRef('main')]
141 })
142
143 hypervisor.send(message)
144
145 const stateRoot = await hypervisor.createStateRoot()
146 t.deepEquals(stateRoot, expectedState, 'expected root!')
147})
148
149tape('three communicating actors', async t => {
150 t.plan(3)
151 const expectedState = Buffer.from('ae2e8afa84748192064ddebab30d0e9852ceb722', 'hex')
152 const tree = new RadixTree({
153 db: db
154 })
155
156 class testVMContainerA extends BaseContainer {
157 main (funcRef) {
158 const message = new Message({
159 funcRef: funcRef,
160 funcArguments: [2]
161 })
162 this.actor.send(message)
163 }
164 }
165
166 class testVMContainerB extends BaseContainer {
167 main (arg) {
168 t.equals(arg, 2, 'should recive a message')
169 }
170
171 static get typeId () {
172 return 8
173 }
174 }
175
176 const hypervisor = new Hypervisor({tree, containers: [testVMContainerA, testVMContainerB]})
177
178 let {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId)
179 let {module: moduleA0} = hypervisor.createActor(testVMContainerA.typeId)
180 let {module: moduleA1} = hypervisor.createActor(testVMContainerA.typeId)
181
182 const message0 = new Message({
183 funcRef: moduleA0.getFuncRef('main'),
184 funcArguments: [moduleB.getFuncRef('main')]
185 })
186
187 const message1 = new Message({
188 funcRef: moduleA1.getFuncRef('main'),
189 funcArguments: [moduleB.getFuncRef('main')]
190 })
191
192 await hypervisor.send(message0)
193 await hypervisor.send(message1)
194
195 const stateRoot = await hypervisor.createStateRoot()
196 t.deepEquals(stateRoot, expectedState, 'expected root!')
197})
198
199tape('three communicating actors, with tick counting', async t => {
200 t.plan(3)
201 const expectedState = Buffer.from('ae2e8afa84748192064ddebab30d0e9852ceb722', 'hex')
202 const tree = new RadixTree({
203 db: db
204 })
205
206 class testVMContainerA extends BaseContainer {
207 main (funcRef) {
208 this.actor.incrementTicks(1)
209 const message = new Message({
210 funcRef,
211 funcArguments: [2]
212 })
213 this.actor.send(message)
214 }
215 }
216
217 class testVMContainerB extends BaseContainer {
218 main (arg) {
219 t.equals(arg, 2, 'should recive a message')
220 }
221
222 static get typeId () {
223 return 8
224 }
225 }
226
227 const hypervisor = new Hypervisor({tree, containers: [testVMContainerA, testVMContainerB]})
228
229 let actorB = hypervisor.createActor(testVMContainerB.typeId)
230 let actorA0 = hypervisor.createActor(testVMContainerA.typeId)
231 let actorA1 = hypervisor.createActor(testVMContainerA.typeId)
232
233 const funcRef0 = actorA0.module.getFuncRef('main')
234 funcRef0.gas = 10000
235
236 const message0 = new Message({
237 funcRef: funcRef0,
238 funcArguments: [actorB.module.getFuncRef('main')]
239 })
240 const funcRef1 = actorA1.module.getFuncRef('main')
241 funcRef1.gas = 10000
242 const message1 = new Message({
243 funcRef: funcRef1,
244 funcArguments: [actorB.module.getFuncRef('main')]
245 })
246
247 hypervisor.send(message0)
248 hypervisor.send(message1)
249
250 const stateRoot = await hypervisor.createStateRoot()
251 t.deepEquals(stateRoot, expectedState, 'expected root!')
252})
253
254tape('errors', async t => {
255 t.plan(3)
256 const expectedState = Buffer.from('7f638e41261bc0238c3e9b34fce11827b6a3cb61', 'hex')
257 const tree = new RadixTree({
258 db
259 })
260
261 class testVMContainerA extends BaseContainer {
262 main (funcRef) {
263 const message = new Message({
264 funcRef
265 })
266 message.on('execution:error', () => {
267 t.pass('should recive a exeption')
268 })
269 this.actor.send(message)
270 }
271 }
272
273 class testVMContainerB extends BaseContainer {
274 main (funcRef) {
275 t.true(true, 'should recive a message')
276 throw new Error('test error')
277 }
278
279 static get typeId () {
280 return 8
281 }
282 }
283
284 const hypervisor = new Hypervisor({tree})
285 hypervisor.registerContainer(testVMContainerA)
286 hypervisor.registerContainer(testVMContainerB)
287
288 let {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId)
289 let {module: moduleA} = hypervisor.createActor(testVMContainerA.typeId)
290 const message = new Message({
291 funcRef: moduleA.getFuncRef('main'),
292 funcArguments: [moduleB.getFuncRef('main')]
293 })
294 hypervisor.send(message)
295 const stateRoot = await hypervisor.createStateRoot()
296 t.deepEquals(stateRoot, expectedState, 'expected root!')
297})
298
299tape('out-of-gas', async t => {
300 t.plan(1)
301 const tree = new RadixTree({
302 db
303 })
304
305 class testVMContainer extends BaseContainer {
306 main (m) {
307 this.actor.incrementTicks(1)
308 }
309 }
310
311 const hypervisor = new Hypervisor({tree, containers: [testVMContainer]})
312 await hypervisor.createStateRoot()
313
314 const {module} = hypervisor.createActor(testVMContainer.typeId)
315
316 const message = new Message({
317 funcRef: module.getFuncRef('main'),
318 funcArguments: [1]
319 }).on('execution:error', e => {
320 t.equals(e.message, errors.OUT_OF_GAS)
321 })
322 hypervisor.send(message)
323})
324
325tape('no mettering', async t => {
326 t.plan(1)
327 const tree = new RadixTree({
328 db
329 })
330
331 class testVMContainer extends BaseContainer {
332 main (m) {
333 this.actor.incrementTicks(1)
334 t.pass('shouldnt meter')
335 }
336 }
337
338 const hypervisor = new Hypervisor({
339 tree,
340 containers: [testVMContainer],
341 meter: false
342 })
343 await hypervisor.createStateRoot()
344
345 const {module} = hypervisor.createActor(testVMContainer.typeId)
346
347 const message = new Message({
348 funcRef: module.getFuncRef('main'),
349 funcArguments: [1]
350 })
351 hypervisor.send(message)
352})
353
354tape('actor creation', async t => {
355 t.plan(2)
356 const expectedState = Buffer.from('0e6d32f2fe8b5b99f0203eb46bfc7e319a07f700', 'hex')
357
358 const tree = new RadixTree({
359 db
360 })
361
362 class testVMContainerA extends BaseContainer {
363 async start (funcRef) {
364 const {module} = this.actor.createActor(testVMContainerB.typeId)
365 const message = new Message({
366 funcRef: module.getFuncRef('main'),
367 funcArguments: [{
368 identifier: [0, 'main'],
369 actorID: this.actor.id
370 }]
371 })
372 this.actor.send(message)
373 }
374 main (data) {
375 t.equals(data, 'test', 'should recive a response message')
376 }
377 }
378
379 class testVMContainerB extends BaseContainer {
380 main (funcRef) {
381 this.actor.send(new Message({funcRef, funcArguments: ['test']}))
382 }
383
384 static get typeId () {
385 return 8
386 }
387 }
388
389 const hypervisor = new Hypervisor({tree, containers: [testVMContainerA, testVMContainerB]})
390
391 const {module} = hypervisor.createActor(testVMContainerA.typeId)
392 await hypervisor.send(new Message({funcRef: module.getFuncRef('start')}))
393
394 const stateRoot = await hypervisor.createStateRoot()
395 t.deepEquals(stateRoot, expectedState, 'expected root!')
396 t.end()
397})
398
399tape('simple message arbiter test', async t => {
400 t.plan(4)
401 const expectedState = Buffer.from('7f638e41261bc0238c3e9b34fce11827b6a3cb61', 'hex')
402 const tree = new RadixTree({
403 db
404 })
405
406 class testVMContainerA extends BaseContainer {
407 main (funcRef) {
408 funcRef.gas = 1000
409 const message1 = new Message({
410 funcArguments: ['first'],
411 funcRef
412 })
413 const message2 = new Message({
414 funcArguments: ['second'],
415 funcRef
416 })
417 const message3 = new Message({
418 funcArguments: ['third'],
419 funcRef
420 })
421 this.actor.send(message1)
422 this.actor.incrementTicks(1)
423 this.actor.send(message2)
424 this.actor.incrementTicks(1)
425 this.actor.send(message3)
426 }
427 }
428
429 let recMsg = 0
430
431 class testVMContainerB extends BaseContainer {
432 main (data) {
433 this.actor.incrementTicks(1)
434 if (recMsg === 0) {
435 t.equal(data, 'first', 'should recive fist message')
436 } else if (recMsg === 1) {
437 t.equal(data, 'second', 'should recive second message')
438 } else {
439 t.equal(data, 'third', 'should recive third message')
440 }
441 recMsg++
442 }
443
444 static get typeId () {
445 return 8
446 }
447 }
448
449 const hypervisor = new Hypervisor({tree, containers: [testVMContainerA, testVMContainerB]})
450
451 const {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId)
452 const {module: moduleA} = hypervisor.createActor(testVMContainerA.typeId)
453 const funcRef = moduleA.getFuncRef('main')
454 funcRef.gas = 4000
455
456 const message = new Message({
457 funcRef,
458 funcArguments: [moduleB.getFuncRef('main')]
459 })
460 hypervisor.send(message)
461
462 const stateRoot = await hypervisor.createStateRoot()
463 t.deepEquals(stateRoot, expectedState, 'expected root!')
464})
465
466tape('arbiter test for id comparision', async t => {
467 t.plan(5)
468 let message
469 const expectedState = Buffer.from('ae2e8afa84748192064ddebab30d0e9852ceb722', 'hex')
470
471 const tree = new RadixTree({
472 db: db
473 })
474
475 class testVMContainerA extends BaseContainer {
476 main (funcRef, funcArguments) {
477 message = new Message({
478 funcRef,
479 funcArguments: [funcArguments]
480 })
481 this.actor.send(message)
482 }
483 }
484
485 let recMsg = 0
486
487 class testVMContainerB extends BaseContainer {
488 main (data) {
489 if (recMsg === 0) {
490 t.equal(data, 'first', 'should recive fist message')
491 } else if (recMsg === 1) {
492 t.equal(data, 'second', 'should recive second message')
493 } else {
494 t.equal(data, 'third', 'should recive third message')
495 }
496 recMsg++
497 }
498
499 static get typeId () {
500 return 8
501 }
502 }
503
504 const hypervisor = new Hypervisor({tree, containers: [testVMContainerA, testVMContainerB]})
505
506 let {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId)
507 hypervisor.send(new Message({
508 funcRef: moduleB.getFuncRef('main'),
509 funcArguments: ['first']
510 }))
511
512 const sr1 = await hypervisor.createStateRoot()
513
514 const {module: moduleA0} = hypervisor.createActor(testVMContainerA.typeId)
515
516 hypervisor.send(new Message({
517 funcRef: moduleA0.getFuncRef('main'),
518 funcArguments: [moduleB.getFuncRef('main'), 'second']
519 }))
520
521 const {module: moduleA1} = hypervisor.createActor(testVMContainerA.typeId)
522 hypervisor.send(new Message({
523 funcRef: moduleA1.getFuncRef('main'),
524 funcArguments: [moduleB.getFuncRef('main'), 'third']
525 }))
526
527 const stateRoot = await hypervisor.createStateRoot()
528 t.deepEquals(stateRoot, expectedState, 'expected root!')
529
530 await hypervisor.setStateRoot(sr1)
531 t.equals(hypervisor.nonce, 1, 'should get the correct nonce')
532 t.end()
533})
534
535tape('async work', async t => {
536 t.plan(3)
537 const expectedState = Buffer.from('7f638e41261bc0238c3e9b34fce11827b6a3cb61', 'hex')
538
539 const tree = new RadixTree({
540 db
541 })
542
543 class testVMContainerA extends BaseContainer {
544 main (funcRef) {
545 funcRef.gas = 10
546 const message = new Message({
547 funcRef,
548 funcArguments: [2]
549 })
550 this.actor.send(message)
551
552 const message2 = new Message({
553 funcRef,
554 funcArguments: [2]
555 })
556 this.actor.send(message2)
557 this.actor.incrementTicks(1)
558 return new Promise((resolve, reject) => {
559 setTimeout(() => {
560 resolve()
561 }, 10)
562 })
563 }
564 }
565
566 class testVMContainerB extends BaseContainer {
567 main (args) {
568 this.actor.incrementTicks(1)
569 t.equals(args, 2, 'should recive a message')
570 }
571
572 static get typeId () {
573 return 8
574 }
575 }
576
577 const hypervisor = new Hypervisor({tree, containers: [testVMContainerA, testVMContainerB]})
578
579 const {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId)
580 const {module: moduleA} = hypervisor.createActor(testVMContainerA.typeId)
581 const funcRef = moduleA.getFuncRef('main')
582 funcRef.gas = 200
583
584 const message = new Message({
585 funcRef,
586 funcArguments: [moduleB.getFuncRef('main')]
587 })
588
589 hypervisor.send(message)
590
591 const stateRoot = await hypervisor.createStateRoot()
592 t.deepEquals(stateRoot, expectedState, 'expected root!')
593})
594
595tape('driver', async t => {
596 const tree = new RadixTree({
597 db
598 })
599
600 const egress = new EgressDriver()
601
602 egress.on('message', msg => {
603 t.equals(msg.funcArguments[0], 'hello')
604 t.end()
605 })
606
607 class testVMContainer extends BaseContainer {
608 main (funcRef) {
609 this.actor.send(new Message({
610 funcRef,
611 funcArguments: ['hello']
612 }))
613 }
614 }
615
616 const hypervisor = new Hypervisor({
617 tree,
618 containers: [testVMContainer],
619 drivers: [egress]
620 })
621 const {module} = hypervisor.createActor(testVMContainer.typeId)
622
623 const message = new Message({
624 funcRef: module.getFuncRef('main'),
625 funcArguments: [new FunctionRef({actorID: egress.id})]
626 })
627
628 hypervisor.send(message)
629})
630
631tape('random', async t => {
632 const numOfActors = 10
633 const depth = 10
634 const messageOrder = {}
635 let numOfMsg = 0
636 const tree = new RadixTree({
637 db
638 })
639
640 class BenchmarkContainer extends BaseContainer {
641 main () {
642 const refs = [...arguments]
643 const ref = refs.pop()
644 const last = messageOrder[this.actor.id.id.toString('hex')]
645 const message = this.actor.currentMessage
646 if (last !== undefined) {
647 t.ok(last <= message._fromTicks, 'message should be in correct order')
648 }
649 messageOrder[this.actor.id.id.toString('hex')] = message._fromTicks
650 numOfMsg++
651
652 this.actor.incrementTicks(10)
653 if (ref) {
654 ref.gas = this.actor.currentMessage.funcRef.gas
655 this.actor.send(new Message({
656 funcRef: ref,
657 funcArguments: refs
658 }))
659 }
660 }
661 }
662
663 const hypervisor = new Hypervisor({tree})
664 hypervisor.registerContainer(BenchmarkContainer)
665
666 const references = []
667 let _numOfActors = numOfActors
668 while (_numOfActors--) {
669 const {module} = hypervisor.createActor(BenchmarkContainer.typeId)
670 const funcRef = module.getFuncRef('main')
671 references.push(funcRef)
672 }
673 _numOfActors = numOfActors
674 const msgs = []
675 while (_numOfActors--) {
676 let _depth = depth
677 const funcArguments = []
678 while (_depth--) {
679 const r = Math.floor(Math.random() * numOfActors)
680 const ref = references[r].copy()
681 funcArguments.push(ref)
682 }
683 const funcRef = references[_numOfActors]
684 funcRef.gas = 1000000
685
686 const message = new Message({
687 funcArguments,
688 funcRef
689 })
690 msgs.push(message)
691 }
692
693 hypervisor.send(msgs)
694 await hypervisor.scheduler.on('idle', () => {
695 t.equals(numOfMsg, depth * numOfActors + numOfActors)
696 t.end()
697 })
698})
699

Built with git-ssb-web