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