github.com/ConsenSys/Quorum@v20.10.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  }