From 516ff4664a4e558211ef8135bdc03d70f900be02 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 30 May 2018 14:20:08 +0800 Subject: [PATCH 01/15] contracts: add checkpoint registrar smart contract --- contracts/registrar/contract/registrar.go | 711 +++++++++++++++++++++ contracts/registrar/contract/registrar.sol | 212 ++++++ 2 files changed, 923 insertions(+) create mode 100644 contracts/registrar/contract/registrar.go create mode 100644 contracts/registrar/contract/registrar.sol diff --git a/contracts/registrar/contract/registrar.go b/contracts/registrar/contract/registrar.go new file mode 100644 index 0000000000..c8db5de473 --- /dev/null +++ b/contracts/registrar/contract/registrar.go @@ -0,0 +1,711 @@ +// 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" +) + +// ContractABI is the input ABI used to generate the binding from. +const ContractABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"GetAllAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetLatestCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"},{\"name\":\"_sectionHead\",\"type\":\"bytes32\"},{\"name\":\"_chtRoot\",\"type\":\"bytes32\"},{\"name\":\"_bloomTrieRoot\",\"type\":\"bytes32\"}],\"name\":\"SetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"}],\"name\":\"GetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"RemoveAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"AddAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_adminlist\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"index\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"sectionHead\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"chtRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"bloomTrieRoot\",\"type\":\"bytes32\"}],\"name\":\"NewCheckpointEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"AddAdminEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"RemoveAdminEvent\",\"type\":\"event\"}]" + +// ContractBin is the compiled bytecode used for deploying new contracts. +const ContractBin = `608060405234801561001057600080fd5b50604051610c3f380380610c3f8339810180604052810190808051820192919050505060008090505b8151811015610127576001600080848481518110151561005557fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600182828151811015156100ad57fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508080600101915050610039565b5050610b07806101386000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806345848dfc1461007d5780634d6a304c146100e9578063651c7f4914610141578063710aeac8146101b0578063753f40ca14610217578063ad6de44514610272575b600080fd5b34801561008957600080fd5b506100926102cd565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156100d55780820151818401526020810190506100ba565b505050509050019250505060405180910390f35b3480156100f557600080fd5b506100fe6103b4565b6040518085815260200184600019166000191681526020018360001916600019168152602001826000191660001916815260200194505050505060405180910390f35b34801561014d57600080fd5b50610196600480360381019080803590602001909291908035600019169060200190929190803560001916906020019092919080356000191690602001909291905050506103e7565b604051808215151515815260200191505060405180910390f35b3480156101bc57600080fd5b506101db60048036038101908080359060200190929190505050610539565b60405180846000191660001916815260200183600019166000191681526020018260001916600019168152602001935050505060405180910390f35b34801561022357600080fd5b50610258600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506105ba565b604051808215151515815260200191505060405180910390f35b34801561027e57600080fd5b506102b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108aa565b604051808215151515815260200191505060405180910390f35b60608060006001805490506040519080825280602002602001820160405280156103065781602001602082028038833980820191505090505b509150600090505b6001805490508110156103ac5760018181548110151561032a57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110151561036357fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050808060010191505061030e565b819250505090565b60008060008060008060006103ca600354610539565b925092509250600354838383965096509650965050505090919293565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561043557600080fd5b600160035401851415801561044d5750600060035414155b1561045b5760009050610531565b606060405190810160405280856000191681526020018460001916815260200183600019168152506002600087815260200190815260200160002060008201518160000190600019169055602082015181600101906000191690556040820151816002019060001916905590505084600381905550847fa9b81895520c1feeea26e91ca03e455eb4be8dc9ecb34071c362e67835a6fd4285858560405180846000191660001916815260200183600019166000191681526020018260001916600019168152602001935050505060405180910390a25b949350505050565b6000806000610546610a5f565b600260008681526020019081526020016000206060604051908101604052908160008201546000191660001916815260200160018201546000191660001916815260200160028201546000191660001916815250509050806000015181602001518260400151935093509350509193909250565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561060b57600080fd5b60008060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141561065b57600092506108a3565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b60018054905082101561083b578373ffffffffffffffffffffffffffffffffffffffff166001838154811015156106d557fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561082e578190505b60018080549050038110156107cf57600180820181548110151561074057fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660018281548110151561077a57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508080600101915050610720565b6001808080549050038154811015156107e457fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600180818180549050039150816108289190610a8a565b5061083b565b81806001019250506106a2565b7f16f0165239516629af323911340c1c906029142cb0dc3c32c93ce6808d98a4ee84604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1600192505b5050919050565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156108f857600080fd5b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411156109485760009050610a5a565b60016000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018290806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507f68377f3d45858cbcc9e95998fb55b9c0f9e16b6ebf5f3602a40e2fcd0d7b8c0082604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1600190505b919050565b6060604051908101604052806000801916815260200160008019168152602001600080191681525090565b815481835581811115610ab157818360005260206000209182019101610ab09190610ab6565b5b505050565b610ad891905b80821115610ad4576000816000905550600101610abc565b5090565b905600a165627a7a72305820cbcd53f37f129054d200a6fe33ecd6996d1ac9fda6f8f3f481f7f6fdcac623260029` + +// DeployContract deploys a new Ethereum contract, binding an instance of Contract to it. +func DeployContract(auth *bind.TransactOpts, backend bind.ContractBackend, _adminlist []common.Address) (common.Address, *types.Transaction, *Contract, error) { + parsed, err := abi.JSON(strings.NewReader(ContractABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ContractBin), backend, _adminlist) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Contract{ContractCaller: ContractCaller{contract: contract}, ContractTransactor: ContractTransactor{contract: contract}, ContractFilterer: ContractFilterer{contract: contract}}, nil +} + +// Contract is an auto generated Go binding around an Ethereum contract. +type Contract struct { + ContractCaller // Read-only binding to the contract + ContractTransactor // Write-only binding to the contract + ContractFilterer // Log filterer for contract events +} + +// ContractCaller is an auto generated read-only Go binding around an Ethereum contract. +type ContractCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContractTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ContractTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ContractFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContractSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ContractSession struct { + Contract *Contract // 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 +} + +// ContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ContractCallerSession struct { + Contract *ContractCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ContractTransactorSession struct { + Contract *ContractTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ContractRaw is an auto generated low-level Go binding around an Ethereum contract. +type ContractRaw struct { + Contract *Contract // Generic contract binding to access the raw methods on +} + +// ContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ContractCallerRaw struct { + Contract *ContractCaller // Generic read-only contract binding to access the raw methods on +} + +// ContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ContractTransactorRaw struct { + Contract *ContractTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewContract creates a new instance of Contract, bound to a specific deployed contract. +func NewContract(address common.Address, backend bind.ContractBackend) (*Contract, error) { + contract, err := bindContract(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Contract{ContractCaller: ContractCaller{contract: contract}, ContractTransactor: ContractTransactor{contract: contract}, ContractFilterer: ContractFilterer{contract: contract}}, nil +} + +// NewContractCaller creates a new read-only instance of Contract, bound to a specific deployed contract. +func NewContractCaller(address common.Address, caller bind.ContractCaller) (*ContractCaller, error) { + contract, err := bindContract(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ContractCaller{contract: contract}, nil +} + +// NewContractTransactor creates a new write-only instance of Contract, bound to a specific deployed contract. +func NewContractTransactor(address common.Address, transactor bind.ContractTransactor) (*ContractTransactor, error) { + contract, err := bindContract(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ContractTransactor{contract: contract}, nil +} + +// NewContractFilterer creates a new log filterer instance of Contract, bound to a specific deployed contract. +func NewContractFilterer(address common.Address, filterer bind.ContractFilterer) (*ContractFilterer, error) { + contract, err := bindContract(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ContractFilterer{contract: contract}, nil +} + +// bindContract binds a generic wrapper to an already deployed contract. +func bindContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(ContractABI)) + 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 (_Contract *ContractRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _Contract.Contract.ContractCaller.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 (_Contract *ContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Contract.Contract.ContractTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Contract *ContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Contract.Contract.ContractTransactor.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 (_Contract *ContractCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _Contract.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 (_Contract *ContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Contract.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Contract *ContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Contract.Contract.contract.Transact(opts, method, params...) +} + +// GetAllAdmin is a free data retrieval call binding the contract method 0x45848dfc. +// +// Solidity: function GetAllAdmin() constant returns(address[]) +func (_Contract *ContractCaller) GetAllAdmin(opts *bind.CallOpts) ([]common.Address, error) { + var ( + ret0 = new([]common.Address) + ) + out := ret0 + err := _Contract.contract.Call(opts, out, "GetAllAdmin") + return *ret0, err +} + +// GetAllAdmin is a free data retrieval call binding the contract method 0x45848dfc. +// +// Solidity: function GetAllAdmin() constant returns(address[]) +func (_Contract *ContractSession) GetAllAdmin() ([]common.Address, error) { + return _Contract.Contract.GetAllAdmin(&_Contract.CallOpts) +} + +// GetAllAdmin is a free data retrieval call binding the contract method 0x45848dfc. +// +// Solidity: function GetAllAdmin() constant returns(address[]) +func (_Contract *ContractCallerSession) GetAllAdmin() ([]common.Address, error) { + return _Contract.Contract.GetAllAdmin(&_Contract.CallOpts) +} + +// GetCheckpoint is a free data retrieval call binding the contract method 0x710aeac8. +// +// Solidity: function GetCheckpoint(_sectionIndex uint256) constant returns(bytes32, bytes32, bytes32) +func (_Contract *ContractCaller) GetCheckpoint(opts *bind.CallOpts, _sectionIndex *big.Int) ([32]byte, [32]byte, [32]byte, error) { + var ( + ret0 = new([32]byte) + ret1 = new([32]byte) + ret2 = new([32]byte) + ) + out := &[]interface{}{ + ret0, + ret1, + ret2, + } + err := _Contract.contract.Call(opts, out, "GetCheckpoint", _sectionIndex) + return *ret0, *ret1, *ret2, err +} + +// GetCheckpoint is a free data retrieval call binding the contract method 0x710aeac8. +// +// Solidity: function GetCheckpoint(_sectionIndex uint256) constant returns(bytes32, bytes32, bytes32) +func (_Contract *ContractSession) GetCheckpoint(_sectionIndex *big.Int) ([32]byte, [32]byte, [32]byte, error) { + return _Contract.Contract.GetCheckpoint(&_Contract.CallOpts, _sectionIndex) +} + +// GetCheckpoint is a free data retrieval call binding the contract method 0x710aeac8. +// +// Solidity: function GetCheckpoint(_sectionIndex uint256) constant returns(bytes32, bytes32, bytes32) +func (_Contract *ContractCallerSession) GetCheckpoint(_sectionIndex *big.Int) ([32]byte, [32]byte, [32]byte, error) { + return _Contract.Contract.GetCheckpoint(&_Contract.CallOpts, _sectionIndex) +} + +// GetLatestCheckpoint is a free data retrieval call binding the contract method 0x4d6a304c. +// +// Solidity: function GetLatestCheckpoint() constant returns(uint256, bytes32, bytes32, bytes32) +func (_Contract *ContractCaller) GetLatestCheckpoint(opts *bind.CallOpts) (*big.Int, [32]byte, [32]byte, [32]byte, error) { + var ( + ret0 = new(*big.Int) + ret1 = new([32]byte) + ret2 = new([32]byte) + ret3 = new([32]byte) + ) + out := &[]interface{}{ + ret0, + ret1, + ret2, + ret3, + } + err := _Contract.contract.Call(opts, out, "GetLatestCheckpoint") + return *ret0, *ret1, *ret2, *ret3, err +} + +// GetLatestCheckpoint is a free data retrieval call binding the contract method 0x4d6a304c. +// +// Solidity: function GetLatestCheckpoint() constant returns(uint256, bytes32, bytes32, bytes32) +func (_Contract *ContractSession) GetLatestCheckpoint() (*big.Int, [32]byte, [32]byte, [32]byte, error) { + return _Contract.Contract.GetLatestCheckpoint(&_Contract.CallOpts) +} + +// GetLatestCheckpoint is a free data retrieval call binding the contract method 0x4d6a304c. +// +// Solidity: function GetLatestCheckpoint() constant returns(uint256, bytes32, bytes32, bytes32) +func (_Contract *ContractCallerSession) GetLatestCheckpoint() (*big.Int, [32]byte, [32]byte, [32]byte, error) { + return _Contract.Contract.GetLatestCheckpoint(&_Contract.CallOpts) +} + +// AddAdmin is a paid mutator transaction binding the contract method 0xad6de445. +// +// Solidity: function AddAdmin(_addr address) returns(bool) +func (_Contract *ContractTransactor) AddAdmin(opts *bind.TransactOpts, _addr common.Address) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "AddAdmin", _addr) +} + +// AddAdmin is a paid mutator transaction binding the contract method 0xad6de445. +// +// Solidity: function AddAdmin(_addr address) returns(bool) +func (_Contract *ContractSession) AddAdmin(_addr common.Address) (*types.Transaction, error) { + return _Contract.Contract.AddAdmin(&_Contract.TransactOpts, _addr) +} + +// AddAdmin is a paid mutator transaction binding the contract method 0xad6de445. +// +// Solidity: function AddAdmin(_addr address) returns(bool) +func (_Contract *ContractTransactorSession) AddAdmin(_addr common.Address) (*types.Transaction, error) { + return _Contract.Contract.AddAdmin(&_Contract.TransactOpts, _addr) +} + +// RemoveAdmin is a paid mutator transaction binding the contract method 0x753f40ca. +// +// Solidity: function RemoveAdmin(_addr address) returns(bool) +func (_Contract *ContractTransactor) RemoveAdmin(opts *bind.TransactOpts, _addr common.Address) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "RemoveAdmin", _addr) +} + +// RemoveAdmin is a paid mutator transaction binding the contract method 0x753f40ca. +// +// Solidity: function RemoveAdmin(_addr address) returns(bool) +func (_Contract *ContractSession) RemoveAdmin(_addr common.Address) (*types.Transaction, error) { + return _Contract.Contract.RemoveAdmin(&_Contract.TransactOpts, _addr) +} + +// RemoveAdmin is a paid mutator transaction binding the contract method 0x753f40ca. +// +// Solidity: function RemoveAdmin(_addr address) returns(bool) +func (_Contract *ContractTransactorSession) RemoveAdmin(_addr common.Address) (*types.Transaction, error) { + return _Contract.Contract.RemoveAdmin(&_Contract.TransactOpts, _addr) +} + +// SetCheckpoint is a paid mutator transaction binding the contract method 0x651c7f49. +// +// Solidity: function SetCheckpoint(_sectionIndex uint256, _sectionHead bytes32, _chtRoot bytes32, _bloomTrieRoot bytes32) returns(bool) +func (_Contract *ContractTransactor) SetCheckpoint(opts *bind.TransactOpts, _sectionIndex *big.Int, _sectionHead [32]byte, _chtRoot [32]byte, _bloomTrieRoot [32]byte) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "SetCheckpoint", _sectionIndex, _sectionHead, _chtRoot, _bloomTrieRoot) +} + +// SetCheckpoint is a paid mutator transaction binding the contract method 0x651c7f49. +// +// Solidity: function SetCheckpoint(_sectionIndex uint256, _sectionHead bytes32, _chtRoot bytes32, _bloomTrieRoot bytes32) returns(bool) +func (_Contract *ContractSession) SetCheckpoint(_sectionIndex *big.Int, _sectionHead [32]byte, _chtRoot [32]byte, _bloomTrieRoot [32]byte) (*types.Transaction, error) { + return _Contract.Contract.SetCheckpoint(&_Contract.TransactOpts, _sectionIndex, _sectionHead, _chtRoot, _bloomTrieRoot) +} + +// SetCheckpoint is a paid mutator transaction binding the contract method 0x651c7f49. +// +// Solidity: function SetCheckpoint(_sectionIndex uint256, _sectionHead bytes32, _chtRoot bytes32, _bloomTrieRoot bytes32) returns(bool) +func (_Contract *ContractTransactorSession) SetCheckpoint(_sectionIndex *big.Int, _sectionHead [32]byte, _chtRoot [32]byte, _bloomTrieRoot [32]byte) (*types.Transaction, error) { + return _Contract.Contract.SetCheckpoint(&_Contract.TransactOpts, _sectionIndex, _sectionHead, _chtRoot, _bloomTrieRoot) +} + +// ContractAddAdminEventIterator is returned from FilterAddAdminEvent and is used to iterate over the raw logs and unpacked data for AddAdminEvent events raised by the Contract contract. +type ContractAddAdminEventIterator struct { + Event *ContractAddAdminEvent // 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 *ContractAddAdminEventIterator) 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(ContractAddAdminEvent) + 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(ContractAddAdminEvent) + 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 *ContractAddAdminEventIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ContractAddAdminEventIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ContractAddAdminEvent represents a AddAdminEvent event raised by the Contract contract. +type ContractAddAdminEvent struct { + Addr common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterAddAdminEvent is a free log retrieval operation binding the contract event 0x68377f3d45858cbcc9e95998fb55b9c0f9e16b6ebf5f3602a40e2fcd0d7b8c00. +// +// Solidity: e AddAdminEvent(addr address) +func (_Contract *ContractFilterer) FilterAddAdminEvent(opts *bind.FilterOpts) (*ContractAddAdminEventIterator, error) { + + logs, sub, err := _Contract.contract.FilterLogs(opts, "AddAdminEvent") + if err != nil { + return nil, err + } + return &ContractAddAdminEventIterator{contract: _Contract.contract, event: "AddAdminEvent", logs: logs, sub: sub}, nil +} + +// WatchAddAdminEvent is a free log subscription operation binding the contract event 0x68377f3d45858cbcc9e95998fb55b9c0f9e16b6ebf5f3602a40e2fcd0d7b8c00. +// +// Solidity: e AddAdminEvent(addr address) +func (_Contract *ContractFilterer) WatchAddAdminEvent(opts *bind.WatchOpts, sink chan<- *ContractAddAdminEvent) (event.Subscription, error) { + + logs, sub, err := _Contract.contract.WatchLogs(opts, "AddAdminEvent") + 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(ContractAddAdminEvent) + if err := _Contract.contract.UnpackLog(event, "AddAdminEvent", 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 +} + +// ContractNewCheckpointEventIterator is returned from FilterNewCheckpointEvent and is used to iterate over the raw logs and unpacked data for NewCheckpointEvent events raised by the Contract contract. +type ContractNewCheckpointEventIterator struct { + Event *ContractNewCheckpointEvent // 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 *ContractNewCheckpointEventIterator) 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(ContractNewCheckpointEvent) + 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(ContractNewCheckpointEvent) + 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 *ContractNewCheckpointEventIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ContractNewCheckpointEventIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ContractNewCheckpointEvent represents a NewCheckpointEvent event raised by the Contract contract. +type ContractNewCheckpointEvent struct { + Index *big.Int + SectionHead [32]byte + ChtRoot [32]byte + BloomTrieRoot [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterNewCheckpointEvent is a free log retrieval operation binding the contract event 0xa9b81895520c1feeea26e91ca03e455eb4be8dc9ecb34071c362e67835a6fd42. +// +// Solidity: e NewCheckpointEvent(index indexed uint256, sectionHead bytes32, chtRoot bytes32, bloomTrieRoot bytes32) +func (_Contract *ContractFilterer) FilterNewCheckpointEvent(opts *bind.FilterOpts, index []*big.Int) (*ContractNewCheckpointEventIterator, error) { + + var indexRule []interface{} + for _, indexItem := range index { + indexRule = append(indexRule, indexItem) + } + + logs, sub, err := _Contract.contract.FilterLogs(opts, "NewCheckpointEvent", indexRule) + if err != nil { + return nil, err + } + return &ContractNewCheckpointEventIterator{contract: _Contract.contract, event: "NewCheckpointEvent", logs: logs, sub: sub}, nil +} + +// WatchNewCheckpointEvent is a free log subscription operation binding the contract event 0xa9b81895520c1feeea26e91ca03e455eb4be8dc9ecb34071c362e67835a6fd42. +// +// Solidity: e NewCheckpointEvent(index indexed uint256, sectionHead bytes32, chtRoot bytes32, bloomTrieRoot bytes32) +func (_Contract *ContractFilterer) WatchNewCheckpointEvent(opts *bind.WatchOpts, sink chan<- *ContractNewCheckpointEvent, index []*big.Int) (event.Subscription, error) { + + var indexRule []interface{} + for _, indexItem := range index { + indexRule = append(indexRule, indexItem) + } + + logs, sub, err := _Contract.contract.WatchLogs(opts, "NewCheckpointEvent", indexRule) + 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(ContractNewCheckpointEvent) + if err := _Contract.contract.UnpackLog(event, "NewCheckpointEvent", 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 +} + +// ContractRemoveAdminEventIterator is returned from FilterRemoveAdminEvent and is used to iterate over the raw logs and unpacked data for RemoveAdminEvent events raised by the Contract contract. +type ContractRemoveAdminEventIterator struct { + Event *ContractRemoveAdminEvent // 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 *ContractRemoveAdminEventIterator) 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(ContractRemoveAdminEvent) + 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(ContractRemoveAdminEvent) + 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 *ContractRemoveAdminEventIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ContractRemoveAdminEventIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ContractRemoveAdminEvent represents a RemoveAdminEvent event raised by the Contract contract. +type ContractRemoveAdminEvent struct { + Addr common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRemoveAdminEvent is a free log retrieval operation binding the contract event 0x16f0165239516629af323911340c1c906029142cb0dc3c32c93ce6808d98a4ee. +// +// Solidity: e RemoveAdminEvent(addr address) +func (_Contract *ContractFilterer) FilterRemoveAdminEvent(opts *bind.FilterOpts) (*ContractRemoveAdminEventIterator, error) { + + logs, sub, err := _Contract.contract.FilterLogs(opts, "RemoveAdminEvent") + if err != nil { + return nil, err + } + return &ContractRemoveAdminEventIterator{contract: _Contract.contract, event: "RemoveAdminEvent", logs: logs, sub: sub}, nil +} + +// WatchRemoveAdminEvent is a free log subscription operation binding the contract event 0x16f0165239516629af323911340c1c906029142cb0dc3c32c93ce6808d98a4ee. +// +// Solidity: e RemoveAdminEvent(addr address) +func (_Contract *ContractFilterer) WatchRemoveAdminEvent(opts *bind.WatchOpts, sink chan<- *ContractRemoveAdminEvent) (event.Subscription, error) { + + logs, sub, err := _Contract.contract.WatchLogs(opts, "RemoveAdminEvent") + 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(ContractRemoveAdminEvent) + if err := _Contract.contract.UnpackLog(event, "RemoveAdminEvent", 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/registrar/contract/registrar.sol b/contracts/registrar/contract/registrar.sol new file mode 100644 index 0000000000..4f9fd57bcc --- /dev/null +++ b/contracts/registrar/contract/registrar.sol @@ -0,0 +1,212 @@ +pragma solidity ^0.4.24; + +/** + * @title Registrar + * @author Gary Rong + * @dev Implementation of the blockchain checkpoint information registrar. + */ +contract Registrar { + /* + Definitions + */ + + // Checkpoint represents a set of post-processed trie roots (CHT and BloomTrie) + // associated with the appropriate section head hash. + // + // It is used to start light syncing from this checkpoint + // and avoid downloading the entire header chain while still being able to securely + // access old headers/logs. + struct Checkpoint { + bytes32 sectionHead; + bytes32 chtRoot; + bytes32 bloomTrieRoot; + } + + /* + Modifiers + */ + + /** + * @dev Check whether the message sender is authorized. + */ + modifier OnlyAuthorized() { + require(admins[msg.sender] > 0); + _; + } + + /* + Events + */ + + // NewCheckpointEvent is emitted when new checkpoint is registered. + event NewCheckpointEvent(uint indexed index, bytes32 sectionHead, bytes32 chtRoot, bytes32 bloomTrieRoot); + + // AddAdminEvent is emitted when new address is accepted as admin. + event AddAdminEvent(address addr); + + // RemoveAdminEvent is emitted when an admin is removed. + event RemoveAdminEvent(address addr); + + /* + Public Functions + */ + constructor(address[] _adminlist) public { + for (uint i = 0; i < _adminlist.length; i++) { + admins[_adminlist[i]] = 1; + adminList.push(_adminlist[i]); + } + } + + /** + * @dev Get latest stable checkpoint information. + * @return section index + * @return section head + * @return cht root hash + * @return bloom trie root hash + */ + function GetLatestCheckpoint() + view + public + returns(uint, bytes32, bytes32, bytes32) { + (bytes32 sectionHead, bytes32 chtRoot, bytes32 bloomRoot) = GetCheckpoint(latest); + return (latest, sectionHead, chtRoot, bloomRoot); + } + + /** + * @dev Get a stable checkpoint information with specified section index. + * @param _sectionIndex section index + * @return section head + * @return cht root hash + * @return bloom trie root hash + */ + function GetCheckpoint(uint _sectionIndex) + view + public + returns(bytes32, bytes32, bytes32) + { + Checkpoint memory checkpoint = checkpoints[_sectionIndex]; + return (checkpoint.sectionHead, checkpoint.chtRoot, checkpoint.bloomTrieRoot); + } + + /** + * @dev Set stable checkpoint information. + * + * Note we trust the given information here provided by foundation, + * need a trust less version for future. + * @param _sectionIndex section index + * @param _sectionHead section header + * @param _chtRoot cht root hash + * @param _bloomTrieRoot bloom trie root hash + * @return indicator whether set checkpoint successfully + */ + function SetCheckpoint( + uint _sectionIndex, + bytes32 _sectionHead, + bytes32 _chtRoot, + bytes32 _bloomTrieRoot + ) + OnlyAuthorized + public + returns(bool) + { + // Ensure the checkpoint information provided is strictly continuous with previous one. + if (_sectionIndex != latest + 1 && latest != 0) { + return false; + } + checkpoints[_sectionIndex] = Checkpoint({ + sectionHead: _sectionHead, + chtRoot: _chtRoot, + bloomTrieRoot: _bloomTrieRoot + }); + latest = _sectionIndex; + + emit NewCheckpointEvent(_sectionIndex, _sectionHead, _chtRoot, _bloomTrieRoot); + } + + /** + * @dev Add a new address to admin list + * @param _addr specified new admin address. + * @return indicator whether add new admin successfully + */ + function AddAdmin(address _addr) + OnlyAuthorized + public + returns(bool) + { + // Ensure the specified address is not admin yet. + if (admins[_addr] > 0) { + return false; + } + admins[_addr] = 1; + adminList.push(_addr); + + emit AddAdminEvent(_addr); + return true; + } + + /** + * @dev Remove a admin from the list + * @param _addr specified admin address to remove. + * @return indicator whether remove admin successfully + */ + function RemoveAdmin(address _addr) + OnlyAuthorized + public + returns(bool) + { + // Ensure the specified address is admin. + if (admins[_addr] == 0) { + return false; + } + delete admins[_addr]; + for (uint i = 0; i < adminList.length; i++) { + if (adminList[i] == _addr) { + // Not leave a gap + for (uint idx = i; idx < adminList.length-1; idx++){ + adminList[idx] = adminList[idx+1]; + } + delete adminList[adminList.length-1]; + adminList.length -= 1; + break; + } + } + + emit RemoveAdminEvent(_addr); + return true; + } + + + /** + * @dev Get all admin addresses + * @return address list + */ + function GetAllAdmin() + public + view + returns(address[]) + { + address[] memory ret = new address[](adminList.length); + for (uint i = 0; i < adminList.length; i++) { + ret[i] = adminList[i]; + } + return ret; + } + + /* + Fields + */ + + // A map of admin users who have the permission to update CHT and bloom Trie root + mapping(address => uint) admins; + + // A list of admin users so that we can obtain all admin users. + address[] adminList; + + // Registered checkpoint information + mapping(uint => Checkpoint) checkpoints; + + // Latest stored section id + // Note all registered checkpoint information should continuous with previous one. + uint latest; +} + From 8f0e1537bba14031152315a46ad7f047f3b5eec5 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 4 Jun 2018 14:31:44 +0800 Subject: [PATCH 02/15] eth, internal: implements contract backend --- eth/bind.go | 181 +++++++++++++++++++++++++++++++++++++ eth/filters/api.go | 5 + internal/ethapi/backend.go | 3 + 3 files changed, 189 insertions(+) create mode 100644 eth/bind.go diff --git a/eth/bind.go b/eth/bind.go new file mode 100644 index 0000000000..21259b3e50 --- /dev/null +++ b/eth/bind.go @@ -0,0 +1,181 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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. +// +// The go-ethereum library 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 the go-ethereum library. If not, see . + +package eth + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/filters" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" +) + +// ContractBackend implements bind.ContractBackend with direct calls to Ethereum +// internals to support operating on contracts within subprotocols like eth, les and +// swarm. +// +// Internally this backend uses the already exposed API endpoints of the Ethereum +// object. These should be rewritten to internal Go method calls when the Go API +// is refactored to support a clean library use. +type ContractBackend struct { + eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata + bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data + txapi *ethapi.PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data + filterapi *filters.PublicFilterAPI // Wrapper around the filter to watch and retrieve contract logs +} + +// NewContractBackend creates a new native contract backend using an existing +// Ethereum object. +func NewContractBackend(apiBackend ethapi.Backend, lightMode bool) *ContractBackend { + return &ContractBackend{ + eapi: ethapi.NewPublicEthereumAPI(apiBackend), + bcapi: ethapi.NewPublicBlockChainAPI(apiBackend), + txapi: ethapi.NewPublicTransactionPoolAPI(apiBackend, new(ethapi.AddrLocker)), + filterapi: filters.NewPublicFilterAPI(apiBackend.(filters.Backend), lightMode), + } +} + +// CodeAt implements bind.ContractCaller retrieving any code associated +// with the contract from the local API. +func (b *ContractBackend) CodeAt(ctx context.Context, contract common.Address, blockNum *big.Int) ([]byte, error) { + return b.bcapi.GetCode(ctx, contract, toBlockNumber(blockNum)) +} + +// ContractCall implements bind.ContractCaller executing an Ethereum contract +// call with the specified data as the input. The pending flag requests execution +// against the pending block, not the stable head of the chain. +func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNum *big.Int) ([]byte, error) { + out, err := b.bcapi.Call(ctx, toCallArgs(msg), toBlockNumber(blockNum)) + return out, err +} + +// PendingCodeAt implements bind.ContractTransactor retrieving any code associated +// with the contract from the local API. +func (b *ContractBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { + return b.bcapi.GetCode(ctx, contract, rpc.PendingBlockNumber) +} + +// PendingAccountNonce implements bind.ContractTransactor retrieving the current +// pending nonce associated with an account. +func (b *ContractBackend) PendingNonceAt(ctx context.Context, account common.Address) (nonce uint64, err error) { + out, err := b.txapi.GetTransactionCount(ctx, account, rpc.PendingBlockNumber) + if out != nil { + nonce = uint64(*out) + } + return nonce, err +} + +// SuggestGasPrice implements bind.ContractTransactor retrieving the currently +// suggested gas price to allow a timely execution of a transaction. +func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { + return b.eapi.GasPrice(ctx) +} + +// EstimateGasLimit implements bind.ContractTransactor trying to estimate the gas +// needed to execute a specific transaction based on the current pending state of +// the backend blockchain. There is no guarantee that this is the true gas limit +// requirement as other transactions may be added or removed by miners, but it +// should provide a basis for setting a reasonable default. +func (b *ContractBackend) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) { + gas, err := b.bcapi.EstimateGas(ctx, toCallArgs(msg)) + return uint64(gas), err +} + +// SendTransaction implements bind.ContractTransactor injecting the transaction +// into the pending pool for execution. +func (b *ContractBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { + raw, _ := rlp.EncodeToBytes(tx) + _, err := b.txapi.SendRawTransaction(ctx, raw) + return err +} + +// FilterLogs implements bind.ContractFilterer returning logs matching the given argument +// that are stored within the state. +func (b *ContractBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { + ret, err := b.filterapi.GetLogs(ctx, filters.FilterCriteria(query)) + if err != nil { + return nil, err + } + logs := make([]types.Log, len(ret)) + for idx, log := range ret { + logs[idx] = *log + } + return logs, nil +} + +// SubscribeFilterLogs implements bind.ContractFilterer watching new fired logs matching the given argument. +func (b *ContractBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { + // Subscribe to contract events + sink := make(chan []*types.Log) + + sub, err := b.filterapi.EventSystem().SubscribeLogs(query, sink) + if err != nil { + return nil, err + } + // Since we're getting logs in batches, we need to flatten them into a plain stream + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case logs := <-sink: + for _, log := range logs { + select { + case ch <- *log: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs { + args := ethapi.CallArgs{ + To: msg.To, + From: msg.From, + Data: msg.Data, + Gas: hexutil.Uint64(msg.Gas), + } + if msg.GasPrice != nil { + args.GasPrice = hexutil.Big(*msg.GasPrice) + } + if msg.Value != nil { + args.Value = hexutil.Big(*msg.Value) + } + return args +} + +func toBlockNumber(num *big.Int) rpc.BlockNumber { + if num == nil { + return rpc.LatestBlockNumber + } + return rpc.BlockNumber(num.Int64()) +} diff --git a/eth/filters/api.go b/eth/filters/api.go index 5ed80a8875..9c2cb093c9 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -75,6 +75,11 @@ func NewPublicFilterAPI(backend Backend, lightMode bool) *PublicFilterAPI { return api } +// EventSystem returns +func (filter *PublicFilterAPI) EventSystem() *EventSystem { + return filter.events +} + // timeoutLoop runs every 5 minutes and deletes filters that have not been recently used. // Tt is started when the api is created. func (api *PublicFilterAPI) timeoutLoop() { diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index c9ffe230c6..444f051652 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -44,6 +45,8 @@ type Backend interface { ChainDb() ethdb.Database EventMux() *event.TypeMux AccountManager() *accounts.Manager + BloomStatus() (uint64, uint64) + ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) // BlockChain API SetHead(number uint64) From 1f2f7ea18eb5a7c3f96327667c8b1d966a0acb0d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 4 Jun 2018 19:43:53 +0800 Subject: [PATCH 03/15] contracts: add registrar wrapper and unittests --- accounts/abi/bind/backends/simulated.go | 22 ++++ contracts/registrar/contract/registrar.go | 2 +- contracts/registrar/contract/registrar.sol | 14 ++ contracts/registrar/registrar.go | 88 +++++++++++++ contracts/registrar/registrar_test.go | 142 +++++++++++++++++++++ 5 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 contracts/registrar/registrar.go create mode 100644 contracts/registrar/registrar_test.go diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index fa8828f61b..336c59e5b9 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -405,6 +405,28 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { return nil } +// ShiftBlocks inserts a batch of empty blocks to blockchain. +func (b *SimulatedBackend) ShiftBlocks(number int) error { + b.mu.Lock() + defer b.mu.Unlock() + // Insert a batch of empty blocks and commit to the database + blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, number, func(i int, block *core.BlockGen) {}) + if _, err := b.blockchain.InsertChain(blocks); err != nil { + panic(err) // This cannot happen unless the simulator is wrong, fail in that case + } + // Apply all pending transactions to new pending blocks. + blocks, _ = core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { + for _, tx := range b.pendingBlock.Transactions() { + block.AddTx(tx) + } + }) + + statedb, _ := b.blockchain.State() + b.pendingBlock = blocks[0] + b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) + return nil +} + // callmsg implements core.Message to allow passing it as a transaction simulator. type callmsg struct { ethereum.CallMsg diff --git a/contracts/registrar/contract/registrar.go b/contracts/registrar/contract/registrar.go index c8db5de473..ebb292e9ef 100644 --- a/contracts/registrar/contract/registrar.go +++ b/contracts/registrar/contract/registrar.go @@ -19,7 +19,7 @@ import ( const ContractABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"GetAllAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetLatestCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"},{\"name\":\"_sectionHead\",\"type\":\"bytes32\"},{\"name\":\"_chtRoot\",\"type\":\"bytes32\"},{\"name\":\"_bloomTrieRoot\",\"type\":\"bytes32\"}],\"name\":\"SetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"}],\"name\":\"GetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"RemoveAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"AddAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_adminlist\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"index\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"sectionHead\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"chtRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"bloomTrieRoot\",\"type\":\"bytes32\"}],\"name\":\"NewCheckpointEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"AddAdminEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"RemoveAdminEvent\",\"type\":\"event\"}]" // ContractBin is the compiled bytecode used for deploying new contracts. -const ContractBin = `608060405234801561001057600080fd5b50604051610c3f380380610c3f8339810180604052810190808051820192919050505060008090505b8151811015610127576001600080848481518110151561005557fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600182828151811015156100ad57fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508080600101915050610039565b5050610b07806101386000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806345848dfc1461007d5780634d6a304c146100e9578063651c7f4914610141578063710aeac8146101b0578063753f40ca14610217578063ad6de44514610272575b600080fd5b34801561008957600080fd5b506100926102cd565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156100d55780820151818401526020810190506100ba565b505050509050019250505060405180910390f35b3480156100f557600080fd5b506100fe6103b4565b6040518085815260200184600019166000191681526020018360001916600019168152602001826000191660001916815260200194505050505060405180910390f35b34801561014d57600080fd5b50610196600480360381019080803590602001909291908035600019169060200190929190803560001916906020019092919080356000191690602001909291905050506103e7565b604051808215151515815260200191505060405180910390f35b3480156101bc57600080fd5b506101db60048036038101908080359060200190929190505050610539565b60405180846000191660001916815260200183600019166000191681526020018260001916600019168152602001935050505060405180910390f35b34801561022357600080fd5b50610258600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506105ba565b604051808215151515815260200191505060405180910390f35b34801561027e57600080fd5b506102b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108aa565b604051808215151515815260200191505060405180910390f35b60608060006001805490506040519080825280602002602001820160405280156103065781602001602082028038833980820191505090505b509150600090505b6001805490508110156103ac5760018181548110151561032a57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110151561036357fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050808060010191505061030e565b819250505090565b60008060008060008060006103ca600354610539565b925092509250600354838383965096509650965050505090919293565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561043557600080fd5b600160035401851415801561044d5750600060035414155b1561045b5760009050610531565b606060405190810160405280856000191681526020018460001916815260200183600019168152506002600087815260200190815260200160002060008201518160000190600019169055602082015181600101906000191690556040820151816002019060001916905590505084600381905550847fa9b81895520c1feeea26e91ca03e455eb4be8dc9ecb34071c362e67835a6fd4285858560405180846000191660001916815260200183600019166000191681526020018260001916600019168152602001935050505060405180910390a25b949350505050565b6000806000610546610a5f565b600260008681526020019081526020016000206060604051908101604052908160008201546000191660001916815260200160018201546000191660001916815260200160028201546000191660001916815250509050806000015181602001518260400151935093509350509193909250565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561060b57600080fd5b60008060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141561065b57600092506108a3565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b60018054905082101561083b578373ffffffffffffffffffffffffffffffffffffffff166001838154811015156106d557fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561082e578190505b60018080549050038110156107cf57600180820181548110151561074057fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660018281548110151561077a57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508080600101915050610720565b6001808080549050038154811015156107e457fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600180818180549050039150816108289190610a8a565b5061083b565b81806001019250506106a2565b7f16f0165239516629af323911340c1c906029142cb0dc3c32c93ce6808d98a4ee84604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1600192505b5050919050565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156108f857600080fd5b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411156109485760009050610a5a565b60016000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018290806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507f68377f3d45858cbcc9e95998fb55b9c0f9e16b6ebf5f3602a40e2fcd0d7b8c0082604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1600190505b919050565b6060604051908101604052806000801916815260200160008019168152602001600080191681525090565b815481835581811115610ab157818360005260206000209182019101610ab09190610ab6565b5b505050565b610ad891905b80821115610ad4576000816000905550600101610abc565b5090565b905600a165627a7a72305820cbcd53f37f129054d200a6fe33ecd6996d1ac9fda6f8f3f481f7f6fdcac623260029` +const ContractBin = `608060405234801561001057600080fd5b50604051610d06380380610d0683398101806040528101908080518201929190505050600060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060013390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600090505b81518110156101d2576001600080848481518110151561010057fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001828281518110151561015857fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505080806001019150506100e4565b5050610b23806101e36000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806345848dfc1461007d5780634d6a304c146100e9578063651c7f4914610141578063710aeac8146101b0578063753f40ca14610217578063ad6de44514610272575b600080fd5b34801561008957600080fd5b506100926102cd565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156100d55780820151818401526020810190506100ba565b505050509050019250505060405180910390f35b3480156100f557600080fd5b506100fe6103b4565b6040518085815260200184600019166000191681526020018360001916600019168152602001826000191660001916815260200194505050505060405180910390f35b34801561014d57600080fd5b50610196600480360381019080803590602001909291908035600019169060200190929190803560001916906020019092919080356000191690602001909291905050506103e7565b604051808215151515815260200191505060405180910390f35b3480156101bc57600080fd5b506101db60048036038101908080359060200190929190505050610555565b60405180846000191660001916815260200183600019166000191681526020018260001916600019168152602001935050505060405180910390f35b34801561022357600080fd5b50610258600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506105d6565b604051808215151515815260200191505060405180910390f35b34801561027e57600080fd5b506102b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108c6565b604051808215151515815260200191505060405180910390f35b60608060006001805490506040519080825280602002602001820160405280156103065781602001602082028038833980820191505090505b509150600090505b6001805490508110156103ac5760018181548110151561032a57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110151561036357fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050808060010191505061030e565b819250505090565b60008060008060008060006103ca600354610555565b925092509250600354838383965096509650965050505090919293565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561043557600080fd5b600160035401851415801561044d5750600060035414155b1561045b576000905061054d565b612710618000600187010201431015610477576000905061054d565b606060405190810160405280856000191681526020018460001916815260200183600019168152506002600087815260200190815260200160002060008201518160000190600019169055602082015181600101906000191690556040820151816002019060001916905590505084600381905550847fa9b81895520c1feeea26e91ca03e455eb4be8dc9ecb34071c362e67835a6fd4285858560405180846000191660001916815260200183600019166000191681526020018260001916600019168152602001935050505060405180910390a25b949350505050565b6000806000610562610a7b565b600260008681526020019081526020016000206060604051908101604052908160008201546000191660001916815260200160018201546000191660001916815260200160028201546000191660001916815250509050806000015181602001518260400151935093509350509193909250565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561062757600080fd5b60008060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141561067757600092506108bf565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b600180549050821015610857578373ffffffffffffffffffffffffffffffffffffffff166001838154811015156106f157fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561084a578190505b60018080549050038110156107eb57600180820181548110151561075c57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660018281548110151561079657fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808060010191505061073c565b60018080805490500381548110151561080057fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600180818180549050039150816108449190610aa6565b50610857565b81806001019250506106be565b7f16f0165239516629af323911340c1c906029142cb0dc3c32c93ce6808d98a4ee84604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1600192505b5050919050565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561091457600080fd5b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411156109645760009050610a76565b60016000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018290806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507f68377f3d45858cbcc9e95998fb55b9c0f9e16b6ebf5f3602a40e2fcd0d7b8c0082604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1600190505b919050565b6060604051908101604052806000801916815260200160008019168152602001600080191681525090565b815481835581811115610acd57818360005260206000209182019101610acc9190610ad2565b5b505050565b610af491905b80821115610af0576000816000905550600101610ad8565b5090565b905600a165627a7a72305820de9e3481e0a4d931d0b0a0a34b53b4315479499d7deb6724e5de6d1f439d44e70029` // DeployContract deploys a new Ethereum contract, binding an instance of Contract to it. func DeployContract(auth *bind.TransactOpts, backend bind.ContractBackend, _adminlist []common.Address) (common.Address, *types.Transaction, *Contract, error) { diff --git a/contracts/registrar/contract/registrar.sol b/contracts/registrar/contract/registrar.sol index 4f9fd57bcc..cb92b92d39 100644 --- a/contracts/registrar/contract/registrar.sol +++ b/contracts/registrar/contract/registrar.sol @@ -51,6 +51,9 @@ contract Registrar { Public Functions */ constructor(address[] _adminlist) public { + // regard contract creator as a default admin. + admins[msg.sender] = 1; + adminList.push(msg.sender); for (uint i = 0; i < _adminlist.length; i++) { admins[_adminlist[i]] = 1; adminList.push(_adminlist[i]); @@ -113,6 +116,11 @@ contract Registrar { if (_sectionIndex != latest + 1 && latest != 0) { return false; } + // Ensure the checkpoint is stable enough to be registered. + if (block.number < (_sectionIndex+1)*sectionSize+confirmations) { + return false; + } + checkpoints[_sectionIndex] = Checkpoint({ sectionHead: _sectionHead, chtRoot: _chtRoot, @@ -208,5 +216,11 @@ contract Registrar { // Latest stored section id // Note all registered checkpoint information should continuous with previous one. uint latest; + + // The frequency for creating a checkpoint + uint constant sectionSize = 32768; + + // The number of confirmations needed before a checkpoint can be registered. + uint constant confirmations = 10000; } diff --git a/contracts/registrar/registrar.go b/contracts/registrar/registrar.go new file mode 100644 index 0000000000..6860ef39ce --- /dev/null +++ b/contracts/registrar/registrar.go @@ -0,0 +1,88 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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. +// +// The go-ethereum library 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 the go-ethereum library. If not, see . + +package registrar + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/contracts/registrar/contract" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/internal/ethapi" +) + +var ( + MainNetAddr = common.HexToAddress("") + TestNetAddr = common.HexToAddress("0x3b934494985d17bcb49557671e1bc8ec32cccdd5") // Rinkeby +) + +var errEventNotFound = errors.New("contract event not found") + +const ( + sectionSize = 32768 // The frequency for creating a checkpoint + checkpointConfirmation = 10000 // The number of confirmations needed before a checkpoint becoming stable. +) + +// Checkpoint represents a set of post-processed trie roots (CHT and BloomTrie) associated with +// the appropriate section index and head hash. +// +// It is used to start light syncing from this checkpoint and avoid downloading the entire header chain +// while still being able to securely access old headers/logs. +type Checkpoint struct { + SectionIndex uint64 + SectionHead common.Hash // Block Hash for the last block in the section + ChtRoot common.Hash // CHT(Canonical Hash Trie) root associated to the section + BloomTrieRoot common.Hash // Bloom Trie root associated to the section +} + +type Registrar struct { + contract *contract.Contract +} + +// NewRegistrar binds checkpoint contract and returns a registrar instance. +func NewRegistrar(contractAddr common.Address, backend ethapi.Backend, lightMode bool) (*Registrar, error) { + contract, err := contract.NewContract(contractAddr, eth.NewContractBackend(backend, lightMode)) + if err != nil { + return nil, err + } + + return &Registrar{ + contract: contract, + }, nil +} + +// WatchNewCheckpointEvent watches new fired NewCheckpointEvent and delivers all matching events by result channel. +func (registrar *Registrar) WatchNewCheckpointEvent(sink chan<- *contract.ContractNewCheckpointEvent) (event.Subscription, error) { + return registrar.contract.WatchNewCheckpointEvent(nil, sink, nil) +} + +// FilterNewCheckpointEvent filters out NewCheckpointEvent for specific section number. +func (registrar *Registrar) FilterNewCheckpointEvent(head uint64, section uint64) (*contract.ContractNewCheckpointEventIterator, error) { + start := (section + 1) * sectionSize + end := head - checkpointConfirmation + if end < start { + return nil, errEventNotFound + } + opt := &bind.FilterOpts{ + Start: start, + End: &end, + } + return registrar.contract.FilterNewCheckpointEvent(opt, []*big.Int{big.NewInt(int64(section))}) +} diff --git a/contracts/registrar/registrar_test.go b/contracts/registrar/registrar_test.go new file mode 100644 index 0000000000..98f7dd1355 --- /dev/null +++ b/contracts/registrar/registrar_test.go @@ -0,0 +1,142 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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. +// +// The go-ethereum library 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 the go-ethereum library. If not, see . + +package registrar + +import ( + "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/registrar/contract" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr = crypto.PubkeyToAddress(key.PublicKey) + emptyHash = [32]byte{} + + trustedCheckpoint = Checkpoint{ + SectionIndex: 0, + SectionHead: common.HexToHash("14c8639dfc32812ed20839f5a11993cd59b22e5226cb2179640ba5c1f0c08f87"), + ChtRoot: common.HexToHash("cf92fd2a79464354e8dae4d589ae92acdf90a3a4f8f7d8a3ec5fb9c114ae81cd"), + BloomTrieRoot: common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), + } +) + +func TestAdminManagement(t *testing.T) { + var ( + adminCandidate = common.HexToAddress("0x123") + adminCandidate2 = common.HexToAddress("0x456") + ) + + // Deploy registrar contract + transactOpts := bind.NewKeyedTransactor(key) + contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) + _, _, contract, err := contract.DeployContract(transactOpts, contractBackend, nil) + if err != nil { + t.Error("deploy registrar contract failed", err) + } + contractBackend.Commit() + + // Test AddAdmin function + contract.AddAdmin(transactOpts, addr) // Contract should ignore the duplicate registration + contract.AddAdmin(transactOpts, adminCandidate) + contract.AddAdmin(transactOpts, adminCandidate2) + contractBackend.Commit() + adminList, err := contract.GetAllAdmin(nil) + if err != nil { + t.Error("fetch admin list failed", err) + } + if !reflect.DeepEqual(adminList, []common.Address{addr, adminCandidate, adminCandidate2}) { + t.Error("expect the returned admin list contain 3 address") + } + + // Test RemoveAdmin function (remove at the middle) + contract.RemoveAdmin(transactOpts, adminCandidate) + contractBackend.Commit() + adminList, err = contract.GetAllAdmin(nil) + if err != nil { + t.Error("fetch admin list failed", err) + } + if !reflect.DeepEqual(adminList, []common.Address{addr, adminCandidate2}) { + t.Error("expect the returned admin list contain 3 address") + } + + // Test RemoveAdmin function (remove at the head) + contract.RemoveAdmin(transactOpts, addr) + contractBackend.Commit() + adminList, err = contract.GetAllAdmin(nil) + if err != nil { + t.Error("fetch admin list failed", err) + } + if !reflect.DeepEqual(adminList, []common.Address{adminCandidate2}) { + t.Error("expect the returned admin list contain 3 address") + } + + // Test unauthorized operation + contract.AddAdmin(transactOpts, adminCandidate) + contractBackend.Commit() + adminList, err = contract.GetAllAdmin(nil) + if err != nil { + t.Error("fetch admin list failed", err) + } + if !reflect.DeepEqual(adminList, []common.Address{adminCandidate2}) { + t.Error("expect the returned admin list contain 3 address") + } +} + +func TestCheckpointRegister(t *testing.T) { + // Deploy registrar contract + transactOpts := bind.NewKeyedTransactor(key) + contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) + _, _, contract, err := contract.DeployContract(transactOpts, contractBackend, []common.Address{addr}) + if err != nil { + t.Error("deploy registrar contract failed", err) + } + contractBackend.Commit() + + // Register an unstable checkpoint + contract.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIndex)), trustedCheckpoint.SectionHead, + trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) + contractBackend.Commit() + head, chtRoot, bloomTrieRoot, err := contract.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIndex))) + if err != nil { + t.Error("fetch checkpoint failed", err) + } + if head != emptyHash || chtRoot != emptyHash || bloomTrieRoot != emptyHash { + t.Error("the unstable checkpoint is not allowed to be registered") + } + + // Register a stable checkpoint + contractBackend.ShiftBlocks(sectionSize + checkpointConfirmation) + contract.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIndex)), trustedCheckpoint.SectionHead, + trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) + contractBackend.Commit() + head, chtRoot, bloomTrieRoot, err = contract.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIndex))) + if err != nil { + t.Error("fetch checkpoint failed", err) + } + if !reflect.DeepEqual(head[:], trustedCheckpoint.SectionHead.Bytes()) || !reflect.DeepEqual(chtRoot[:], trustedCheckpoint.ChtRoot.Bytes()) || + !reflect.DeepEqual(bloomTrieRoot[:], trustedCheckpoint.BloomTrieRoot.Bytes()) { + t.Error("expect the returned checkpoint should be same with the given one") + } +} From 2da657de34583fec12543409f27910f73efb0329 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 5 Jun 2018 13:59:10 +0800 Subject: [PATCH 04/15] les: create costtable file --- les/costtable.go | 199 +++++++++++++++++++++++++++++++++++++++++++++++ les/server.go | 185 ++----------------------------------------- 2 files changed, 206 insertions(+), 178 deletions(-) create mode 100644 les/costtable.go diff --git a/les/costtable.go b/les/costtable.go new file mode 100644 index 0000000000..e651bec28f --- /dev/null +++ b/les/costtable.go @@ -0,0 +1,199 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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. +// +// The go-ethereum library 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 the go-ethereum library. If not, see . + +package les + +import ( + "encoding/binary" + "math" + "sync" + + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/rlp" +) + +type requestCosts struct { + baseCost, reqCost uint64 +} + +type requestCostTable map[uint64]*requestCosts + +type RequestCostList []struct { + MsgCode, BaseCost, ReqCost uint64 +} + +func (list RequestCostList) decode() requestCostTable { + table := make(requestCostTable) + for _, e := range list { + table[e.MsgCode] = &requestCosts{ + baseCost: e.BaseCost, + reqCost: e.ReqCost, + } + } + return table +} + +type linReg struct { + sumX, sumY, sumXX, sumXY float64 + cnt uint64 +} + +const linRegMaxCnt = 100000 + +func (l *linReg) add(x, y float64) { + if l.cnt >= linRegMaxCnt { + sub := float64(l.cnt+1-linRegMaxCnt) / linRegMaxCnt + l.sumX -= l.sumX * sub + l.sumY -= l.sumY * sub + l.sumXX -= l.sumXX * sub + l.sumXY -= l.sumXY * sub + l.cnt = linRegMaxCnt - 1 + } + l.cnt++ + l.sumX += x + l.sumY += y + l.sumXX += x * x + l.sumXY += x * y +} + +func (l *linReg) calc() (b, m float64) { + if l.cnt == 0 { + return 0, 0 + } + cnt := float64(l.cnt) + d := cnt*l.sumXX - l.sumX*l.sumX + if d < 0.001 { + return l.sumY / cnt, 0 + } + m = (cnt*l.sumXY - l.sumX*l.sumY) / d + b = (l.sumY / cnt) - (m * l.sumX / cnt) + return b, m +} + +func (l *linReg) toBytes() []byte { + var arr [40]byte + binary.BigEndian.PutUint64(arr[0:8], math.Float64bits(l.sumX)) + binary.BigEndian.PutUint64(arr[8:16], math.Float64bits(l.sumY)) + binary.BigEndian.PutUint64(arr[16:24], math.Float64bits(l.sumXX)) + binary.BigEndian.PutUint64(arr[24:32], math.Float64bits(l.sumXY)) + binary.BigEndian.PutUint64(arr[32:40], l.cnt) + return arr[:] +} + +func linRegFromBytes(data []byte) *linReg { + if len(data) != 40 { + return nil + } + l := &linReg{} + l.sumX = math.Float64frombits(binary.BigEndian.Uint64(data[0:8])) + l.sumY = math.Float64frombits(binary.BigEndian.Uint64(data[8:16])) + l.sumXX = math.Float64frombits(binary.BigEndian.Uint64(data[16:24])) + l.sumXY = math.Float64frombits(binary.BigEndian.Uint64(data[24:32])) + l.cnt = binary.BigEndian.Uint64(data[32:40]) + return l +} + +type requestCostStats struct { + lock sync.RWMutex + db ethdb.Database + stats map[uint64]*linReg +} + +type requestCostStatsRlp []struct { + MsgCode uint64 + Data []byte +} + +var rcStatsKey = []byte("_requestCostStats") + +func newCostStats(db ethdb.Database) *requestCostStats { + stats := make(map[uint64]*linReg) + for _, code := range reqList { + stats[code] = &linReg{cnt: 100} + } + + if db != nil { + data, err := db.Get(rcStatsKey) + var statsRlp requestCostStatsRlp + if err == nil { + err = rlp.DecodeBytes(data, &statsRlp) + } + if err == nil { + for _, r := range statsRlp { + if stats[r.MsgCode] != nil { + if l := linRegFromBytes(r.Data); l != nil { + stats[r.MsgCode] = l + } + } + } + } + } + + return &requestCostStats{ + db: db, + stats: stats, + } +} + +func (s *requestCostStats) store() { + s.lock.Lock() + defer s.lock.Unlock() + + statsRlp := make(requestCostStatsRlp, len(reqList)) + for i, code := range reqList { + statsRlp[i].MsgCode = code + statsRlp[i].Data = s.stats[code].toBytes() + } + + if data, err := rlp.EncodeToBytes(statsRlp); err == nil { + s.db.Put(rcStatsKey, data) + } +} + +func (s *requestCostStats) getCurrentList() RequestCostList { + s.lock.Lock() + defer s.lock.Unlock() + + list := make(RequestCostList, len(reqList)) + //fmt.Println("RequestCostList") + for idx, code := range reqList { + b, m := s.stats[code].calc() + //fmt.Println(code, s.stats[code].cnt, b/1000000, m/1000000) + if m < 0 { + b += m + m = 0 + } + if b < 0 { + b = 0 + } + + list[idx].MsgCode = code + list[idx].BaseCost = uint64(b * 2) + list[idx].ReqCost = uint64(m * 2) + } + return list +} + +func (s *requestCostStats) update(msgCode, reqCnt, cost uint64) { + s.lock.Lock() + defer s.lock.Unlock() + + c, ok := s.stats[msgCode] + if !ok || reqCnt == 0 { + return + } + c.add(float64(reqCnt), float64(cost)) +} diff --git a/les/server.go b/les/server.go index fca6124c9c..86ddb07bb9 100644 --- a/les/server.go +++ b/les/server.go @@ -19,22 +19,19 @@ package les import ( "crypto/ecdsa" - "encoding/binary" - "math" "sync" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/contracts/registrar" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/les/flowcontrol" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/discv5" - "github.com/ethereum/go-ethereum/rlp" ) type LesServer struct { @@ -47,7 +44,12 @@ type LesServer struct { privateKey *ecdsa.PrivateKey quitSync chan struct{} - chtIndexer, bloomTrieIndexer *core.ChainIndexer + // Checkpoint contract relative fields + registrar *registrar.Registrar // Handler for checkpoint contract + + // Indexers + chtIndexer *core.ChainIndexer // Indexers for creating cht root for each block section + bloomTrieIndexer *core.ChainIndexer // Indexers for creating bloom trie root for each block section } func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { @@ -142,179 +144,6 @@ func (s *LesServer) Stop() { s.protocolManager.Stop() } -type requestCosts struct { - baseCost, reqCost uint64 -} - -type requestCostTable map[uint64]*requestCosts - -type RequestCostList []struct { - MsgCode, BaseCost, ReqCost uint64 -} - -func (list RequestCostList) decode() requestCostTable { - table := make(requestCostTable) - for _, e := range list { - table[e.MsgCode] = &requestCosts{ - baseCost: e.BaseCost, - reqCost: e.ReqCost, - } - } - return table -} - -type linReg struct { - sumX, sumY, sumXX, sumXY float64 - cnt uint64 -} - -const linRegMaxCnt = 100000 - -func (l *linReg) add(x, y float64) { - if l.cnt >= linRegMaxCnt { - sub := float64(l.cnt+1-linRegMaxCnt) / linRegMaxCnt - l.sumX -= l.sumX * sub - l.sumY -= l.sumY * sub - l.sumXX -= l.sumXX * sub - l.sumXY -= l.sumXY * sub - l.cnt = linRegMaxCnt - 1 - } - l.cnt++ - l.sumX += x - l.sumY += y - l.sumXX += x * x - l.sumXY += x * y -} - -func (l *linReg) calc() (b, m float64) { - if l.cnt == 0 { - return 0, 0 - } - cnt := float64(l.cnt) - d := cnt*l.sumXX - l.sumX*l.sumX - if d < 0.001 { - return l.sumY / cnt, 0 - } - m = (cnt*l.sumXY - l.sumX*l.sumY) / d - b = (l.sumY / cnt) - (m * l.sumX / cnt) - return b, m -} - -func (l *linReg) toBytes() []byte { - var arr [40]byte - binary.BigEndian.PutUint64(arr[0:8], math.Float64bits(l.sumX)) - binary.BigEndian.PutUint64(arr[8:16], math.Float64bits(l.sumY)) - binary.BigEndian.PutUint64(arr[16:24], math.Float64bits(l.sumXX)) - binary.BigEndian.PutUint64(arr[24:32], math.Float64bits(l.sumXY)) - binary.BigEndian.PutUint64(arr[32:40], l.cnt) - return arr[:] -} - -func linRegFromBytes(data []byte) *linReg { - if len(data) != 40 { - return nil - } - l := &linReg{} - l.sumX = math.Float64frombits(binary.BigEndian.Uint64(data[0:8])) - l.sumY = math.Float64frombits(binary.BigEndian.Uint64(data[8:16])) - l.sumXX = math.Float64frombits(binary.BigEndian.Uint64(data[16:24])) - l.sumXY = math.Float64frombits(binary.BigEndian.Uint64(data[24:32])) - l.cnt = binary.BigEndian.Uint64(data[32:40]) - return l -} - -type requestCostStats struct { - lock sync.RWMutex - db ethdb.Database - stats map[uint64]*linReg -} - -type requestCostStatsRlp []struct { - MsgCode uint64 - Data []byte -} - -var rcStatsKey = []byte("_requestCostStats") - -func newCostStats(db ethdb.Database) *requestCostStats { - stats := make(map[uint64]*linReg) - for _, code := range reqList { - stats[code] = &linReg{cnt: 100} - } - - if db != nil { - data, err := db.Get(rcStatsKey) - var statsRlp requestCostStatsRlp - if err == nil { - err = rlp.DecodeBytes(data, &statsRlp) - } - if err == nil { - for _, r := range statsRlp { - if stats[r.MsgCode] != nil { - if l := linRegFromBytes(r.Data); l != nil { - stats[r.MsgCode] = l - } - } - } - } - } - - return &requestCostStats{ - db: db, - stats: stats, - } -} - -func (s *requestCostStats) store() { - s.lock.Lock() - defer s.lock.Unlock() - - statsRlp := make(requestCostStatsRlp, len(reqList)) - for i, code := range reqList { - statsRlp[i].MsgCode = code - statsRlp[i].Data = s.stats[code].toBytes() - } - - if data, err := rlp.EncodeToBytes(statsRlp); err == nil { - s.db.Put(rcStatsKey, data) - } -} - -func (s *requestCostStats) getCurrentList() RequestCostList { - s.lock.Lock() - defer s.lock.Unlock() - - list := make(RequestCostList, len(reqList)) - //fmt.Println("RequestCostList") - for idx, code := range reqList { - b, m := s.stats[code].calc() - //fmt.Println(code, s.stats[code].cnt, b/1000000, m/1000000) - if m < 0 { - b += m - m = 0 - } - if b < 0 { - b = 0 - } - - list[idx].MsgCode = code - list[idx].BaseCost = uint64(b * 2) - list[idx].ReqCost = uint64(m * 2) - } - return list -} - -func (s *requestCostStats) update(msgCode, reqCnt, cost uint64) { - s.lock.Lock() - defer s.lock.Unlock() - - c, ok := s.stats[msgCode] - if !ok || reqCnt == 0 { - return - } - c.add(float64(reqCnt), float64(cost)) -} - func (pm *ProtocolManager) blockLoop() { pm.wg.Add(1) headCh := make(chan core.ChainHeadEvent, 10) From 88004ccbc2fcd7e3bcce63c2f194bf1cd1253425 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 5 Jun 2018 18:25:54 +0800 Subject: [PATCH 05/15] light, les: watch checkpoint event and update in local --- contracts/registrar/registrar.go | 21 ++--- contracts/registrar/registrar_test.go | 15 ++-- eth/bind.go | 6 +- les/server.go | 53 +++++++++++- light/checkpoint.go | 120 ++++++++++++++++++++++++++ light/checkpoint_test.go | 45 ++++++++++ light/lightchain.go | 16 ++-- light/odr.go | 2 +- light/odr_util.go | 2 +- light/postprocess.go | 56 +++--------- params/config.go | 1 + 11 files changed, 258 insertions(+), 79 deletions(-) create mode 100644 light/checkpoint.go create mode 100644 light/checkpoint_test.go diff --git a/contracts/registrar/registrar.go b/contracts/registrar/registrar.go index 6860ef39ce..9ef1f7e062 100644 --- a/contracts/registrar/registrar.go +++ b/contracts/registrar/registrar.go @@ -26,11 +26,16 @@ import ( "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/params" ) var ( - MainNetAddr = common.HexToAddress("") - TestNetAddr = common.HexToAddress("0x3b934494985d17bcb49557671e1bc8ec32cccdd5") // Rinkeby + // registrar contract address for mainnet or test chain. + RegistrarAddr = map[common.Hash]common.Address{ + params.MainnetGenesisHash: common.HexToAddress(""), + params.TestnetGenesisHash: common.HexToAddress(""), + params.RinkebyGenesisHash: common.HexToAddress("0x3b934494985d17bcb49557671e1bc8ec32cccdd5"), + } ) var errEventNotFound = errors.New("contract event not found") @@ -40,18 +45,6 @@ const ( checkpointConfirmation = 10000 // The number of confirmations needed before a checkpoint becoming stable. ) -// Checkpoint represents a set of post-processed trie roots (CHT and BloomTrie) associated with -// the appropriate section index and head hash. -// -// It is used to start light syncing from this checkpoint and avoid downloading the entire header chain -// while still being able to securely access old headers/logs. -type Checkpoint struct { - SectionIndex uint64 - SectionHead common.Hash // Block Hash for the last block in the section - ChtRoot common.Hash // CHT(Canonical Hash Trie) root associated to the section - BloomTrieRoot common.Hash // Bloom Trie root associated to the section -} - type Registrar struct { contract *contract.Contract } diff --git a/contracts/registrar/registrar_test.go b/contracts/registrar/registrar_test.go index 98f7dd1355..6c07b02629 100644 --- a/contracts/registrar/registrar_test.go +++ b/contracts/registrar/registrar_test.go @@ -27,15 +27,16 @@ import ( "github.com/ethereum/go-ethereum/contracts/registrar/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/light" ) var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key, _ = crypto.GenerateKey() addr = crypto.PubkeyToAddress(key.PublicKey) emptyHash = [32]byte{} - trustedCheckpoint = Checkpoint{ - SectionIndex: 0, + trustedCheckpoint = light.TrustedCheckpoint{ + SectionIdx: 0, SectionHead: common.HexToHash("14c8639dfc32812ed20839f5a11993cd59b22e5226cb2179640ba5c1f0c08f87"), ChtRoot: common.HexToHash("cf92fd2a79464354e8dae4d589ae92acdf90a3a4f8f7d8a3ec5fb9c114ae81cd"), BloomTrieRoot: common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), @@ -115,10 +116,10 @@ func TestCheckpointRegister(t *testing.T) { contractBackend.Commit() // Register an unstable checkpoint - contract.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIndex)), trustedCheckpoint.SectionHead, + contract.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) contractBackend.Commit() - head, chtRoot, bloomTrieRoot, err := contract.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIndex))) + head, chtRoot, bloomTrieRoot, err := contract.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) if err != nil { t.Error("fetch checkpoint failed", err) } @@ -128,10 +129,10 @@ func TestCheckpointRegister(t *testing.T) { // Register a stable checkpoint contractBackend.ShiftBlocks(sectionSize + checkpointConfirmation) - contract.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIndex)), trustedCheckpoint.SectionHead, + contract.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) contractBackend.Commit() - head, chtRoot, bloomTrieRoot, err = contract.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIndex))) + head, chtRoot, bloomTrieRoot, err = contract.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) if err != nil { t.Error("fetch checkpoint failed", err) } diff --git a/eth/bind.go b/eth/bind.go index 21259b3e50..7119114519 100644 --- a/eth/bind.go +++ b/eth/bind.go @@ -89,7 +89,11 @@ func (b *ContractBackend) PendingNonceAt(ctx context.Context, account common.Add // SuggestGasPrice implements bind.ContractTransactor retrieving the currently // suggested gas price to allow a timely execution of a transaction. func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { - return b.eapi.GasPrice(ctx) + price, err := b.eapi.GasPrice(ctx) + if err != nil { + return nil, err + } + return (*big.Int)(price), nil } // EstimateGasLimit implements bind.ContractTransactor trying to estimate the gas diff --git a/les/server.go b/les/server.go index 86ddb07bb9..ec276d1aa2 100644 --- a/les/server.go +++ b/les/server.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/registrar" + "github.com/ethereum/go-ethereum/contracts/registrar/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" @@ -44,8 +45,9 @@ type LesServer struct { privateKey *ecdsa.PrivateKey quitSync chan struct{} - // Checkpoint contract relative fields - registrar *registrar.Registrar // Handler for checkpoint contract + // Checkpoint relative fields + registrar *registrar.Registrar // Handler for checkpoint contract + stableCheckpoint *light.TrustedCheckpoint // The nearest stable checkpoint // Indexers chtIndexer *core.ChainIndexer // Indexers for creating cht root for each block section @@ -102,6 +104,13 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { } srv.fcManager = flowcontrol.NewClientManager(uint64(config.LightServ), 10, 1000000000) srv.fcCostStats = newCostStats(eth.ChainDb()) + if addr, ok := registrar.RegistrarAddr[eth.BlockChain().Genesis().Hash()]; ok { + registrar, err := registrar.NewRegistrar(addr, eth.APIBackend, false) + if err != nil { + return nil, err + } + srv.registrar = registrar + } return srv, nil } @@ -126,6 +135,9 @@ func (s *LesServer) Start(srvr *p2p.Server) { } s.privateKey = srvr.PrivateKey s.protocolManager.blockLoop() + if s.registrar != nil { + s.checkpointLoop() + } } func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) { @@ -142,6 +154,43 @@ func (s *LesServer) Stop() { <-s.protocolManager.noMorePeers }() s.protocolManager.Stop() + close(s.quitSync) +} + +// checkpointLoop starts a standalone goroutine to watch new checkpoint event and upgrades local's stable checkpoint. +func (s *LesServer) checkpointLoop() (err error) { + sink := make(chan *contract.ContractNewCheckpointEvent) + sub, err := s.registrar.WatchNewCheckpointEvent(sink) + if err != nil { + return + } + defer func() { + sub.Unsubscribe() + }() + + for { + select { + case event := <-sink: + // New stable checkpoint received + // Note several duplicate events can be received due to chain reorg, just track the first arrive one. + if event.Index.Uint64() > s.stableCheckpoint.SectionIdx { + checkpoint := &light.TrustedCheckpoint{ + SectionIdx: event.Index.Uint64(), + SectionHead: common.Hash(event.SectionHead), + ChtRoot: common.Hash(event.ChtRoot), + BloomTrieRoot: common.Hash(event.BloomTrieRoot), + } + light.WriteTrustedCheckpoint(s.protocolManager.chainDb, checkpoint) + s.stableCheckpoint = checkpoint + log.Info("update checkpoint", "section", checkpoint.SectionIdx, "head", checkpoint.SectionHead.Hex(), + "chtRoot", checkpoint.ChtRoot.Hex(), "bloomTrieRoot", checkpoint.BloomTrieRoot.Hex()) + } + + case <-s.quitSync: + // Les server is closed. + return + } + } } func (pm *ProtocolManager) blockLoop() { diff --git a/light/checkpoint.go b/light/checkpoint.go new file mode 100644 index 0000000000..192471f30f --- /dev/null +++ b/light/checkpoint.go @@ -0,0 +1,120 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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. +// +// The go-ethereum library 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 the go-ethereum library. If not, see . + +package light + +import ( + "io" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" +) + +var ( + // checkpointKey tracks the latest stable checkpoint. + checkpointKey = []byte("Checkpoint") +) + +// TrustedCheckpoint represents a set of post-processed trie roots (CHT and BloomTrie) associated with +// the appropriate section index and head hash. +// +// It is used to start light syncing from this checkpoint and avoid downloading the entire header chain +// while still being able to securely access old headers/logs. +type TrustedCheckpoint struct { + Name string // Indicator which chain the checkpoint belongs to + SectionIdx uint64 // Section index + SectionHead common.Hash // Block Hash for the last block in the section + ChtRoot common.Hash // CHT(Canonical Hash Trie) root associated to the section + BloomTrieRoot common.Hash // Bloom Trie root associated to the section +} + +type trustCheckpointRLP struct { + SectionIdx uint64 + SectionHead common.Hash + ChtRoot common.Hash + BloomTrieRoot common.Hash +} + +// EncodeRLP implements rlp.Encoder, and flattens the necessary fields of a checkpoint +// into an RLP stream. +func (c *TrustedCheckpoint) EncodeRLP(w io.Writer) (err error) { + return rlp.Encode(w, &trustCheckpointRLP{c.SectionIdx, c.SectionHead, c.ChtRoot, c.BloomTrieRoot}) +} + +// DecodeRLP implements rlp.Decoder, and loads the necessary fields of a checkpoint +// from an RLP stream. +func (c *TrustedCheckpoint) DecodeRLP(s *rlp.Stream) error { + var dec trustCheckpointRLP + if err := s.Decode(&dec); err != nil { + return err + } + c.SectionIdx, c.SectionHead, c.ChtRoot, c.BloomTrieRoot = dec.SectionIdx, dec.SectionHead, dec.ChtRoot, dec.BloomTrieRoot + return nil +} + +var ( + // Hardcode checkpoint for mainnet and testnet(ropsten). Will be deleted eventually once checkpoint contract + // works. + mainnetCheckpoint = TrustedCheckpoint{ + Name: "mainnet", + SectionIdx: 179, + SectionHead: common.HexToHash("ae778e455492db1183e566fa0c67f954d256fdd08618f6d5a393b0e24576d0ea"), + ChtRoot: common.HexToHash("646b338f9ca74d936225338916be53710ec84020b89946004a8605f04c817f16"), + BloomTrieRoot: common.HexToHash("d0f978f5dbc86e5bf931d8dd5b2ecbebbda6dc78f8896af6a27b46a3ced0ac25"), + } + + ropstenCheckpoint = TrustedCheckpoint{ + Name: "ropsten", + SectionIdx: 107, + SectionHead: common.HexToHash("e1988f95399debf45b873e065e5cd61b416ef2e2e5deec5a6f87c3127086e1ce"), + ChtRoot: common.HexToHash("15cba18e4de0ab1e95e202625199ba30147aec8b0b70384b66ebea31ba6a18e0"), + BloomTrieRoot: common.HexToHash("e00fa6389b2e597d9df52172cd8e936879eed0fca4fa59db99e2c8ed682562f2"), + } +) + +// TrustedCheckpoints associates each known checkpoint with the genesis hash of the chain it belongs to. +var TrustedCheckpoints = map[common.Hash]TrustedCheckpoint{ + params.MainnetGenesisHash: mainnetCheckpoint, + params.TestnetGenesisHash: ropstenCheckpoint, +} + +// ReadTrustedCheckpoint retrieves the checkpoint from the database. +func ReadTrustedCheckpoint(db ethdb.Database) *TrustedCheckpoint { + data, err := db.Get(checkpointKey) + if err != nil { + return nil + } + c := new(TrustedCheckpoint) + if err := rlp.DecodeBytes(data, c); err != nil { + log.Error("Invalid checkpoint RLP", "err", err) + return nil + } + return c +} + +// WriteTrustedCheckpoint stores an RLP encoded checkpoint into the database. +func WriteTrustedCheckpoint(db ethdb.Putter, checkpoint *TrustedCheckpoint) { + data, err := rlp.EncodeToBytes(checkpoint) + if err != nil { + log.Crit("Failed to RLP encode checkpoint", err) + } + if err := db.Put(checkpointKey, data); err != nil { + log.Crit("Failed to store checkpoint", "err", err) + } +} diff --git a/light/checkpoint_test.go b/light/checkpoint_test.go new file mode 100644 index 0000000000..483fb12724 --- /dev/null +++ b/light/checkpoint_test.go @@ -0,0 +1,45 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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. +// +// The go-ethereum library 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 the go-ethereum library. If not, see . + +package light + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" +) + +var testCheckpoint = &TrustedCheckpoint{ + Name: "test", + SectionIdx: 100, + SectionHead: common.HexToHash("0xbeef"), + ChtRoot: common.HexToHash("0xdead"), + BloomTrieRoot: common.HexToHash("0xdeadbeef"), +} + +func TestRWCheckpoint(t *testing.T) { + mdb := ethdb.NewMemDatabase() + WriteTrustedCheckpoint(mdb, testCheckpoint) + if !assertCheckpointEqual(testCheckpoint, ReadTrustedCheckpoint(mdb)) { + t.Error("the checkpoint retrieved from database is different") + } +} + +func assertCheckpointEqual(ckp1, ckp2 *TrustedCheckpoint) bool { + return ckp1.SectionIdx == ckp2.SectionIdx && ckp1.SectionHead == ckp2.SectionHead && ckp1.ChtRoot == ckp2.ChtRoot && + ckp1.BloomTrieRoot == ckp2.BloomTrieRoot +} diff --git a/light/lightchain.go b/light/lightchain.go index 30b9bd89a6..c8ded16a22 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -98,7 +98,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. if bc.genesisBlock == nil { return nil, core.ErrNoGenesis } - if cp, ok := trustedCheckpoints[bc.genesisBlock.Hash()]; ok { + if cp, ok := TrustedCheckpoints[bc.genesisBlock.Hash()]; ok { bc.addTrustedCheckpoint(cp) } if err := bc.loadLastState(); err != nil { @@ -116,19 +116,19 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. } // addTrustedCheckpoint adds a trusted checkpoint to the blockchain -func (self *LightChain) addTrustedCheckpoint(cp trustedCheckpoint) { +func (self *LightChain) addTrustedCheckpoint(cp TrustedCheckpoint) { if self.odr.ChtIndexer() != nil { - StoreChtRoot(self.chainDb, cp.sectionIdx, cp.sectionHead, cp.chtRoot) - self.odr.ChtIndexer().AddKnownSectionHead(cp.sectionIdx, cp.sectionHead) + StoreChtRoot(self.chainDb, cp.SectionIdx, cp.SectionHead, cp.ChtRoot) + self.odr.ChtIndexer().AddKnownSectionHead(cp.SectionIdx, cp.SectionHead) } if self.odr.BloomTrieIndexer() != nil { - StoreBloomTrieRoot(self.chainDb, cp.sectionIdx, cp.sectionHead, cp.bloomTrieRoot) - self.odr.BloomTrieIndexer().AddKnownSectionHead(cp.sectionIdx, cp.sectionHead) + StoreBloomTrieRoot(self.chainDb, cp.SectionIdx, cp.SectionHead, cp.BloomTrieRoot) + self.odr.BloomTrieIndexer().AddKnownSectionHead(cp.SectionIdx, cp.SectionHead) } if self.odr.BloomIndexer() != nil { - self.odr.BloomIndexer().AddKnownSectionHead(cp.sectionIdx, cp.sectionHead) + self.odr.BloomIndexer().AddKnownSectionHead(cp.SectionIdx, cp.SectionHead) } - log.Info("Added trusted checkpoint", "chain", cp.name, "block", (cp.sectionIdx+1)*CHTFrequencyClient-1, "hash", cp.sectionHead) + log.Info("Added trusted checkpoint", "chain", cp.Name, "block", (cp.SectionIdx+1)*CHTFrequencyClient-1, "hash", cp.SectionHead) } func (self *LightChain) getProcInterrupt() bool { diff --git a/light/odr.go b/light/odr.go index 8f1e50b817..fe22c45c34 100644 --- a/light/odr.go +++ b/light/odr.go @@ -164,7 +164,7 @@ func (req *BloomRequest) StoreResult(db ethdb.Database) { for i, sectionIdx := range req.SectionIdxList { sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1) // if we don't have the canonical hash stored for this section head number, we'll still store it under - // a key with a zero sectionHead. GetBloomBits will look there too if we still don't have the canonical + // a key with a zero SectionHead. GetBloomBits will look there too if we still don't have the canonical // hash. In the unlikely case we've retrieved the section head hash since then, we'll just retrieve the // bit vector again from the network. rawdb.WriteBloomBits(db, req.BitIdx, sectionIdx, sectionHead, req.BloomBits[i]) diff --git a/light/odr_util.go b/light/odr_util.go index 620af63835..c909a93bfa 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -203,7 +203,7 @@ func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxLi for i, sectionIdx := range sectionIdxList { sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1) // if we don't have the canonical hash stored for this section head number, we'll still look for - // an entry with a zero sectionHead (we store it with zero section head too if we don't know it + // an entry with a zero SectionHead (we store it with zero section head too if we don't know it // at the time of the retrieval) bloomBits, err := rawdb.ReadBloomBits(db, bitIdx, sectionIdx, sectionHead) if err == nil { diff --git a/light/postprocess.go b/light/postprocess.go index 2090a9d044..455db98638 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -29,11 +29,18 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) +var ( + ErrNoTrustedCht = errors.New("No trusted canonical hash trie") + ErrNoTrustedBloomTrie = errors.New("No trusted bloom trie") + ErrNoHeader = errors.New("Header not found") + chtPrefix = []byte("chtRoot-") // chtPrefix + chtNum (uint64 big endian) -> trie root hash + ChtTablePrefix = "cht-" +) + const ( // CHTFrequencyClient is the block frequency for creating CHTs on the client side. CHTFrequencyClient = 32768 @@ -47,47 +54,6 @@ const ( HelperTrieProcessConfirmations = 256 // number of confirmations before a HelperTrie is generated ) -// trustedCheckpoint represents a set of post-processed trie roots (CHT and BloomTrie) associated with -// the appropriate section index and head hash. It is used to start light syncing from this checkpoint -// and avoid downloading the entire header chain while still being able to securely access old headers/logs. -type trustedCheckpoint struct { - name string - sectionIdx uint64 - sectionHead, chtRoot, bloomTrieRoot common.Hash -} - -var ( - mainnetCheckpoint = trustedCheckpoint{ - name: "mainnet", - sectionIdx: 179, - sectionHead: common.HexToHash("ae778e455492db1183e566fa0c67f954d256fdd08618f6d5a393b0e24576d0ea"), - chtRoot: common.HexToHash("646b338f9ca74d936225338916be53710ec84020b89946004a8605f04c817f16"), - bloomTrieRoot: common.HexToHash("d0f978f5dbc86e5bf931d8dd5b2ecbebbda6dc78f8896af6a27b46a3ced0ac25"), - } - - ropstenCheckpoint = trustedCheckpoint{ - name: "ropsten", - sectionIdx: 107, - sectionHead: common.HexToHash("e1988f95399debf45b873e065e5cd61b416ef2e2e5deec5a6f87c3127086e1ce"), - chtRoot: common.HexToHash("15cba18e4de0ab1e95e202625199ba30147aec8b0b70384b66ebea31ba6a18e0"), - bloomTrieRoot: common.HexToHash("e00fa6389b2e597d9df52172cd8e936879eed0fca4fa59db99e2c8ed682562f2"), - } -) - -// trustedCheckpoints associates each known checkpoint with the genesis hash of the chain it belongs to -var trustedCheckpoints = map[common.Hash]trustedCheckpoint{ - params.MainnetGenesisHash: mainnetCheckpoint, - params.TestnetGenesisHash: ropstenCheckpoint, -} - -var ( - ErrNoTrustedCht = errors.New("No trusted canonical hash trie") - ErrNoTrustedBloomTrie = errors.New("No trusted bloom trie") - ErrNoHeader = errors.New("Header not found") - chtPrefix = []byte("chtRoot-") // chtPrefix + chtNum (uint64 big endian) -> trie root hash - ChtTablePrefix = "cht-" -) - // ChtNode structures are stored in the Canonical Hash Trie in an RLP encoded format type ChtNode struct { Hash common.Hash @@ -95,7 +61,7 @@ type ChtNode struct { } // GetChtRoot reads the CHT root assoctiated to the given section from the database -// Note that sectionIdx is specified according to LES/1 CHT section size +// Note that SectionIdx is specified according to LES/1 CHT section size func GetChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], sectionIdx) @@ -104,13 +70,13 @@ func GetChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) c } // GetChtV2Root reads the CHT root assoctiated to the given section from the database -// Note that sectionIdx is specified according to LES/2 CHT section size +// Note that SectionIdx is specified according to LES/2 CHT section size func GetChtV2Root(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash { return GetChtRoot(db, (sectionIdx+1)*(CHTFrequencyClient/CHTFrequencyServer)-1, sectionHead) } // StoreChtRoot writes the CHT root assoctiated to the given section into the database -// Note that sectionIdx is specified according to LES/1 CHT section size +// Note that SectionIdx is specified according to LES/1 CHT section size func StoreChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root common.Hash) { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], sectionIdx) diff --git a/params/config.go b/params/config.go index b9e9bb8d6e..70a1edead4 100644 --- a/params/config.go +++ b/params/config.go @@ -27,6 +27,7 @@ import ( var ( MainnetGenesisHash = common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") TestnetGenesisHash = common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d") + RinkebyGenesisHash = common.HexToHash("0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177") ) var ( From 85e287fd88d757c1709ed028532ca7bd66a00dd1 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 7 Jun 2018 16:57:40 +0800 Subject: [PATCH 06/15] contracts: modify checkpoint contract and rewrite unittests --- contracts/registrar/contract/registrar.go | 137 ++++++------ contracts/registrar/contract/registrar.sol | 76 +++---- contracts/registrar/registrar.go | 6 +- contracts/registrar/registrar_test.go | 242 +++++++++++++++------ les/server.go | 24 +- 5 files changed, 284 insertions(+), 201 deletions(-) diff --git a/contracts/registrar/contract/registrar.go b/contracts/registrar/contract/registrar.go index ebb292e9ef..ef5f87e847 100644 --- a/contracts/registrar/contract/registrar.go +++ b/contracts/registrar/contract/registrar.go @@ -16,10 +16,10 @@ import ( ) // ContractABI is the input ABI used to generate the binding from. -const ContractABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"GetAllAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetLatestCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"},{\"name\":\"_sectionHead\",\"type\":\"bytes32\"},{\"name\":\"_chtRoot\",\"type\":\"bytes32\"},{\"name\":\"_bloomTrieRoot\",\"type\":\"bytes32\"}],\"name\":\"SetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"}],\"name\":\"GetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"RemoveAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"AddAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_adminlist\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"index\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"sectionHead\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"chtRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"bloomTrieRoot\",\"type\":\"bytes32\"}],\"name\":\"NewCheckpointEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"AddAdminEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"RemoveAdminEvent\",\"type\":\"event\"}]" +const ContractABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"},{\"name\":\"_description\",\"type\":\"string\"}],\"name\":\"AddAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetAllAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetLatestCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"},{\"name\":\"_sectionHead\",\"type\":\"bytes32\"},{\"name\":\"_chtRoot\",\"type\":\"bytes32\"},{\"name\":\"_bloomTrieRoot\",\"type\":\"bytes32\"}],\"name\":\"SetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"}],\"name\":\"GetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"},{\"name\":\"_reason\",\"type\":\"string\"}],\"name\":\"RemoveAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_adminlist\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"index\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"checkpointHash\",\"type\":\"bytes32\"}],\"name\":\"NewCheckpointEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"description\",\"type\":\"string\"}],\"name\":\"AddAdminEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"RemoveAdminEvent\",\"type\":\"event\"}]" // ContractBin is the compiled bytecode used for deploying new contracts. -const ContractBin = `608060405234801561001057600080fd5b50604051610d06380380610d0683398101806040528101908080518201929190505050600060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060013390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600090505b81518110156101d2576001600080848481518110151561010057fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001828281518110151561015857fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505080806001019150506100e4565b5050610b23806101e36000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806345848dfc1461007d5780634d6a304c146100e9578063651c7f4914610141578063710aeac8146101b0578063753f40ca14610217578063ad6de44514610272575b600080fd5b34801561008957600080fd5b506100926102cd565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156100d55780820151818401526020810190506100ba565b505050509050019250505060405180910390f35b3480156100f557600080fd5b506100fe6103b4565b6040518085815260200184600019166000191681526020018360001916600019168152602001826000191660001916815260200194505050505060405180910390f35b34801561014d57600080fd5b50610196600480360381019080803590602001909291908035600019169060200190929190803560001916906020019092919080356000191690602001909291905050506103e7565b604051808215151515815260200191505060405180910390f35b3480156101bc57600080fd5b506101db60048036038101908080359060200190929190505050610555565b60405180846000191660001916815260200183600019166000191681526020018260001916600019168152602001935050505060405180910390f35b34801561022357600080fd5b50610258600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506105d6565b604051808215151515815260200191505060405180910390f35b34801561027e57600080fd5b506102b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108c6565b604051808215151515815260200191505060405180910390f35b60608060006001805490506040519080825280602002602001820160405280156103065781602001602082028038833980820191505090505b509150600090505b6001805490508110156103ac5760018181548110151561032a57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110151561036357fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050808060010191505061030e565b819250505090565b60008060008060008060006103ca600354610555565b925092509250600354838383965096509650965050505090919293565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561043557600080fd5b600160035401851415801561044d5750600060035414155b1561045b576000905061054d565b612710618000600187010201431015610477576000905061054d565b606060405190810160405280856000191681526020018460001916815260200183600019168152506002600087815260200190815260200160002060008201518160000190600019169055602082015181600101906000191690556040820151816002019060001916905590505084600381905550847fa9b81895520c1feeea26e91ca03e455eb4be8dc9ecb34071c362e67835a6fd4285858560405180846000191660001916815260200183600019166000191681526020018260001916600019168152602001935050505060405180910390a25b949350505050565b6000806000610562610a7b565b600260008681526020019081526020016000206060604051908101604052908160008201546000191660001916815260200160018201546000191660001916815260200160028201546000191660001916815250509050806000015181602001518260400151935093509350509193909250565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561062757600080fd5b60008060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141561067757600092506108bf565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b600180549050821015610857578373ffffffffffffffffffffffffffffffffffffffff166001838154811015156106f157fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561084a578190505b60018080549050038110156107eb57600180820181548110151561075c57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660018281548110151561079657fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808060010191505061073c565b60018080805490500381548110151561080057fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600180818180549050039150816108449190610aa6565b50610857565b81806001019250506106be565b7f16f0165239516629af323911340c1c906029142cb0dc3c32c93ce6808d98a4ee84604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1600192505b5050919050565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561091457600080fd5b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411156109645760009050610a76565b60016000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018290806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507f68377f3d45858cbcc9e95998fb55b9c0f9e16b6ebf5f3602a40e2fcd0d7b8c0082604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1600190505b919050565b6060604051908101604052806000801916815260200160008019168152602001600080191681525090565b815481835581811115610acd57818360005260206000209182019101610acc9190610ad2565b5b505050565b610af491905b80821115610af0576000816000905550600101610ad8565b5090565b905600a165627a7a72305820de9e3481e0a4d931d0b0a0a34b53b4315479499d7deb6724e5de6d1f439d44e70029` +const ContractBin = `608060405234801561001057600080fd5b50604051610e83380380610e8383398101806040528101908080518201929190505050600060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060013390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600090505b81518110156101d2576001600080848481518110151561010057fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001828281518110151561015857fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505080806001019150506100e4565b5050610ca0806101e36000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633561247d1461007d57806345848dfc1461011e5780634d6a304c1461018a578063651c7f49146101c4578063710aeac814610233578063a5ba0be21461027c575b600080fd5b34801561008957600080fd5b50610104600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061031d565b604051808215151515815260200191505060405180910390f35b34801561012a57600080fd5b50610133610574565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561017657808201518184015260208101905061015b565b505050509050019250505060405180910390f35b34801561019657600080fd5b5061019f61065b565b6040518083815260200182600019166000191681526020019250505060405180910390f35b3480156101d057600080fd5b506102196004803603810190808035906020019092919080356000191690602001909291908035600019169060200190929190803560001916906020019092919050505061067a565b604051808215151515815260200191505060405180910390f35b34801561023f57600080fd5b5061025e60048036038101908080359060200190929190505050610874565b60405180826000191660001916815260200191505060405180910390f35b34801561028857600080fd5b50610303600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610891565b604051808215151515815260200191505060405180910390f35b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561036b57600080fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411156103bb576000905061056e565b60016000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507fecd88a3d10808aac9f879bbae95f9e4f9687f6c9f0615b88af2085f226d3cf93833384604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561052d578082015181840152602081019050610512565b50505050905090810190601f16801561055a5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600190505b92915050565b60608060006001805490506040519080825280602002602001820160405280156105ad5781602001602082028038833980820191505090505b509150600090505b600180549050811015610653576001818154811015156105d157fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110151561060a57fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080806001019150506105b5565b819250505090565b600080600061066b600354610874565b90506003548192509250509091565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156106c857600080fd5b60035485141580156106df57506001600354018514155b80156106ee5750600060035414155b156106fc576000905061086c565b6101f4618000600187010201431015610718576000905061086c565b8383836040516020018084600019166000191681526020018360001916600019168152602001826000191660001916815260200193505050506040516020818303038152906040526040518082805190602001908083835b6020831015156107955780518252602082019150602081019050602083039250610770565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060026000878152602001908152602001600020816000191690555084600381905550847f5b3eab050ccf1a983a26b4f6acb13c199093c7d2e7523a0ff036519f7ddaf560336002600089815260200190815260200160002054604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182600019166000191681526020019250505060405180910390a25b949350505050565b600060026000838152602001908152602001600020549050919050565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156108e257600080fd5b60008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414156109325760009250610c1b565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b600180549050821015610b12578473ffffffffffffffffffffffffffffffffffffffff166001838154811015156109ac57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610b05578190505b6001808054905003811015610aa6576001808201815481101515610a1757fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600182815481101515610a5157fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080806001019150506109f7565b600180808054905003815481101515610abb57fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905560018081818054905003915081610aff9190610c23565b50610b12565b8180600101925050610979565b7fe7d6ab069cde0507dc9c5971bf93e9fd183db04690725946e8cae907367e7c1f853386604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610bda578082015181840152602081019050610bbf565b50505050905090810190601f168015610c075780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600192505b505092915050565b815481835581811115610c4a57818360005260206000209182019101610c499190610c4f565b5b505050565b610c7191905b80821115610c6d576000816000905550600101610c55565b5090565b905600a165627a7a72305820791f0110aacecdc551cc4d3bda7cc4228762aa3acdce5f7b1b1d9efb1534b8320029` // DeployContract deploys a new Ethereum contract, binding an instance of Contract to it. func DeployContract(auth *bind.TransactOpts, backend bind.ContractBackend, _adminlist []common.Address) (common.Address, *types.Transaction, *Contract, error) { @@ -204,110 +204,100 @@ func (_Contract *ContractCallerSession) GetAllAdmin() ([]common.Address, error) // GetCheckpoint is a free data retrieval call binding the contract method 0x710aeac8. // -// Solidity: function GetCheckpoint(_sectionIndex uint256) constant returns(bytes32, bytes32, bytes32) -func (_Contract *ContractCaller) GetCheckpoint(opts *bind.CallOpts, _sectionIndex *big.Int) ([32]byte, [32]byte, [32]byte, error) { +// Solidity: function GetCheckpoint(_sectionIndex uint256) constant returns(bytes32) +func (_Contract *ContractCaller) GetCheckpoint(opts *bind.CallOpts, _sectionIndex *big.Int) ([32]byte, error) { var ( ret0 = new([32]byte) - ret1 = new([32]byte) - ret2 = new([32]byte) ) - out := &[]interface{}{ - ret0, - ret1, - ret2, - } + out := ret0 err := _Contract.contract.Call(opts, out, "GetCheckpoint", _sectionIndex) - return *ret0, *ret1, *ret2, err + return *ret0, err } // GetCheckpoint is a free data retrieval call binding the contract method 0x710aeac8. // -// Solidity: function GetCheckpoint(_sectionIndex uint256) constant returns(bytes32, bytes32, bytes32) -func (_Contract *ContractSession) GetCheckpoint(_sectionIndex *big.Int) ([32]byte, [32]byte, [32]byte, error) { +// Solidity: function GetCheckpoint(_sectionIndex uint256) constant returns(bytes32) +func (_Contract *ContractSession) GetCheckpoint(_sectionIndex *big.Int) ([32]byte, error) { return _Contract.Contract.GetCheckpoint(&_Contract.CallOpts, _sectionIndex) } // GetCheckpoint is a free data retrieval call binding the contract method 0x710aeac8. // -// Solidity: function GetCheckpoint(_sectionIndex uint256) constant returns(bytes32, bytes32, bytes32) -func (_Contract *ContractCallerSession) GetCheckpoint(_sectionIndex *big.Int) ([32]byte, [32]byte, [32]byte, error) { +// Solidity: function GetCheckpoint(_sectionIndex uint256) constant returns(bytes32) +func (_Contract *ContractCallerSession) GetCheckpoint(_sectionIndex *big.Int) ([32]byte, error) { return _Contract.Contract.GetCheckpoint(&_Contract.CallOpts, _sectionIndex) } // GetLatestCheckpoint is a free data retrieval call binding the contract method 0x4d6a304c. // -// Solidity: function GetLatestCheckpoint() constant returns(uint256, bytes32, bytes32, bytes32) -func (_Contract *ContractCaller) GetLatestCheckpoint(opts *bind.CallOpts) (*big.Int, [32]byte, [32]byte, [32]byte, error) { +// Solidity: function GetLatestCheckpoint() constant returns(uint256, bytes32) +func (_Contract *ContractCaller) GetLatestCheckpoint(opts *bind.CallOpts) (*big.Int, [32]byte, error) { var ( ret0 = new(*big.Int) ret1 = new([32]byte) - ret2 = new([32]byte) - ret3 = new([32]byte) ) out := &[]interface{}{ ret0, ret1, - ret2, - ret3, } err := _Contract.contract.Call(opts, out, "GetLatestCheckpoint") - return *ret0, *ret1, *ret2, *ret3, err + return *ret0, *ret1, err } // GetLatestCheckpoint is a free data retrieval call binding the contract method 0x4d6a304c. // -// Solidity: function GetLatestCheckpoint() constant returns(uint256, bytes32, bytes32, bytes32) -func (_Contract *ContractSession) GetLatestCheckpoint() (*big.Int, [32]byte, [32]byte, [32]byte, error) { +// Solidity: function GetLatestCheckpoint() constant returns(uint256, bytes32) +func (_Contract *ContractSession) GetLatestCheckpoint() (*big.Int, [32]byte, error) { return _Contract.Contract.GetLatestCheckpoint(&_Contract.CallOpts) } // GetLatestCheckpoint is a free data retrieval call binding the contract method 0x4d6a304c. // -// Solidity: function GetLatestCheckpoint() constant returns(uint256, bytes32, bytes32, bytes32) -func (_Contract *ContractCallerSession) GetLatestCheckpoint() (*big.Int, [32]byte, [32]byte, [32]byte, error) { +// Solidity: function GetLatestCheckpoint() constant returns(uint256, bytes32) +func (_Contract *ContractCallerSession) GetLatestCheckpoint() (*big.Int, [32]byte, error) { return _Contract.Contract.GetLatestCheckpoint(&_Contract.CallOpts) } -// AddAdmin is a paid mutator transaction binding the contract method 0xad6de445. +// AddAdmin is a paid mutator transaction binding the contract method 0x3561247d. // -// Solidity: function AddAdmin(_addr address) returns(bool) -func (_Contract *ContractTransactor) AddAdmin(opts *bind.TransactOpts, _addr common.Address) (*types.Transaction, error) { - return _Contract.contract.Transact(opts, "AddAdmin", _addr) +// Solidity: function AddAdmin(_addr address, _description string) returns(bool) +func (_Contract *ContractTransactor) AddAdmin(opts *bind.TransactOpts, _addr common.Address, _description string) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "AddAdmin", _addr, _description) } -// AddAdmin is a paid mutator transaction binding the contract method 0xad6de445. +// AddAdmin is a paid mutator transaction binding the contract method 0x3561247d. // -// Solidity: function AddAdmin(_addr address) returns(bool) -func (_Contract *ContractSession) AddAdmin(_addr common.Address) (*types.Transaction, error) { - return _Contract.Contract.AddAdmin(&_Contract.TransactOpts, _addr) +// Solidity: function AddAdmin(_addr address, _description string) returns(bool) +func (_Contract *ContractSession) AddAdmin(_addr common.Address, _description string) (*types.Transaction, error) { + return _Contract.Contract.AddAdmin(&_Contract.TransactOpts, _addr, _description) } -// AddAdmin is a paid mutator transaction binding the contract method 0xad6de445. +// AddAdmin is a paid mutator transaction binding the contract method 0x3561247d. // -// Solidity: function AddAdmin(_addr address) returns(bool) -func (_Contract *ContractTransactorSession) AddAdmin(_addr common.Address) (*types.Transaction, error) { - return _Contract.Contract.AddAdmin(&_Contract.TransactOpts, _addr) +// Solidity: function AddAdmin(_addr address, _description string) returns(bool) +func (_Contract *ContractTransactorSession) AddAdmin(_addr common.Address, _description string) (*types.Transaction, error) { + return _Contract.Contract.AddAdmin(&_Contract.TransactOpts, _addr, _description) } -// RemoveAdmin is a paid mutator transaction binding the contract method 0x753f40ca. +// RemoveAdmin is a paid mutator transaction binding the contract method 0xa5ba0be2. // -// Solidity: function RemoveAdmin(_addr address) returns(bool) -func (_Contract *ContractTransactor) RemoveAdmin(opts *bind.TransactOpts, _addr common.Address) (*types.Transaction, error) { - return _Contract.contract.Transact(opts, "RemoveAdmin", _addr) +// Solidity: function RemoveAdmin(_addr address, _reason string) returns(bool) +func (_Contract *ContractTransactor) RemoveAdmin(opts *bind.TransactOpts, _addr common.Address, _reason string) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "RemoveAdmin", _addr, _reason) } -// RemoveAdmin is a paid mutator transaction binding the contract method 0x753f40ca. +// RemoveAdmin is a paid mutator transaction binding the contract method 0xa5ba0be2. // -// Solidity: function RemoveAdmin(_addr address) returns(bool) -func (_Contract *ContractSession) RemoveAdmin(_addr common.Address) (*types.Transaction, error) { - return _Contract.Contract.RemoveAdmin(&_Contract.TransactOpts, _addr) +// Solidity: function RemoveAdmin(_addr address, _reason string) returns(bool) +func (_Contract *ContractSession) RemoveAdmin(_addr common.Address, _reason string) (*types.Transaction, error) { + return _Contract.Contract.RemoveAdmin(&_Contract.TransactOpts, _addr, _reason) } -// RemoveAdmin is a paid mutator transaction binding the contract method 0x753f40ca. +// RemoveAdmin is a paid mutator transaction binding the contract method 0xa5ba0be2. // -// Solidity: function RemoveAdmin(_addr address) returns(bool) -func (_Contract *ContractTransactorSession) RemoveAdmin(_addr common.Address) (*types.Transaction, error) { - return _Contract.Contract.RemoveAdmin(&_Contract.TransactOpts, _addr) +// Solidity: function RemoveAdmin(_addr address, _reason string) returns(bool) +func (_Contract *ContractTransactorSession) RemoveAdmin(_addr common.Address, _reason string) (*types.Transaction, error) { + return _Contract.Contract.RemoveAdmin(&_Contract.TransactOpts, _addr, _reason) } // SetCheckpoint is a paid mutator transaction binding the contract method 0x651c7f49. @@ -400,13 +390,15 @@ func (it *ContractAddAdminEventIterator) Close() error { // ContractAddAdminEvent represents a AddAdminEvent event raised by the Contract contract. type ContractAddAdminEvent struct { - Addr common.Address - Raw types.Log // Blockchain specific contextual infos + Addr common.Address + Grantor common.Address + Description string + Raw types.Log // Blockchain specific contextual infos } -// FilterAddAdminEvent is a free log retrieval operation binding the contract event 0x68377f3d45858cbcc9e95998fb55b9c0f9e16b6ebf5f3602a40e2fcd0d7b8c00. +// FilterAddAdminEvent is a free log retrieval operation binding the contract event 0xecd88a3d10808aac9f879bbae95f9e4f9687f6c9f0615b88af2085f226d3cf93. // -// Solidity: e AddAdminEvent(addr address) +// Solidity: e AddAdminEvent(addr address, grantor address, description string) func (_Contract *ContractFilterer) FilterAddAdminEvent(opts *bind.FilterOpts) (*ContractAddAdminEventIterator, error) { logs, sub, err := _Contract.contract.FilterLogs(opts, "AddAdminEvent") @@ -416,9 +408,9 @@ func (_Contract *ContractFilterer) FilterAddAdminEvent(opts *bind.FilterOpts) (* return &ContractAddAdminEventIterator{contract: _Contract.contract, event: "AddAdminEvent", logs: logs, sub: sub}, nil } -// WatchAddAdminEvent is a free log subscription operation binding the contract event 0x68377f3d45858cbcc9e95998fb55b9c0f9e16b6ebf5f3602a40e2fcd0d7b8c00. +// WatchAddAdminEvent is a free log subscription operation binding the contract event 0xecd88a3d10808aac9f879bbae95f9e4f9687f6c9f0615b88af2085f226d3cf93. // -// Solidity: e AddAdminEvent(addr address) +// Solidity: e AddAdminEvent(addr address, grantor address, description string) func (_Contract *ContractFilterer) WatchAddAdminEvent(opts *bind.WatchOpts, sink chan<- *ContractAddAdminEvent) (event.Subscription, error) { logs, sub, err := _Contract.contract.WatchLogs(opts, "AddAdminEvent") @@ -522,16 +514,15 @@ func (it *ContractNewCheckpointEventIterator) Close() error { // ContractNewCheckpointEvent represents a NewCheckpointEvent event raised by the Contract contract. type ContractNewCheckpointEvent struct { - Index *big.Int - SectionHead [32]byte - ChtRoot [32]byte - BloomTrieRoot [32]byte - Raw types.Log // Blockchain specific contextual infos + Index *big.Int + Grantor common.Address + CheckpointHash [32]byte + Raw types.Log // Blockchain specific contextual infos } -// FilterNewCheckpointEvent is a free log retrieval operation binding the contract event 0xa9b81895520c1feeea26e91ca03e455eb4be8dc9ecb34071c362e67835a6fd42. +// FilterNewCheckpointEvent is a free log retrieval operation binding the contract event 0x5b3eab050ccf1a983a26b4f6acb13c199093c7d2e7523a0ff036519f7ddaf560. // -// Solidity: e NewCheckpointEvent(index indexed uint256, sectionHead bytes32, chtRoot bytes32, bloomTrieRoot bytes32) +// Solidity: e NewCheckpointEvent(index indexed uint256, grantor address, checkpointHash bytes32) func (_Contract *ContractFilterer) FilterNewCheckpointEvent(opts *bind.FilterOpts, index []*big.Int) (*ContractNewCheckpointEventIterator, error) { var indexRule []interface{} @@ -546,9 +537,9 @@ func (_Contract *ContractFilterer) FilterNewCheckpointEvent(opts *bind.FilterOpt return &ContractNewCheckpointEventIterator{contract: _Contract.contract, event: "NewCheckpointEvent", logs: logs, sub: sub}, nil } -// WatchNewCheckpointEvent is a free log subscription operation binding the contract event 0xa9b81895520c1feeea26e91ca03e455eb4be8dc9ecb34071c362e67835a6fd42. +// WatchNewCheckpointEvent is a free log subscription operation binding the contract event 0x5b3eab050ccf1a983a26b4f6acb13c199093c7d2e7523a0ff036519f7ddaf560. // -// Solidity: e NewCheckpointEvent(index indexed uint256, sectionHead bytes32, chtRoot bytes32, bloomTrieRoot bytes32) +// Solidity: e NewCheckpointEvent(index indexed uint256, grantor address, checkpointHash bytes32) func (_Contract *ContractFilterer) WatchNewCheckpointEvent(opts *bind.WatchOpts, sink chan<- *ContractNewCheckpointEvent, index []*big.Int) (event.Subscription, error) { var indexRule []interface{} @@ -657,13 +648,15 @@ func (it *ContractRemoveAdminEventIterator) Close() error { // ContractRemoveAdminEvent represents a RemoveAdminEvent event raised by the Contract contract. type ContractRemoveAdminEvent struct { - Addr common.Address - Raw types.Log // Blockchain specific contextual infos + Addr common.Address + Grantor common.Address + Reason string + Raw types.Log // Blockchain specific contextual infos } -// FilterRemoveAdminEvent is a free log retrieval operation binding the contract event 0x16f0165239516629af323911340c1c906029142cb0dc3c32c93ce6808d98a4ee. +// FilterRemoveAdminEvent is a free log retrieval operation binding the contract event 0xe7d6ab069cde0507dc9c5971bf93e9fd183db04690725946e8cae907367e7c1f. // -// Solidity: e RemoveAdminEvent(addr address) +// Solidity: e RemoveAdminEvent(addr address, grantor address, reason string) func (_Contract *ContractFilterer) FilterRemoveAdminEvent(opts *bind.FilterOpts) (*ContractRemoveAdminEventIterator, error) { logs, sub, err := _Contract.contract.FilterLogs(opts, "RemoveAdminEvent") @@ -673,9 +666,9 @@ func (_Contract *ContractFilterer) FilterRemoveAdminEvent(opts *bind.FilterOpts) return &ContractRemoveAdminEventIterator{contract: _Contract.contract, event: "RemoveAdminEvent", logs: logs, sub: sub}, nil } -// WatchRemoveAdminEvent is a free log subscription operation binding the contract event 0x16f0165239516629af323911340c1c906029142cb0dc3c32c93ce6808d98a4ee. +// WatchRemoveAdminEvent is a free log subscription operation binding the contract event 0xe7d6ab069cde0507dc9c5971bf93e9fd183db04690725946e8cae907367e7c1f. // -// Solidity: e RemoveAdminEvent(addr address) +// Solidity: e RemoveAdminEvent(addr address, grantor address, reason string) func (_Contract *ContractFilterer) WatchRemoveAdminEvent(opts *bind.WatchOpts, sink chan<- *ContractRemoveAdminEvent) (event.Subscription, error) { logs, sub, err := _Contract.contract.WatchLogs(opts, "RemoveAdminEvent") diff --git a/contracts/registrar/contract/registrar.sol b/contracts/registrar/contract/registrar.sol index cb92b92d39..37125bccb3 100644 --- a/contracts/registrar/contract/registrar.sol +++ b/contracts/registrar/contract/registrar.sol @@ -6,22 +6,6 @@ pragma solidity ^0.4.24; * @dev Implementation of the blockchain checkpoint information registrar. */ contract Registrar { - /* - Definitions - */ - - // Checkpoint represents a set of post-processed trie roots (CHT and BloomTrie) - // associated with the appropriate section head hash. - // - // It is used to start light syncing from this checkpoint - // and avoid downloading the entire header chain while still being able to securely - // access old headers/logs. - struct Checkpoint { - bytes32 sectionHead; - bytes32 chtRoot; - bytes32 bloomTrieRoot; - } - /* Modifiers */ @@ -39,13 +23,17 @@ contract Registrar { */ // NewCheckpointEvent is emitted when new checkpoint is registered. - event NewCheckpointEvent(uint indexed index, bytes32 sectionHead, bytes32 chtRoot, bytes32 bloomTrieRoot); + // Grantor indicates the people register the checkpoint. + // We use checkpoint hash instead of the full checkpoint to make the transaction cheaper. + event NewCheckpointEvent(uint indexed index, address grantor, bytes32 checkpointHash); // AddAdminEvent is emitted when new address is accepted as admin. - event AddAdminEvent(address addr); + // Grantor indicates who authorizes the add admin operation. + event AddAdminEvent(address addr, address grantor, string description); // RemoveAdminEvent is emitted when an admin is removed. - event RemoveAdminEvent(address addr); + // Grantor indicates who authorizes the remove admin operation. + event RemoveAdminEvent(address addr, address grantor, string reason); /* Public Functions @@ -63,36 +51,37 @@ contract Registrar { /** * @dev Get latest stable checkpoint information. * @return section index - * @return section head - * @return cht root hash - * @return bloom trie root hash + * @return checkpoint hash */ function GetLatestCheckpoint() view public - returns(uint, bytes32, bytes32, bytes32) { - (bytes32 sectionHead, bytes32 chtRoot, bytes32 bloomRoot) = GetCheckpoint(latest); - return (latest, sectionHead, chtRoot, bloomRoot); + returns(uint, bytes32) { + bytes32 hash = GetCheckpoint(latest); + return (latest, hash); } /** * @dev Get a stable checkpoint information with specified section index. * @param _sectionIndex section index - * @return section head - * @return cht root hash - * @return bloom trie root hash + * @return checkpoint hash */ function GetCheckpoint(uint _sectionIndex) view public - returns(bytes32, bytes32, bytes32) + returns(bytes32) { - Checkpoint memory checkpoint = checkpoints[_sectionIndex]; - return (checkpoint.sectionHead, checkpoint.chtRoot, checkpoint.bloomTrieRoot); + return checkpoints[_sectionIndex]; } /** * @dev Set stable checkpoint information. + * Checkpoint represents a set of post-processed trie roots (CHT and BloomTrie) + * associated with the appropriate section head hash. + * + * It is used to start light syncing from this checkpoint + * and avoid downloading the entire header chain while still being able to securely + * access old headers/logs. * * Note we trust the given information here provided by foundation, * need a trust less version for future. @@ -113,7 +102,8 @@ contract Registrar { returns(bool) { // Ensure the checkpoint information provided is strictly continuous with previous one. - if (_sectionIndex != latest + 1 && latest != 0) { + // But the latest checkpoint modification is allowed. + if (_sectionIndex != latest && _sectionIndex != latest + 1 && latest != 0) { return false; } // Ensure the checkpoint is stable enough to be registered. @@ -121,14 +111,10 @@ contract Registrar { return false; } - checkpoints[_sectionIndex] = Checkpoint({ - sectionHead: _sectionHead, - chtRoot: _chtRoot, - bloomTrieRoot: _bloomTrieRoot - }); + checkpoints[_sectionIndex] = keccak256(abi.encodePacked(_sectionHead, _chtRoot, _bloomTrieRoot)); latest = _sectionIndex; - emit NewCheckpointEvent(_sectionIndex, _sectionHead, _chtRoot, _bloomTrieRoot); + emit NewCheckpointEvent(_sectionIndex, msg.sender, checkpoints[_sectionIndex]); } /** @@ -136,7 +122,7 @@ contract Registrar { * @param _addr specified new admin address. * @return indicator whether add new admin successfully */ - function AddAdmin(address _addr) + function AddAdmin(address _addr, string _description) OnlyAuthorized public returns(bool) @@ -148,7 +134,7 @@ contract Registrar { admins[_addr] = 1; adminList.push(_addr); - emit AddAdminEvent(_addr); + emit AddAdminEvent(_addr, msg.sender, _description); return true; } @@ -157,7 +143,7 @@ contract Registrar { * @param _addr specified admin address to remove. * @return indicator whether remove admin successfully */ - function RemoveAdmin(address _addr) + function RemoveAdmin(address _addr, string _reason) OnlyAuthorized public returns(bool) @@ -179,7 +165,7 @@ contract Registrar { } } - emit RemoveAdminEvent(_addr); + emit RemoveAdminEvent(_addr, msg.sender, _reason); return true; } @@ -211,7 +197,7 @@ contract Registrar { address[] adminList; // Registered checkpoint information - mapping(uint => Checkpoint) checkpoints; + mapping(uint => bytes32) checkpoints; // Latest stored section id // Note all registered checkpoint information should continuous with previous one. @@ -221,6 +207,8 @@ contract Registrar { uint constant sectionSize = 32768; // The number of confirmations needed before a checkpoint can be registered. - uint constant confirmations = 10000; + // We have to make sure the checkpoint registered will not be invalid due to + // chain reorg. + uint constant confirmations = 500; } diff --git a/contracts/registrar/registrar.go b/contracts/registrar/registrar.go index 9ef1f7e062..f2059baf0d 100644 --- a/contracts/registrar/registrar.go +++ b/contracts/registrar/registrar.go @@ -30,11 +30,11 @@ import ( ) var ( - // registrar contract address for mainnet or test chain. + // registrar contract address for mainnet and testnet. RegistrarAddr = map[common.Hash]common.Address{ params.MainnetGenesisHash: common.HexToAddress(""), params.TestnetGenesisHash: common.HexToAddress(""), - params.RinkebyGenesisHash: common.HexToAddress("0x3b934494985d17bcb49557671e1bc8ec32cccdd5"), + params.RinkebyGenesisHash: common.HexToAddress("0xe3f2686a5d0c56a2d853c19c46b173a755263be8"), } ) @@ -42,7 +42,7 @@ var errEventNotFound = errors.New("contract event not found") const ( sectionSize = 32768 // The frequency for creating a checkpoint - checkpointConfirmation = 10000 // The number of confirmations needed before a checkpoint becoming stable. + checkpointConfirmation = 500 // The number of confirmations needed before a checkpoint can be accepted ) type Registrar struct { diff --git a/contracts/registrar/registrar_test.go b/contracts/registrar/registrar_test.go index 6c07b02629..9565cd9325 100644 --- a/contracts/registrar/registrar_test.go +++ b/contracts/registrar/registrar_test.go @@ -17,9 +17,11 @@ package registrar import ( + "errors" "math/big" "reflect" "testing" + "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" @@ -43,101 +45,209 @@ var ( } ) +// validateOperation executes the operation, watches and delivers all events fired by the backend and ensures the +// correctness by assert function. +func validateOperation(t *testing.T, c *contract.Contract, backend *backends.SimulatedBackend, operation func(), + assert func(<-chan *contract.ContractNewCheckpointEvent, <-chan *contract.ContractAddAdminEvent, <-chan *contract.ContractRemoveAdminEvent) error, opName string) { + // Watch all events and deliver them to assert function + var ( + sink1 = make(chan *contract.ContractNewCheckpointEvent) + sink2 = make(chan *contract.ContractAddAdminEvent) + sink3 = make(chan *contract.ContractRemoveAdminEvent) + ) + sub1, _ := c.WatchNewCheckpointEvent(nil, sink1, nil) + sub2, _ := c.WatchAddAdminEvent(nil, sink2) + sub3, _ := c.WatchRemoveAdminEvent(nil, sink3) + defer func() { + // Close all subscribers + sub1.Unsubscribe() + sub2.Unsubscribe() + sub3.Unsubscribe() + }() + operation() + + // flush pending block + backend.Commit() + if err := assert(sink1, sink2, sink3); err != nil { + t.Errorf("operation {%s} failed, err %s", opName, err) + } +} + +// validateEvents checks that the correct number of contract events +// fired by contract backend. +func validateEvents(target int, sink interface{}) bool { + chanval := reflect.ValueOf(sink) + chantyp := chanval.Type() + if chantyp.Kind() != reflect.Chan || chantyp.ChanDir()&reflect.RecvDir == 0 { + return false + } + count := 0 + timeout := time.After(1 * time.Second) + cases := []reflect.SelectCase{{Chan: chanval, Dir: reflect.SelectRecv}, {Chan: reflect.ValueOf(timeout), Dir: reflect.SelectRecv}} + for { + chose, _, _ := reflect.Select(cases) + if chose == 1 { + // Not enough event received + return false + } + count += 1 + if count == target { + break + } + } + done := time.After(50 * time.Millisecond) + cases = cases[:1] + cases = append(cases, reflect.SelectCase{Chan: reflect.ValueOf(done), Dir: reflect.SelectRecv}) + chose, _, _ := reflect.Select(cases) + // If chose equal 0, it means receiving redundant events. + return chose == 1 +} + +// Tests contract administrator managements. func TestAdminManagement(t *testing.T) { var ( - adminCandidate = common.HexToAddress("0x123") - adminCandidate2 = common.HexToAddress("0x456") + adminCandidate = common.HexToAddress("0xdead") + adminCandidate2 = common.HexToAddress("0xbeef") ) // Deploy registrar contract transactOpts := bind.NewKeyedTransactor(key) contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) - _, _, contract, err := contract.DeployContract(transactOpts, contractBackend, nil) + _, _, c, err := contract.DeployContract(transactOpts, contractBackend, nil) if err != nil { t.Error("deploy registrar contract failed", err) } contractBackend.Commit() // Test AddAdmin function - contract.AddAdmin(transactOpts, addr) // Contract should ignore the duplicate registration - contract.AddAdmin(transactOpts, adminCandidate) - contract.AddAdmin(transactOpts, adminCandidate2) - contractBackend.Commit() - adminList, err := contract.GetAllAdmin(nil) - if err != nil { - t.Error("fetch admin list failed", err) - } - if !reflect.DeepEqual(adminList, []common.Address{addr, adminCandidate, adminCandidate2}) { - t.Error("expect the returned admin list contain 3 address") - } + validateOperation(t, c, contractBackend, func() { + for _, a := range []common.Address{addr, adminCandidate, adminCandidate2} { + c.AddAdmin(transactOpts, a, "") + } + }, func(sink1 <-chan *contract.ContractNewCheckpointEvent, sink2 <-chan *contract.ContractAddAdminEvent, sink3 <-chan *contract.ContractRemoveAdminEvent) error { + adminList, err := c.GetAllAdmin(nil) + if err != nil { + return errors.New("get admin list failed") + } + if !reflect.DeepEqual(adminList, []common.Address{addr, adminCandidate, adminCandidate2}) { + return errors.New("add admin failed") + } + if !validateEvents(2, sink2) { + return errors.New("receive incorrect number of events") + } + return nil + }, "add admin") - // Test RemoveAdmin function (remove at the middle) - contract.RemoveAdmin(transactOpts, adminCandidate) - contractBackend.Commit() - adminList, err = contract.GetAllAdmin(nil) - if err != nil { - t.Error("fetch admin list failed", err) - } - if !reflect.DeepEqual(adminList, []common.Address{addr, adminCandidate2}) { - t.Error("expect the returned admin list contain 3 address") - } + // Test Remove admin function + validateOperation(t, c, contractBackend, func() { + c.RemoveAdmin(transactOpts, adminCandidate, "") + }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { + adminList, err := c.GetAllAdmin(nil) + if err != nil { + return errors.New("get admin list failed") + } + if !reflect.DeepEqual(adminList, []common.Address{addr, adminCandidate2}) { + return errors.New("remove admin failed") + } + if !validateEvents(1, events3) { + return errors.New("receive incorrect number of events") + } + return nil + }, "remove admin at middle") // Test RemoveAdmin function (remove at the head) - contract.RemoveAdmin(transactOpts, addr) - contractBackend.Commit() - adminList, err = contract.GetAllAdmin(nil) - if err != nil { - t.Error("fetch admin list failed", err) - } - if !reflect.DeepEqual(adminList, []common.Address{adminCandidate2}) { - t.Error("expect the returned admin list contain 3 address") - } + validateOperation(t, c, contractBackend, func() { + c.RemoveAdmin(transactOpts, addr, "") + }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { + adminList, err := c.GetAllAdmin(nil) + if err != nil { + return errors.New("get admin list failed") + } + if !reflect.DeepEqual(adminList, []common.Address{adminCandidate2}) { + return errors.New("remove admin failed") + } + if !validateEvents(1, events3) { + return errors.New("receive incorrect number of events") + } + return nil + }, "remove admin at head") // Test unauthorized operation - contract.AddAdmin(transactOpts, adminCandidate) - contractBackend.Commit() - adminList, err = contract.GetAllAdmin(nil) - if err != nil { - t.Error("fetch admin list failed", err) - } - if !reflect.DeepEqual(adminList, []common.Address{adminCandidate2}) { - t.Error("expect the returned admin list contain 3 address") - } + validateOperation(t, c, contractBackend, func() { + c.AddAdmin(transactOpts, adminCandidate, "") + }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { + adminList, err := c.GetAllAdmin(nil) + if err != nil { + return errors.New("get admin list failed") + } + if !reflect.DeepEqual(adminList, []common.Address{adminCandidate2}) { + return errors.New("unauthorized operation should be banned") + } + return nil + }, "unauthorized operation") } +// Tests checkpoint managements. func TestCheckpointRegister(t *testing.T) { // Deploy registrar contract transactOpts := bind.NewKeyedTransactor(key) contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) - _, _, contract, err := contract.DeployContract(transactOpts, contractBackend, []common.Address{addr}) + _, _, c, err := contract.DeployContract(transactOpts, contractBackend, []common.Address{addr}) if err != nil { t.Error("deploy registrar contract failed", err) } contractBackend.Commit() - // Register an unstable checkpoint - contract.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, - trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) - contractBackend.Commit() - head, chtRoot, bloomTrieRoot, err := contract.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) - if err != nil { - t.Error("fetch checkpoint failed", err) - } - if head != emptyHash || chtRoot != emptyHash || bloomTrieRoot != emptyHash { - t.Error("the unstable checkpoint is not allowed to be registered") - } + // Register unstable checkpoint + validateOperation(t, c, contractBackend, func() { + c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, + trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) + }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { + hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) + if err != nil { + return errors.New("get checkpoint failed") + } + if hash != emptyHash { + return errors.New("unstable checkpoint should be banned") + } + return nil + }, "register unstable checkpoint") // Register a stable checkpoint - contractBackend.ShiftBlocks(sectionSize + checkpointConfirmation) - contract.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, - trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) - contractBackend.Commit() - head, chtRoot, bloomTrieRoot, err = contract.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) - if err != nil { - t.Error("fetch checkpoint failed", err) - } - if !reflect.DeepEqual(head[:], trustedCheckpoint.SectionHead.Bytes()) || !reflect.DeepEqual(chtRoot[:], trustedCheckpoint.ChtRoot.Bytes()) || - !reflect.DeepEqual(bloomTrieRoot[:], trustedCheckpoint.BloomTrieRoot.Bytes()) { - t.Error("expect the returned checkpoint should be same with the given one") - } + validateOperation(t, c, contractBackend, func() { + contractBackend.ShiftBlocks(sectionSize + checkpointConfirmation) + c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, + trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) + }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { + hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) + if err != nil { + return errors.New("get checkpoint failed") + } + if common.Hash(hash).Hex() != crypto.Keccak256Hash(trustedCheckpoint.SectionHead.Bytes(), trustedCheckpoint.ChtRoot.Bytes(), trustedCheckpoint.BloomTrieRoot.Bytes()).Hex() { + return errors.New("register stable checkpoint failed") + } + if !validateEvents(1, events) { + return errors.New("receive incorrect number of events") + } + return nil + }, "register stable checkpoint") + + // Modify the latest checkpoint + validateOperation(t, c, contractBackend, func() { + trustedCheckpoint.SectionHead = common.HexToHash("dead") + c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, + trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) + }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { + hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) + if err != nil { + return errors.New("get checkpoint failed") + } + if common.Hash(hash).Hex() != crypto.Keccak256Hash(trustedCheckpoint.SectionHead.Bytes(), trustedCheckpoint.ChtRoot.Bytes(), trustedCheckpoint.BloomTrieRoot.Bytes()).Hex() { + return errors.New("register stable checkpoint failed") + } + if !validateEvents(1, events) { + return errors.New("receive incorrect number of events") + } + return nil + }, "modify latest checkpoint") } diff --git a/les/server.go b/les/server.go index ec276d1aa2..8d7b9b05c8 100644 --- a/les/server.go +++ b/les/server.go @@ -136,7 +136,7 @@ func (s *LesServer) Start(srvr *p2p.Server) { s.privateKey = srvr.PrivateKey s.protocolManager.blockLoop() if s.registrar != nil { - s.checkpointLoop() + go s.checkpointLoop() } } @@ -154,10 +154,9 @@ func (s *LesServer) Stop() { <-s.protocolManager.noMorePeers }() s.protocolManager.Stop() - close(s.quitSync) } -// checkpointLoop starts a standalone goroutine to watch new checkpoint event and upgrades local's stable checkpoint. +// checkpointLoop starts a standalone goroutine to watch new checkpoint event and updates local's stable checkpoint. func (s *LesServer) checkpointLoop() (err error) { sink := make(chan *contract.ContractNewCheckpointEvent) sub, err := s.registrar.WatchNewCheckpointEvent(sink) @@ -171,19 +170,12 @@ func (s *LesServer) checkpointLoop() (err error) { for { select { case event := <-sink: - // New stable checkpoint received - // Note several duplicate events can be received due to chain reorg, just track the first arrive one. - if event.Index.Uint64() > s.stableCheckpoint.SectionIdx { - checkpoint := &light.TrustedCheckpoint{ - SectionIdx: event.Index.Uint64(), - SectionHead: common.Hash(event.SectionHead), - ChtRoot: common.Hash(event.ChtRoot), - BloomTrieRoot: common.Hash(event.BloomTrieRoot), - } - light.WriteTrustedCheckpoint(s.protocolManager.chainDb, checkpoint) - s.stableCheckpoint = checkpoint - log.Info("update checkpoint", "section", checkpoint.SectionIdx, "head", checkpoint.SectionHead.Hex(), - "chtRoot", checkpoint.ChtRoot.Hex(), "bloomTrieRoot", checkpoint.BloomTrieRoot.Hex()) + // Note several duplicate events can be received because of latest checkpoint modification is allowed. + // Always update local checkpoint when the section index is not less than the local one. + // todo(rjl493456442) update local checkpoint + if event.Index.Uint64() >= s.stableCheckpoint.SectionIdx { + log.Info("update checkpoint", "section", event.Index, "hash", common.Hash(event.CheckpointHash).Hex(), + "grantor", event.Grantor.Hex()) } case <-s.quitSync: From 03820baeefb2eb0a29cbcaa7447e11fa37ab1ca2 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 1 Jun 2018 12:20:48 +0800 Subject: [PATCH 07/15] les: expose les server API --- eth/backend.go | 6 ++++ internal/web3ext/web3ext.go | 15 ++++++++++ les/api.go | 60 +++++++++++++++++++++++++++++++++++++ les/server.go | 42 ++++++++++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 les/api.go diff --git a/eth/backend.go b/eth/backend.go index a18abdfb56..d601dd9c28 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -54,6 +54,7 @@ import ( type LesServer interface { Start(srvr *p2p.Server) Stop() + APIs() []rpc.API Protocols() []p2p.Protocol SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) } @@ -247,6 +248,11 @@ func (s *Ethereum) APIs() []rpc.API { // Append any APIs exposed explicitly by the consensus engine apis = append(apis, s.engine.APIs(s.BlockChain())...) + // Append any APIs exposed explicitly by the les server + if s.lesServer != nil { + apis = append(apis, s.lesServer.APIs()...) + } + // Append all the local APIs and return return append(apis, []rpc.API{ { diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 89ebceec7c..a4e95b2978 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -30,6 +30,7 @@ var Modules = map[string]string{ "shh": Shh_JS, "swarmfs": SWARMFS_JS, "txpool": TxPool_JS, + "les": LES_JS, } const Chequebook_JS = ` @@ -631,3 +632,17 @@ web3._extend({ ] }); ` + +const LES_JS = ` +web3._extend({ + property: 'les', + methods: [], + properties: + [ + new web3._extend.Property({ + name: 'checkpoint', + getter: 'les_checkpoint' + }), + ] +}); +` diff --git a/les/api.go b/les/api.go new file mode 100644 index 0000000000..6987031913 --- /dev/null +++ b/les/api.go @@ -0,0 +1,60 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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. +// +// The go-ethereum library 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 the go-ethereum library. If not, see . + +package les + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var ( + errNoStableCheckpoint = errors.New("no stable checkpoint provided") +) + +// PublicLesServerAPI provides an API to access the les server. +// It offers only methods that operate on public data that is freely available to anyone. +type PublicLesServerAPI struct { + server *LesServer +} + +// NewPublicLesServerAPI creates a new les server API. +func NewPublicLesServerAPI(server *LesServer) *PublicLesServerAPI { + return &PublicLesServerAPI{ + server: server, + } +} + +// Checkpoint returns the latest checkpoint package. +// +// The checkpoint package consists of 4 strings: +// result[0], hex encoded latest section index +// result[1], 32 bytes hex encoded latest section head hash +// result[2], 32 bytes hex encoded latest section canonical hash trie root hash +// result[3], 32 bytes hex encoded latest section bloom trie root hash +func (api *PublicLesServerAPI) Checkpoint() ([4]string, error) { + var res [4]string + sectionIdx, sectionHead, chtRoot, bloomTrieRoot := api.server.getCheckpoint() + if sectionHead == (common.Hash{}) || chtRoot == (common.Hash{}) || bloomTrieRoot == (common.Hash{}) { + return res, errNoStableCheckpoint + } + res[0] = hexutil.Encode(big.NewInt(int64(sectionIdx)).Bytes()) + res[1], res[2], res[3] = sectionHead.Hex(), chtRoot.Hex(), bloomTrieRoot.Hex() + return res, nil +} diff --git a/les/server.go b/les/server.go index 8d7b9b05c8..f3182b68ff 100644 --- a/les/server.go +++ b/les/server.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/discv5" + "github.com/ethereum/go-ethereum/rpc" ) type LesServer struct { @@ -156,12 +157,53 @@ func (s *LesServer) Stop() { s.protocolManager.Stop() } +// APIs implements LesServer, returns all API service provided by les server. +func (s *LesServer) APIs() []rpc.API { + return []rpc.API{ + { + Namespace: "les", + Version: "1.0", + Service: NewPublicLesServerAPI(s), + Public: true, + }, + } +} + +// getCheckpoint finds the common stored section index and returns a set of +// post-processed trie roots (CHT and BloomTrie) associated with +// the appropriate section index and head hash as a checkpoint package. +// +// Note for cht, the section size in LES1 is 4K, so indexer still uses LES/1 +// 4k section size for backwards server compatibility. For bloomTrie, the size +// of the section used for indexer is 32K. +func (s *LesServer) getCheckpoint() (uint64, common.Hash, common.Hash, common.Hash) { + chtCount, _, _ := s.chtIndexer.Sections() + bloomTrieCount, _, _ := s.bloomTrieIndexer.Sections() + count := chtCount / (light.CHTFrequencyClient / light.CHTFrequencyServer) + // Cap the section index if the two sections are not consistent. + if count > bloomTrieCount { + count = bloomTrieCount + } + if count == 0 { + // No checkpoint information can be provided. + return 0, common.Hash{}, common.Hash{}, common.Hash{} + } + // convert last LES/2 section index back to LES/1 index for chtIndexer.SectionHead + latest := count*(light.CHTFrequencyClient/light.CHTFrequencyServer) - 1 + + sectionHead := s.chtIndexer.SectionHead(latest) + chtRoot := light.GetChtRoot(s.protocolManager.chainDb, latest, sectionHead) + bloomTrieRoot := light.GetBloomTrieRoot(s.protocolManager.chainDb, count-1, sectionHead) + return count - 1, sectionHead, chtRoot, bloomTrieRoot +} + // checkpointLoop starts a standalone goroutine to watch new checkpoint event and updates local's stable checkpoint. func (s *LesServer) checkpointLoop() (err error) { sink := make(chan *contract.ContractNewCheckpointEvent) sub, err := s.registrar.WatchNewCheckpointEvent(sink) if err != nil { return + } defer func() { sub.Unsubscribe() From 2b319f6b3e249d8b2fb2f3e0810bb4f53b45d849 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 1 Jun 2018 15:14:02 +0800 Subject: [PATCH 08/15] les: expose getCheckpoint API --- internal/web3ext/web3ext.go | 13 ++++++++++--- les/api.go | 20 ++++++++++++++++++-- les/server.go | 17 ++++++++++++----- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index a4e95b2978..88675a9659 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -636,12 +636,19 @@ web3._extend({ const LES_JS = ` web3._extend({ property: 'les', - methods: [], + methods: + [ + new web3._extend.Method({ + name: 'getCheckpoint', + call: 'les_getCheckpoint', + params: 1 + }), + ], properties: [ new web3._extend.Property({ - name: 'checkpoint', - getter: 'les_checkpoint' + name: 'latestCheckpoint', + getter: 'les_latestCheckpoint' }), ] }); diff --git a/les/api.go b/les/api.go index 6987031913..b58cf0fc82 100644 --- a/les/api.go +++ b/les/api.go @@ -48,9 +48,9 @@ func NewPublicLesServerAPI(server *LesServer) *PublicLesServerAPI { // result[1], 32 bytes hex encoded latest section head hash // result[2], 32 bytes hex encoded latest section canonical hash trie root hash // result[3], 32 bytes hex encoded latest section bloom trie root hash -func (api *PublicLesServerAPI) Checkpoint() ([4]string, error) { +func (api *PublicLesServerAPI) LatestCheckpoint() ([4]string, error) { var res [4]string - sectionIdx, sectionHead, chtRoot, bloomTrieRoot := api.server.getCheckpoint() + sectionIdx, sectionHead, chtRoot, bloomTrieRoot := api.server.latestCheckpoint() if sectionHead == (common.Hash{}) || chtRoot == (common.Hash{}) || bloomTrieRoot == (common.Hash{}) { return res, errNoStableCheckpoint } @@ -58,3 +58,19 @@ func (api *PublicLesServerAPI) Checkpoint() ([4]string, error) { res[1], res[2], res[3] = sectionHead.Hex(), chtRoot.Hex(), bloomTrieRoot.Hex() return res, nil } + +// GetCheckpoint returns the specific checkpoint package. +// +// The checkpoint package consists of 3 strings: +// result[0], 32 bytes hex encoded latest section head hash +// result[1], 32 bytes hex encoded latest section canonical hash trie root hash +// result[2], 32 bytes hex encoded latest section bloom trie root hash +func (api *PublicLesServerAPI) GetCheckpoint(index uint64) ([3]string, error) { + var res [3]string + sectionHead, chtRoot, bloomTrieRoot := api.server.getCheckpoint(index) + if sectionHead == (common.Hash{}) || chtRoot == (common.Hash{}) || bloomTrieRoot == (common.Hash{}) { + return res, errNoStableCheckpoint + } + res[0], res[1], res[2] = sectionHead.Hex(), chtRoot.Hex(), bloomTrieRoot.Hex() + return res, nil +} diff --git a/les/server.go b/les/server.go index f3182b68ff..7d935d1a31 100644 --- a/les/server.go +++ b/les/server.go @@ -169,14 +169,14 @@ func (s *LesServer) APIs() []rpc.API { } } -// getCheckpoint finds the common stored section index and returns a set of +// latestCheckpoint finds the common stored section index and returns a set of // post-processed trie roots (CHT and BloomTrie) associated with // the appropriate section index and head hash as a checkpoint package. // // Note for cht, the section size in LES1 is 4K, so indexer still uses LES/1 // 4k section size for backwards server compatibility. For bloomTrie, the size // of the section used for indexer is 32K. -func (s *LesServer) getCheckpoint() (uint64, common.Hash, common.Hash, common.Hash) { +func (s *LesServer) latestCheckpoint() (uint64, common.Hash, common.Hash, common.Hash) { chtCount, _, _ := s.chtIndexer.Sections() bloomTrieCount, _, _ := s.bloomTrieIndexer.Sections() count := chtCount / (light.CHTFrequencyClient / light.CHTFrequencyServer) @@ -188,13 +188,20 @@ func (s *LesServer) getCheckpoint() (uint64, common.Hash, common.Hash, common.Ha // No checkpoint information can be provided. return 0, common.Hash{}, common.Hash{}, common.Hash{} } + sectionHead, chtRoot, bloomTrieRoot := s.getCheckpoint(count - 1) + return count - 1, sectionHead, chtRoot, bloomTrieRoot +} + +// getCheckpoint returns a set of post-processed trie roots (CHT and BloomTrie) +// associated with the appropriate head hash by specific section index. +func (s *LesServer) getCheckpoint(index uint64) (common.Hash, common.Hash, common.Hash) { // convert last LES/2 section index back to LES/1 index for chtIndexer.SectionHead - latest := count*(light.CHTFrequencyClient/light.CHTFrequencyServer) - 1 + latest := (index+1)*(light.CHTFrequencyClient/light.CHTFrequencyServer) - 1 sectionHead := s.chtIndexer.SectionHead(latest) chtRoot := light.GetChtRoot(s.protocolManager.chainDb, latest, sectionHead) - bloomTrieRoot := light.GetBloomTrieRoot(s.protocolManager.chainDb, count-1, sectionHead) - return count - 1, sectionHead, chtRoot, bloomTrieRoot + bloomTrieRoot := light.GetBloomTrieRoot(s.protocolManager.chainDb, index, sectionHead) + return sectionHead, chtRoot, bloomTrieRoot } // checkpointLoop starts a standalone goroutine to watch new checkpoint event and updates local's stable checkpoint. From 536eb1632dab229b41a8c90b6c40685f9d82d2c1 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 8 Jun 2018 10:41:31 +0800 Subject: [PATCH 09/15] les: update/recover stable checkpoint --- contracts/registrar/contract/registrar.go | 2 +- contracts/registrar/contract/registrar.sol | 2 +- contracts/registrar/registrar.go | 18 +-- contracts/registrar/registrar_test.go | 24 +++- les/server.go | 126 ++++++++++++++++++--- light/checkpoint.go | 25 +++- light/checkpoint_test.go | 10 ++ 7 files changed, 171 insertions(+), 36 deletions(-) diff --git a/contracts/registrar/contract/registrar.go b/contracts/registrar/contract/registrar.go index ef5f87e847..d79736abf0 100644 --- a/contracts/registrar/contract/registrar.go +++ b/contracts/registrar/contract/registrar.go @@ -19,7 +19,7 @@ import ( const ContractABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"},{\"name\":\"_description\",\"type\":\"string\"}],\"name\":\"AddAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetAllAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetLatestCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"},{\"name\":\"_sectionHead\",\"type\":\"bytes32\"},{\"name\":\"_chtRoot\",\"type\":\"bytes32\"},{\"name\":\"_bloomTrieRoot\",\"type\":\"bytes32\"}],\"name\":\"SetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"}],\"name\":\"GetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"},{\"name\":\"_reason\",\"type\":\"string\"}],\"name\":\"RemoveAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_adminlist\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"index\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"checkpointHash\",\"type\":\"bytes32\"}],\"name\":\"NewCheckpointEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"description\",\"type\":\"string\"}],\"name\":\"AddAdminEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"RemoveAdminEvent\",\"type\":\"event\"}]" // ContractBin is the compiled bytecode used for deploying new contracts. -const ContractBin = `608060405234801561001057600080fd5b50604051610e83380380610e8383398101806040528101908080518201929190505050600060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060013390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600090505b81518110156101d2576001600080848481518110151561010057fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001828281518110151561015857fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505080806001019150506100e4565b5050610ca0806101e36000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633561247d1461007d57806345848dfc1461011e5780634d6a304c1461018a578063651c7f49146101c4578063710aeac814610233578063a5ba0be21461027c575b600080fd5b34801561008957600080fd5b50610104600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061031d565b604051808215151515815260200191505060405180910390f35b34801561012a57600080fd5b50610133610574565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561017657808201518184015260208101905061015b565b505050509050019250505060405180910390f35b34801561019657600080fd5b5061019f61065b565b6040518083815260200182600019166000191681526020019250505060405180910390f35b3480156101d057600080fd5b506102196004803603810190808035906020019092919080356000191690602001909291908035600019169060200190929190803560001916906020019092919050505061067a565b604051808215151515815260200191505060405180910390f35b34801561023f57600080fd5b5061025e60048036038101908080359060200190929190505050610874565b60405180826000191660001916815260200191505060405180910390f35b34801561028857600080fd5b50610303600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610891565b604051808215151515815260200191505060405180910390f35b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561036b57600080fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411156103bb576000905061056e565b60016000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507fecd88a3d10808aac9f879bbae95f9e4f9687f6c9f0615b88af2085f226d3cf93833384604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561052d578082015181840152602081019050610512565b50505050905090810190601f16801561055a5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600190505b92915050565b60608060006001805490506040519080825280602002602001820160405280156105ad5781602001602082028038833980820191505090505b509150600090505b600180549050811015610653576001818154811015156105d157fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110151561060a57fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080806001019150506105b5565b819250505090565b600080600061066b600354610874565b90506003548192509250509091565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156106c857600080fd5b60035485141580156106df57506001600354018514155b80156106ee5750600060035414155b156106fc576000905061086c565b6101f4618000600187010201431015610718576000905061086c565b8383836040516020018084600019166000191681526020018360001916600019168152602001826000191660001916815260200193505050506040516020818303038152906040526040518082805190602001908083835b6020831015156107955780518252602082019150602081019050602083039250610770565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060026000878152602001908152602001600020816000191690555084600381905550847f5b3eab050ccf1a983a26b4f6acb13c199093c7d2e7523a0ff036519f7ddaf560336002600089815260200190815260200160002054604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182600019166000191681526020019250505060405180910390a25b949350505050565b600060026000838152602001908152602001600020549050919050565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156108e257600080fd5b60008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414156109325760009250610c1b565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b600180549050821015610b12578473ffffffffffffffffffffffffffffffffffffffff166001838154811015156109ac57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610b05578190505b6001808054905003811015610aa6576001808201815481101515610a1757fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600182815481101515610a5157fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080806001019150506109f7565b600180808054905003815481101515610abb57fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905560018081818054905003915081610aff9190610c23565b50610b12565b8180600101925050610979565b7fe7d6ab069cde0507dc9c5971bf93e9fd183db04690725946e8cae907367e7c1f853386604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610bda578082015181840152602081019050610bbf565b50505050905090810190601f168015610c075780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600192505b505092915050565b815481835581811115610c4a57818360005260206000209182019101610c499190610c4f565b5b505050565b610c7191905b80821115610c6d576000816000905550600101610c55565b5090565b905600a165627a7a72305820791f0110aacecdc551cc4d3bda7cc4228762aa3acdce5f7b1b1d9efb1534b8320029` +const ContractBin = `608060405234801561001057600080fd5b50604051610e83380380610e8383398101806040528101908080518201929190505050600060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060013390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600090505b81518110156101d2576001600080848481518110151561010057fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001828281518110151561015857fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505080806001019150506100e4565b5050610ca0806101e36000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633561247d1461007d57806345848dfc1461011e5780634d6a304c1461018a578063651c7f49146101c4578063710aeac814610233578063a5ba0be21461027c575b600080fd5b34801561008957600080fd5b50610104600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061031d565b604051808215151515815260200191505060405180910390f35b34801561012a57600080fd5b50610133610574565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561017657808201518184015260208101905061015b565b505050509050019250505060405180910390f35b34801561019657600080fd5b5061019f61065b565b6040518083815260200182600019166000191681526020019250505060405180910390f35b3480156101d057600080fd5b506102196004803603810190808035906020019092919080356000191690602001909291908035600019169060200190929190803560001916906020019092919050505061067a565b604051808215151515815260200191505060405180910390f35b34801561023f57600080fd5b5061025e60048036038101908080359060200190929190505050610874565b60405180826000191660001916815260200191505060405180910390f35b34801561028857600080fd5b50610303600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610891565b604051808215151515815260200191505060405180910390f35b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561036b57600080fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411156103bb576000905061056e565b60016000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507fecd88a3d10808aac9f879bbae95f9e4f9687f6c9f0615b88af2085f226d3cf93833384604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561052d578082015181840152602081019050610512565b50505050905090810190601f16801561055a5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600190505b92915050565b60608060006001805490506040519080825280602002602001820160405280156105ad5781602001602082028038833980820191505090505b509150600090505b600180549050811015610653576001818154811015156105d157fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110151561060a57fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080806001019150506105b5565b819250505090565b600080600061066b600354610874565b90506003548192509250509091565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156106c857600080fd5b60035485141580156106df57506001600354018514155b80156106ee5750600060035414155b156106fc576000905061086c565b610100618000600187010201431015610718576000905061086c565b8383836040516020018084600019166000191681526020018360001916600019168152602001826000191660001916815260200193505050506040516020818303038152906040526040518082805190602001908083835b6020831015156107955780518252602082019150602081019050602083039250610770565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060026000878152602001908152602001600020816000191690555084600381905550847f5b3eab050ccf1a983a26b4f6acb13c199093c7d2e7523a0ff036519f7ddaf560336002600089815260200190815260200160002054604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182600019166000191681526020019250505060405180910390a25b949350505050565b600060026000838152602001908152602001600020549050919050565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156108e257600080fd5b60008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414156109325760009250610c1b565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b600180549050821015610b12578473ffffffffffffffffffffffffffffffffffffffff166001838154811015156109ac57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610b05578190505b6001808054905003811015610aa6576001808201815481101515610a1757fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600182815481101515610a5157fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080806001019150506109f7565b600180808054905003815481101515610abb57fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905560018081818054905003915081610aff9190610c23565b50610b12565b8180600101925050610979565b7fe7d6ab069cde0507dc9c5971bf93e9fd183db04690725946e8cae907367e7c1f853386604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610bda578082015181840152602081019050610bbf565b50505050905090810190601f168015610c075780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600192505b505092915050565b815481835581811115610c4a57818360005260206000209182019101610c499190610c4f565b5b505050565b610c7191905b80821115610c6d576000816000905550600101610c55565b5090565b905600a165627a7a723058208a04962a64cdbd8ff23fe8ac9263f150ac5ef09bc46fe9c174e53bdd9f58e11d0029` // DeployContract deploys a new Ethereum contract, binding an instance of Contract to it. func DeployContract(auth *bind.TransactOpts, backend bind.ContractBackend, _adminlist []common.Address) (common.Address, *types.Transaction, *Contract, error) { diff --git a/contracts/registrar/contract/registrar.sol b/contracts/registrar/contract/registrar.sol index 37125bccb3..a5e1f8d0c8 100644 --- a/contracts/registrar/contract/registrar.sol +++ b/contracts/registrar/contract/registrar.sol @@ -209,6 +209,6 @@ contract Registrar { // The number of confirmations needed before a checkpoint can be registered. // We have to make sure the checkpoint registered will not be invalid due to // chain reorg. - uint constant confirmations = 500; + uint constant confirmations = 256; } diff --git a/contracts/registrar/registrar.go b/contracts/registrar/registrar.go index f2059baf0d..dfa47570b1 100644 --- a/contracts/registrar/registrar.go +++ b/contracts/registrar/registrar.go @@ -32,19 +32,14 @@ import ( var ( // registrar contract address for mainnet and testnet. RegistrarAddr = map[common.Hash]common.Address{ - params.MainnetGenesisHash: common.HexToAddress(""), - params.TestnetGenesisHash: common.HexToAddress(""), + // params.MainnetGenesisHash: common.HexToAddress(""), + // params.TestnetGenesisHash: common.HexToAddress(""), params.RinkebyGenesisHash: common.HexToAddress("0xe3f2686a5d0c56a2d853c19c46b173a755263be8"), } ) var errEventNotFound = errors.New("contract event not found") -const ( - sectionSize = 32768 // The frequency for creating a checkpoint - checkpointConfirmation = 500 // The number of confirmations needed before a checkpoint can be accepted -) - type Registrar struct { contract *contract.Contract } @@ -67,15 +62,14 @@ func (registrar *Registrar) WatchNewCheckpointEvent(sink chan<- *contract.Contra } // FilterNewCheckpointEvent filters out NewCheckpointEvent for specific section number. -func (registrar *Registrar) FilterNewCheckpointEvent(head uint64, section uint64) (*contract.ContractNewCheckpointEventIterator, error) { - start := (section + 1) * sectionSize - end := head - checkpointConfirmation - if end < start { +func (registrar *Registrar) FilterNewCheckpointEvent(head, section, sectionSize, processConfirm uint64) (*contract.ContractNewCheckpointEventIterator, error) { + start := (section+1)*sectionSize + processConfirm + if head < start { return nil, errEventNotFound } opt := &bind.FilterOpts{ Start: start, - End: &end, + End: &head, } return registrar.contract.FilterNewCheckpointEvent(opt, []*big.Int{big.NewInt(int64(section))}) } diff --git a/contracts/registrar/registrar_test.go b/contracts/registrar/registrar_test.go index 9565cd9325..9add4c638d 100644 --- a/contracts/registrar/registrar_test.go +++ b/contracts/registrar/registrar_test.go @@ -213,9 +213,27 @@ func TestCheckpointRegister(t *testing.T) { return nil }, "register unstable checkpoint") + contractBackend.ShiftBlocks(light.CheckpointFrequency + light.CheckpointProcessConfirmations) + + // Register by unauthorized user + validateOperation(t, c, contractBackend, func() { + user2, _ := crypto.GenerateKey() + unauthorized := bind.NewKeyedTransactor(user2) + c.SetCheckpoint(unauthorized, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, + trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) + }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { + hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) + if err != nil { + return errors.New("get checkpoint failed") + } + if hash != emptyHash { + return errors.New("unstable checkpoint should be banned") + } + return nil + }, "register by unauthorized user") + // Register a stable checkpoint validateOperation(t, c, contractBackend, func() { - contractBackend.ShiftBlocks(sectionSize + checkpointConfirmation) c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { @@ -223,7 +241,7 @@ func TestCheckpointRegister(t *testing.T) { if err != nil { return errors.New("get checkpoint failed") } - if common.Hash(hash).Hex() != crypto.Keccak256Hash(trustedCheckpoint.SectionHead.Bytes(), trustedCheckpoint.ChtRoot.Bytes(), trustedCheckpoint.BloomTrieRoot.Bytes()).Hex() { + if !trustedCheckpoint.HashEqual(common.Hash(hash)) { return errors.New("register stable checkpoint failed") } if !validateEvents(1, events) { @@ -242,7 +260,7 @@ func TestCheckpointRegister(t *testing.T) { if err != nil { return errors.New("get checkpoint failed") } - if common.Hash(hash).Hex() != crypto.Keccak256Hash(trustedCheckpoint.SectionHead.Bytes(), trustedCheckpoint.ChtRoot.Bytes(), trustedCheckpoint.BloomTrieRoot.Bytes()).Hex() { + if !trustedCheckpoint.HashEqual(common.Hash(hash)) { return errors.New("register stable checkpoint failed") } if !validateEvents(1, events) { diff --git a/les/server.go b/les/server.go index 7d935d1a31..5ad0fcb065 100644 --- a/les/server.go +++ b/les/server.go @@ -19,6 +19,7 @@ package les import ( "crypto/ecdsa" + "errors" "sync" "github.com/ethereum/go-ethereum/common" @@ -28,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/les/flowcontrol" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" @@ -36,8 +38,13 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) +// chainHeadChanSize is the size of channel listening to ChainHeadEvent. +const SubscribeChainHeadEvent = 10 + type LesServer struct { config *eth.Config + backend *eth.EthAPIBackend + chaindb ethdb.Database protocolManager *ProtocolManager fcManager *flowcontrol.ClientManager // nil if our node is client only fcCostStats *requestCostStats @@ -69,6 +76,8 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { srv := &LesServer{ config: config, + backend: eth.APIBackend, + chaindb: eth.ChainDb(), protocolManager: pm, quitSync: quitSync, lesTopics: lesTopics, @@ -85,14 +94,14 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { // convert last LES/2 section index back to LES/1 index for chtIndexer.SectionHead chtLastSectionV1 := (chtLastSection+1)*(light.CHTFrequencyClient/light.CHTFrequencyServer) - 1 chtSectionHead := srv.chtIndexer.SectionHead(chtLastSectionV1) - chtRoot := light.GetChtV2Root(pm.chainDb, chtLastSection, chtSectionHead) + chtRoot := light.GetChtV2Root(srv.chaindb, chtLastSection, chtSectionHead) logger.Info("Loaded CHT", "section", chtLastSection, "head", chtSectionHead, "root", chtRoot) } bloomTrieSectionCount, _, _ := srv.bloomTrieIndexer.Sections() if bloomTrieSectionCount != 0 { bloomTrieLastSection := bloomTrieSectionCount - 1 bloomTrieSectionHead := srv.bloomTrieIndexer.SectionHead(bloomTrieLastSection) - bloomTrieRoot := light.GetBloomTrieRoot(pm.chainDb, bloomTrieLastSection, bloomTrieSectionHead) + bloomTrieRoot := light.GetBloomTrieRoot(srv.chaindb, bloomTrieLastSection, bloomTrieSectionHead) logger.Info("Loaded bloom trie", "section", bloomTrieLastSection, "head", bloomTrieSectionHead, "root", bloomTrieRoot) } @@ -137,6 +146,7 @@ func (s *LesServer) Start(srvr *p2p.Server) { s.privateKey = srvr.PrivateKey s.protocolManager.blockLoop() if s.registrar != nil { + s.stableCheckpoint = s.recoverCheckpoint() go s.checkpointLoop() } } @@ -204,29 +214,66 @@ func (s *LesServer) getCheckpoint(index uint64) (common.Hash, common.Hash, commo return sectionHead, chtRoot, bloomTrieRoot } -// checkpointLoop starts a standalone goroutine to watch new checkpoint event and updates local's stable checkpoint. +// checkpointLoop starts a standalone goroutine to watch new checkpoint events and updates local's stable checkpoint. func (s *LesServer) checkpointLoop() (err error) { - sink := make(chan *contract.ContractNewCheckpointEvent) - sub, err := s.registrar.WatchNewCheckpointEvent(sink) + var ( + eventCh = make(chan *contract.ContractNewCheckpointEvent) + headCh = make(chan core.ChainHeadEvent, SubscribeChainHeadEvent) + announcement = make(map[uint64]common.Hash) + ) + eventSub, err := s.registrar.WatchNewCheckpointEvent(eventCh) if err != nil { - return - + return err + } + headSub := s.backend.SubscribeChainHeadEvent(headCh) + if headSub == nil { + eventSub.Unsubscribe() + return errors.New("subscribe head event failed") } defer func() { - sub.Unsubscribe() + eventSub.Unsubscribe() + headSub.Unsubscribe() }() for { select { - case event := <-sink: - // Note several duplicate events can be received because of latest checkpoint modification is allowed. - // Always update local checkpoint when the section index is not less than the local one. - // todo(rjl493456442) update local checkpoint - if event.Index.Uint64() >= s.stableCheckpoint.SectionIdx { - log.Info("update checkpoint", "section", event.Index, "hash", common.Hash(event.CheckpointHash).Hex(), - "grantor", event.Grantor.Hex()) + case event := <-eventCh: + if event == nil { + // This should never happen. + log.Info("Ignore empty checkpoint event") + continue + } + // Note several duplicate events may be received because of chain reorg and the modification of the latest checkpoint. + if s.stableCheckpoint == nil || event.Index.Uint64() >= s.stableCheckpoint.SectionIdx { + log.Info("Receive new checkpoint event", "section", event.Index, "hash", common.Hash(event.CheckpointHash).Hex(), + "grantor", event.Grantor.Hex()) + announcement[event.Index.Uint64()] = common.Hash(event.CheckpointHash) + } + case head := <-headCh: + number := head.Block.NumberU64() + if number < light.CheckpointConfirmations+light.CheckpointFrequency { + continue + } + idx := (number-light.CheckpointConfirmations)/light.CheckpointFrequency - 1 + if s.stableCheckpoint == nil || idx > s.stableCheckpoint.SectionIdx { + hash, ok := announcement[idx] + if !ok { + continue + } + sectionHead := s.bloomTrieIndexer.SectionHead(idx) + checkpoint := &light.TrustedCheckpoint{ + SectionIdx: idx, + SectionHead: sectionHead, + ChtRoot: light.GetChtV2Root(s.chaindb, idx, sectionHead), + BloomTrieRoot: light.GetBloomTrieRoot(s.chaindb, idx, sectionHead), + } + if checkpoint.HashEqual(common.Hash(hash)) { + light.WriteTrustedCheckpoint(s.chaindb, checkpoint) + s.stableCheckpoint = checkpoint + log.Info("Update stable checkpoint", "section", checkpoint.SectionIdx) + delete(announcement, idx) + } } - case <-s.quitSync: // Les server is closed. return @@ -234,6 +281,53 @@ func (s *LesServer) checkpointLoop() (err error) { } } +// recoveryCheckpoint filters checkpoint announcement events and recovers stable checkpoint. +func (s *LesServer) recoverCheckpoint() *light.TrustedCheckpoint { + var ( + sectionCnt, _, _ = s.bloomTrieIndexer.Sections() + stable = light.ReadTrustedCheckpoint(s.chaindb) + unstableIdx = sectionCnt - 1 + headHash = rawdb.ReadHeadHeaderHash(s.chaindb) + headNumber = rawdb.ReadHeaderNumber(s.chaindb, headHash) + ) + if headNumber == nil { + return nil + } + for stable == nil || stable.SectionIdx < unstableIdx { + if (unstableIdx+1)*light.CheckpointFrequency+light.CheckpointConfirmations <= *headNumber { + iter, err := s.registrar.FilterNewCheckpointEvent(*headNumber, unstableIdx, light.CheckpointFrequency, light.CheckpointProcessConfirmations) + if err == nil { + for iter.Next() { + sectionHead := s.bloomTrieIndexer.SectionHead(unstableIdx) + checkpoint := &light.TrustedCheckpoint{ + SectionIdx: unstableIdx, + SectionHead: sectionHead, + ChtRoot: light.GetChtV2Root(s.chaindb, unstableIdx, sectionHead), + BloomTrieRoot: light.GetBloomTrieRoot(s.chaindb, unstableIdx, sectionHead), + } + if checkpoint.HashEqual(common.Hash(iter.Event.CheckpointHash)) { + light.WriteTrustedCheckpoint(s.chaindb, checkpoint) + iter.Close() + log.Info("Recover checkpoint", "index", checkpoint.SectionIdx) + return checkpoint + } + } + iter.Close() + } + } + if unstableIdx == 0 { + break + } + unstableIdx -= 1 + } + if stable == nil { + log.Info("No stable checkpoint") + } else { + log.Info("Recover checkpoint", "index", stable.SectionIdx) + } + return stable +} + func (pm *ProtocolManager) blockLoop() { pm.wg.Add(1) headCh := make(chan core.ChainHeadEvent, 10) diff --git a/light/checkpoint.go b/light/checkpoint.go index 192471f30f..118cb646b8 100644 --- a/light/checkpoint.go +++ b/light/checkpoint.go @@ -20,17 +20,27 @@ import ( "io" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" ) -var ( - // checkpointKey tracks the latest stable checkpoint. - checkpointKey = []byte("Checkpoint") +const ( + // CheckpointFrequency is the block frequency for creating checkpoint + CheckpointFrequency = 32768 + + // CheckpointProcessConfirmations is the number before a checkpoint is generated + CheckpointProcessConfirmations = 256 + + // CheckpointConfirmations is the number of confirmations before a checkpoint is stable + CheckpointConfirmations = 8192 ) +// checkpointKey tracks the latest stable checkpoint. +var checkpointKey = []byte("Checkpoint") + // TrustedCheckpoint represents a set of post-processed trie roots (CHT and BloomTrie) associated with // the appropriate section index and head hash. // @@ -68,6 +78,15 @@ func (c *TrustedCheckpoint) DecodeRLP(s *rlp.Stream) error { return nil } +// HashEqual returns an indicator comparing the itself hash with given one. +// A nil argument is equivalent to an empty slice. +func (c *TrustedCheckpoint) HashEqual(hash common.Hash) bool { + if c.SectionHead == (common.Hash{}) && c.ChtRoot == (common.Hash{}) && c.BloomTrieRoot == (common.Hash{}) { + return hash == common.Hash{} + } + return crypto.Keccak256Hash(c.SectionHead.Bytes(), c.ChtRoot.Bytes(), c.BloomTrieRoot.Bytes()) == hash +} + var ( // Hardcode checkpoint for mainnet and testnet(ropsten). Will be deleted eventually once checkpoint contract // works. diff --git a/light/checkpoint_test.go b/light/checkpoint_test.go index 483fb12724..3b419c5ea8 100644 --- a/light/checkpoint_test.go +++ b/light/checkpoint_test.go @@ -39,6 +39,16 @@ func TestRWCheckpoint(t *testing.T) { } } +func TestHashEqual(t *testing.T) { + if !testCheckpoint.HashEqual(common.HexToHash("0x6142a271d44a56107cd9de0be0a04211841593906b310f8c4d33be56b6e78959")) { + t.Error("checkpoint should hash equal to given one") + } + emptyCheckpoint := &TrustedCheckpoint{} + if !emptyCheckpoint.HashEqual(common.Hash{}) { + t.Error("empty checkpoint should equal to empty hash") + } +} + func assertCheckpointEqual(ckp1, ckp2 *TrustedCheckpoint) bool { return ckp1.SectionIdx == ckp2.SectionIdx && ckp1.SectionHead == ckp2.SectionHead && ckp1.ChtRoot == ckp2.ChtRoot && ckp1.BloomTrieRoot == ckp2.BloomTrieRoot From a3871519760650c796801914e5ddcdd5962b052e Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 12 Jun 2018 10:24:33 +0800 Subject: [PATCH 10/15] contracts: register hash only and fix interface puzzle --- contracts/registrar/contract/registrar.go | 28 ++++++------- contracts/registrar/contract/registrar.sol | 12 ++---- contracts/registrar/registrar.go | 8 ++-- contracts/registrar/registrar_test.go | 21 +++++----- eth/bind.go | 47 ++++++++++++++-------- eth/filters/api.go | 5 --- internal/ethapi/backend.go | 3 -- les/server.go | 22 +++++----- 8 files changed, 71 insertions(+), 75 deletions(-) diff --git a/contracts/registrar/contract/registrar.go b/contracts/registrar/contract/registrar.go index d79736abf0..5b4c774b49 100644 --- a/contracts/registrar/contract/registrar.go +++ b/contracts/registrar/contract/registrar.go @@ -16,10 +16,10 @@ import ( ) // ContractABI is the input ABI used to generate the binding from. -const ContractABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"},{\"name\":\"_description\",\"type\":\"string\"}],\"name\":\"AddAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetAllAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetLatestCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"},{\"name\":\"_sectionHead\",\"type\":\"bytes32\"},{\"name\":\"_chtRoot\",\"type\":\"bytes32\"},{\"name\":\"_bloomTrieRoot\",\"type\":\"bytes32\"}],\"name\":\"SetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"}],\"name\":\"GetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"},{\"name\":\"_reason\",\"type\":\"string\"}],\"name\":\"RemoveAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_adminlist\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"index\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"checkpointHash\",\"type\":\"bytes32\"}],\"name\":\"NewCheckpointEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"description\",\"type\":\"string\"}],\"name\":\"AddAdminEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"RemoveAdminEvent\",\"type\":\"event\"}]" +const ContractABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"},{\"name\":\"_description\",\"type\":\"string\"}],\"name\":\"AddAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetAllAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetLatestCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"}],\"name\":\"GetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"},{\"name\":\"_reason\",\"type\":\"string\"}],\"name\":\"RemoveAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"},{\"name\":\"_hash\",\"type\":\"bytes32\"}],\"name\":\"SetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_adminlist\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"index\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"checkpointHash\",\"type\":\"bytes32\"}],\"name\":\"NewCheckpointEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"description\",\"type\":\"string\"}],\"name\":\"AddAdminEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"RemoveAdminEvent\",\"type\":\"event\"}]" // ContractBin is the compiled bytecode used for deploying new contracts. -const ContractBin = `608060405234801561001057600080fd5b50604051610e83380380610e8383398101806040528101908080518201929190505050600060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060013390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600090505b81518110156101d2576001600080848481518110151561010057fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001828281518110151561015857fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505080806001019150506100e4565b5050610ca0806101e36000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633561247d1461007d57806345848dfc1461011e5780634d6a304c1461018a578063651c7f49146101c4578063710aeac814610233578063a5ba0be21461027c575b600080fd5b34801561008957600080fd5b50610104600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061031d565b604051808215151515815260200191505060405180910390f35b34801561012a57600080fd5b50610133610574565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561017657808201518184015260208101905061015b565b505050509050019250505060405180910390f35b34801561019657600080fd5b5061019f61065b565b6040518083815260200182600019166000191681526020019250505060405180910390f35b3480156101d057600080fd5b506102196004803603810190808035906020019092919080356000191690602001909291908035600019169060200190929190803560001916906020019092919050505061067a565b604051808215151515815260200191505060405180910390f35b34801561023f57600080fd5b5061025e60048036038101908080359060200190929190505050610874565b60405180826000191660001916815260200191505060405180910390f35b34801561028857600080fd5b50610303600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610891565b604051808215151515815260200191505060405180910390f35b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561036b57600080fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411156103bb576000905061056e565b60016000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507fecd88a3d10808aac9f879bbae95f9e4f9687f6c9f0615b88af2085f226d3cf93833384604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561052d578082015181840152602081019050610512565b50505050905090810190601f16801561055a5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600190505b92915050565b60608060006001805490506040519080825280602002602001820160405280156105ad5781602001602082028038833980820191505090505b509150600090505b600180549050811015610653576001818154811015156105d157fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110151561060a57fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080806001019150506105b5565b819250505090565b600080600061066b600354610874565b90506003548192509250509091565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156106c857600080fd5b60035485141580156106df57506001600354018514155b80156106ee5750600060035414155b156106fc576000905061086c565b610100618000600187010201431015610718576000905061086c565b8383836040516020018084600019166000191681526020018360001916600019168152602001826000191660001916815260200193505050506040516020818303038152906040526040518082805190602001908083835b6020831015156107955780518252602082019150602081019050602083039250610770565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060026000878152602001908152602001600020816000191690555084600381905550847f5b3eab050ccf1a983a26b4f6acb13c199093c7d2e7523a0ff036519f7ddaf560336002600089815260200190815260200160002054604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182600019166000191681526020019250505060405180910390a25b949350505050565b600060026000838152602001908152602001600020549050919050565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156108e257600080fd5b60008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414156109325760009250610c1b565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b600180549050821015610b12578473ffffffffffffffffffffffffffffffffffffffff166001838154811015156109ac57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610b05578190505b6001808054905003811015610aa6576001808201815481101515610a1757fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600182815481101515610a5157fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080806001019150506109f7565b600180808054905003815481101515610abb57fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905560018081818054905003915081610aff9190610c23565b50610b12565b8180600101925050610979565b7fe7d6ab069cde0507dc9c5971bf93e9fd183db04690725946e8cae907367e7c1f853386604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610bda578082015181840152602081019050610bbf565b50505050905090810190601f168015610c075780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600192505b505092915050565b815481835581811115610c4a57818360005260206000209182019101610c499190610c4f565b5b505050565b610c7191905b80821115610c6d576000816000905550600101610c55565b5090565b905600a165627a7a723058208a04962a64cdbd8ff23fe8ac9263f150ac5ef09bc46fe9c174e53bdd9f58e11d0029` +const ContractBin = `608060405234801561001057600080fd5b50604051610da9380380610da983398101806040528101908080518201929190505050600060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060013390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600090505b81518110156101d2576001600080848481518110151561010057fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001828281518110151561015857fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505080806001019150506100e4565b5050610bc6806101e36000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633561247d1461007d57806345848dfc1461011e5780634d6a304c1461018a578063710aeac8146101c4578063a5ba0be21461020d578063c4885d57146102ae575b600080fd5b34801561008957600080fd5b50610104600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610301565b604051808215151515815260200191505060405180910390f35b34801561012a57600080fd5b50610133610558565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561017657808201518184015260208101905061015b565b505050509050019250505060405180910390f35b34801561019657600080fd5b5061019f61063f565b6040518083815260200182600019166000191681526020019250505060405180910390f35b3480156101d057600080fd5b506101ef6004803603810190808035906020019092919050505061065e565b60405180826000191660001916815260200191505060405180910390f35b34801561021957600080fd5b50610294600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061067b565b604051808215151515815260200191505060405180910390f35b3480156102ba57600080fd5b506102e7600480360381019080803590602001909291908035600019169060200190929190505050610a0d565b604051808215151515815260200191505060405180910390f35b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561034f57600080fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111561039f5760009050610552565b60016000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507fecd88a3d10808aac9f879bbae95f9e4f9687f6c9f0615b88af2085f226d3cf93833384604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156105115780820151818401526020810190506104f6565b50505050905090810190601f16801561053e5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600190505b92915050565b60608060006001805490506040519080825280602002602001820160405280156105915781602001602082028038833980820191505090505b509150600090505b600180549050811015610637576001818154811015156105b557fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682828151811015156105ee57fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508080600101915050610599565b819250505090565b600080600061064f60035461065e565b90506003548192509250509091565b600060026000838152602001908152602001600020549050919050565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156106cc57600080fd5b60008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141561071c5760009250610a05565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b6001805490508210156108fc578473ffffffffffffffffffffffffffffffffffffffff1660018381548110151561079657fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156108ef578190505b600180805490500381101561089057600180820181548110151561080157fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660018281548110151561083b57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080806001019150506107e1565b6001808080549050038154811015156108a557fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600180818180549050039150816108e99190610b49565b506108fc565b8180600101925050610763565b7fe7d6ab069cde0507dc9c5971bf93e9fd183db04690725946e8cae907367e7c1f853386604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156109c45780820151818401526020810190506109a9565b50505050905090810190601f1680156109f15780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600192505b505092915050565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111515610a5b57600080fd5b6003548314158015610a7257506001600354018314155b8015610a815750600060035414155b15610a8f5760009050610b43565b610100618000600185010201431015610aab5760009050610b43565b8160026000858152602001908152602001600020816000191690555082600381905550827f5b3eab050ccf1a983a26b4f6acb13c199093c7d2e7523a0ff036519f7ddaf5603384604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182600019166000191681526020019250505060405180910390a25b92915050565b815481835581811115610b7057818360005260206000209182019101610b6f9190610b75565b5b505050565b610b9791905b80821115610b93576000816000905550600101610b7b565b5090565b905600a165627a7a72305820eb37f4d3298a6e621a53fa9a92f70e4ae3fa9a8908075f947a120f69cf68fef40029` // DeployContract deploys a new Ethereum contract, binding an instance of Contract to it. func DeployContract(auth *bind.TransactOpts, backend bind.ContractBackend, _adminlist []common.Address) (common.Address, *types.Transaction, *Contract, error) { @@ -300,25 +300,25 @@ func (_Contract *ContractTransactorSession) RemoveAdmin(_addr common.Address, _r return _Contract.Contract.RemoveAdmin(&_Contract.TransactOpts, _addr, _reason) } -// SetCheckpoint is a paid mutator transaction binding the contract method 0x651c7f49. +// SetCheckpoint is a paid mutator transaction binding the contract method 0xc4885d57. // -// Solidity: function SetCheckpoint(_sectionIndex uint256, _sectionHead bytes32, _chtRoot bytes32, _bloomTrieRoot bytes32) returns(bool) -func (_Contract *ContractTransactor) SetCheckpoint(opts *bind.TransactOpts, _sectionIndex *big.Int, _sectionHead [32]byte, _chtRoot [32]byte, _bloomTrieRoot [32]byte) (*types.Transaction, error) { - return _Contract.contract.Transact(opts, "SetCheckpoint", _sectionIndex, _sectionHead, _chtRoot, _bloomTrieRoot) +// Solidity: function SetCheckpoint(_sectionIndex uint256, _hash bytes32) returns(bool) +func (_Contract *ContractTransactor) SetCheckpoint(opts *bind.TransactOpts, _sectionIndex *big.Int, _hash [32]byte) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "SetCheckpoint", _sectionIndex, _hash) } -// SetCheckpoint is a paid mutator transaction binding the contract method 0x651c7f49. +// SetCheckpoint is a paid mutator transaction binding the contract method 0xc4885d57. // -// Solidity: function SetCheckpoint(_sectionIndex uint256, _sectionHead bytes32, _chtRoot bytes32, _bloomTrieRoot bytes32) returns(bool) -func (_Contract *ContractSession) SetCheckpoint(_sectionIndex *big.Int, _sectionHead [32]byte, _chtRoot [32]byte, _bloomTrieRoot [32]byte) (*types.Transaction, error) { - return _Contract.Contract.SetCheckpoint(&_Contract.TransactOpts, _sectionIndex, _sectionHead, _chtRoot, _bloomTrieRoot) +// Solidity: function SetCheckpoint(_sectionIndex uint256, _hash bytes32) returns(bool) +func (_Contract *ContractSession) SetCheckpoint(_sectionIndex *big.Int, _hash [32]byte) (*types.Transaction, error) { + return _Contract.Contract.SetCheckpoint(&_Contract.TransactOpts, _sectionIndex, _hash) } -// SetCheckpoint is a paid mutator transaction binding the contract method 0x651c7f49. +// SetCheckpoint is a paid mutator transaction binding the contract method 0xc4885d57. // -// Solidity: function SetCheckpoint(_sectionIndex uint256, _sectionHead bytes32, _chtRoot bytes32, _bloomTrieRoot bytes32) returns(bool) -func (_Contract *ContractTransactorSession) SetCheckpoint(_sectionIndex *big.Int, _sectionHead [32]byte, _chtRoot [32]byte, _bloomTrieRoot [32]byte) (*types.Transaction, error) { - return _Contract.Contract.SetCheckpoint(&_Contract.TransactOpts, _sectionIndex, _sectionHead, _chtRoot, _bloomTrieRoot) +// Solidity: function SetCheckpoint(_sectionIndex uint256, _hash bytes32) returns(bool) +func (_Contract *ContractTransactorSession) SetCheckpoint(_sectionIndex *big.Int, _hash [32]byte) (*types.Transaction, error) { + return _Contract.Contract.SetCheckpoint(&_Contract.TransactOpts, _sectionIndex, _hash) } // ContractAddAdminEventIterator is returned from FilterAddAdminEvent and is used to iterate over the raw logs and unpacked data for AddAdminEvent events raised by the Contract contract. diff --git a/contracts/registrar/contract/registrar.sol b/contracts/registrar/contract/registrar.sol index a5e1f8d0c8..122f5611de 100644 --- a/contracts/registrar/contract/registrar.sol +++ b/contracts/registrar/contract/registrar.sol @@ -86,16 +86,12 @@ contract Registrar { * Note we trust the given information here provided by foundation, * need a trust less version for future. * @param _sectionIndex section index - * @param _sectionHead section header - * @param _chtRoot cht root hash - * @param _bloomTrieRoot bloom trie root hash + * @param _hash checkpoint hash calculated in the client side * @return indicator whether set checkpoint successfully */ function SetCheckpoint( uint _sectionIndex, - bytes32 _sectionHead, - bytes32 _chtRoot, - bytes32 _bloomTrieRoot + bytes32 _hash ) OnlyAuthorized public @@ -111,10 +107,10 @@ contract Registrar { return false; } - checkpoints[_sectionIndex] = keccak256(abi.encodePacked(_sectionHead, _chtRoot, _bloomTrieRoot)); + checkpoints[_sectionIndex] = _hash; latest = _sectionIndex; - emit NewCheckpointEvent(_sectionIndex, msg.sender, checkpoints[_sectionIndex]); + emit NewCheckpointEvent(_sectionIndex, msg.sender, _hash); } /** diff --git a/contracts/registrar/registrar.go b/contracts/registrar/registrar.go index dfa47570b1..1c1a176b79 100644 --- a/contracts/registrar/registrar.go +++ b/contracts/registrar/registrar.go @@ -23,9 +23,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/registrar/contract" - "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/params" ) @@ -34,7 +32,7 @@ var ( RegistrarAddr = map[common.Hash]common.Address{ // params.MainnetGenesisHash: common.HexToAddress(""), // params.TestnetGenesisHash: common.HexToAddress(""), - params.RinkebyGenesisHash: common.HexToAddress("0xe3f2686a5d0c56a2d853c19c46b173a755263be8"), + params.RinkebyGenesisHash: common.HexToAddress("0xaefc742121f79ce9d0953fea7c9cd10f6586179b"), } ) @@ -45,8 +43,8 @@ type Registrar struct { } // NewRegistrar binds checkpoint contract and returns a registrar instance. -func NewRegistrar(contractAddr common.Address, backend ethapi.Backend, lightMode bool) (*Registrar, error) { - contract, err := contract.NewContract(contractAddr, eth.NewContractBackend(backend, lightMode)) +func NewRegistrar(contractAddr common.Address, backend bind.ContractBackend) (*Registrar, error) { + contract, err := contract.NewContract(contractAddr, backend) if err != nil { return nil, err } diff --git a/contracts/registrar/registrar_test.go b/contracts/registrar/registrar_test.go index 9add4c638d..54c37f7ff6 100644 --- a/contracts/registrar/registrar_test.go +++ b/contracts/registrar/registrar_test.go @@ -43,6 +43,7 @@ var ( ChtRoot: common.HexToHash("cf92fd2a79464354e8dae4d589ae92acdf90a3a4f8f7d8a3ec5fb9c114ae81cd"), BloomTrieRoot: common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), } + checkpointHash = crypto.Keccak256Hash(trustedCheckpoint.SectionHead.Bytes(), trustedCheckpoint.ChtRoot.Bytes(), trustedCheckpoint.BloomTrieRoot.Bytes()) ) // validateOperation executes the operation, watches and delivers all events fired by the backend and ensures the @@ -200,8 +201,7 @@ func TestCheckpointRegister(t *testing.T) { // Register unstable checkpoint validateOperation(t, c, contractBackend, func() { - c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, - trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) + c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), checkpointHash) }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) if err != nil { @@ -219,29 +219,27 @@ func TestCheckpointRegister(t *testing.T) { validateOperation(t, c, contractBackend, func() { user2, _ := crypto.GenerateKey() unauthorized := bind.NewKeyedTransactor(user2) - c.SetCheckpoint(unauthorized, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, - trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) + c.SetCheckpoint(unauthorized, big.NewInt(int64(trustedCheckpoint.SectionIdx)), checkpointHash) }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) if err != nil { return errors.New("get checkpoint failed") } if hash != emptyHash { - return errors.New("unstable checkpoint should be banned") + return errors.New("checkpoint from unauthorized user should be banned") } return nil }, "register by unauthorized user") // Register a stable checkpoint validateOperation(t, c, contractBackend, func() { - c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, - trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) + c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), checkpointHash) }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) if err != nil { return errors.New("get checkpoint failed") } - if !trustedCheckpoint.HashEqual(common.Hash(hash)) { + if hash != checkpointHash { return errors.New("register stable checkpoint failed") } if !validateEvents(1, events) { @@ -250,17 +248,16 @@ func TestCheckpointRegister(t *testing.T) { return nil }, "register stable checkpoint") + fakeHash := crypto.Keccak256Hash([]byte("dead"), []byte("beef"), []byte("deadbeef")) // Modify the latest checkpoint validateOperation(t, c, contractBackend, func() { - trustedCheckpoint.SectionHead = common.HexToHash("dead") - c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), trustedCheckpoint.SectionHead, - trustedCheckpoint.ChtRoot, trustedCheckpoint.BloomTrieRoot) + c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), fakeHash) }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) if err != nil { return errors.New("get checkpoint failed") } - if !trustedCheckpoint.HashEqual(common.Hash(hash)) { + if hash != fakeHash { return errors.New("register stable checkpoint failed") } if !validateEvents(1, events) { diff --git a/eth/bind.go b/eth/bind.go index 7119114519..ca339b696a 100644 --- a/eth/bind.go +++ b/eth/bind.go @@ -39,20 +39,22 @@ import ( // object. These should be rewritten to internal Go method calls when the Go API // is refactored to support a clean library use. type ContractBackend struct { - eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata - bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data - txapi *ethapi.PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data - filterapi *filters.PublicFilterAPI // Wrapper around the filter to watch and retrieve contract logs + filterBackend filters.Backend // Backend used for filter vm logs. + events *filters.EventSystem // Event system used to watch new fired vm logs. + eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata + bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data + txapi *ethapi.PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data } // NewContractBackend creates a new native contract backend using an existing // Ethereum object. -func NewContractBackend(apiBackend ethapi.Backend, lightMode bool) *ContractBackend { +func NewContractBackend(apiBackend ethapi.Backend, filterBackend filters.Backend, lightMode bool) *ContractBackend { return &ContractBackend{ - eapi: ethapi.NewPublicEthereumAPI(apiBackend), - bcapi: ethapi.NewPublicBlockChainAPI(apiBackend), - txapi: ethapi.NewPublicTransactionPoolAPI(apiBackend, new(ethapi.AddrLocker)), - filterapi: filters.NewPublicFilterAPI(apiBackend.(filters.Backend), lightMode), + filterBackend: filterBackend, + events: filters.NewEventSystem(apiBackend.EventMux(), filterBackend, lightMode), + eapi: ethapi.NewPublicEthereumAPI(apiBackend), + bcapi: ethapi.NewPublicBlockChainAPI(apiBackend), + txapi: ethapi.NewPublicTransactionPoolAPI(apiBackend, new(ethapi.AddrLocker)), } } @@ -93,7 +95,7 @@ func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) if err != nil { return nil, err } - return (*big.Int)(price), nil + return price.ToInt(), nil } // EstimateGasLimit implements bind.ContractTransactor trying to estimate the gas @@ -117,23 +119,34 @@ func (b *ContractBackend) SendTransaction(ctx context.Context, tx *types.Transac // FilterLogs implements bind.ContractFilterer returning logs matching the given argument // that are stored within the state. func (b *ContractBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { - ret, err := b.filterapi.GetLogs(ctx, filters.FilterCriteria(query)) + // Initialize unset filter boundaried to run from genesis to chain head + from := int64(0) + if query.FromBlock != nil { + from = query.FromBlock.Int64() + } + to := int64(-1) + if query.ToBlock != nil { + to = query.ToBlock.Int64() + } + // Construct and execute the filter + filter := filters.New(b.filterBackend, from, to, query.Addresses, query.Topics) + + logs, err := filter.Logs(ctx) if err != nil { return nil, err } - logs := make([]types.Log, len(ret)) - for idx, log := range ret { - logs[idx] = *log + res := make([]types.Log, len(logs)) + for i, log := range logs { + res[i] = *log } - return logs, nil + return res, nil } // SubscribeFilterLogs implements bind.ContractFilterer watching new fired logs matching the given argument. func (b *ContractBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { // Subscribe to contract events sink := make(chan []*types.Log) - - sub, err := b.filterapi.EventSystem().SubscribeLogs(query, sink) + sub, err := b.events.SubscribeLogs(query, sink) if err != nil { return nil, err } diff --git a/eth/filters/api.go b/eth/filters/api.go index 9c2cb093c9..5ed80a8875 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -75,11 +75,6 @@ func NewPublicFilterAPI(backend Backend, lightMode bool) *PublicFilterAPI { return api } -// EventSystem returns -func (filter *PublicFilterAPI) EventSystem() *EventSystem { - return filter.events -} - // timeoutLoop runs every 5 minutes and deletes filters that have not been recently used. // Tt is started when the api is created. func (api *PublicFilterAPI) timeoutLoop() { diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 444f051652..c9ffe230c6 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -45,8 +44,6 @@ type Backend interface { ChainDb() ethdb.Database EventMux() *event.TypeMux AccountManager() *accounts.Manager - BloomStatus() (uint64, uint64) - ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) // BlockChain API SetHead(number uint64) diff --git a/les/server.go b/les/server.go index 5ad0fcb065..aeabbc0ff1 100644 --- a/les/server.go +++ b/les/server.go @@ -62,27 +62,27 @@ type LesServer struct { bloomTrieIndexer *core.ChainIndexer // Indexers for creating bloom trie root for each block section } -func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { +func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) { quitSync := make(chan struct{}) - pm, err := NewProtocolManager(eth.BlockChain().Config(), false, ServerProtocolVersions, config.NetworkId, eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil, nil, quitSync, new(sync.WaitGroup)) + pm, err := NewProtocolManager(e.BlockChain().Config(), false, ServerProtocolVersions, config.NetworkId, e.EventMux(), e.Engine(), newPeerSet(), e.BlockChain(), e.TxPool(), e.ChainDb(), nil, nil, nil, quitSync, new(sync.WaitGroup)) if err != nil { return nil, err } lesTopics := make([]discv5.Topic, len(AdvertiseProtocolVersions)) for i, pv := range AdvertiseProtocolVersions { - lesTopics[i] = lesTopic(eth.BlockChain().Genesis().Hash(), pv) + lesTopics[i] = lesTopic(e.BlockChain().Genesis().Hash(), pv) } srv := &LesServer{ config: config, - backend: eth.APIBackend, - chaindb: eth.ChainDb(), + backend: e.APIBackend, + chaindb: e.ChainDb(), protocolManager: pm, quitSync: quitSync, lesTopics: lesTopics, - chtIndexer: light.NewChtIndexer(eth.ChainDb(), false), - bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), false), + chtIndexer: light.NewChtIndexer(e.ChainDb(), false), + bloomTrieIndexer: light.NewBloomTrieIndexer(e.ChainDb(), false), } logger := log.New() @@ -105,7 +105,7 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { logger.Info("Loaded bloom trie", "section", bloomTrieLastSection, "head", bloomTrieSectionHead, "root", bloomTrieRoot) } - srv.chtIndexer.Start(eth.BlockChain()) + srv.chtIndexer.Start(e.BlockChain()) pm.server = srv srv.defParams = &flowcontrol.ServerParams{ @@ -113,9 +113,9 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { MinRecharge: 50000, } srv.fcManager = flowcontrol.NewClientManager(uint64(config.LightServ), 10, 1000000000) - srv.fcCostStats = newCostStats(eth.ChainDb()) - if addr, ok := registrar.RegistrarAddr[eth.BlockChain().Genesis().Hash()]; ok { - registrar, err := registrar.NewRegistrar(addr, eth.APIBackend, false) + srv.fcCostStats = newCostStats(e.ChainDb()) + if addr, ok := registrar.RegistrarAddr[e.BlockChain().Genesis().Hash()]; ok { + registrar, err := registrar.NewRegistrar(addr, eth.NewContractBackend(e.APIBackend, e.APIBackend, false)) if err != nil { return nil, err } From ca478b2dd29973c666c62cb46f3f980b0b25562c Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 13 Jun 2018 11:14:36 +0800 Subject: [PATCH 11/15] contracts: limit modification allowed time range --- contracts/registrar/contract/registrar.go | 2 +- contracts/registrar/contract/registrar.sol | 11 +++- contracts/registrar/registrar_test.go | 65 ++++++++++++++++------ 3 files changed, 57 insertions(+), 21 deletions(-) diff --git a/contracts/registrar/contract/registrar.go b/contracts/registrar/contract/registrar.go index 5b4c774b49..543a5fc643 100644 --- a/contracts/registrar/contract/registrar.go +++ b/contracts/registrar/contract/registrar.go @@ -19,7 +19,7 @@ import ( const ContractABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"},{\"name\":\"_description\",\"type\":\"string\"}],\"name\":\"AddAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetAllAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"GetLatestCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"}],\"name\":\"GetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_addr\",\"type\":\"address\"},{\"name\":\"_reason\",\"type\":\"string\"}],\"name\":\"RemoveAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_sectionIndex\",\"type\":\"uint256\"},{\"name\":\"_hash\",\"type\":\"bytes32\"}],\"name\":\"SetCheckpoint\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_adminlist\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"index\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"checkpointHash\",\"type\":\"bytes32\"}],\"name\":\"NewCheckpointEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"description\",\"type\":\"string\"}],\"name\":\"AddAdminEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"grantor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"RemoveAdminEvent\",\"type\":\"event\"}]" // ContractBin is the compiled bytecode used for deploying new contracts. -const ContractBin = `608060405234801561001057600080fd5b50604051610da9380380610da983398101806040528101908080518201929190505050600060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060013390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600090505b81518110156101d2576001600080848481518110151561010057fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001828281518110151561015857fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505080806001019150506100e4565b5050610bc6806101e36000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633561247d1461007d57806345848dfc1461011e5780634d6a304c1461018a578063710aeac8146101c4578063a5ba0be21461020d578063c4885d57146102ae575b600080fd5b34801561008957600080fd5b50610104600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610301565b604051808215151515815260200191505060405180910390f35b34801561012a57600080fd5b50610133610558565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561017657808201518184015260208101905061015b565b505050509050019250505060405180910390f35b34801561019657600080fd5b5061019f61063f565b6040518083815260200182600019166000191681526020019250505060405180910390f35b3480156101d057600080fd5b506101ef6004803603810190808035906020019092919050505061065e565b60405180826000191660001916815260200191505060405180910390f35b34801561021957600080fd5b50610294600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061067b565b604051808215151515815260200191505060405180910390f35b3480156102ba57600080fd5b506102e7600480360381019080803590602001909291908035600019169060200190929190505050610a0d565b604051808215151515815260200191505060405180910390f35b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561034f57600080fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111561039f5760009050610552565b60016000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507fecd88a3d10808aac9f879bbae95f9e4f9687f6c9f0615b88af2085f226d3cf93833384604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156105115780820151818401526020810190506104f6565b50505050905090810190601f16801561053e5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600190505b92915050565b60608060006001805490506040519080825280602002602001820160405280156105915781602001602082028038833980820191505090505b509150600090505b600180549050811015610637576001818154811015156105b557fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682828151811015156105ee57fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508080600101915050610599565b819250505090565b600080600061064f60035461065e565b90506003548192509250509091565b600060026000838152602001908152602001600020549050919050565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156106cc57600080fd5b60008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141561071c5760009250610a05565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b6001805490508210156108fc578473ffffffffffffffffffffffffffffffffffffffff1660018381548110151561079657fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156108ef578190505b600180805490500381101561089057600180820181548110151561080157fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660018281548110151561083b57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080806001019150506107e1565b6001808080549050038154811015156108a557fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600180818180549050039150816108e99190610b49565b506108fc565b8180600101925050610763565b7fe7d6ab069cde0507dc9c5971bf93e9fd183db04690725946e8cae907367e7c1f853386604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156109c45780820151818401526020810190506109a9565b50505050905090810190601f1680156109f15780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600192505b505092915050565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111515610a5b57600080fd5b6003548314158015610a7257506001600354018314155b8015610a815750600060035414155b15610a8f5760009050610b43565b610100618000600185010201431015610aab5760009050610b43565b8160026000858152602001908152602001600020816000191690555082600381905550827f5b3eab050ccf1a983a26b4f6acb13c199093c7d2e7523a0ff036519f7ddaf5603384604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182600019166000191681526020019250505060405180910390a25b92915050565b815481835581811115610b7057818360005260206000209182019101610b6f9190610b75565b5b505050565b610b9791905b80821115610b93576000816000905550600101610b7b565b5090565b905600a165627a7a72305820eb37f4d3298a6e621a53fa9a92f70e4ae3fa9a8908075f947a120f69cf68fef40029` +const ContractBin = `608060405234801561001057600080fd5b50604051610de2380380610de283398101806040528101908080518201929190505050600060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060013390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600090505b81518110156101d2576001600080848481518110151561010057fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001828281518110151561015857fe5b9060200190602002015190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505080806001019150506100e4565b5050610bff806101e36000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633561247d1461007d57806345848dfc1461011e5780634d6a304c1461018a578063710aeac8146101c4578063a5ba0be21461020d578063c4885d57146102ae575b600080fd5b34801561008957600080fd5b50610104600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610301565b604051808215151515815260200191505060405180910390f35b34801561012a57600080fd5b50610133610558565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561017657808201518184015260208101905061015b565b505050509050019250505060405180910390f35b34801561019657600080fd5b5061019f61063f565b6040518083815260200182600019166000191681526020019250505060405180910390f35b3480156101d057600080fd5b506101ef6004803603810190808035906020019092919050505061065e565b60405180826000191660001916815260200191505060405180910390f35b34801561021957600080fd5b50610294600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061067b565b604051808215151515815260200191505060405180910390f35b3480156102ba57600080fd5b506102e7600480360381019080803590602001909291908035600019169060200190929190505050610a0d565b604051808215151515815260200191505060405180910390f35b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205411151561034f57600080fd5b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111561039f5760009050610552565b60016000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060018390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507fecd88a3d10808aac9f879bbae95f9e4f9687f6c9f0615b88af2085f226d3cf93833384604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156105115780820151818401526020810190506104f6565b50505050905090810190601f16801561053e5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600190505b92915050565b60608060006001805490506040519080825280602002602001820160405280156105915781602001602082028038833980820191505090505b509150600090505b600180549050811015610637576001818154811015156105b557fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682828151811015156105ee57fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508080600101915050610599565b819250505090565b600080600061064f60035461065e565b90506003548192509250509091565b600060026000838152602001908152602001600020549050919050565b6000806000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115156106cc57600080fd5b60008060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054141561071c5760009250610a05565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009055600091505b6001805490508210156108fc578473ffffffffffffffffffffffffffffffffffffffff1660018381548110151561079657fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156108ef578190505b600180805490500381101561089057600180820181548110151561080157fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660018281548110151561083b57fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080806001019150506107e1565b6001808080549050038154811015156108a557fe5b9060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055600180818180549050039150816108e99190610b82565b506108fc565b8180600101925050610763565b7fe7d6ab069cde0507dc9c5971bf93e9fd183db04690725946e8cae907367e7c1f853386604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156109c45780820151818401526020810190506109a9565b50505050905090810190601f1680156109f15780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1600192505b505092915050565b6000806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111515610a5b57600080fd5b6003548314158015610a7257506001600354018314155b8015610a815750600060035414155b15610a8f5760009050610b7c565b610100618000600185010201431015610aab5760009050610b7c565b600060035414158015610abf575060035483145b8015610ad657506120006180006001850102014310155b15610ae45760009050610b7c565b8160026000858152602001908152602001600020816000191690555082600381905550827f5b3eab050ccf1a983a26b4f6acb13c199093c7d2e7523a0ff036519f7ddaf5603384604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182600019166000191681526020019250505060405180910390a25b92915050565b815481835581811115610ba957818360005260206000209182019101610ba89190610bae565b5b505050565b610bd091905b80821115610bcc576000816000905550600101610bb4565b5090565b905600a165627a7a723058206af229b85ceb246e4b06af39c8058d670504df652a68b19dad6b2a883f3028580029` // DeployContract deploys a new Ethereum contract, binding an instance of Contract to it. func DeployContract(auth *bind.TransactOpts, backend bind.ContractBackend, _adminlist []common.Address) (common.Address, *types.Transaction, *Contract, error) { diff --git a/contracts/registrar/contract/registrar.sol b/contracts/registrar/contract/registrar.sol index 122f5611de..7dbbfe8e6d 100644 --- a/contracts/registrar/contract/registrar.sol +++ b/contracts/registrar/contract/registrar.sol @@ -103,9 +103,13 @@ contract Registrar { return false; } // Ensure the checkpoint is stable enough to be registered. - if (block.number < (_sectionIndex+1)*sectionSize+confirmations) { + if (block.number < (_sectionIndex+1)*sectionSize+processConfirmations) { return false; } + // Ensure the modification for registered checkpoint within the allowed time range + if (latest != 0 && _sectionIndex == latest && block.number >= (_sectionIndex+1)*sectionSize+confirmations) { + return false; + } checkpoints[_sectionIndex] = _hash; latest = _sectionIndex; @@ -205,6 +209,9 @@ contract Registrar { // The number of confirmations needed before a checkpoint can be registered. // We have to make sure the checkpoint registered will not be invalid due to // chain reorg. - uint constant confirmations = 256; + uint constant processConfirmations = 256; + + // The number of confirmations when a registered checkpoint can not be modified. + uint constant confirmations = 8192; } diff --git a/contracts/registrar/registrar_test.go b/contracts/registrar/registrar_test.go index 54c37f7ff6..393ece8123 100644 --- a/contracts/registrar/registrar_test.go +++ b/contracts/registrar/registrar_test.go @@ -37,13 +37,8 @@ var ( addr = crypto.PubkeyToAddress(key.PublicKey) emptyHash = [32]byte{} - trustedCheckpoint = light.TrustedCheckpoint{ - SectionIdx: 0, - SectionHead: common.HexToHash("14c8639dfc32812ed20839f5a11993cd59b22e5226cb2179640ba5c1f0c08f87"), - ChtRoot: common.HexToHash("cf92fd2a79464354e8dae4d589ae92acdf90a3a4f8f7d8a3ec5fb9c114ae81cd"), - BloomTrieRoot: common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), - } - checkpointHash = crypto.Keccak256Hash(trustedCheckpoint.SectionHead.Bytes(), trustedCheckpoint.ChtRoot.Bytes(), trustedCheckpoint.BloomTrieRoot.Bytes()) + checkpointHash0 = crypto.Keccak256Hash(common.Hex2Bytes("dead0"), common.Hex2Bytes("beef0"), common.Hex2Bytes("deadbeef0")) + checkpointHash1 = crypto.Keccak256Hash(common.Hex2Bytes("dead1"), common.Hex2Bytes("beef1"), common.Hex2Bytes("deadbeef1")) ) // validateOperation executes the operation, watches and delivers all events fired by the backend and ensures the @@ -201,9 +196,9 @@ func TestCheckpointRegister(t *testing.T) { // Register unstable checkpoint validateOperation(t, c, contractBackend, func() { - c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), checkpointHash) + c.SetCheckpoint(transactOpts, big.NewInt(0), checkpointHash0) }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { - hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) + hash, err := c.GetCheckpoint(nil, big.NewInt(0)) if err != nil { return errors.New("get checkpoint failed") } @@ -219,9 +214,9 @@ func TestCheckpointRegister(t *testing.T) { validateOperation(t, c, contractBackend, func() { user2, _ := crypto.GenerateKey() unauthorized := bind.NewKeyedTransactor(user2) - c.SetCheckpoint(unauthorized, big.NewInt(int64(trustedCheckpoint.SectionIdx)), checkpointHash) + c.SetCheckpoint(unauthorized, big.NewInt(0), checkpointHash0) }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { - hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) + hash, err := c.GetCheckpoint(nil, big.NewInt(0)) if err != nil { return errors.New("get checkpoint failed") } @@ -233,13 +228,13 @@ func TestCheckpointRegister(t *testing.T) { // Register a stable checkpoint validateOperation(t, c, contractBackend, func() { - c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), checkpointHash) + c.SetCheckpoint(transactOpts, big.NewInt(0), checkpointHash0) }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { - hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) + hash, err := c.GetCheckpoint(nil, big.NewInt(0)) if err != nil { return errors.New("get checkpoint failed") } - if hash != checkpointHash { + if hash != checkpointHash0 { return errors.New("register stable checkpoint failed") } if !validateEvents(1, events) { @@ -248,16 +243,16 @@ func TestCheckpointRegister(t *testing.T) { return nil }, "register stable checkpoint") - fakeHash := crypto.Keccak256Hash([]byte("dead"), []byte("beef"), []byte("deadbeef")) + newHash := crypto.Keccak256Hash([]byte("dead00"), []byte("beef00"), []byte("deadbeef00")) // Modify the latest checkpoint validateOperation(t, c, contractBackend, func() { - c.SetCheckpoint(transactOpts, big.NewInt(int64(trustedCheckpoint.SectionIdx)), fakeHash) + c.SetCheckpoint(transactOpts, big.NewInt(0), newHash) }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { - hash, err := c.GetCheckpoint(nil, big.NewInt(int64(trustedCheckpoint.SectionIdx))) + hash, err := c.GetCheckpoint(nil, big.NewInt(0)) if err != nil { return errors.New("get checkpoint failed") } - if hash != fakeHash { + if hash != newHash { return errors.New("register stable checkpoint failed") } if !validateEvents(1, events) { @@ -265,4 +260,38 @@ func TestCheckpointRegister(t *testing.T) { } return nil }, "modify latest checkpoint") + + contractBackend.ShiftBlocks(light.CheckpointFrequency) + // Register checkpoint 1 + validateOperation(t, c, contractBackend, func() { + c.SetCheckpoint(transactOpts, big.NewInt(1), checkpointHash1) + }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { + hash, err := c.GetCheckpoint(nil, big.NewInt(1)) + if err != nil { + return errors.New("get checkpoint failed") + } + if hash != checkpointHash1 { + return errors.New("register stable checkpoint failed") + } + if !validateEvents(1, events) { + return errors.New("receive incorrect number of events") + } + return nil + }, "register stable checkpoint 1") + + contractBackend.ShiftBlocks(light.CheckpointConfirmations) + newHash1 := crypto.Keccak256Hash([]byte("dead11"), []byte("beef11"), []byte("deadbeef11")) + // Modify the registered checkpoint after a very long time + validateOperation(t, c, contractBackend, func() { + c.SetCheckpoint(transactOpts, big.NewInt(1), newHash1) + }, func(events <-chan *contract.ContractNewCheckpointEvent, events2 <-chan *contract.ContractAddAdminEvent, events3 <-chan *contract.ContractRemoveAdminEvent) error { + hash, err := c.GetCheckpoint(nil, big.NewInt(1)) + if err != nil { + return errors.New("get checkpoint failed") + } + if hash != checkpointHash1 { + return errors.New("checkpoint modified out of allowed time range") + } + return nil + }, "modify checkpoint out of allowed time range") } From d3d408ba8112e61eb0bea34a13d1a7866e697a1c Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 13 Jun 2018 13:21:41 +0800 Subject: [PATCH 12/15] node, eth, les: use ethclient as a contract backend --- cmd/utils/flags.go | 17 +++ contracts/registrar/registrar.go | 2 +- contracts/registrar/registrar_test.go | 8 +- eth/backend.go | 10 ++ eth/bind.go | 198 -------------------------- les/server.go | 76 ++++++---- light/checkpoint.go | 7 +- node/node.go | 41 +++++- node/service.go | 4 + 9 files changed, 128 insertions(+), 235 deletions(-) delete mode 100644 eth/bind.go diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 522ad06b61..afa1d4d403 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -19,11 +19,13 @@ package utils import ( "crypto/ecdsa" + "errors" "fmt" "io/ioutil" "math/big" "os" "path/filepath" + "reflect" "runtime" "strconv" "strings" @@ -44,6 +46,7 @@ import ( "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethstats" "github.com/ethereum/go-ethereum/les" @@ -1175,6 +1178,20 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) { } return fullNode, err }) + if err == nil { + err = stack.RegisterCallback(reflect.TypeOf(ð.Ethereum{}), func(service node.Service) error { + if e, ok := service.(*eth.Ethereum); ok { + rpcClient, err := stack.AttachLocked() + if err != nil { + return err + } + e.SetClient(ethclient.NewClient(rpcClient)) + return nil + } else { + return errors.New("the service given is not the required type") + } + }) + } } if err != nil { Fatalf("Failed to register the Ethereum service: %v", err) diff --git a/contracts/registrar/registrar.go b/contracts/registrar/registrar.go index 1c1a176b79..a7d8ce81c3 100644 --- a/contracts/registrar/registrar.go +++ b/contracts/registrar/registrar.go @@ -32,7 +32,7 @@ var ( RegistrarAddr = map[common.Hash]common.Address{ // params.MainnetGenesisHash: common.HexToAddress(""), // params.TestnetGenesisHash: common.HexToAddress(""), - params.RinkebyGenesisHash: common.HexToAddress("0xaefc742121f79ce9d0953fea7c9cd10f6586179b"), + params.RinkebyGenesisHash: common.HexToAddress("0xc72f57e41e2498ad3dab92f665b0f21e2c4f4b79"), } ) diff --git a/contracts/registrar/registrar_test.go b/contracts/registrar/registrar_test.go index 393ece8123..46f6ff1948 100644 --- a/contracts/registrar/registrar_test.go +++ b/contracts/registrar/registrar_test.go @@ -37,8 +37,8 @@ var ( addr = crypto.PubkeyToAddress(key.PublicKey) emptyHash = [32]byte{} - checkpointHash0 = crypto.Keccak256Hash(common.Hex2Bytes("dead0"), common.Hex2Bytes("beef0"), common.Hex2Bytes("deadbeef0")) - checkpointHash1 = crypto.Keccak256Hash(common.Hex2Bytes("dead1"), common.Hex2Bytes("beef1"), common.Hex2Bytes("deadbeef1")) + checkpointHash0 = crypto.Keccak256Hash(common.FromHex("dead0"), common.FromHex("beef0"), common.FromHex("deadbeef0")) + checkpointHash1 = crypto.Keccak256Hash(common.FromHex("dead1"), common.FromHex("beef1"), common.FromHex("deadbeef1")) ) // validateOperation executes the operation, watches and delivers all events fired by the backend and ensures the @@ -243,7 +243,7 @@ func TestCheckpointRegister(t *testing.T) { return nil }, "register stable checkpoint") - newHash := crypto.Keccak256Hash([]byte("dead00"), []byte("beef00"), []byte("deadbeef00")) + newHash := crypto.Keccak256Hash(common.FromHex("dead00"), common.FromHex("beef00"), common.FromHex("deadbeef00")) // Modify the latest checkpoint validateOperation(t, c, contractBackend, func() { c.SetCheckpoint(transactOpts, big.NewInt(0), newHash) @@ -280,7 +280,7 @@ func TestCheckpointRegister(t *testing.T) { }, "register stable checkpoint 1") contractBackend.ShiftBlocks(light.CheckpointConfirmations) - newHash1 := crypto.Keccak256Hash([]byte("dead11"), []byte("beef11"), []byte("deadbeef11")) + newHash1 := crypto.Keccak256Hash(common.FromHex("dead11"), common.FromHex("beef11"), common.FromHex("deadbeef11")) // Modify the registered checkpoint after a very long time validateOperation(t, c, contractBackend, func() { c.SetCheckpoint(transactOpts, big.NewInt(1), newHash1) diff --git a/eth/backend.go b/eth/backend.go index d601dd9c28..fabeee75fa 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -57,6 +58,7 @@ type LesServer interface { APIs() []rpc.API Protocols() []p2p.Protocol SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) + SetClient(*ethclient.Client) } // Ethereum implements the Ethereum full node service. @@ -100,6 +102,14 @@ func (s *Ethereum) AddLesServer(ls LesServer) { ls.SetBloomBitsIndexer(s.bloomIndexer) } +// SetClient sets a rpc client which connecting to our local node. +func (s *Ethereum) SetClient(client *ethclient.Client) { + // Pass the rpc client to les server if it is enabled. + if s.lesServer != nil { + s.lesServer.SetClient(client) + } +} + // New creates a new Ethereum object (including the // initialisation of the common Ethereum object) func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { diff --git a/eth/bind.go b/eth/bind.go deleted file mode 100644 index ca339b696a..0000000000 --- a/eth/bind.go +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library 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. -// -// The go-ethereum library 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 the go-ethereum library. If not, see . - -package eth - -import ( - "context" - "math/big" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/filters" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/internal/ethapi" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc" -) - -// ContractBackend implements bind.ContractBackend with direct calls to Ethereum -// internals to support operating on contracts within subprotocols like eth, les and -// swarm. -// -// Internally this backend uses the already exposed API endpoints of the Ethereum -// object. These should be rewritten to internal Go method calls when the Go API -// is refactored to support a clean library use. -type ContractBackend struct { - filterBackend filters.Backend // Backend used for filter vm logs. - events *filters.EventSystem // Event system used to watch new fired vm logs. - eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata - bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data - txapi *ethapi.PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data -} - -// NewContractBackend creates a new native contract backend using an existing -// Ethereum object. -func NewContractBackend(apiBackend ethapi.Backend, filterBackend filters.Backend, lightMode bool) *ContractBackend { - return &ContractBackend{ - filterBackend: filterBackend, - events: filters.NewEventSystem(apiBackend.EventMux(), filterBackend, lightMode), - eapi: ethapi.NewPublicEthereumAPI(apiBackend), - bcapi: ethapi.NewPublicBlockChainAPI(apiBackend), - txapi: ethapi.NewPublicTransactionPoolAPI(apiBackend, new(ethapi.AddrLocker)), - } -} - -// CodeAt implements bind.ContractCaller retrieving any code associated -// with the contract from the local API. -func (b *ContractBackend) CodeAt(ctx context.Context, contract common.Address, blockNum *big.Int) ([]byte, error) { - return b.bcapi.GetCode(ctx, contract, toBlockNumber(blockNum)) -} - -// ContractCall implements bind.ContractCaller executing an Ethereum contract -// call with the specified data as the input. The pending flag requests execution -// against the pending block, not the stable head of the chain. -func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNum *big.Int) ([]byte, error) { - out, err := b.bcapi.Call(ctx, toCallArgs(msg), toBlockNumber(blockNum)) - return out, err -} - -// PendingCodeAt implements bind.ContractTransactor retrieving any code associated -// with the contract from the local API. -func (b *ContractBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { - return b.bcapi.GetCode(ctx, contract, rpc.PendingBlockNumber) -} - -// PendingAccountNonce implements bind.ContractTransactor retrieving the current -// pending nonce associated with an account. -func (b *ContractBackend) PendingNonceAt(ctx context.Context, account common.Address) (nonce uint64, err error) { - out, err := b.txapi.GetTransactionCount(ctx, account, rpc.PendingBlockNumber) - if out != nil { - nonce = uint64(*out) - } - return nonce, err -} - -// SuggestGasPrice implements bind.ContractTransactor retrieving the currently -// suggested gas price to allow a timely execution of a transaction. -func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { - price, err := b.eapi.GasPrice(ctx) - if err != nil { - return nil, err - } - return price.ToInt(), nil -} - -// EstimateGasLimit implements bind.ContractTransactor trying to estimate the gas -// needed to execute a specific transaction based on the current pending state of -// the backend blockchain. There is no guarantee that this is the true gas limit -// requirement as other transactions may be added or removed by miners, but it -// should provide a basis for setting a reasonable default. -func (b *ContractBackend) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) { - gas, err := b.bcapi.EstimateGas(ctx, toCallArgs(msg)) - return uint64(gas), err -} - -// SendTransaction implements bind.ContractTransactor injecting the transaction -// into the pending pool for execution. -func (b *ContractBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { - raw, _ := rlp.EncodeToBytes(tx) - _, err := b.txapi.SendRawTransaction(ctx, raw) - return err -} - -// FilterLogs implements bind.ContractFilterer returning logs matching the given argument -// that are stored within the state. -func (b *ContractBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { - // Initialize unset filter boundaried to run from genesis to chain head - from := int64(0) - if query.FromBlock != nil { - from = query.FromBlock.Int64() - } - to := int64(-1) - if query.ToBlock != nil { - to = query.ToBlock.Int64() - } - // Construct and execute the filter - filter := filters.New(b.filterBackend, from, to, query.Addresses, query.Topics) - - logs, err := filter.Logs(ctx) - if err != nil { - return nil, err - } - res := make([]types.Log, len(logs)) - for i, log := range logs { - res[i] = *log - } - return res, nil -} - -// SubscribeFilterLogs implements bind.ContractFilterer watching new fired logs matching the given argument. -func (b *ContractBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { - // Subscribe to contract events - sink := make(chan []*types.Log) - sub, err := b.events.SubscribeLogs(query, sink) - if err != nil { - return nil, err - } - // Since we're getting logs in batches, we need to flatten them into a plain stream - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case logs := <-sink: - for _, log := range logs { - select { - case ch <- *log: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs { - args := ethapi.CallArgs{ - To: msg.To, - From: msg.From, - Data: msg.Data, - Gas: hexutil.Uint64(msg.Gas), - } - if msg.GasPrice != nil { - args.GasPrice = hexutil.Big(*msg.GasPrice) - } - if msg.Value != nil { - args.Value = hexutil.Big(*msg.Value) - } - return args -} - -func toBlockNumber(num *big.Int) rpc.BlockNumber { - if num == nil { - return rpc.LatestBlockNumber - } - return rpc.BlockNumber(num.Int64()) -} diff --git a/les/server.go b/les/server.go index aeabbc0ff1..56bd04f61c 100644 --- a/les/server.go +++ b/les/server.go @@ -21,6 +21,8 @@ import ( "crypto/ecdsa" "errors" "sync" + "sync/atomic" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/registrar" @@ -29,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/les/flowcontrol" "github.com/ethereum/go-ethereum/light" @@ -53,9 +56,10 @@ type LesServer struct { privateKey *ecdsa.PrivateKey quitSync chan struct{} - // Checkpoint relative fields - registrar *registrar.Registrar // Handler for checkpoint contract - stableCheckpoint *light.TrustedCheckpoint // The nearest stable checkpoint + // Checkpoint contract relative fields + genesis common.Hash // Genesis block hash for contract address detection + registrar *registrar.Registrar // Handler for checkpoint contract, initialized after server is started. + watching int32 // Indicator whether the checkpoint contract is being watched // Indexers chtIndexer *core.ChainIndexer // Indexers for creating cht root for each block section @@ -83,6 +87,7 @@ func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) { lesTopics: lesTopics, chtIndexer: light.NewChtIndexer(e.ChainDb(), false), bloomTrieIndexer: light.NewBloomTrieIndexer(e.ChainDb(), false), + genesis: e.BlockChain().Genesis().Hash(), } logger := log.New() @@ -114,13 +119,6 @@ func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) { } srv.fcManager = flowcontrol.NewClientManager(uint64(config.LightServ), 10, 1000000000) srv.fcCostStats = newCostStats(e.ChainDb()) - if addr, ok := registrar.RegistrarAddr[e.BlockChain().Genesis().Hash()]; ok { - registrar, err := registrar.NewRegistrar(addr, eth.NewContractBackend(e.APIBackend, e.APIBackend, false)) - if err != nil { - return nil, err - } - srv.registrar = registrar - } return srv, nil } @@ -145,16 +143,28 @@ func (s *LesServer) Start(srvr *p2p.Server) { } s.privateKey = srvr.PrivateKey s.protocolManager.blockLoop() - if s.registrar != nil { - s.stableCheckpoint = s.recoverCheckpoint() - go s.checkpointLoop() - } } func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) { bloomIndexer.AddChildIndexer(s.bloomTrieIndexer) } +// SetClient sets the rpc client and starts watching checkpoint contract if it is not yet watched. +func (s *LesServer) SetClient(client *ethclient.Client) { + if addr, ok := registrar.RegistrarAddr[s.genesis]; ok { + if !atomic.CompareAndSwapInt32(&s.watching, 0, 1) { + return + } + registrar, err := registrar.NewRegistrar(addr, client) + if err != nil { + atomic.StoreInt32(&s.watching, 0) + return + } + s.registrar = registrar + go s.checkpointLoop(s.recoverCheckpoint()) + } +} + // Stop stops the LES service func (s *LesServer) Stop() { s.chtIndexer.Close() @@ -165,6 +175,7 @@ func (s *LesServer) Stop() { <-s.protocolManager.noMorePeers }() s.protocolManager.Stop() + atomic.StoreInt32(&s.watching, 0) } // APIs implements LesServer, returns all API service provided by les server. @@ -215,7 +226,7 @@ func (s *LesServer) getCheckpoint(index uint64) (common.Hash, common.Hash, commo } // checkpointLoop starts a standalone goroutine to watch new checkpoint events and updates local's stable checkpoint. -func (s *LesServer) checkpointLoop() (err error) { +func (s *LesServer) checkpointLoop(checkpoint *light.TrustedCheckpoint) (err error) { var ( eventCh = make(chan *contract.ContractNewCheckpointEvent) headCh = make(chan core.ChainHeadEvent, SubscribeChainHeadEvent) @@ -230,9 +241,12 @@ func (s *LesServer) checkpointLoop() (err error) { eventSub.Unsubscribe() return errors.New("subscribe head event failed") } + + ticker := time.NewTicker(5 * time.Minute) defer func() { eventSub.Unsubscribe() headSub.Unsubscribe() + ticker.Stop() }() for { @@ -243,8 +257,9 @@ func (s *LesServer) checkpointLoop() (err error) { log.Info("Ignore empty checkpoint event") continue } - // Note several duplicate events may be received because of chain reorg and the modification of the latest checkpoint. - if s.stableCheckpoint == nil || event.Index.Uint64() >= s.stableCheckpoint.SectionIdx { + // Note several events have same index may be received because of chain reorg and + // the modification of the latest checkpoint. + if checkpoint == nil || event.Index.Uint64() > checkpoint.SectionIdx { log.Info("Receive new checkpoint event", "section", event.Index, "hash", common.Hash(event.CheckpointHash).Hex(), "grantor", event.Grantor.Hex()) announcement[event.Index.Uint64()] = common.Hash(event.CheckpointHash) @@ -255,22 +270,29 @@ func (s *LesServer) checkpointLoop() (err error) { continue } idx := (number-light.CheckpointConfirmations)/light.CheckpointFrequency - 1 - if s.stableCheckpoint == nil || idx > s.stableCheckpoint.SectionIdx { + if checkpoint == nil || idx > checkpoint.SectionIdx { hash, ok := announcement[idx] if !ok { continue } sectionHead := s.bloomTrieIndexer.SectionHead(idx) - checkpoint := &light.TrustedCheckpoint{ + c := &light.TrustedCheckpoint{ SectionIdx: idx, SectionHead: sectionHead, ChtRoot: light.GetChtV2Root(s.chaindb, idx, sectionHead), BloomTrieRoot: light.GetBloomTrieRoot(s.chaindb, idx, sectionHead), } - if checkpoint.HashEqual(common.Hash(hash)) { - light.WriteTrustedCheckpoint(s.chaindb, checkpoint) - s.stableCheckpoint = checkpoint - log.Info("Update stable checkpoint", "section", checkpoint.SectionIdx) + if c.HashEqual(common.Hash(hash)) { + light.WriteTrustedCheckpoint(s.chaindb, c) + checkpoint = c + delete(announcement, idx) + log.Info("Update stable checkpoint", "section", checkpoint.SectionIdx, "hash", checkpoint.Hash().Hex()) + } + } + case <-ticker.C: + // Evict useless announcement every 5 minutes. + for idx := range announcement { + if checkpoint != nil && checkpoint.SectionIdx >= idx { delete(announcement, idx) } } @@ -286,13 +308,13 @@ func (s *LesServer) recoverCheckpoint() *light.TrustedCheckpoint { var ( sectionCnt, _, _ = s.bloomTrieIndexer.Sections() stable = light.ReadTrustedCheckpoint(s.chaindb) - unstableIdx = sectionCnt - 1 headHash = rawdb.ReadHeadHeaderHash(s.chaindb) headNumber = rawdb.ReadHeaderNumber(s.chaindb, headHash) ) - if headNumber == nil { + if headNumber == nil || sectionCnt == 0 { return nil } + unstableIdx := sectionCnt - 1 for stable == nil || stable.SectionIdx < unstableIdx { if (unstableIdx+1)*light.CheckpointFrequency+light.CheckpointConfirmations <= *headNumber { iter, err := s.registrar.FilterNewCheckpointEvent(*headNumber, unstableIdx, light.CheckpointFrequency, light.CheckpointProcessConfirmations) @@ -308,7 +330,7 @@ func (s *LesServer) recoverCheckpoint() *light.TrustedCheckpoint { if checkpoint.HashEqual(common.Hash(iter.Event.CheckpointHash)) { light.WriteTrustedCheckpoint(s.chaindb, checkpoint) iter.Close() - log.Info("Recover checkpoint", "index", checkpoint.SectionIdx) + log.Info("Recover checkpoint", "index", checkpoint.SectionIdx, "hash", checkpoint.Hash().Hex()) return checkpoint } } @@ -323,7 +345,7 @@ func (s *LesServer) recoverCheckpoint() *light.TrustedCheckpoint { if stable == nil { log.Info("No stable checkpoint") } else { - log.Info("Recover checkpoint", "index", stable.SectionIdx) + log.Info("Recover checkpoint", "index", stable.SectionIdx, "hash", stable.Hash().Hex()) } return stable } diff --git a/light/checkpoint.go b/light/checkpoint.go index 118cb646b8..8933c84ac4 100644 --- a/light/checkpoint.go +++ b/light/checkpoint.go @@ -84,7 +84,12 @@ func (c *TrustedCheckpoint) HashEqual(hash common.Hash) bool { if c.SectionHead == (common.Hash{}) && c.ChtRoot == (common.Hash{}) && c.BloomTrieRoot == (common.Hash{}) { return hash == common.Hash{} } - return crypto.Keccak256Hash(c.SectionHead.Bytes(), c.ChtRoot.Bytes(), c.BloomTrieRoot.Bytes()) == hash + return c.Hash() == hash +} + +// Hash returns the hash of checkpoint three key fields(sectionHead, chtRoot and bloomTrieRoot). +func (c *TrustedCheckpoint) Hash() common.Hash { + return crypto.Keccak256Hash(c.SectionHead.Bytes(), c.ChtRoot.Bytes(), c.BloomTrieRoot.Bytes()) } var ( diff --git a/node/node.go b/node/node.go index ada3837217..58f9141d2a 100644 --- a/node/node.go +++ b/node/node.go @@ -48,8 +48,9 @@ type Node struct { serverConfig p2p.Config server *p2p.Server // Currently running P2P networking layer - serviceFuncs []ServiceConstructor // Service constructors (in dependency order) - services map[reflect.Type]Service // Currently running services + serviceFuncs []ServiceConstructor // Service constructors (in dependency order) + callbacks map[reflect.Type][]ServiceCallback // Service callback functions + services map[reflect.Type]Service // Currently running services rpcAPIs []rpc.API // List of APIs currently provided by the node inprocHandler *rpc.Server // In-process RPC request handler to process the API requests @@ -113,6 +114,7 @@ func New(conf *Config) (*Node, error) { ephemeralKeystore: ephemeralKeystore, config: conf, serviceFuncs: []ServiceConstructor{}, + callbacks: make(map[reflect.Type][]ServiceCallback), ipcEndpoint: conf.IPCEndpoint(), httpEndpoint: conf.HTTPEndpoint(), wsEndpoint: conf.WSEndpoint(), @@ -134,6 +136,18 @@ func (n *Node) Register(constructor ServiceConstructor) error { return nil } +// RegisterCallback injects a callback function associated with the specified service. +func (n *Node) RegisterCallback(typ reflect.Type, callback ServiceCallback) error { + n.lock.Lock() + defer n.lock.Unlock() + + if n.server != nil { + return ErrNodeRunning + } + n.callbacks[typ] = append(n.callbacks[typ], callback) + return nil +} + // Start create a live P2P node and starts running it. func (n *Node) Start() error { n.lock.Lock() @@ -211,7 +225,7 @@ func (n *Node) Start() error { // Mark the service started for potential cleanup started = append(started, kind) } - // Lastly start the configured RPC interfaces + // Start the configured RPC interfaces if err := n.startRPC(services); err != nil { for _, service := range services { service.Stop() @@ -223,7 +237,21 @@ func (n *Node) Start() error { n.services = services n.server = running n.stop = make(chan struct{}) - + // Lastly invokes all registered services callbacks after server is started. + for typ, callbacks := range n.callbacks { + if service, ok := services[typ]; ok { + for _, callback := range callbacks { + if err := callback(service); err != nil { + for _, service := range services { + service.Stop() + } + running.Stop() + n.services, n.server, n.stop = nil, nil, nil + return err + } + } + } + } return nil } @@ -480,7 +508,12 @@ func (n *Node) Restart() error { func (n *Node) Attach() (*rpc.Client, error) { n.lock.RLock() defer n.lock.RUnlock() + return n.AttachLocked() +} +// AttachLocked creates an RPC client attached to an in-process API handler. +// Note, this function assumes the lock of node is held. +func (n *Node) AttachLocked() (*rpc.Client, error) { if n.server == nil { return nil, ErrNodeStopped } diff --git a/node/service.go b/node/service.go index 6a96d9b1e1..ae65e10d4f 100644 --- a/node/service.go +++ b/node/service.go @@ -71,6 +71,10 @@ func (ctx *ServiceContext) Service(service interface{}) error { // registered for service instantiation. type ServiceConstructor func(ctx *ServiceContext) (Service, error) +// ServiceCallback is the function signature of the callbacks needed to be invoked +// after associated service is started. +type ServiceCallback func(service Service) error + // Service is an individual protocol that can be registered into a node. // // Notes: From f923674365bf7446116f4f46d8a3e9fc038cee04 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 11 Jul 2018 16:31:19 +0800 Subject: [PATCH 13/15] cmd, les: polish a bit and add some annotation --- cmd/utils/flags.go | 2 ++ les/server.go | 26 +++++++++++++++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index afa1d4d403..db1d0ba420 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1181,6 +1181,8 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) { if err == nil { err = stack.RegisterCallback(reflect.TypeOf(ð.Ethereum{}), func(service node.Service) error { if e, ok := service.(*eth.Ethereum); ok { + // The node lock will be held during the whole node setup procedure, so no extra + // lock operation is needed. rpcClient, err := stack.AttachLocked() if err != nil { return err diff --git a/les/server.go b/les/server.go index 56bd04f61c..617212166c 100644 --- a/les/server.go +++ b/les/server.go @@ -151,18 +151,22 @@ func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) { // SetClient sets the rpc client and starts watching checkpoint contract if it is not yet watched. func (s *LesServer) SetClient(client *ethclient.Client) { - if addr, ok := registrar.RegistrarAddr[s.genesis]; ok { - if !atomic.CompareAndSwapInt32(&s.watching, 0, 1) { - return - } - registrar, err := registrar.NewRegistrar(addr, client) - if err != nil { - atomic.StoreInt32(&s.watching, 0) - return - } - s.registrar = registrar - go s.checkpointLoop(s.recoverCheckpoint()) + addr, ok := registrar.RegistrarAddr[s.genesis] + if !ok { + log.Info("The registrar contract is not deployed") + return } + registrar, err := registrar.NewRegistrar(addr, client) + if err != nil { + log.Info("Bind registrar contract failed", "err", err) + return + } + if !atomic.CompareAndSwapInt32(&s.watching, 0, 1) { + log.Info("Already bound and listening to registrar contract") + return + } + s.registrar = registrar + go s.checkpointLoop(s.recoverCheckpoint()) } // Stop stops the LES service From ca0ac58f18dc6415e07fb13437aa8db64eeb26f3 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 11 Jul 2018 16:48:08 +0800 Subject: [PATCH 14/15] les: expose les API as private API service --- les/api.go | 25 ++++++++++++------------- les/server.go | 47 ++++++++++++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/les/api.go b/les/api.go index b58cf0fc82..27d3e3975f 100644 --- a/les/api.go +++ b/les/api.go @@ -25,51 +25,50 @@ import ( ) var ( - errNoStableCheckpoint = errors.New("no stable checkpoint provided") + errNoCheckpoint = errors.New("no local checkpoint provided") ) -// PublicLesServerAPI provides an API to access the les server. -// It offers only methods that operate on public data that is freely available to anyone. -type PublicLesServerAPI struct { +// PrivateLesServerAPI provides a private API to access the les server. +type PrivateLesServerAPI struct { server *LesServer } -// NewPublicLesServerAPI creates a new les server API. -func NewPublicLesServerAPI(server *LesServer) *PublicLesServerAPI { - return &PublicLesServerAPI{ +// NewPrivateLesServerAPI creates a new les server API. +func NewPrivateLesServerAPI(server *LesServer) *PrivateLesServerAPI { + return &PrivateLesServerAPI{ server: server, } } -// Checkpoint returns the latest checkpoint package. +// Checkpoint returns the latest local checkpoint package. // // The checkpoint package consists of 4 strings: // result[0], hex encoded latest section index // result[1], 32 bytes hex encoded latest section head hash // result[2], 32 bytes hex encoded latest section canonical hash trie root hash // result[3], 32 bytes hex encoded latest section bloom trie root hash -func (api *PublicLesServerAPI) LatestCheckpoint() ([4]string, error) { +func (api *PrivateLesServerAPI) LatestCheckpoint() ([4]string, error) { var res [4]string sectionIdx, sectionHead, chtRoot, bloomTrieRoot := api.server.latestCheckpoint() if sectionHead == (common.Hash{}) || chtRoot == (common.Hash{}) || bloomTrieRoot == (common.Hash{}) { - return res, errNoStableCheckpoint + return res, errNoCheckpoint } res[0] = hexutil.Encode(big.NewInt(int64(sectionIdx)).Bytes()) res[1], res[2], res[3] = sectionHead.Hex(), chtRoot.Hex(), bloomTrieRoot.Hex() return res, nil } -// GetCheckpoint returns the specific checkpoint package. +// GetCheckpoint returns the specific local checkpoint package. // // The checkpoint package consists of 3 strings: // result[0], 32 bytes hex encoded latest section head hash // result[1], 32 bytes hex encoded latest section canonical hash trie root hash // result[2], 32 bytes hex encoded latest section bloom trie root hash -func (api *PublicLesServerAPI) GetCheckpoint(index uint64) ([3]string, error) { +func (api *PrivateLesServerAPI) GetCheckpoint(index uint64) ([3]string, error) { var res [3]string sectionHead, chtRoot, bloomTrieRoot := api.server.getCheckpoint(index) if sectionHead == (common.Hash{}) || chtRoot == (common.Hash{}) || bloomTrieRoot == (common.Hash{}) { - return res, errNoStableCheckpoint + return res, errNoCheckpoint } res[0], res[1], res[2] = sectionHead.Hex(), chtRoot.Hex(), bloomTrieRoot.Hex() return res, nil diff --git a/les/server.go b/les/server.go index 617212166c..3f30b85aa8 100644 --- a/les/server.go +++ b/les/server.go @@ -188,15 +188,15 @@ func (s *LesServer) APIs() []rpc.API { { Namespace: "les", Version: "1.0", - Service: NewPublicLesServerAPI(s), - Public: true, + Service: NewPrivateLesServerAPI(s), + Public: false, }, } } // latestCheckpoint finds the common stored section index and returns a set of // post-processed trie roots (CHT and BloomTrie) associated with -// the appropriate section index and head hash as a checkpoint package. +// the appropriate section index and head hash as a local checkpoint package. // // Note for cht, the section size in LES1 is 4K, so indexer still uses LES/1 // 4k section size for backwards server compatibility. For bloomTrie, the size @@ -219,6 +219,9 @@ func (s *LesServer) latestCheckpoint() (uint64, common.Hash, common.Hash, common // getCheckpoint returns a set of post-processed trie roots (CHT and BloomTrie) // associated with the appropriate head hash by specific section index. +// +// The returned checkpoint is only the checkpoint generated by the local indexers, +// not the stable checkpoint registered in the registrar contract. func (s *LesServer) getCheckpoint(index uint64) (common.Hash, common.Hash, common.Hash) { // convert last LES/2 section index back to LES/1 index for chtIndexer.SectionHead latest := (index+1)*(light.CHTFrequencyClient/light.CHTFrequencyServer) - 1 @@ -315,6 +318,7 @@ func (s *LesServer) recoverCheckpoint() *light.TrustedCheckpoint { headHash = rawdb.ReadHeadHeaderHash(s.chaindb) headNumber = rawdb.ReadHeaderNumber(s.chaindb, headHash) ) + // Short circuit if there is no local checkpoint generated. if headNumber == nil || sectionCnt == 0 { return nil } @@ -322,24 +326,25 @@ func (s *LesServer) recoverCheckpoint() *light.TrustedCheckpoint { for stable == nil || stable.SectionIdx < unstableIdx { if (unstableIdx+1)*light.CheckpointFrequency+light.CheckpointConfirmations <= *headNumber { iter, err := s.registrar.FilterNewCheckpointEvent(*headNumber, unstableIdx, light.CheckpointFrequency, light.CheckpointProcessConfirmations) - if err == nil { - for iter.Next() { - sectionHead := s.bloomTrieIndexer.SectionHead(unstableIdx) - checkpoint := &light.TrustedCheckpoint{ - SectionIdx: unstableIdx, - SectionHead: sectionHead, - ChtRoot: light.GetChtV2Root(s.chaindb, unstableIdx, sectionHead), - BloomTrieRoot: light.GetBloomTrieRoot(s.chaindb, unstableIdx, sectionHead), - } - if checkpoint.HashEqual(common.Hash(iter.Event.CheckpointHash)) { - light.WriteTrustedCheckpoint(s.chaindb, checkpoint) - iter.Close() - log.Info("Recover checkpoint", "index", checkpoint.SectionIdx, "hash", checkpoint.Hash().Hex()) - return checkpoint - } - } - iter.Close() + if err != nil { + continue } + for iter.Next() { + sectionHead := s.bloomTrieIndexer.SectionHead(unstableIdx) + checkpoint := &light.TrustedCheckpoint{ + SectionIdx: unstableIdx, + SectionHead: sectionHead, + ChtRoot: light.GetChtV2Root(s.chaindb, unstableIdx, sectionHead), + BloomTrieRoot: light.GetBloomTrieRoot(s.chaindb, unstableIdx, sectionHead), + } + if checkpoint.HashEqual(common.Hash(iter.Event.CheckpointHash)) { + light.WriteTrustedCheckpoint(s.chaindb, checkpoint) + iter.Close() + log.Info("Recover stable checkpoint", "index", checkpoint.SectionIdx, "hash", checkpoint.Hash().Hex()) + return checkpoint + } + } + iter.Close() } if unstableIdx == 0 { break @@ -349,7 +354,7 @@ func (s *LesServer) recoverCheckpoint() *light.TrustedCheckpoint { if stable == nil { log.Info("No stable checkpoint") } else { - log.Info("Recover checkpoint", "index", stable.SectionIdx, "hash", stable.Hash().Hex()) + log.Info("Recover stable checkpoint", "index", stable.SectionIdx, "hash", stable.Hash().Hex()) } return stable } From 90366b3bb73414e51254f94686d3c745497b0d6c Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 30 Jul 2018 13:18:15 +0800 Subject: [PATCH 15/15] les: recover stable checkpoint if nil --- les/server.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/les/server.go b/les/server.go index 3f30b85aa8..39929c6685 100644 --- a/les/server.go +++ b/les/server.go @@ -276,6 +276,9 @@ func (s *LesServer) checkpointLoop(checkpoint *light.TrustedCheckpoint) (err err if number < light.CheckpointConfirmations+light.CheckpointFrequency { continue } + if checkpoint == nil { + checkpoint = s.recoverCheckpoint() + } idx := (number-light.CheckpointConfirmations)/light.CheckpointFrequency - 1 if checkpoint == nil || idx > checkpoint.SectionIdx { hash, ok := announcement[idx]