diff --git a/beacon-chain/LICENSE.md b/LICENSE.md similarity index 100% rename from beacon-chain/LICENSE.md rename to LICENSE.md diff --git a/beacon-chain/BUILD.bazel b/beacon-chain/BUILD.bazel index 9284d557c..6da777969 100644 --- a/beacon-chain/BUILD.bazel +++ b/beacon-chain/BUILD.bazel @@ -4,5 +4,5 @@ go_library( name = "go_default_library", srcs = ["config.go"], importpath = "github.com/prysmaticlabs/geth-sharding/beacon-chain", - visibility = ["//visibility:public"], + visibility = ["//beacon-chain:__subpackages__"], ) diff --git a/beacon-chain/types/BUILD.bazel b/beacon-chain/types/BUILD.bazel index 3d1d4dfce..3c37f0006 100644 --- a/beacon-chain/types/BUILD.bazel +++ b/beacon-chain/types/BUILD.bazel @@ -7,6 +7,6 @@ go_library( "state.go", ], importpath = "github.com/prysmaticlabs/geth-sharding/beacon-chain/types", - visibility = ["//visibility:public"], + visibility = ["//beacon-chain:__subpackages__"], deps = ["@com_github_ethereum_go_ethereum//common:go_default_library"], ) diff --git a/contracts/BUILD.bazel b/contracts/BUILD.bazel new file mode 100644 index 000000000..09057778e --- /dev/null +++ b/contracts/BUILD.bazel @@ -0,0 +1,29 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["validator_registration.go"], + importpath = "github.com/prysmaticlabs/geth-sharding/contracts", + visibility = ["//visibility:public"], + deps = [ + "@com_github_ethereum_go_ethereum//:go_default_library", + "@com_github_ethereum_go_ethereum//accounts/abi:go_default_library", + "@com_github_ethereum_go_ethereum//accounts/abi/bind:go_default_library", + "@com_github_ethereum_go_ethereum//common:go_default_library", + "@com_github_ethereum_go_ethereum//core/types:go_default_library", + "@com_github_ethereum_go_ethereum//event:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["validator_registration_test.go"], + embed = [":go_default_library"], + deps = [ + "@com_github_ethereum_go_ethereum//accounts/abi/bind:go_default_library", + "@com_github_ethereum_go_ethereum//accounts/abi/bind/backends:go_default_library", + "@com_github_ethereum_go_ethereum//common:go_default_library", + "@com_github_ethereum_go_ethereum//core:go_default_library", + "@com_github_ethereum_go_ethereum//crypto:go_default_library", + ], +) diff --git a/contracts/README.md b/contracts/README.md new file mode 100644 index 000000000..18c0e24b2 --- /dev/null +++ b/contracts/README.md @@ -0,0 +1,32 @@ +## Validator Registration Contract + +For beacon chain design, a validator will deposit 32 ETH to the main chain smart contract. +The deposit is considered to be burned. As you burn the 32 ETH to participate, +the beacon chain will see it and will credit the validator with the validator bond, +and the validator can begin to validate. At some point in the future, after a hard fork, +the original deposit + interest can be withdrawn back on one of the shards. + +## How to execute tests + +``` +go test ./... + +``` + +Run with `-v` option for detailed log output + +``` +go test ./... -v +=== RUN TestSetupAndContractRegistration +--- PASS: TestSetupAndContractRegistration (0.01s) +=== RUN TestRegisterWithLessThan32Eth +--- PASS: TestRegisterWithLessThan32Eth (0.00s) +=== RUN TestRegisterWithMoreThan32Eth +--- PASS: TestRegisterWithMoreThan32Eth (0.00s) +=== RUN TestRegisterTwice +--- PASS: TestRegisterTwice (0.01s) +=== RUN TestRegister +--- PASS: TestRegister (0.01s) +PASS +ok beacon-chain/contracts 0.151s +``` \ No newline at end of file diff --git a/contracts/validator_registration.go b/contracts/validator_registration.go new file mode 100644 index 000000000..b87471fc7 --- /dev/null +++ b/contracts/validator_registration.go @@ -0,0 +1,375 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contracts + +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" +) + +// ValidatorRegistrationABI is the input ABI used to generate the binding from. +const ValidatorRegistrationABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"usedPubkey\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"VALIDATOR_DEPOSIT\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_pubkey\",\"type\":\"bytes32\"},{\"name\":\"_withdrawalShardID\",\"type\":\"uint256\"},{\"name\":\"_withdrawalAddressbytes32\",\"type\":\"address\"},{\"name\":\"_randaoCommitment\",\"type\":\"bytes32\"}],\"name\":\"deposit\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"pubKey\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"withdrawalShardID\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"withdrawalAddressbytes32\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"randaoCommitment\",\"type\":\"bytes32\"}],\"name\":\"ValidatorRegistered\",\"type\":\"event\"}]" + +// ValidatorRegistrationBin is the compiled bytecode used for deploying new contracts. +const ValidatorRegistrationBin = `0x608060405234801561001057600080fd5b506101d3806100206000396000f3006080604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166301110845811461005b578063441d92cc14610087578063881d2135146100ae575b600080fd5b34801561006757600080fd5b506100736004356100da565b604080519115158252519081900360200190f35b34801561009357600080fd5b5061009c6100ef565b60408051918252519081900360200190f35b6100d860043560243573ffffffffffffffffffffffffffffffffffffffff604435166064356100fc565b005b60006020819052908152604090205460ff1681565b6801bc16d674ec80000081565b346801bc16d674ec8000001461011157600080fd5b60008481526020819052604090205460ff161561012d57600080fd5b60008481526020818152604091829020805460ff19166001179055815186815290810185905273ffffffffffffffffffffffffffffffffffffffff8416818301526060810183905290517f7b0678aab009b61a805f5004869728b53a444f9a3e6bb9e22b8537c89af512749181900360800190a1505050505600a165627a7a72305820ba933a3e2d7a01de483490b3379e3c0ff9eb8040d0bb6eccf192fca140f752d70029` + +// DeployValidatorRegistration deploys a new Ethereum contract, binding an instance of ValidatorRegistration to it. +func DeployValidatorRegistration(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *ValidatorRegistration, error) { + parsed, err := abi.JSON(strings.NewReader(ValidatorRegistrationABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ValidatorRegistrationBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &ValidatorRegistration{ValidatorRegistrationCaller: ValidatorRegistrationCaller{contract: contract}, ValidatorRegistrationTransactor: ValidatorRegistrationTransactor{contract: contract}, ValidatorRegistrationFilterer: ValidatorRegistrationFilterer{contract: contract}}, nil +} + +// ValidatorRegistration is an auto generated Go binding around an Ethereum contract. +type ValidatorRegistration struct { + ValidatorRegistrationCaller // Read-only binding to the contract + ValidatorRegistrationTransactor // Write-only binding to the contract + ValidatorRegistrationFilterer // Log filterer for contract events +} + +// ValidatorRegistrationCaller is an auto generated read-only Go binding around an Ethereum contract. +type ValidatorRegistrationCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ValidatorRegistrationTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ValidatorRegistrationTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ValidatorRegistrationFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ValidatorRegistrationFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ValidatorRegistrationSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ValidatorRegistrationSession struct { + Contract *ValidatorRegistration // 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 +} + +// ValidatorRegistrationCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ValidatorRegistrationCallerSession struct { + Contract *ValidatorRegistrationCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ValidatorRegistrationTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ValidatorRegistrationTransactorSession struct { + Contract *ValidatorRegistrationTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ValidatorRegistrationRaw is an auto generated low-level Go binding around an Ethereum contract. +type ValidatorRegistrationRaw struct { + Contract *ValidatorRegistration // Generic contract binding to access the raw methods on +} + +// ValidatorRegistrationCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ValidatorRegistrationCallerRaw struct { + Contract *ValidatorRegistrationCaller // Generic read-only contract binding to access the raw methods on +} + +// ValidatorRegistrationTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ValidatorRegistrationTransactorRaw struct { + Contract *ValidatorRegistrationTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewValidatorRegistration creates a new instance of ValidatorRegistration, bound to a specific deployed contract. +func NewValidatorRegistration(address common.Address, backend bind.ContractBackend) (*ValidatorRegistration, error) { + contract, err := bindValidatorRegistration(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ValidatorRegistration{ValidatorRegistrationCaller: ValidatorRegistrationCaller{contract: contract}, ValidatorRegistrationTransactor: ValidatorRegistrationTransactor{contract: contract}, ValidatorRegistrationFilterer: ValidatorRegistrationFilterer{contract: contract}}, nil +} + +// NewValidatorRegistrationCaller creates a new read-only instance of ValidatorRegistration, bound to a specific deployed contract. +func NewValidatorRegistrationCaller(address common.Address, caller bind.ContractCaller) (*ValidatorRegistrationCaller, error) { + contract, err := bindValidatorRegistration(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ValidatorRegistrationCaller{contract: contract}, nil +} + +// NewValidatorRegistrationTransactor creates a new write-only instance of ValidatorRegistration, bound to a specific deployed contract. +func NewValidatorRegistrationTransactor(address common.Address, transactor bind.ContractTransactor) (*ValidatorRegistrationTransactor, error) { + contract, err := bindValidatorRegistration(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ValidatorRegistrationTransactor{contract: contract}, nil +} + +// NewValidatorRegistrationFilterer creates a new log filterer instance of ValidatorRegistration, bound to a specific deployed contract. +func NewValidatorRegistrationFilterer(address common.Address, filterer bind.ContractFilterer) (*ValidatorRegistrationFilterer, error) { + contract, err := bindValidatorRegistration(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ValidatorRegistrationFilterer{contract: contract}, nil +} + +// bindValidatorRegistration binds a generic wrapper to an already deployed contract. +func bindValidatorRegistration(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(ValidatorRegistrationABI)) + 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 (_ValidatorRegistration *ValidatorRegistrationRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _ValidatorRegistration.Contract.ValidatorRegistrationCaller.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 (_ValidatorRegistration *ValidatorRegistrationRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ValidatorRegistration.Contract.ValidatorRegistrationTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ValidatorRegistration *ValidatorRegistrationRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ValidatorRegistration.Contract.ValidatorRegistrationTransactor.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 (_ValidatorRegistration *ValidatorRegistrationCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _ValidatorRegistration.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 (_ValidatorRegistration *ValidatorRegistrationTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ValidatorRegistration.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ValidatorRegistration *ValidatorRegistrationTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ValidatorRegistration.Contract.contract.Transact(opts, method, params...) +} + +// VALIDATORDEPOSIT is a free data retrieval call binding the contract method 0x441d92cc. +// +// Solidity: function VALIDATOR_DEPOSIT() constant returns(uint256) +func (_ValidatorRegistration *ValidatorRegistrationCaller) VALIDATORDEPOSIT(opts *bind.CallOpts) (*big.Int, error) { + var ( + ret0 = new(*big.Int) + ) + out := ret0 + err := _ValidatorRegistration.contract.Call(opts, out, "VALIDATOR_DEPOSIT") + return *ret0, err +} + +// VALIDATORDEPOSIT is a free data retrieval call binding the contract method 0x441d92cc. +// +// Solidity: function VALIDATOR_DEPOSIT() constant returns(uint256) +func (_ValidatorRegistration *ValidatorRegistrationSession) VALIDATORDEPOSIT() (*big.Int, error) { + return _ValidatorRegistration.Contract.VALIDATORDEPOSIT(&_ValidatorRegistration.CallOpts) +} + +// VALIDATORDEPOSIT is a free data retrieval call binding the contract method 0x441d92cc. +// +// Solidity: function VALIDATOR_DEPOSIT() constant returns(uint256) +func (_ValidatorRegistration *ValidatorRegistrationCallerSession) VALIDATORDEPOSIT() (*big.Int, error) { + return _ValidatorRegistration.Contract.VALIDATORDEPOSIT(&_ValidatorRegistration.CallOpts) +} + +// UsedPubkey is a free data retrieval call binding the contract method 0x01110845. +// +// Solidity: function usedPubkey( bytes32) constant returns(bool) +func (_ValidatorRegistration *ValidatorRegistrationCaller) UsedPubkey(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { + var ( + ret0 = new(bool) + ) + out := ret0 + err := _ValidatorRegistration.contract.Call(opts, out, "usedPubkey", arg0) + return *ret0, err +} + +// UsedPubkey is a free data retrieval call binding the contract method 0x01110845. +// +// Solidity: function usedPubkey( bytes32) constant returns(bool) +func (_ValidatorRegistration *ValidatorRegistrationSession) UsedPubkey(arg0 [32]byte) (bool, error) { + return _ValidatorRegistration.Contract.UsedPubkey(&_ValidatorRegistration.CallOpts, arg0) +} + +// UsedPubkey is a free data retrieval call binding the contract method 0x01110845. +// +// Solidity: function usedPubkey( bytes32) constant returns(bool) +func (_ValidatorRegistration *ValidatorRegistrationCallerSession) UsedPubkey(arg0 [32]byte) (bool, error) { + return _ValidatorRegistration.Contract.UsedPubkey(&_ValidatorRegistration.CallOpts, arg0) +} + +// Deposit is a paid mutator transaction binding the contract method 0x881d2135. +// +// Solidity: function deposit(_pubkey bytes32, _withdrawalShardID uint256, _withdrawalAddressbytes32 address, _randaoCommitment bytes32) returns() +func (_ValidatorRegistration *ValidatorRegistrationTransactor) Deposit(opts *bind.TransactOpts, _pubkey [32]byte, _withdrawalShardID *big.Int, _withdrawalAddressbytes32 common.Address, _randaoCommitment [32]byte) (*types.Transaction, error) { + return _ValidatorRegistration.contract.Transact(opts, "deposit", _pubkey, _withdrawalShardID, _withdrawalAddressbytes32, _randaoCommitment) +} + +// Deposit is a paid mutator transaction binding the contract method 0x881d2135. +// +// Solidity: function deposit(_pubkey bytes32, _withdrawalShardID uint256, _withdrawalAddressbytes32 address, _randaoCommitment bytes32) returns() +func (_ValidatorRegistration *ValidatorRegistrationSession) Deposit(_pubkey [32]byte, _withdrawalShardID *big.Int, _withdrawalAddressbytes32 common.Address, _randaoCommitment [32]byte) (*types.Transaction, error) { + return _ValidatorRegistration.Contract.Deposit(&_ValidatorRegistration.TransactOpts, _pubkey, _withdrawalShardID, _withdrawalAddressbytes32, _randaoCommitment) +} + +// Deposit is a paid mutator transaction binding the contract method 0x881d2135. +// +// Solidity: function deposit(_pubkey bytes32, _withdrawalShardID uint256, _withdrawalAddressbytes32 address, _randaoCommitment bytes32) returns() +func (_ValidatorRegistration *ValidatorRegistrationTransactorSession) Deposit(_pubkey [32]byte, _withdrawalShardID *big.Int, _withdrawalAddressbytes32 common.Address, _randaoCommitment [32]byte) (*types.Transaction, error) { + return _ValidatorRegistration.Contract.Deposit(&_ValidatorRegistration.TransactOpts, _pubkey, _withdrawalShardID, _withdrawalAddressbytes32, _randaoCommitment) +} + +// ValidatorRegistrationValidatorRegisteredIterator is returned from FilterValidatorRegistered and is used to iterate over the raw logs and unpacked data for ValidatorRegistered events raised by the ValidatorRegistration contract. +type ValidatorRegistrationValidatorRegisteredIterator struct { + Event *ValidatorRegistrationValidatorRegistered // 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 *ValidatorRegistrationValidatorRegisteredIterator) 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(ValidatorRegistrationValidatorRegistered) + 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(ValidatorRegistrationValidatorRegistered) + 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 *ValidatorRegistrationValidatorRegisteredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ValidatorRegistrationValidatorRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ValidatorRegistrationValidatorRegistered represents a ValidatorRegistered event raised by the ValidatorRegistration contract. +type ValidatorRegistrationValidatorRegistered struct { + PubKey [32]byte + WithdrawalShardID *big.Int + WithdrawalAddressbytes32 common.Address + RandaoCommitment [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterValidatorRegistered is a free log retrieval operation binding the contract event 0x7b0678aab009b61a805f5004869728b53a444f9a3e6bb9e22b8537c89af51274. +// +// Solidity: event ValidatorRegistered(pubKey bytes32, withdrawalShardID uint256, withdrawalAddressbytes32 address, randaoCommitment bytes32) +func (_ValidatorRegistration *ValidatorRegistrationFilterer) FilterValidatorRegistered(opts *bind.FilterOpts) (*ValidatorRegistrationValidatorRegisteredIterator, error) { + + logs, sub, err := _ValidatorRegistration.contract.FilterLogs(opts, "ValidatorRegistered") + if err != nil { + return nil, err + } + return &ValidatorRegistrationValidatorRegisteredIterator{contract: _ValidatorRegistration.contract, event: "ValidatorRegistered", logs: logs, sub: sub}, nil +} + +// WatchValidatorRegistered is a free log subscription operation binding the contract event 0x7b0678aab009b61a805f5004869728b53a444f9a3e6bb9e22b8537c89af51274. +// +// Solidity: event ValidatorRegistered(pubKey bytes32, withdrawalShardID uint256, withdrawalAddressbytes32 address, randaoCommitment bytes32) +func (_ValidatorRegistration *ValidatorRegistrationFilterer) WatchValidatorRegistered(opts *bind.WatchOpts, sink chan<- *ValidatorRegistrationValidatorRegistered) (event.Subscription, error) { + + logs, sub, err := _ValidatorRegistration.contract.WatchLogs(opts, "ValidatorRegistered") + 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(ValidatorRegistrationValidatorRegistered) + if err := _ValidatorRegistration.contract.UnpackLog(event, "ValidatorRegistered", 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 +} diff --git a/contracts/validator_registration.sol b/contracts/validator_registration.sol new file mode 100644 index 000000000..c6f357132 --- /dev/null +++ b/contracts/validator_registration.sol @@ -0,0 +1,35 @@ +pragma solidity 0.4.23; + +contract ValidatorRegistration { + event ValidatorRegistered( + bytes32 pubKey, + uint256 withdrawalShardID, + address withdrawalAddressbytes32, + bytes32 randaoCommitment + ); + + mapping (bytes32 => bool) public usedPubkey; + + uint public constant VALIDATOR_DEPOSIT = 32 ether; + + // Validator registers by sending a transaction of 32ETH to + // the following deposit function. The deposit function takes in + // validator's public key, withdrawal shard ID (which shard + // to send the deposit back to), withdrawal address (which address + // to send the deposit back to) and randao commitment. + function deposit( + bytes32 _pubkey, + uint _withdrawalShardID, + address _withdrawalAddressbytes32, + bytes32 _randaoCommitment + ) + public payable + { + require(msg.value == VALIDATOR_DEPOSIT); + require(!usedPubkey[_pubkey]); + + usedPubkey[_pubkey] = true; + + emit ValidatorRegistered(_pubkey, _withdrawalShardID, _withdrawalAddressbytes32, _randaoCommitment); + } +} \ No newline at end of file diff --git a/contracts/validator_registration_test.go b/contracts/validator_registration_test.go new file mode 100644 index 000000000..aa4d7f1f9 --- /dev/null +++ b/contracts/validator_registration_test.go @@ -0,0 +1,156 @@ +package contracts + +import ( + "crypto/ecdsa" + "fmt" + "log" + "math/big" + "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/core" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + amount33Eth, _ = new(big.Int).SetString("33000000000000000000", 10) + amount32Eth, _ = new(big.Int).SetString("32000000000000000000", 10) + amount31Eth, _ = new(big.Int).SetString("31000000000000000000", 10) +) + +type testAccount struct { + addr common.Address + withdrawalAddress common.Address + randaoCommitment [32]byte + pubKey [32]byte + contract *ValidatorRegistration + backend *backends.SimulatedBackend + txOpts *bind.TransactOpts +} + +func setup() (*testAccount, error) { + genesis := make(core.GenesisAlloc) + privKey, _ := crypto.GenerateKey() + pubKeyECDSA, ok := privKey.Public().(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("error casting public key to ECDSA") + } + + // strip off the 0x and the first 2 characters 04 which is always the EC prefix and is not required. + publicKeyBytes := crypto.FromECDSAPub(pubKeyECDSA)[4:] + var pubKey [32]byte + copy(pubKey[:], []byte(publicKeyBytes)) + + addr := crypto.PubkeyToAddress(privKey.PublicKey) + txOpts := bind.NewKeyedTransactor(privKey) + startingBalance, _ := new(big.Int).SetString("100000000000000000000", 10) + genesis[addr] = core.GenesisAccount{Balance: startingBalance} + backend := backends.NewSimulatedBackend(genesis) + + _, _, contract, err := DeployValidatorRegistration(txOpts, backend) + if err != nil { + return nil, err + } + + return &testAccount{addr, common.Address{}, [32]byte{}, pubKey, contract, backend, txOpts}, nil +} + +func TestSetupAndContractRegistration(t *testing.T) { + _, err := setup() + if err != nil { + log.Fatalf("Can not deploy validator registration contract: %v", err) + } +} + +// negative test case, deposit with less than 32 ETH. +func TestRegisterWithLessThan32Eth(t *testing.T) { + testAccount, err := setup() + if err != nil { + t.Fatal(err) + } + withdrawAddr := &common.Address{'A', 'D', 'D', 'R', 'E', 'S', 'S'} + randaoCommitment := &[32]byte{'S', 'H', 'H', 'H', 'H', 'I', 'T', 'S', 'A', 'S', 'E', 'C', 'R', 'E', 'T'} + + testAccount.txOpts.Value = amount31Eth + _, err = testAccount.contract.Deposit(testAccount.txOpts, testAccount.pubKey, big.NewInt(0), *withdrawAddr, *randaoCommitment) + if err == nil { + t.Error("Validator registration should have failed with insufficient deposit") + } +} + +// negative test case, deposit more than 32 ETH. +func TestRegisterWithMoreThan32Eth(t *testing.T) { + testAccount, err := setup() + if err != nil { + t.Fatal(err) + } + withdrawAddr := &common.Address{'A', 'D', 'D', 'R', 'E', 'S', 'S'} + randaoCommitment := &[32]byte{'S', 'H', 'H', 'H', 'H', 'I', 'T', 'S', 'A', 'S', 'E', 'C', 'R', 'E', 'T'} + + testAccount.txOpts.Value = amount33Eth + _, err = testAccount.contract.Deposit(testAccount.txOpts, testAccount.pubKey, big.NewInt(0), *withdrawAddr, *randaoCommitment) + if err == nil { + t.Error("Validator registration should have failed with more than deposit amount") + } +} + +// negative test case, test registering with the same public key twice. +func TestRegisterTwice(t *testing.T) { + testAccount, err := setup() + if err != nil { + t.Fatal(err) + } + withdrawAddr := &common.Address{'A', 'D', 'D', 'R', 'E', 'S', 'S'} + randaoCommitment := &[32]byte{'S', 'H', 'H', 'H', 'H', 'I', 'T', 'S', 'A', 'S', 'E', 'C', 'R', 'E', 'T'} + + testAccount.txOpts.Value = amount32Eth + _, err = testAccount.contract.Deposit(testAccount.txOpts, testAccount.pubKey, big.NewInt(0), *withdrawAddr, *randaoCommitment) + testAccount.backend.Commit() + if err != nil { + t.Errorf("Validator registration failed: %v", err) + } + + testAccount.txOpts.Value = amount32Eth + _, err = testAccount.contract.Deposit(testAccount.txOpts, testAccount.pubKey, big.NewInt(0), *withdrawAddr, *randaoCommitment) + testAccount.backend.Commit() + if err == nil { + t.Errorf("Registration should have failed with same public key twice") + } +} + +// normal test case, test depositing 32 ETH and verify validatorRegistered event is correctly emitted. +func TestRegister(t *testing.T) { + testAccount, err := setup() + if err != nil { + t.Fatal(err) + } + withdrawAddr := &common.Address{'A', 'D', 'D', 'R', 'E', 'S', 'S'} + randaoCommitment := &[32]byte{'S', 'H', 'H', 'H', 'H', 'I', 'T', 'S', 'A', 'S', 'E', 'C', 'R', 'E', 'T'} + shardID := big.NewInt(99) + testAccount.txOpts.Value = amount32Eth + + _, err = testAccount.contract.Deposit(testAccount.txOpts, testAccount.pubKey, shardID, *withdrawAddr, *randaoCommitment) + testAccount.backend.Commit() + if err != nil { + t.Errorf("Validator registration failed: %v", err) + } + log, err := testAccount.contract.FilterValidatorRegistered(&bind.FilterOpts{}) + if err != nil { + t.Fatal(err) + } + log.Next() + if log.Event.WithdrawalShardID.Cmp(shardID) != 0 { + t.Errorf("validatorRegistered event withdrawal shard ID miss matched. Want: %v, Got: %v", shardID, log.Event.WithdrawalShardID) + } + if log.Event.RandaoCommitment != *randaoCommitment { + t.Errorf("validatorRegistered event randao commitment miss matched. Want: %v, Got: %v", *randaoCommitment, log.Event.RandaoCommitment) + } + if log.Event.PubKey != testAccount.pubKey { + t.Errorf("validatorRegistered event public key miss matched. Want: %v, Got: %v", testAccount.pubKey, log.Event.PubKey) + } + if log.Event.WithdrawalAddressbytes32 != *withdrawAddr { + t.Errorf("validatorRegistered event withdrawal address miss matched. Want: %v, Got: %v", *withdrawAddr, log.Event.WithdrawalAddressbytes32) + } +} diff --git a/sharding/BUILD.bazel b/sharding/BUILD.bazel index 66aeb5436..7506709a7 100644 --- a/sharding/BUILD.bazel +++ b/sharding/BUILD.bazel @@ -4,7 +4,7 @@ go_library( name = "go_default_library", srcs = ["main.go"], importpath = "github.com/prysmaticlabs/geth-sharding/sharding", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/node:go_default_library", "//sharding/utils:go_default_library", @@ -15,5 +15,5 @@ go_library( go_binary( name = "sharding", embed = [":go_default_library"], - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], ) diff --git a/sharding/contracts/BUILD.bazel b/sharding/contracts/BUILD.bazel index 9e9605c0e..91f73d584 100644 --- a/sharding/contracts/BUILD.bazel +++ b/sharding/contracts/BUILD.bazel @@ -8,7 +8,7 @@ go_library( "types.go", ], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/contracts", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "@com_github_ethereum_go_ethereum//:go_default_library", "@com_github_ethereum_go_ethereum//accounts/abi:go_default_library", diff --git a/sharding/database/BUILD.bazel b/sharding/database/BUILD.bazel index ba7aedd09..577ca9c0c 100644 --- a/sharding/database/BUILD.bazel +++ b/sharding/database/BUILD.bazel @@ -7,7 +7,7 @@ go_library( "inmemory.go", ], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/database", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "@com_github_ethereum_go_ethereum//common:go_default_library", "@com_github_ethereum_go_ethereum//ethdb:go_default_library", diff --git a/sharding/internal/BUILD.bazel b/sharding/internal/BUILD.bazel index 32c1c3cb3..ba3ca0525 100644 --- a/sharding/internal/BUILD.bazel +++ b/sharding/internal/BUILD.bazel @@ -4,7 +4,7 @@ go_library( name = "go_default_library", srcs = ["client_helper.go"], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/internal", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/contracts:go_default_library", "//sharding/params:go_default_library", diff --git a/sharding/mainchain/BUILD.bazel b/sharding/mainchain/BUILD.bazel index 562d32f44..6d4dbc506 100644 --- a/sharding/mainchain/BUILD.bazel +++ b/sharding/mainchain/BUILD.bazel @@ -8,7 +8,7 @@ go_library( "utils.go", ], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/mainchain", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/contracts:go_default_library", "//sharding/params:go_default_library", diff --git a/sharding/node/BUILD.bazel b/sharding/node/BUILD.bazel index d0477b4ad..22d8e98c9 100644 --- a/sharding/node/BUILD.bazel +++ b/sharding/node/BUILD.bazel @@ -4,7 +4,7 @@ go_library( name = "go_default_library", srcs = ["backend.go"], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/node", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/database:go_default_library", "//sharding/mainchain:go_default_library", diff --git a/sharding/notary/BUILD.bazel b/sharding/notary/BUILD.bazel index a6d99ed70..5864a6e26 100644 --- a/sharding/notary/BUILD.bazel +++ b/sharding/notary/BUILD.bazel @@ -7,7 +7,7 @@ go_library( "service.go", ], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/notary", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/contracts:go_default_library", "//sharding/database:go_default_library", diff --git a/sharding/observer/BUILD.bazel b/sharding/observer/BUILD.bazel index b47de8186..cf19ed7de 100644 --- a/sharding/observer/BUILD.bazel +++ b/sharding/observer/BUILD.bazel @@ -4,7 +4,7 @@ go_library( name = "go_default_library", srcs = ["service.go"], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/observer", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/database:go_default_library", "//sharding/mainchain:go_default_library", diff --git a/sharding/p2p/BUILD.bazel b/sharding/p2p/BUILD.bazel index f00d5f0c0..5d720cdad 100644 --- a/sharding/p2p/BUILD.bazel +++ b/sharding/p2p/BUILD.bazel @@ -9,7 +9,7 @@ go_library( "service.go", ], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/p2p", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "@com_github_ethereum_go_ethereum//event:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", diff --git a/sharding/p2p/messages/BUILD.bazel b/sharding/p2p/messages/BUILD.bazel index df1982c09..b280d11e2 100644 --- a/sharding/p2p/messages/BUILD.bazel +++ b/sharding/p2p/messages/BUILD.bazel @@ -4,6 +4,6 @@ go_library( name = "go_default_library", srcs = ["messages.go"], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/p2p/messages", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = ["@com_github_ethereum_go_ethereum//common:go_default_library"], ) diff --git a/sharding/params/BUILD.bazel b/sharding/params/BUILD.bazel index b6f46ac30..fac9144fd 100644 --- a/sharding/params/BUILD.bazel +++ b/sharding/params/BUILD.bazel @@ -4,7 +4,7 @@ go_library( name = "go_default_library", srcs = ["config.go"], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/params", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = ["@com_github_ethereum_go_ethereum//common:go_default_library"], ) diff --git a/sharding/proposer/BUILD.bazel b/sharding/proposer/BUILD.bazel index 26c0671fc..e3c545cb2 100644 --- a/sharding/proposer/BUILD.bazel +++ b/sharding/proposer/BUILD.bazel @@ -7,7 +7,7 @@ go_library( "service.go", ], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/proposer", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/database:go_default_library", "//sharding/mainchain:go_default_library", diff --git a/sharding/simulator/BUILD.bazel b/sharding/simulator/BUILD.bazel index 7f97061ff..d186f8368 100644 --- a/sharding/simulator/BUILD.bazel +++ b/sharding/simulator/BUILD.bazel @@ -4,7 +4,7 @@ go_library( name = "go_default_library", srcs = ["service.go"], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/simulator", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/mainchain:go_default_library", "//sharding/p2p:go_default_library", diff --git a/sharding/syncer/BUILD.bazel b/sharding/syncer/BUILD.bazel index 448a63fbc..14b984eaa 100644 --- a/sharding/syncer/BUILD.bazel +++ b/sharding/syncer/BUILD.bazel @@ -7,7 +7,7 @@ go_library( "service.go", ], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/syncer", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/database:go_default_library", "//sharding/mainchain:go_default_library", diff --git a/sharding/txpool/BUILD.bazel b/sharding/txpool/BUILD.bazel index 426a1e77b..17cf0dd93 100644 --- a/sharding/txpool/BUILD.bazel +++ b/sharding/txpool/BUILD.bazel @@ -4,7 +4,7 @@ go_library( name = "go_default_library", srcs = ["service.go"], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/txpool", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/p2p:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", diff --git a/sharding/types/BUILD.bazel b/sharding/types/BUILD.bazel index 5ab8d33e7..d0cec693f 100644 --- a/sharding/types/BUILD.bazel +++ b/sharding/types/BUILD.bazel @@ -8,7 +8,7 @@ go_library( "shard.go", ], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/types", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/utils:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", diff --git a/sharding/utils/BUILD.bazel b/sharding/utils/BUILD.bazel index af5098771..a4b60cfac 100644 --- a/sharding/utils/BUILD.bazel +++ b/sharding/utils/BUILD.bazel @@ -10,7 +10,7 @@ go_library( "service.go", ], importpath = "github.com/prysmaticlabs/geth-sharding/sharding/utils", - visibility = ["//visibility:public"], + visibility = ["//sharding:__subpackages__"], deps = [ "//sharding/params:go_default_library", "@com_github_ethereum_go_ethereum//node:go_default_library",