github.com/codingfuture/orig-energi3@v0.8.4/energi/contracts/test/MasternodeRegistryV1.spec.js (about) 1 // Copyright 2019 The Energi Core Authors 2 // This file is part of the Energi Core library. 3 // 4 // The Energi Core library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The Energi Core library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Energi Governance system is the fundamental part of Energi Core. 18 19 'use strict'; 20 21 const MockProxy = artifacts.require('MockProxy'); 22 const MockContract = artifacts.require('MockContract'); 23 const MasternodeRegistryV1 = artifacts.require('MasternodeRegistryV1'); 24 const IBlockReward = artifacts.require('IBlockReward'); 25 const IMasternodeRegistry = artifacts.require('IMasternodeRegistry'); 26 const IMasternodeToken = artifacts.require('IMasternodeToken'); 27 const ITreasury = artifacts.require('ITreasury'); 28 const StorageMasternodeRegistryV1 = artifacts.require('StorageMasternodeRegistryV1'); 29 30 const common = require('./common'); 31 32 contract("MasternodeRegistryV1", async accounts => { 33 const s = { 34 artifacts, 35 accounts, 36 assert, 37 it, 38 web3, 39 storage: null, 40 }; 41 42 const { toWei } = web3.utils; 43 const vperiod = common.mnregistry_config[1]; 44 const isTargetChanges = async (_token, _mn) => { 45 // Proper way is to check pending block validation target against current, 46 // but there are some issues. 47 return (await web3.eth.getBlockNumber() % vperiod === (vperiod - 1)) 48 }; 49 50 before(async () => { 51 s.orig = await MasternodeRegistryV1.deployed(); 52 s.proxy = await MockProxy.at(await s.orig.proxy()); 53 await s.proxy.setImpl(s.orig.address); 54 55 s.fake = await MockContract.new(s.proxy.address); 56 s.proxy_abi = await MasternodeRegistryV1.at(s.proxy.address); 57 58 s.token_abi = await IMasternodeRegistry.at(s.proxy.address); 59 s.reward_abi = await IBlockReward.at(s.proxy.address); 60 s.storage = await StorageMasternodeRegistryV1.at(await s.proxy_abi.v1storage()); 61 62 s.mntoken_proxy_addr = await s.orig.token_proxy(); 63 //s.mntoken_proxy = await MockProxy.at(s.mntoken_proxy_addr); 64 s.mntoken_abi = await IMasternodeToken.at(s.mntoken_proxy_addr); 65 66 s.treasury_proxy_addr = await s.orig.treasury_proxy(); 67 s.treasury_proxy = await MockProxy.at(s.treasury_proxy_addr); 68 s.treasury_abi = await ITreasury.at(s.treasury_proxy_addr); 69 s.treasury_impl = await ITreasury.at(await s.treasury_proxy.impl()); 70 71 Object.freeze(s); 72 }); 73 74 after(async () => { 75 const impl = await MasternodeRegistryV1.new( 76 s.proxy.address, 77 s.mntoken_proxy_addr, 78 s.treasury_proxy_addr, 79 common.mnregistry_config 80 ); 81 await s.proxy.setImpl(impl.address); 82 }); 83 84 describe('common pre', () => common.govPreTests(s) ); 85 86 //--- 87 describe('Primary', () => { 88 const { fromAscii, toBN } = web3.utils; 89 90 const collateral1 = toWei('30000', 'ether'); 91 const collateral2 = toWei('20000', 'ether'); 92 const collateral3 = toWei('10000', 'ether'); 93 const reward = toBN(toWei('9.14', 'ether')); 94 95 const owner1 = accounts[1]; 96 const owner2 = accounts[2]; 97 const owner3 = accounts[3]; 98 const not_owner = accounts[0]; 99 100 const masternode1 = accounts[9]; 101 const masternode2 = accounts[8]; 102 const masternode3 = accounts[7]; 103 104 const ip1 = toBN(0x12345678); 105 const ip2 = toBN(0x87654321); 106 const ip3 = toBN(0x43218765); 107 108 const enode_common = '123456789012345678901234567890' 109 const enode1 = [fromAscii(enode_common + '11'), fromAscii(enode_common + '11')]; 110 const enode2 = [fromAscii(enode_common + '11'), fromAscii(enode_common + '22')]; 111 const enode3 = [fromAscii(enode_common + '11'), fromAscii(enode_common + '33')]; 112 113 before(async () => { 114 await s.mntoken_abi.depositCollateral({ 115 from: owner1, 116 value: collateral1, 117 }); 118 await s.mntoken_abi.depositCollateral({ 119 from: owner2, 120 value: collateral2, 121 }); 122 await s.mntoken_abi.depositCollateral({ 123 from: owner3, 124 value: collateral3, 125 }); 126 }); 127 128 after(async () => { 129 await s.mntoken_abi.withdrawCollateral(collateral1, { 130 from: owner1, 131 }); 132 await s.mntoken_abi.withdrawCollateral(collateral2, { 133 from: owner2, 134 }); 135 await s.mntoken_abi.withdrawCollateral(collateral3, { 136 from: owner3, 137 }); 138 }); 139 140 describe('No MN', () => { 141 it('should silently denounce()', async () => { 142 await s.token_abi.denounce(masternode1); 143 expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(0); 144 }); 145 146 it('should refuse to heartbeat() too old block', async () => { 147 const bn = await web3.eth.getBlockNumber(); 148 const b = await web3.eth.getBlock(bn); 149 150 try { 151 await s.token_abi.heartbeat(bn - 11, b.hash, '0', common.zerofee_callopts); 152 assert.fail('It should fail'); 153 } catch(e) { 154 assert.match(e.message, /Too old/); 155 } 156 }); 157 158 it('should refuse to heartbeat() wrong block', async () => { 159 const bn = (await web3.eth.getBlockNumber()); 160 const b = await web3.eth.getBlock(bn); 161 162 try { 163 await s.token_abi.heartbeat(bn - 10, b.hash, '0', common.zerofee_callopts); 164 assert.fail('It should fail'); 165 } catch(e) { 166 assert.match(e.message, /Block mismatch/); 167 } 168 }); 169 170 it('should refuse to heartbeat() not active', async () => { 171 const bn = await web3.eth.getBlockNumber(); 172 const b = await web3.eth.getBlock(bn); 173 174 try { 175 await s.token_abi.heartbeat(bn, b.hash, '0', common.zerofee_callopts); 176 assert.fail('It should fail'); 177 } catch(e) { 178 assert.match(e.message, /Not active/); 179 } 180 }); 181 182 it('should refuse to invalidate() vote for self', async () => { 183 try { 184 await s.token_abi.invalidate( 185 owner1, {from: owner1, ...common.zerofee_callopts}); 186 assert.fail('It should fail'); 187 } catch(e) { 188 assert.match(e.message, /Invalidation for self/); 189 } 190 }); 191 192 it('should refuse to invalidate() not active', async () => { 193 try { 194 await s.token_abi.invalidate(masternode2, common.zerofee_callopts); 195 assert.fail('It should fail'); 196 } catch(e) { 197 assert.match(e.message, /Not active caller/); 198 } 199 }); 200 201 it('should not be isActive()', async () => { 202 const res = await s.token_abi.isActive(masternode1); 203 expect(res).false; 204 }); 205 206 it('should correctly count()', async () => { 207 const res = await s.token_abi.count(); 208 assert.equal(res[0], 0); 209 assert.equal(res[1], 0); 210 assert.equal(res[2], 0); 211 }); 212 213 it('should handle info()', async () => { 214 try { 215 await s.token_abi.info(masternode1); 216 assert.fail('It should fail'); 217 } catch (e) { 218 assert.match(e.message, /Unknown masternode/); 219 } 220 }); 221 222 it('should handle ownerInfo()', async () => { 223 try { 224 await s.token_abi.ownerInfo(owner1); 225 assert.fail('It should fail'); 226 } catch (e) { 227 assert.match(e.message, /Unknown owner/); 228 } 229 }); 230 231 it('should process reward() to Treasury', async () => { 232 const treasury_before = toBN(await web3.eth.getBalance(s.treasury_impl.address)); 233 234 let r = await s.reward_abi.getReward(0); 235 assert.equal(r.valueOf(), 0); 236 237 const count = 3; 238 239 for (let i = count; i > 0; --i) { 240 r = await s.reward_abi.getReward(i); 241 242 if (r.eq(toBN(0))) { 243 // superblock case 244 r = await s.reward_abi.getReward(i+1); 245 } 246 247 expect(r.toString()).eql(reward.toString()); 248 await s.reward_abi.reward({ 249 from: not_owner, 250 value: r 251 }); 252 } 253 254 // Kick the rest 255 await s.reward_abi.reward(); 256 257 const treasury_after = toBN(await web3.eth.getBalance(s.treasury_impl.address)); 258 expect(treasury_after.sub(treasury_before).toString()) 259 .eql(reward.mul(toBN(count)).toString()); 260 }); 261 262 it('should handle onCollateralUpdate()', async () => { 263 await s.token_abi.onCollateralUpdate(owner1); 264 }); 265 266 it('should handle enumerate()', async () => { 267 expect(await s.token_abi.enumerate()).lengthOf(0); 268 }); 269 270 it.skip('must forbid more than one reward() per block', async () => { 271 // Bug: https://github.com/trufflesuite/truffle/issues/1389 272 const batch = web3.eth.BatchRequest(); 273 batch.add(s.reward_abi.reward.request({value: reward})); 274 batch.add(s.reward_abi.reward.request({value: reward})); 275 276 try { 277 await batch.execute(); 278 assert.fail('It must fail'); 279 } catch (e) { 280 assert.match(e.message, /Call outside of governance/); 281 } 282 }); 283 }); 284 285 describe('Single MN', () => { 286 let announced_block; 287 288 it('should refuse announce() without collateral', async () => { 289 try { 290 await s.token_abi.announce( 291 masternode1, ip1, enode1, { from: not_owner }); 292 assert.fail('It should fail'); 293 } catch (e) { 294 assert.match(e.message, /Invalid collateral/); 295 } 296 297 expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(0); 298 }); 299 300 const non_routables = { 301 '127.0.0.0/8' : [ 0x7F000001, 0x7FFFFFFF ], 302 '10.0.0.0/8' : [ 0x0A000001, 0x0AFFFFFF ], 303 '172.16.0.0/12' : [ 0xAC100001, 0xAC108001 ], 304 '192.168.0.0/16' : [ 0xC0A80001, 0xC0A88001 ], 305 '0.0.0.0/8' : [ 0x00123456 ], 306 '100.64.0.0/10' : [ 0x64400001, 0x64480001 ], 307 '169.254.0.0/16' : [ 0xA9FE0001, 0xA9FEFFFF ], 308 '198.18.0.0/15' : [ 0xC6120001, 0xC613FFFF ], 309 '198.51.100.0/24' : [ 0xC6336401, 0xC63364FF ], 310 '203.0.113.0/24' : [ 0xCB007101, 0xCB0071FE ], 311 '224.0.0.0/4' : [ 0xE0000001, 0xE80FF001 ], 312 '240.0.0.0/4' : [ 0xF0000001, 0xF800FFFF ], 313 '255.255.255.255/32' : [ 0xFFFFFFFF ], 314 }; 315 316 for (let k in non_routables) { 317 it(`should refuse announce() non-routable IPs: ${k}`, async () => { 318 for (let ip of non_routables[k]) { 319 try { 320 await s.token_abi.announce( 321 masternode1, ip, enode1, { from: owner1 }); 322 assert.fail('It should fail'); 323 } catch (e) { 324 assert.match(e.message, /Wrong IP/); 325 } 326 } 327 }); 328 } 329 330 it('should announce()', async () => { 331 const res = await s.mntoken_abi.balanceInfo(owner1); 332 assert.equal(res['0'].valueOf(), collateral1); 333 334 await s.token_abi.announce( 335 masternode1, ip1, enode1, { from: owner1 }); 336 337 const ann_e = await s.orig.getPastEvents('Announced', common.evt_last_block); 338 expect(ann_e).lengthOf(1); 339 common.stringifyBN(web3, ann_e[0].args); 340 expect(ann_e[0].args).deep.include({ 341 '0': masternode1, 342 '1': owner1, 343 '2': ip1.toString(), 344 '3': enode1, 345 '4': toBN(collateral1).toString(), 346 '__length__': 5, 347 'masternode': masternode1, 348 'owner': owner1, 349 'ipv4address': ip1.toString(), 350 'enode': enode1, 351 'collateral': toBN(collateral1).toString(), 352 }); 353 354 const den_e = await s.orig.getPastEvents('Denounced', common.evt_last_block); 355 expect(den_e).lengthOf(0); 356 }); 357 358 it('should re-announce MN', async () => { 359 await s.token_abi.announce( 360 masternode1, ip1, enode1, { from: owner1 }); 361 362 const ann_e = await s.orig.getPastEvents('Announced', common.evt_last_block); 363 expect(ann_e).lengthOf(1); 364 expect(ann_e[0].args).deep.include({ 365 '0': masternode1, 366 '1': owner1, 367 '2': ip1, 368 '3': enode1, 369 '4': toBN(collateral1), 370 '__length__': 5, 371 'masternode': masternode1, 372 'owner': owner1, 373 'ipv4address': ip1, 374 'enode': enode1, 375 'collateral': toBN(collateral1), 376 }); 377 378 const den_e = await s.orig.getPastEvents('Denounced', common.evt_last_block); 379 expect(den_e).lengthOf(1); 380 expect(den_e[0].args).deep.include({ 381 '0': masternode1, 382 '1': owner1, 383 '__length__': 2, 384 'masternode': masternode1, 385 'owner': owner1, 386 }); 387 388 announced_block = await web3.eth.getBlockNumber(); 389 }); 390 391 it('should refuse announce() another owner\'s MN', async () => { 392 try { 393 await s.token_abi.announce( 394 masternode1, ip2, enode2, { from: owner2 }); 395 assert.fail('It should fail'); 396 } catch (e) { 397 assert.match(e.message, /Invalid owner/); 398 } 399 400 expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(0); 401 }); 402 403 it('should refuse denounce() another owner\'s MN', async () => { 404 try { 405 await s.token_abi.denounce(masternode1, { from: owner2 }); 406 assert.fail('It should fail'); 407 } catch (e) { 408 assert.match(e.message, /Invalid owner/); 409 } 410 411 expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(0); 412 }); 413 414 it('should forbid heartbeat() too early', async () => { 415 const bn = await web3.eth.getBlockNumber(); 416 const b = await web3.eth.getBlock(bn); 417 418 try { 419 await s.token_abi.heartbeat(bn, b.hash, '0', {from: masternode1, ...common.zerofee_callopts}); 420 assert.fail('It should fail'); 421 } catch (e) { 422 assert.match(e.message, /Too early/); 423 } 424 425 await common.moveTime(web3, 59*30); 426 427 try { 428 await s.token_abi.heartbeat(bn, b.hash, '0', {from: masternode1, ...common.zerofee_callopts}); 429 assert.fail('It should fail'); 430 } catch (e) { 431 assert.match(e.message, /Too early/); 432 } 433 }); 434 435 it('should be isActive()', async () => { 436 expect(await s.token_abi.isActive(masternode1)).true; 437 expect(await s.token_abi.isActive(masternode2)).false; 438 }); 439 440 it('should heartbeat()', async () => { 441 await common.moveTime(web3, 60*30+1); 442 443 const s1 = await s.orig.mn_status(masternode1); 444 const bn = await web3.eth.getBlockNumber(); 445 const b = await web3.eth.getBlock(bn); 446 447 await s.token_abi.heartbeat(bn, b.hash, '0', {from: masternode1, ...common.zerofee_callopts}); 448 449 const s2 = await s.orig.mn_status(masternode1); 450 expect(s2.last_heartbeat.gt(s1.last_heartbeat)).true; 451 expect(s2.last_heartbeat.gt(b.timestamp)).true; 452 453 const evt = await s.orig.getPastEvents('Heartbeat', common.evt_last_block); 454 expect(evt).lengthOf(1); 455 456 expect(evt[0].args).deep.include({ 457 '0': masternode1, 458 '__length__': 1, 459 'masternode': masternode1, 460 }); 461 }); 462 463 it('should correctly count', async () => { 464 const res = await s.token_abi.count(); 465 assert.equal(res[0], 1); 466 assert.equal(res[1], 1); 467 assert.equal(res[2].toString(), collateral1.toString()); 468 }); 469 470 it('should produce info()', async () => { 471 const info = await s.token_abi.info(masternode1); 472 common.stringifyBN(web3, info); 473 expect(info).deep.include({ 474 owner: owner1, 475 ipv4address: toBN(ip1).toString(), 476 enode: enode1, 477 collateral: toBN(collateral1).toString(), 478 }); 479 }); 480 481 it('should produce ownerInfo()', async () => { 482 const info = await s.token_abi.ownerInfo(owner1); 483 common.stringifyBN(web3, info); 484 expect(info).deep.include({ 485 masternode: masternode1, 486 ipv4address: toBN(ip1).toString(), 487 enode: enode1, 488 collateral: toBN(collateral1).toString(), 489 announced_block: announced_block.toString(), 490 }); 491 }); 492 493 it('should process reward()', async () => { 494 const treasury_before = toBN(await web3.eth.getBalance(s.treasury_impl.address)); 495 const owner_before = toBN(await web3.eth.getBalance(owner1)); 496 const count = 3; 497 498 for (let i = count; i > 0; --i) { 499 const r = await s.reward_abi.getReward(i); 500 expect(r).eql(reward); 501 await s.reward_abi.reward({ 502 from: owner2, 503 value: r 504 }); 505 } 506 507 const treasury_after = toBN(await web3.eth.getBalance(s.treasury_impl.address)); 508 expect(treasury_before.toString()).equal(treasury_after.toString()); 509 510 const owner_after = toBN(await web3.eth.getBalance(owner1)); 511 expect(owner_after.sub(owner_before).toString()) 512 .eql(reward.mul(toBN(count)).toString()); 513 }); 514 515 it('should handle onCollateralUpdate()', async () => { 516 await s.token_abi.onCollateralUpdate(owner1); 517 expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(0); 518 }); 519 520 it('should handle enumerate()', async () => { 521 expect(await s.token_abi.enumerate()).members([masternode1]); 522 }); 523 524 it('should forbid heartbeat() too late', async () => { 525 const bn = await web3.eth.getBlockNumber(); 526 const b = await web3.eth.getBlock(bn); 527 528 try { 529 await s.token_abi.heartbeat(bn, b.hash, '0', {from: masternode1, ...common.zerofee_callopts}); 530 assert.fail('It should fail'); 531 } catch (e) { 532 assert.match(e.message, /Too early/); 533 } 534 535 await common.moveTime(web3, 2*60*60); 536 537 try { 538 await s.token_abi.heartbeat(bn, b.hash, '0', {from: masternode1, ...common.zerofee_callopts}); 539 assert.fail('It should fail'); 540 } catch (e) { 541 assert.match(e.message, /Not active/); 542 } 543 544 // Denounce does not happen on read-only 545 expect(await s.orig.getPastEvents( 546 'Denounced', common.evt_last_block)).lengthOf(0); 547 }); 548 549 it('should denounce() on collateral change', async() => { 550 await s.token_abi.announce( 551 masternode1, ip1, enode1, { from: owner1 }); 552 553 await s.mntoken_abi.depositCollateral({ 554 from: owner1, 555 value: collateral1, 556 }); 557 expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1); 558 expect(await s.token_abi.enumerate()).members([]); 559 560 await s.token_abi.announce( 561 masternode1, ip1, enode1, { from: owner1 }); 562 expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(1); 563 expect(await s.token_abi.enumerate()).members([masternode1]); 564 565 await s.mntoken_abi.withdrawCollateral(collateral1, { 566 from: owner1, 567 }); 568 569 expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1); 570 expect(await s.token_abi.enumerate()).members([]); 571 572 await s.token_abi.announce( 573 masternode1, ip1, enode1, { from: owner1 }); 574 }); 575 576 it('should denounce()', async()=> { 577 await s.token_abi.denounce(masternode1, { from: owner1 }); 578 const evt = await s.orig.getPastEvents('Denounced', common.evt_last_block); 579 expect(evt).lengthOf(1); 580 expect(evt[0].args).deep.include({ 581 '0': masternode1, 582 '1': owner1, 583 '__length__': 2, 584 'masternode': masternode1, 585 'owner': owner1, 586 }); 587 }); 588 }); 589 590 describe('Two MN', () => { 591 const nodes = [ 592 { 593 masternode: masternode1, 594 ip: ip1, 595 enode: enode1, 596 owner: owner1, 597 collateral: collateral1, 598 }, 599 { 600 masternode: masternode2, 601 ip: ip2, 602 enode: enode2, 603 owner: owner2, 604 collateral: collateral2, 605 }, 606 ]; 607 608 it('should announce()', async () => { 609 for (let mn of nodes) { 610 await s.token_abi.announce( 611 mn.masternode, mn.ip, mn.enode, { from: mn.owner }); 612 } 613 614 const mn1_status = await s.orig.mn_status(masternode1); 615 const mn2_status = await s.orig.mn_status(masternode2); 616 expect(mn1_status.seq_payouts.toString()).equal('3'); 617 expect(mn2_status.seq_payouts.toString()).equal('2'); 618 }); 619 620 it('should re-announce MN', async () => { 621 // back order to test current being left in place first 622 for (let mn of Array.from(nodes).reverse()) { 623 await s.token_abi.announce( 624 mn.masternode, mn.ip, mn.enode, { from: mn.owner }); 625 626 const ann_e = await s.orig.getPastEvents('Announced', common.evt_last_block); 627 expect(ann_e).lengthOf(1); 628 common.stringifyBN(web3, ann_e[0].args); 629 expect(ann_e[0].args).deep.include({ 630 '0': mn.masternode, 631 '1': mn.owner, 632 '2': toBN(mn.ip).toString(), 633 '3': mn.enode, 634 '4': toBN(mn.collateral).toString(), 635 '__length__': 5, 636 'masternode': mn.masternode, 637 'owner': mn.owner, 638 'ipv4address': toBN(mn.ip).toString(), 639 'enode': mn.enode, 640 'collateral': toBN(mn.collateral).toString(), 641 }); 642 643 const den_e = await s.orig.getPastEvents('Denounced', common.evt_last_block); 644 expect(den_e).lengthOf(1); 645 common.stringifyBN(web3, den_e[0].args); 646 expect(den_e[0].args).deep.include({ 647 '0': mn.masternode, 648 '1': mn.owner, 649 '__length__': 2, 650 'masternode': mn.masternode, 651 'owner': mn.owner, 652 }); 653 } 654 }); 655 656 it('should refuse announce() another owner\'s MN', async () => { 657 try { 658 await s.token_abi.announce( 659 masternode1, ip2, enode2, { from: owner2 }); 660 assert.fail('It should fail'); 661 } catch (e) { 662 assert.match(e.message, /Invalid owner/); 663 } 664 665 expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(0); 666 }); 667 668 it('should refuse denounce() another owner\'s MN', async () => { 669 try { 670 await s.token_abi.denounce(masternode1, { from: owner2 }); 671 assert.fail('It should fail'); 672 } catch (e) { 673 assert.match(e.message, /Invalid owner/); 674 } 675 676 expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(0); 677 }); 678 679 it('should be isActive()', async () => { 680 for (let mn of nodes) { 681 expect(await s.token_abi.isActive(mn.masternode)).true; 682 } 683 }); 684 685 it('should heartbeat()', async () => { 686 await common.moveTime(web3, 60*30+1); 687 688 const s1 = await s.orig.mn_status(masternode1); 689 const s1o = await s.orig.mn_status(masternode2); 690 const bn = await web3.eth.getBlockNumber(); 691 const b = await web3.eth.getBlock(bn); 692 693 await s.token_abi.heartbeat(bn, b.hash, '0', {from: masternode1, ...common.zerofee_callopts}); 694 695 const s2 = await s.orig.mn_status(masternode1); 696 expect(s2.last_heartbeat.gt(s1.last_heartbeat)).true; 697 expect(s2.last_heartbeat.gt(b.timestamp)).true; 698 699 const s2o = await s.orig.mn_status(masternode2); 700 expect(s2o.last_heartbeat.eq(s1o.last_heartbeat)).true; 701 702 const evt = await s.orig.getPastEvents('Heartbeat', common.evt_last_block); 703 expect(evt).lengthOf(1); 704 705 expect(evt[0].args).deep.include({ 706 '0': masternode1, 707 '__length__': 1, 708 'masternode': masternode1, 709 }); 710 }); 711 712 it('should correctly count', async () => { 713 const res = await s.token_abi.count(); 714 common.stringifyBN(web3, res); 715 expect(res).eql({ 716 '0': '2', 717 '1': '2', 718 '2': toWei('50000', 'ether'), 719 '3': toWei('50000', 'ether'), 720 '4': toWei('60000', 'ether'), 721 'active': '2', 722 'total': '2', 723 'active_collateral': toWei('50000', 'ether'), 724 'total_collateral': toWei('50000', 'ether'), 725 'max_of_all_times': toWei('60000', 'ether'), 726 }); 727 }); 728 729 it('should produce info()', async () => { 730 for (let mn of nodes) { 731 const info = await s.token_abi.info(mn.masternode); 732 common.stringifyBN(web3, info); 733 expect(info).deep.include({ 734 owner: mn.owner, 735 ipv4address: toBN(mn.ip).toString(), 736 enode: mn.enode, 737 collateral: toBN(mn.collateral).toString() 738 }); 739 } 740 }); 741 742 it('should process reward()', async () => { 743 const treasury_before = toBN(await web3.eth.getBalance(s.treasury_impl.address)); 744 const owner1_before = toBN(await web3.eth.getBalance(owner1)); 745 const owner2_before = toBN(await web3.eth.getBalance(owner2)); 746 const count = 10; 747 let sb = false; 748 749 for (let i = count; i > 0; --i) { 750 let r = await s.reward_abi.getReward(i); 751 if (r.eq(toBN(0))) { 752 // superblock case 753 r = await s.reward_abi.getReward(i+1); 754 sb = true; 755 } 756 757 expect(r.toString()).eql(reward.toString()); 758 759 await s.reward_abi.reward({ 760 from: owner3, 761 value: r 762 }); 763 } 764 765 expect(sb).true; 766 767 const treasury_after = toBN(await web3.eth.getBalance(s.treasury_impl.address)); 768 expect(treasury_before.toString()).equal(treasury_after.toString()); 769 770 const owner1_after = toBN(await web3.eth.getBalance(owner1)); 771 const owner2_after = toBN(await web3.eth.getBalance(owner2)); 772 expect(owner1_after.sub(owner1_before).toString()) 773 .eql(reward.mul(toBN(6)).toString()); 774 expect(owner2_after.sub(owner2_before).toString()) 775 .eql(reward.mul(toBN(4)).toString()); 776 }); 777 778 it('should handle enumerate()', async () => { 779 expect(await s.token_abi.enumerate()).members([masternode1, masternode2]); 780 }); 781 782 it('should denounce() on collateral change', async() => { 783 await s.mntoken_abi.depositCollateral({ 784 from: owner1, 785 value: collateral1, 786 }); 787 expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1); 788 expect(await s.token_abi.enumerate()).members([masternode2]); 789 790 await s.token_abi.announce( 791 masternode1, ip1, enode1, { from: owner1 }); 792 expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(1); 793 expect(await s.token_abi.enumerate()).members([masternode1, masternode2]); 794 795 await s.mntoken_abi.withdrawCollateral(collateral1, { 796 from: owner1, 797 }); 798 799 expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1); 800 expect(await s.token_abi.enumerate()).members([masternode2]); 801 802 await s.token_abi.announce( 803 masternode1, ip1, enode1, { from: owner1 }); 804 }); 805 806 it('should denounce()', async()=> { 807 for (let mn of nodes) { 808 await s.token_abi.denounce(mn.masternode, { from: mn.owner }); 809 const evt = await s.orig.getPastEvents('Denounced', common.evt_last_block); 810 expect(evt).lengthOf(1); 811 expect(evt[0].args).deep.include({ 812 '0': mn.masternode, 813 '1': mn.owner, 814 '__length__': 2, 815 'masternode': mn.masternode, 816 'owner': mn.owner, 817 }); 818 } 819 }); 820 }); 821 822 describe('Three MN', () => { 823 const nodes = [ 824 { 825 masternode: masternode1, 826 ip: ip1, 827 enode: enode1, 828 owner: owner1, 829 collateral: collateral1, 830 }, 831 { 832 masternode: masternode2, 833 ip: ip2, 834 enode: enode2, 835 owner: owner2, 836 collateral: collateral2, 837 }, 838 { 839 masternode: masternode3, 840 ip: ip3, 841 enode: enode3, 842 owner: owner3, 843 collateral: collateral3, 844 }, 845 ]; 846 847 it('should announce()', async () => { 848 for (let mn of nodes) { 849 await s.token_abi.announce( 850 mn.masternode, mn.ip, mn.enode, { from: mn.owner }); 851 } 852 853 const mn1_status = await s.orig.mn_status(masternode1); 854 const mn2_status = await s.orig.mn_status(masternode2); 855 const mn3_status = await s.orig.mn_status(masternode3); 856 expect(mn1_status.seq_payouts.toString()).equal('3'); 857 expect(mn2_status.seq_payouts.toString()).equal('2'); 858 expect(mn3_status.seq_payouts.toString()).equal('1'); 859 }); 860 861 it('should re-announce MN', async () => { 862 // back order to test current being left in place first 863 for (let mn of Array.from(nodes).reverse()) { 864 await s.token_abi.announce( 865 mn.masternode, mn.ip, mn.enode, { from: mn.owner }); 866 867 const ann_e = await s.orig.getPastEvents('Announced', common.evt_last_block); 868 expect(ann_e).lengthOf(1); 869 common.stringifyBN(web3, ann_e[0].args); 870 expect(ann_e[0].args).deep.include({ 871 '0': mn.masternode, 872 '1': mn.owner, 873 '2': toBN(mn.ip).toString(), 874 '3': mn.enode, 875 '4': toBN(mn.collateral).toString(), 876 '__length__': 5, 877 'masternode': mn.masternode, 878 'owner': mn.owner, 879 'ipv4address': toBN(mn.ip).toString(), 880 'enode': mn.enode, 881 'collateral': toBN(mn.collateral).toString(), 882 }); 883 884 const den_e = await s.orig.getPastEvents('Denounced', common.evt_last_block); 885 expect(den_e).lengthOf(1); 886 common.stringifyBN(web3, den_e[0].args); 887 expect(den_e[0].args).deep.include({ 888 '0': mn.masternode, 889 '1': mn.owner, 890 '__length__': 2, 891 'masternode': mn.masternode, 892 'owner': mn.owner, 893 }); 894 } 895 }); 896 897 it('should be isActive()', async () => { 898 for (let mn of nodes) { 899 expect(await s.token_abi.isActive(mn.masternode)).true; 900 expect(await s.token_abi.isActive(mn.owner)).false; 901 } 902 }); 903 904 it('should correctly count', async () => { 905 const res = await s.token_abi.count(); 906 common.stringifyBN(web3, res); 907 expect(res).eql({ 908 '0': '3', 909 '1': '3', 910 '2': toWei('60000', 'ether'), 911 '3': toWei('60000', 'ether'), 912 '4': toWei('80000', 'ether'), 913 'active': '3', 914 'total': '3', 915 'active_collateral': toWei('60000', 'ether'), 916 'total_collateral': toWei('60000', 'ether'), 917 'max_of_all_times': toWei('80000', 'ether'), 918 }); 919 }); 920 921 it('should produce info()', async () => { 922 for (let mn of nodes) { 923 const info = await s.token_abi.info(mn.masternode); 924 common.stringifyBN(web3, info); 925 expect(info).deep.include({ 926 owner: mn.owner, 927 ipv4address: toBN(mn.ip).toString(), 928 enode: mn.enode, 929 collateral: toBN(mn.collateral).toString() 930 }); 931 } 932 }); 933 934 it('should process reward()', async () => { 935 const treasury_before = toBN(await web3.eth.getBalance(s.treasury_impl.address)); 936 const owner1_before = toBN(await web3.eth.getBalance(owner1)); 937 const owner2_before = toBN(await web3.eth.getBalance(owner2)); 938 const owner3_before = toBN(await web3.eth.getBalance(owner3)); 939 const count = 18; 940 let sb = false; 941 942 for (let i = count; i > 0; --i) { 943 let r = await s.reward_abi.getReward(i); 944 if (r.eq(toBN(0))) { 945 // superblock case 946 r = await s.reward_abi.getReward(i+1); 947 sb = true; 948 } 949 950 expect(r.toString()).eql(reward.toString()); 951 952 await s.reward_abi.reward({ 953 from: not_owner, 954 value: r 955 }); 956 957 const target1 = await s.token_abi.validationTarget(masternode1); 958 const target2 = await s.token_abi.validationTarget(masternode2); 959 const target3 = await s.token_abi.validationTarget(masternode3); 960 expect(target1).not.equal(masternode1); 961 expect(target2).not.equal(masternode2); 962 expect(target3).not.equal(masternode3); 963 expect(target1).not.equal(target2); 964 expect(target1).not.equal(target3); 965 966 if (i === 13 || i == 11 || i == 9) { 967 let t = target1; 968 969 if (await isTargetChanges(s.token_abi, masternode1)) { 970 // still a chance of fail. 971 t = (t === masternode3) ? masternode2 : masternode3; 972 } 973 974 const invalidator = (t === masternode3) ? masternode1 : masternode2; 975 976 await s.token_abi.invalidate(masternode3, {from: invalidator}); 977 } 978 } 979 980 expect(sb).true; 981 982 // One invalidation at round 2 983 const treasury_after = toBN(await web3.eth.getBalance(s.treasury_impl.address)); 984 expect(treasury_after.sub(treasury_before).toString()) 985 .eql(reward.mul(toBN(1)).toString()) 986 987 const owner1_after = toBN(await web3.eth.getBalance(owner1)); 988 const owner2_after = toBN(await web3.eth.getBalance(owner2)); 989 const owner3_after = toBN(await web3.eth.getBalance(owner3)); 990 expect(owner1_after.sub(owner1_before).toString()) 991 .eql(reward.mul(toBN(3+3+3)).toString()); 992 expect(owner2_after.sub(owner2_before).toString()) 993 .eql(reward.mul(toBN(2+2+2)).toString()); 994 expect(owner3_after.sub(owner3_before).toString()) 995 .eql(reward.mul(toBN(1+0+1)).toString()); 996 }); 997 998 999 it('should calculate validation target by periods', async () => { 1000 let bn = await web3.eth.getBlockNumber(); 1001 const valTarget = () => { 1002 return s.token_abi.methods['validationTarget(address)'](masternode1, bn); 1003 } 1004 1005 let tmp = await valTarget(); 1006 let target = tmp; 1007 1008 do { 1009 --bn; 1010 target = await valTarget(); 1011 } while ( target === tmp ); 1012 1013 for (let k = 0; k < 3; ++k) { 1014 for (let i = vperiod; i > 0; --i, --bn) { 1015 tmp = await valTarget(); 1016 expect(tmp).equal(target); 1017 } 1018 1019 for (let i = vperiod; i > 0; --i, --bn) { 1020 tmp = await valTarget(); 1021 expect(tmp).not.equal(target); 1022 } 1023 } 1024 }); 1025 1026 it('should refuse invalidate() wrong target', async () => { 1027 try { 1028 let target = await s.token_abi.validationTarget(masternode1); 1029 1030 if ((target == masternode2) && !await isTargetChanges(s.token_abi, masternode1)) { 1031 target = masternode3; 1032 } else { 1033 target = masternode2; 1034 } 1035 1036 await s.token_abi.invalidate(target, {from:masternode1, ...common.zerofee_callopts}); 1037 assert.fail('It must fail'); 1038 } catch (e) { 1039 assert.match(e.message, /Invalid target/); 1040 } 1041 }); 1042 1043 it('should process reward() deactivate missing heartbeat', async () => { 1044 await common.moveTime(web3, 40*60); 1045 1046 { 1047 const b = await web3.eth.getBlock('latest'); 1048 await s.token_abi.heartbeat(b.number, b.hash, '12', {from:masternode1, ...common.zerofee_callopts}); 1049 await s.token_abi.heartbeat(b.number, b.hash, '23', {from:masternode2, ...common.zerofee_callopts}); 1050 await s.token_abi.heartbeat(b.number, b.hash, '34', {from:masternode3, ...common.zerofee_callopts}); 1051 } 1052 1053 await common.moveTime(web3, 70*60); 1054 1055 const treasury_before = toBN(await web3.eth.getBalance(s.treasury_impl.address)); 1056 const owner1_before = toBN(await web3.eth.getBalance(owner1)); 1057 const owner2_before = toBN(await web3.eth.getBalance(owner2)); 1058 const owner3_before = toBN(await web3.eth.getBalance(owner3)); 1059 const count = 18; 1060 let sb = false; 1061 1062 for (let i = count; i > 0; --i) { 1063 if (i == 12 || i == 8 || i == 4) { 1064 const bn = await web3.eth.getBlockNumber(); 1065 const b = await web3.eth.getBlock(bn); 1066 await s.token_abi.heartbeat(bn, b.hash, '12', {from:masternode1, ...common.zerofee_callopts}); 1067 await s.token_abi.heartbeat(bn, b.hash, '34', {from:masternode3, ...common.zerofee_callopts}); 1068 await common.moveTime(web3, 91*60); 1069 } 1070 1071 let r = await s.reward_abi.getReward(i); 1072 if (r.eq(toBN(0))) { 1073 // superblock case 1074 r = await s.reward_abi.getReward(i+1); 1075 sb = true; 1076 } 1077 1078 expect(r.toString()).eql(reward.toString()); 1079 1080 await s.reward_abi.reward({ 1081 from: not_owner, 1082 value: r, 1083 }); 1084 } 1085 1086 expect(sb).true; 1087 1088 const treasury_after = toBN(await web3.eth.getBalance(s.treasury_impl.address)); 1089 const owner1_after = toBN(await web3.eth.getBalance(owner1)); 1090 const owner2_after = toBN(await web3.eth.getBalance(owner2)); 1091 const owner3_after = toBN(await web3.eth.getBalance(owner3)); 1092 1093 // The treasury must get reward of nodes without votes by design 1094 expect(treasury_after.sub(treasury_before).toString()) 1095 .eql(reward.mul(toBN(0)).toString()) 1096 expect(owner1_after.sub(owner1_before).toString()) 1097 .eql(reward.mul(toBN(3+3+3+3)).toString()); 1098 expect(owner2_after.sub(owner2_before).toString()) 1099 .eql(reward.mul(toBN(2+0+0+0)).toString()); 1100 expect(owner3_after.sub(owner3_before).toString()) 1101 .eql(reward.mul(toBN(1+1+1+1)).toString()); 1102 1103 expect(await s.token_abi.isActive(masternode1)).true; 1104 expect(await s.token_abi.isActive(masternode2)).false; 1105 expect(await s.token_abi.isActive(masternode3)).true; 1106 }); 1107 1108 it('should skip inactive node from validation', async () => { 1109 const target1 = await s.token_abi.validationTarget(masternode1); 1110 const target3 = await s.token_abi.validationTarget(masternode3); 1111 expect(target1).eql(masternode3); 1112 expect(target3).eql(masternode1); 1113 }); 1114 1115 it('should refuse invalidate() by inactive node', async () => { 1116 try { 1117 await s.token_abi.invalidate(masternode1, {from:masternode2, ...common.zerofee_callopts}); 1118 assert.fail('It must fail'); 1119 } catch (e) { 1120 assert.match(e.message, /Not active caller/); 1121 } 1122 }); 1123 1124 it('should refuse double invalidate()', async () => { 1125 await s.token_abi.invalidate(masternode3, {from:masternode1, ...common.zerofee_callopts}); 1126 1127 try { 1128 for (let i = 0; i < vperiod; ++i) { 1129 await s.token_abi.invalidate(masternode3, {from:masternode1, ...common.zerofee_callopts}); 1130 } 1131 assert.fail('It must fail'); 1132 } catch (e) { 1133 assert.match(e.message, /Already invalidated/); 1134 } 1135 }); 1136 1137 it('should handle enumerate()', async () => { 1138 expect(await s.token_abi.enumerate()).members([ 1139 masternode1, masternode2, masternode3]); 1140 }); 1141 1142 it('should handle enumerateActive()', async () => { 1143 expect(await s.token_abi.enumerateActive()).members([ 1144 masternode1, masternode3]); 1145 }); 1146 1147 it('should denounce() on collateral change', async() => { 1148 await s.mntoken_abi.depositCollateral({ 1149 from: owner1, 1150 value: collateral1, 1151 }); 1152 expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1); 1153 expect(await s.token_abi.enumerate()).members([masternode2, masternode3]); 1154 1155 await s.token_abi.announce( 1156 masternode1, ip1, enode1, { from: owner1 }); 1157 expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(1); 1158 expect(await s.token_abi.enumerate()).members([masternode1, masternode2, masternode3]); 1159 1160 await s.mntoken_abi.withdrawCollateral(collateral1, { 1161 from: owner1, 1162 }); 1163 1164 expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1); 1165 expect(await s.token_abi.enumerate()).members([masternode2, masternode3]); 1166 1167 await s.token_abi.announce( 1168 masternode1, ip1, enode1, { from: owner1 }); 1169 }); 1170 1171 it('should cleanup inactive node', async () => { 1172 await common.moveTime(web3, 25*60*60); 1173 1174 for (let i = 4; i > 0; --i) { 1175 await s.reward_abi.reward({ 1176 from: not_owner, 1177 value: reward 1178 }); 1179 } 1180 1181 expect(await s.token_abi.enumerate()).members([masternode1, masternode3]); 1182 }); 1183 1184 it('should denounce()', async()=> { 1185 for (let mn of nodes) { 1186 await s.token_abi.denounce(mn.masternode, { from: mn.owner }); 1187 const evt = await s.orig.getPastEvents('Denounced', common.evt_last_block); 1188 1189 if (mn.masternode == masternode2) { 1190 expect(evt).lengthOf(0); 1191 continue; 1192 } 1193 1194 expect(evt).lengthOf(1); 1195 expect(evt[0].args).deep.include({ 1196 '0': mn.masternode, 1197 '1': mn.owner, 1198 '__length__': 2, 1199 'masternode': mn.masternode, 1200 'owner': mn.owner, 1201 }); 1202 } 1203 }); 1204 1205 it('should correctly count() ever max', async () => { 1206 const res = await s.token_abi.count(); 1207 common.stringifyBN(web3, res); 1208 expect(res).eql({ 1209 '0': '0', 1210 '1': '0', 1211 '2': toWei('0', 'ether'), 1212 '3': toWei('0', 'ether'), 1213 '4': toWei('90000', 'ether'), 1214 'active': '0', 1215 'total': '0', 1216 'active_collateral': toWei('0', 'ether'), 1217 'total_collateral': toWei('0', 'ether'), 1218 'max_of_all_times': toWei('90000', 'ether'), 1219 }); 1220 }); 1221 }); 1222 1223 describe('StorageMasternodeRegistryV1', async () => { 1224 it ('should refuse setMasternode() from outside', async () => { 1225 try { 1226 await s.storage.setMasternode( 1227 masternode1, 1228 masternode1, 1229 ip1, 1230 enode1, 1231 '0', 1232 '0', 1233 masternode1, 1234 masternode1 1235 ); 1236 assert.fail('It must fail'); 1237 } catch (e) { 1238 assert.match(e.message, /Not owner/); 1239 } 1240 }); 1241 1242 it ('should refuse setMasternodePos() from outside', async () => { 1243 try { 1244 await s.storage.setMasternodePos( 1245 masternode1, 1246 false, masternode1, 1247 false, masternode1 1248 ); 1249 assert.fail('It must fail'); 1250 } catch (e) { 1251 assert.match(e.message, /Not owner/); 1252 } 1253 }); 1254 1255 it ('should refuse deleteMasternode() from outside', async () => { 1256 try { 1257 await s.storage.deleteMasternode(masternode1); 1258 assert.fail('It must fail'); 1259 } catch (e) { 1260 assert.match(e.message, /Not owner/); 1261 } 1262 }); 1263 }); 1264 }); 1265 1266 //--- 1267 describe('common post', () => common.govPostTests(s) ); 1268 });