github.com/codingfuture/orig-energi3@v0.8.4/energi/contracts/test/BlacklistRegistryV1.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 BlacklistRegistryV1 = artifacts.require('BlacklistRegistryV1'); 24 const IBlacklistRegistry = artifacts.require('IBlacklistRegistry'); 25 const IProposal = artifacts.require('IProposal'); 26 const Gen2Migration = artifacts.require('Gen2Migration'); 27 const MasternodeRegistryV1 = artifacts.require('MasternodeRegistryV1'); 28 const MasternodeTokenV1 = artifacts.require('MasternodeTokenV1'); 29 const TreasuryV1 = artifacts.require('TreasuryV1'); 30 const StorageBlacklistRegistryV1 = artifacts.require('StorageBlacklistRegistryV1'); 31 const MockBlacklistProposalV1 = artifacts.require('MockBlacklistProposalV1'); 32 33 const common = require('./common'); 34 35 contract("BlacklistRegistryV1", 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.treasury_orig = await TreasuryV1.deployed(); 52 s.treasury = await TreasuryV1.at(await s.treasury_orig.proxy()); 53 54 s.orig = await BlacklistRegistryV1.deployed(); 55 s.proxy = await MockProxy.at(await s.orig.proxy()); 56 s.mnregistry_proxy = await MockProxy.at(await s.orig.mnregistry_proxy()); 57 s.fake = await MockContract.new(s.proxy.address); 58 s.proxy_abi = await BlacklistRegistryV1.at(s.proxy.address); 59 s.token_abi = await IBlacklistRegistry.at(s.proxy.address); 60 await s.proxy.setImpl(s.orig.address); 61 s.storage = await StorageBlacklistRegistryV1.at(await s.proxy_abi.v1storage()); 62 s.compensation_fund = await s.orig.compensation_fund(); 63 Object.freeze(s); 64 }); 65 66 after(async () => { 67 const impl = await BlacklistRegistryV1.new( 68 s.proxy.address, s.mnregistry_proxy.address, 69 Gen2Migration.address, s.compensation_fund, 70 accounts[9], 71 { gas: "10000000" }); 72 await s.proxy.setImpl(impl.address); 73 }); 74 75 describe('common pre', () => common.govPreTests(s) ); 76 77 //--- 78 describe('Primary', () => { 79 const { fromAscii, toBN, toWei } = web3.utils; 80 const enforce_fee = toBN(toWei('1000', 'ether')); 81 const revoke_fee = toBN(toWei('100', 'ether')); 82 const drain_fee = toBN(toWei('100', 'ether')); 83 84 const collateral1 = toBN(toWei('50000', 'ether')); 85 const owner1 = accounts[0]; 86 const masternode1 = accounts[9]; 87 const ip1 = toBN(0x12345678); 88 const enode_common = '123456789012345678901234567890' 89 const enode1 = [fromAscii(enode_common + '11'), fromAscii(enode_common + '11')]; 90 91 const target1 = accounts[1]; 92 const target2 = accounts[2]; 93 94 before(async () => { 95 await s.mntoken.depositCollateral({ 96 from: owner1, 97 value: collateral1, 98 }); 99 await s.registry.announce(masternode1, ip1, enode1, {from: owner1}); 100 }); 101 102 after(async () => { 103 await s.mntoken.withdrawCollateral(collateral1, { 104 from: owner1, 105 }); 106 }); 107 108 it('should not be enforcelisted by default', async () => { 109 expect(await s.token_abi.isBlacklisted(target1)).false; 110 }); 111 112 it('should return EBI signer', async () => { 113 expect(await s.token_abi.EBI_signer()).equal(accounts[3]); 114 }); 115 116 it('should refuse propose() without proper fee', async () => { 117 try { 118 await s.token_abi.propose(target1, { value: enforce_fee.sub(toBN(1)) }); 119 assert.fail('It should fail'); 120 } catch (e) { 121 assert.match(e.message, /Invalid fee/); 122 } 123 124 try { 125 await s.token_abi.propose(target1, { value: enforce_fee.add(toBN(1)) }); 126 assert.fail('It should fail'); 127 } catch (e) { 128 assert.match(e.message, /Invalid fee/); 129 } 130 131 try { 132 await s.token_abi.propose(target1, { 133 value: enforce_fee, from: await s.token_abi.EBI_signer()}); 134 assert.fail('It should fail'); 135 } catch (e) { 136 assert.match(e.message, /Invalid fee/); 137 } 138 }); 139 140 it('should refuse proposeRevoke() without proper fee', async () => { 141 try { 142 await s.token_abi.propose(target1, { value: revoke_fee.sub(toBN(1)) }); 143 assert.fail('It should fail'); 144 } catch (e) { 145 assert.match(e.message, /Invalid fee/); 146 } 147 148 try { 149 await s.token_abi.propose(target1, { value: revoke_fee.add(toBN(1)) }); 150 assert.fail('It should fail'); 151 } catch (e) { 152 assert.match(e.message, /Invalid fee/); 153 } 154 155 try { 156 await s.token_abi.propose(target1, { 157 value: revoke_fee, from: await s.token_abi.EBI_signer()}); 158 assert.fail('It should fail'); 159 } catch (e) { 160 assert.match(e.message, /Invalid fee/); 161 } 162 }); 163 164 165 it('should refuse proposeDrain() without proper fee', async () => { 166 try { 167 await s.token_abi.proposeDrain(target1, { value: drain_fee.sub(toBN(1)) }); 168 assert.fail('It should fail'); 169 } catch (e) { 170 assert.match(e.message, /Invalid fee/); 171 } 172 173 try { 174 await s.token_abi.proposeDrain(target1, { value: drain_fee.add(toBN(1)) }); 175 assert.fail('It should fail'); 176 } catch (e) { 177 assert.match(e.message, /Invalid fee/); 178 } 179 180 try { 181 await s.token_abi.proposeDrain(target1, { 182 value: drain_fee, from: await s.token_abi.EBI_signer()}); 183 assert.fail('It should fail'); 184 } catch (e) { 185 assert.match(e.message, /Invalid fee/); 186 } 187 }); 188 189 it('should refuse proposeRevoke() on no enforce voting', async () => { 190 try { 191 await s.token_abi.proposeRevoke(target1, { value: revoke_fee }); 192 assert.fail('It should fail'); 193 } catch (e) { 194 assert.match(e.message, /No need \(1\)/); 195 } 196 }); 197 198 it('should enumerate*() empty', async () => { 199 expect(await s.token_abi.enumerateAll()).length(0); 200 expect(await s.token_abi.enumerateBlocked()).length(0); 201 }); 202 203 it('should propose()', async () => { 204 await s.token_abi.propose(target1, { value: enforce_fee }); 205 206 const evt = await s.orig.getPastEvents('BlacklistProposal', common.evt_last_block); 207 expect(evt).lengthOf(1); 208 common.stringifyBN(web3, evt[0].args); 209 expect(evt[0].args).deep.include({ 210 '0': target1, 211 '__length__': 2, 212 'target': target1, 213 }); 214 expect(evt[0].args).include.keys('proposal'); 215 216 expect(await s.token_abi.isBlacklisted(target1)).false; 217 }); 218 219 it('should enumerate*() one', async () => { 220 const all = await s.token_abi.enumerateAll(); 221 const blocked = await s.token_abi.enumerateBlocked(); 222 223 expect(all).eql([target1]); 224 expect(blocked).eql(['0x0000000000000000000000000000000000000000']); 225 }); 226 227 it('should refuse propose() on active enforce voting', async () => { 228 try { 229 await s.token_abi.propose(target1, { value: enforce_fee }); 230 assert.fail('It should fail'); 231 } catch (e) { 232 assert.match(e.message, /Already active \(2\)/); 233 } 234 }); 235 236 it('should refuse proposeRevoke() on active enforce voting', async () => { 237 try { 238 await s.token_abi.proposeRevoke(target1, { value: revoke_fee }); 239 assert.fail('It should fail'); 240 } catch (e) { 241 assert.match(e.message, /Not applicable/); 242 } 243 }); 244 245 it('should refuse proposeRevoke() on rejected enforcement', async () => { 246 const old_proposal = await IProposal.at((await s.token_abi.proposals(target1))['0']); 247 await old_proposal.voteReject({from: owner1}); 248 249 try { 250 await s.token_abi.proposeRevoke(target1, { value: revoke_fee }); 251 assert.fail('It should fail'); 252 } catch (e) { 253 assert.match(e.message, /No need \(2\)/); 254 } 255 }); 256 257 it('should propose() and collect rejected', async () => { 258 await s.token_abi.propose(target1, { value: enforce_fee }); 259 expect(await s.treasury_orig.getPastEvents('Contribution', common.evt_last_block)).lengthOf(1); 260 expect(await s.token_abi.isBlacklisted(target1)).false; 261 expect(await s.token_abi.isBlacklisted(target2)).false; 262 }); 263 264 it('should refuse collect() on lack of enforcement', async () => { 265 try { 266 await s.token_abi.collect(target2); 267 assert.fail('It should fail'); 268 } catch (e) { 269 assert.match(e.message, /Nothing to collect/); 270 } 271 }); 272 273 it('should refuse collect() on enforce voting', async () => { 274 try { 275 await s.token_abi.collect(target1); 276 assert.fail('It should fail'); 277 } catch (e) { 278 assert.match(e.message, /Enforce voting in progress/); 279 } 280 }); 281 282 it('should refuse propose() on enabled', async () => { 283 const old_proposal = await IProposal.at((await s.token_abi.proposals(target1))['0']); 284 await old_proposal.voteAccept({from: owner1}); 285 expect(await s.token_abi.isBlacklisted(target1)).true; 286 expect(await s.token_abi.isBlacklisted(target2)).false; 287 288 try { 289 await s.token_abi.propose(target1, { value: enforce_fee }); 290 assert.fail('It should fail'); 291 } catch (e) { 292 assert.match(e.message, /Already active \(2\)/); 293 } 294 }); 295 296 it('should refuse collect() on enforced', async () => { 297 try { 298 await s.token_abi.collect(target1); 299 assert.fail('It should fail'); 300 } catch (e) { 301 assert.match(e.message, /No proposals ready to collect/); 302 } 303 }); 304 305 it('should proposeRevoke()', async () => { 306 await s.token_abi.proposeRevoke(target1, { value: revoke_fee }); 307 expect(await s.token_abi.isBlacklisted(target1)).true; 308 expect(await s.token_abi.isBlacklisted(target2)).false; 309 }); 310 311 it('should refuse proposeRevoke() on active revoke voting', async () => { 312 try { 313 await s.token_abi.proposeRevoke(target1, { value: revoke_fee }); 314 assert.fail('It should fail'); 315 } catch (e) { 316 assert.match(e.message, /Already active/); 317 } 318 }); 319 320 it('should proposeRevoke() and collect rejected', async () => { 321 const old_proposal = await IProposal.at((await s.token_abi.proposals(target1))['1']); 322 await old_proposal.voteReject({from: owner1}); 323 await s.token_abi.proposeRevoke(target1, { value: revoke_fee }); 324 expect(await s.treasury_orig.getPastEvents('Contribution', common.evt_last_block)).lengthOf(1); 325 expect(await s.token_abi.isBlacklisted(target1)).true; 326 expect(await s.token_abi.isBlacklisted(target2)).false; 327 }); 328 329 it('should refuse collect() on revoke voting', async () => { 330 try { 331 await s.token_abi.collect(target1); 332 assert.fail('It should fail'); 333 } catch (e) { 334 assert.match(e.message, /Revoke voting in progress/); 335 } 336 }); 337 338 it('should collect() after rejected revocation', async () => { 339 const old_proposal = await IProposal.at((await s.token_abi.proposals(target1))['1']); 340 await old_proposal.voteReject({from: owner1}); 341 await s.token_abi.collect(target1); 342 expect(await s.treasury_orig.getPastEvents('Contribution', common.evt_last_block)).lengthOf(1); 343 expect(await s.token_abi.isBlacklisted(target1)).true; 344 expect(await s.token_abi.isBlacklisted(target2)).false; 345 }); 346 347 it('should collect() after approved revocation', async () => { 348 await s.token_abi.proposeRevoke(target1, { value: revoke_fee }); 349 const old_proposal = await IProposal.at((await s.token_abi.proposals(target1))['1']); 350 await old_proposal.voteAccept({from: owner1}); 351 await s.token_abi.collect(target1); 352 expect(await s.treasury_orig.getPastEvents('Contribution', common.evt_last_block)).lengthOf(0); 353 expect(await s.token_abi.isBlacklisted(target1)).false; 354 expect(await s.token_abi.isBlacklisted(target2)).false; 355 356 }); 357 358 it('should isObey() on accept', async () => { 359 const proposal = await MockBlacklistProposalV1.new(s.mnregistry_proxy.address, accounts[0]); 360 expect(await proposal.isObeyed()).false; 361 await proposal.voteAccept(); 362 expect(await proposal.isObeyed()).true; 363 }); 364 365 it('should isObeyed() on 2:1 weight over 10x votes', async () => { 366 const proposal = await MockBlacklistProposalV1.new(s.mnregistry_proxy.address, accounts[0]); 367 expect(await proposal.isObeyed()).false; 368 369 const b = toBN(toWei('10000', 'ether')); 370 371 // Must obey 10x 372 await proposal.setWeights(toBN(20), toBN(9), toBN(10), toBN(30)); 373 expect(await proposal.isObeyed()).false; 374 375 // 2>1 376 await proposal.setWeights(toBN(20).mul(b), toBN(9).mul(b), toBN(1).mul(b), toBN(50).mul(b)); 377 expect(await proposal.isObeyed()).true; 378 expect(await proposal.isAccepted()).false; 379 380 // 2:1 381 await proposal.setWeights(toBN(20).mul(b), toBN(10).mul(b), toBN(1).mul(b), toBN(50).mul(b)); 382 expect(await proposal.isObeyed()).false; 383 expect(await proposal.isAccepted()).false; 384 385 // < 10x 386 await proposal.setWeights(toBN(7).mul(b), toBN(3).mul(b), toBN(1).mul(b), toBN(50).mul(b)); 387 expect(await proposal.isObeyed()).false; 388 expect(await proposal.isAccepted()).false; 389 }); 390 391 it('should proposeDrain() collect rejected', async () => { 392 await s.token_abi.propose(target1, { value: enforce_fee }); 393 const enforce = await IProposal.at((await s.token_abi.proposals(target1))['0']); 394 await enforce.voteAccept(); 395 await s.token_abi.proposeDrain(target1, { value: drain_fee }); 396 const drain = await IProposal.at((await s.token_abi.proposals(target1))['2']); 397 398 expect(await s.token_abi.isDrainable(target1)).false; 399 await drain.voteReject(); 400 expect(await s.token_abi.isDrainable(target1)).false; 401 402 s.token_abi.collect(target1); 403 }); 404 405 it('should proposeDrain()', async () => { 406 await s.token_abi.proposeDrain(target1, { value: drain_fee }); 407 const drain = await IProposal.at((await s.token_abi.proposals(target1))['2']); 408 409 expect(await s.token_abi.isDrainable(target1)).false; 410 await drain.voteAccept(); 411 expect(await s.token_abi.isDrainable(target1)).true; 412 }); 413 414 it('should refuse onDrain()', async () => { 415 try { 416 await s.token_abi.onDrain(target1); 417 assert.fail('It should fail'); 418 } catch (e) { 419 assert.match(e.message, /Not consensus/); 420 } 421 }); 422 423 it('should accept drainMigration()', async () => { 424 try { 425 await s.token_abi.drainMigration(0, target1); 426 assert.fail('It should fail'); 427 } catch (e) { 428 assert.match(e.message, /Invalid ID/); 429 } 430 }); 431 432 it('should refuse drainMigration()', async () => { 433 try { 434 await s.token_abi.drainMigration(0, target2); 435 assert.fail('It should fail'); 436 } catch (e) { 437 assert.match(e.message, /Not drainable/); 438 } 439 }); 440 }); 441 442 443 //--- 444 describe('StorageBlacklistRegistryV1', async () => { 445 it ('should refuse setRevoke() from outside', async () => { 446 try { 447 await s.storage.setRevoke(s.fake.address, s.fake.address); 448 assert.fail('It must fail'); 449 } catch (e) { 450 assert.match(e.message, /Not owner/); 451 } 452 }); 453 454 it ('should refuse setEnforce() from outside', async () => { 455 try { 456 await s.storage.setEnforce(s.fake.address, s.fake.address); 457 assert.fail('It must fail'); 458 } catch (e) { 459 assert.match(e.message, /Not owner/); 460 } 461 }); 462 463 it ('should refuse remove() from outside', async () => { 464 try { 465 await s.storage.remove(s.fake.address); 466 assert.fail('It must fail'); 467 } catch (e) { 468 assert.match(e.message, /Not owner/); 469 } 470 }); 471 }); 472 473 //--- 474 describe('common post', () => common.govPostTests(s) ); 475 }); 476