From ce678ac543058ef01f3de27988bf259dbbb1b2cf Mon Sep 17 00:00:00 2001 From: Yoshihito Aso Date: Tue, 7 Jul 2026 20:15:36 +0900 Subject: [PATCH 1/4] Add QBFT validator set contract package --- contracts/validatorcontract/README.md | 87 ++ .../contract/validator_set.go | 1367 +++++++++++++++++ .../contract/validator_set.sol | 294 ++++ contracts/validatorcontract/validator.go | 51 + contracts/validatorcontract/validator_test.go | 443 ++++++ 5 files changed, 2242 insertions(+) create mode 100644 contracts/validatorcontract/README.md create mode 100644 contracts/validatorcontract/contract/validator_set.go create mode 100644 contracts/validatorcontract/contract/validator_set.sol create mode 100644 contracts/validatorcontract/validator.go create mode 100644 contracts/validatorcontract/validator_test.go diff --git a/contracts/validatorcontract/README.md b/contracts/validatorcontract/README.md new file mode 100644 index 000000000..fbe14265f --- /dev/null +++ b/contracts/validatorcontract/README.md @@ -0,0 +1,87 @@ +# Validator Set Contract + +This package contains the reference validator set contract used with QBFT contract-based validator selection. + +## Files + +- `contract/validator_set.sol`: Solidity source for the validator set contract. +- `contract/validator_set.go`: generated Go binding. Do not edit by hand. +- `validator.go`: small Go wrapper around the generated binding. +- `validator_test.go`: simulated backend tests for the contract behavior. + +## Update Flow + +1. Edit `contract/validator_set.sol`. +2. Keep the Solidity pragma on a real compiler version supported by the local toolchain. The current source uses Solidity `^0.8.30`. +3. Preserve the QBFT compatibility method: + + ```solidity + function getValidators() external view returns (address[] memory) + ``` + + QBFT contract mode calls this method and expects it to return the active validator list. In this implementation, validators in maintenance are excluded from the returned list. + +4. Compile the contract to temporary Foundry artifacts: + + ```sh + forge build \ + --use 0.8.30 \ + --evm-version paris \ + --contracts contracts/validatorcontract/contract \ + --out /private/tmp/validatorcontract-out \ + --cache-path /private/tmp/validatorcontract-cache + ``` + + The `paris` EVM target keeps the generated bytecode compatible with the Go simulated backend used by the tests. + +5. Extract ABI and bytecode: + + ```sh + jq '.abi' /private/tmp/validatorcontract-out/validator_set.sol/ValidatorSet.json \ + > /private/tmp/ValidatorSet.abi + + jq -r '.bytecode.object' /private/tmp/validatorcontract-out/validator_set.sol/ValidatorSet.json \ + > /private/tmp/ValidatorSet.bin + ``` + +6. Regenerate the Go binding: + + ```sh + go run ./cmd/abigen \ + --abi /private/tmp/ValidatorSet.abi \ + --bin /private/tmp/ValidatorSet.bin \ + --pkg contract \ + --type ValidatorSet \ + --out contracts/validatorcontract/contract/validator_set.go + ``` + +7. Format generated and handwritten Go files: + + ```sh + gofmt -w \ + contracts/validatorcontract/validator.go \ + contracts/validatorcontract/validator_test.go \ + contracts/validatorcontract/contract/validator_set.go + ``` + +8. Run tests: + + ```sh + go test ./contracts/validatorcontract + go test ./contracts/... + ``` + +## Contract Compatibility Rules + +- `getValidators()` must remain present with the same signature. +- `getValidators()` must return only active validators. +- Governance quorum is based on all registered validators, not only active validators. +- `faultTolerance()` is calculated as `(N - 1) / 3`, where `N` is the number of registered validators. +- `quorumSize()` is calculated as `2f + 1`. +- A validator in maintenance still has governance voting power. +- At most `f` validators may be in maintenance at the same time. + +## Notes + +- The generated binding includes deployment bytecode, so regenerate it whenever the Solidity source changes, including NatSpec-only changes that affect metadata. +- Do not commit temporary Foundry `cache/` or `out/` directories. Prefer the `/private/tmp/...` paths shown above. diff --git a/contracts/validatorcontract/contract/validator_set.go b/contracts/validatorcontract/contract/validator_set.go new file mode 100644 index 000000000..45e11d85e --- /dev/null +++ b/contracts/validatorcontract/contract/validator_set.go @@ -0,0 +1,1367 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contract + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// ValidatorSetABI is the input ABI used to generate the binding from. +const ValidatorSetABI = "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"initialValidators\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"enterMaintenance\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"exitMaintenance\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"faultTolerance\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllValidators\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getValidators\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hasVoted\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"voter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isInMaintenance\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isValidator\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maintenanceSize\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalExecuted\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalId\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"proposalVotes\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quorumSize\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"voteAddValidator\",\"inputs\":[{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"voteRemoveValidator\",\"inputs\":[{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"MaintenanceEntered\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaintenanceExited\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorAdded\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorRemoved\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorVote\",\"inputs\":[{\"name\":\"proposalId\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"operation\",\"type\":\"uint8\",\"indexed\":true,\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"voter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"votes\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"quorum\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]" + +var ValidatorSetParsedABI, _ = abi.JSON(strings.NewReader(ValidatorSetABI)) + +// ValidatorSetBin is the compiled bytecode used for deploying new contracts. +var ValidatorSetBin = "0x608060405234801561001057600080fd5b50604051612ac3380380612ac38339818101604052810190610032919061048c565b6000815111610076576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161006d90610532565b60405180910390fd5b60005b81518110156100b8576100ab82828151811061009857610097610552565b5b60200260200101516100bf60201b60201c565b8080600101915050610079565b505061067f565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361012e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610125906105cd565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156101bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101b29061065f565b60405180910390fd5b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600080549050600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610323826102da565b810181811067ffffffffffffffff82111715610342576103416102eb565b5b80604052505050565b60006103556102c1565b9050610361828261031a565b919050565b600067ffffffffffffffff821115610381576103806102eb565b5b602082029050602081019050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103c282610397565b9050919050565b6103d2816103b7565b81146103dd57600080fd5b50565b6000815190506103ef816103c9565b92915050565b600061040861040384610366565b61034b565b9050808382526020820190506020840283018581111561042b5761042a610392565b5b835b81811015610454578061044088826103e0565b84526020840193505060208101905061042d565b5050509392505050565b600082601f830112610473576104726102d5565b5b81516104838482602086016103f5565b91505092915050565b6000602082840312156104a2576104a16102cb565b5b600082015167ffffffffffffffff8111156104c0576104bf6102d0565b5b6104cc8482850161045e565b91505092915050565b600082825260208201905092915050565b7f56616c696461746f725365743a20656d7074792076616c696461746f72730000600082015250565b600061051c601e836104d5565b9150610527826104e6565b602082019050919050565b6000602082019050818103600083015261054b8161050f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f56616c696461746f725365743a207a65726f2076616c696461746f7200000000600082015250565b60006105b7601c836104d5565b91506105c282610581565b602082019050919050565b600060208201905081810360008301526105e6816105aa565b9050919050565b7f56616c696461746f725365743a206475706c69636174652076616c696461746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b60006106496021836104d5565b9150610654826105ed565b604082019050919050565b600060208201905081810360008301526106788161063c565b9050919050565b6124358061068e6000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80639bf6a74a11610097578063e6c166e311610066578063e6c166e31461024e578063eac942a91461027e578063f3513a37146102ae578063facd743b146102cc576100f5565b80639bf6a74a146101b4578063a8b4b210146101d0578063b7ab4db514610200578063dfa45bdd1461021e576100f5565b806357456f22116100d357806357456f22146101405780635e401b3e1461015c57806375b76f1c1461018c5780639369d7de146101aa576100f5565b806304c4fec6146100fa57806322e28369146101045780633068ef4d14610122575b600080fd5b6101026102fc565b005b61010c6104c9565b6040516101199190611706565b60405180910390f35b61012a6104d3565b6040516101379190611706565b60405180910390f35b61015a60048036038101906101559190611784565b6104fa565b005b610176600480360381019061017191906117d6565b610690565b6040516101839190611844565b60405180910390f35b610194610705565b6040516101a19190611706565b60405180910390f35b6101b261072a565b005b6101ce60048036038101906101c99190611784565b610943565b005b6101ea60048036038101906101e5919061185f565b610ab1565b6040516101f791906118b8565b60405180910390f35b610208610ae4565b6040516102159190611991565b60405180910390f35b61023860048036038101906102339190611784565b610c63565b6040516102459190611844565b60405180910390f35b6102686004803603810190610263919061185f565b610cb9565b6040516102759190611706565b60405180910390f35b6102986004803603810190610293919061185f565b610ce3565b6040516102a59190611844565b60405180910390f35b6102b6610d1a565b6040516102c39190611991565b60405180910390f35b6102e660048036038101906102e19190611784565b610e1e565b6040516102f39190611844565b60405180910390f35b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610388576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161037f90611a36565b60405180910390fd5b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610414576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161040b90611aa2565b60405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506004600081548092919061047f90611af1565b91905055503373ffffffffffffffffffffffffffffffffffffffff167f0203ae0082a4b3f0b71e461ab5245258799bdb5d52d0f224a6aaed75deca688960405160405180910390a2565b6000600454905090565b600060016104df610705565b60026104eb9190611b1a565b6104f59190611b5c565b905090565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610586576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161057d90611a36565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036105f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ec90611bdc565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610682576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161067990611c6e565b60405180910390fd5b61068d600082610e74565b50565b6000600560006106a08686610ab1565b815260200190815260200160002060020160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1690509392505050565b60006003600160008054905061071b9190611c8e565b6107259190611cf1565b905090565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166107b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107ad90611a36565b60405180910390fd5b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610843576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161083a90611d94565b60405180910390fd5b61084b610705565b6004541061088e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161088590611e26565b60405180910390fd5b6001600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600460008154809291906108f990611e46565b91905055503373ffffffffffffffffffffffffffffffffffffffff167f44aa86acf916265e97ff989ab2c2289b9f442a5a4769121a3c82d3daf7ea972b60405160405180910390a2565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166109cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c690611a36565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610a5b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5290611f00565b60405180910390fd5b600160008054905011610aa3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9a90611f92565b60405180910390fd5b610aae600182610e74565b50565b60008282604051602001610ac6929190612098565b60405160208183030381529060405280519060200120905092915050565b60606000600454600080549050610afb9190611c8e565b905060008167ffffffffffffffff811115610b1957610b186120c4565b5b604051908082528060200260200182016040528015610b475781602001602082028036833780820191505090505b5090506000805b600080549050811015610c59576000808281548110610b7057610b6f6120f3565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610c4b5780848481518110610c0257610c016120f3565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508280610c4790611e46565b9350505b508080600101915050610b4e565b5081935050505090565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600060056000610cc98585610ab1565b815260200190815260200160002060000154905092915050565b600060056000610cf38585610ab1565b815260200190815260200160002060010160009054906101000a900460ff16905092915050565b60606000808054905067ffffffffffffffff811115610d3c57610d3b6120c4565b5b604051908082528060200260200182016040528015610d6a5781602001602082028036833780820191505090505b50905060005b600080549050811015610e165760008181548110610d9157610d906120f3565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110610dcf57610dce6120f3565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508080600101915050610d70565b508091505090565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000610e808383610ab1565b905060006005600083815260200190815260200160002090508060010160009054906101000a900460ff1615610eeb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ee29061216e565b60405180910390fd5b8060020160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610f7a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f71906121da565b60405180910390fd5b60018160020160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550806000016000815480929190610fe990611e46565b91905055506000610ff86104d3565b90508373ffffffffffffffffffffffffffffffffffffffff1685600181111561102457611023611fb2565b5b847f88de5c1b4216be3907eda6a00c98004ce4a2076ccd207f384d40e92d288fdab63386600001548660405161105c93929190612209565b60405180910390a4808260000154106111575760018260010160006101000a81548160ff021916908315150217905550600060018111156110a05761109f611fb2565b5b8560018111156110b3576110b2611fb2565b5b03611109576110c18461115e565b8373ffffffffffffffffffffffffffffffffffffffff167fe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec388498760405160405180910390a2611156565b61111284611360565b8373ffffffffffffffffffffffffffffffffffffffff167fe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f160405160405180910390a25b5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036111cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111c49061228c565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561125a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112519061231e565b60405180910390fd5b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600080549050600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166113ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113e3906123b0565b60405180910390fd5b600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156114af576000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600460008154809291906114a990611af1565b91905055505b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060008190505b600160008054905061150b9190611c8e565b81101561160f576000806001836115229190611b5c565b81548110611533576115326120f3565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508060008381548110611575576115746120f3565b5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505080806001019150506114f9565b506000805480611622576116216123d0565b5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690559055600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81549060ff02191690555050565b6000819050919050565b611700816116ed565b82525050565b600060208201905061171b60008301846116f7565b92915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061175182611726565b9050919050565b61176181611746565b811461176c57600080fd5b50565b60008135905061177e81611758565b92915050565b60006020828403121561179a57611799611721565b5b60006117a88482850161176f565b91505092915050565b600281106117be57600080fd5b50565b6000813590506117d0816117b1565b92915050565b6000806000606084860312156117ef576117ee611721565b5b60006117fd868287016117c1565b935050602061180e8682870161176f565b925050604061181f8682870161176f565b9150509250925092565b60008115159050919050565b61183e81611829565b82525050565b60006020820190506118596000830184611835565b92915050565b6000806040838503121561187657611875611721565b5b6000611884858286016117c1565b92505060206118958582860161176f565b9150509250929050565b6000819050919050565b6118b28161189f565b82525050565b60006020820190506118cd60008301846118a9565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61190881611746565b82525050565b600061191a83836118ff565b60208301905092915050565b6000602082019050919050565b600061193e826118d3565b61194881856118de565b9350611953836118ef565b8060005b8381101561198457815161196b888261190e565b975061197683611926565b925050600181019050611957565b5085935050505092915050565b600060208201905081810360008301526119ab8184611933565b905092915050565b600082825260208201905092915050565b7f56616c696461746f725365743a2073656e646572206973206e6f742076616c6960008201527f6461746f72000000000000000000000000000000000000000000000000000000602082015250565b6000611a206025836119b3565b9150611a2b826119c4565b604082019050919050565b60006020820190508181036000830152611a4f81611a13565b9050919050565b7f56616c696461746f725365743a206e6f7420696e206d61696e74656e616e6365600082015250565b6000611a8c6020836119b3565b9150611a9782611a56565b602082019050919050565b60006020820190508181036000830152611abb81611a7f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611afc826116ed565b915060008203611b0f57611b0e611ac2565b5b600182039050919050565b6000611b25826116ed565b9150611b30836116ed565b9250828202611b3e816116ed565b91508282048414831517611b5557611b54611ac2565b5b5092915050565b6000611b67826116ed565b9150611b72836116ed565b9250828201905080821115611b8a57611b89611ac2565b5b92915050565b7f56616c696461746f725365743a207a65726f2063616e64696461746500000000600082015250565b6000611bc6601c836119b3565b9150611bd182611b90565b602082019050919050565b60006020820190508181036000830152611bf581611bb9565b9050919050565b7f56616c696461746f725365743a2063616e6469646174652069732076616c696460008201527f61746f7200000000000000000000000000000000000000000000000000000000602082015250565b6000611c586024836119b3565b9150611c6382611bfc565b604082019050919050565b60006020820190508181036000830152611c8781611c4b565b9050919050565b6000611c99826116ed565b9150611ca4836116ed565b9250828203905081811115611cbc57611cbb611ac2565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000611cfc826116ed565b9150611d07836116ed565b925082611d1757611d16611cc2565b5b828204905092915050565b7f56616c696461746f725365743a20616c726561647920696e206d61696e74656e60008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000611d7e6024836119b3565b9150611d8982611d22565b604082019050919050565b60006020820190508181036000830152611dad81611d71565b9050919050565b7f56616c696461746f725365743a20746f6f206d616e792076616c696461746f7260008201527f7320696e206d61696e74656e616e636500000000000000000000000000000000602082015250565b6000611e106030836119b3565b9150611e1b82611db4565b604082019050919050565b60006020820190508181036000830152611e3f81611e03565b9050919050565b6000611e51826116ed565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e8357611e82611ac2565b5b600182019050919050565b7f56616c696461746f725365743a2063616e646964617465206973206e6f74207660008201527f616c696461746f72000000000000000000000000000000000000000000000000602082015250565b6000611eea6028836119b3565b9150611ef582611e8e565b604082019050919050565b60006020820190508181036000830152611f1981611edd565b9050919050565b7f56616c696461746f725365743a2063616e6e6f742072656d6f7665206c61737460008201527f2076616c696461746f7200000000000000000000000000000000000000000000602082015250565b6000611f7c602a836119b3565b9150611f8782611f20565b604082019050919050565b60006020820190508181036000830152611fab81611f6f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60028110611ff257611ff1611fb2565b5b50565b600081905061200382611fe1565b919050565b600061201382611ff5565b9050919050565b60008160f81b9050919050565b60006120328261201a565b9050919050565b61204a61204582612008565b612027565b82525050565b60008160601b9050919050565b600061206882612050565b9050919050565b600061207a8261205d565b9050919050565b61209261208d82611746565b61206f565b82525050565b60006120a48285612039565b6001820191506120b48284612081565b6014820191508190509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f56616c696461746f725365743a2070726f706f73616c20657865637574656400600082015250565b6000612158601f836119b3565b915061216382612122565b602082019050919050565b600060208201905081810360008301526121878161214b565b9050919050565b7f56616c696461746f725365743a20616c726561647920766f7465640000000000600082015250565b60006121c4601b836119b3565b91506121cf8261218e565b602082019050919050565b600060208201905081810360008301526121f3816121b7565b9050919050565b61220381611746565b82525050565b600060608201905061221e60008301866121fa565b61222b60208301856116f7565b61223860408301846116f7565b949350505050565b7f56616c696461746f725365743a207a65726f2076616c696461746f7200000000600082015250565b6000612276601c836119b3565b915061228182612240565b602082019050919050565b600060208201905081810360008301526122a581612269565b9050919050565b7f56616c696461746f725365743a206475706c69636174652076616c696461746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b60006123086021836119b3565b9150612313826122ac565b604082019050919050565b60006020820190508181036000830152612337816122fb565b9050919050565b7f56616c696461746f725365743a2076616c696461746f72206e6f7420666f756e60008201527f6400000000000000000000000000000000000000000000000000000000000000602082015250565b600061239a6021836119b3565b91506123a58261233e565b604082019050919050565b600060208201905081810360008301526123c98161238d565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212205b825b33b91a6b548e067adf4c576ee2301f5f03372edcd2dccfc1e17b0231ff64736f6c634300081e0033" + +// DeployValidatorSet deploys a new Ethereum contract, binding an instance of ValidatorSet to it. +func DeployValidatorSet(auth *bind.TransactOpts, backend bind.ContractBackend, initialValidators []common.Address) (common.Address, *types.Transaction, *ValidatorSet, error) { + parsed, err := abi.JSON(strings.NewReader(ValidatorSetABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ValidatorSetBin), backend, initialValidators) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &ValidatorSet{ValidatorSetCaller: ValidatorSetCaller{contract: contract}, ValidatorSetTransactor: ValidatorSetTransactor{contract: contract}, ValidatorSetFilterer: ValidatorSetFilterer{contract: contract}}, nil +} + +// ValidatorSet is an auto generated Go binding around an Ethereum contract. +type ValidatorSet struct { + ValidatorSetCaller // Read-only binding to the contract + ValidatorSetTransactor // Write-only binding to the contract + ValidatorSetFilterer // Log filterer for contract events +} + +// ValidatorSetCaller is an auto generated read-only Go binding around an Ethereum contract. +type ValidatorSetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ValidatorSetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ValidatorSetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ValidatorSetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ValidatorSetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ValidatorSetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ValidatorSetSession struct { + Contract *ValidatorSet // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ValidatorSetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ValidatorSetCallerSession struct { + Contract *ValidatorSetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ValidatorSetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ValidatorSetTransactorSession struct { + Contract *ValidatorSetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ValidatorSetRaw is an auto generated low-level Go binding around an Ethereum contract. +type ValidatorSetRaw struct { + Contract *ValidatorSet // Generic contract binding to access the raw methods on +} + +// ValidatorSetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ValidatorSetCallerRaw struct { + Contract *ValidatorSetCaller // Generic read-only contract binding to access the raw methods on +} + +// ValidatorSetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ValidatorSetTransactorRaw struct { + Contract *ValidatorSetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewValidatorSet creates a new instance of ValidatorSet, bound to a specific deployed contract. +func NewValidatorSet(address common.Address, backend bind.ContractBackend) (*ValidatorSet, error) { + contract, err := bindValidatorSet(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ValidatorSet{ValidatorSetCaller: ValidatorSetCaller{contract: contract}, ValidatorSetTransactor: ValidatorSetTransactor{contract: contract}, ValidatorSetFilterer: ValidatorSetFilterer{contract: contract}}, nil +} + +// NewValidatorSetCaller creates a new read-only instance of ValidatorSet, bound to a specific deployed contract. +func NewValidatorSetCaller(address common.Address, caller bind.ContractCaller) (*ValidatorSetCaller, error) { + contract, err := bindValidatorSet(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ValidatorSetCaller{contract: contract}, nil +} + +// NewValidatorSetTransactor creates a new write-only instance of ValidatorSet, bound to a specific deployed contract. +func NewValidatorSetTransactor(address common.Address, transactor bind.ContractTransactor) (*ValidatorSetTransactor, error) { + contract, err := bindValidatorSet(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ValidatorSetTransactor{contract: contract}, nil +} + +// NewValidatorSetFilterer creates a new log filterer instance of ValidatorSet, bound to a specific deployed contract. +func NewValidatorSetFilterer(address common.Address, filterer bind.ContractFilterer) (*ValidatorSetFilterer, error) { + contract, err := bindValidatorSet(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ValidatorSetFilterer{contract: contract}, nil +} + +// bindValidatorSet binds a generic wrapper to an already deployed contract. +func bindValidatorSet(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(ValidatorSetABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ValidatorSet *ValidatorSetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ValidatorSet.Contract.ValidatorSetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ValidatorSet *ValidatorSetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ValidatorSet.Contract.ValidatorSetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ValidatorSet *ValidatorSetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ValidatorSet.Contract.ValidatorSetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ValidatorSet *ValidatorSetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ValidatorSet.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ValidatorSet *ValidatorSetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ValidatorSet.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ValidatorSet *ValidatorSetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ValidatorSet.Contract.contract.Transact(opts, method, params...) +} + +// FaultTolerance is a free data retrieval call binding the contract method 0x75b76f1c. +// +// Solidity: function faultTolerance() view returns(uint256) +func (_ValidatorSet *ValidatorSetCaller) FaultTolerance(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "faultTolerance") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FaultTolerance is a free data retrieval call binding the contract method 0x75b76f1c. +// +// Solidity: function faultTolerance() view returns(uint256) +func (_ValidatorSet *ValidatorSetSession) FaultTolerance() (*big.Int, error) { + return _ValidatorSet.Contract.FaultTolerance(&_ValidatorSet.CallOpts) +} + +// FaultTolerance is a free data retrieval call binding the contract method 0x75b76f1c. +// +// Solidity: function faultTolerance() view returns(uint256) +func (_ValidatorSet *ValidatorSetCallerSession) FaultTolerance() (*big.Int, error) { + return _ValidatorSet.Contract.FaultTolerance(&_ValidatorSet.CallOpts) +} + +// GetAllValidators is a free data retrieval call binding the contract method 0xf3513a37. +// +// Solidity: function getAllValidators() view returns(address[]) +func (_ValidatorSet *ValidatorSetCaller) GetAllValidators(opts *bind.CallOpts) ([]common.Address, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "getAllValidators") + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +// GetAllValidators is a free data retrieval call binding the contract method 0xf3513a37. +// +// Solidity: function getAllValidators() view returns(address[]) +func (_ValidatorSet *ValidatorSetSession) GetAllValidators() ([]common.Address, error) { + return _ValidatorSet.Contract.GetAllValidators(&_ValidatorSet.CallOpts) +} + +// GetAllValidators is a free data retrieval call binding the contract method 0xf3513a37. +// +// Solidity: function getAllValidators() view returns(address[]) +func (_ValidatorSet *ValidatorSetCallerSession) GetAllValidators() ([]common.Address, error) { + return _ValidatorSet.Contract.GetAllValidators(&_ValidatorSet.CallOpts) +} + +// GetValidators is a free data retrieval call binding the contract method 0xb7ab4db5. +// +// Solidity: function getValidators() view returns(address[]) +func (_ValidatorSet *ValidatorSetCaller) GetValidators(opts *bind.CallOpts) ([]common.Address, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "getValidators") + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +// GetValidators is a free data retrieval call binding the contract method 0xb7ab4db5. +// +// Solidity: function getValidators() view returns(address[]) +func (_ValidatorSet *ValidatorSetSession) GetValidators() ([]common.Address, error) { + return _ValidatorSet.Contract.GetValidators(&_ValidatorSet.CallOpts) +} + +// GetValidators is a free data retrieval call binding the contract method 0xb7ab4db5. +// +// Solidity: function getValidators() view returns(address[]) +func (_ValidatorSet *ValidatorSetCallerSession) GetValidators() ([]common.Address, error) { + return _ValidatorSet.Contract.GetValidators(&_ValidatorSet.CallOpts) +} + +// HasVoted is a free data retrieval call binding the contract method 0x5e401b3e. +// +// Solidity: function hasVoted(uint8 operation, address candidate, address voter) view returns(bool) +func (_ValidatorSet *ValidatorSetCaller) HasVoted(opts *bind.CallOpts, operation uint8, candidate common.Address, voter common.Address) (bool, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "hasVoted", operation, candidate, voter) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasVoted is a free data retrieval call binding the contract method 0x5e401b3e. +// +// Solidity: function hasVoted(uint8 operation, address candidate, address voter) view returns(bool) +func (_ValidatorSet *ValidatorSetSession) HasVoted(operation uint8, candidate common.Address, voter common.Address) (bool, error) { + return _ValidatorSet.Contract.HasVoted(&_ValidatorSet.CallOpts, operation, candidate, voter) +} + +// HasVoted is a free data retrieval call binding the contract method 0x5e401b3e. +// +// Solidity: function hasVoted(uint8 operation, address candidate, address voter) view returns(bool) +func (_ValidatorSet *ValidatorSetCallerSession) HasVoted(operation uint8, candidate common.Address, voter common.Address) (bool, error) { + return _ValidatorSet.Contract.HasVoted(&_ValidatorSet.CallOpts, operation, candidate, voter) +} + +// IsInMaintenance is a free data retrieval call binding the contract method 0xdfa45bdd. +// +// Solidity: function isInMaintenance(address validator) view returns(bool) +func (_ValidatorSet *ValidatorSetCaller) IsInMaintenance(opts *bind.CallOpts, validator common.Address) (bool, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "isInMaintenance", validator) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsInMaintenance is a free data retrieval call binding the contract method 0xdfa45bdd. +// +// Solidity: function isInMaintenance(address validator) view returns(bool) +func (_ValidatorSet *ValidatorSetSession) IsInMaintenance(validator common.Address) (bool, error) { + return _ValidatorSet.Contract.IsInMaintenance(&_ValidatorSet.CallOpts, validator) +} + +// IsInMaintenance is a free data retrieval call binding the contract method 0xdfa45bdd. +// +// Solidity: function isInMaintenance(address validator) view returns(bool) +func (_ValidatorSet *ValidatorSetCallerSession) IsInMaintenance(validator common.Address) (bool, error) { + return _ValidatorSet.Contract.IsInMaintenance(&_ValidatorSet.CallOpts, validator) +} + +// IsValidator is a free data retrieval call binding the contract method 0xfacd743b. +// +// Solidity: function isValidator(address validator) view returns(bool) +func (_ValidatorSet *ValidatorSetCaller) IsValidator(opts *bind.CallOpts, validator common.Address) (bool, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "isValidator", validator) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsValidator is a free data retrieval call binding the contract method 0xfacd743b. +// +// Solidity: function isValidator(address validator) view returns(bool) +func (_ValidatorSet *ValidatorSetSession) IsValidator(validator common.Address) (bool, error) { + return _ValidatorSet.Contract.IsValidator(&_ValidatorSet.CallOpts, validator) +} + +// IsValidator is a free data retrieval call binding the contract method 0xfacd743b. +// +// Solidity: function isValidator(address validator) view returns(bool) +func (_ValidatorSet *ValidatorSetCallerSession) IsValidator(validator common.Address) (bool, error) { + return _ValidatorSet.Contract.IsValidator(&_ValidatorSet.CallOpts, validator) +} + +// MaintenanceSize is a free data retrieval call binding the contract method 0x22e28369. +// +// Solidity: function maintenanceSize() view returns(uint256) +func (_ValidatorSet *ValidatorSetCaller) MaintenanceSize(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "maintenanceSize") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MaintenanceSize is a free data retrieval call binding the contract method 0x22e28369. +// +// Solidity: function maintenanceSize() view returns(uint256) +func (_ValidatorSet *ValidatorSetSession) MaintenanceSize() (*big.Int, error) { + return _ValidatorSet.Contract.MaintenanceSize(&_ValidatorSet.CallOpts) +} + +// MaintenanceSize is a free data retrieval call binding the contract method 0x22e28369. +// +// Solidity: function maintenanceSize() view returns(uint256) +func (_ValidatorSet *ValidatorSetCallerSession) MaintenanceSize() (*big.Int, error) { + return _ValidatorSet.Contract.MaintenanceSize(&_ValidatorSet.CallOpts) +} + +// ProposalExecuted is a free data retrieval call binding the contract method 0xeac942a9. +// +// Solidity: function proposalExecuted(uint8 operation, address candidate) view returns(bool) +func (_ValidatorSet *ValidatorSetCaller) ProposalExecuted(opts *bind.CallOpts, operation uint8, candidate common.Address) (bool, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "proposalExecuted", operation, candidate) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// ProposalExecuted is a free data retrieval call binding the contract method 0xeac942a9. +// +// Solidity: function proposalExecuted(uint8 operation, address candidate) view returns(bool) +func (_ValidatorSet *ValidatorSetSession) ProposalExecuted(operation uint8, candidate common.Address) (bool, error) { + return _ValidatorSet.Contract.ProposalExecuted(&_ValidatorSet.CallOpts, operation, candidate) +} + +// ProposalExecuted is a free data retrieval call binding the contract method 0xeac942a9. +// +// Solidity: function proposalExecuted(uint8 operation, address candidate) view returns(bool) +func (_ValidatorSet *ValidatorSetCallerSession) ProposalExecuted(operation uint8, candidate common.Address) (bool, error) { + return _ValidatorSet.Contract.ProposalExecuted(&_ValidatorSet.CallOpts, operation, candidate) +} + +// ProposalId is a free data retrieval call binding the contract method 0xa8b4b210. +// +// Solidity: function proposalId(uint8 operation, address candidate) pure returns(bytes32) +func (_ValidatorSet *ValidatorSetCaller) ProposalId(opts *bind.CallOpts, operation uint8, candidate common.Address) ([32]byte, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "proposalId", operation, candidate) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// ProposalId is a free data retrieval call binding the contract method 0xa8b4b210. +// +// Solidity: function proposalId(uint8 operation, address candidate) pure returns(bytes32) +func (_ValidatorSet *ValidatorSetSession) ProposalId(operation uint8, candidate common.Address) ([32]byte, error) { + return _ValidatorSet.Contract.ProposalId(&_ValidatorSet.CallOpts, operation, candidate) +} + +// ProposalId is a free data retrieval call binding the contract method 0xa8b4b210. +// +// Solidity: function proposalId(uint8 operation, address candidate) pure returns(bytes32) +func (_ValidatorSet *ValidatorSetCallerSession) ProposalId(operation uint8, candidate common.Address) ([32]byte, error) { + return _ValidatorSet.Contract.ProposalId(&_ValidatorSet.CallOpts, operation, candidate) +} + +// ProposalVotes is a free data retrieval call binding the contract method 0xe6c166e3. +// +// Solidity: function proposalVotes(uint8 operation, address candidate) view returns(uint256) +func (_ValidatorSet *ValidatorSetCaller) ProposalVotes(opts *bind.CallOpts, operation uint8, candidate common.Address) (*big.Int, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "proposalVotes", operation, candidate) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProposalVotes is a free data retrieval call binding the contract method 0xe6c166e3. +// +// Solidity: function proposalVotes(uint8 operation, address candidate) view returns(uint256) +func (_ValidatorSet *ValidatorSetSession) ProposalVotes(operation uint8, candidate common.Address) (*big.Int, error) { + return _ValidatorSet.Contract.ProposalVotes(&_ValidatorSet.CallOpts, operation, candidate) +} + +// ProposalVotes is a free data retrieval call binding the contract method 0xe6c166e3. +// +// Solidity: function proposalVotes(uint8 operation, address candidate) view returns(uint256) +func (_ValidatorSet *ValidatorSetCallerSession) ProposalVotes(operation uint8, candidate common.Address) (*big.Int, error) { + return _ValidatorSet.Contract.ProposalVotes(&_ValidatorSet.CallOpts, operation, candidate) +} + +// QuorumSize is a free data retrieval call binding the contract method 0x3068ef4d. +// +// Solidity: function quorumSize() view returns(uint256) +func (_ValidatorSet *ValidatorSetCaller) QuorumSize(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "quorumSize") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// QuorumSize is a free data retrieval call binding the contract method 0x3068ef4d. +// +// Solidity: function quorumSize() view returns(uint256) +func (_ValidatorSet *ValidatorSetSession) QuorumSize() (*big.Int, error) { + return _ValidatorSet.Contract.QuorumSize(&_ValidatorSet.CallOpts) +} + +// QuorumSize is a free data retrieval call binding the contract method 0x3068ef4d. +// +// Solidity: function quorumSize() view returns(uint256) +func (_ValidatorSet *ValidatorSetCallerSession) QuorumSize() (*big.Int, error) { + return _ValidatorSet.Contract.QuorumSize(&_ValidatorSet.CallOpts) +} + +// EnterMaintenance is a paid mutator transaction binding the contract method 0x9369d7de. +// +// Solidity: function enterMaintenance() returns() +func (_ValidatorSet *ValidatorSetTransactor) EnterMaintenance(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ValidatorSet.contract.Transact(opts, "enterMaintenance") +} + +// EnterMaintenance is a paid mutator transaction binding the contract method 0x9369d7de. +// +// Solidity: function enterMaintenance() returns() +func (_ValidatorSet *ValidatorSetSession) EnterMaintenance() (*types.Transaction, error) { + return _ValidatorSet.Contract.EnterMaintenance(&_ValidatorSet.TransactOpts) +} + +// EnterMaintenance is a paid mutator transaction binding the contract method 0x9369d7de. +// +// Solidity: function enterMaintenance() returns() +func (_ValidatorSet *ValidatorSetTransactorSession) EnterMaintenance() (*types.Transaction, error) { + return _ValidatorSet.Contract.EnterMaintenance(&_ValidatorSet.TransactOpts) +} + +// ExitMaintenance is a paid mutator transaction binding the contract method 0x04c4fec6. +// +// Solidity: function exitMaintenance() returns() +func (_ValidatorSet *ValidatorSetTransactor) ExitMaintenance(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ValidatorSet.contract.Transact(opts, "exitMaintenance") +} + +// ExitMaintenance is a paid mutator transaction binding the contract method 0x04c4fec6. +// +// Solidity: function exitMaintenance() returns() +func (_ValidatorSet *ValidatorSetSession) ExitMaintenance() (*types.Transaction, error) { + return _ValidatorSet.Contract.ExitMaintenance(&_ValidatorSet.TransactOpts) +} + +// ExitMaintenance is a paid mutator transaction binding the contract method 0x04c4fec6. +// +// Solidity: function exitMaintenance() returns() +func (_ValidatorSet *ValidatorSetTransactorSession) ExitMaintenance() (*types.Transaction, error) { + return _ValidatorSet.Contract.ExitMaintenance(&_ValidatorSet.TransactOpts) +} + +// VoteAddValidator is a paid mutator transaction binding the contract method 0x57456f22. +// +// Solidity: function voteAddValidator(address candidate) returns() +func (_ValidatorSet *ValidatorSetTransactor) VoteAddValidator(opts *bind.TransactOpts, candidate common.Address) (*types.Transaction, error) { + return _ValidatorSet.contract.Transact(opts, "voteAddValidator", candidate) +} + +// VoteAddValidator is a paid mutator transaction binding the contract method 0x57456f22. +// +// Solidity: function voteAddValidator(address candidate) returns() +func (_ValidatorSet *ValidatorSetSession) VoteAddValidator(candidate common.Address) (*types.Transaction, error) { + return _ValidatorSet.Contract.VoteAddValidator(&_ValidatorSet.TransactOpts, candidate) +} + +// VoteAddValidator is a paid mutator transaction binding the contract method 0x57456f22. +// +// Solidity: function voteAddValidator(address candidate) returns() +func (_ValidatorSet *ValidatorSetTransactorSession) VoteAddValidator(candidate common.Address) (*types.Transaction, error) { + return _ValidatorSet.Contract.VoteAddValidator(&_ValidatorSet.TransactOpts, candidate) +} + +// VoteRemoveValidator is a paid mutator transaction binding the contract method 0x9bf6a74a. +// +// Solidity: function voteRemoveValidator(address candidate) returns() +func (_ValidatorSet *ValidatorSetTransactor) VoteRemoveValidator(opts *bind.TransactOpts, candidate common.Address) (*types.Transaction, error) { + return _ValidatorSet.contract.Transact(opts, "voteRemoveValidator", candidate) +} + +// VoteRemoveValidator is a paid mutator transaction binding the contract method 0x9bf6a74a. +// +// Solidity: function voteRemoveValidator(address candidate) returns() +func (_ValidatorSet *ValidatorSetSession) VoteRemoveValidator(candidate common.Address) (*types.Transaction, error) { + return _ValidatorSet.Contract.VoteRemoveValidator(&_ValidatorSet.TransactOpts, candidate) +} + +// VoteRemoveValidator is a paid mutator transaction binding the contract method 0x9bf6a74a. +// +// Solidity: function voteRemoveValidator(address candidate) returns() +func (_ValidatorSet *ValidatorSetTransactorSession) VoteRemoveValidator(candidate common.Address) (*types.Transaction, error) { + return _ValidatorSet.Contract.VoteRemoveValidator(&_ValidatorSet.TransactOpts, candidate) +} + +// ValidatorSetMaintenanceEnteredIterator is returned from FilterMaintenanceEntered and is used to iterate over the raw logs and unpacked data for MaintenanceEntered events raised by the ValidatorSet contract. +type ValidatorSetMaintenanceEnteredIterator struct { + Event *ValidatorSetMaintenanceEntered // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ValidatorSetMaintenanceEnteredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ValidatorSetMaintenanceEntered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ValidatorSetMaintenanceEntered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ValidatorSetMaintenanceEnteredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ValidatorSetMaintenanceEnteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ValidatorSetMaintenanceEntered represents a MaintenanceEntered event raised by the ValidatorSet contract. +type ValidatorSetMaintenanceEntered struct { + Validator common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMaintenanceEntered is a free log retrieval operation binding the contract event 0x44aa86acf916265e97ff989ab2c2289b9f442a5a4769121a3c82d3daf7ea972b. +// +// Solidity: event MaintenanceEntered(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) FilterMaintenanceEntered(opts *bind.FilterOpts, validator []common.Address) (*ValidatorSetMaintenanceEnteredIterator, error) { + + var validatorRule []interface{} + for _, validatorItem := range validator { + validatorRule = append(validatorRule, validatorItem) + } + + logs, sub, err := _ValidatorSet.contract.FilterLogs(opts, "MaintenanceEntered", validatorRule) + if err != nil { + return nil, err + } + return &ValidatorSetMaintenanceEnteredIterator{contract: _ValidatorSet.contract, event: "MaintenanceEntered", logs: logs, sub: sub}, nil +} + +var MaintenanceEnteredTopicHash = "0x44aa86acf916265e97ff989ab2c2289b9f442a5a4769121a3c82d3daf7ea972b" + +// WatchMaintenanceEntered is a free log subscription operation binding the contract event 0x44aa86acf916265e97ff989ab2c2289b9f442a5a4769121a3c82d3daf7ea972b. +// +// Solidity: event MaintenanceEntered(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) WatchMaintenanceEntered(opts *bind.WatchOpts, sink chan<- *ValidatorSetMaintenanceEntered, validator []common.Address) (event.Subscription, error) { + + var validatorRule []interface{} + for _, validatorItem := range validator { + validatorRule = append(validatorRule, validatorItem) + } + + logs, sub, err := _ValidatorSet.contract.WatchLogs(opts, "MaintenanceEntered", validatorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ValidatorSetMaintenanceEntered) + if err := _ValidatorSet.contract.UnpackLog(event, "MaintenanceEntered", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMaintenanceEntered is a log parse operation binding the contract event 0x44aa86acf916265e97ff989ab2c2289b9f442a5a4769121a3c82d3daf7ea972b. +// +// Solidity: event MaintenanceEntered(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) ParseMaintenanceEntered(log types.Log) (*ValidatorSetMaintenanceEntered, error) { + event := new(ValidatorSetMaintenanceEntered) + if err := _ValidatorSet.contract.UnpackLog(event, "MaintenanceEntered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ValidatorSetMaintenanceExitedIterator is returned from FilterMaintenanceExited and is used to iterate over the raw logs and unpacked data for MaintenanceExited events raised by the ValidatorSet contract. +type ValidatorSetMaintenanceExitedIterator struct { + Event *ValidatorSetMaintenanceExited // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ValidatorSetMaintenanceExitedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ValidatorSetMaintenanceExited) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ValidatorSetMaintenanceExited) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ValidatorSetMaintenanceExitedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ValidatorSetMaintenanceExitedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ValidatorSetMaintenanceExited represents a MaintenanceExited event raised by the ValidatorSet contract. +type ValidatorSetMaintenanceExited struct { + Validator common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMaintenanceExited is a free log retrieval operation binding the contract event 0x0203ae0082a4b3f0b71e461ab5245258799bdb5d52d0f224a6aaed75deca6889. +// +// Solidity: event MaintenanceExited(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) FilterMaintenanceExited(opts *bind.FilterOpts, validator []common.Address) (*ValidatorSetMaintenanceExitedIterator, error) { + + var validatorRule []interface{} + for _, validatorItem := range validator { + validatorRule = append(validatorRule, validatorItem) + } + + logs, sub, err := _ValidatorSet.contract.FilterLogs(opts, "MaintenanceExited", validatorRule) + if err != nil { + return nil, err + } + return &ValidatorSetMaintenanceExitedIterator{contract: _ValidatorSet.contract, event: "MaintenanceExited", logs: logs, sub: sub}, nil +} + +var MaintenanceExitedTopicHash = "0x0203ae0082a4b3f0b71e461ab5245258799bdb5d52d0f224a6aaed75deca6889" + +// WatchMaintenanceExited is a free log subscription operation binding the contract event 0x0203ae0082a4b3f0b71e461ab5245258799bdb5d52d0f224a6aaed75deca6889. +// +// Solidity: event MaintenanceExited(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) WatchMaintenanceExited(opts *bind.WatchOpts, sink chan<- *ValidatorSetMaintenanceExited, validator []common.Address) (event.Subscription, error) { + + var validatorRule []interface{} + for _, validatorItem := range validator { + validatorRule = append(validatorRule, validatorItem) + } + + logs, sub, err := _ValidatorSet.contract.WatchLogs(opts, "MaintenanceExited", validatorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ValidatorSetMaintenanceExited) + if err := _ValidatorSet.contract.UnpackLog(event, "MaintenanceExited", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMaintenanceExited is a log parse operation binding the contract event 0x0203ae0082a4b3f0b71e461ab5245258799bdb5d52d0f224a6aaed75deca6889. +// +// Solidity: event MaintenanceExited(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) ParseMaintenanceExited(log types.Log) (*ValidatorSetMaintenanceExited, error) { + event := new(ValidatorSetMaintenanceExited) + if err := _ValidatorSet.contract.UnpackLog(event, "MaintenanceExited", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ValidatorSetValidatorAddedIterator is returned from FilterValidatorAdded and is used to iterate over the raw logs and unpacked data for ValidatorAdded events raised by the ValidatorSet contract. +type ValidatorSetValidatorAddedIterator struct { + Event *ValidatorSetValidatorAdded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ValidatorSetValidatorAddedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ValidatorSetValidatorAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ValidatorSetValidatorAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ValidatorSetValidatorAddedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ValidatorSetValidatorAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ValidatorSetValidatorAdded represents a ValidatorAdded event raised by the ValidatorSet contract. +type ValidatorSetValidatorAdded struct { + Validator common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterValidatorAdded is a free log retrieval operation binding the contract event 0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987. +// +// Solidity: event ValidatorAdded(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) FilterValidatorAdded(opts *bind.FilterOpts, validator []common.Address) (*ValidatorSetValidatorAddedIterator, error) { + + var validatorRule []interface{} + for _, validatorItem := range validator { + validatorRule = append(validatorRule, validatorItem) + } + + logs, sub, err := _ValidatorSet.contract.FilterLogs(opts, "ValidatorAdded", validatorRule) + if err != nil { + return nil, err + } + return &ValidatorSetValidatorAddedIterator{contract: _ValidatorSet.contract, event: "ValidatorAdded", logs: logs, sub: sub}, nil +} + +var ValidatorAddedTopicHash = "0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987" + +// WatchValidatorAdded is a free log subscription operation binding the contract event 0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987. +// +// Solidity: event ValidatorAdded(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) WatchValidatorAdded(opts *bind.WatchOpts, sink chan<- *ValidatorSetValidatorAdded, validator []common.Address) (event.Subscription, error) { + + var validatorRule []interface{} + for _, validatorItem := range validator { + validatorRule = append(validatorRule, validatorItem) + } + + logs, sub, err := _ValidatorSet.contract.WatchLogs(opts, "ValidatorAdded", validatorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ValidatorSetValidatorAdded) + if err := _ValidatorSet.contract.UnpackLog(event, "ValidatorAdded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseValidatorAdded is a log parse operation binding the contract event 0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987. +// +// Solidity: event ValidatorAdded(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) ParseValidatorAdded(log types.Log) (*ValidatorSetValidatorAdded, error) { + event := new(ValidatorSetValidatorAdded) + if err := _ValidatorSet.contract.UnpackLog(event, "ValidatorAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ValidatorSetValidatorRemovedIterator is returned from FilterValidatorRemoved and is used to iterate over the raw logs and unpacked data for ValidatorRemoved events raised by the ValidatorSet contract. +type ValidatorSetValidatorRemovedIterator struct { + Event *ValidatorSetValidatorRemoved // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ValidatorSetValidatorRemovedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ValidatorSetValidatorRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ValidatorSetValidatorRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ValidatorSetValidatorRemovedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ValidatorSetValidatorRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ValidatorSetValidatorRemoved represents a ValidatorRemoved event raised by the ValidatorSet contract. +type ValidatorSetValidatorRemoved struct { + Validator common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterValidatorRemoved is a free log retrieval operation binding the contract event 0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1. +// +// Solidity: event ValidatorRemoved(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) FilterValidatorRemoved(opts *bind.FilterOpts, validator []common.Address) (*ValidatorSetValidatorRemovedIterator, error) { + + var validatorRule []interface{} + for _, validatorItem := range validator { + validatorRule = append(validatorRule, validatorItem) + } + + logs, sub, err := _ValidatorSet.contract.FilterLogs(opts, "ValidatorRemoved", validatorRule) + if err != nil { + return nil, err + } + return &ValidatorSetValidatorRemovedIterator{contract: _ValidatorSet.contract, event: "ValidatorRemoved", logs: logs, sub: sub}, nil +} + +var ValidatorRemovedTopicHash = "0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1" + +// WatchValidatorRemoved is a free log subscription operation binding the contract event 0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1. +// +// Solidity: event ValidatorRemoved(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) WatchValidatorRemoved(opts *bind.WatchOpts, sink chan<- *ValidatorSetValidatorRemoved, validator []common.Address) (event.Subscription, error) { + + var validatorRule []interface{} + for _, validatorItem := range validator { + validatorRule = append(validatorRule, validatorItem) + } + + logs, sub, err := _ValidatorSet.contract.WatchLogs(opts, "ValidatorRemoved", validatorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ValidatorSetValidatorRemoved) + if err := _ValidatorSet.contract.UnpackLog(event, "ValidatorRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseValidatorRemoved is a log parse operation binding the contract event 0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1. +// +// Solidity: event ValidatorRemoved(address indexed validator) +func (_ValidatorSet *ValidatorSetFilterer) ParseValidatorRemoved(log types.Log) (*ValidatorSetValidatorRemoved, error) { + event := new(ValidatorSetValidatorRemoved) + if err := _ValidatorSet.contract.UnpackLog(event, "ValidatorRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ValidatorSetValidatorVoteIterator is returned from FilterValidatorVote and is used to iterate over the raw logs and unpacked data for ValidatorVote events raised by the ValidatorSet contract. +type ValidatorSetValidatorVoteIterator struct { + Event *ValidatorSetValidatorVote // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ValidatorSetValidatorVoteIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ValidatorSetValidatorVote) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ValidatorSetValidatorVote) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ValidatorSetValidatorVoteIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ValidatorSetValidatorVoteIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ValidatorSetValidatorVote represents a ValidatorVote event raised by the ValidatorSet contract. +type ValidatorSetValidatorVote struct { + ProposalId [32]byte + Operation uint8 + Candidate common.Address + Voter common.Address + Votes *big.Int + Quorum *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterValidatorVote is a free log retrieval operation binding the contract event 0x88de5c1b4216be3907eda6a00c98004ce4a2076ccd207f384d40e92d288fdab6. +// +// Solidity: event ValidatorVote(bytes32 indexed proposalId, uint8 indexed operation, address indexed candidate, address voter, uint256 votes, uint256 quorum) +func (_ValidatorSet *ValidatorSetFilterer) FilterValidatorVote(opts *bind.FilterOpts, proposalId [][32]byte, operation []uint8, candidate []common.Address) (*ValidatorSetValidatorVoteIterator, error) { + + var proposalIdRule []interface{} + for _, proposalIdItem := range proposalId { + proposalIdRule = append(proposalIdRule, proposalIdItem) + } + var operationRule []interface{} + for _, operationItem := range operation { + operationRule = append(operationRule, operationItem) + } + var candidateRule []interface{} + for _, candidateItem := range candidate { + candidateRule = append(candidateRule, candidateItem) + } + + logs, sub, err := _ValidatorSet.contract.FilterLogs(opts, "ValidatorVote", proposalIdRule, operationRule, candidateRule) + if err != nil { + return nil, err + } + return &ValidatorSetValidatorVoteIterator{contract: _ValidatorSet.contract, event: "ValidatorVote", logs: logs, sub: sub}, nil +} + +var ValidatorVoteTopicHash = "0x88de5c1b4216be3907eda6a00c98004ce4a2076ccd207f384d40e92d288fdab6" + +// WatchValidatorVote is a free log subscription operation binding the contract event 0x88de5c1b4216be3907eda6a00c98004ce4a2076ccd207f384d40e92d288fdab6. +// +// Solidity: event ValidatorVote(bytes32 indexed proposalId, uint8 indexed operation, address indexed candidate, address voter, uint256 votes, uint256 quorum) +func (_ValidatorSet *ValidatorSetFilterer) WatchValidatorVote(opts *bind.WatchOpts, sink chan<- *ValidatorSetValidatorVote, proposalId [][32]byte, operation []uint8, candidate []common.Address) (event.Subscription, error) { + + var proposalIdRule []interface{} + for _, proposalIdItem := range proposalId { + proposalIdRule = append(proposalIdRule, proposalIdItem) + } + var operationRule []interface{} + for _, operationItem := range operation { + operationRule = append(operationRule, operationItem) + } + var candidateRule []interface{} + for _, candidateItem := range candidate { + candidateRule = append(candidateRule, candidateItem) + } + + logs, sub, err := _ValidatorSet.contract.WatchLogs(opts, "ValidatorVote", proposalIdRule, operationRule, candidateRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ValidatorSetValidatorVote) + if err := _ValidatorSet.contract.UnpackLog(event, "ValidatorVote", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseValidatorVote is a log parse operation binding the contract event 0x88de5c1b4216be3907eda6a00c98004ce4a2076ccd207f384d40e92d288fdab6. +// +// Solidity: event ValidatorVote(bytes32 indexed proposalId, uint8 indexed operation, address indexed candidate, address voter, uint256 votes, uint256 quorum) +func (_ValidatorSet *ValidatorSetFilterer) ParseValidatorVote(log types.Log) (*ValidatorSetValidatorVote, error) { + event := new(ValidatorSetValidatorVote) + if err := _ValidatorSet.contract.UnpackLog(event, "ValidatorVote", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/contracts/validatorcontract/contract/validator_set.sol b/contracts/validatorcontract/contract/validator_set.sol new file mode 100644 index 000000000..a91e2c114 --- /dev/null +++ b/contracts/validatorcontract/contract/validator_set.sol @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright 2026 BOOSTRY Co., Ltd. +pragma solidity ^0.8.30; + +/// @title ValidatorSet +/// @notice Reference validator contract for QBFT contract-based validator selection. +/// @dev +/// This contract exposes `getValidators()` as the canonical read interface used by +/// QBFT contract-based validator selection. The returned validator set excludes +/// validators that have put themselves into maintenance mode, while governance +/// voting power remains based on the full registered validator set. +contract ValidatorSet { + /// @notice Governance operation type for validator set proposals. + /// @dev Values are part of the proposal ID preimage. Do not reorder them in upgrades. + enum Operation { + Add, + Remove + } + + /// @dev Tracks votes for a single operation/candidate pair. + /// The nested `voted` mapping prevents duplicate votes by the same validator. + struct Proposal { + uint256 votes; + bool executed; + mapping(address => bool) voted; + } + + /// @notice Emitted when a candidate reaches quorum and is added as a validator. + /// @param validator The validator address added to the registered validator set. + event ValidatorAdded(address indexed validator); + + /// @notice Emitted when a candidate reaches quorum and is removed from the validator set. + /// @param validator The validator address removed from the registered validator set. + event ValidatorRemoved(address indexed validator); + + /// @notice Emitted whenever a validator casts a governance vote. + /// @param proposalId Unique ID derived from the operation and candidate. + /// @param operation The requested validator set operation. + /// @param candidate The address proposed for addition or removal. + /// @param voter The validator that cast the vote. + /// @param votes Current number of votes recorded for the proposal after this vote. + /// @param quorum Number of votes required for the proposal to execute. + event ValidatorVote( + bytes32 indexed proposalId, + Operation indexed operation, + address indexed candidate, + address voter, + uint256 votes, + uint256 quorum + ); + + /// @notice Emitted when a validator enters maintenance mode. + /// @param validator The validator excluded from `getValidators()` while in maintenance. + event MaintenanceEntered(address indexed validator); + + /// @notice Emitted when a validator exits maintenance mode. + /// @param validator The validator included again in `getValidators()`. + event MaintenanceExited(address indexed validator); + + address[] private validators; + mapping(address => bool) private validatorStatus; + mapping(address => uint256) private validatorIndexes; + mapping(address => bool) private maintenanceStatus; + uint256 private maintenanceCount; + mapping(bytes32 => Proposal) private proposals; + + modifier onlyValidator() { + require(validatorStatus[msg.sender], "ValidatorSet: sender is not validator"); + _; + } + + /// @notice Deploys the validator set with the initial registered validators. + /// @dev + /// The initial list must be non-empty, contain no zero address, and contain no + /// duplicate addresses. All initial validators are active at deployment. + /// @param initialValidators Initial registered validator addresses. + constructor(address[] memory initialValidators) { + require(initialValidators.length > 0, "ValidatorSet: empty validators"); + for (uint256 i = 0; i < initialValidators.length; i++) { + _addValidator(initialValidators[i]); + } + } + + /// @notice Returns active validators for QBFT proposer selection and quorum calculation. + /// @dev + /// This is the compatibility method expected by the existing QBFT contract mode. + /// Validators in maintenance are deliberately excluded from this returned list. + /// The returned order follows the registered validator order, skipping maintenance entries. + /// @return Active validator addresses. + function getValidators() external view returns (address[] memory) { + uint256 activeCount = validators.length - maintenanceCount; + address[] memory activeValidators = new address[](activeCount); + uint256 index = 0; + + for (uint256 i = 0; i < validators.length; i++) { + address validator = validators[i]; + if (!maintenanceStatus[validator]) { + activeValidators[index] = validator; + index++; + } + } + + return activeValidators; + } + + /// @notice Returns the full registered validator set. + /// @dev Includes validators currently in maintenance. + /// @return All registered validator addresses in registration order. + function getAllValidators() external view returns (address[] memory) { + address[] memory allValidators = new address[](validators.length); + for (uint256 i = 0; i < validators.length; i++) { + allValidators[i] = validators[i]; + } + return allValidators; + } + + /// @notice Checks whether an address is a registered validator. + /// @param validator Address to check. + /// @return True if the address is registered as a validator. + function isValidator(address validator) external view returns (bool) { + return validatorStatus[validator]; + } + + /// @notice Checks whether a validator is currently in maintenance. + /// @param validator Address to check. + /// @return True if the address is flagged as in maintenance. + function isInMaintenance(address validator) external view returns (bool) { + return maintenanceStatus[validator]; + } + + /// @notice Returns the tolerated Byzantine fault count `f`. + /// @dev Calculated from the full registered validator count as `(N - 1) / 3`. + /// @return Number of faulty validators tolerated by the current registered set size. + function faultTolerance() public view returns (uint256) { + return (validators.length - 1) / 3; + } + + /// @notice Returns the validator governance quorum. + /// @dev Uses the QBFT-style threshold `2f + 1`, where `f` is based on registered validators. + /// @return Number of votes required to execute add/remove proposals. + function quorumSize() public view returns (uint256) { + return (2 * faultTolerance()) + 1; + } + + /// @notice Returns the number of validators currently in maintenance. + /// @return Current maintenance validator count. + function maintenanceSize() external view returns (uint256) { + return maintenanceCount; + } + + /// @notice Computes the proposal ID for a validator set operation. + /// @dev The same operation/candidate pair maps to the same proposal for all voters. + /// @param operation Validator set operation type. + /// @param candidate Candidate address proposed for addition or removal. + /// @return Unique proposal ID. + function proposalId(Operation operation, address candidate) public pure returns (bytes32) { + return keccak256(abi.encodePacked(operation, candidate)); + } + + /// @notice Returns the number of votes recorded for a proposal. + /// @param operation Validator set operation type. + /// @param candidate Candidate address proposed for addition or removal. + /// @return Number of votes recorded for the proposal. + function proposalVotes(Operation operation, address candidate) external view returns (uint256) { + return proposals[proposalId(operation, candidate)].votes; + } + + /// @notice Checks whether a proposal has already executed. + /// @param operation Validator set operation type. + /// @param candidate Candidate address proposed for addition or removal. + /// @return True if the proposal reached quorum and executed. + function proposalExecuted(Operation operation, address candidate) external view returns (bool) { + return proposals[proposalId(operation, candidate)].executed; + } + + /// @notice Checks whether a validator has voted for a proposal. + /// @param operation Validator set operation type. + /// @param candidate Candidate address proposed for addition or removal. + /// @param voter Validator address to check. + /// @return True if `voter` has already voted for the proposal. + function hasVoted(Operation operation, address candidate, address voter) external view returns (bool) { + return proposals[proposalId(operation, candidate)].voted[voter]; + } + + /// @notice Votes to add a new validator. + /// @dev + /// Only registered validators may vote. The candidate must not already be a validator. + /// When the proposal reaches `quorumSize()`, the candidate is added immediately. + /// @param candidate Address proposed as a new validator. + function voteAddValidator(address candidate) external onlyValidator { + require(candidate != address(0), "ValidatorSet: zero candidate"); + require(!validatorStatus[candidate], "ValidatorSet: candidate is validator"); + + _vote(Operation.Add, candidate); + } + + /// @notice Votes to remove an existing validator. + /// @dev + /// Only registered validators may vote. The candidate must currently be registered. + /// When the proposal reaches `quorumSize()`, the candidate is removed immediately. + /// If the candidate is in maintenance, the maintenance count is decremented as part of removal. + /// @param candidate Existing validator proposed for removal. + function voteRemoveValidator(address candidate) external onlyValidator { + require(validatorStatus[candidate], "ValidatorSet: candidate is not validator"); + require(validators.length > 1, "ValidatorSet: cannot remove last validator"); + + _vote(Operation.Remove, candidate); + } + + /// @notice Puts the caller into maintenance mode. + /// @dev + /// Maintenance mode excludes the caller from `getValidators()` but does not remove + /// governance voting rights. At most `faultTolerance()` validators may be in + /// maintenance at the same time. + function enterMaintenance() external onlyValidator { + require(!maintenanceStatus[msg.sender], "ValidatorSet: already in maintenance"); + require(maintenanceCount < faultTolerance(), "ValidatorSet: too many validators in maintenance"); + + maintenanceStatus[msg.sender] = true; + maintenanceCount++; + + emit MaintenanceEntered(msg.sender); + } + + /// @notice Removes the caller from maintenance mode. + /// @dev The caller becomes visible through `getValidators()` again after this call. + function exitMaintenance() external onlyValidator { + require(maintenanceStatus[msg.sender], "ValidatorSet: not in maintenance"); + + maintenanceStatus[msg.sender] = false; + maintenanceCount--; + + emit MaintenanceExited(msg.sender); + } + + /// @dev Records a validator vote and executes the proposal immediately once quorum is reached. + /// Reverts if the proposal already executed or the caller already voted for it. + function _vote(Operation operation, address candidate) private { + bytes32 id = proposalId(operation, candidate); + Proposal storage proposal = proposals[id]; + require(!proposal.executed, "ValidatorSet: proposal executed"); + require(!proposal.voted[msg.sender], "ValidatorSet: already voted"); + + proposal.voted[msg.sender] = true; + proposal.votes++; + + uint256 quorum = quorumSize(); + emit ValidatorVote(id, operation, candidate, msg.sender, proposal.votes, quorum); + + if (proposal.votes >= quorum) { + proposal.executed = true; + if (operation == Operation.Add) { + _addValidator(candidate); + emit ValidatorAdded(candidate); + } else { + _removeValidator(candidate); + emit ValidatorRemoved(candidate); + } + } + } + + /// @dev Adds a validator to the registered set and preserves registration order. + /// Reverts on zero address or duplicate registration. + function _addValidator(address validator) private { + require(validator != address(0), "ValidatorSet: zero validator"); + require(!validatorStatus[validator], "ValidatorSet: duplicate validator"); + + validatorStatus[validator] = true; + validatorIndexes[validator] = validators.length; + validators.push(validator); + } + + /// @dev Removes a validator from the registered set while preserving the order of remaining validators. + /// Clears maintenance state first so `maintenanceCount` remains consistent. + function _removeValidator(address validator) private { + require(validatorStatus[validator], "ValidatorSet: validator not found"); + + if (maintenanceStatus[validator]) { + maintenanceStatus[validator] = false; + maintenanceCount--; + } + + uint256 index = validatorIndexes[validator]; + for (uint256 i = index; i < validators.length - 1; i++) { + address nextValidator = validators[i + 1]; + validators[i] = nextValidator; + validatorIndexes[nextValidator] = i; + } + + validators.pop(); + delete validatorIndexes[validator]; + delete validatorStatus[validator]; + } +} diff --git a/contracts/validatorcontract/validator.go b/contracts/validatorcontract/validator.go new file mode 100644 index 000000000..052a735ac --- /dev/null +++ b/contracts/validatorcontract/validator.go @@ -0,0 +1,51 @@ +// Copyright 2026 BOOSTRY Co., Ltd. +// This file is part of ibet-Core. +// +// ibet-Core is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ibet-Core is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with ibet-Core. If not, see . + +// Package validatorcontract is an on-chain validator set contract wrapper. +package validatorcontract + +//go:generate abigen --sol contract/validator_set.sol --pkg contract --out contract/validator_set.go + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/contracts/validatorcontract/contract" +) + +// ValidatorSet is a Go wrapper around an on-chain validator set contract. +type ValidatorSet struct { + address common.Address + contract *contract.ValidatorSet +} + +// NewValidatorSet binds validator set contract and returns a wrapper instance. +func NewValidatorSet(contractAddr common.Address, backend bind.ContractBackend) (*ValidatorSet, error) { + c, err := contract.NewValidatorSet(contractAddr, backend) + if err != nil { + return nil, err + } + return &ValidatorSet{address: contractAddr, contract: c}, nil +} + +// ContractAddr returns the address of contract. +func (set *ValidatorSet) ContractAddr() common.Address { + return set.address +} + +// Contract returns the underlying contract instance. +func (set *ValidatorSet) Contract() *contract.ValidatorSet { + return set.contract +} diff --git a/contracts/validatorcontract/validator_test.go b/contracts/validatorcontract/validator_test.go new file mode 100644 index 000000000..445537047 --- /dev/null +++ b/contracts/validatorcontract/validator_test.go @@ -0,0 +1,443 @@ +// Copyright 2026 BOOSTRY Co., Ltd. +// This file is part of ibet-Core. +// +// ibet-Core is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ibet-Core is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with ibet-Core. If not, see . + +package validatorcontract + +import ( + "context" + "crypto/ecdsa" + "math/big" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/contracts/validatorcontract/contract" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" +) + +const ( + operationAdd uint8 = 0 + operationRemove uint8 = 1 +) + +var validatorContractChainID = big.NewInt(1337) + +type testAccount struct { + key *ecdsa.PrivateKey + addr common.Address +} + +func newTestAccount(t *testing.T) testAccount { + t.Helper() + + key, err := crypto.GenerateKey() + if err != nil { + t.Fatalf("failed to generate key: %v", err) + } + return testAccount{ + key: key, + addr: crypto.PubkeyToAddress(key.PublicKey), + } +} + +func newTestAuth(t *testing.T, account testAccount) *bind.TransactOpts { + t.Helper() + + auth, err := bind.NewKeyedTransactorWithChainID(account.key, validatorContractChainID) + if err != nil { + t.Fatalf("failed to create transactor: %v", err) + } + return auth +} + +func deployValidatorSet(t *testing.T) (*backends.SimulatedBackend, *contract.ValidatorSet, []testAccount) { + t.Helper() + + accounts := make([]testAccount, 6) + alloc := make(core.GenesisAlloc) + for i := range accounts { + accounts[i] = newTestAccount(t) + alloc[accounts[i].addr] = core.GenesisAccount{Balance: big.NewInt(1000000000000000000)} + } + + backend := backends.NewSimulatedBackend(alloc, 10000000) + initialValidators := []common.Address{ + accounts[0].addr, + accounts[1].addr, + accounts[2].addr, + accounts[3].addr, + } + _, _, validatorSet, err := contract.DeployValidatorSet(newTestAuth(t, accounts[0]), backend, initialValidators) + if err != nil { + backend.Close() + t.Fatalf("failed to deploy validator set: %v", err) + } + backend.Commit() + + return backend, validatorSet, accounts +} + +func deployValidatorSetWithValidators(t *testing.T, validators []common.Address) (*backends.SimulatedBackend, *types.Transaction, error) { + t.Helper() + + deployer := newTestAccount(t) + alloc := core.GenesisAlloc{deployer.addr: core.GenesisAccount{Balance: big.NewInt(1000000000000000000)}} + for _, validator := range validators { + alloc[validator] = core.GenesisAccount{Balance: big.NewInt(1000000000000000000)} + } + backend := backends.NewSimulatedBackend(alloc, 10000000) + + _, tx, _, err := contract.DeployValidatorSet(newTestAuth(t, deployer), backend, validators) + return backend, tx, err +} + +func mustTransact(t *testing.T, backend *backends.SimulatedBackend, transact func() (*types.Transaction, error)) { + t.Helper() + + tx, err := transact() + if err != nil { + t.Fatalf("transaction failed before mining: %v", err) + } + backend.Commit() + receipt, err := backend.TransactionReceipt(context.Background(), tx.Hash()) + if err != nil { + t.Fatalf("failed to fetch transaction receipt: %v", err) + } + if receipt.Status != types.ReceiptStatusSuccessful { + t.Fatalf("transaction reverted: %s", tx.Hash()) + } +} + +func mustReject(t *testing.T, backend *backends.SimulatedBackend, transact func() (*types.Transaction, error)) { + t.Helper() + + tx, err := transact() + if err != nil { + return + } + backend.Commit() + receipt, err := backend.TransactionReceipt(context.Background(), tx.Hash()) + if err != nil { + t.Fatalf("failed to fetch transaction receipt: %v", err) + } + if receipt.Status != types.ReceiptStatusFailed { + t.Fatalf("transaction unexpectedly succeeded: %s", tx.Hash()) + } +} + +func assertAddresses(t *testing.T, got []common.Address, want []common.Address) { + t.Helper() + + if !reflect.DeepEqual(got, want) { + t.Fatalf("validator mismatch\n got: %v\nwant: %v", got, want) + } +} + +func TestValidatorSetInitialState(t *testing.T) { + // Viewpoint: a freshly deployed 4-validator set exposes the same active/full validator list and derives f=1, quorum=3. + backend, validatorSet, accounts := deployValidatorSet(t) + defer backend.Close() + + wantValidators := []common.Address{accounts[0].addr, accounts[1].addr, accounts[2].addr, accounts[3].addr} + activeValidators, err := validatorSet.GetValidators(nil) + if err != nil { + t.Fatalf("failed to get validators: %v", err) + } + assertAddresses(t, activeValidators, wantValidators) + + allValidators, err := validatorSet.GetAllValidators(nil) + if err != nil { + t.Fatalf("failed to get all validators: %v", err) + } + assertAddresses(t, allValidators, wantValidators) + + f, err := validatorSet.FaultTolerance(nil) + if err != nil { + t.Fatalf("failed to get fault tolerance: %v", err) + } + if f.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("unexpected fault tolerance: %s", f) + } + + quorum, err := validatorSet.QuorumSize(nil) + if err != nil { + t.Fatalf("failed to get quorum size: %v", err) + } + if quorum.Cmp(big.NewInt(3)) != 0 { + t.Fatalf("unexpected quorum size: %s", quorum) + } +} + +func TestValidatorSetRejectsInvalidInitialValidators(t *testing.T) { + // Viewpoint: constructor validation rejects empty, zero-address, and duplicate initial validator lists. + for _, tt := range []struct { + name string + validators func() []common.Address + }{ + { + name: "empty", + validators: func() []common.Address { + return nil + }, + }, + { + name: "zero address", + validators: func() []common.Address { + return []common.Address{newTestAccount(t).addr, common.Address{}} + }, + }, + { + name: "duplicate", + validators: func() []common.Address { + account := newTestAccount(t) + return []common.Address{account.addr, account.addr} + }, + }, + } { + t.Run(tt.name, func(t *testing.T) { + backend, tx, err := deployValidatorSetWithValidators(t, tt.validators()) + defer backend.Close() + if err != nil { + return + } + backend.Commit() + receipt, err := backend.TransactionReceipt(context.Background(), tx.Hash()) + if err != nil { + t.Fatalf("failed to fetch deploy receipt: %v", err) + } + if receipt.Status != types.ReceiptStatusFailed { + t.Fatalf("invalid validator deployment unexpectedly succeeded: %s", tx.Hash()) + } + }) + } +} + +func TestValidatorSetAddAndRemoveByQuorum(t *testing.T) { + // Viewpoint: add/remove proposals do not execute before quorum and execute immediately when the third vote reaches 2f+1. + backend, validatorSet, accounts := deployValidatorSet(t) + defer backend.Close() + + candidate := accounts[4].addr + // Two votes are recorded for the add proposal, but the candidate is not registered yet. + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteAddValidator(newTestAuth(t, accounts[0]), candidate) + }) + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteAddValidator(newTestAuth(t, accounts[1]), candidate) + }) + + isValidator, err := validatorSet.IsValidator(nil, candidate) + if err != nil { + t.Fatalf("failed to check candidate before quorum: %v", err) + } + if isValidator { + t.Fatal("candidate became validator before quorum") + } + votes, err := validatorSet.ProposalVotes(nil, operationAdd, candidate) + if err != nil { + t.Fatalf("failed to get add proposal votes: %v", err) + } + if votes.Cmp(big.NewInt(2)) != 0 { + t.Fatalf("unexpected add proposal votes: %s", votes) + } + + // The third vote reaches quorum and appends the candidate to the registered validator list. + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteAddValidator(newTestAuth(t, accounts[2]), candidate) + }) + isValidator, err = validatorSet.IsValidator(nil, candidate) + if err != nil { + t.Fatalf("failed to check candidate after quorum: %v", err) + } + if !isValidator { + t.Fatal("candidate did not become validator after quorum") + } + + allValidators, err := validatorSet.GetAllValidators(nil) + if err != nil { + t.Fatalf("failed to get all validators after add: %v", err) + } + assertAddresses(t, allValidators, []common.Address{accounts[0].addr, accounts[1].addr, accounts[2].addr, accounts[3].addr, candidate}) + + // Two votes are recorded for the remove proposal, but the candidate remains registered. + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteRemoveValidator(newTestAuth(t, accounts[0]), candidate) + }) + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteRemoveValidator(newTestAuth(t, accounts[1]), candidate) + }) + isValidator, err = validatorSet.IsValidator(nil, candidate) + if err != nil { + t.Fatalf("failed to check removal candidate before quorum: %v", err) + } + if !isValidator { + t.Fatal("candidate was removed before quorum") + } + + // The third remove vote reaches quorum and removes the candidate while preserving remaining validator order. + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteRemoveValidator(newTestAuth(t, accounts[2]), candidate) + }) + isValidator, err = validatorSet.IsValidator(nil, candidate) + if err != nil { + t.Fatalf("failed to check removal candidate after quorum: %v", err) + } + if isValidator { + t.Fatal("candidate was not removed after quorum") + } + + allValidators, err = validatorSet.GetAllValidators(nil) + if err != nil { + t.Fatalf("failed to get all validators after remove: %v", err) + } + assertAddresses(t, allValidators, []common.Address{accounts[0].addr, accounts[1].addr, accounts[2].addr, accounts[3].addr}) +} + +func TestValidatorSetRejectsInvalidVotes(t *testing.T) { + // Viewpoint: + // Governance votes must come from validators, target valid candidates, + // and be counted at most once per validator. + + backend, validatorSet, accounts := deployValidatorSet(t) + defer backend.Close() + + candidate := accounts[4].addr + // A zero-address add candidate and a non-validator voter are both invalid. + mustReject(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteAddValidator(newTestAuth(t, accounts[0]), common.Address{}) + }) + mustReject(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteAddValidator(newTestAuth(t, accounts[5]), candidate) + }) + + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteAddValidator(newTestAuth(t, accounts[0]), candidate) + }) + // The same validator cannot vote twice for the same operation/candidate proposal. + mustReject(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteAddValidator(newTestAuth(t, accounts[0]), candidate) + }) + + hasVoted, err := validatorSet.HasVoted(nil, operationAdd, candidate, accounts[0].addr) + if err != nil { + t.Fatalf("failed to check vote status: %v", err) + } + if !hasVoted { + t.Fatal("expected validator vote to be recorded") + } +} + +func TestValidatorSetMaintenance(t *testing.T) { + // Viewpoint: + // Maintenance excludes only the caller from active validators, + // enforces the f-validator cap, and restores the active set on exit. + + backend, validatorSet, accounts := deployValidatorSet(t) + defer backend.Close() + + // With 4 registered validators, f=1, so the first validator may enter maintenance. + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.EnterMaintenance(newTestAuth(t, accounts[0])) + }) + + activeValidators, err := validatorSet.GetValidators(nil) + if err != nil { + t.Fatalf("failed to get active validators in maintenance: %v", err) + } + assertAddresses(t, activeValidators, []common.Address{accounts[1].addr, accounts[2].addr, accounts[3].addr}) + + maintenanceSize, err := validatorSet.MaintenanceSize(nil) + if err != nil { + t.Fatalf("failed to get maintenance size: %v", err) + } + if maintenanceSize.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("unexpected maintenance size: %s", maintenanceSize) + } + + inMaintenance, err := validatorSet.IsInMaintenance(nil, accounts[0].addr) + if err != nil { + t.Fatalf("failed to get maintenance flag: %v", err) + } + if !inMaintenance { + t.Fatal("validator is not marked in maintenance") + } + + // A second simultaneous maintenance entry exceeds f, and non-validators cannot enter maintenance. + mustReject(t, backend, func() (*types.Transaction, error) { + return validatorSet.EnterMaintenance(newTestAuth(t, accounts[1])) + }) + mustReject(t, backend, func() (*types.Transaction, error) { + return validatorSet.EnterMaintenance(newTestAuth(t, accounts[5])) + }) + + // Exiting maintenance returns the validator to the active list in its original order. + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.ExitMaintenance(newTestAuth(t, accounts[0])) + }) + activeValidators, err = validatorSet.GetValidators(nil) + if err != nil { + t.Fatalf("failed to get active validators after maintenance exit: %v", err) + } + assertAddresses(t, activeValidators, []common.Address{accounts[0].addr, accounts[1].addr, accounts[2].addr, accounts[3].addr}) +} + +func TestValidatorSetRemoveValidatorInMaintenance(t *testing.T) { + // Viewpoint: + // Removing a validator currently in maintenance clears its maintenance flag + // and decrements maintenance count. + + backend, validatorSet, accounts := deployValidatorSet(t) + defer backend.Close() + + // The validator remains eligible to vote while in maintenance, and three registered validators can remove it. + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.EnterMaintenance(newTestAuth(t, accounts[0])) + }) + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteRemoveValidator(newTestAuth(t, accounts[0]), accounts[0].addr) + }) + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteRemoveValidator(newTestAuth(t, accounts[1]), accounts[0].addr) + }) + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteRemoveValidator(newTestAuth(t, accounts[2]), accounts[0].addr) + }) + + isValidator, err := validatorSet.IsValidator(nil, accounts[0].addr) + if err != nil { + t.Fatalf("failed to check removed validator: %v", err) + } + if isValidator { + t.Fatal("maintenance validator was not removed") + } + maintenanceSize, err := validatorSet.MaintenanceSize(nil) + if err != nil { + t.Fatalf("failed to get maintenance size after removal: %v", err) + } + if maintenanceSize.Sign() != 0 { + t.Fatalf("maintenance count did not decrement after removal: %s", maintenanceSize) + } + + activeValidators, err := validatorSet.GetValidators(nil) + if err != nil { + t.Fatalf("failed to get validators after maintenance removal: %v", err) + } + assertAddresses(t, activeValidators, []common.Address{accounts[1].addr, accounts[2].addr, accounts[3].addr}) +} From 5f6ed5245c06533e4429b19bc5bb4a0172b65d71 Mon Sep 17 00:00:00 2001 From: Yoshihito Aso Date: Tue, 7 Jul 2026 20:22:50 +0900 Subject: [PATCH 2/4] [skip ci] formatting --- contracts/validatorcontract/validator_test.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/contracts/validatorcontract/validator_test.go b/contracts/validatorcontract/validator_test.go index 445537047..d11fa4214 100644 --- a/contracts/validatorcontract/validator_test.go +++ b/contracts/validatorcontract/validator_test.go @@ -151,7 +151,9 @@ func assertAddresses(t *testing.T, got []common.Address, want []common.Address) } func TestValidatorSetInitialState(t *testing.T) { - // Viewpoint: a freshly deployed 4-validator set exposes the same active/full validator list and derives f=1, quorum=3. + // Viewpoint: + // A freshly deployed 4-validator set exposes the same active/full validator list and derives f=1, quorum=3. + backend, validatorSet, accounts := deployValidatorSet(t) defer backend.Close() @@ -186,7 +188,9 @@ func TestValidatorSetInitialState(t *testing.T) { } func TestValidatorSetRejectsInvalidInitialValidators(t *testing.T) { - // Viewpoint: constructor validation rejects empty, zero-address, and duplicate initial validator lists. + // Viewpoint: + // Constructor validation rejects empty, zero-address, and duplicate initial validator lists. + for _, tt := range []struct { name string validators func() []common.Address @@ -230,7 +234,9 @@ func TestValidatorSetRejectsInvalidInitialValidators(t *testing.T) { } func TestValidatorSetAddAndRemoveByQuorum(t *testing.T) { - // Viewpoint: add/remove proposals do not execute before quorum and execute immediately when the third vote reaches 2f+1. + // Viewpoint: + // Add/Remove proposals do not execute before quorum and execute immediately when the third vote reaches 2f+1. + backend, validatorSet, accounts := deployValidatorSet(t) defer backend.Close() From 66a4da303343f15c00a4bd5d60f1c6c8c0a7fc55 Mon Sep 17 00:00:00 2001 From: Yoshihito Aso Date: Tue, 7 Jul 2026 20:23:37 +0900 Subject: [PATCH 3/4] [skip ci] formatting --- contracts/validatorcontract/validator_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/validatorcontract/validator_test.go b/contracts/validatorcontract/validator_test.go index d11fa4214..feb7347fe 100644 --- a/contracts/validatorcontract/validator_test.go +++ b/contracts/validatorcontract/validator_test.go @@ -151,9 +151,9 @@ func assertAddresses(t *testing.T, got []common.Address, want []common.Address) } func TestValidatorSetInitialState(t *testing.T) { - // Viewpoint: + // Viewpoint: // A freshly deployed 4-validator set exposes the same active/full validator list and derives f=1, quorum=3. - + backend, validatorSet, accounts := deployValidatorSet(t) defer backend.Close() @@ -188,9 +188,9 @@ func TestValidatorSetInitialState(t *testing.T) { } func TestValidatorSetRejectsInvalidInitialValidators(t *testing.T) { - // Viewpoint: + // Viewpoint: // Constructor validation rejects empty, zero-address, and duplicate initial validator lists. - + for _, tt := range []struct { name string validators func() []common.Address @@ -234,9 +234,9 @@ func TestValidatorSetRejectsInvalidInitialValidators(t *testing.T) { } func TestValidatorSetAddAndRemoveByQuorum(t *testing.T) { - // Viewpoint: + // Viewpoint: // Add/Remove proposals do not execute before quorum and execute immediately when the third vote reaches 2f+1. - + backend, validatorSet, accounts := deployValidatorSet(t) defer backend.Close() From c81e588ab2bd4f6a222fd9d62e350392ce0dd945 Mon Sep 17 00:00:00 2001 From: Yoshihito Aso Date: Tue, 7 Jul 2026 21:17:35 +0900 Subject: [PATCH 4/4] Version validator set proposal IDs --- contracts/validatorcontract/README.md | 1 + .../contract/validator_set.go | 72 +++++++++++++++-- .../contract/validator_set.sol | 41 +++++++--- contracts/validatorcontract/validator_test.go | 79 +++++++++++++++++++ 4 files changed, 179 insertions(+), 14 deletions(-) diff --git a/contracts/validatorcontract/README.md b/contracts/validatorcontract/README.md index fbe14265f..fca08dc68 100644 --- a/contracts/validatorcontract/README.md +++ b/contracts/validatorcontract/README.md @@ -78,6 +78,7 @@ This package contains the reference validator set contract used with QBFT contra - Governance quorum is based on all registered validators, not only active validators. - `faultTolerance()` is calculated as `(N - 1) / 3`, where `N` is the number of registered validators. - `quorumSize()` is calculated as `2f + 1`. +- Add/remove proposal IDs include the current validator set version, so the same address can be removed, re-added, and removed again in later versions. - A validator in maintenance still has governance voting power. - At most `f` validators may be in maintenance at the same time. diff --git a/contracts/validatorcontract/contract/validator_set.go b/contracts/validatorcontract/contract/validator_set.go index 45e11d85e..c8b67686f 100644 --- a/contracts/validatorcontract/contract/validator_set.go +++ b/contracts/validatorcontract/contract/validator_set.go @@ -27,12 +27,12 @@ var ( ) // ValidatorSetABI is the input ABI used to generate the binding from. -const ValidatorSetABI = "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"initialValidators\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"enterMaintenance\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"exitMaintenance\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"faultTolerance\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllValidators\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getValidators\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hasVoted\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"voter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isInMaintenance\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isValidator\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maintenanceSize\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalExecuted\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalId\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"proposalVotes\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quorumSize\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"voteAddValidator\",\"inputs\":[{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"voteRemoveValidator\",\"inputs\":[{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"MaintenanceEntered\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaintenanceExited\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorAdded\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorRemoved\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorVote\",\"inputs\":[{\"name\":\"proposalId\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"operation\",\"type\":\"uint8\",\"indexed\":true,\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"voter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"votes\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"quorum\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]" +const ValidatorSetABI = "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"initialValidators\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"enterMaintenance\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"exitMaintenance\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"faultTolerance\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllValidators\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getValidators\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hasVoted\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"voter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isInMaintenance\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isValidator\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maintenanceSize\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalExecuted\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalId\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalIdAtVersion\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"versionNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"proposalVotes\",\"inputs\":[{\"name\":\"operation\",\"type\":\"uint8\",\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quorumSize\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"voteAddValidator\",\"inputs\":[{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"voteRemoveValidator\",\"inputs\":[{\"name\":\"candidate\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"MaintenanceEntered\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaintenanceExited\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorAdded\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorRemoved\",\"inputs\":[{\"name\":\"validator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorVote\",\"inputs\":[{\"name\":\"proposalId\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"operation\",\"type\":\"uint8\",\"indexed\":true,\"internalType\":\"enumValidatorSet.Operation\"},{\"name\":\"candidate\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"voter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"votes\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"quorum\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]" var ValidatorSetParsedABI, _ = abi.JSON(strings.NewReader(ValidatorSetABI)) // ValidatorSetBin is the compiled bytecode used for deploying new contracts. -var ValidatorSetBin = "0x608060405234801561001057600080fd5b50604051612ac3380380612ac38339818101604052810190610032919061048c565b6000815111610076576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161006d90610532565b60405180910390fd5b60005b81518110156100b8576100ab82828151811061009857610097610552565b5b60200260200101516100bf60201b60201c565b8080600101915050610079565b505061067f565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361012e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610125906105cd565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156101bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101b29061065f565b60405180910390fd5b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600080549050600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610323826102da565b810181811067ffffffffffffffff82111715610342576103416102eb565b5b80604052505050565b60006103556102c1565b9050610361828261031a565b919050565b600067ffffffffffffffff821115610381576103806102eb565b5b602082029050602081019050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103c282610397565b9050919050565b6103d2816103b7565b81146103dd57600080fd5b50565b6000815190506103ef816103c9565b92915050565b600061040861040384610366565b61034b565b9050808382526020820190506020840283018581111561042b5761042a610392565b5b835b81811015610454578061044088826103e0565b84526020840193505060208101905061042d565b5050509392505050565b600082601f830112610473576104726102d5565b5b81516104838482602086016103f5565b91505092915050565b6000602082840312156104a2576104a16102cb565b5b600082015167ffffffffffffffff8111156104c0576104bf6102d0565b5b6104cc8482850161045e565b91505092915050565b600082825260208201905092915050565b7f56616c696461746f725365743a20656d7074792076616c696461746f72730000600082015250565b600061051c601e836104d5565b9150610527826104e6565b602082019050919050565b6000602082019050818103600083015261054b8161050f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f56616c696461746f725365743a207a65726f2076616c696461746f7200000000600082015250565b60006105b7601c836104d5565b91506105c282610581565b602082019050919050565b600060208201905081810360008301526105e6816105aa565b9050919050565b7f56616c696461746f725365743a206475706c69636174652076616c696461746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b60006106496021836104d5565b9150610654826105ed565b604082019050919050565b600060208201905081810360008301526106788161063c565b9050919050565b6124358061068e6000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80639bf6a74a11610097578063e6c166e311610066578063e6c166e31461024e578063eac942a91461027e578063f3513a37146102ae578063facd743b146102cc576100f5565b80639bf6a74a146101b4578063a8b4b210146101d0578063b7ab4db514610200578063dfa45bdd1461021e576100f5565b806357456f22116100d357806357456f22146101405780635e401b3e1461015c57806375b76f1c1461018c5780639369d7de146101aa576100f5565b806304c4fec6146100fa57806322e28369146101045780633068ef4d14610122575b600080fd5b6101026102fc565b005b61010c6104c9565b6040516101199190611706565b60405180910390f35b61012a6104d3565b6040516101379190611706565b60405180910390f35b61015a60048036038101906101559190611784565b6104fa565b005b610176600480360381019061017191906117d6565b610690565b6040516101839190611844565b60405180910390f35b610194610705565b6040516101a19190611706565b60405180910390f35b6101b261072a565b005b6101ce60048036038101906101c99190611784565b610943565b005b6101ea60048036038101906101e5919061185f565b610ab1565b6040516101f791906118b8565b60405180910390f35b610208610ae4565b6040516102159190611991565b60405180910390f35b61023860048036038101906102339190611784565b610c63565b6040516102459190611844565b60405180910390f35b6102686004803603810190610263919061185f565b610cb9565b6040516102759190611706565b60405180910390f35b6102986004803603810190610293919061185f565b610ce3565b6040516102a59190611844565b60405180910390f35b6102b6610d1a565b6040516102c39190611991565b60405180910390f35b6102e660048036038101906102e19190611784565b610e1e565b6040516102f39190611844565b60405180910390f35b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610388576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161037f90611a36565b60405180910390fd5b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610414576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161040b90611aa2565b60405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506004600081548092919061047f90611af1565b91905055503373ffffffffffffffffffffffffffffffffffffffff167f0203ae0082a4b3f0b71e461ab5245258799bdb5d52d0f224a6aaed75deca688960405160405180910390a2565b6000600454905090565b600060016104df610705565b60026104eb9190611b1a565b6104f59190611b5c565b905090565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610586576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161057d90611a36565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036105f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ec90611bdc565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610682576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161067990611c6e565b60405180910390fd5b61068d600082610e74565b50565b6000600560006106a08686610ab1565b815260200190815260200160002060020160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1690509392505050565b60006003600160008054905061071b9190611c8e565b6107259190611cf1565b905090565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166107b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107ad90611a36565b60405180910390fd5b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610843576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161083a90611d94565b60405180910390fd5b61084b610705565b6004541061088e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161088590611e26565b60405180910390fd5b6001600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600460008154809291906108f990611e46565b91905055503373ffffffffffffffffffffffffffffffffffffffff167f44aa86acf916265e97ff989ab2c2289b9f442a5a4769121a3c82d3daf7ea972b60405160405180910390a2565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166109cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c690611a36565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610a5b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5290611f00565b60405180910390fd5b600160008054905011610aa3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9a90611f92565b60405180910390fd5b610aae600182610e74565b50565b60008282604051602001610ac6929190612098565b60405160208183030381529060405280519060200120905092915050565b60606000600454600080549050610afb9190611c8e565b905060008167ffffffffffffffff811115610b1957610b186120c4565b5b604051908082528060200260200182016040528015610b475781602001602082028036833780820191505090505b5090506000805b600080549050811015610c59576000808281548110610b7057610b6f6120f3565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610c4b5780848481518110610c0257610c016120f3565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508280610c4790611e46565b9350505b508080600101915050610b4e565b5081935050505090565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600060056000610cc98585610ab1565b815260200190815260200160002060000154905092915050565b600060056000610cf38585610ab1565b815260200190815260200160002060010160009054906101000a900460ff16905092915050565b60606000808054905067ffffffffffffffff811115610d3c57610d3b6120c4565b5b604051908082528060200260200182016040528015610d6a5781602001602082028036833780820191505090505b50905060005b600080549050811015610e165760008181548110610d9157610d906120f3565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110610dcf57610dce6120f3565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508080600101915050610d70565b508091505090565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000610e808383610ab1565b905060006005600083815260200190815260200160002090508060010160009054906101000a900460ff1615610eeb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ee29061216e565b60405180910390fd5b8060020160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610f7a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f71906121da565b60405180910390fd5b60018160020160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550806000016000815480929190610fe990611e46565b91905055506000610ff86104d3565b90508373ffffffffffffffffffffffffffffffffffffffff1685600181111561102457611023611fb2565b5b847f88de5c1b4216be3907eda6a00c98004ce4a2076ccd207f384d40e92d288fdab63386600001548660405161105c93929190612209565b60405180910390a4808260000154106111575760018260010160006101000a81548160ff021916908315150217905550600060018111156110a05761109f611fb2565b5b8560018111156110b3576110b2611fb2565b5b03611109576110c18461115e565b8373ffffffffffffffffffffffffffffffffffffffff167fe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec388498760405160405180910390a2611156565b61111284611360565b8373ffffffffffffffffffffffffffffffffffffffff167fe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f160405160405180910390a25b5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036111cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111c49061228c565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561125a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112519061231e565b60405180910390fd5b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600080549050600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166113ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113e3906123b0565b60405180910390fd5b600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156114af576000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600460008154809291906114a990611af1565b91905055505b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060008190505b600160008054905061150b9190611c8e565b81101561160f576000806001836115229190611b5c565b81548110611533576115326120f3565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508060008381548110611575576115746120f3565b5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505080806001019150506114f9565b506000805480611622576116216123d0565b5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690559055600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81549060ff02191690555050565b6000819050919050565b611700816116ed565b82525050565b600060208201905061171b60008301846116f7565b92915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061175182611726565b9050919050565b61176181611746565b811461176c57600080fd5b50565b60008135905061177e81611758565b92915050565b60006020828403121561179a57611799611721565b5b60006117a88482850161176f565b91505092915050565b600281106117be57600080fd5b50565b6000813590506117d0816117b1565b92915050565b6000806000606084860312156117ef576117ee611721565b5b60006117fd868287016117c1565b935050602061180e8682870161176f565b925050604061181f8682870161176f565b9150509250925092565b60008115159050919050565b61183e81611829565b82525050565b60006020820190506118596000830184611835565b92915050565b6000806040838503121561187657611875611721565b5b6000611884858286016117c1565b92505060206118958582860161176f565b9150509250929050565b6000819050919050565b6118b28161189f565b82525050565b60006020820190506118cd60008301846118a9565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61190881611746565b82525050565b600061191a83836118ff565b60208301905092915050565b6000602082019050919050565b600061193e826118d3565b61194881856118de565b9350611953836118ef565b8060005b8381101561198457815161196b888261190e565b975061197683611926565b925050600181019050611957565b5085935050505092915050565b600060208201905081810360008301526119ab8184611933565b905092915050565b600082825260208201905092915050565b7f56616c696461746f725365743a2073656e646572206973206e6f742076616c6960008201527f6461746f72000000000000000000000000000000000000000000000000000000602082015250565b6000611a206025836119b3565b9150611a2b826119c4565b604082019050919050565b60006020820190508181036000830152611a4f81611a13565b9050919050565b7f56616c696461746f725365743a206e6f7420696e206d61696e74656e616e6365600082015250565b6000611a8c6020836119b3565b9150611a9782611a56565b602082019050919050565b60006020820190508181036000830152611abb81611a7f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611afc826116ed565b915060008203611b0f57611b0e611ac2565b5b600182039050919050565b6000611b25826116ed565b9150611b30836116ed565b9250828202611b3e816116ed565b91508282048414831517611b5557611b54611ac2565b5b5092915050565b6000611b67826116ed565b9150611b72836116ed565b9250828201905080821115611b8a57611b89611ac2565b5b92915050565b7f56616c696461746f725365743a207a65726f2063616e64696461746500000000600082015250565b6000611bc6601c836119b3565b9150611bd182611b90565b602082019050919050565b60006020820190508181036000830152611bf581611bb9565b9050919050565b7f56616c696461746f725365743a2063616e6469646174652069732076616c696460008201527f61746f7200000000000000000000000000000000000000000000000000000000602082015250565b6000611c586024836119b3565b9150611c6382611bfc565b604082019050919050565b60006020820190508181036000830152611c8781611c4b565b9050919050565b6000611c99826116ed565b9150611ca4836116ed565b9250828203905081811115611cbc57611cbb611ac2565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000611cfc826116ed565b9150611d07836116ed565b925082611d1757611d16611cc2565b5b828204905092915050565b7f56616c696461746f725365743a20616c726561647920696e206d61696e74656e60008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000611d7e6024836119b3565b9150611d8982611d22565b604082019050919050565b60006020820190508181036000830152611dad81611d71565b9050919050565b7f56616c696461746f725365743a20746f6f206d616e792076616c696461746f7260008201527f7320696e206d61696e74656e616e636500000000000000000000000000000000602082015250565b6000611e106030836119b3565b9150611e1b82611db4565b604082019050919050565b60006020820190508181036000830152611e3f81611e03565b9050919050565b6000611e51826116ed565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e8357611e82611ac2565b5b600182019050919050565b7f56616c696461746f725365743a2063616e646964617465206973206e6f74207660008201527f616c696461746f72000000000000000000000000000000000000000000000000602082015250565b6000611eea6028836119b3565b9150611ef582611e8e565b604082019050919050565b60006020820190508181036000830152611f1981611edd565b9050919050565b7f56616c696461746f725365743a2063616e6e6f742072656d6f7665206c61737460008201527f2076616c696461746f7200000000000000000000000000000000000000000000602082015250565b6000611f7c602a836119b3565b9150611f8782611f20565b604082019050919050565b60006020820190508181036000830152611fab81611f6f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60028110611ff257611ff1611fb2565b5b50565b600081905061200382611fe1565b919050565b600061201382611ff5565b9050919050565b60008160f81b9050919050565b60006120328261201a565b9050919050565b61204a61204582612008565b612027565b82525050565b60008160601b9050919050565b600061206882612050565b9050919050565b600061207a8261205d565b9050919050565b61209261208d82611746565b61206f565b82525050565b60006120a48285612039565b6001820191506120b48284612081565b6014820191508190509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f56616c696461746f725365743a2070726f706f73616c20657865637574656400600082015250565b6000612158601f836119b3565b915061216382612122565b602082019050919050565b600060208201905081810360008301526121878161214b565b9050919050565b7f56616c696461746f725365743a20616c726561647920766f7465640000000000600082015250565b60006121c4601b836119b3565b91506121cf8261218e565b602082019050919050565b600060208201905081810360008301526121f3816121b7565b9050919050565b61220381611746565b82525050565b600060608201905061221e60008301866121fa565b61222b60208301856116f7565b61223860408301846116f7565b949350505050565b7f56616c696461746f725365743a207a65726f2076616c696461746f7200000000600082015250565b6000612276601c836119b3565b915061228182612240565b602082019050919050565b600060208201905081810360008301526122a581612269565b9050919050565b7f56616c696461746f725365743a206475706c69636174652076616c696461746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b60006123086021836119b3565b9150612313826122ac565b604082019050919050565b60006020820190508181036000830152612337816122fb565b9050919050565b7f56616c696461746f725365743a2076616c696461746f72206e6f7420666f756e60008201527f6400000000000000000000000000000000000000000000000000000000000000602082015250565b600061239a6021836119b3565b91506123a58261233e565b604082019050919050565b600060208201905081810360008301526123c98161238d565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212205b825b33b91a6b548e067adf4c576ee2301f5f03372edcd2dccfc1e17b0231ff64736f6c634300081e0033" +var ValidatorSetBin = "0x608060405234801561001057600080fd5b50604051612c28380380612c288339818101604052810190610032919061048c565b6000815111610076576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161006d90610532565b60405180910390fd5b60005b81518110156100b8576100ab82828151811061009857610097610552565b5b60200260200101516100bf60201b60201c565b8080600101915050610079565b505061067f565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361012e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610125906105cd565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156101bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101b29061065f565b60405180910390fd5b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600080549050600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610323826102da565b810181811067ffffffffffffffff82111715610342576103416102eb565b5b80604052505050565b60006103556102c1565b9050610361828261031a565b919050565b600067ffffffffffffffff821115610381576103806102eb565b5b602082029050602081019050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103c282610397565b9050919050565b6103d2816103b7565b81146103dd57600080fd5b50565b6000815190506103ef816103c9565b92915050565b600061040861040384610366565b61034b565b9050808382526020820190506020840283018581111561042b5761042a610392565b5b835b81811015610454578061044088826103e0565b84526020840193505060208101905061042d565b5050509392505050565b600082601f830112610473576104726102d5565b5b81516104838482602086016103f5565b91505092915050565b6000602082840312156104a2576104a16102cb565b5b600082015167ffffffffffffffff8111156104c0576104bf6102d0565b5b6104cc8482850161045e565b91505092915050565b600082825260208201905092915050565b7f56616c696461746f725365743a20656d7074792076616c696461746f72730000600082015250565b600061051c601e836104d5565b9150610527826104e6565b602082019050919050565b6000602082019050818103600083015261054b8161050f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f56616c696461746f725365743a207a65726f2076616c696461746f7200000000600082015250565b60006105b7601c836104d5565b91506105c282610581565b602082019050919050565b600060208201905081810360008301526105e6816105aa565b9050919050565b7f56616c696461746f725365743a206475706c69636174652076616c696461746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b60006106496021836104d5565b9150610654826105ed565b604082019050919050565b600060208201905081810360008301526106788161063c565b9050919050565b61259a8061068e6000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c80639369d7de116100a2578063dfa45bdd11610071578063dfa45bdd14610282578063e6c166e3146102b2578063eac942a9146102e2578063f3513a3714610312578063facd743b146103305761010b565b80639369d7de1461020e5780639bf6a74a14610218578063a8b4b21014610234578063b7ab4db5146102645761010b565b806357456f22116100de57806357456f221461017457806358753136146101905780635e401b3e146101c057806375b76f1c146101f05761010b565b806304c4fec61461011057806322e283691461011a5780633068ef4d1461013857806354fd4d5014610156575b600080fd5b610118610360565b005b61012261052d565b60405161012f91906117ba565b60405180910390f35b610140610537565b60405161014d91906117ba565b60405180910390f35b61015e61055e565b60405161016b91906117ba565b60405180910390f35b61018e60048036038101906101899190611838565b610568565b005b6101aa60048036038101906101a591906118b6565b6106fe565b6040516101b79190611922565b60405180910390f35b6101da60048036038101906101d5919061193d565b610734565b6040516101e791906119ab565b60405180910390f35b6101f86107a9565b60405161020591906117ba565b60405180910390f35b6102166107ce565b005b610232600480360381019061022d9190611838565b6109e7565b005b61024e600480360381019061024991906119c6565b610b55565b60405161025b9190611922565b60405180910390f35b61026c610b69565b6040516102799190611ac4565b60405180910390f35b61029c60048036038101906102979190611838565b610ce8565b6040516102a991906119ab565b60405180910390f35b6102cc60048036038101906102c791906119c6565b610d3e565b6040516102d991906117ba565b60405180910390f35b6102fc60048036038101906102f791906119c6565b610d68565b60405161030991906119ab565b60405180910390f35b61031a610d9f565b6040516103279190611ac4565b60405180910390f35b61034a60048036038101906103459190611838565b610ea3565b60405161035791906119ab565b60405180910390f35b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166103ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103e390611b69565b60405180910390fd5b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610478576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161046f90611bd5565b60405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600460008154809291906104e390611c24565b91905055503373ffffffffffffffffffffffffffffffffffffffff167f0203ae0082a4b3f0b71e461ab5245258799bdb5d52d0f224a6aaed75deca688960405160405180910390a2565b6000600454905090565b600060016105436107a9565b600261054f9190611c4d565b6105599190611c8f565b905090565b6000600554905090565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166105f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105eb90611b69565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610663576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161065a90611d0f565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156106f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106e790611da1565b60405180910390fd5b6106fb600082610ef9565b50565b600083838360405160200161071593929190611ec8565b6040516020818303038152906040528051906020012090509392505050565b60006006600061074486866111fb565b815260200190815260200160002060020160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1690509392505050565b6000600360016000805490506107bf9190611f05565b6107c99190611f68565b905090565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661085a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161085190611b69565b60405180910390fd5b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156108e7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108de9061200b565b60405180910390fd5b6108ef6107a9565b60045410610932576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109299061209d565b60405180910390fd5b6001600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506004600081548092919061099d906120bd565b91905055503373ffffffffffffffffffffffffffffffffffffffff167f44aa86acf916265e97ff989ab2c2289b9f442a5a4769121a3c82d3daf7ea972b60405160405180910390a2565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610a73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a6a90611b69565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610aff576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af690612177565b60405180910390fd5b600160008054905011610b47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b3e90612209565b60405180910390fd5b610b52600182610ef9565b50565b6000610b6183836111fb565b905092915050565b60606000600454600080549050610b809190611f05565b905060008167ffffffffffffffff811115610b9e57610b9d612229565b5b604051908082528060200260200182016040528015610bcc5781602001602082028036833780820191505090505b5090506000805b600080549050811015610cde576000808281548110610bf557610bf4612258565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610cd05780848481518110610c8757610c86612258565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508280610ccc906120bd565b9350505b508080600101915050610bd3565b5081935050505090565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600060066000610d4e85856111fb565b815260200190815260200160002060000154905092915050565b600060066000610d7885856111fb565b815260200190815260200160002060010160009054906101000a900460ff16905092915050565b60606000808054905067ffffffffffffffff811115610dc157610dc0612229565b5b604051908082528060200260200182016040528015610def5781602001602082028036833780820191505090505b50905060005b600080549050811015610e9b5760008181548110610e1657610e15612258565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110610e5457610e53612258565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508080600101915050610df5565b508091505090565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000610f0583836111fb565b905060006006600083815260200190815260200160002090508060010160009054906101000a900460ff1615610f70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f67906122d3565b60405180910390fd5b8060020160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610fff576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ff69061233f565b60405180910390fd5b60018160020160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555080600001600081548092919061106e906120bd565b9190505550600061107d610537565b90508373ffffffffffffffffffffffffffffffffffffffff168560018111156110a9576110a8611dc1565b5b847f88de5c1b4216be3907eda6a00c98004ce4a2076ccd207f384d40e92d288fdab6338660000154866040516110e19392919061236e565b60405180910390a4808260000154106111f45760018260010160006101000a81548160ff0219169083151502179055506000600181111561112557611124611dc1565b5b85600181111561113857611137611dc1565b5b0361118e5761114684611212565b8373ffffffffffffffffffffffffffffffffffffffff167fe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec388498760405160405180910390a26111db565b61119784611414565b8373ffffffffffffffffffffffffffffffffffffffff167fe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f160405160405180910390a25b600560008154809291906111ee906120bd565b91905055505b5050505050565b600061120a83836005546106fe565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611281576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611278906123f1565b60405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561130e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161130590612483565b60405180910390fd5b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600080549050600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166114a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161149790612515565b60405180910390fd5b600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611563576000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506004600081548092919061155d90611c24565b91905055505b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060008190505b60016000805490506115bf9190611f05565b8110156116c3576000806001836115d69190611c8f565b815481106115e7576115e6612258565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050806000838154811061162957611628612258565b5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505080806001019150506115ad565b5060008054806116d6576116d5612535565b5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690559055600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81549060ff02191690555050565b6000819050919050565b6117b4816117a1565b82525050565b60006020820190506117cf60008301846117ab565b92915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611805826117da565b9050919050565b611815816117fa565b811461182057600080fd5b50565b6000813590506118328161180c565b92915050565b60006020828403121561184e5761184d6117d5565b5b600061185c84828501611823565b91505092915050565b6002811061187257600080fd5b50565b60008135905061188481611865565b92915050565b611893816117a1565b811461189e57600080fd5b50565b6000813590506118b08161188a565b92915050565b6000806000606084860312156118cf576118ce6117d5565b5b60006118dd86828701611875565b93505060206118ee86828701611823565b92505060406118ff868287016118a1565b9150509250925092565b6000819050919050565b61191c81611909565b82525050565b60006020820190506119376000830184611913565b92915050565b600080600060608486031215611956576119556117d5565b5b600061196486828701611875565b935050602061197586828701611823565b925050604061198686828701611823565b9150509250925092565b60008115159050919050565b6119a581611990565b82525050565b60006020820190506119c0600083018461199c565b92915050565b600080604083850312156119dd576119dc6117d5565b5b60006119eb85828601611875565b92505060206119fc85828601611823565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b611a3b816117fa565b82525050565b6000611a4d8383611a32565b60208301905092915050565b6000602082019050919050565b6000611a7182611a06565b611a7b8185611a11565b9350611a8683611a22565b8060005b83811015611ab7578151611a9e8882611a41565b9750611aa983611a59565b925050600181019050611a8a565b5085935050505092915050565b60006020820190508181036000830152611ade8184611a66565b905092915050565b600082825260208201905092915050565b7f56616c696461746f725365743a2073656e646572206973206e6f742076616c6960008201527f6461746f72000000000000000000000000000000000000000000000000000000602082015250565b6000611b53602583611ae6565b9150611b5e82611af7565b604082019050919050565b60006020820190508181036000830152611b8281611b46565b9050919050565b7f56616c696461746f725365743a206e6f7420696e206d61696e74656e616e6365600082015250565b6000611bbf602083611ae6565b9150611bca82611b89565b602082019050919050565b60006020820190508181036000830152611bee81611bb2565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611c2f826117a1565b915060008203611c4257611c41611bf5565b5b600182039050919050565b6000611c58826117a1565b9150611c63836117a1565b9250828202611c71816117a1565b91508282048414831517611c8857611c87611bf5565b5b5092915050565b6000611c9a826117a1565b9150611ca5836117a1565b9250828201905080821115611cbd57611cbc611bf5565b5b92915050565b7f56616c696461746f725365743a207a65726f2063616e64696461746500000000600082015250565b6000611cf9601c83611ae6565b9150611d0482611cc3565b602082019050919050565b60006020820190508181036000830152611d2881611cec565b9050919050565b7f56616c696461746f725365743a2063616e6469646174652069732076616c696460008201527f61746f7200000000000000000000000000000000000000000000000000000000602082015250565b6000611d8b602483611ae6565b9150611d9682611d2f565b604082019050919050565b60006020820190508181036000830152611dba81611d7e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60028110611e0157611e00611dc1565b5b50565b6000819050611e1282611df0565b919050565b6000611e2282611e04565b9050919050565b60008160f81b9050919050565b6000611e4182611e29565b9050919050565b611e59611e5482611e17565b611e36565b82525050565b60008160601b9050919050565b6000611e7782611e5f565b9050919050565b6000611e8982611e6c565b9050919050565b611ea1611e9c826117fa565b611e7e565b82525050565b6000819050919050565b611ec2611ebd826117a1565b611ea7565b82525050565b6000611ed48286611e48565b600182019150611ee48285611e90565b601482019150611ef48284611eb1565b602082019150819050949350505050565b6000611f10826117a1565b9150611f1b836117a1565b9250828203905081811115611f3357611f32611bf5565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000611f73826117a1565b9150611f7e836117a1565b925082611f8e57611f8d611f39565b5b828204905092915050565b7f56616c696461746f725365743a20616c726561647920696e206d61696e74656e60008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000611ff5602483611ae6565b915061200082611f99565b604082019050919050565b6000602082019050818103600083015261202481611fe8565b9050919050565b7f56616c696461746f725365743a20746f6f206d616e792076616c696461746f7260008201527f7320696e206d61696e74656e616e636500000000000000000000000000000000602082015250565b6000612087603083611ae6565b91506120928261202b565b604082019050919050565b600060208201905081810360008301526120b68161207a565b9050919050565b60006120c8826117a1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036120fa576120f9611bf5565b5b600182019050919050565b7f56616c696461746f725365743a2063616e646964617465206973206e6f74207660008201527f616c696461746f72000000000000000000000000000000000000000000000000602082015250565b6000612161602883611ae6565b915061216c82612105565b604082019050919050565b6000602082019050818103600083015261219081612154565b9050919050565b7f56616c696461746f725365743a2063616e6e6f742072656d6f7665206c61737460008201527f2076616c696461746f7200000000000000000000000000000000000000000000602082015250565b60006121f3602a83611ae6565b91506121fe82612197565b604082019050919050565b60006020820190508181036000830152612222816121e6565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f56616c696461746f725365743a2070726f706f73616c20657865637574656400600082015250565b60006122bd601f83611ae6565b91506122c882612287565b602082019050919050565b600060208201905081810360008301526122ec816122b0565b9050919050565b7f56616c696461746f725365743a20616c726561647920766f7465640000000000600082015250565b6000612329601b83611ae6565b9150612334826122f3565b602082019050919050565b600060208201905081810360008301526123588161231c565b9050919050565b612368816117fa565b82525050565b6000606082019050612383600083018661235f565b61239060208301856117ab565b61239d60408301846117ab565b949350505050565b7f56616c696461746f725365743a207a65726f2076616c696461746f7200000000600082015250565b60006123db601c83611ae6565b91506123e6826123a5565b602082019050919050565b6000602082019050818103600083015261240a816123ce565b9050919050565b7f56616c696461746f725365743a206475706c69636174652076616c696461746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b600061246d602183611ae6565b915061247882612411565b604082019050919050565b6000602082019050818103600083015261249c81612460565b9050919050565b7f56616c696461746f725365743a2076616c696461746f72206e6f7420666f756e60008201527f6400000000000000000000000000000000000000000000000000000000000000602082015250565b60006124ff602183611ae6565b915061250a826124a3565b604082019050919050565b6000602082019050818103600083015261252e816124f2565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122010ef9fcd63ea0d158ca96d87736aac0c3ac9911a27cfc09892a45b5805a9eed764736f6c634300081e0033" // DeployValidatorSet deploys a new Ethereum contract, binding an instance of ValidatorSet to it. func DeployValidatorSet(auth *bind.TransactOpts, backend bind.ContractBackend, initialValidators []common.Address) (common.Address, *types.Transaction, *ValidatorSet, error) { @@ -440,7 +440,7 @@ func (_ValidatorSet *ValidatorSetCallerSession) ProposalExecuted(operation uint8 // ProposalId is a free data retrieval call binding the contract method 0xa8b4b210. // -// Solidity: function proposalId(uint8 operation, address candidate) pure returns(bytes32) +// Solidity: function proposalId(uint8 operation, address candidate) view returns(bytes32) func (_ValidatorSet *ValidatorSetCaller) ProposalId(opts *bind.CallOpts, operation uint8, candidate common.Address) ([32]byte, error) { var out []interface{} err := _ValidatorSet.contract.Call(opts, &out, "proposalId", operation, candidate) @@ -457,18 +457,49 @@ func (_ValidatorSet *ValidatorSetCaller) ProposalId(opts *bind.CallOpts, operati // ProposalId is a free data retrieval call binding the contract method 0xa8b4b210. // -// Solidity: function proposalId(uint8 operation, address candidate) pure returns(bytes32) +// Solidity: function proposalId(uint8 operation, address candidate) view returns(bytes32) func (_ValidatorSet *ValidatorSetSession) ProposalId(operation uint8, candidate common.Address) ([32]byte, error) { return _ValidatorSet.Contract.ProposalId(&_ValidatorSet.CallOpts, operation, candidate) } // ProposalId is a free data retrieval call binding the contract method 0xa8b4b210. // -// Solidity: function proposalId(uint8 operation, address candidate) pure returns(bytes32) +// Solidity: function proposalId(uint8 operation, address candidate) view returns(bytes32) func (_ValidatorSet *ValidatorSetCallerSession) ProposalId(operation uint8, candidate common.Address) ([32]byte, error) { return _ValidatorSet.Contract.ProposalId(&_ValidatorSet.CallOpts, operation, candidate) } +// ProposalIdAtVersion is a free data retrieval call binding the contract method 0x58753136. +// +// Solidity: function proposalIdAtVersion(uint8 operation, address candidate, uint256 versionNumber) pure returns(bytes32) +func (_ValidatorSet *ValidatorSetCaller) ProposalIdAtVersion(opts *bind.CallOpts, operation uint8, candidate common.Address, versionNumber *big.Int) ([32]byte, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "proposalIdAtVersion", operation, candidate, versionNumber) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// ProposalIdAtVersion is a free data retrieval call binding the contract method 0x58753136. +// +// Solidity: function proposalIdAtVersion(uint8 operation, address candidate, uint256 versionNumber) pure returns(bytes32) +func (_ValidatorSet *ValidatorSetSession) ProposalIdAtVersion(operation uint8, candidate common.Address, versionNumber *big.Int) ([32]byte, error) { + return _ValidatorSet.Contract.ProposalIdAtVersion(&_ValidatorSet.CallOpts, operation, candidate, versionNumber) +} + +// ProposalIdAtVersion is a free data retrieval call binding the contract method 0x58753136. +// +// Solidity: function proposalIdAtVersion(uint8 operation, address candidate, uint256 versionNumber) pure returns(bytes32) +func (_ValidatorSet *ValidatorSetCallerSession) ProposalIdAtVersion(operation uint8, candidate common.Address, versionNumber *big.Int) ([32]byte, error) { + return _ValidatorSet.Contract.ProposalIdAtVersion(&_ValidatorSet.CallOpts, operation, candidate, versionNumber) +} + // ProposalVotes is a free data retrieval call binding the contract method 0xe6c166e3. // // Solidity: function proposalVotes(uint8 operation, address candidate) view returns(uint256) @@ -531,6 +562,37 @@ func (_ValidatorSet *ValidatorSetCallerSession) QuorumSize() (*big.Int, error) { return _ValidatorSet.Contract.QuorumSize(&_ValidatorSet.CallOpts) } +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(uint256) +func (_ValidatorSet *ValidatorSetCaller) Version(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ValidatorSet.contract.Call(opts, &out, "version") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(uint256) +func (_ValidatorSet *ValidatorSetSession) Version() (*big.Int, error) { + return _ValidatorSet.Contract.Version(&_ValidatorSet.CallOpts) +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(uint256) +func (_ValidatorSet *ValidatorSetCallerSession) Version() (*big.Int, error) { + return _ValidatorSet.Contract.Version(&_ValidatorSet.CallOpts) +} + // EnterMaintenance is a paid mutator transaction binding the contract method 0x9369d7de. // // Solidity: function enterMaintenance() returns() diff --git a/contracts/validatorcontract/contract/validator_set.sol b/contracts/validatorcontract/contract/validator_set.sol index a91e2c114..c0e13eb17 100644 --- a/contracts/validatorcontract/contract/validator_set.sol +++ b/contracts/validatorcontract/contract/validator_set.sol @@ -34,7 +34,7 @@ contract ValidatorSet { event ValidatorRemoved(address indexed validator); /// @notice Emitted whenever a validator casts a governance vote. - /// @param proposalId Unique ID derived from the operation and candidate. + /// @param proposalId Unique ID derived from the operation, candidate, and validator set version. /// @param operation The requested validator set operation. /// @param candidate The address proposed for addition or removal. /// @param voter The validator that cast the vote. @@ -62,6 +62,7 @@ contract ValidatorSet { mapping(address => uint256) private validatorIndexes; mapping(address => bool) private maintenanceStatus; uint256 private maintenanceCount; + uint256 private validatorSetVersion; mapping(bytes32 => Proposal) private proposals; modifier onlyValidator() { @@ -148,13 +149,29 @@ contract ValidatorSet { return maintenanceCount; } + /// @notice Returns the current validator set version. + /// @dev The version is incremented each time an add/remove proposal executes. + /// @return Current validator set version. + function version() external view returns (uint256) { + return validatorSetVersion; + } + /// @notice Computes the proposal ID for a validator set operation. - /// @dev The same operation/candidate pair maps to the same proposal for all voters. + /// @dev The same operation/candidate pair maps to the same proposal for all voters within the current validator set version. + /// @param operation Validator set operation type. + /// @param candidate Candidate address proposed for addition or removal. + /// @return Unique proposal ID for the current validator set version. + function proposalId(Operation operation, address candidate) public view returns (bytes32) { + return _currentProposalId(operation, candidate); + } + + /// @notice Computes the proposal ID for a validator set operation at a specific version. /// @param operation Validator set operation type. /// @param candidate Candidate address proposed for addition or removal. - /// @return Unique proposal ID. - function proposalId(Operation operation, address candidate) public pure returns (bytes32) { - return keccak256(abi.encodePacked(operation, candidate)); + /// @param versionNumber Validator set version to include in the proposal ID. + /// @return Unique proposal ID for the operation, candidate, and version. + function proposalIdAtVersion(Operation operation, address candidate, uint256 versionNumber) public pure returns (bytes32) { + return keccak256(abi.encodePacked(operation, candidate, versionNumber)); } /// @notice Returns the number of votes recorded for a proposal. @@ -162,7 +179,7 @@ contract ValidatorSet { /// @param candidate Candidate address proposed for addition or removal. /// @return Number of votes recorded for the proposal. function proposalVotes(Operation operation, address candidate) external view returns (uint256) { - return proposals[proposalId(operation, candidate)].votes; + return proposals[_currentProposalId(operation, candidate)].votes; } /// @notice Checks whether a proposal has already executed. @@ -170,7 +187,7 @@ contract ValidatorSet { /// @param candidate Candidate address proposed for addition or removal. /// @return True if the proposal reached quorum and executed. function proposalExecuted(Operation operation, address candidate) external view returns (bool) { - return proposals[proposalId(operation, candidate)].executed; + return proposals[_currentProposalId(operation, candidate)].executed; } /// @notice Checks whether a validator has voted for a proposal. @@ -179,7 +196,7 @@ contract ValidatorSet { /// @param voter Validator address to check. /// @return True if `voter` has already voted for the proposal. function hasVoted(Operation operation, address candidate, address voter) external view returns (bool) { - return proposals[proposalId(operation, candidate)].voted[voter]; + return proposals[_currentProposalId(operation, candidate)].voted[voter]; } /// @notice Votes to add a new validator. @@ -236,7 +253,7 @@ contract ValidatorSet { /// @dev Records a validator vote and executes the proposal immediately once quorum is reached. /// Reverts if the proposal already executed or the caller already voted for it. function _vote(Operation operation, address candidate) private { - bytes32 id = proposalId(operation, candidate); + bytes32 id = _currentProposalId(operation, candidate); Proposal storage proposal = proposals[id]; require(!proposal.executed, "ValidatorSet: proposal executed"); require(!proposal.voted[msg.sender], "ValidatorSet: already voted"); @@ -256,9 +273,15 @@ contract ValidatorSet { _removeValidator(candidate); emit ValidatorRemoved(candidate); } + validatorSetVersion++; } } + /// @dev Computes a proposal ID for the current validator set version. + function _currentProposalId(Operation operation, address candidate) private view returns (bytes32) { + return proposalIdAtVersion(operation, candidate, validatorSetVersion); + } + /// @dev Adds a validator to the registered set and preserves registration order. /// Reverts on zero address or duplicate registration. function _addValidator(address validator) private { diff --git a/contracts/validatorcontract/validator_test.go b/contracts/validatorcontract/validator_test.go index feb7347fe..5ee1e4e8c 100644 --- a/contracts/validatorcontract/validator_test.go +++ b/contracts/validatorcontract/validator_test.go @@ -316,6 +316,85 @@ func TestValidatorSetAddAndRemoveByQuorum(t *testing.T) { assertAddresses(t, allValidators, []common.Address{accounts[0].addr, accounts[1].addr, accounts[2].addr, accounts[3].addr}) } +func TestValidatorSetCanReuseCandidateAcrossVersions(t *testing.T) { + // Viewpoint: + // The same candidate can be added, removed, added again, and removed again because proposal IDs are versioned. + + backend, validatorSet, accounts := deployValidatorSet(t) + defer backend.Close() + + candidate := accounts[4].addr + voteAdd := func(voters ...testAccount) { + for _, voter := range voters { + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteAddValidator(newTestAuth(t, voter), candidate) + }) + } + } + voteRemove := func(voters ...testAccount) { + for _, voter := range voters { + mustTransact(t, backend, func() (*types.Transaction, error) { + return validatorSet.VoteRemoveValidator(newTestAuth(t, voter), candidate) + }) + } + } + assertVersion := func(want int64) { + got, err := validatorSet.Version(nil) + if err != nil { + t.Fatalf("failed to get validator set version: %v", err) + } + if got.Cmp(big.NewInt(want)) != 0 { + t.Fatalf("unexpected validator set version: got %s, want %d", got, want) + } + } + + assertVersion(0) + + // First add executes at version 0 and advances the version. + voteAdd(accounts[0], accounts[1], accounts[2]) + isValidator, err := validatorSet.IsValidator(nil, candidate) + if err != nil { + t.Fatalf("failed to check candidate after first add: %v", err) + } + if !isValidator { + t.Fatal("candidate was not added") + } + assertVersion(1) + + // First remove executes at version 1 and advances the version. + voteRemove(accounts[0], accounts[1], accounts[2]) + isValidator, err = validatorSet.IsValidator(nil, candidate) + if err != nil { + t.Fatalf("failed to check candidate after first remove: %v", err) + } + if isValidator { + t.Fatal("candidate was not removed") + } + assertVersion(2) + + // The second add uses a fresh versioned proposal instead of the executed add proposal from version 0. + voteAdd(accounts[0], accounts[1], accounts[2]) + isValidator, err = validatorSet.IsValidator(nil, candidate) + if err != nil { + t.Fatalf("failed to check candidate after second add: %v", err) + } + if !isValidator { + t.Fatal("candidate was not re-added") + } + assertVersion(3) + + // The second remove also uses a fresh versioned proposal. + voteRemove(accounts[0], accounts[1], accounts[2]) + isValidator, err = validatorSet.IsValidator(nil, candidate) + if err != nil { + t.Fatalf("failed to check candidate after second remove: %v", err) + } + if isValidator { + t.Fatal("candidate was not removed again") + } + assertVersion(4) +} + func TestValidatorSetRejectsInvalidVotes(t *testing.T) { // Viewpoint: // Governance votes must come from validators, target valid candidates,