git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 7c1b9abb1401216b0a7325dfb2213933eda8826a

Files: 7c1b9abb1401216b0a7325dfb2213933eda8826a / tests / index.js

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

Built with git-ssb-web