github.com/codingfuture/orig-energi3@v0.8.4/energi/contracts/test/CheckpointRegistryV2.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 CheckpointRegistryV2 = artifacts.require('CheckpointRegistryV2');
    24  const ICheckpointRegistry = artifacts.require('ICheckpointRegistry');
    25  const ICheckpoint = artifacts.require('ICheckpoint');
    26  const ICheckpointV2 = artifacts.require('ICheckpointV2');
    27  const StorageCheckpointRegistryV1 = artifacts.require('StorageCheckpointRegistryV1');
    28  
    29  const MasternodeRegistryV1 = artifacts.require('MasternodeRegistryV1');
    30  const MasternodeTokenV1 = artifacts.require('MasternodeTokenV1');
    31  
    32  const common = require('./common');
    33  const ethjs = require('ethereumjs-util');
    34  
    35  contract("CheckpointRegistryV2", async accounts => {
    36      const s = {
    37          artifacts,
    38          accounts,
    39          assert,
    40          it,
    41          web3,
    42      };
    43  
    44      before(async () => {
    45          s.registry_orig = await MasternodeRegistryV1.deployed();
    46          s.registry = await MasternodeRegistryV1.at(await s.registry_orig.proxy());
    47  
    48          s.mntoken_orig = await MasternodeTokenV1.deployed();
    49          s.mntoken = await MasternodeTokenV1.at(await s.mntoken_orig.proxy());
    50  
    51          s.orig = await CheckpointRegistryV2.deployed();
    52          s.proxy = await MockProxy.at(await s.orig.proxy());
    53          s.fake = await MockContract.new(s.proxy.address);
    54          s.proxy_abi = await CheckpointRegistryV2.at(s.proxy.address);
    55          s.token_abi = await ICheckpointRegistry.at(s.proxy.address);
    56          await s.proxy.setImpl(s.orig.address);
    57          s.storage = await StorageCheckpointRegistryV1.at(await s.proxy_abi.v1storage());
    58          Object.freeze(s);
    59      });
    60  
    61      after(async () => {
    62          const impl = await CheckpointRegistryV2.new(
    63              s.proxy.address, s.registry.address, accounts[3]);
    64          await s.proxy.setImpl(impl.address);
    65      });
    66  
    67      describe('common pre', () => common.govPreTests(s) );
    68  
    69      //---
    70      describe('Primary', () => {
    71          const { fromAscii, toBN, toWei } = web3.utils;
    72  
    73          const collateral1 = toBN(toWei('50000', 'ether'));
    74          const owner1 = accounts[0];
    75          const sigacc = web3.eth.accounts.privateKeyToAccount(
    76              '0x4118811427785a33e8c61303e64b43d0d6b69db3caa4074f2ddbdec0b9d4c878');
    77          const mnacc1 = web3.eth.accounts.create();
    78          const nonmnacc1 = web3.eth.accounts.create();
    79          const masternode1 = mnacc1.address;
    80          const ip1 = toBN(0x12345678);
    81          const enode_common = '123456789012345678901234567890'
    82          const enode1 = [fromAscii(enode_common + '11'), fromAscii(enode_common + '11')];
    83  
    84          const ecsign = (acc, hash) => {
    85              const sig = ethjs.ecsign(
    86                  toBN(hash).toArrayLike(Buffer),
    87                  toBN(acc.privateKey).toArrayLike(Buffer)
    88              );
    89              return '0x'+[sig.r.toString('hex'), sig.s.toString('hex'), sig.v.toString(16)].join('');
    90          };
    91  
    92          const cp_count = 100;
    93          const cp_sign = cp_count - 1;
    94          const block_hash = '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
    95          let cp_list;
    96          let mn_sig;
    97          let cpp_sig;
    98  
    99          const mn_sig_reg = async (acc, num, block_hash) => {
   100              const sigbase = await s.token_abi.signatureBase(num, block_hash); 
   101              return ecsign(acc, sigbase);
   102          };
   103          const mn_sig_cp = async (acc, cp_address) => {
   104              const cp = await ICheckpoint.at(cp_address);
   105              const sigbase = await cp.signatureBase();
   106              return ecsign(acc, sigbase);
   107          };
   108  
   109          before(async () => {
   110              await s.mntoken.depositCollateral({
   111                  from: owner1,
   112                  value: collateral1,
   113              });
   114              await s.registry.announce(masternode1, ip1, enode1, {from: owner1});
   115          });
   116  
   117          after(async () => {
   118              await s.mntoken.withdrawCollateral(collateral1, {
   119                  from: owner1,
   120              });
   121          });
   122  
   123          it('should refuse propose() with invalid signature length', async () => {
   124              try {
   125                  await s.token_abi.propose(1, block_hash, block_hash);
   126                  assert.fail('It must fail');
   127              } catch (e) {
   128                  assert.match(e.message, /Invalid signature length/);
   129              }
   130          });
   131  
   132          it('should refuse propose() from invalid signer', async () => {
   133              try {
   134                  await s.token_abi.propose(
   135                      1, block_hash, await mn_sig_reg(mnacc1, 1, block_hash));
   136                  assert.fail('It must fail');
   137              } catch (e) {
   138                  assert.match(e.message, /Invalid signer/);
   139              }
   140          });
   141  
   142          it('should propose() from valid signer', async () => {
   143              for (let i = 1; i <= cp_count; ++i) {
   144                  const num = parseInt(i/2);
   145                  cpp_sig = await mn_sig_reg(sigacc, num, block_hash);
   146                  await s.token_abi.propose(
   147                      num, block_hash, cpp_sig);
   148              }
   149          });
   150  
   151          it('should checkpoints()', async () => {
   152              cp_list = await s.token_abi.checkpoints();
   153              expect(cp_list.length).equal(cp_count);
   154          });
   155  
   156          it('should refuse to sign() by non-MN', async() => {
   157              try {
   158                  await s.token_abi.sign(cp_list[cp_sign], ecsign(nonmnacc1, block_hash));
   159                  assert.fail('It must fail');
   160              } catch (e) {
   161                  assert.match(e.message, /Not active MN/);
   162              }
   163          });
   164  
   165          it('should refuse to sign() by invalid signature length', async() => {
   166              try {
   167                  await s.token_abi.sign(cp_list[cp_sign], block_hash);
   168                  assert.fail('It must fail');
   169              } catch (e) {
   170                  assert.match(e.message, /Invalid signature length/);
   171              }
   172          });
   173  
   174          it('should sign() by MN', async() => {
   175              mn_sig = await mn_sig_cp(mnacc1, cp_list[cp_sign]);
   176              await s.token_abi.sign(cp_list[cp_sign], mn_sig);
   177          });
   178  
   179          it('should refuse to sign() by already signed MN', async() => {
   180              try {
   181                  await s.token_abi.sign(cp_list[cp_sign], await mn_sig_cp(mnacc1, cp_list[cp_sign]));
   182                  assert.fail('It must fail');
   183              } catch (e) {
   184                  assert.match(e.message, /Already signed/);
   185              }
   186          });
   187  
   188          it('should refuse to sign() by CPP signer', async() => {
   189              try {
   190                  await s.token_abi.sign(cp_list[cp_sign], await mn_sig_cp(sigacc, cp_list[cp_sign]));
   191                  assert.fail('It must fail');
   192              } catch (e) {
   193                  assert.match(e.message, /Already signed/);
   194              }
   195          });
   196  
   197          it('should have correct signatureBase()', async () => {
   198              const hash = await s.token_abi.signatureBase(cp_sign+1, block_hash);
   199              const reqhash = web3.utils.soliditySha3(
   200                  "||Energi Blockchain Checkpoint||",
   201                  toBN(cp_sign + 1),
   202                  toBN(block_hash),
   203              );
   204              expect(hash.toString()).equal(reqhash.toString());
   205          });
   206  
   207          describe('CheckpointV2', async () => {
   208              it('should show info()', async () => {
   209                  const cp = await ICheckpoint.at(cp_list[cp_sign]);
   210                  const res = await cp.info();
   211  
   212                  common.stringifyBN(web3, res);
   213                  expect(res).include({
   214                      number: toBN(parseInt((cp_sign+1)/2)).toString(),
   215                      hash:   block_hash,
   216                  });
   217                  expect(res).include.keys('since');
   218              });
   219  
   220              it('should show signature()', async () => {
   221                  const cp = await ICheckpoint.at(cp_list[cp_sign]);
   222                  const res = await cp.signature(masternode1);
   223  
   224                  expect(res.toString()).equal(mn_sig);
   225              });
   226  
   227              it('should show signature() of CPP signer', async () => {
   228                  const cp = await ICheckpoint.at(cp_list[cp_sign]);
   229                  const res = await cp.signature(sigacc.address);
   230  
   231                  expect(res.toString()).equal(cpp_sig);
   232              });
   233  
   234              it('should fail signature() on not signed', async () => {
   235                  const cp = await ICheckpoint.at(cp_list[cp_sign]);
   236  
   237                  try {
   238                      await cp.signature(accounts[0]);
   239                      assert.fail('It must fail');
   240                  } catch (e) {
   241                      assert.match(e.message, /Not signed yet/);
   242                  }
   243              });
   244  
   245              it('should show signatures()', async () => {
   246                  const cp = await ICheckpoint.at(cp_list[cp_sign]);
   247                  const res = await cp.signatures();
   248  
   249                  expect(res).include(cpp_sig);
   250                  expect(res).include(mn_sig);
   251              });
   252  
   253              it('should have correct signatureBase()', async () => {
   254                  const cp = await ICheckpoint.at(cp_list[cp_sign]);
   255                  const hash = await cp.signatureBase();
   256                  const reqhash = web3.utils.soliditySha3(
   257                      "||Energi Blockchain Checkpoint||",
   258                      toBN(parseInt((cp_sign+1)/2)),
   259                      toBN(block_hash),
   260                  );
   261                  expect(hash.toString()).equal(reqhash.toString());
   262              });
   263  
   264              it('should correctly handle canVote()', async () => {
   265                  const num = 101;
   266                  await s.token_abi.propose(num, block_hash,
   267                      await mn_sig_reg(sigacc, num, block_hash));
   268                  const cps = await s.token_abi.checkpoints();
   269                  const cpa = cps[cps.length - 1];
   270                  const cp = await ICheckpointV2.at(cpa);
   271  
   272                  expect(await cp.canVote(sigacc.address)).false;
   273  
   274                  expect(await cp.canVote(masternode1)).true;
   275                  await s.token_abi.sign(cpa, await mn_sig_cp(mnacc1, cpa));
   276                  expect(await cp.canVote(masternode1)).false;
   277  
   278                  expect(await cp.canVote(nonmnacc1.address)).true;
   279  
   280                  for (let i = 0; i < 24*60-1; ++i) {
   281                      try {
   282                          expect(await cp.canVote(nonmnacc1.address)).true;
   283                      } catch (e) {
   284                          // eslint-disable-next-line no-console
   285                          console.log(`Iteration ${i}`);
   286                          throw e;
   287                      }
   288                      common.moveTime(web3, 1);
   289                  }
   290  
   291                  expect(await cp.canVote(nonmnacc1.address)).false;
   292              });
   293          });
   294      });
   295  
   296      //---
   297      describe('StorageCheckpointRegistryV1', async () => {
   298          it ('should refuse add() from outside', async () => {
   299              try {
   300                  await s.storage.add(s.fake.address);
   301                  assert.fail('It must fail');
   302              } catch (e) {
   303                  assert.match(e.message, /Not owner/);
   304              }
   305          });
   306  
   307          it ('should listCheckpoints() from outside', async () => {
   308              await s.storage.listCheckpoints();
   309          });
   310      });
   311  
   312      //---
   313      describe('common post', () => common.govPostTests(s) );
   314  });