github.com/codingfuture/orig-energi3@v0.8.4/energi/contracts/test/MasternodeRegistryV2.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 MockProposal = artifacts.require('MockProposal');
    24  const MockSporkRegistry = artifacts.require('MockSporkRegistry')
    25  const MockMasternodeTokenV2 = artifacts.require('MockMasternodeTokenV2')
    26  const MasternodeRegistryV2 = artifacts.require('MasternodeRegistryV2');
    27  const MasternodeRegistryV1 = artifacts.require('MasternodeRegistryV1');
    28  const IBlockReward = artifacts.require('IBlockReward');
    29  const IMasternodeRegistryV2 = artifacts.require('IMasternodeRegistryV2');
    30  const IMasternodeToken = artifacts.require('IMasternodeToken');
    31  const ITreasury = artifacts.require('ITreasury');
    32  const StorageMasternodeRegistryV1 = artifacts.require('StorageMasternodeRegistryV1');
    33  
    34  const common = require('./common');
    35  
    36  contract("MasternodeRegistryV2", async accounts => {
    37      const s = {
    38          artifacts,
    39          accounts,
    40          assert,
    41          it,
    42          web3,
    43          storage: null,
    44      };
    45  
    46      const { toWei } = web3.utils;
    47      const vperiod = common.mnregistry_config_v2[1];
    48      const isTargetChanges = async (_token, _mn) => {
    49          return await _token.validationTarget(_mn, 'latest') !=  await _token.validationTarget(_mn, 'pending');
    50      };
    51      const sw_features = web3.utils.toBN((1 << 24) | (2 << 16) | (3 << 8));
    52  
    53      before(async () => {
    54          s.orig = await MasternodeRegistryV2.deployed();
    55          s.proxy = await MockProxy.at(await s.orig.proxy());
    56          await s.proxy.setImpl(s.orig.address);
    57  
    58          s.fake = await MockContract.new(s.proxy.address);
    59          s.proxy_abi = await MasternodeRegistryV2.at(s.proxy.address);
    60  
    61          s.token_abi = await IMasternodeRegistryV2.at(s.proxy.address);
    62          s.reward_abi = await IBlockReward.at(s.proxy.address);
    63          s.storage = await StorageMasternodeRegistryV1.at(await s.proxy_abi.v1storage());
    64  
    65          s.mntoken_proxy_addr = await s.orig.token_proxy();
    66          //s.mntoken_proxy = await MockProxy.at(s.mntoken_proxy_addr);
    67          s.mntoken_abi = await IMasternodeToken.at(s.mntoken_proxy_addr);
    68  
    69          s.treasury_proxy_addr = await s.orig.treasury_proxy();
    70          s.treasury_proxy = await MockProxy.at(s.treasury_proxy_addr);
    71          s.treasury_abi = await ITreasury.at(s.treasury_proxy_addr);
    72          s.treasury_impl = await ITreasury.at(await s.treasury_proxy.impl());
    73  
    74          Object.freeze(s);
    75      });
    76  
    77      after(async () => {
    78          const impl = await MasternodeRegistryV2.new(
    79              s.proxy.address,
    80              s.mntoken_proxy_addr,
    81              s.treasury_proxy_addr,
    82              common.mnregistry_config_v2,
    83              common.mnreg_deploy_opts
    84          );
    85          await s.proxy.setImpl(impl.address);
    86      });
    87  
    88      describe('common pre', () => common.govPreTests(s) );
    89  
    90      //---
    91      describe('Primary', () => {
    92          const { fromAscii, toBN } = web3.utils;
    93  
    94          const collateral1 = toWei('3000', 'ether');
    95          const collateral2 = toWei('2000', 'ether');
    96          const collateral3 = toWei('1000', 'ether');
    97          const reward = toBN(toWei('9.14', 'ether'));
    98  
    99          const owner1 = accounts[1];
   100          const owner2 = accounts[2];
   101          const owner3 = accounts[3];
   102          const not_owner = accounts[0];
   103  
   104          const masternode1 = accounts[9];
   105          const masternode2 = accounts[8];
   106          const masternode3 = accounts[7];
   107  
   108          const ip1 = toBN(0x12345678);
   109          const ip2 = toBN(0x87654321);
   110          const ip3 = toBN(0x43218765);
   111  
   112          const enode_common = '123456789012345678901234567890'
   113          const enode1 = [fromAscii(enode_common + '11'), fromAscii(enode_common + '11')];
   114          const enode2 = [fromAscii(enode_common + '11'), fromAscii(enode_common + '22')];
   115          const enode3 = [fromAscii(enode_common + '11'), fromAscii(enode_common + '33')];
   116  
   117          before(async () => {
   118              await s.mntoken_abi.depositCollateral({
   119                  from: owner1,
   120                  value: collateral1,
   121              });
   122              await s.mntoken_abi.depositCollateral({
   123                  from: owner2,
   124                  value: collateral2,
   125              });
   126              await s.mntoken_abi.depositCollateral({
   127                  from: owner3,
   128                  value: collateral3,
   129              });
   130          });
   131  
   132          after(async () => {
   133              await s.mntoken_abi.withdrawCollateral(collateral1, {
   134                  from: owner1,
   135              });
   136              await s.mntoken_abi.withdrawCollateral(collateral2, {
   137                  from: owner2,
   138              });
   139              await s.mntoken_abi.withdrawCollateral(collateral3, {
   140                  from: owner3,
   141              });
   142          });
   143  
   144          const checkHeartbeat = async () => {
   145              try {
   146                  const evt = await s.orig.getPastEvents('Heartbeat', common.evt_last_block);
   147                  expect(evt).lengthOf(0);
   148              } catch(e) {
   149                  //expect(e.message).match(/doesn't exist in this contract/);
   150              }
   151          };
   152  
   153          describe('No MN', () => {
   154              it('should silently denounce()', async () => {
   155                  await s.token_abi.denounce(masternode1);
   156                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(0);
   157              });
   158  
   159              it('should refuse to heartbeat() too old block', async () => {
   160                  const bn = await web3.eth.getBlockNumber();
   161                  const b = await web3.eth.getBlock(bn);
   162  
   163                  try {
   164                      await s.token_abi.heartbeat(bn - 11, b.hash, sw_features, common.zerofee_callopts);
   165                      assert.fail('It should fail');
   166                  } catch(e) {
   167                      assert.match(e.message, /Too old/);
   168                  }
   169              });
   170  
   171              it('should refuse to heartbeat() wrong block', async () => {
   172                  const bn = (await web3.eth.getBlockNumber());
   173                  const b = await web3.eth.getBlock(bn);
   174  
   175                  try {
   176                      await s.token_abi.heartbeat(bn - 10, b.hash, sw_features, common.zerofee_callopts);
   177                      assert.fail('It should fail');
   178                  } catch(e) {
   179                      assert.match(e.message, /Block mismatch/);
   180                  }
   181              });
   182  
   183              it('should refuse to heartbeat() not active', async () => {
   184                  const bn = await web3.eth.getBlockNumber();
   185                  const b = await web3.eth.getBlock(bn);
   186  
   187                  try {
   188                      await s.token_abi.heartbeat(bn, b.hash, sw_features, common.zerofee_callopts);
   189                      assert.fail('It should fail');
   190                  } catch(e) {
   191                      assert.match(e.message, /Not active/);
   192                  }
   193              });
   194  
   195              it('should refuse to invalidate() vote for self', async () => {
   196                  try {
   197                      await s.token_abi.invalidate(
   198                          owner1, {from: owner1, ...common.zerofee_callopts});
   199                      assert.fail('It should fail');
   200                  } catch(e) {
   201                      assert.match(e.message, /Invalidation for self/);
   202                  }
   203              });
   204  
   205              it('should refuse to invalidate() not active', async () => {
   206                  try {
   207                      await s.token_abi.invalidate(masternode2, common.zerofee_callopts);
   208                      assert.fail('It should fail');
   209                  } catch(e) {
   210                      assert.match(e.message, /Not active caller/);
   211                  }
   212              });
   213  
   214              it('should not be isActive()', async () => {
   215                  const res = await s.token_abi.isActive(masternode1);
   216                  expect(res).false;
   217              });
   218  
   219              it('should correctly count()', async () => {
   220                  const res = await s.token_abi.count();
   221                  assert.equal(res[0], 0);
   222                  assert.equal(res[1], 0);
   223                  assert.equal(res[2], 0);
   224              });
   225  
   226              it('should handle info()', async () => {
   227                  try {
   228                      await s.token_abi.info(masternode1);
   229                      assert.fail('It should fail');
   230                  } catch (e) {
   231                      assert.match(e.message, /Unknown masternode/);
   232                  }
   233              });
   234  
   235              it('should handle ownerInfo()', async () => {
   236                  try {
   237                      await s.token_abi.ownerInfo(owner1);
   238                      assert.fail('It should fail');
   239                  } catch (e) {
   240                      assert.match(e.message, /Unknown owner/);
   241                  }
   242              });
   243  
   244              it('should process reward() to Treasury', async () => {
   245                  const treasury_before = toBN(await web3.eth.getBalance(s.treasury_impl.address));
   246  
   247                  let r = await s.reward_abi.getReward(0);
   248                  assert.equal(r.valueOf(), 0);
   249  
   250                  const count = 3;
   251                  
   252                  for (let i = count; i > 0; --i) {
   253                      r = await s.reward_abi.getReward(i);
   254  
   255                      if (r.eq(toBN(0))) {
   256                          // superblock case
   257                          r = await s.reward_abi.getReward(i+1);
   258                      }
   259  
   260                      expect(r.toString()).eql(reward.toString());
   261                      await s.reward_abi.reward({
   262                          from: not_owner,
   263                          value: r
   264                      });
   265                  }
   266  
   267                  // Kick the rest
   268                  await s.reward_abi.reward();
   269  
   270                  const treasury_after = toBN(await web3.eth.getBalance(s.treasury_impl.address));
   271                  expect(treasury_after.sub(treasury_before).toString())
   272                      .eql(reward.mul(toBN(count)).toString());
   273              });
   274  
   275              it('should handle onCollateralUpdate()', async () => {
   276                  await s.token_abi.onCollateralUpdate(owner1);
   277              });
   278  
   279              it('collateralLimits() should return correct values', async () => {
   280                  let limits = await s.token_abi.collateralLimits();
   281                  common.stringifyBN(web3, limits);
   282                  expect(limits).include({
   283                      min: '1000000000000000000000', // 1000 NRG
   284                      max: '100000000000000000000000', // 100,000 NRG
   285                  });
   286              });
   287  
   288              it('should handle enumerate()', async () => {
   289                  expect(await s.token_abi.enumerate()).lengthOf(0);
   290              });
   291  
   292              it.skip('must forbid more than one reward() per block', async () => {
   293                  // Bug: https://github.com/trufflesuite/truffle/issues/1389
   294                  const batch = web3.eth.BatchRequest();
   295                  batch.add(s.reward_abi.reward.request({value: reward}));
   296                  batch.add(s.reward_abi.reward.request({value: reward}));
   297  
   298                  try {
   299                      await batch.execute();
   300                      assert.fail('It must fail');
   301                  } catch (e) {
   302                      assert.match(e.message, /Call outside of governance/);
   303                  }
   304              });
   305          });
   306  
   307          describe('Single MN', () => {
   308              let announced_block;
   309  
   310              it('should refuse announce() without collateral', async () => {
   311                  try {
   312                      await s.token_abi.announce(
   313                          masternode1, ip1, enode1, { from: not_owner });
   314                      assert.fail('It should fail');
   315                  } catch (e) {
   316                      assert.match(e.message, /Invalid collateral/);
   317                  }
   318  
   319                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(0);
   320              });
   321  
   322              const non_routables = {
   323                  '127.0.0.0/8' : [ 0x7F000001, 0x7FFFFFFF ],
   324                  '10.0.0.0/8' : [ 0x0A000001, 0x0AFFFFFF ],
   325                  '172.16.0.0/12' : [ 0xAC100001, 0xAC108001 ],
   326                  '192.168.0.0/16' : [ 0xC0A80001, 0xC0A88001 ],
   327                  '0.0.0.0/8' : [ 0x00123456 ],
   328                  '100.64.0.0/10' : [ 0x64400001, 0x64480001 ],
   329                  '169.254.0.0/16' : [ 0xA9FE0001, 0xA9FEFFFF ],
   330                  '198.18.0.0/15' : [ 0xC6120001, 0xC613FFFF ],
   331                  '198.51.100.0/24' : [ 0xC6336401, 0xC63364FF ],
   332                  '203.0.113.0/24' : [ 0xCB007101, 0xCB0071FE ],
   333                  '224.0.0.0/4' : [ 0xE0000001, 0xE80FF001 ],
   334                  '240.0.0.0/4' : [ 0xF0000001, 0xF800FFFF ],
   335                  '255.255.255.255/32' : [ 0xFFFFFFFF ],
   336              };
   337  
   338              for (let k in non_routables) {
   339                  it(`should refuse announce() non-routable IPs: ${k}`, async () => {
   340                      for (let ip of non_routables[k]) {
   341                          try {
   342                              await s.token_abi.announce(
   343                                  masternode1, ip, enode1, { from: owner1 });
   344                              assert.fail('It should fail');
   345                          } catch (e) {
   346                              assert.match(e.message, /Wrong IP/);
   347                          }
   348                      }
   349                  });
   350              }
   351  
   352              it('should announce()', async () => {
   353                  const res = await s.mntoken_abi.balanceInfo(owner1);
   354                  assert.equal(res['0'].valueOf(), collateral1);
   355  
   356                  await s.token_abi.announce(
   357                      masternode1, ip1, enode1, { from: owner1 });
   358  
   359                  const ann_e = await s.orig.getPastEvents('Announced', common.evt_last_block);
   360                  expect(ann_e).lengthOf(1);
   361                  common.stringifyBN(web3, ann_e[0].args);
   362                  expect(ann_e[0].args).deep.include({
   363                      '0': masternode1,
   364                      '1': owner1,
   365                      '2': ip1.toString(),
   366                      '3': enode1,
   367                      '4': toBN(collateral1).toString(),
   368                      '__length__': 5,
   369                      'masternode': masternode1,
   370                      'owner': owner1,
   371                      'ipv4address': ip1.toString(),
   372                      'enode': enode1,
   373                      'collateral': toBN(collateral1).toString(),
   374                  });
   375  
   376                  const den_e = await s.orig.getPastEvents('Denounced', common.evt_last_block);
   377                  expect(den_e).lengthOf(0);
   378              });
   379  
   380              it('should re-announce MN', async () => {
   381                  await s.token_abi.announce(
   382                      masternode1, ip1, enode1, { from: owner1 });
   383  
   384                  const ann_e = await s.orig.getPastEvents('Announced', common.evt_last_block);
   385                  expect(ann_e).lengthOf(1);
   386                  expect(ann_e[0].args).deep.include({
   387                      '0': masternode1,
   388                      '1': owner1,
   389                      '2': ip1,
   390                      '3': enode1,
   391                      '4': toBN(collateral1),
   392                      '__length__': 5,
   393                      'masternode': masternode1,
   394                      'owner': owner1,
   395                      'ipv4address': ip1,
   396                      'enode': enode1,
   397                      'collateral': toBN(collateral1),
   398                  });
   399  
   400                  const den_e = await s.orig.getPastEvents('Denounced', common.evt_last_block);
   401                  expect(den_e).lengthOf(1);
   402                  expect(den_e[0].args).deep.include({
   403                      '0': masternode1,
   404                      '1': owner1,
   405                      '__length__': 2,
   406                      'masternode': masternode1,
   407                      'owner': owner1,
   408                  });
   409  
   410                  announced_block = await web3.eth.getBlockNumber();
   411              });
   412  
   413              it('should refuse announce() another owner\'s MN', async () => {
   414                  try {
   415                      await s.token_abi.announce(
   416                          masternode1, ip2, enode2, { from: owner2 });
   417                      assert.fail('It should fail');
   418                  } catch (e) {
   419                      assert.match(e.message, /Invalid owner/);
   420                  }
   421  
   422                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(0);
   423              });
   424  
   425              it('should refuse denounce() another owner\'s MN', async () => {
   426                  try {
   427                      await s.token_abi.denounce(masternode1, { from: owner2 });
   428                      assert.fail('It should fail');
   429                  } catch (e) {
   430                      assert.match(e.message, /Invalid owner/);
   431                  }
   432  
   433                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(0);
   434              });
   435  
   436              it('should forbid heartbeat() at wrong time', async () => {
   437                  const bn = await web3.eth.getBlockNumber();
   438                  const b = await web3.eth.getBlock(bn);
   439  
   440                  // The first must succeed
   441                  await s.token_abi.heartbeat(bn, b.hash, sw_features, {from: masternode1, ...common.zerofee_callopts});
   442  
   443                  try {
   444                      await s.token_abi.heartbeat(bn, b.hash, sw_features, {from: masternode1, ...common.zerofee_callopts});
   445                      assert.fail('It should fail');
   446                  } catch (e) {
   447                      assert.match(e.message, /Too early/);
   448                  }
   449  
   450                  await common.moveTime(web3, 59*30);
   451  
   452                  try {
   453                      await s.token_abi.heartbeat(bn, b.hash, sw_features, {from: masternode1, ...common.zerofee_callopts});
   454                      assert.fail('It should fail');
   455                  } catch (e) {
   456                      assert.match(e.message, /Too early/);
   457                  }
   458              });
   459  
   460              it('should be isActive()', async () => {
   461                  expect(await s.token_abi.isActive(masternode1)).true;
   462                  expect(await s.token_abi.isActive(masternode2)).false;
   463              });
   464  
   465              it('should handle onCollateralUpdate()', async () => {
   466                  await s.token_abi.onCollateralUpdate(owner1);
   467                  await s.token_abi.onCollateralUpdate(owner2);
   468                  expect(await s.token_abi.isActive(masternode1)).true;
   469                  expect(await s.token_abi.isActive(masternode2)).false;
   470              });
   471  
   472              it('should canHeartbeat()', async () => {
   473                  expect(await s.token_abi.canHeartbeat(masternode1)).false;
   474                  expect(await s.token_abi.canHeartbeat(masternode2)).false;
   475  
   476                  await common.moveTime(web3, 60*30+1);
   477  
   478                  expect(await s.token_abi.canHeartbeat(masternode1)).true;
   479                  expect(await s.token_abi.canHeartbeat(masternode2)).false;
   480              });
   481  
   482              it('should heartbeat()', async () => {
   483                  const s1 = await s.orig.mn_status(masternode1);
   484                  const bn = await web3.eth.getBlockNumber();
   485                  const b = await web3.eth.getBlock(bn);
   486  
   487                  await s.token_abi.heartbeat(bn, b.hash, sw_features, {from: masternode1, ...common.zerofee_callopts});
   488  
   489                  const s2 = await s.orig.mn_status(masternode1);
   490                  expect(s2.next_heartbeat.gt(s1.next_heartbeat)).true;
   491                  expect(s2.next_heartbeat.gt(b.timestamp)).true;
   492  
   493                  await checkHeartbeat();
   494              });
   495  
   496              it('should correctly count', async () => {
   497                  const res = await s.token_abi.count();
   498                  assert.equal(res[0], 1);
   499                  assert.equal(res[1], 1);
   500                  assert.equal(res[2].toString(), collateral1.toString());
   501              });
   502  
   503              it('should produce info()', async () => {
   504                  const info = await s.token_abi.info(masternode1);
   505                  common.stringifyBN(web3, info);
   506                  expect(info).deep.include({
   507                      owner: owner1,
   508                      ipv4address: toBN(ip1).toString(),
   509                      enode: enode1,
   510                      collateral: toBN(collateral1).toString(),
   511                      sw_features: sw_features.toString(),
   512                  });
   513              });
   514  
   515              it('should produce ownerInfo()', async () => {
   516                  const info = await s.token_abi.ownerInfo(owner1);
   517                  common.stringifyBN(web3, info);
   518                  expect(info).deep.include({
   519                      masternode: masternode1,
   520                      ipv4address: toBN(ip1).toString(),
   521                      enode: enode1,
   522                      collateral: toBN(collateral1).toString(),
   523                      announced_block: announced_block.toString(),
   524                      sw_features: sw_features.toString(),
   525                  });
   526              });
   527  
   528              it('should process reward()', async () => {
   529                  const treasury_before = toBN(await web3.eth.getBalance(s.treasury_impl.address));
   530                  const owner_before = toBN(await web3.eth.getBalance(owner1));
   531                  const count = 3;
   532  
   533                  for (let i = count; i > 0; --i) {
   534                      const r = await s.reward_abi.getReward(i);
   535                      expect(r).eql(reward);
   536                      await s.reward_abi.reward({
   537                          from: owner2,
   538                          value: r
   539                      });
   540                  }
   541  
   542                  const treasury_after = toBN(await web3.eth.getBalance(s.treasury_impl.address));
   543                  expect(treasury_before.toString()).equal(treasury_after.toString());
   544  
   545                  const owner_after = toBN(await web3.eth.getBalance(owner1));
   546                  expect(owner_after.sub(owner_before).toString())
   547                      .eql(reward.mul(toBN(count)).toString());
   548              });
   549  
   550              it('should handle onCollateralUpdate()', async () => {
   551                  await s.token_abi.onCollateralUpdate(owner1);
   552                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(0);
   553              });
   554  
   555              it('should handle enumerate()', async () => {
   556                  expect(await s.token_abi.enumerate()).members([masternode1]);
   557              });
   558  
   559              it('should forbid heartbeat() too late', async () => {
   560                  const bn = await web3.eth.getBlockNumber();
   561                  const b = await web3.eth.getBlock(bn);
   562  
   563                  expect(await s.token_abi.canHeartbeat(masternode1)).false;
   564  
   565                  try {
   566                      await s.token_abi.heartbeat(bn, b.hash, sw_features, {from: masternode1, ...common.zerofee_callopts});
   567                      assert.fail('It should fail');
   568                  } catch (e) {
   569                      assert.match(e.message, /Too early/);
   570                  }
   571  
   572                  const mn1_status = await s.orig.mn_status(masternode1);
   573                  let to_move = (mn1_status.next_heartbeat.add(toBN(2*60*60+1)));
   574                  to_move = to_move.sub(toBN((await web3.eth.getBlock('latest')).timestamp));
   575  
   576                  await common.moveTime(web3, to_move.toNumber());
   577  
   578                  expect(await s.token_abi.canHeartbeat(masternode1)).false;
   579  
   580                  try {
   581                      await s.token_abi.heartbeat(bn, b.hash, '0', {from: masternode1, ...common.zerofee_callopts});
   582                      assert.fail('It should fail');
   583                  } catch (e) {
   584                      assert.match(e.message, /Not active/);
   585                  }
   586  
   587                  // Denounce does not happen on read-only
   588                  expect(await s.orig.getPastEvents(
   589                      'Denounced', common.evt_last_block)).lengthOf(0);
   590              });
   591  
   592              it('should denounce() on collateral withdrawal', async() => {
   593                  await s.token_abi.announce(
   594                      masternode1, ip1, enode1, { from: owner1 });
   595  
   596                  await s.mntoken_abi.withdrawCollateral(collateral1, {from: owner1});
   597  
   598                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1);
   599                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(0);
   600                  expect(await s.token_abi.enumerate()).members([]);
   601              });
   602  
   603              it('should re-announce() on collateral change', async() => {
   604                  // Initial
   605                  await s.mntoken_abi.depositCollateral({
   606                      from: owner1,
   607                      value: collateral1,
   608                  });
   609                  await s.token_abi.announce(
   610                      masternode1, ip1, enode1, { from: owner1 });
   611  
   612                  // Change +
   613                  await s.mntoken_abi.depositCollateral({
   614                      from: owner1,
   615                      value: collateral1,
   616                  });
   617  
   618                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1);
   619                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(1);
   620                  expect(await s.token_abi.enumerate()).members([masternode1]);
   621  
   622                  // Change -
   623                  await s.mntoken_abi.withdrawCollateral(collateral1, {from: owner1});
   624  
   625                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1);
   626                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(1);
   627                  expect(await s.token_abi.enumerate()).members([masternode1]);
   628              });
   629  
   630              it('should denounce()', async()=> {
   631                  await s.token_abi.denounce(masternode1, { from: owner1 });
   632                  const evt = await s.orig.getPastEvents('Denounced', common.evt_last_block);
   633                  expect(evt).lengthOf(1);
   634                  expect(evt[0].args).deep.include({
   635                      '0': masternode1,
   636                      '1': owner1,
   637                      '__length__': 2,
   638                      'masternode': masternode1,
   639                      'owner': owner1,
   640                  });
   641              });
   642          });
   643  
   644          describe('Two MN', () => {
   645              const nodes = [
   646                  {
   647                      masternode: masternode1,
   648                      ip: ip1,
   649                      enode: enode1,
   650                      owner: owner1,
   651                      collateral: collateral1,
   652                  },
   653                  {
   654                      masternode: masternode2,
   655                      ip: ip2,
   656                      enode: enode2,
   657                      owner: owner2,
   658                      collateral: collateral2,
   659                  },
   660              ];
   661  
   662              it('should announce()', async () => {
   663                  for (let mn of nodes) {
   664                      await s.token_abi.announce(
   665                          mn.masternode, mn.ip, mn.enode, { from: mn.owner });
   666                  }
   667  
   668                  const mn1_status = await s.orig.mn_status(masternode1);
   669                  const mn2_status = await s.orig.mn_status(masternode2);
   670                  expect(mn1_status.seq_payouts.toString()).equal('3');
   671                  expect(mn2_status.seq_payouts.toString()).equal('2');
   672              });
   673  
   674              it('should re-announce MN', async () => {
   675                  // back order to test current being left in place first
   676                  for (let mn of Array.from(nodes).reverse()) {
   677                      await s.token_abi.announce(
   678                          mn.masternode, mn.ip, mn.enode, { from: mn.owner });
   679  
   680                      const ann_e = await s.orig.getPastEvents('Announced', common.evt_last_block);
   681                      expect(ann_e).lengthOf(1);
   682                      common.stringifyBN(web3, ann_e[0].args);
   683                      expect(ann_e[0].args).deep.include({
   684                          '0': mn.masternode,
   685                          '1': mn.owner,
   686                          '2': toBN(mn.ip).toString(),
   687                          '3': mn.enode,
   688                          '4': toBN(mn.collateral).toString(),
   689                          '__length__': 5,
   690                          'masternode': mn.masternode,
   691                          'owner': mn.owner,
   692                          'ipv4address': toBN(mn.ip).toString(),
   693                          'enode': mn.enode,
   694                          'collateral': toBN(mn.collateral).toString(),
   695                      });
   696  
   697                      const den_e = await s.orig.getPastEvents('Denounced', common.evt_last_block);
   698                      expect(den_e).lengthOf(1);
   699                      common.stringifyBN(web3, den_e[0].args);
   700                      expect(den_e[0].args).deep.include({
   701                          '0': mn.masternode,
   702                          '1': mn.owner,
   703                          '__length__': 2,
   704                          'masternode': mn.masternode,
   705                          'owner': mn.owner,
   706                      });
   707                  }
   708              });
   709  
   710              it('should refuse announce() another owner\'s MN', async () => {
   711                  try {
   712                      await s.token_abi.announce(
   713                          masternode1, ip2, enode2, { from: owner2 });
   714                      assert.fail('It should fail');
   715                  } catch (e) {
   716                      assert.match(e.message, /Invalid owner/);
   717                  }
   718  
   719                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(0);
   720              });
   721  
   722              it('should refuse denounce() another owner\'s MN', async () => {
   723                  try {
   724                      await s.token_abi.denounce(masternode1, { from: owner2 });
   725                      assert.fail('It should fail');
   726                  } catch (e) {
   727                      assert.match(e.message, /Invalid owner/);
   728                  }
   729  
   730                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(0);
   731              });
   732  
   733              it('should be isActive()', async () => {
   734                  for (let mn of nodes) {
   735                      expect(await s.token_abi.isActive(mn.masternode)).true;
   736                  }
   737              });
   738  
   739              it('should heartbeat()', async () => {
   740                  await common.moveTime(web3, 60*30+1);
   741  
   742                  const s1 = await s.orig.mn_status(masternode1);
   743                  const s1o = await s.orig.mn_status(masternode2);
   744                  const bn = await web3.eth.getBlockNumber();
   745                  const b = await web3.eth.getBlock(bn);
   746  
   747                  await s.token_abi.heartbeat(bn, b.hash, sw_features, {from: masternode1, ...common.zerofee_callopts});
   748                  
   749                  const s2 = await s.orig.mn_status(masternode1);
   750                  expect(s2.next_heartbeat.gt(s1.next_heartbeat)).true;
   751                  expect(s2.next_heartbeat.gt(b.timestamp)).true;
   752  
   753                  const s2o = await s.orig.mn_status(masternode2);
   754                  expect(s2o.next_heartbeat.eq(s1o.next_heartbeat)).true;
   755                  
   756                  await checkHeartbeat();
   757              });
   758  
   759              it('should correctly count', async () => {
   760                  const res = await s.token_abi.count();
   761                  common.stringifyBN(web3, res);
   762                  expect(res).eql({
   763                      '0': '2',
   764                      '1': '2',
   765                      '2': toWei('5000', 'ether'),
   766                      '3': toWei('5000', 'ether'),
   767                      '4': toWei('10000', 'ether'),
   768                      'active': '2',
   769                      'total': '2',
   770                      'active_collateral': toWei('5000', 'ether'),
   771                      'total_collateral': toWei('5000', 'ether'),
   772                      'max_of_all_times': toWei('10000', 'ether'),
   773                  });
   774              });
   775  
   776              it('should produce info()', async () => {
   777                  for (let mn of nodes) {
   778                      const info = await s.token_abi.info(mn.masternode);
   779                      common.stringifyBN(web3, info);
   780                      expect(info).deep.include({
   781                          owner: mn.owner,
   782                          ipv4address: toBN(mn.ip).toString(),
   783                          enode: mn.enode,
   784                          collateral: toBN(mn.collateral).toString(),
   785                          sw_features: (mn.masternode === masternode1) ? sw_features.toString() : '0',
   786                      });
   787                  }
   788              });
   789  
   790              it('should process reward()', async () => {
   791                  const treasury_before = toBN(await web3.eth.getBalance(s.treasury_impl.address));
   792                  const owner1_before = toBN(await web3.eth.getBalance(owner1));
   793                  const owner2_before = toBN(await web3.eth.getBalance(owner2));
   794                  const count = 10;
   795                  let sb = false;
   796  
   797                  for (let i = count; i > 0; --i) {
   798                      let r = await s.reward_abi.getReward(i);
   799                      if (r.eq(toBN(0))) {
   800                          // superblock case
   801                          r = await s.reward_abi.getReward(i+1);
   802                          sb = true;
   803                      }
   804  
   805                      expect(r.toString()).eql(reward.toString());
   806  
   807                      await s.reward_abi.reward({
   808                          from: owner3,
   809                          value: r
   810                      });
   811                  }
   812  
   813                  expect(sb).true;
   814  
   815                  const treasury_after = toBN(await web3.eth.getBalance(s.treasury_impl.address));
   816                  expect(treasury_before.toString()).equal(treasury_after.toString());
   817  
   818                  const owner1_after = toBN(await web3.eth.getBalance(owner1));
   819                  const owner2_after = toBN(await web3.eth.getBalance(owner2));
   820                  expect(owner1_after.sub(owner1_before).toString())
   821                      .eql(reward.mul(toBN(6)).toString());
   822                  expect(owner2_after.sub(owner2_before).toString())
   823                      .eql(reward.mul(toBN(4)).toString());
   824              });
   825  
   826              it('should handle enumerate()', async () => {
   827                  expect(await s.token_abi.enumerate()).members([masternode1, masternode2]);
   828              });
   829  
   830              it('should denounce() on collateral withdrawal', async() => {
   831                  await s.token_abi.announce(
   832                      masternode1, ip1, enode1, { from: owner1 });
   833  
   834                  await s.mntoken_abi.withdrawCollateral(collateral1, {from: owner1});
   835  
   836                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1);
   837                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(0);
   838                  expect(await s.token_abi.enumerate()).members([masternode2]);
   839              });
   840  
   841              it('should re-announce() on collateral change', async() => {
   842                  // Initial
   843                  await s.mntoken_abi.depositCollateral({
   844                      from: owner1,
   845                      value: collateral1,
   846                  });
   847                  await s.token_abi.announce(
   848                      masternode1, ip1, enode1, { from: owner1 });
   849  
   850                  // Change +
   851                  await s.mntoken_abi.depositCollateral({
   852                      from: owner1,
   853                      value: collateral1,
   854                  });
   855  
   856                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1);
   857                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(1);
   858                  expect(await s.token_abi.enumerate()).members([masternode1, masternode2]);
   859  
   860                  // Change -
   861                  await s.mntoken_abi.withdrawCollateral(collateral1, {from: owner1});
   862  
   863                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1);
   864                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(1);
   865                  expect(await s.token_abi.enumerate()).members([masternode1, masternode2]);
   866              });
   867  
   868              it('should denounce()', async()=> {
   869                  for (let mn of nodes) {
   870                      await s.token_abi.denounce(mn.masternode, { from: mn.owner });
   871                      const evt = await s.orig.getPastEvents('Denounced', common.evt_last_block);
   872                      expect(evt).lengthOf(1);
   873                      expect(evt[0].args).deep.include({
   874                          '0': mn.masternode,
   875                          '1': mn.owner,
   876                          '__length__': 2,
   877                          'masternode': mn.masternode,
   878                          'owner': mn.owner,
   879                      });
   880                  }
   881              });
   882          });
   883  
   884          describe('Three MN', () => {
   885              const nodes = [
   886                  {
   887                      masternode: masternode1,
   888                      ip: ip1,
   889                      enode: enode1,
   890                      owner: owner1,
   891                      collateral: collateral1,
   892                  },
   893                  {
   894                      masternode: masternode2,
   895                      ip: ip2,
   896                      enode: enode2,
   897                      owner: owner2,
   898                      collateral: collateral2,
   899                  },
   900                  {
   901                      masternode: masternode3,
   902                      ip: ip3,
   903                      enode: enode3,
   904                      owner: owner3,
   905                      collateral: collateral3,
   906                  },
   907              ];
   908  
   909              it('should announce()', async () => {
   910                  for (let mn of nodes) {
   911                      await s.token_abi.announce(
   912                          mn.masternode, mn.ip, mn.enode, { from: mn.owner });
   913                  }
   914  
   915                  const mn1_status = await s.orig.mn_status(masternode1);
   916                  const mn2_status = await s.orig.mn_status(masternode2);
   917                  const mn3_status = await s.orig.mn_status(masternode3);
   918                  expect(mn1_status.seq_payouts.toString()).equal('3');
   919                  expect(mn2_status.seq_payouts.toString()).equal('2');
   920                  expect(mn3_status.seq_payouts.toString()).equal('1');
   921              });
   922  
   923              it('should re-announce MN', async () => {
   924                  // back order to test current being left in place first
   925                  for (let mn of Array.from(nodes).reverse()) {
   926                      await s.token_abi.announce(
   927                          mn.masternode, mn.ip, mn.enode, { from: mn.owner });
   928  
   929                      const ann_e = await s.orig.getPastEvents('Announced', common.evt_last_block);
   930                      expect(ann_e).lengthOf(1);
   931                      common.stringifyBN(web3, ann_e[0].args);
   932                      expect(ann_e[0].args).deep.include({
   933                          '0': mn.masternode,
   934                          '1': mn.owner,
   935                          '2': toBN(mn.ip).toString(),
   936                          '3': mn.enode,
   937                          '4': toBN(mn.collateral).toString(),
   938                          '__length__': 5,
   939                          'masternode': mn.masternode,
   940                          'owner': mn.owner,
   941                          'ipv4address': toBN(mn.ip).toString(),
   942                          'enode': mn.enode,
   943                          'collateral': toBN(mn.collateral).toString(),
   944                      });
   945  
   946                      const den_e = await s.orig.getPastEvents('Denounced', common.evt_last_block);
   947                      expect(den_e).lengthOf(1);
   948                      common.stringifyBN(web3, den_e[0].args);
   949                      expect(den_e[0].args).deep.include({
   950                          '0': mn.masternode,
   951                          '1': mn.owner,
   952                          '__length__': 2,
   953                          'masternode': mn.masternode,
   954                          'owner': mn.owner,
   955                      });
   956                  }
   957              });
   958  
   959              it('should be isActive()', async () => {
   960                  for (let mn of nodes) {
   961                      expect(await s.token_abi.isActive(mn.masternode)).true;
   962                      expect(await s.token_abi.isActive(mn.owner)).false;
   963                  }
   964              });
   965  
   966              it('should correctly count', async () => {
   967                  const res = await s.token_abi.count();
   968                  common.stringifyBN(web3, res);
   969                  expect(res).eql({
   970                      '0': '3',
   971                      '1': '3',
   972                      '2': toWei('6000', 'ether'),
   973                      '3': toWei('6000', 'ether'),
   974                      '4': toWei('10000', 'ether'),
   975                      'active': '3',
   976                      'total': '3',
   977                      'active_collateral': toWei('6000', 'ether'),
   978                      'total_collateral': toWei('6000', 'ether'),
   979                      'max_of_all_times': toWei('10000', 'ether'),
   980                  });
   981              });
   982  
   983              it('should produce info()', async () => {
   984                  for (let mn of nodes) {
   985                      const info = await s.token_abi.info(mn.masternode);
   986                      common.stringifyBN(web3, info);
   987                      expect(info).deep.include({
   988                          owner: mn.owner,
   989                          ipv4address: toBN(mn.ip).toString(),
   990                          enode: mn.enode,
   991                          collateral: toBN(mn.collateral).toString(),
   992                          sw_features: '0',
   993                      });
   994                  }
   995              });
   996  
   997              it('should process reward()', async () => {
   998                  const treasury_before = toBN(await web3.eth.getBalance(s.treasury_impl.address));
   999                  const owner1_before = toBN(await web3.eth.getBalance(owner1));
  1000                  const owner2_before = toBN(await web3.eth.getBalance(owner2));
  1001                  const owner3_before = toBN(await web3.eth.getBalance(owner3));
  1002                  const count = 18;
  1003                  let sb = false;
  1004                  
  1005                  for (let i = count; i > 0; --i) {
  1006                      let r = await s.reward_abi.getReward(i);
  1007                      if (r.eq(toBN(0))) {
  1008                          // superblock case
  1009                          r = await s.reward_abi.getReward(i+1);
  1010                          sb = true;
  1011                      }
  1012  
  1013                      expect(r.toString()).eql(reward.toString());
  1014  
  1015                      await s.reward_abi.reward({
  1016                          from: not_owner,
  1017                          value: r
  1018                      });
  1019  
  1020                      const target1 = await s.token_abi.validationTarget(masternode1);
  1021                      const target2 = await s.token_abi.validationTarget(masternode2);
  1022                      const target3 = await s.token_abi.validationTarget(masternode3);
  1023                      expect(target1).not.equal(masternode1);
  1024                      expect(target2).not.equal(masternode2);
  1025                      expect(target3).not.equal(masternode3);
  1026                      expect(target1).not.equal(target2);
  1027                      expect(target1).not.equal(target3);
  1028  
  1029                      if (i > 6 && i < 12 || i == 13) {
  1030                          let t = target1;
  1031  
  1032                          if (await isTargetChanges(s.token_abi, masternode1)) {
  1033                              // still a chance of fail.
  1034                              t = (t === masternode3) ? masternode2 : masternode3;
  1035                          }
  1036  
  1037                          const invalidator = (t === masternode3) ? masternode1 : masternode2;
  1038  
  1039                          if (await s.token_abi.canInvalidate(invalidator)) {
  1040                              await s.token_abi.invalidate(masternode3, {from: invalidator});
  1041                          }
  1042                      }
  1043                  }
  1044  
  1045                  expect(sb).true;
  1046  
  1047                  // One invalidation at round 2
  1048                  const treasury_after = toBN(await web3.eth.getBalance(s.treasury_impl.address));
  1049                  expect(treasury_after.sub(treasury_before).toString())
  1050                      .eql(reward.mul(toBN(1)).toString())
  1051  
  1052                  const owner1_after = toBN(await web3.eth.getBalance(owner1));
  1053                  const owner2_after = toBN(await web3.eth.getBalance(owner2));
  1054                  const owner3_after = toBN(await web3.eth.getBalance(owner3));
  1055                  expect(owner1_after.sub(owner1_before).toString())
  1056                      .eql(reward.mul(toBN(3+3+3)).toString());
  1057                  expect(owner2_after.sub(owner2_before).toString())
  1058                      .eql(reward.mul(toBN(2+2+2)).toString());
  1059                  expect(owner3_after.sub(owner3_before).toString())
  1060                      .eql(reward.mul(toBN(1+0+1)).toString());
  1061              });
  1062  
  1063  
  1064              it('should calculate validation target by periods', async () => {
  1065                  let bn = await web3.eth.getBlockNumber();
  1066                  const valTarget = () => {
  1067                      return s.token_abi.methods['validationTarget(address)'](masternode1, bn);
  1068                  }
  1069  
  1070                  let tmp = await valTarget();
  1071                  let target = tmp;
  1072  
  1073                  do {
  1074                      --bn;
  1075                      target = await valTarget();
  1076                  } while ( target === tmp );
  1077  
  1078                  const obn = bn;
  1079  
  1080                  for (let i = vperiod; i > 0; --i, --bn) {
  1081                      tmp = await valTarget();
  1082                      expect(tmp).equal(target);
  1083                  }
  1084  
  1085                  bn = obn + 1;
  1086  
  1087                  for (let i = vperiod; i > 0; --i, ++bn) {
  1088                      tmp = await valTarget();
  1089                      expect(tmp).not.equal(target);
  1090                  }
  1091              });
  1092  
  1093              it('should refuse invalidate() wrong target', async () => {
  1094                  try {
  1095                      let target = await s.token_abi.validationTarget(masternode1);
  1096  
  1097                      if ((target == masternode2) && !await isTargetChanges(s.token_abi, masternode1)) {
  1098                          target = masternode3;
  1099                      } else {
  1100                          target = masternode2;
  1101                      }
  1102                      
  1103                      await s.token_abi.invalidate(target, {from:masternode1, ...common.zerofee_callopts});
  1104                      assert.fail('It must fail');
  1105                  } catch (e) {
  1106                      assert.match(e.message, /Invalid target/);
  1107                  }
  1108              });
  1109  
  1110              it('should process reward() deactivate missing heartbeat', async () => {
  1111                  await common.moveTime(web3, 40*60);
  1112  
  1113                  {
  1114                      const b = await web3.eth.getBlock('latest');
  1115                      await s.token_abi.heartbeat(b.number, b.hash, '12', {from:masternode1, ...common.zerofee_callopts});
  1116                      await s.token_abi.heartbeat(b.number, b.hash, '23', {from:masternode2, ...common.zerofee_callopts});
  1117                      await s.token_abi.heartbeat(b.number, b.hash, '34', {from:masternode3, ...common.zerofee_callopts});
  1118                  }
  1119  
  1120                  await common.moveTime(web3, 70*60);
  1121  
  1122                  const treasury_before = toBN(await web3.eth.getBalance(s.treasury_impl.address));
  1123                  const owner1_before = toBN(await web3.eth.getBalance(owner1));
  1124                  const owner2_before = toBN(await web3.eth.getBalance(owner2));
  1125                  const owner3_before = toBN(await web3.eth.getBalance(owner3));
  1126                  const count = 18;
  1127                  let sb = false;
  1128  
  1129                  for (let i = count; i > 0; --i) {
  1130                      if (i == 12 || i == 8 || i == 4) {
  1131                          const bn = await web3.eth.getBlockNumber();
  1132                          const b = await web3.eth.getBlock(bn);
  1133                          await s.token_abi.heartbeat(bn, b.hash, '12', {from:masternode1, ...common.zerofee_callopts});
  1134                          await s.token_abi.heartbeat(bn, b.hash, '34', {from:masternode3, ...common.zerofee_callopts});
  1135                          await common.moveTime(web3, 91*60);
  1136                      }
  1137  
  1138                      let r = await s.reward_abi.getReward(i);
  1139                      if (r.eq(toBN(0))) {
  1140                          // superblock case
  1141                          r = await s.reward_abi.getReward(i+1);
  1142                          sb = true;
  1143                      }
  1144  
  1145                      expect(r.toString()).eql(reward.toString());
  1146  
  1147                      await s.reward_abi.reward({
  1148                          from: not_owner,
  1149                          value: r,
  1150                      });
  1151                  }
  1152  
  1153                  expect(sb).true;
  1154  
  1155                  const treasury_after = toBN(await web3.eth.getBalance(s.treasury_impl.address));
  1156                  const owner1_after = toBN(await web3.eth.getBalance(owner1));
  1157                  const owner2_after = toBN(await web3.eth.getBalance(owner2));
  1158                  const owner3_after = toBN(await web3.eth.getBalance(owner3));
  1159  
  1160                  // The treasury must get reward of nodes without votes by design
  1161                  expect(treasury_after.sub(treasury_before).toString())
  1162                      .eql(reward.mul(toBN(0)).toString())
  1163                  expect(owner1_after.sub(owner1_before).toString())
  1164                      .eql(reward.mul(toBN(3+3+3+3)).toString());
  1165                  expect(owner2_after.sub(owner2_before).toString())
  1166                      .eql(reward.mul(toBN(2+0+0+0)).toString());
  1167                  expect(owner3_after.sub(owner3_before).toString())
  1168                      .eql(reward.mul(toBN(1+1+1+1)).toString());
  1169  
  1170                  expect(await s.token_abi.isActive(masternode1)).true;
  1171                  expect(await s.token_abi.isActive(masternode2)).false;
  1172                  expect(await s.token_abi.isActive(masternode3)).true;
  1173              });
  1174  
  1175              it('should skip inactive node from validation', async () => {
  1176                  const target1 = await s.token_abi.validationTarget(masternode1);
  1177                  const target3 = await s.token_abi.validationTarget(masternode3);
  1178                  expect(target1).eql(masternode3);
  1179                  expect(target3).eql(masternode1);
  1180              });
  1181  
  1182              it('should canInvalidate()', async () => {
  1183                  expect(await s.token_abi.canInvalidate(masternode1)).true;
  1184                  expect(await s.token_abi.canInvalidate(masternode2)).false;
  1185                  expect(await s.token_abi.canInvalidate(masternode3)).true;
  1186              });
  1187  
  1188              it('should refuse invalidate() by inactive node', async () => {
  1189                  try {
  1190                      await s.token_abi.invalidate(masternode1, {from:masternode2, ...common.zerofee_callopts});
  1191                      assert.fail('It must fail');
  1192                  } catch (e) {
  1193                      assert.match(e.message, /Not active caller/);
  1194                  }
  1195              });
  1196  
  1197              it('should refuse double invalidate()', async () => {
  1198                  expect(await s.token_abi.canInvalidate(masternode1)).true;
  1199                  expect(await s.token_abi.canInvalidate(masternode3)).true;
  1200                  await s.token_abi.invalidate(masternode3, {from:masternode1, ...common.zerofee_callopts});
  1201                  expect(await s.token_abi.canInvalidate(masternode1)).false;
  1202                  expect(await s.token_abi.canInvalidate(masternode3)).true;
  1203  
  1204                  try {
  1205                      for (let i = 0; i < vperiod; ++i) {
  1206                          await s.token_abi.invalidate(masternode3, {from:masternode1, ...common.zerofee_callopts});
  1207                      }
  1208                      assert.fail('It must fail');
  1209                  } catch (e) {
  1210                      assert.match(e.message, /Already invalidated/);
  1211                  }
  1212              });
  1213  
  1214              it('should handle enumerate()', async () => {
  1215                  expect(await s.token_abi.enumerate()).members([
  1216                      masternode1, masternode2, masternode3]);
  1217              });
  1218  
  1219              it('should handle enumerateActive()', async () => {
  1220                  expect(await s.token_abi.enumerateActive()).members([
  1221                      masternode1, masternode3]);
  1222              });
  1223  
  1224              it('should denounce() on collateral withdrawal', async() => {
  1225                  await s.token_abi.announce(
  1226                      masternode1, ip1, enode1, { from: owner1 });
  1227  
  1228                  await s.mntoken_abi.withdrawCollateral(collateral1, {from: owner1});
  1229  
  1230                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1);
  1231                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(0);
  1232                  expect(await s.token_abi.enumerate()).members([masternode2, masternode3]);
  1233              });
  1234  
  1235              it('should re-announce() on collateral change', async() => {
  1236                  // Initial
  1237                  await s.mntoken_abi.depositCollateral({
  1238                      from: owner1,
  1239                      value: collateral1,
  1240                  });
  1241                  await s.token_abi.announce(
  1242                      masternode1, ip1, enode1, { from: owner1 });
  1243  
  1244                  // Change +
  1245                  await s.mntoken_abi.depositCollateral({
  1246                      from: owner1,
  1247                      value: collateral1,
  1248                  });
  1249  
  1250                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1);
  1251                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(1);
  1252                  expect(await s.token_abi.enumerate()).members([masternode1, masternode2, masternode3]);
  1253  
  1254                  // Change -
  1255                  await s.mntoken_abi.withdrawCollateral(collateral1, {from: owner1});
  1256  
  1257                  expect(await s.orig.getPastEvents('Denounced', common.evt_last_block)).lengthOf(1);
  1258                  expect(await s.orig.getPastEvents('Announced', common.evt_last_block)).lengthOf(1);
  1259                  expect(await s.token_abi.enumerate()).members([masternode1, masternode2, masternode3]);
  1260              });
  1261  
  1262              it('should cleanup inactive node', async () => {
  1263                  await common.moveTime(web3, 25*60*60);
  1264  
  1265                  for (let i = 4; i > 0; --i) {
  1266                      await s.reward_abi.reward({
  1267                          from: not_owner,
  1268                          value: reward
  1269                      });
  1270                  }
  1271  
  1272                  expect(await s.token_abi.enumerate()).members([masternode1, masternode3]);
  1273              });
  1274  
  1275              it('should denounce()', async()=> {
  1276                  for (let mn of nodes) {
  1277                      await s.token_abi.denounce(mn.masternode, { from: mn.owner });
  1278                      const evt = await s.orig.getPastEvents('Denounced', common.evt_last_block);
  1279  
  1280                      if (mn.masternode == masternode2) {
  1281                          expect(evt).lengthOf(0);
  1282                          continue;
  1283                      }
  1284  
  1285                      expect(evt).lengthOf(1);
  1286                      expect(evt[0].args).deep.include({
  1287                          '0': mn.masternode,
  1288                          '1': mn.owner,
  1289                          '__length__': 2,
  1290                          'masternode': mn.masternode,
  1291                          'owner': mn.owner,
  1292                      });
  1293                  }
  1294              });
  1295  
  1296              it('should correctly count() ever max', async () => {
  1297                  const res = await s.token_abi.count();
  1298                  common.stringifyBN(web3, res);
  1299                  expect(res).eql({
  1300                      '0': '0',
  1301                      '1': '0',
  1302                      '2': toWei('0', 'ether'),
  1303                      '3': toWei('0', 'ether'),
  1304                      '4': toWei('10000', 'ether'),
  1305                      'active': '0',
  1306                      'total': '0',
  1307                      'active_collateral': toWei('0', 'ether'),
  1308                      'total_collateral': toWei('0', 'ether'),
  1309                      'max_of_all_times': toWei('10000', 'ether'),
  1310                  });
  1311              });
  1312  
  1313              it('should migrate from V1', async () => {
  1314                  const collateral = toWei('10000', 'ether');
  1315  
  1316                  // Spork registry
  1317                  const registry_proxy = await MockProxy.new();
  1318                  const registry = await MockSporkRegistry.new(registry_proxy.address);
  1319                  await registry_proxy.setImpl(registry.address);
  1320  
  1321                  // MNReg proxy
  1322                  const mn_proxy = await MockProxy.new();
  1323                  const imn = await IMasternodeRegistryV2.at(mn_proxy.address);
  1324  
  1325                  const impl1 = await MasternodeRegistryV1.new(
  1326                      mn_proxy.address,
  1327                      s.mntoken_proxy_addr,
  1328                      s.treasury_proxy_addr,
  1329                      common.mnregistry_config
  1330                  );
  1331                  const impl2 = await MasternodeRegistryV2.new(
  1332                      mn_proxy.address,
  1333                      s.mntoken_proxy_addr,
  1334                      s.treasury_proxy_addr,
  1335                      common.mnregistry_config_v2,
  1336                      common.mnreg_deploy_opts
  1337                  );
  1338                  await mn_proxy.setImpl(impl1.address);
  1339  
  1340                  // Announce
  1341                  for (let mn of nodes) {
  1342                      if (mn.masternode === masternode3) {
  1343                          continue;
  1344                      }
  1345  
  1346                      await s.mntoken_abi.depositCollateral({
  1347                          from: mn.owner,
  1348                          value: collateral,
  1349                      });
  1350  
  1351                      await imn.announce(mn.masternode, mn.ip, mn.enode, { from: mn.owner });
  1352                  }
  1353  
  1354                  expect(await imn.enumerate()).members([masternode1, masternode2]);
  1355  
  1356                  expect(await impl2.enumerate()).members([]);
  1357  
  1358                  // Upgrade
  1359                  const { logs } = await mn_proxy.proposeUpgrade(impl2.address, 0);
  1360                  s.assert.equal(logs.length, 1);
  1361  
  1362                  const proposal = await MockProposal.at(logs[0].args['1']);
  1363  
  1364                  await proposal.setAccepted();
  1365                  await mn_proxy.upgrade(proposal.address);
  1366  
  1367                  // Ensure MNs are still there
  1368                  expect(await imn.enumerate()).members([masternode1, masternode2]);
  1369  
  1370                  expect(await impl2.enumerate()).members([masternode1, masternode2]);
  1371              });
  1372          });
  1373  
  1374          const SPI_MN_COUNT = process.env.SPI_MN_COUNT || 10; // set to 10000 at runtime
  1375          describe(`${SPI_MN_COUNT} MNs`, () => {
  1376              const nodes = [];
  1377  
  1378              let mntoken_orig;
  1379              let mntoken_proxy;
  1380              let mnreg_orig;
  1381              let mnreg_proxy;
  1382              let mnreg_abi;
  1383              let reward_abi;
  1384  
  1385              before(async () => {
  1386                  mntoken_proxy = await MockProxy.new();
  1387                  mnreg_proxy = await MockProxy.new();
  1388  
  1389                  mntoken_orig = await MockMasternodeTokenV2.new(
  1390                      mntoken_proxy.address, mnreg_proxy.address,
  1391                      common.mnreg_deploy_opts);
  1392                  await mntoken_proxy.setImpl(mntoken_orig.address);
  1393  
  1394                  const params = common.mnregistry_config_v2.slice();
  1395                  params[4] = 10;
  1396  
  1397                  mnreg_orig = await MasternodeRegistryV2.new(
  1398                      mnreg_proxy.address,
  1399                      mntoken_proxy.address,
  1400                      s.treasury_proxy_addr,
  1401                      params,
  1402                      common.mnreg_deploy_opts
  1403                  );
  1404                  await mnreg_proxy.setImpl(mnreg_orig.address);
  1405                  mnreg_abi = await IMasternodeRegistryV2.at(mnreg_orig.address);
  1406                  reward_abi = await IBlockReward.at(mnreg_orig.address);
  1407              });
  1408  
  1409              it('should generate metadata', async function() {
  1410                  this.timeout(7200e3);
  1411                  const c1k = toBN(toWei('1000', 'ether'));
  1412                  const for_fees = toBN(toWei('1', 'ether'));
  1413                  const e1 = fromAscii('12345678901234567890123456789012');
  1414  
  1415                  for (let i = 1; i <= SPI_MN_COUNT; ++i) {
  1416                      const e2 = (i.toString() + '000000').repeat(10).substr(0, 32);
  1417                      const masternode = await web3.eth.personal.newAccount('');
  1418                      const owner = await web3.eth.personal.newAccount('');
  1419                      const collateral = c1k.mul(toBN(1 + i%100));
  1420  
  1421                      await web3.eth.personal.unlockAccount(masternode, '', 0);
  1422                      await web3.eth.personal.unlockAccount(owner, '', 0);
  1423  
  1424                      nodes.push({
  1425                          masternode,
  1426                          owner,
  1427                          ip: ip1,
  1428                          enode: [e1, fromAscii(e2)],
  1429                          collateral,
  1430                      });
  1431  
  1432                      await web3.eth.sendTransaction({
  1433                          to: owner,
  1434                          from: owner1,
  1435                          value: for_fees,
  1436                      });
  1437                      await web3.eth.sendTransaction({
  1438                          to: masternode,
  1439                          from: owner1,
  1440                          value: for_fees,
  1441                      });
  1442                      await mntoken_orig.setBalance(owner, collateral);
  1443  
  1444                      if (i%100 === 0) {
  1445                          // eslint-disable-next-line no-console
  1446                          console.log(`Done ${i}`);
  1447                      }
  1448                  }
  1449              });
  1450  
  1451              it('should announce all', async function() {
  1452                  this.timeout(7200e3);
  1453                  let i = 0;
  1454  
  1455                  for (let n of nodes) {
  1456                      await mnreg_abi.announce(n.masternode, n.ip, n.enode, {
  1457                          from: n.owner
  1458                      });
  1459  
  1460                      if (++i%100 === 0) {
  1461                          // eslint-disable-next-line no-console
  1462                          console.log(`Done ${i}`);
  1463                      }
  1464                  }
  1465              });
  1466  
  1467              it('should simulate operation', async function() {
  1468                  this.timeout(7200e3);
  1469                  let i = 0;
  1470  
  1471                  await common.moveTime(web3, 60*30);
  1472  
  1473                  for (let { masternode } of nodes) {
  1474                      if (!await mnreg_abi.canHeartbeat(masternode)) {
  1475                          const status = await mnreg_orig.mn_status(masternode);
  1476                          let to_move = status.next_heartbeat.add(toBN(1));
  1477                          to_move = to_move.sub(toBN(await web3.eth.getBlock('latest')).timestamp);
  1478  
  1479                          await common.moveTime(web3, to_move.toNumber());
  1480                      }
  1481  
  1482                      const bn = await web3.eth.getBlockNumber();
  1483                      const b = await web3.eth.getBlock(bn);
  1484  
  1485                      await mnreg_abi.heartbeat(bn, b.hash, '0', {
  1486                          from: masternode,
  1487                          ...common.zerofee_callopts,
  1488                      });
  1489                      await reward_abi.reward({value: reward});
  1490  
  1491                      if (++i%100 === 0) {
  1492                          // eslint-disable-next-line no-console
  1493                          console.log(`Done ${i}`);
  1494                      }
  1495                  }
  1496              });
  1497          });
  1498      });
  1499  
  1500      //---
  1501      describe('common post', () => common.govPostTests(s) );
  1502  });