mirror of
https://github.com/status-im/topic-democracy.git
synced 2025-02-24 16:18:46 +00:00
implement cached delegation reader into proposal
This commit is contained in:
parent
5af5d523b5
commit
3776e17802
64
contracts/democracy/delegation/DelegationReader.sol
Normal file
64
contracts/democracy/delegation/DelegationReader.sol
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
pragma solidity >=0.5.0 <0.6.0;
|
||||||
|
|
||||||
|
import "./Delegation.sol";
|
||||||
|
|
||||||
|
contract DelegationReader {
|
||||||
|
Delegation delegation;
|
||||||
|
mapping(address => address) delegationOf;
|
||||||
|
|
||||||
|
function validDelegate(
|
||||||
|
address _who
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns(bool);
|
||||||
|
|
||||||
|
|
||||||
|
function precomputeDelegateOf(
|
||||||
|
address _who,
|
||||||
|
uint _block,
|
||||||
|
bool _revalidate
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
delegationOf[_who] = _revalidate ? delegateOfAt(_who, _block) : cachedDelegateOfAt(_who, _block);
|
||||||
|
}
|
||||||
|
|
||||||
|
function delegateOfAt(
|
||||||
|
address _who,
|
||||||
|
uint _block
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns(address delegate)
|
||||||
|
{
|
||||||
|
delegate = _who;
|
||||||
|
do {
|
||||||
|
delegate = delegation.delegatedToAt(delegate, _block);
|
||||||
|
} while (!validDelegate(delegate));
|
||||||
|
}
|
||||||
|
|
||||||
|
function cachedDelegateOfAt(
|
||||||
|
address _who,
|
||||||
|
uint _block
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns(address delegate)
|
||||||
|
{
|
||||||
|
delegate = _who;
|
||||||
|
do {
|
||||||
|
address delegationOfd = delegationOf[delegate];
|
||||||
|
if(delegationOfd != address(0)){
|
||||||
|
return delegationOfd;
|
||||||
|
}else {
|
||||||
|
delegate = delegation.delegatedToAt(delegate, _block);
|
||||||
|
}
|
||||||
|
} while (!validDelegate(delegate));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -32,7 +32,8 @@ interface Proposal {
|
|||||||
bytes32[] calldata _proof,
|
bytes32[] calldata _proof,
|
||||||
bytes calldata _signature
|
bytes calldata _signature
|
||||||
) external;
|
) external;
|
||||||
function tabulateDelegated(address _voter) external;
|
|
||||||
|
function tabulateDelegated(address _source, bool _cached) external;
|
||||||
function precomputeDelegation(address _start, bool _clean) external;
|
function precomputeDelegation(address _start, bool _clean) external;
|
||||||
function finalize() external;
|
function finalize() external;
|
||||||
function clear() external;
|
function clear() external;
|
||||||
|
@ -4,6 +4,7 @@ import "../../common/Controlled.sol";
|
|||||||
import "../../deploy/InstanceAbstract.sol";
|
import "../../deploy/InstanceAbstract.sol";
|
||||||
import "../../token/MiniMeToken.sol";
|
import "../../token/MiniMeToken.sol";
|
||||||
import "../delegation/Delegation.sol";
|
import "../delegation/Delegation.sol";
|
||||||
|
import "../delegation/DelegationReader.sol";
|
||||||
import "./Proposal.sol";
|
import "./Proposal.sol";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,10 +12,9 @@ import "./Proposal.sol";
|
|||||||
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
|
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
|
||||||
* Store votes and tabulate results for Democracy.
|
* Store votes and tabulate results for Democracy.
|
||||||
*/
|
*/
|
||||||
contract ProposalAbstract is InstanceAbstract, Proposal, Controlled {
|
contract ProposalAbstract is InstanceAbstract, DelegationReader, Proposal, Controlled {
|
||||||
|
|
||||||
MiniMeToken public token;
|
MiniMeToken public token;
|
||||||
Delegation public delegation;
|
|
||||||
uint256 public tabulationBlockDelay;
|
uint256 public tabulationBlockDelay;
|
||||||
|
|
||||||
bytes32 public dataHash;
|
bytes32 public dataHash;
|
||||||
@ -27,7 +27,6 @@ contract ProposalAbstract is InstanceAbstract, Proposal, Controlled {
|
|||||||
|
|
||||||
//tabulation process
|
//tabulation process
|
||||||
uint256 public lastTabulationBlock;
|
uint256 public lastTabulationBlock;
|
||||||
mapping(address => address) public delegationOf;
|
|
||||||
mapping(address => address) public tabulated;
|
mapping(address => address) public tabulated;
|
||||||
mapping(uint8 => uint256) public results;
|
mapping(uint8 => uint256) public results;
|
||||||
|
|
||||||
@ -50,4 +49,14 @@ contract ProposalAbstract is InstanceAbstract, Proposal, Controlled {
|
|||||||
require(lastTabulationBlock + tabulationBlockDelay < block.number, "Tabulation not ended");
|
require(lastTabulationBlock + tabulationBlockDelay < block.number, "Tabulation not ended");
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validDelegate(
|
||||||
|
address _who
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns(bool)
|
||||||
|
{
|
||||||
|
return voteMap[_who] != Vote.Null;
|
||||||
|
}
|
||||||
}
|
}
|
@ -95,30 +95,31 @@ contract ProposalBase is ProposalAbstract, MessageSigned {
|
|||||||
* @dev might run out of gas, to prevent this, precompute the delegation
|
* @dev might run out of gas, to prevent this, precompute the delegation
|
||||||
* Should be called every time a nearer delegate tabulate their vote
|
* Should be called every time a nearer delegate tabulate their vote
|
||||||
* @param _source holder which not voted but have a delegate that voted
|
* @param _source holder which not voted but have a delegate that voted
|
||||||
|
* @param _cached true if should use lookup values from precomputed
|
||||||
*/
|
*/
|
||||||
function tabulateDelegated(address _source)
|
function tabulateDelegated(address _source, bool _cached)
|
||||||
external
|
external
|
||||||
tabulationPeriod
|
tabulationPeriod
|
||||||
{
|
{
|
||||||
(address _claimer, Vote _vote) = findNearestDelegatable(_source); // try finding first delegate from chain which voted
|
address claimer = _cached ? cachedDelegateOfAt(_source, voteBlockEnd): delegateOfAt(_source, voteBlockEnd);
|
||||||
setTabulation(_source, _claimer, _vote);
|
setTabulation(_source, claimer, voteMap[claimer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice precomputes a delegate vote based on current votes tabulated
|
* @notice precomputes a delegate vote based on current votes tabulated
|
||||||
* @dev to precompute a very long delegate chain, go from the end to start with _clean false.
|
* @dev to precompute a very long delegate chain, go from the end to start with _clean false.
|
||||||
* @param _start who will have delegate precomputed
|
* @param _start who will have delegate precomputed
|
||||||
* @param _clean if true dont use precomputed results
|
* @param _revalidate if true dont use precomputed results
|
||||||
* TODO: fix long delegate chain recompute in case new votes
|
* TODO: fix long delegate chain recompute in case new votes
|
||||||
*/
|
*/
|
||||||
function precomputeDelegation(
|
function precomputeDelegation(
|
||||||
address _start,
|
address _start,
|
||||||
bool _clean
|
bool _revalidate
|
||||||
)
|
)
|
||||||
external
|
external
|
||||||
tabulationPeriod
|
tabulationPeriod
|
||||||
{
|
{
|
||||||
cacheDelegation(_start,_clean);
|
precomputeDelegateOf(_start, voteBlockEnd, _revalidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,6 +188,14 @@ contract ProposalBase is ProposalAbstract, MessageSigned {
|
|||||||
return getSignHash(voteHash(_vote));
|
return getSignHash(voteHash(_vote));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function delegateOf(address _who) external view returns(address) {
|
||||||
|
return delegateOfAt(_who, voteBlockEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cachedDelegateOf(address _who) external view returns(address) {
|
||||||
|
return cachedDelegateOfAt(_who, voteBlockEnd);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice get result
|
* @notice get result
|
||||||
*/
|
*/
|
||||||
@ -245,34 +254,25 @@ contract ProposalBase is ProposalAbstract, MessageSigned {
|
|||||||
require(vote == Vote.Null, "Not delegatable");
|
require(vote == Vote.Null, "Not delegatable");
|
||||||
claimer = _source; // try finding first delegate from chain which voted
|
claimer = _source; // try finding first delegate from chain which voted
|
||||||
while(vote == Vote.Null) {
|
while(vote == Vote.Null) {
|
||||||
address claimerDelegate = delegationOf[claimer];
|
address claimerDelegate = delegation.delegatedToAt(claimer, voteBlockEnd);
|
||||||
if(claimerDelegate == address(0)){
|
|
||||||
claimerDelegate = delegation.delegatedToAt(claimer, voteBlockEnd);
|
|
||||||
}
|
|
||||||
require(claimer != claimerDelegate, "No delegate vote found");
|
|
||||||
claimer = claimerDelegate;
|
claimer = claimerDelegate;
|
||||||
vote = voteMap[claimer]; //loads delegate vote.
|
vote = voteMap[claimer]; //loads delegate vote.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cacheDelegation(address _source, bool _clean) private returns (address delegate) {
|
function cachedFindNearestDelegatable(address _source) internal view returns (address claimer, Vote vote){
|
||||||
delegate = _source;
|
vote = voteMap[_source];
|
||||||
if(voteMap[_source] == Vote.Null) {
|
require(vote == Vote.Null, "Not delegatable");
|
||||||
if(!_clean) {
|
claimer = _source; // try finding first delegate from chain which voted
|
||||||
delegate = delegationOf[delegate];
|
while(vote == Vote.Null) {
|
||||||
}
|
address claimerDelegate = delegationOf[claimer];
|
||||||
if(delegate == address(0)){
|
if(claimerDelegate == address(0)){
|
||||||
delegate = delegation.delegatedToAt(_source, voteBlockEnd); //get delegate chain tail
|
claimerDelegate = delegation.delegatedToAt(claimer, voteBlockEnd);
|
||||||
}
|
}
|
||||||
|
claimer = claimerDelegate;
|
||||||
|
vote = voteMap[claimer]; //loads delegate vote.
|
||||||
}
|
}
|
||||||
|
|
||||||
require(delegate != address(0), "No delegate vote found");
|
|
||||||
if(voteMap[delegate] == Vote.Null) {
|
|
||||||
delegate = cacheDelegation(delegate, _clean);
|
|
||||||
}
|
|
||||||
delegationOf[_source] = delegate;
|
|
||||||
return delegate;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -62,7 +62,7 @@ contract ProposalInit is ProposalAbstract {
|
|||||||
function voteDirect(Vote) external{}
|
function voteDirect(Vote) external{}
|
||||||
function tabulateDirect(address ) external{}
|
function tabulateDirect(address ) external{}
|
||||||
function tabulateSigned(Vote, uint256, bytes32[] calldata, bytes calldata) external{}
|
function tabulateSigned(Vote, uint256, bytes32[] calldata, bytes calldata) external{}
|
||||||
function tabulateDelegated(address) external{}
|
function tabulateDelegated(address,bool) external{}
|
||||||
function precomputeDelegation(address, bool) external{}
|
function precomputeDelegation(address, bool) external{}
|
||||||
function finalize() external{}
|
function finalize() external{}
|
||||||
function clear() external{}
|
function clear() external{}
|
||||||
|
106
test/proposal.js
106
test/proposal.js
@ -37,6 +37,17 @@ config({
|
|||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function delegationOf(contract, influenceSrc) {
|
||||||
|
let delegation = [];
|
||||||
|
var curDelegate = influenceSrc;
|
||||||
|
do {
|
||||||
|
delegation.push(curDelegate)
|
||||||
|
curDelegate = await contract.methods.delegatedTo(curDelegate).call();
|
||||||
|
}while(!delegation.includes(curDelegate));
|
||||||
|
return delegation;
|
||||||
|
}
|
||||||
|
|
||||||
function mintTokens(accounts, amount) {
|
function mintTokens(accounts, amount) {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
accounts.map((account) => {
|
accounts.map((account) => {
|
||||||
@ -68,7 +79,15 @@ async function tabulateDirect(proposal, account) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function tabulateDelegated(proposal, account) {
|
async function tabulateDelegated(proposal, account) {
|
||||||
return addGas(proposal.methods.tabulateDelegated(account), web3.eth.defaultAccount);
|
let nc = proposal.methods.tabulateDelegated(account, false);
|
||||||
|
let yc = proposal.methods.tabulateDelegated(account, true);
|
||||||
|
let ng = await nc.estimateGas();
|
||||||
|
let yg = await yc.estimateGas();
|
||||||
|
var call = nc;
|
||||||
|
if(yg < ng && await proposal.methods.delegateOf(account).call() == await proposal.methods.cachedDelegateOf(account).call()){
|
||||||
|
call = yc;
|
||||||
|
}
|
||||||
|
return addGas(call, web3.eth.defaultAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function tabulateSigned(proposal, sig) {
|
async function tabulateSigned(proposal, sig) {
|
||||||
@ -103,7 +122,7 @@ contract("Proposal", function() {
|
|||||||
mintTokens(res, initialBalance).then((mintReceipts) => {
|
mintTokens(res, initialBalance).then((mintReceipts) => {
|
||||||
newDelegation(utils.zeroAddress, defaultDelegate).then((createdRoot) => {
|
newDelegation(utils.zeroAddress, defaultDelegate).then((createdRoot) => {
|
||||||
RootDelegation = createdRoot;
|
RootDelegation = createdRoot;
|
||||||
newDelegation(RootDelegation._address, utils.zeroAddress).then((createdChild) => {
|
newDelegation(RootDelegation._address, defaultDelegate).then((createdChild) => {
|
||||||
ChildDelegation = createdChild;
|
ChildDelegation = createdChild;
|
||||||
Promise.all([
|
Promise.all([
|
||||||
// root: 0 -> 1 -> 2 -> 3 (-> 5)
|
// root: 0 -> 1 -> 2 -> 3 (-> 5)
|
||||||
@ -119,7 +138,7 @@ contract("Proposal", function() {
|
|||||||
RootDelegation.methods.delegate(accounts[9]).send({from: accounts[8]}),
|
RootDelegation.methods.delegate(accounts[9]).send({from: accounts[8]}),
|
||||||
RootDelegation.methods.delegate(accounts[6]).send({from: accounts[9]}),
|
RootDelegation.methods.delegate(accounts[6]).send({from: accounts[9]}),
|
||||||
// child: 5 -> 6
|
// child: 5 -> 6
|
||||||
ChildDelegation.methods.delegate(accounts[7]).send({from: accounts[5]})
|
ChildDelegation.methods.delegate(accounts[6]).send({from: accounts[5]})
|
||||||
]).then((delegateReceipts) => {
|
]).then((delegateReceipts) => {
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
@ -227,7 +246,7 @@ contract("Proposal", function() {
|
|||||||
|
|
||||||
it("reject tabulateDelegated when voting not ended", async function () {
|
it("reject tabulateDelegated when voting not ended", async function () {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[0])),
|
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[0], false)),
|
||||||
"Voting not ended")
|
"Voting not ended")
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -257,8 +276,8 @@ contract("Proposal", function() {
|
|||||||
|
|
||||||
it("reject tabulates when no delegate voted", async function () {;
|
it("reject tabulates when no delegate voted", async function () {;
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[4])),
|
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[4], false)),
|
||||||
"No delegate vote found")
|
"revert")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not have a lastTabulationBlock", async function () {
|
it("should not have a lastTabulationBlock", async function () {
|
||||||
@ -308,11 +327,11 @@ contract("Proposal", function() {
|
|||||||
|
|
||||||
it("should not tabulate for delegate if voted ", async function () {
|
it("should not tabulate for delegate if voted ", async function () {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[2])),
|
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[2], false)),
|
||||||
"Not delegatable")
|
"Voter already tabulated")
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[5])),
|
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[5], false)),
|
||||||
"Not delegatable")
|
"Voter already tabulated")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("tabulates approve influence from direct delegate", async function () {
|
it("tabulates approve influence from direct delegate", async function () {
|
||||||
@ -337,7 +356,7 @@ contract("Proposal", function() {
|
|||||||
|
|
||||||
it("should not tabulate influence from circular delegation chain when none voted", async function () {
|
it("should not tabulate influence from circular delegation chain when none voted", async function () {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[7])),
|
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[7], false)),
|
||||||
"revert")
|
"revert")
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -458,7 +477,7 @@ contract("Proposal", function() {
|
|||||||
|
|
||||||
it("reject tabulateDelegated after finalization", async function () {
|
it("reject tabulateDelegated after finalization", async function () {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[0])),
|
await utils.getEVMException(testProposal.methods.tabulateDelegated(accounts[0], false)),
|
||||||
"Tabulation ended"
|
"Tabulation ended"
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
@ -577,7 +596,7 @@ contract("Proposal", function() {
|
|||||||
it("clear after finalization", async function () {
|
it("clear after finalization", async function () {
|
||||||
await testProposal.methods.clear().send({from: web3.eth.defaultAccount});
|
await testProposal.methods.clear().send({from: web3.eth.defaultAccount});
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe("test simple quorum reject", function() {
|
describe("test simple quorum reject", function() {
|
||||||
var sigs = [];
|
var sigs = [];
|
||||||
@ -674,7 +693,7 @@ contract("Proposal", function() {
|
|||||||
it("clear after finalization", async function () {
|
it("clear after finalization", async function () {
|
||||||
await testProposal.methods.clear().send({from: web3.eth.defaultAccount});
|
await testProposal.methods.clear().send({from: web3.eth.defaultAccount});
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe("test simple quorum approve", function() {
|
describe("test simple quorum approve", function() {
|
||||||
var sigs = [];
|
var sigs = [];
|
||||||
@ -768,6 +787,65 @@ contract("Proposal", function() {
|
|||||||
assert.equal(receipt.events.FinalResult.returnValues.result, VOTE_APPROVE)
|
assert.equal(receipt.events.FinalResult.returnValues.result, VOTE_APPROVE)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("clear after finalization", async function () {
|
||||||
|
await testProposal.methods.clear().send({from: web3.eth.defaultAccount});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("test delegate precompute", function() {
|
||||||
|
var sigs = [];
|
||||||
|
var testProposal;
|
||||||
|
var blockStart;
|
||||||
|
var voteBlockEnd;
|
||||||
|
it("create proposal by factory", async function () {
|
||||||
|
blockStart = await web3.eth.getBlockNumber();
|
||||||
|
|
||||||
|
receipt = await ProposalFactory.methods.createProposal(
|
||||||
|
MiniMeToken._address,
|
||||||
|
ChildDelegation._address,
|
||||||
|
"0xDA0",
|
||||||
|
tabulationBlockDelay,
|
||||||
|
blockStart,
|
||||||
|
blockEndDelay,
|
||||||
|
QUORUM_SIMPLE
|
||||||
|
).send()
|
||||||
|
testProposal = new web3.eth.Contract(ProposalBase._jsonInterface, receipt.events.InstanceCreated.returnValues.instance);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("include direct vote", async function () {
|
||||||
|
|
||||||
|
let receipt = await testProposal.methods.voteDirect(VOTE_APPROVE).send({from: accounts[8]});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("increases block number to vote block end", async function () {
|
||||||
|
voteBlockEnd = await testProposal.methods.voteBlockEnd().call();
|
||||||
|
await utils.setBlockNumber(+voteBlockEnd+1);
|
||||||
|
assert(await web3.eth.getBlockNumber() > voteBlockEnd, "Wrong block number")
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should precompute delegate", async function () {
|
||||||
|
let gasBefore = await testProposal.methods.tabulateDelegated(accounts[0], true).estimateGas();
|
||||||
|
let call = testProposal.methods.precomputeDelegation(accounts[0],true);
|
||||||
|
await call.send({from: accounts[0], gas: await call.estimateGas()+ 10000 });
|
||||||
|
let gasAfter = await testProposal.methods.tabulateDelegated(accounts[0], true).estimateGas();
|
||||||
|
assert.equal(await testProposal.methods.cachedDelegateOf(accounts[0]).call(),await testProposal.methods.delegateOf(accounts[0]).call(), "Rendered wrong delegate");
|
||||||
|
assert(gasAfter < gasBefore, "Didn't reduced gas usage");
|
||||||
|
await tabulateDelegated(testProposal, accounts[0]);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("increses block to tabulation end", async function (){
|
||||||
|
await utils.increaseBlock(+tabulationBlockDelay+1);
|
||||||
|
let lastTabulationBlock = await testProposal.methods.lastTabulationBlock().call();
|
||||||
|
assert(await web3.eth.getBlockNumber() > +lastTabulationBlock+tabulationBlockDelay, "Wrong block number")
|
||||||
|
});
|
||||||
|
|
||||||
|
it("finalizes after tabulation end", async function (){
|
||||||
|
receipt = await testProposal.methods.finalize().send({from: web3.eth.defaultAccount});
|
||||||
|
assert.equal(receipt.events.FinalResult.returnValues.result, VOTE_APPROVE)
|
||||||
|
});
|
||||||
|
|
||||||
it("clear after finalization", async function () {
|
it("clear after finalization", async function () {
|
||||||
await testProposal.methods.clear().send({from: web3.eth.defaultAccount});
|
await testProposal.methods.clear().send({from: web3.eth.defaultAccount});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user