Feature/mailserver registry smart contract (#1135)
* add verifier and test using simulated backend * add ContractCaller * commit simulated backend after deploy and after smart contract writes * use bind.NewKeyedTransactor for all transactions in tests * rename RegistryVerifier to Verifier * initialize contract verifier if MailServerRegistryAddress config is set * use contractAddress.Hash() * refactoring * use fmt.Sprintf to format contract address in logs * fix test and lint warnings * update Gopkg.lock * update Gopkg.lock once more
This commit is contained in:
parent
cf21f981f7
commit
874a3e8151
|
@ -1025,6 +1025,8 @@
|
||||||
"github.com/btcsuite/btcutil/base58",
|
"github.com/btcsuite/btcutil/base58",
|
||||||
"github.com/ethereum/go-ethereum",
|
"github.com/ethereum/go-ethereum",
|
||||||
"github.com/ethereum/go-ethereum/accounts",
|
"github.com/ethereum/go-ethereum/accounts",
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi",
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind",
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends",
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends",
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore",
|
"github.com/ethereum/go-ethereum/accounts/keystore",
|
||||||
"github.com/ethereum/go-ethereum/common",
|
"github.com/ethereum/go-ethereum/common",
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package contracts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RPCClient interface {
|
||||||
|
CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContractCaller struct {
|
||||||
|
c RPCClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContractCaller(c RPCClient) *ContractCaller {
|
||||||
|
return &ContractCaller{
|
||||||
|
c: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeAt returns the contract code of the given account.
|
||||||
|
// The block number can be nil, in which case the code is taken from the latest known block.
|
||||||
|
func (cc *ContractCaller) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) {
|
||||||
|
var result hexutil.Bytes
|
||||||
|
err := cc.c.CallContext(ctx, &result, "eth_getCode", account, "latest")
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallContract executes a message call transaction, which is directly executed in the VM
|
||||||
|
// of the node, but never mined into the blockchain.
|
||||||
|
//
|
||||||
|
// blockNumber selects the block height at which the call runs. It can be nil, in which
|
||||||
|
// case the code is taken from the latest known block. Note that state from very old
|
||||||
|
// blocks might not be available.
|
||||||
|
func (cc *ContractCaller) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
|
||||||
|
var hex hexutil.Bytes
|
||||||
|
err := cc.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), "latest")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return hex, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toCallArg(msg ethereum.CallMsg) interface{} {
|
||||||
|
arg := map[string]interface{}{
|
||||||
|
"from": msg.From,
|
||||||
|
"to": msg.To,
|
||||||
|
}
|
||||||
|
if len(msg.Data) > 0 {
|
||||||
|
arg["data"] = hexutil.Bytes(msg.Data)
|
||||||
|
}
|
||||||
|
if msg.Value != nil {
|
||||||
|
arg["value"] = (*hexutil.Big)(msg.Value)
|
||||||
|
}
|
||||||
|
if msg.Gas != 0 {
|
||||||
|
arg["gas"] = hexutil.Uint64(msg.Gas)
|
||||||
|
}
|
||||||
|
if msg.GasPrice != nil {
|
||||||
|
arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
|
||||||
|
}
|
||||||
|
return arg
|
||||||
|
}
|
|
@ -0,0 +1,535 @@
|
||||||
|
// Code generated - DO NOT EDIT.
|
||||||
|
// This file is a generated binding and any manual changes will be lost.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegistryABI is the input ABI used to generate the binding from.
|
||||||
|
const RegistryABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_newController\",\"type\":\"address\"}],\"name\":\"changeController\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a\",\"type\":\"bytes\"}],\"name\":\"remove\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"a\",\"type\":\"bytes\"}],\"name\":\"exists\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a\",\"type\":\"bytes\"}],\"name\":\"add\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"controller\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"a\",\"type\":\"bytes\"}],\"name\":\"MailServerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"a\",\"type\":\"bytes\"}],\"name\":\"MailServerRemoved\",\"type\":\"event\"}]"
|
||||||
|
|
||||||
|
// RegistryBin is the compiled bytecode used for deploying new contracts.
|
||||||
|
const RegistryBin = `6080604052336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610511806100536000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633cebb8231461007257806358edef4c146100b557806379fc09a2146100f0578063ba65811114610143578063f77c47911461017e575b600080fd5b34801561007e57600080fd5b506100b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506101d5565b005b3480156100c157600080fd5b506100ee600480360381019080803590602001908201803590602001919091929391929390505050610273565b005b3480156100fc57600080fd5b50610129600480360381019080803590602001908201803590602001919091929391929390505050610396565b604051808215151515815260200191505060405180910390f35b34801561014f57600080fd5b5061017c6004803603810190808035906020019082018035906020019190919293919293905050506103d3565b005b34801561018a57600080fd5b506101936104c0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561023057600080fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156102ce57600080fd5b6001828260405180838380828437820191505092505050908152602001604051809103902060009054906101000a900460ff16151561030c57600080fd5b6001828260405180838380828437820191505092505050908152602001604051809103902060006101000a81549060ff02191690557f44e7d85a87eeb950b8bdc144d44b0b474be610d1953607251a0130edc10a222b8282604051808060200182810382528484828181526020019250808284378201915050935050505060405180910390a15050565b60006001838360405180838380828437820191505092505050908152602001604051809103902060009054906101000a900460ff16905092915050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561042e57600080fd5b600180838360405180838380828437820191505092505050908152602001604051809103902060006101000a81548160ff0219169083151502179055507fcb379cb5890ec9889055734e1561cdc353a342d46d8d650c8c3a8d66383c29cd8282604051808060200182810382528484828181526020019250808284378201915050935050505060405180910390a15050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a723058205234376a4ed154ce31a74225ac2258d6a4a82fd5fef967aaaf17c005c40b6f370029`
|
||||||
|
|
||||||
|
// DeployRegistry deploys a new Ethereum contract, binding an instance of Registry to it.
|
||||||
|
func DeployRegistry(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Registry, error) {
|
||||||
|
parsed, err := abi.JSON(strings.NewReader(RegistryABI))
|
||||||
|
if err != nil {
|
||||||
|
return common.Address{}, nil, nil, err
|
||||||
|
}
|
||||||
|
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(RegistryBin), backend)
|
||||||
|
if err != nil {
|
||||||
|
return common.Address{}, nil, nil, err
|
||||||
|
}
|
||||||
|
return address, tx, &Registry{RegistryCaller: RegistryCaller{contract: contract}, RegistryTransactor: RegistryTransactor{contract: contract}, RegistryFilterer: RegistryFilterer{contract: contract}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registry is an auto generated Go binding around an Ethereum contract.
|
||||||
|
type Registry struct {
|
||||||
|
RegistryCaller // Read-only binding to the contract
|
||||||
|
RegistryTransactor // Write-only binding to the contract
|
||||||
|
RegistryFilterer // Log filterer for contract events
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryCaller is an auto generated read-only Go binding around an Ethereum contract.
|
||||||
|
type RegistryCaller struct {
|
||||||
|
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryTransactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||||
|
type RegistryTransactor struct {
|
||||||
|
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||||
|
type RegistryFilterer struct {
|
||||||
|
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistrySession is an auto generated Go binding around an Ethereum contract,
|
||||||
|
// with pre-set call and transact options.
|
||||||
|
type RegistrySession struct {
|
||||||
|
Contract *Registry // 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||||
|
// with pre-set call options.
|
||||||
|
type RegistryCallerSession struct {
|
||||||
|
Contract *RegistryCaller // Generic contract caller binding to set the session for
|
||||||
|
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||||
|
// with pre-set transact options.
|
||||||
|
type RegistryTransactorSession struct {
|
||||||
|
Contract *RegistryTransactor // Generic contract transactor binding to set the session for
|
||||||
|
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryRaw is an auto generated low-level Go binding around an Ethereum contract.
|
||||||
|
type RegistryRaw struct {
|
||||||
|
Contract *Registry // Generic contract binding to access the raw methods on
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||||
|
type RegistryCallerRaw struct {
|
||||||
|
Contract *RegistryCaller // Generic read-only contract binding to access the raw methods on
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||||
|
type RegistryTransactorRaw struct {
|
||||||
|
Contract *RegistryTransactor // Generic write-only contract binding to access the raw methods on
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRegistry creates a new instance of Registry, bound to a specific deployed contract.
|
||||||
|
func NewRegistry(address common.Address, backend bind.ContractBackend) (*Registry, error) {
|
||||||
|
contract, err := bindRegistry(address, backend, backend, backend)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Registry{RegistryCaller: RegistryCaller{contract: contract}, RegistryTransactor: RegistryTransactor{contract: contract}, RegistryFilterer: RegistryFilterer{contract: contract}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRegistryCaller creates a new read-only instance of Registry, bound to a specific deployed contract.
|
||||||
|
func NewRegistryCaller(address common.Address, caller bind.ContractCaller) (*RegistryCaller, error) {
|
||||||
|
contract, err := bindRegistry(address, caller, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &RegistryCaller{contract: contract}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRegistryTransactor creates a new write-only instance of Registry, bound to a specific deployed contract.
|
||||||
|
func NewRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*RegistryTransactor, error) {
|
||||||
|
contract, err := bindRegistry(address, nil, transactor, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &RegistryTransactor{contract: contract}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRegistryFilterer creates a new log filterer instance of Registry, bound to a specific deployed contract.
|
||||||
|
func NewRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*RegistryFilterer, error) {
|
||||||
|
contract, err := bindRegistry(address, nil, nil, filterer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &RegistryFilterer{contract: contract}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindRegistry binds a generic wrapper to an already deployed contract.
|
||||||
|
func bindRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||||
|
parsed, err := abi.JSON(strings.NewReader(RegistryABI))
|
||||||
|
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 (_Registry *RegistryRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
|
||||||
|
return _Registry.Contract.RegistryCaller.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 (_Registry *RegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||||
|
return _Registry.Contract.RegistryTransactor.contract.Transfer(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transact invokes the (paid) contract method with params as input values.
|
||||||
|
func (_Registry *RegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||||
|
return _Registry.Contract.RegistryTransactor.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 (_Registry *RegistryCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
|
||||||
|
return _Registry.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 (_Registry *RegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||||
|
return _Registry.Contract.contract.Transfer(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transact invokes the (paid) contract method with params as input values.
|
||||||
|
func (_Registry *RegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||||
|
return _Registry.Contract.contract.Transact(opts, method, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controller is a free data retrieval call binding the contract method 0xf77c4791.
|
||||||
|
//
|
||||||
|
// Solidity: function controller() constant returns(address)
|
||||||
|
func (_Registry *RegistryCaller) Controller(opts *bind.CallOpts) (common.Address, error) {
|
||||||
|
var (
|
||||||
|
ret0 = new(common.Address)
|
||||||
|
)
|
||||||
|
out := ret0
|
||||||
|
err := _Registry.contract.Call(opts, out, "controller")
|
||||||
|
return *ret0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controller is a free data retrieval call binding the contract method 0xf77c4791.
|
||||||
|
//
|
||||||
|
// Solidity: function controller() constant returns(address)
|
||||||
|
func (_Registry *RegistrySession) Controller() (common.Address, error) {
|
||||||
|
return _Registry.Contract.Controller(&_Registry.CallOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controller is a free data retrieval call binding the contract method 0xf77c4791.
|
||||||
|
//
|
||||||
|
// Solidity: function controller() constant returns(address)
|
||||||
|
func (_Registry *RegistryCallerSession) Controller() (common.Address, error) {
|
||||||
|
return _Registry.Contract.Controller(&_Registry.CallOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exists is a free data retrieval call binding the contract method 0x79fc09a2.
|
||||||
|
//
|
||||||
|
// Solidity: function exists(a bytes) constant returns(bool)
|
||||||
|
func (_Registry *RegistryCaller) Exists(opts *bind.CallOpts, a []byte) (bool, error) {
|
||||||
|
var (
|
||||||
|
ret0 = new(bool)
|
||||||
|
)
|
||||||
|
out := ret0
|
||||||
|
err := _Registry.contract.Call(opts, out, "exists", a)
|
||||||
|
return *ret0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exists is a free data retrieval call binding the contract method 0x79fc09a2.
|
||||||
|
//
|
||||||
|
// Solidity: function exists(a bytes) constant returns(bool)
|
||||||
|
func (_Registry *RegistrySession) Exists(a []byte) (bool, error) {
|
||||||
|
return _Registry.Contract.Exists(&_Registry.CallOpts, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exists is a free data retrieval call binding the contract method 0x79fc09a2.
|
||||||
|
//
|
||||||
|
// Solidity: function exists(a bytes) constant returns(bool)
|
||||||
|
func (_Registry *RegistryCallerSession) Exists(a []byte) (bool, error) {
|
||||||
|
return _Registry.Contract.Exists(&_Registry.CallOpts, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add is a paid mutator transaction binding the contract method 0xba658111.
|
||||||
|
//
|
||||||
|
// Solidity: function add(a bytes) returns()
|
||||||
|
func (_Registry *RegistryTransactor) Add(opts *bind.TransactOpts, a []byte) (*types.Transaction, error) {
|
||||||
|
return _Registry.contract.Transact(opts, "add", a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add is a paid mutator transaction binding the contract method 0xba658111.
|
||||||
|
//
|
||||||
|
// Solidity: function add(a bytes) returns()
|
||||||
|
func (_Registry *RegistrySession) Add(a []byte) (*types.Transaction, error) {
|
||||||
|
return _Registry.Contract.Add(&_Registry.TransactOpts, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add is a paid mutator transaction binding the contract method 0xba658111.
|
||||||
|
//
|
||||||
|
// Solidity: function add(a bytes) returns()
|
||||||
|
func (_Registry *RegistryTransactorSession) Add(a []byte) (*types.Transaction, error) {
|
||||||
|
return _Registry.Contract.Add(&_Registry.TransactOpts, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeController is a paid mutator transaction binding the contract method 0x3cebb823.
|
||||||
|
//
|
||||||
|
// Solidity: function changeController(_newController address) returns()
|
||||||
|
func (_Registry *RegistryTransactor) ChangeController(opts *bind.TransactOpts, _newController common.Address) (*types.Transaction, error) {
|
||||||
|
return _Registry.contract.Transact(opts, "changeController", _newController)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeController is a paid mutator transaction binding the contract method 0x3cebb823.
|
||||||
|
//
|
||||||
|
// Solidity: function changeController(_newController address) returns()
|
||||||
|
func (_Registry *RegistrySession) ChangeController(_newController common.Address) (*types.Transaction, error) {
|
||||||
|
return _Registry.Contract.ChangeController(&_Registry.TransactOpts, _newController)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeController is a paid mutator transaction binding the contract method 0x3cebb823.
|
||||||
|
//
|
||||||
|
// Solidity: function changeController(_newController address) returns()
|
||||||
|
func (_Registry *RegistryTransactorSession) ChangeController(_newController common.Address) (*types.Transaction, error) {
|
||||||
|
return _Registry.Contract.ChangeController(&_Registry.TransactOpts, _newController)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove is a paid mutator transaction binding the contract method 0x58edef4c.
|
||||||
|
//
|
||||||
|
// Solidity: function remove(a bytes) returns()
|
||||||
|
func (_Registry *RegistryTransactor) Remove(opts *bind.TransactOpts, a []byte) (*types.Transaction, error) {
|
||||||
|
return _Registry.contract.Transact(opts, "remove", a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove is a paid mutator transaction binding the contract method 0x58edef4c.
|
||||||
|
//
|
||||||
|
// Solidity: function remove(a bytes) returns()
|
||||||
|
func (_Registry *RegistrySession) Remove(a []byte) (*types.Transaction, error) {
|
||||||
|
return _Registry.Contract.Remove(&_Registry.TransactOpts, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove is a paid mutator transaction binding the contract method 0x58edef4c.
|
||||||
|
//
|
||||||
|
// Solidity: function remove(a bytes) returns()
|
||||||
|
func (_Registry *RegistryTransactorSession) Remove(a []byte) (*types.Transaction, error) {
|
||||||
|
return _Registry.Contract.Remove(&_Registry.TransactOpts, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryMailServerAddedIterator is returned from FilterMailServerAdded and is used to iterate over the raw logs and unpacked data for MailServerAdded events raised by the Registry contract.
|
||||||
|
type RegistryMailServerAddedIterator struct {
|
||||||
|
Event *RegistryMailServerAdded // 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 *RegistryMailServerAddedIterator) 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(RegistryMailServerAdded)
|
||||||
|
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(RegistryMailServerAdded)
|
||||||
|
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 *RegistryMailServerAddedIterator) Error() error {
|
||||||
|
return it.fail
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close terminates the iteration process, releasing any pending underlying
|
||||||
|
// resources.
|
||||||
|
func (it *RegistryMailServerAddedIterator) Close() error {
|
||||||
|
it.sub.Unsubscribe()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryMailServerAdded represents a MailServerAdded event raised by the Registry contract.
|
||||||
|
type RegistryMailServerAdded struct {
|
||||||
|
A []byte
|
||||||
|
Raw types.Log // Blockchain specific contextual infos
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterMailServerAdded is a free log retrieval operation binding the contract event 0xcb379cb5890ec9889055734e1561cdc353a342d46d8d650c8c3a8d66383c29cd.
|
||||||
|
//
|
||||||
|
// Solidity: e MailServerAdded(a bytes)
|
||||||
|
func (_Registry *RegistryFilterer) FilterMailServerAdded(opts *bind.FilterOpts) (*RegistryMailServerAddedIterator, error) {
|
||||||
|
|
||||||
|
logs, sub, err := _Registry.contract.FilterLogs(opts, "MailServerAdded")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &RegistryMailServerAddedIterator{contract: _Registry.contract, event: "MailServerAdded", logs: logs, sub: sub}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatchMailServerAdded is a free log subscription operation binding the contract event 0xcb379cb5890ec9889055734e1561cdc353a342d46d8d650c8c3a8d66383c29cd.
|
||||||
|
//
|
||||||
|
// Solidity: e MailServerAdded(a bytes)
|
||||||
|
func (_Registry *RegistryFilterer) WatchMailServerAdded(opts *bind.WatchOpts, sink chan<- *RegistryMailServerAdded) (event.Subscription, error) {
|
||||||
|
|
||||||
|
logs, sub, err := _Registry.contract.WatchLogs(opts, "MailServerAdded")
|
||||||
|
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(RegistryMailServerAdded)
|
||||||
|
if err := _Registry.contract.UnpackLog(event, "MailServerAdded", 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryMailServerRemovedIterator is returned from FilterMailServerRemoved and is used to iterate over the raw logs and unpacked data for MailServerRemoved events raised by the Registry contract.
|
||||||
|
type RegistryMailServerRemovedIterator struct {
|
||||||
|
Event *RegistryMailServerRemoved // 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 *RegistryMailServerRemovedIterator) 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(RegistryMailServerRemoved)
|
||||||
|
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(RegistryMailServerRemoved)
|
||||||
|
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 *RegistryMailServerRemovedIterator) Error() error {
|
||||||
|
return it.fail
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close terminates the iteration process, releasing any pending underlying
|
||||||
|
// resources.
|
||||||
|
func (it *RegistryMailServerRemovedIterator) Close() error {
|
||||||
|
it.sub.Unsubscribe()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryMailServerRemoved represents a MailServerRemoved event raised by the Registry contract.
|
||||||
|
type RegistryMailServerRemoved struct {
|
||||||
|
A []byte
|
||||||
|
Raw types.Log // Blockchain specific contextual infos
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterMailServerRemoved is a free log retrieval operation binding the contract event 0x44e7d85a87eeb950b8bdc144d44b0b474be610d1953607251a0130edc10a222b.
|
||||||
|
//
|
||||||
|
// Solidity: e MailServerRemoved(a bytes)
|
||||||
|
func (_Registry *RegistryFilterer) FilterMailServerRemoved(opts *bind.FilterOpts) (*RegistryMailServerRemovedIterator, error) {
|
||||||
|
|
||||||
|
logs, sub, err := _Registry.contract.FilterLogs(opts, "MailServerRemoved")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &RegistryMailServerRemovedIterator{contract: _Registry.contract, event: "MailServerRemoved", logs: logs, sub: sub}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatchMailServerRemoved is a free log subscription operation binding the contract event 0x44e7d85a87eeb950b8bdc144d44b0b474be610d1953607251a0130edc10a222b.
|
||||||
|
//
|
||||||
|
// Solidity: e MailServerRemoved(a bytes)
|
||||||
|
func (_Registry *RegistryFilterer) WatchMailServerRemoved(opts *bind.WatchOpts, sink chan<- *RegistryMailServerRemoved) (event.Subscription, error) {
|
||||||
|
|
||||||
|
logs, sub, err := _Registry.contract.WatchLogs(opts, "MailServerRemoved")
|
||||||
|
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(RegistryMailServerRemoved)
|
||||||
|
if err := _Registry.contract.UnpackLog(event, "MailServerRemoved", 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
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
)
|
||||||
|
|
||||||
|
var logger = log.New("package", "mailserver/registry")
|
||||||
|
|
||||||
|
// Verifier verifies nodes based on a smart contract.
|
||||||
|
type Verifier struct {
|
||||||
|
rc *RegistryCaller
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewVerifier returns a new Verifier instance.
|
||||||
|
func NewVerifier(contractCaller bind.ContractCaller, contractAddress common.Address) (*Verifier, error) {
|
||||||
|
logger.Debug("initializing mailserver registry verifier", "address", fmt.Sprintf("0x%x", contractAddress))
|
||||||
|
rc, err := NewRegistryCaller(contractAddress, contractCaller)
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("error initializing mailserver registry verifier", "address", fmt.Sprintf("0x%x", contractAddress))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Verifier{
|
||||||
|
rc: rc,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyNode checks if a given node is trusted using a smart contract.
|
||||||
|
func (v *Verifier) VerifyNode(ctx context.Context, nodeID discover.NodeID) bool {
|
||||||
|
res, err := v.rc.Exists(&bind.CallOpts{Context: ctx}, nodeID.Bytes())
|
||||||
|
logger.Debug("verifying node", "id", nodeID, "verified", res)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("error verifying node", "id", nodeID, "error", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VerifierTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
backend *backends.SimulatedBackend
|
||||||
|
privKey *ecdsa.PrivateKey
|
||||||
|
from common.Address
|
||||||
|
contractAddress common.Address
|
||||||
|
registry *Registry
|
||||||
|
verifier *Verifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifierTestSuite(t *testing.T) {
|
||||||
|
suite.Run(t, &VerifierTestSuite{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *VerifierTestSuite) SetupTest() {
|
||||||
|
s.setupAccount()
|
||||||
|
s.setupBackendAndContract()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
s.verifier, err = NewVerifier(s.backend, s.contractAddress)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *VerifierTestSuite) setupBackendAndContract() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
auth := bind.NewKeyedTransactor(s.privKey)
|
||||||
|
alloc := make(core.GenesisAlloc)
|
||||||
|
alloc[auth.From] = core.GenesisAccount{Balance: big.NewInt(133700000)}
|
||||||
|
s.backend = backends.NewSimulatedBackend(alloc)
|
||||||
|
|
||||||
|
s.contractAddress, _, s.registry, err = DeployRegistry(auth, s.backend)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.backend.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *VerifierTestSuite) setupAccount() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
s.privKey, err = crypto.GenerateKey()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
s.from = crypto.PubkeyToAddress(s.privKey.PublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *VerifierTestSuite) add(nodeID discover.NodeID) {
|
||||||
|
auth := bind.NewKeyedTransactor(s.privKey)
|
||||||
|
_, err := s.registry.Add(auth, nodeID[:])
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.backend.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *VerifierTestSuite) generateNodeID() discover.NodeID {
|
||||||
|
k, err := crypto.GenerateKey()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
return discover.PubkeyID(&k.PublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *VerifierTestSuite) TestVerifyNode() {
|
||||||
|
id := s.generateNodeID()
|
||||||
|
res := s.verifier.VerifyNode(context.Background(), id)
|
||||||
|
s.Require().False(res)
|
||||||
|
|
||||||
|
s.add(id)
|
||||||
|
|
||||||
|
res = s.verifier.VerifyNode(context.Background(), id)
|
||||||
|
s.Require().True(res)
|
||||||
|
}
|
|
@ -251,6 +251,9 @@ func (n *StatusNode) startDiscovery() error {
|
||||||
// TODO(dshulyak) consider adding a flag to define this behaviour
|
// TODO(dshulyak) consider adding a flag to define this behaviour
|
||||||
options.AllowStop = len(n.config.RegisterTopics) == 0
|
options.AllowStop = len(n.config.RegisterTopics) == 0
|
||||||
options.TrustedMailServers = parseNodesToNodeID(n.config.ClusterConfig.TrustedMailServers)
|
options.TrustedMailServers = parseNodesToNodeID(n.config.ClusterConfig.TrustedMailServers)
|
||||||
|
|
||||||
|
options.MailServerRegistryAddress = n.config.MailServerRegistryAddress
|
||||||
|
|
||||||
n.peerPool = peers.NewPeerPool(
|
n.peerPool = peers.NewPeerPool(
|
||||||
n.discovery,
|
n.discovery,
|
||||||
n.config.RequireTopics,
|
n.config.RequireTopics,
|
||||||
|
@ -263,7 +266,7 @@ func (n *StatusNode) startDiscovery() error {
|
||||||
if err := n.register.Start(); err != nil {
|
if err := n.register.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return n.peerPool.Start(n.gethNode.Server())
|
return n.peerPool.Start(n.gethNode.Server(), n.rpcClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop will stop current StatusNode. A stopped node cannot be resumed.
|
// Stop will stop current StatusNode. A stopped node cannot be resumed.
|
||||||
|
@ -565,8 +568,8 @@ func (n *StatusNode) AccountKeyStore() (*keystore.KeyStore, error) {
|
||||||
|
|
||||||
// RPCClient exposes reference to RPC client connected to the running node.
|
// RPCClient exposes reference to RPC client connected to the running node.
|
||||||
func (n *StatusNode) RPCClient() *rpc.Client {
|
func (n *StatusNode) RPCClient() *rpc.Client {
|
||||||
n.mu.Lock()
|
n.mu.RLock()
|
||||||
defer n.mu.Unlock()
|
defer n.mu.RUnlock()
|
||||||
return n.rpcClient
|
return n.rpcClient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -357,6 +357,9 @@ type NodeConfig struct {
|
||||||
|
|
||||||
// DebugAPIEnabled enables debug api
|
// DebugAPIEnabled enables debug api
|
||||||
DebugAPIEnabled bool
|
DebugAPIEnabled bool
|
||||||
|
|
||||||
|
// MailServerRegistryAddress is the MailServerRegistry contract address
|
||||||
|
MailServerRegistryAddress string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNodeConfig creates new node configuration object
|
// NewNodeConfig creates new node configuration object
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
@ -12,7 +13,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/contracts"
|
||||||
"github.com/status-im/status-go/discovery"
|
"github.com/status-im/status-go/discovery"
|
||||||
|
"github.com/status-im/status-go/mailserver/registry"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/peers/verifier"
|
"github.com/status-im/status-go/peers/verifier"
|
||||||
"github.com/status-im/status-go/signal"
|
"github.com/status-im/status-go/signal"
|
||||||
|
@ -56,6 +59,8 @@ type Options struct {
|
||||||
TopicStopSearchDelay time.Duration
|
TopicStopSearchDelay time.Duration
|
||||||
// TrustedMailServers is a list of trusted nodes.
|
// TrustedMailServers is a list of trusted nodes.
|
||||||
TrustedMailServers []discover.NodeID
|
TrustedMailServers []discover.NodeID
|
||||||
|
// MailServerRegistryAddress is the MailServerRegistry contract address
|
||||||
|
MailServerRegistryAddress string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDefaultOptions returns a struct with default Options.
|
// NewDefaultOptions returns a struct with default Options.
|
||||||
|
@ -115,7 +120,7 @@ func (p *PeerPool) setDiscoveryTimeout() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start creates topic pool for each topic in config and subscribes to server events.
|
// Start creates topic pool for each topic in config and subscribes to server events.
|
||||||
func (p *PeerPool) Start(server *p2p.Server) error {
|
func (p *PeerPool) Start(server *p2p.Server, rpcClient contracts.RPCClient) error {
|
||||||
if !p.discovery.Running() {
|
if !p.discovery.Running() {
|
||||||
return ErrDiscv5NotRunning
|
return ErrDiscv5NotRunning
|
||||||
}
|
}
|
||||||
|
@ -143,7 +148,11 @@ func (p *PeerPool) Start(server *p2p.Server) error {
|
||||||
var topicPool TopicPoolInterface
|
var topicPool TopicPoolInterface
|
||||||
t := newTopicPool(p.discovery, topic, limits, p.opts.SlowSync, p.opts.FastSync, p.cache)
|
t := newTopicPool(p.discovery, topic, limits, p.opts.SlowSync, p.opts.FastSync, p.cache)
|
||||||
if topic == MailServerDiscoveryTopic {
|
if topic == MailServerDiscoveryTopic {
|
||||||
topicPool = newCacheOnlyTopicPool(t, verifier.NewLocalVerifier(p.opts.TrustedMailServers))
|
v, err := p.initVerifier(rpcClient)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
topicPool = newCacheOnlyTopicPool(t, v)
|
||||||
} else {
|
} else {
|
||||||
topicPool = t
|
topicPool = t
|
||||||
}
|
}
|
||||||
|
@ -159,6 +168,16 @@ func (p *PeerPool) Start(server *p2p.Server) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PeerPool) initVerifier(rpcClient contracts.RPCClient) (v Verifier, err error) {
|
||||||
|
if addr := p.opts.MailServerRegistryAddress; addr != "" {
|
||||||
|
caller := contracts.NewContractCaller(rpcClient)
|
||||||
|
addrBytes := common.FromHex(addr)
|
||||||
|
return registry.NewVerifier(caller, common.BytesToAddress(addrBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
return verifier.NewLocalVerifier(p.opts.TrustedMailServers), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *PeerPool) startDiscovery() error {
|
func (p *PeerPool) startDiscovery() error {
|
||||||
if p.discovery.Running() {
|
if p.discovery.Running() {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -162,13 +162,13 @@ func (s *PeerPoolSimulationSuite) TestPeerPoolCacheEthV5() {
|
||||||
config := map[discv5.Topic]params.Limits{
|
config := map[discv5.Topic]params.Limits{
|
||||||
topic: params.NewLimits(1, 1),
|
topic: params.NewLimits(1, 1),
|
||||||
}
|
}
|
||||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond, nil}
|
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond, nil, ""}
|
||||||
cache, err := newInMemoryCache()
|
cache, err := newInMemoryCache()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||||
|
|
||||||
// start peer pool
|
// start peer pool
|
||||||
s.Require().NoError(peerPool.Start(s.peers[1]))
|
s.Require().NoError(peerPool.Start(s.peers[1], nil))
|
||||||
defer peerPool.Stop()
|
defer peerPool.Stop()
|
||||||
|
|
||||||
// check if cache is passed to topic pools
|
// check if cache is passed to topic pools
|
||||||
|
@ -220,7 +220,7 @@ func (s *PeerPoolSimulationSuite) singleTopicDiscoveryWithFailover() {
|
||||||
config := map[discv5.Topic]params.Limits{
|
config := map[discv5.Topic]params.Limits{
|
||||||
topic: params.NewLimits(1, 1), // limits are chosen for simplicity of the simulation
|
topic: params.NewLimits(1, 1), // limits are chosen for simplicity of the simulation
|
||||||
}
|
}
|
||||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 0, nil}
|
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 0, nil, ""}
|
||||||
cache, err := newInMemoryCache()
|
cache, err := newInMemoryCache()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||||
|
@ -235,7 +235,7 @@ func (s *PeerPoolSimulationSuite) singleTopicDiscoveryWithFailover() {
|
||||||
defer subscription.Unsubscribe()
|
defer subscription.Unsubscribe()
|
||||||
|
|
||||||
// start the peer pool
|
// start the peer pool
|
||||||
s.Require().NoError(peerPool.Start(s.peers[1]))
|
s.Require().NoError(peerPool.Start(s.peers[1], nil))
|
||||||
defer peerPool.Stop()
|
defer peerPool.Stop()
|
||||||
s.Equal(signal.EventDiscoveryStarted, s.getPoolEvent(poolEvents))
|
s.Equal(signal.EventDiscoveryStarted, s.getPoolEvent(poolEvents))
|
||||||
|
|
||||||
|
@ -302,9 +302,9 @@ func TestPeerPoolMaxPeersOverflow(t *testing.T) {
|
||||||
defer func() { assert.NoError(t, discovery.Stop()) }()
|
defer func() { assert.NoError(t, discovery.Stop()) }()
|
||||||
require.True(t, discovery.Running())
|
require.True(t, discovery.Running())
|
||||||
|
|
||||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, 0, true, 100 * time.Millisecond, nil}
|
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, 0, true, 100 * time.Millisecond, nil, ""}
|
||||||
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
||||||
require.NoError(t, pool.Start(peer))
|
require.NoError(t, pool.Start(peer, nil))
|
||||||
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
||||||
// without config, it will stop the discovery because all topic pools are satisfied
|
// without config, it will stop the discovery because all topic pools are satisfied
|
||||||
pool.events <- &p2p.PeerEvent{Type: p2p.PeerEventTypeAdd}
|
pool.events <- &p2p.PeerEvent{Type: p2p.PeerEventTypeAdd}
|
||||||
|
@ -355,9 +355,9 @@ func TestPeerPoolDiscV5Timeout(t *testing.T) {
|
||||||
require.True(t, discovery.Running())
|
require.True(t, discovery.Running())
|
||||||
|
|
||||||
// start PeerPool
|
// start PeerPool
|
||||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, true, 100 * time.Millisecond, nil}
|
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, true, 100 * time.Millisecond, nil, ""}
|
||||||
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
||||||
require.NoError(t, pool.Start(server))
|
require.NoError(t, pool.Start(server, nil))
|
||||||
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
||||||
|
|
||||||
// timeout after finding no peers
|
// timeout after finding no peers
|
||||||
|
@ -402,9 +402,9 @@ func TestPeerPoolNotAllowedStopping(t *testing.T) {
|
||||||
require.True(t, discovery.Running())
|
require.True(t, discovery.Running())
|
||||||
|
|
||||||
// start PeerPool
|
// start PeerPool
|
||||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, false, 100 * time.Millisecond, nil}
|
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, false, 100 * time.Millisecond, nil, ""}
|
||||||
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
||||||
require.NoError(t, pool.Start(server))
|
require.NoError(t, pool.Start(server, nil))
|
||||||
|
|
||||||
// wait 2x timeout duration
|
// wait 2x timeout duration
|
||||||
<-time.After(pool.opts.DiscServerTimeout * 2)
|
<-time.After(pool.opts.DiscServerTimeout * 2)
|
||||||
|
@ -419,13 +419,13 @@ func (s *PeerPoolSimulationSuite) TestUpdateTopicLimits() {
|
||||||
config := map[discv5.Topic]params.Limits{
|
config := map[discv5.Topic]params.Limits{
|
||||||
topic: params.NewLimits(1, 1),
|
topic: params.NewLimits(1, 1),
|
||||||
}
|
}
|
||||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond, nil}
|
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond, nil, ""}
|
||||||
cache, err := newInMemoryCache()
|
cache, err := newInMemoryCache()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||||
|
|
||||||
// start peer pool
|
// start peer pool
|
||||||
s.Require().NoError(peerPool.Start(s.peers[1]))
|
s.Require().NoError(peerPool.Start(s.peers[1], nil))
|
||||||
defer peerPool.Stop()
|
defer peerPool.Stop()
|
||||||
|
|
||||||
for _, topicPool := range peerPool.topics {
|
for _, topicPool := range peerPool.topics {
|
||||||
|
@ -495,9 +495,10 @@ func (s *PeerPoolSimulationSuite) TestMailServerPeersDiscovery() {
|
||||||
true,
|
true,
|
||||||
100 * time.Millisecond,
|
100 * time.Millisecond,
|
||||||
[]discover.NodeID{s.peers[0].Self().ID},
|
[]discover.NodeID{s.peers[0].Self().ID},
|
||||||
|
"",
|
||||||
}
|
}
|
||||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||||
s.Require().NoError(peerPool.Start(s.peers[1]))
|
s.Require().NoError(peerPool.Start(s.peers[1], nil))
|
||||||
defer peerPool.Stop()
|
defer peerPool.Stop()
|
||||||
|
|
||||||
// wait for and verify the mail server peer
|
// wait for and verify the mail server peer
|
||||||
|
|
Loading…
Reference in New Issue