github.com/Night-mk/quorum@v21.1.0+incompatible/extension/extensionContracts/contract_extender.sol (about) 1 pragma solidity ^0.5.3; 2 3 contract ContractExtender { 4 5 //target details - what, who and when to extend 6 address public creator; 7 string public targetRecipientPTMKey; 8 address public contractToExtend; 9 10 //list of wallet addresses that can cast votes 11 address[] public walletAddressesToVote; 12 uint256 public totalNumberOfVoters; 13 mapping(address => bool) walletAddressesToVoteMap; 14 uint256 numberOfVotesSoFar; 15 mapping(address => bool) hasVotedMapping; 16 mapping(address => bool) public votes; 17 18 //contains the total outcome of voting 19 //true if ALL nodes vote true, false if ANY node votes false 20 bool public voteOutcome; 21 22 //the hash of the shared payload 23 string public sharedDataHash; 24 string[] uuids; 25 26 //if creator cancelled this extension 27 bool public isFinished; 28 29 // General housekeeping 30 event NewContractExtensionContractCreated(address toExtend, string recipientPTMKey, address recipientAddress); //to tell nodes a new extension is happening 31 event AllNodesHaveAccepted(bool outcome); //when all nodes have voted 32 event CanPerformStateShare(); //when all nodes have voted & the recipient has accepted 33 event ExtensionFinished(); //if the extension is cancelled or completed 34 event NewVote(bool vote, address voter); // when someone voted (either true or false) 35 event StateShared(address toExtend, string tesserahash, string uuid); //when the state is shared and can be replayed into the database 36 event UpdateMembers(address toExtend, string uuid); //to update the original transaction hash for the new party member 37 38 constructor(address contractAddress, address recipientAddress, string memory recipientPTMKey) public { 39 creator = msg.sender; 40 41 targetRecipientPTMKey = recipientPTMKey; 42 43 contractToExtend = contractAddress; 44 walletAddressesToVote.push(msg.sender); 45 walletAddressesToVote.push(recipientAddress); 46 47 sharedDataHash = ""; 48 49 voteOutcome = true; 50 numberOfVotesSoFar = 0; 51 52 for (uint256 i = 0; i < walletAddressesToVote.length; i++) { 53 walletAddressesToVoteMap[walletAddressesToVote[i]] = true; 54 } 55 totalNumberOfVoters = walletAddressesToVote.length; 56 emit NewContractExtensionContractCreated(contractAddress, recipientPTMKey, recipientAddress); 57 } 58 59 ///////////////////////////////////////////////////////////////////////////////////// 60 //modifiers 61 ///////////////////////////////////////////////////////////////////////////////////// 62 modifier notFinished() { 63 require(!isFinished, "extension has been marked as finished"); 64 _; 65 } 66 67 modifier onlyCreator() { 68 require(msg.sender == creator, "only leader may perform this action"); 69 _; 70 } 71 72 ///////////////////////////////////////////////////////////////////////////////////// 73 //main 74 ///////////////////////////////////////////////////////////////////////////////////// 75 function haveAllNodesVoted() public view returns (bool) { 76 return walletAddressesToVote.length == numberOfVotesSoFar; 77 } 78 79 // returns true if the sender address has already voted on the 80 // extension contracts 81 function checkIfVoted() public view returns (bool) { 82 return hasVotedMapping[msg.sender]; 83 } 84 85 // returns true if the contract extension is finished 86 function checkIfExtensionFinished() public view returns (bool) { 87 return isFinished; 88 } 89 90 // single node vote to either extend or not 91 // can't have voted before 92 function doVote(bool vote, string memory nextuuid) public notFinished() { 93 cast(vote); 94 if (vote) { 95 setUuid(nextuuid); 96 } 97 // check if voting has finished 98 checkVotes(); 99 emit NewVote(vote, msg.sender); 100 } 101 102 // this event is emitted to tell each node to use this tx as the original tx 103 // only if they voted for it 104 function updatePartyMembers() public { 105 for(uint256 i = 0; i < uuids.length; i++) { 106 emit UpdateMembers(contractToExtend, uuids[i]); 107 } 108 } 109 110 //state has been shared off chain via a private transaction, the hash the PTM generated is set here 111 function setSharedStateHash(string memory hash) public onlyCreator() notFinished() { 112 bytes memory hashAsBytes = bytes(sharedDataHash); 113 bytes memory incomingAsBytes = bytes(hash); 114 115 require(incomingAsBytes.length != 0, "new hash cannot be empty"); 116 require(hashAsBytes.length == 0, "state hash already set"); 117 sharedDataHash = hash; 118 119 for(uint256 i = 0; i < uuids.length; i++) { 120 emit StateShared(contractToExtend, sharedDataHash, uuids[i]); 121 } 122 123 finish(); 124 } 125 126 //close the contract to further modifications 127 function finish() public notFinished() onlyCreator() { 128 setFinished(); 129 } 130 131 //this sets a unique code that only the sending node has access to, that can be referred to later 132 function setUuid(string memory nextuuid) public notFinished() { 133 uuids.push(nextuuid); 134 } 135 136 // Internal methods 137 function setFinished() internal { 138 isFinished = true; 139 emit ExtensionFinished(); 140 } 141 142 // checks if all the conditions for voting have been met 143 // either all voted true and target accepted, or someone voted false 144 function checkVotes() internal { 145 if (!voteOutcome) { 146 emit AllNodesHaveAccepted(false); 147 setFinished(); 148 return; 149 } 150 151 if (haveAllNodesVoted()) { 152 emit AllNodesHaveAccepted(true); 153 emit CanPerformStateShare(); 154 } 155 } 156 157 function cast(bool vote) internal { 158 require(!isFinished, "extension process completed. cannot vote"); 159 require(walletAddressesToVoteMap[msg.sender], "not allowed to vote"); 160 require(!hasVotedMapping[msg.sender], "already voted"); 161 require(voteOutcome, "voting already declined"); 162 163 hasVotedMapping[msg.sender] = true; 164 votes[msg.sender] = vote; 165 numberOfVotesSoFar++; 166 voteOutcome = voteOutcome && vote; 167 } 168 }