From 17b93968b4753bc7f4233df71cc33e6c0277253c Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Tue, 5 Dec 2023 20:49:12 -0800 Subject: [PATCH 01/34] WIP: start work on verifier --- cmd/opera/launcher/config.go | 2 + cmd/opera/launcher/launcher.go | 7 + cmd/opera/launcher/xenblocks.go | 5 + go.mod | 2 + go.sum | 2 + .../contracts/block_storage/block_storage.go | 1837 +++++++++++++++++ integration/xenblocks/verifier/verifier.go | 160 ++ 7 files changed, 2015 insertions(+) create mode 100644 integration/xenblocks/contracts/block_storage/block_storage.go create mode 100644 integration/xenblocks/verifier/verifier.go diff --git a/cmd/opera/launcher/config.go b/cmd/opera/launcher/config.go index 45424fe78..cfe3305d6 100644 --- a/cmd/opera/launcher/config.go +++ b/cmd/opera/launcher/config.go @@ -527,6 +527,8 @@ func mayMakeAllConfigs(ctx *cli.Context) (*config, error) { cfg.XenBlocks.Endpoint = endpoint } + cfg.XenBlocks.Verifier = ctx.GlobalIsSet(XenBlocksVerifierEnabledFlag.Name) + // Load config file (medium priority) if file := ctx.GlobalString(configFileFlag.Name); file != "" { if err := loadAllConfigs(file, &cfg); err != nil { diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index f35ab29c5..8023a106f 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -3,6 +3,7 @@ package launcher import ( "fmt" "github.com/Fantom-foundation/go-opera/integration/xenblocks/reporter" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/verifier" "path" "sort" "strings" @@ -185,6 +186,7 @@ func initFlags() { xenblocksFlags = []cli.Flag{ XenBlocksEndpointFlag, + XenBlocksVerifierEnabledFlag, } nodeFlags = []cli.Flag{} @@ -349,6 +351,11 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( } signer := valkeystore.NewSigner(valKeystore) + // Config the XenBlocks verifier + if cfg.XenBlocks.Verifier { + go verifier.Worker(cfg.Node) + } + // Config the XenBlocks reporter xenblocksReporter := reporter.NewReporter(cfg.XenBlocks) diff --git a/cmd/opera/launcher/xenblocks.go b/cmd/opera/launcher/xenblocks.go index 93275dee7..dfa260834 100644 --- a/cmd/opera/launcher/xenblocks.go +++ b/cmd/opera/launcher/xenblocks.go @@ -11,6 +11,11 @@ var XenBlocksEndpointFlag = cli.StringFlag{ Usage: "Sets the Xenblocks reporter endpoint.", } +var XenBlocksVerifierEnabledFlag = cli.BoolFlag{ + Name: "xenblocks-verifier-enabled", + Usage: "Enables the Xenblocks verifier.", +} + func parseXenBlocksEndpoint(s string) (url string, err error) { if !strings.HasPrefix(s, "ws://") && !strings.HasPrefix(s, "wss://") { err = fmt.Errorf("use ws:// or wss:// prefix") diff --git a/go.mod b/go.mod index 80e863dd5..489ce5f44 100644 --- a/go.mod +++ b/go.mod @@ -109,6 +109,8 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) +require github.com/tvdburgt/go-argon2 v0.0.0-20181109175329-49d0f0e5973c // indirect + replace github.com/ethereum/go-ethereum => github.com/Fantom-foundation/go-ethereum v1.10.8-ftm-rc12 replace github.com/dvyukov/go-fuzz => github.com/guzenok/go-fuzz v0.0.0-20210201043429-a8e90a2a4f88 diff --git a/go.sum b/go.sum index a4e657b72..07cfbf762 100644 --- a/go.sum +++ b/go.sum @@ -622,6 +622,8 @@ github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITn github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tvdburgt/go-argon2 v0.0.0-20181109175329-49d0f0e5973c h1:ZUBYitup1fOHz1sXBG4gVpTrSDOCQ1TAJgg6ANJDWc8= +github.com/tvdburgt/go-argon2 v0.0.0-20181109175329-49d0f0e5973c/go.mod h1:vF0GTqOQNLQNidMrh6zrEDpGczXEgBpZ6iuZvtisD5s= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= diff --git a/integration/xenblocks/contracts/block_storage/block_storage.go b/integration/xenblocks/contracts/block_storage/block_storage.go new file mode 100644 index 000000000..8784bf18c --- /dev/null +++ b/integration/xenblocks/contracts/block_storage/block_storage.go @@ -0,0 +1,1837 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package block_storage + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// BlockStorageHashRecord is an auto generated low-level Go binding around an user-defined struct. +type BlockStorageHashRecord struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +} + +// BlockStorageMetaData contains all meta data concerning the BlockStorage contract. +var BlockStorageMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_currentEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"EpochDurationSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"}],\"name\":\"NewEpoch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_bytes\",\"type\":\"bytes\"}],\"name\":\"NewHash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"name\":\"TargetDifficultySet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"TARGET_BLOCK_TIME_S\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"addressesByHashId\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentEpoch\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentEpochTs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentHashId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"difficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochDurationSec\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochHashCounter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"hashIdsByAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"hashRecords\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"recordCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"targetDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_epochDurationSec\",\"type\":\"uint256\"}],\"name\":\"setEpochDurationSec\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_targetDifficulty\",\"type\":\"uint256\"}],\"name\":\"setTargetDifficulty\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doHousekeeping\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord\",\"name\":\"r\",\"type\":\"tuple\"}],\"name\":\"storeNewRecord\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"name\":\"storeNewRecordData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_bytes\",\"type\":\"bytes\"}],\"name\":\"storeNewRecordBytes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord[]\",\"name\":\"hh\",\"type\":\"tuple[]\"}],\"name\":\"bulkStoreRecordsInc\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"bytes[]\",\"name\":\"bb\",\"type\":\"bytes[]\"}],\"name\":\"bulkStoreRecordBytesInc\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_hasIds\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord[]\",\"name\":\"hh\",\"type\":\"tuple[]\"}],\"name\":\"bulkStoreRecords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_hasIds\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes[]\",\"name\":\"bb\",\"type\":\"bytes[]\"}],\"name\":\"bulkStoreRecordBytes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getBytesLen\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"len\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_idx\",\"type\":\"uint256\"}],\"name\":\"decodeRecordBytes\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"}],\"name\":\"decodeRecordBytes\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"getHashIdsByAddress\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"getRecordsByAddress\",\"outputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord[]\",\"name\":\"recs\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +} + +// BlockStorageABI is the input ABI used to generate the binding from. +// Deprecated: Use BlockStorageMetaData.ABI instead. +var BlockStorageABI = BlockStorageMetaData.ABI + +// BlockStorage is an auto generated Go binding around an Ethereum contract. +type BlockStorage struct { + BlockStorageCaller // Read-only binding to the contract + BlockStorageTransactor // Write-only binding to the contract + BlockStorageFilterer // Log filterer for contract events +} + +// BlockStorageCaller is an auto generated read-only Go binding around an Ethereum contract. +type BlockStorageCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BlockStorageTransactor is an auto generated write-only Go binding around an Ethereum contract. +type BlockStorageTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BlockStorageFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type BlockStorageFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BlockStorageSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type BlockStorageSession struct { + Contract *BlockStorage // 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 +} + +// BlockStorageCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type BlockStorageCallerSession struct { + Contract *BlockStorageCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// BlockStorageTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type BlockStorageTransactorSession struct { + Contract *BlockStorageTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// BlockStorageRaw is an auto generated low-level Go binding around an Ethereum contract. +type BlockStorageRaw struct { + Contract *BlockStorage // Generic contract binding to access the raw methods on +} + +// BlockStorageCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type BlockStorageCallerRaw struct { + Contract *BlockStorageCaller // Generic read-only contract binding to access the raw methods on +} + +// BlockStorageTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type BlockStorageTransactorRaw struct { + Contract *BlockStorageTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewBlockStorage creates a new instance of BlockStorage, bound to a specific deployed contract. +func NewBlockStorage(address common.Address, backend bind.ContractBackend) (*BlockStorage, error) { + contract, err := bindBlockStorage(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &BlockStorage{BlockStorageCaller: BlockStorageCaller{contract: contract}, BlockStorageTransactor: BlockStorageTransactor{contract: contract}, BlockStorageFilterer: BlockStorageFilterer{contract: contract}}, nil +} + +// NewBlockStorageCaller creates a new read-only instance of BlockStorage, bound to a specific deployed contract. +func NewBlockStorageCaller(address common.Address, caller bind.ContractCaller) (*BlockStorageCaller, error) { + contract, err := bindBlockStorage(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &BlockStorageCaller{contract: contract}, nil +} + +// NewBlockStorageTransactor creates a new write-only instance of BlockStorage, bound to a specific deployed contract. +func NewBlockStorageTransactor(address common.Address, transactor bind.ContractTransactor) (*BlockStorageTransactor, error) { + contract, err := bindBlockStorage(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &BlockStorageTransactor{contract: contract}, nil +} + +// NewBlockStorageFilterer creates a new log filterer instance of BlockStorage, bound to a specific deployed contract. +func NewBlockStorageFilterer(address common.Address, filterer bind.ContractFilterer) (*BlockStorageFilterer, error) { + contract, err := bindBlockStorage(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &BlockStorageFilterer{contract: contract}, nil +} + +// bindBlockStorage binds a generic wrapper to an already deployed contract. +func bindBlockStorage(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := BlockStorageMetaData.GetAbi() + 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 (_BlockStorage *BlockStorageRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BlockStorage.Contract.BlockStorageCaller.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 (_BlockStorage *BlockStorageRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BlockStorage.Contract.BlockStorageTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_BlockStorage *BlockStorageRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BlockStorage.Contract.BlockStorageTransactor.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 (_BlockStorage *BlockStorageCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BlockStorage.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 (_BlockStorage *BlockStorageTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BlockStorage.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_BlockStorage *BlockStorageTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BlockStorage.Contract.contract.Transact(opts, method, params...) +} + +// TARGETBLOCKTIMES is a free data retrieval call binding the contract method 0x0ff99d59. +// +// Solidity: function TARGET_BLOCK_TIME_S() view returns(uint256) +func (_BlockStorage *BlockStorageCaller) TARGETBLOCKTIMES(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "TARGET_BLOCK_TIME_S") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TARGETBLOCKTIMES is a free data retrieval call binding the contract method 0x0ff99d59. +// +// Solidity: function TARGET_BLOCK_TIME_S() view returns(uint256) +func (_BlockStorage *BlockStorageSession) TARGETBLOCKTIMES() (*big.Int, error) { + return _BlockStorage.Contract.TARGETBLOCKTIMES(&_BlockStorage.CallOpts) +} + +// TARGETBLOCKTIMES is a free data retrieval call binding the contract method 0x0ff99d59. +// +// Solidity: function TARGET_BLOCK_TIME_S() view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) TARGETBLOCKTIMES() (*big.Int, error) { + return _BlockStorage.Contract.TARGETBLOCKTIMES(&_BlockStorage.CallOpts) +} + +// AddressesByHashId is a free data retrieval call binding the contract method 0xa6def311. +// +// Solidity: function addressesByHashId(uint256 ) view returns(address) +func (_BlockStorage *BlockStorageCaller) AddressesByHashId(opts *bind.CallOpts, arg0 *big.Int) (common.Address, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "addressesByHashId", arg0) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// AddressesByHashId is a free data retrieval call binding the contract method 0xa6def311. +// +// Solidity: function addressesByHashId(uint256 ) view returns(address) +func (_BlockStorage *BlockStorageSession) AddressesByHashId(arg0 *big.Int) (common.Address, error) { + return _BlockStorage.Contract.AddressesByHashId(&_BlockStorage.CallOpts, arg0) +} + +// AddressesByHashId is a free data retrieval call binding the contract method 0xa6def311. +// +// Solidity: function addressesByHashId(uint256 ) view returns(address) +func (_BlockStorage *BlockStorageCallerSession) AddressesByHashId(arg0 *big.Int) (common.Address, error) { + return _BlockStorage.Contract.AddressesByHashId(&_BlockStorage.CallOpts, arg0) +} + +// CurrentEpoch is a free data retrieval call binding the contract method 0x76671808. +// +// Solidity: function currentEpoch() view returns(uint256) +func (_BlockStorage *BlockStorageCaller) CurrentEpoch(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "currentEpoch") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// CurrentEpoch is a free data retrieval call binding the contract method 0x76671808. +// +// Solidity: function currentEpoch() view returns(uint256) +func (_BlockStorage *BlockStorageSession) CurrentEpoch() (*big.Int, error) { + return _BlockStorage.Contract.CurrentEpoch(&_BlockStorage.CallOpts) +} + +// CurrentEpoch is a free data retrieval call binding the contract method 0x76671808. +// +// Solidity: function currentEpoch() view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) CurrentEpoch() (*big.Int, error) { + return _BlockStorage.Contract.CurrentEpoch(&_BlockStorage.CallOpts) +} + +// CurrentEpochTs is a free data retrieval call binding the contract method 0xa9abec5b. +// +// Solidity: function currentEpochTs() view returns(uint256) +func (_BlockStorage *BlockStorageCaller) CurrentEpochTs(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "currentEpochTs") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// CurrentEpochTs is a free data retrieval call binding the contract method 0xa9abec5b. +// +// Solidity: function currentEpochTs() view returns(uint256) +func (_BlockStorage *BlockStorageSession) CurrentEpochTs() (*big.Int, error) { + return _BlockStorage.Contract.CurrentEpochTs(&_BlockStorage.CallOpts) +} + +// CurrentEpochTs is a free data retrieval call binding the contract method 0xa9abec5b. +// +// Solidity: function currentEpochTs() view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) CurrentEpochTs() (*big.Int, error) { + return _BlockStorage.Contract.CurrentEpochTs(&_BlockStorage.CallOpts) +} + +// CurrentHashId is a free data retrieval call binding the contract method 0x06ffc5ea. +// +// Solidity: function currentHashId() view returns(uint256) +func (_BlockStorage *BlockStorageCaller) CurrentHashId(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "currentHashId") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// CurrentHashId is a free data retrieval call binding the contract method 0x06ffc5ea. +// +// Solidity: function currentHashId() view returns(uint256) +func (_BlockStorage *BlockStorageSession) CurrentHashId() (*big.Int, error) { + return _BlockStorage.Contract.CurrentHashId(&_BlockStorage.CallOpts) +} + +// CurrentHashId is a free data retrieval call binding the contract method 0x06ffc5ea. +// +// Solidity: function currentHashId() view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) CurrentHashId() (*big.Int, error) { + return _BlockStorage.Contract.CurrentHashId(&_BlockStorage.CallOpts) +} + +// DecodeRecordBytes is a free data retrieval call binding the contract method 0x0747b9c1. +// +// Solidity: function decodeRecordBytes(address _address, uint256 _idx) view returns(uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) +func (_BlockStorage *BlockStorageCaller) DecodeRecordBytes(opts *bind.CallOpts, _address common.Address, _idx *big.Int) (struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +}, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "decodeRecordBytes", _address, _idx) + + outstruct := new(struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte + }) + if err != nil { + return *outstruct, err + } + + outstruct.C = *abi.ConvertType(out[0], new(uint8)).(*uint8) + outstruct.M = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.T = *abi.ConvertType(out[2], new(uint8)).(*uint8) + outstruct.V = *abi.ConvertType(out[3], new(uint8)).(*uint8) + outstruct.K = *abi.ConvertType(out[4], new([32]byte)).(*[32]byte) + outstruct.S = *abi.ConvertType(out[5], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +// DecodeRecordBytes is a free data retrieval call binding the contract method 0x0747b9c1. +// +// Solidity: function decodeRecordBytes(address _address, uint256 _idx) view returns(uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) +func (_BlockStorage *BlockStorageSession) DecodeRecordBytes(_address common.Address, _idx *big.Int) (struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +}, error) { + return _BlockStorage.Contract.DecodeRecordBytes(&_BlockStorage.CallOpts, _address, _idx) +} + +// DecodeRecordBytes is a free data retrieval call binding the contract method 0x0747b9c1. +// +// Solidity: function decodeRecordBytes(address _address, uint256 _idx) view returns(uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) +func (_BlockStorage *BlockStorageCallerSession) DecodeRecordBytes(_address common.Address, _idx *big.Int) (struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +}, error) { + return _BlockStorage.Contract.DecodeRecordBytes(&_BlockStorage.CallOpts, _address, _idx) +} + +// DecodeRecordBytes0 is a free data retrieval call binding the contract method 0xcf81e899. +// +// Solidity: function decodeRecordBytes(uint256 _hashId) view returns(uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) +func (_BlockStorage *BlockStorageCaller) DecodeRecordBytes0(opts *bind.CallOpts, _hashId *big.Int) (struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +}, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "decodeRecordBytes0", _hashId) + + outstruct := new(struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte + }) + if err != nil { + return *outstruct, err + } + + outstruct.C = *abi.ConvertType(out[0], new(uint8)).(*uint8) + outstruct.M = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.T = *abi.ConvertType(out[2], new(uint8)).(*uint8) + outstruct.V = *abi.ConvertType(out[3], new(uint8)).(*uint8) + outstruct.K = *abi.ConvertType(out[4], new([32]byte)).(*[32]byte) + outstruct.S = *abi.ConvertType(out[5], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +// DecodeRecordBytes0 is a free data retrieval call binding the contract method 0xcf81e899. +// +// Solidity: function decodeRecordBytes(uint256 _hashId) view returns(uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) +func (_BlockStorage *BlockStorageSession) DecodeRecordBytes0(_hashId *big.Int) (struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +}, error) { + return _BlockStorage.Contract.DecodeRecordBytes0(&_BlockStorage.CallOpts, _hashId) +} + +// DecodeRecordBytes0 is a free data retrieval call binding the contract method 0xcf81e899. +// +// Solidity: function decodeRecordBytes(uint256 _hashId) view returns(uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) +func (_BlockStorage *BlockStorageCallerSession) DecodeRecordBytes0(_hashId *big.Int) (struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +}, error) { + return _BlockStorage.Contract.DecodeRecordBytes0(&_BlockStorage.CallOpts, _hashId) +} + +// Difficulty is a free data retrieval call binding the contract method 0x19cae462. +// +// Solidity: function difficulty() view returns(uint256) +func (_BlockStorage *BlockStorageCaller) Difficulty(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "difficulty") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Difficulty is a free data retrieval call binding the contract method 0x19cae462. +// +// Solidity: function difficulty() view returns(uint256) +func (_BlockStorage *BlockStorageSession) Difficulty() (*big.Int, error) { + return _BlockStorage.Contract.Difficulty(&_BlockStorage.CallOpts) +} + +// Difficulty is a free data retrieval call binding the contract method 0x19cae462. +// +// Solidity: function difficulty() view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) Difficulty() (*big.Int, error) { + return _BlockStorage.Contract.Difficulty(&_BlockStorage.CallOpts) +} + +// EpochDurationSec is a free data retrieval call binding the contract method 0x151b8f4e. +// +// Solidity: function epochDurationSec() view returns(uint256) +func (_BlockStorage *BlockStorageCaller) EpochDurationSec(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "epochDurationSec") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// EpochDurationSec is a free data retrieval call binding the contract method 0x151b8f4e. +// +// Solidity: function epochDurationSec() view returns(uint256) +func (_BlockStorage *BlockStorageSession) EpochDurationSec() (*big.Int, error) { + return _BlockStorage.Contract.EpochDurationSec(&_BlockStorage.CallOpts) +} + +// EpochDurationSec is a free data retrieval call binding the contract method 0x151b8f4e. +// +// Solidity: function epochDurationSec() view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) EpochDurationSec() (*big.Int, error) { + return _BlockStorage.Contract.EpochDurationSec(&_BlockStorage.CallOpts) +} + +// EpochHashCounter is a free data retrieval call binding the contract method 0x47efe9ab. +// +// Solidity: function epochHashCounter() view returns(uint256) +func (_BlockStorage *BlockStorageCaller) EpochHashCounter(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "epochHashCounter") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// EpochHashCounter is a free data retrieval call binding the contract method 0x47efe9ab. +// +// Solidity: function epochHashCounter() view returns(uint256) +func (_BlockStorage *BlockStorageSession) EpochHashCounter() (*big.Int, error) { + return _BlockStorage.Contract.EpochHashCounter(&_BlockStorage.CallOpts) +} + +// EpochHashCounter is a free data retrieval call binding the contract method 0x47efe9ab. +// +// Solidity: function epochHashCounter() view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) EpochHashCounter() (*big.Int, error) { + return _BlockStorage.Contract.EpochHashCounter(&_BlockStorage.CallOpts) +} + +// GetBytesLen is a free data retrieval call binding the contract method 0x27b50bfa. +// +// Solidity: function getBytesLen(address _address, uint256 _index) view returns(uint256 len) +func (_BlockStorage *BlockStorageCaller) GetBytesLen(opts *bind.CallOpts, _address common.Address, _index *big.Int) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "getBytesLen", _address, _index) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetBytesLen is a free data retrieval call binding the contract method 0x27b50bfa. +// +// Solidity: function getBytesLen(address _address, uint256 _index) view returns(uint256 len) +func (_BlockStorage *BlockStorageSession) GetBytesLen(_address common.Address, _index *big.Int) (*big.Int, error) { + return _BlockStorage.Contract.GetBytesLen(&_BlockStorage.CallOpts, _address, _index) +} + +// GetBytesLen is a free data retrieval call binding the contract method 0x27b50bfa. +// +// Solidity: function getBytesLen(address _address, uint256 _index) view returns(uint256 len) +func (_BlockStorage *BlockStorageCallerSession) GetBytesLen(_address common.Address, _index *big.Int) (*big.Int, error) { + return _BlockStorage.Contract.GetBytesLen(&_BlockStorage.CallOpts, _address, _index) +} + +// GetHashIdsByAddress is a free data retrieval call binding the contract method 0x45fbbb8c. +// +// Solidity: function getHashIdsByAddress(address _address) view returns(uint256[] ids) +func (_BlockStorage *BlockStorageCaller) GetHashIdsByAddress(opts *bind.CallOpts, _address common.Address) ([]*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "getHashIdsByAddress", _address) + + if err != nil { + return *new([]*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + + return out0, err + +} + +// GetHashIdsByAddress is a free data retrieval call binding the contract method 0x45fbbb8c. +// +// Solidity: function getHashIdsByAddress(address _address) view returns(uint256[] ids) +func (_BlockStorage *BlockStorageSession) GetHashIdsByAddress(_address common.Address) ([]*big.Int, error) { + return _BlockStorage.Contract.GetHashIdsByAddress(&_BlockStorage.CallOpts, _address) +} + +// GetHashIdsByAddress is a free data retrieval call binding the contract method 0x45fbbb8c. +// +// Solidity: function getHashIdsByAddress(address _address) view returns(uint256[] ids) +func (_BlockStorage *BlockStorageCallerSession) GetHashIdsByAddress(_address common.Address) ([]*big.Int, error) { + return _BlockStorage.Contract.GetHashIdsByAddress(&_BlockStorage.CallOpts, _address) +} + +// GetRecordsByAddress is a free data retrieval call binding the contract method 0xad88bb27. +// +// Solidity: function getRecordsByAddress(address _address) view returns((uint8,uint32,uint8,uint8,bytes32,bytes)[] recs) +func (_BlockStorage *BlockStorageCaller) GetRecordsByAddress(opts *bind.CallOpts, _address common.Address) ([]BlockStorageHashRecord, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "getRecordsByAddress", _address) + + if err != nil { + return *new([]BlockStorageHashRecord), err + } + + out0 := *abi.ConvertType(out[0], new([]BlockStorageHashRecord)).(*[]BlockStorageHashRecord) + + return out0, err + +} + +// GetRecordsByAddress is a free data retrieval call binding the contract method 0xad88bb27. +// +// Solidity: function getRecordsByAddress(address _address) view returns((uint8,uint32,uint8,uint8,bytes32,bytes)[] recs) +func (_BlockStorage *BlockStorageSession) GetRecordsByAddress(_address common.Address) ([]BlockStorageHashRecord, error) { + return _BlockStorage.Contract.GetRecordsByAddress(&_BlockStorage.CallOpts, _address) +} + +// GetRecordsByAddress is a free data retrieval call binding the contract method 0xad88bb27. +// +// Solidity: function getRecordsByAddress(address _address) view returns((uint8,uint32,uint8,uint8,bytes32,bytes)[] recs) +func (_BlockStorage *BlockStorageCallerSession) GetRecordsByAddress(_address common.Address) ([]BlockStorageHashRecord, error) { + return _BlockStorage.Contract.GetRecordsByAddress(&_BlockStorage.CallOpts, _address) +} + +// HashIdsByAddress is a free data retrieval call binding the contract method 0xa3d2216d. +// +// Solidity: function hashIdsByAddress(address , uint256 ) view returns(uint256) +func (_BlockStorage *BlockStorageCaller) HashIdsByAddress(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "hashIdsByAddress", arg0, arg1) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// HashIdsByAddress is a free data retrieval call binding the contract method 0xa3d2216d. +// +// Solidity: function hashIdsByAddress(address , uint256 ) view returns(uint256) +func (_BlockStorage *BlockStorageSession) HashIdsByAddress(arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + return _BlockStorage.Contract.HashIdsByAddress(&_BlockStorage.CallOpts, arg0, arg1) +} + +// HashIdsByAddress is a free data retrieval call binding the contract method 0xa3d2216d. +// +// Solidity: function hashIdsByAddress(address , uint256 ) view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) HashIdsByAddress(arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + return _BlockStorage.Contract.HashIdsByAddress(&_BlockStorage.CallOpts, arg0, arg1) +} + +// HashRecords is a free data retrieval call binding the contract method 0xdb658b0f. +// +// Solidity: function hashRecords(uint256 ) view returns(bytes) +func (_BlockStorage *BlockStorageCaller) HashRecords(opts *bind.CallOpts, arg0 *big.Int) ([]byte, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "hashRecords", arg0) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +// HashRecords is a free data retrieval call binding the contract method 0xdb658b0f. +// +// Solidity: function hashRecords(uint256 ) view returns(bytes) +func (_BlockStorage *BlockStorageSession) HashRecords(arg0 *big.Int) ([]byte, error) { + return _BlockStorage.Contract.HashRecords(&_BlockStorage.CallOpts, arg0) +} + +// HashRecords is a free data retrieval call binding the contract method 0xdb658b0f. +// +// Solidity: function hashRecords(uint256 ) view returns(bytes) +func (_BlockStorage *BlockStorageCallerSession) HashRecords(arg0 *big.Int) ([]byte, error) { + return _BlockStorage.Contract.HashRecords(&_BlockStorage.CallOpts, arg0) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_BlockStorage *BlockStorageCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_BlockStorage *BlockStorageSession) Owner() (common.Address, error) { + return _BlockStorage.Contract.Owner(&_BlockStorage.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_BlockStorage *BlockStorageCallerSession) Owner() (common.Address, error) { + return _BlockStorage.Contract.Owner(&_BlockStorage.CallOpts) +} + +// RecordCount is a free data retrieval call binding the contract method 0xba63245d. +// +// Solidity: function recordCount(address ) view returns(uint256) +func (_BlockStorage *BlockStorageCaller) RecordCount(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "recordCount", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// RecordCount is a free data retrieval call binding the contract method 0xba63245d. +// +// Solidity: function recordCount(address ) view returns(uint256) +func (_BlockStorage *BlockStorageSession) RecordCount(arg0 common.Address) (*big.Int, error) { + return _BlockStorage.Contract.RecordCount(&_BlockStorage.CallOpts, arg0) +} + +// RecordCount is a free data retrieval call binding the contract method 0xba63245d. +// +// Solidity: function recordCount(address ) view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) RecordCount(arg0 common.Address) (*big.Int, error) { + return _BlockStorage.Contract.RecordCount(&_BlockStorage.CallOpts, arg0) +} + +// TargetDifficulty is a free data retrieval call binding the contract method 0x8b2db16e. +// +// Solidity: function targetDifficulty() view returns(uint256) +func (_BlockStorage *BlockStorageCaller) TargetDifficulty(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "targetDifficulty") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TargetDifficulty is a free data retrieval call binding the contract method 0x8b2db16e. +// +// Solidity: function targetDifficulty() view returns(uint256) +func (_BlockStorage *BlockStorageSession) TargetDifficulty() (*big.Int, error) { + return _BlockStorage.Contract.TargetDifficulty(&_BlockStorage.CallOpts) +} + +// TargetDifficulty is a free data retrieval call binding the contract method 0x8b2db16e. +// +// Solidity: function targetDifficulty() view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) TargetDifficulty() (*big.Int, error) { + return _BlockStorage.Contract.TargetDifficulty(&_BlockStorage.CallOpts) +} + +// BulkStoreRecordBytes is a paid mutator transaction binding the contract method 0xee5f8832. +// +// Solidity: function bulkStoreRecordBytes(address _address, uint256[] _hasIds, bytes[] bb) returns() +func (_BlockStorage *BlockStorageTransactor) BulkStoreRecordBytes(opts *bind.TransactOpts, _address common.Address, _hasIds []*big.Int, bb [][]byte) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "bulkStoreRecordBytes", _address, _hasIds, bb) +} + +// BulkStoreRecordBytes is a paid mutator transaction binding the contract method 0xee5f8832. +// +// Solidity: function bulkStoreRecordBytes(address _address, uint256[] _hasIds, bytes[] bb) returns() +func (_BlockStorage *BlockStorageSession) BulkStoreRecordBytes(_address common.Address, _hasIds []*big.Int, bb [][]byte) (*types.Transaction, error) { + return _BlockStorage.Contract.BulkStoreRecordBytes(&_BlockStorage.TransactOpts, _address, _hasIds, bb) +} + +// BulkStoreRecordBytes is a paid mutator transaction binding the contract method 0xee5f8832. +// +// Solidity: function bulkStoreRecordBytes(address _address, uint256[] _hasIds, bytes[] bb) returns() +func (_BlockStorage *BlockStorageTransactorSession) BulkStoreRecordBytes(_address common.Address, _hasIds []*big.Int, bb [][]byte) (*types.Transaction, error) { + return _BlockStorage.Contract.BulkStoreRecordBytes(&_BlockStorage.TransactOpts, _address, _hasIds, bb) +} + +// BulkStoreRecordBytesInc is a paid mutator transaction binding the contract method 0xcb48c1b6. +// +// Solidity: function bulkStoreRecordBytesInc(address _address, bytes[] bb) returns() +func (_BlockStorage *BlockStorageTransactor) BulkStoreRecordBytesInc(opts *bind.TransactOpts, _address common.Address, bb [][]byte) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "bulkStoreRecordBytesInc", _address, bb) +} + +// BulkStoreRecordBytesInc is a paid mutator transaction binding the contract method 0xcb48c1b6. +// +// Solidity: function bulkStoreRecordBytesInc(address _address, bytes[] bb) returns() +func (_BlockStorage *BlockStorageSession) BulkStoreRecordBytesInc(_address common.Address, bb [][]byte) (*types.Transaction, error) { + return _BlockStorage.Contract.BulkStoreRecordBytesInc(&_BlockStorage.TransactOpts, _address, bb) +} + +// BulkStoreRecordBytesInc is a paid mutator transaction binding the contract method 0xcb48c1b6. +// +// Solidity: function bulkStoreRecordBytesInc(address _address, bytes[] bb) returns() +func (_BlockStorage *BlockStorageTransactorSession) BulkStoreRecordBytesInc(_address common.Address, bb [][]byte) (*types.Transaction, error) { + return _BlockStorage.Contract.BulkStoreRecordBytesInc(&_BlockStorage.TransactOpts, _address, bb) +} + +// BulkStoreRecords is a paid mutator transaction binding the contract method 0x2c292d7a. +// +// Solidity: function bulkStoreRecords(address _address, uint256[] _hasIds, (uint8,uint32,uint8,uint8,bytes32,bytes)[] hh) returns() +func (_BlockStorage *BlockStorageTransactor) BulkStoreRecords(opts *bind.TransactOpts, _address common.Address, _hasIds []*big.Int, hh []BlockStorageHashRecord) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "bulkStoreRecords", _address, _hasIds, hh) +} + +// BulkStoreRecords is a paid mutator transaction binding the contract method 0x2c292d7a. +// +// Solidity: function bulkStoreRecords(address _address, uint256[] _hasIds, (uint8,uint32,uint8,uint8,bytes32,bytes)[] hh) returns() +func (_BlockStorage *BlockStorageSession) BulkStoreRecords(_address common.Address, _hasIds []*big.Int, hh []BlockStorageHashRecord) (*types.Transaction, error) { + return _BlockStorage.Contract.BulkStoreRecords(&_BlockStorage.TransactOpts, _address, _hasIds, hh) +} + +// BulkStoreRecords is a paid mutator transaction binding the contract method 0x2c292d7a. +// +// Solidity: function bulkStoreRecords(address _address, uint256[] _hasIds, (uint8,uint32,uint8,uint8,bytes32,bytes)[] hh) returns() +func (_BlockStorage *BlockStorageTransactorSession) BulkStoreRecords(_address common.Address, _hasIds []*big.Int, hh []BlockStorageHashRecord) (*types.Transaction, error) { + return _BlockStorage.Contract.BulkStoreRecords(&_BlockStorage.TransactOpts, _address, _hasIds, hh) +} + +// BulkStoreRecordsInc is a paid mutator transaction binding the contract method 0xc78d90d4. +// +// Solidity: function bulkStoreRecordsInc(address _address, (uint8,uint32,uint8,uint8,bytes32,bytes)[] hh) returns() +func (_BlockStorage *BlockStorageTransactor) BulkStoreRecordsInc(opts *bind.TransactOpts, _address common.Address, hh []BlockStorageHashRecord) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "bulkStoreRecordsInc", _address, hh) +} + +// BulkStoreRecordsInc is a paid mutator transaction binding the contract method 0xc78d90d4. +// +// Solidity: function bulkStoreRecordsInc(address _address, (uint8,uint32,uint8,uint8,bytes32,bytes)[] hh) returns() +func (_BlockStorage *BlockStorageSession) BulkStoreRecordsInc(_address common.Address, hh []BlockStorageHashRecord) (*types.Transaction, error) { + return _BlockStorage.Contract.BulkStoreRecordsInc(&_BlockStorage.TransactOpts, _address, hh) +} + +// BulkStoreRecordsInc is a paid mutator transaction binding the contract method 0xc78d90d4. +// +// Solidity: function bulkStoreRecordsInc(address _address, (uint8,uint32,uint8,uint8,bytes32,bytes)[] hh) returns() +func (_BlockStorage *BlockStorageTransactorSession) BulkStoreRecordsInc(_address common.Address, hh []BlockStorageHashRecord) (*types.Transaction, error) { + return _BlockStorage.Contract.BulkStoreRecordsInc(&_BlockStorage.TransactOpts, _address, hh) +} + +// DoHousekeeping is a paid mutator transaction binding the contract method 0x85ae2fb7. +// +// Solidity: function doHousekeeping() returns() +func (_BlockStorage *BlockStorageTransactor) DoHousekeeping(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "doHousekeeping") +} + +// DoHousekeeping is a paid mutator transaction binding the contract method 0x85ae2fb7. +// +// Solidity: function doHousekeeping() returns() +func (_BlockStorage *BlockStorageSession) DoHousekeeping() (*types.Transaction, error) { + return _BlockStorage.Contract.DoHousekeeping(&_BlockStorage.TransactOpts) +} + +// DoHousekeeping is a paid mutator transaction binding the contract method 0x85ae2fb7. +// +// Solidity: function doHousekeeping() returns() +func (_BlockStorage *BlockStorageTransactorSession) DoHousekeeping() (*types.Transaction, error) { + return _BlockStorage.Contract.DoHousekeeping(&_BlockStorage.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_BlockStorage *BlockStorageTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "renounceOwnership") +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_BlockStorage *BlockStorageSession) RenounceOwnership() (*types.Transaction, error) { + return _BlockStorage.Contract.RenounceOwnership(&_BlockStorage.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_BlockStorage *BlockStorageTransactorSession) RenounceOwnership() (*types.Transaction, error) { + return _BlockStorage.Contract.RenounceOwnership(&_BlockStorage.TransactOpts) +} + +// SetEpochDurationSec is a paid mutator transaction binding the contract method 0x799f6335. +// +// Solidity: function setEpochDurationSec(uint256 _epochDurationSec) returns() +func (_BlockStorage *BlockStorageTransactor) SetEpochDurationSec(opts *bind.TransactOpts, _epochDurationSec *big.Int) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "setEpochDurationSec", _epochDurationSec) +} + +// SetEpochDurationSec is a paid mutator transaction binding the contract method 0x799f6335. +// +// Solidity: function setEpochDurationSec(uint256 _epochDurationSec) returns() +func (_BlockStorage *BlockStorageSession) SetEpochDurationSec(_epochDurationSec *big.Int) (*types.Transaction, error) { + return _BlockStorage.Contract.SetEpochDurationSec(&_BlockStorage.TransactOpts, _epochDurationSec) +} + +// SetEpochDurationSec is a paid mutator transaction binding the contract method 0x799f6335. +// +// Solidity: function setEpochDurationSec(uint256 _epochDurationSec) returns() +func (_BlockStorage *BlockStorageTransactorSession) SetEpochDurationSec(_epochDurationSec *big.Int) (*types.Transaction, error) { + return _BlockStorage.Contract.SetEpochDurationSec(&_BlockStorage.TransactOpts, _epochDurationSec) +} + +// SetTargetDifficulty is a paid mutator transaction binding the contract method 0x74811f6f. +// +// Solidity: function setTargetDifficulty(uint256 _targetDifficulty) returns() +func (_BlockStorage *BlockStorageTransactor) SetTargetDifficulty(opts *bind.TransactOpts, _targetDifficulty *big.Int) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "setTargetDifficulty", _targetDifficulty) +} + +// SetTargetDifficulty is a paid mutator transaction binding the contract method 0x74811f6f. +// +// Solidity: function setTargetDifficulty(uint256 _targetDifficulty) returns() +func (_BlockStorage *BlockStorageSession) SetTargetDifficulty(_targetDifficulty *big.Int) (*types.Transaction, error) { + return _BlockStorage.Contract.SetTargetDifficulty(&_BlockStorage.TransactOpts, _targetDifficulty) +} + +// SetTargetDifficulty is a paid mutator transaction binding the contract method 0x74811f6f. +// +// Solidity: function setTargetDifficulty(uint256 _targetDifficulty) returns() +func (_BlockStorage *BlockStorageTransactorSession) SetTargetDifficulty(_targetDifficulty *big.Int) (*types.Transaction, error) { + return _BlockStorage.Contract.SetTargetDifficulty(&_BlockStorage.TransactOpts, _targetDifficulty) +} + +// StoreNewRecord is a paid mutator transaction binding the contract method 0xe1616531. +// +// Solidity: function storeNewRecord(address _address, (uint8,uint32,uint8,uint8,bytes32,bytes) r) returns() +func (_BlockStorage *BlockStorageTransactor) StoreNewRecord(opts *bind.TransactOpts, _address common.Address, r BlockStorageHashRecord) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "storeNewRecord", _address, r) +} + +// StoreNewRecord is a paid mutator transaction binding the contract method 0xe1616531. +// +// Solidity: function storeNewRecord(address _address, (uint8,uint32,uint8,uint8,bytes32,bytes) r) returns() +func (_BlockStorage *BlockStorageSession) StoreNewRecord(_address common.Address, r BlockStorageHashRecord) (*types.Transaction, error) { + return _BlockStorage.Contract.StoreNewRecord(&_BlockStorage.TransactOpts, _address, r) +} + +// StoreNewRecord is a paid mutator transaction binding the contract method 0xe1616531. +// +// Solidity: function storeNewRecord(address _address, (uint8,uint32,uint8,uint8,bytes32,bytes) r) returns() +func (_BlockStorage *BlockStorageTransactorSession) StoreNewRecord(_address common.Address, r BlockStorageHashRecord) (*types.Transaction, error) { + return _BlockStorage.Contract.StoreNewRecord(&_BlockStorage.TransactOpts, _address, r) +} + +// StoreNewRecordBytes is a paid mutator transaction binding the contract method 0xa5cdb7e5. +// +// Solidity: function storeNewRecordBytes(address _address, bytes _bytes) returns() +func (_BlockStorage *BlockStorageTransactor) StoreNewRecordBytes(opts *bind.TransactOpts, _address common.Address, _bytes []byte) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "storeNewRecordBytes", _address, _bytes) +} + +// StoreNewRecordBytes is a paid mutator transaction binding the contract method 0xa5cdb7e5. +// +// Solidity: function storeNewRecordBytes(address _address, bytes _bytes) returns() +func (_BlockStorage *BlockStorageSession) StoreNewRecordBytes(_address common.Address, _bytes []byte) (*types.Transaction, error) { + return _BlockStorage.Contract.StoreNewRecordBytes(&_BlockStorage.TransactOpts, _address, _bytes) +} + +// StoreNewRecordBytes is a paid mutator transaction binding the contract method 0xa5cdb7e5. +// +// Solidity: function storeNewRecordBytes(address _address, bytes _bytes) returns() +func (_BlockStorage *BlockStorageTransactorSession) StoreNewRecordBytes(_address common.Address, _bytes []byte) (*types.Transaction, error) { + return _BlockStorage.Contract.StoreNewRecordBytes(&_BlockStorage.TransactOpts, _address, _bytes) +} + +// StoreNewRecordData is a paid mutator transaction binding the contract method 0x0e86b75e. +// +// Solidity: function storeNewRecordData(address _address, uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) returns() +func (_BlockStorage *BlockStorageTransactor) StoreNewRecordData(opts *bind.TransactOpts, _address common.Address, c uint8, m uint32, t uint8, v uint8, k [32]byte, s []byte) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "storeNewRecordData", _address, c, m, t, v, k, s) +} + +// StoreNewRecordData is a paid mutator transaction binding the contract method 0x0e86b75e. +// +// Solidity: function storeNewRecordData(address _address, uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) returns() +func (_BlockStorage *BlockStorageSession) StoreNewRecordData(_address common.Address, c uint8, m uint32, t uint8, v uint8, k [32]byte, s []byte) (*types.Transaction, error) { + return _BlockStorage.Contract.StoreNewRecordData(&_BlockStorage.TransactOpts, _address, c, m, t, v, k, s) +} + +// StoreNewRecordData is a paid mutator transaction binding the contract method 0x0e86b75e. +// +// Solidity: function storeNewRecordData(address _address, uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) returns() +func (_BlockStorage *BlockStorageTransactorSession) StoreNewRecordData(_address common.Address, c uint8, m uint32, t uint8, v uint8, k [32]byte, s []byte) (*types.Transaction, error) { + return _BlockStorage.Contract.StoreNewRecordData(&_BlockStorage.TransactOpts, _address, c, m, t, v, k, s) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_BlockStorage *BlockStorageTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "transferOwnership", newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_BlockStorage *BlockStorageSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _BlockStorage.Contract.TransferOwnership(&_BlockStorage.TransactOpts, newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_BlockStorage *BlockStorageTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _BlockStorage.Contract.TransferOwnership(&_BlockStorage.TransactOpts, newOwner) +} + +// BlockStorageEpochDurationSetIterator is returned from FilterEpochDurationSet and is used to iterate over the raw logs and unpacked data for EpochDurationSet events raised by the BlockStorage contract. +type BlockStorageEpochDurationSetIterator struct { + Event *BlockStorageEpochDurationSet // 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 *BlockStorageEpochDurationSetIterator) 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(BlockStorageEpochDurationSet) + 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(BlockStorageEpochDurationSet) + 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 *BlockStorageEpochDurationSetIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *BlockStorageEpochDurationSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// BlockStorageEpochDurationSet represents a EpochDurationSet event raised by the BlockStorage contract. +type BlockStorageEpochDurationSet struct { + Epoch *big.Int + Duration *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterEpochDurationSet is a free log retrieval operation binding the contract event 0x361d876894ff3854d2e192162a59a0ce8d9e27637af1302a2b8af18e3b007b24. +// +// Solidity: event EpochDurationSet(uint256 indexed epoch, uint256 indexed duration) +func (_BlockStorage *BlockStorageFilterer) FilterEpochDurationSet(opts *bind.FilterOpts, epoch []*big.Int, duration []*big.Int) (*BlockStorageEpochDurationSetIterator, error) { + + var epochRule []interface{} + for _, epochItem := range epoch { + epochRule = append(epochRule, epochItem) + } + var durationRule []interface{} + for _, durationItem := range duration { + durationRule = append(durationRule, durationItem) + } + + logs, sub, err := _BlockStorage.contract.FilterLogs(opts, "EpochDurationSet", epochRule, durationRule) + if err != nil { + return nil, err + } + return &BlockStorageEpochDurationSetIterator{contract: _BlockStorage.contract, event: "EpochDurationSet", logs: logs, sub: sub}, nil +} + +// WatchEpochDurationSet is a free log subscription operation binding the contract event 0x361d876894ff3854d2e192162a59a0ce8d9e27637af1302a2b8af18e3b007b24. +// +// Solidity: event EpochDurationSet(uint256 indexed epoch, uint256 indexed duration) +func (_BlockStorage *BlockStorageFilterer) WatchEpochDurationSet(opts *bind.WatchOpts, sink chan<- *BlockStorageEpochDurationSet, epoch []*big.Int, duration []*big.Int) (event.Subscription, error) { + + var epochRule []interface{} + for _, epochItem := range epoch { + epochRule = append(epochRule, epochItem) + } + var durationRule []interface{} + for _, durationItem := range duration { + durationRule = append(durationRule, durationItem) + } + + logs, sub, err := _BlockStorage.contract.WatchLogs(opts, "EpochDurationSet", epochRule, durationRule) + 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(BlockStorageEpochDurationSet) + if err := _BlockStorage.contract.UnpackLog(event, "EpochDurationSet", 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 +} + +// ParseEpochDurationSet is a log parse operation binding the contract event 0x361d876894ff3854d2e192162a59a0ce8d9e27637af1302a2b8af18e3b007b24. +// +// Solidity: event EpochDurationSet(uint256 indexed epoch, uint256 indexed duration) +func (_BlockStorage *BlockStorageFilterer) ParseEpochDurationSet(log types.Log) (*BlockStorageEpochDurationSet, error) { + event := new(BlockStorageEpochDurationSet) + if err := _BlockStorage.contract.UnpackLog(event, "EpochDurationSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// BlockStorageNewEpochIterator is returned from FilterNewEpoch and is used to iterate over the raw logs and unpacked data for NewEpoch events raised by the BlockStorage contract. +type BlockStorageNewEpochIterator struct { + Event *BlockStorageNewEpoch // 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 *BlockStorageNewEpochIterator) 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(BlockStorageNewEpoch) + 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(BlockStorageNewEpoch) + 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 *BlockStorageNewEpochIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *BlockStorageNewEpochIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// BlockStorageNewEpoch represents a NewEpoch event raised by the BlockStorage contract. +type BlockStorageNewEpoch struct { + Epoch *big.Int + Difficulty *big.Int + Ts *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterNewEpoch is a free log retrieval operation binding the contract event 0x3bb7b347508b7c148ec2094ac60d2e3d8b7595421025643f08b45cb78b326b58. +// +// Solidity: event NewEpoch(uint256 indexed epoch, uint256 difficulty, uint256 ts) +func (_BlockStorage *BlockStorageFilterer) FilterNewEpoch(opts *bind.FilterOpts, epoch []*big.Int) (*BlockStorageNewEpochIterator, error) { + + var epochRule []interface{} + for _, epochItem := range epoch { + epochRule = append(epochRule, epochItem) + } + + logs, sub, err := _BlockStorage.contract.FilterLogs(opts, "NewEpoch", epochRule) + if err != nil { + return nil, err + } + return &BlockStorageNewEpochIterator{contract: _BlockStorage.contract, event: "NewEpoch", logs: logs, sub: sub}, nil +} + +// WatchNewEpoch is a free log subscription operation binding the contract event 0x3bb7b347508b7c148ec2094ac60d2e3d8b7595421025643f08b45cb78b326b58. +// +// Solidity: event NewEpoch(uint256 indexed epoch, uint256 difficulty, uint256 ts) +func (_BlockStorage *BlockStorageFilterer) WatchNewEpoch(opts *bind.WatchOpts, sink chan<- *BlockStorageNewEpoch, epoch []*big.Int) (event.Subscription, error) { + + var epochRule []interface{} + for _, epochItem := range epoch { + epochRule = append(epochRule, epochItem) + } + + logs, sub, err := _BlockStorage.contract.WatchLogs(opts, "NewEpoch", epochRule) + 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(BlockStorageNewEpoch) + if err := _BlockStorage.contract.UnpackLog(event, "NewEpoch", 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 +} + +// ParseNewEpoch is a log parse operation binding the contract event 0x3bb7b347508b7c148ec2094ac60d2e3d8b7595421025643f08b45cb78b326b58. +// +// Solidity: event NewEpoch(uint256 indexed epoch, uint256 difficulty, uint256 ts) +func (_BlockStorage *BlockStorageFilterer) ParseNewEpoch(log types.Log) (*BlockStorageNewEpoch, error) { + event := new(BlockStorageNewEpoch) + if err := _BlockStorage.contract.UnpackLog(event, "NewEpoch", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// BlockStorageNewHashIterator is returned from FilterNewHash and is used to iterate over the raw logs and unpacked data for NewHash events raised by the BlockStorage contract. +type BlockStorageNewHashIterator struct { + Event *BlockStorageNewHash // 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 *BlockStorageNewHashIterator) 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(BlockStorageNewHash) + 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(BlockStorageNewHash) + 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 *BlockStorageNewHashIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *BlockStorageNewHashIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// BlockStorageNewHash represents a NewHash event raised by the BlockStorage contract. +type BlockStorageNewHash struct { + HashId *big.Int + Epoch *big.Int + Account common.Address + Bytes []byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterNewHash is a free log retrieval operation binding the contract event 0x30e5fb28e00aab05ae396f77b088b8627fa5f78c42fbd55fdb593caa2e3f2a2e. +// +// Solidity: event NewHash(uint256 indexed hashId, uint256 indexed epoch, address indexed account, bytes _bytes) +func (_BlockStorage *BlockStorageFilterer) FilterNewHash(opts *bind.FilterOpts, hashId []*big.Int, epoch []*big.Int, account []common.Address) (*BlockStorageNewHashIterator, error) { + + var hashIdRule []interface{} + for _, hashIdItem := range hashId { + hashIdRule = append(hashIdRule, hashIdItem) + } + var epochRule []interface{} + for _, epochItem := range epoch { + epochRule = append(epochRule, epochItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + + logs, sub, err := _BlockStorage.contract.FilterLogs(opts, "NewHash", hashIdRule, epochRule, accountRule) + if err != nil { + return nil, err + } + return &BlockStorageNewHashIterator{contract: _BlockStorage.contract, event: "NewHash", logs: logs, sub: sub}, nil +} + +// WatchNewHash is a free log subscription operation binding the contract event 0x30e5fb28e00aab05ae396f77b088b8627fa5f78c42fbd55fdb593caa2e3f2a2e. +// +// Solidity: event NewHash(uint256 indexed hashId, uint256 indexed epoch, address indexed account, bytes _bytes) +func (_BlockStorage *BlockStorageFilterer) WatchNewHash(opts *bind.WatchOpts, sink chan<- *BlockStorageNewHash, hashId []*big.Int, epoch []*big.Int, account []common.Address) (event.Subscription, error) { + + var hashIdRule []interface{} + for _, hashIdItem := range hashId { + hashIdRule = append(hashIdRule, hashIdItem) + } + var epochRule []interface{} + for _, epochItem := range epoch { + epochRule = append(epochRule, epochItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + + logs, sub, err := _BlockStorage.contract.WatchLogs(opts, "NewHash", hashIdRule, epochRule, accountRule) + 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(BlockStorageNewHash) + if err := _BlockStorage.contract.UnpackLog(event, "NewHash", 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 +} + +// ParseNewHash is a log parse operation binding the contract event 0x30e5fb28e00aab05ae396f77b088b8627fa5f78c42fbd55fdb593caa2e3f2a2e. +// +// Solidity: event NewHash(uint256 indexed hashId, uint256 indexed epoch, address indexed account, bytes _bytes) +func (_BlockStorage *BlockStorageFilterer) ParseNewHash(log types.Log) (*BlockStorageNewHash, error) { + event := new(BlockStorageNewHash) + if err := _BlockStorage.contract.UnpackLog(event, "NewHash", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// BlockStorageOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the BlockStorage contract. +type BlockStorageOwnershipTransferredIterator struct { + Event *BlockStorageOwnershipTransferred // 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 *BlockStorageOwnershipTransferredIterator) 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(BlockStorageOwnershipTransferred) + 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(BlockStorageOwnershipTransferred) + 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 *BlockStorageOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *BlockStorageOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// BlockStorageOwnershipTransferred represents a OwnershipTransferred event raised by the BlockStorage contract. +type BlockStorageOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_BlockStorage *BlockStorageFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*BlockStorageOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _BlockStorage.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &BlockStorageOwnershipTransferredIterator{contract: _BlockStorage.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_BlockStorage *BlockStorageFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BlockStorageOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _BlockStorage.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + 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(BlockStorageOwnershipTransferred) + if err := _BlockStorage.contract.UnpackLog(event, "OwnershipTransferred", 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 +} + +// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_BlockStorage *BlockStorageFilterer) ParseOwnershipTransferred(log types.Log) (*BlockStorageOwnershipTransferred, error) { + event := new(BlockStorageOwnershipTransferred) + if err := _BlockStorage.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// BlockStorageTargetDifficultySetIterator is returned from FilterTargetDifficultySet and is used to iterate over the raw logs and unpacked data for TargetDifficultySet events raised by the BlockStorage contract. +type BlockStorageTargetDifficultySetIterator struct { + Event *BlockStorageTargetDifficultySet // 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 *BlockStorageTargetDifficultySetIterator) 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(BlockStorageTargetDifficultySet) + 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(BlockStorageTargetDifficultySet) + 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 *BlockStorageTargetDifficultySetIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *BlockStorageTargetDifficultySetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// BlockStorageTargetDifficultySet represents a TargetDifficultySet event raised by the BlockStorage contract. +type BlockStorageTargetDifficultySet struct { + Epoch *big.Int + Difficulty *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTargetDifficultySet is a free log retrieval operation binding the contract event 0xa0c1b6fbc0703071b511f72bd3575b2013f2af47bf123f0d84602f476488799c. +// +// Solidity: event TargetDifficultySet(uint256 indexed epoch, uint256 indexed difficulty) +func (_BlockStorage *BlockStorageFilterer) FilterTargetDifficultySet(opts *bind.FilterOpts, epoch []*big.Int, difficulty []*big.Int) (*BlockStorageTargetDifficultySetIterator, error) { + + var epochRule []interface{} + for _, epochItem := range epoch { + epochRule = append(epochRule, epochItem) + } + var difficultyRule []interface{} + for _, difficultyItem := range difficulty { + difficultyRule = append(difficultyRule, difficultyItem) + } + + logs, sub, err := _BlockStorage.contract.FilterLogs(opts, "TargetDifficultySet", epochRule, difficultyRule) + if err != nil { + return nil, err + } + return &BlockStorageTargetDifficultySetIterator{contract: _BlockStorage.contract, event: "TargetDifficultySet", logs: logs, sub: sub}, nil +} + +// WatchTargetDifficultySet is a free log subscription operation binding the contract event 0xa0c1b6fbc0703071b511f72bd3575b2013f2af47bf123f0d84602f476488799c. +// +// Solidity: event TargetDifficultySet(uint256 indexed epoch, uint256 indexed difficulty) +func (_BlockStorage *BlockStorageFilterer) WatchTargetDifficultySet(opts *bind.WatchOpts, sink chan<- *BlockStorageTargetDifficultySet, epoch []*big.Int, difficulty []*big.Int) (event.Subscription, error) { + + var epochRule []interface{} + for _, epochItem := range epoch { + epochRule = append(epochRule, epochItem) + } + var difficultyRule []interface{} + for _, difficultyItem := range difficulty { + difficultyRule = append(difficultyRule, difficultyItem) + } + + logs, sub, err := _BlockStorage.contract.WatchLogs(opts, "TargetDifficultySet", epochRule, difficultyRule) + 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(BlockStorageTargetDifficultySet) + if err := _BlockStorage.contract.UnpackLog(event, "TargetDifficultySet", 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 +} + +// ParseTargetDifficultySet is a log parse operation binding the contract event 0xa0c1b6fbc0703071b511f72bd3575b2013f2af47bf123f0d84602f476488799c. +// +// Solidity: event TargetDifficultySet(uint256 indexed epoch, uint256 indexed difficulty) +func (_BlockStorage *BlockStorageFilterer) ParseTargetDifficultySet(log types.Log) (*BlockStorageTargetDifficultySet, error) { + event := new(BlockStorageTargetDifficultySet) + if err := _BlockStorage.contract.UnpackLog(event, "TargetDifficultySet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go new file mode 100644 index 000000000..230dc3305 --- /dev/null +++ b/integration/xenblocks/verifier/verifier.go @@ -0,0 +1,160 @@ +package verifier + +import ( + "encoding/base64" + "encoding/hex" + "errors" + "fmt" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/tvdburgt/go-argon2" + "math/big" + "os" + "regexp" + "strings" + "time" +) + +var ( + hashId []*big.Int + epoch []*big.Int + account []common.Address + + ctx = &argon2.Context{ + HashLen: 64, + Mode: argon2.ModeArgon2id, + Version: argon2.Version13, + } +) + +func Worker(cfg node.Config) { + log.Info("Starting Block storage watcher") + + // check if file exists + time.Sleep(10 * time.Second) + ipcPath := fmt.Sprintf("%s/%s", cfg.DataDir, cfg.IPCPath) + + for { + if _, err := os.Stat(ipcPath); errors.Is(err, os.ErrNotExist) { + log.Warn("IPC file not found, waiting 10 seconds") + time.Sleep(10 * time.Second) + } else { + break + } + } + + conn, err := ethclient.Dial(ipcPath) + if err != nil { + panic(err) + } + + bs, err := block_storage.NewBlockStorage(common.HexToAddress("0x23213196F7d13153a906c456f5a1008E23EA94bA"), conn) + if err != nil { + panic(err) + } + + channel := make(chan *block_storage.BlockStorageNewHash, 5) + + // Start a goroutine which watches new events + go func() { + sub, err := bs.WatchNewHash(nil, channel, hashId, epoch, account) + if err != nil { + panic(err) + } + + for { + select { + case err := <-sub.Err(): + panic(err) + case t := <-channel: + log.Trace("NewHash event received", "hashId", t.HashId, "epoch", t.Epoch, "account", t.Account) + dr, err := bs.DecodeRecordBytes0(nil, t.HashId) + if err != nil { + return + } + + ctx.Parallelism = int(dr.C) + ctx.Memory = int(dr.M) + ctx.Iterations = int(dr.T) + hashToVerify, err := argon2.HashEncoded(ctx, dr.K[:], dr.S) + if err != nil { + panic(err) + } + + if validateHash(hashToVerify) { + log.Info("Hash verified", "hash", hashToVerify) + } else { + log.Warn("Hash verification failed", "hash", hashToVerify) + } + + // then I can call a vote function + + default: + log.Warn("Channel is full") + } + } + } + }() +} + +func restoreEIP55Address(addr string) bool { + re := regexp.MustCompile("^(0x|)[0-9a-fA-F]{40}$") + return re.MatchString(addr) +} + +func extractSaltFromHash(hashToVerify string) string { + parts := strings.Split(hashToVerify, "$") + if len(parts) != 6 { + log.Warn("less than 6 parts") + return "" + } + return parts[4] +} + +func validatePattern1(salt string) bool { + return salt == "WEVOMTAwODIwMjJYRU4" +} + +func validatePattern2(salt string) bool { + r := regexp.MustCompile(`^[A-Za-z0-9+/]{27}$`) + + if !r.MatchString(salt) { + log.Warn("pattern 2 match failed") + return false + } + + missingPadding := len(salt) % 4 + if missingPadding != 0 { + salt += strings.Repeat("=", 4-missingPadding) + } + + rawDecodedText, err := base64.StdEncoding.DecodeString(salt) + if err != nil { + log.Warn("base64 decode error", "err", err, "salt", salt) + return false + } + + decodedStr := hex.EncodeToString(rawDecodedText) + if !restoreEIP55Address(decodedStr) { + log.Warn("decoded string is not a valid hash", "decodedStr", decodedStr) + return false + } + + return true +} + +func validateHash(hash string) bool { + salt := extractSaltFromHash(hash) + if salt == "" { + return false + } + + if validatePattern1(salt) { + return true + } + + return validatePattern2(salt) +} From 9f0a5cb6b328cdd3815628c8b6385be6f70814b3 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 6 Dec 2023 12:55:37 -0800 Subject: [PATCH 02/34] WIP --- cmd/opera/launcher/launcher.go | 3 +- integration/xenblocks/verifier/utils.go | 71 +++++++ integration/xenblocks/verifier/verifier.go | 213 ++++++++++++--------- 3 files changed, 197 insertions(+), 90 deletions(-) create mode 100644 integration/xenblocks/verifier/utils.go diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index 8023a106f..37088f0ed 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -352,8 +352,9 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( signer := valkeystore.NewSigner(valKeystore) // Config the XenBlocks verifier + xenblocksVerifier := verifier.NewVerifier(cfg.Node, cfg.Emitter.Validator.ID) if cfg.XenBlocks.Verifier { - go verifier.Worker(cfg.Node) + go xenblocksVerifier.Start() } // Config the XenBlocks reporter diff --git a/integration/xenblocks/verifier/utils.go b/integration/xenblocks/verifier/utils.go new file mode 100644 index 000000000..f43b47c7d --- /dev/null +++ b/integration/xenblocks/verifier/utils.go @@ -0,0 +1,71 @@ +package verifier + +import ( + "encoding/base64" + "encoding/hex" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "regexp" + "strings" +) + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func extractSaltFromHash(hashToVerify string) string { + parts := strings.Split(hashToVerify, "$") + if len(parts) != 6 { + log.Warn("less than 6 parts") + return "" + } + return parts[4] +} + +func validatePattern1(salt string) bool { + return salt == pattern1Salt +} + +func validatePattern2(salt string) bool { + r := regexp.MustCompile(`^[A-Za-z0-9+/]{27}$`) + + if !r.MatchString(salt) { + log.Warn("pattern 2 match failed") + return false + } + + missingPadding := len(salt) % 4 + if missingPadding != 0 { + salt += strings.Repeat("=", 4-missingPadding) + } + + rawDecodedText, err := base64.StdEncoding.DecodeString(salt) + if err != nil { + log.Warn("base64 decode error", "err", err, "salt", salt) + return false + } + + decodedStr := hex.EncodeToString(rawDecodedText) + if !common.IsHexAddress(decodedStr) { + log.Warn("decoded string is not a valid hash", "decodedStr", decodedStr) + return false + } + + return true +} + +func validateHash(hash string) bool { + salt := extractSaltFromHash(hash) + if salt == "" { + return false + } + + if validatePattern1(salt) { + return true + } + + return validatePattern2(salt) +} diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 230dc3305..4d425903d 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -1,44 +1,67 @@ package verifier import ( - "encoding/base64" - "encoding/hex" + "crypto/sha256" + "encoding/binary" "errors" "fmt" + "github.com/Fantom-foundation/go-opera/gossip/contract/sfc100" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" + "github.com/Fantom-foundation/go-opera/opera/contracts/sfc" + "github.com/Fantom-foundation/lachesis-base/inter/idx" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/tvdburgt/go-argon2" + "math" "math/big" "os" - "regexp" - "strings" "time" ) var ( - hashId []*big.Int - epoch []*big.Int - account []common.Address - - ctx = &argon2.Context{ - HashLen: 64, - Mode: argon2.ModeArgon2id, - Version: argon2.Version13, - } + numOfWorkers = 3 + backlog = 5 + hashLen = 64 + validatorsFactor = 0.2 + pattern1Salt = "WEVOMTAwODIwMjJYRU4" + blockStorageAddr = "0x23213196F7d13153a906c456f5a1008E23EA94bA" ) -func Worker(cfg node.Config) { - log.Info("Starting Block storage watcher") +type Verifier struct { + enabled bool + numOfWorkers int + backlog int + ipcPath string + validatorId uint32 + bs *block_storage.BlockStorage + sfc *sfc100.ContractCaller + eventChannel chan *block_storage.BlockStorageNewHash + conn *ethclient.Client + sub event.Subscription +} - // check if file exists - time.Sleep(10 * time.Second) - ipcPath := fmt.Sprintf("%s/%s", cfg.DataDir, cfg.IPCPath) +func NewVerifier(nodeCfg node.Config, validatorId idx.ValidatorID) *Verifier { + ipcPath := fmt.Sprintf("%s/%s", nodeCfg.DataDir, nodeCfg.IPCPath) + return &Verifier{ + enabled: false, + ipcPath: ipcPath, + numOfWorkers: numOfWorkers, + backlog: backlog, + validatorId: uint32(validatorId), + } +} + +func (x *Verifier) Start() { + log.Info("Starting Block storage watcher") + time.Sleep(5 * time.Second) + x.enabled = true for { - if _, err := os.Stat(ipcPath); errors.Is(err, os.ErrNotExist) { + if _, err := os.Stat(x.ipcPath); errors.Is(err, os.ErrNotExist) { log.Warn("IPC file not found, waiting 10 seconds") time.Sleep(10 * time.Second) } else { @@ -46,115 +69,127 @@ func Worker(cfg node.Config) { } } - conn, err := ethclient.Dial(ipcPath) + var err error + x.conn, err = ethclient.Dial(x.ipcPath) + if err != nil { + panic(err) + } + + x.bs, err = block_storage.NewBlockStorage(common.HexToAddress(blockStorageAddr), x.conn) if err != nil { panic(err) } - bs, err := block_storage.NewBlockStorage(common.HexToAddress("0x23213196F7d13153a906c456f5a1008E23EA94bA"), conn) + x.sfc, err = sfc100.NewContractCaller(sfc.ContractAddress, x.conn) if err != nil { panic(err) } - channel := make(chan *block_storage.BlockStorageNewHash, 5) + x.eventChannel = make(chan *block_storage.BlockStorageNewHash, backlog) + for w := 1; w <= numOfWorkers; w++ { + go x.worker(x.eventChannel) + } // Start a goroutine which watches new events go func() { - sub, err := bs.WatchNewHash(nil, channel, hashId, epoch, account) + x.sub, err = x.bs.WatchNewHash(nil, x.eventChannel, nil, nil, nil) if err != nil { panic(err) } for { select { - case err := <-sub.Err(): - panic(err) - case t := <-channel: - log.Trace("NewHash event received", "hashId", t.HashId, "epoch", t.Epoch, "account", t.Account) - dr, err := bs.DecodeRecordBytes0(nil, t.HashId) - if err != nil { - return - } - - ctx.Parallelism = int(dr.C) - ctx.Memory = int(dr.M) - ctx.Iterations = int(dr.T) - hashToVerify, err := argon2.HashEncoded(ctx, dr.K[:], dr.S) - if err != nil { - panic(err) - } - - if validateHash(hashToVerify) { - log.Info("Hash verified", "hash", hashToVerify) - } else { - log.Warn("Hash verification failed", "hash", hashToVerify) - } - - // then I can call a vote function - - default: - log.Warn("Channel is full") - } + case err := <-x.sub.Err(): + log.Error("Error in BlockStorage watcher", "err", err) + break } + time.Sleep(time.Second) } }() } -func restoreEIP55Address(addr string) bool { - re := regexp.MustCompile("^(0x|)[0-9a-fA-F]{40}$") - return re.MatchString(addr) -} - -func extractSaltFromHash(hashToVerify string) string { - parts := strings.Split(hashToVerify, "$") - if len(parts) != 6 { - log.Warn("less than 6 parts") - return "" +func (x *Verifier) worker(events <-chan *block_storage.BlockStorageNewHash) { + for e := range events { + x.handleEvent(e) } - return parts[4] } -func validatePattern1(salt string) bool { - return salt == "WEVOMTAwODIwMjJYRU4" -} - -func validatePattern2(salt string) bool { - r := regexp.MustCompile(`^[A-Za-z0-9+/]{27}$`) +func (x *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { + log.Debug("NewHash event received", "hashId", event.HashId, "epoch", event.Epoch, "account", event.Account) - if !r.MatchString(salt) { - log.Warn("pattern 2 match failed") - return false + if !x.shouldVote(event.Raw.BlockNumber) { + log.Debug("Not voting for this hash", "hash", event.Raw.BlockHash) + return } - missingPadding := len(salt) % 4 - if missingPadding != 0 { - salt += strings.Repeat("=", 4-missingPadding) + dr, err := x.bs.DecodeRecordBytes0(nil, event.HashId) + if err != nil { + return } - rawDecodedText, err := base64.StdEncoding.DecodeString(salt) + hashToVerify, err := argon2Hash(dr.C, dr.M, dr.T, dr.S, dr.K) if err != nil { - log.Warn("base64 decode error", "err", err, "salt", salt) - return false + panic(err) } - decodedStr := hex.EncodeToString(rawDecodedText) - if !restoreEIP55Address(decodedStr) { - log.Warn("decoded string is not a valid hash", "decodedStr", decodedStr) - return false + if validateHash(hashToVerify) { + log.Info("Hash verified", "hash", hashToVerify) + } else { + log.Warn("Hash verification failed", "hash", hashToVerify) } - return true + // TODO: parse XNM, XUNI or XNM+X.BLK + // TODO: vote for each hash } -func validateHash(hash string) bool { - salt := extractSaltFromHash(hash) - if salt == "" { - return false +func argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, key [32]byte) (string, error) { + ctx := &argon2.Context{ + Iterations: int(iterations), + Memory: int(memory), + Parallelism: int(parallelism), + HashLen: hashLen, + Mode: argon2.ModeArgon2i, + Version: argon2.Version13, + } + + return argon2.HashEncoded(ctx, key[:], salt) +} + +func (x *Verifier) getValidatorCount(blockNumber uint64) (uint64, error) { + bn := new(big.Int).SetUint64(blockNumber) + id, err := x.sfc.LastValidatorID(&bind.CallOpts{BlockNumber: bn}) + if err != nil { + return 0, err } + return id.Uint64(), nil +} - if validatePattern1(salt) { - return true +func (x *Verifier) shouldVote(blockNumber uint64) bool { + validatorsCount, err := x.getValidatorCount(blockNumber) + if err != nil { + log.Error("Error getting validator count", "err", err) + return false } - return validatePattern2(salt) + seed := sha256.Sum256([]byte(fmt.Sprintf("%d-%d", blockNumber, x.validatorId))) + randomState := binary.LittleEndian.Uint64(seed[:]) % validatorsCount + + // Calculate the number of validators to vote (percentage of validators) + numVotingValidators := max(1, int(math.Round(validatorsFactor*float64(validatorsCount)))) + + // Calculate the position of the validator within the selected validators + positionInSelectedValidators := randomState % uint64(numVotingValidators) + + // Check if the given validator index matches the calculated position + return positionInSelectedValidators == uint64(x.validatorId)%uint64(numVotingValidators) +} + +func (x *Verifier) Close() { + if x.enabled { + log.Info("Closing Block storage watcher") + x.sub.Unsubscribe() + time.Sleep(time.Second) + close(x.eventChannel) + x.conn.Close() + } } From b50010936a23f55a632546c65db6257b39b21b6b Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 6 Dec 2023 13:19:17 -0800 Subject: [PATCH 03/34] create new context on each hash for thread safey --- integration/xenblocks/verifier/verifier.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 4d425903d..c1bc2ea84 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -143,15 +143,14 @@ func (x *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { } func argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, key [32]byte) (string, error) { - ctx := &argon2.Context{ - Iterations: int(iterations), - Memory: int(memory), - Parallelism: int(parallelism), - HashLen: hashLen, - Mode: argon2.ModeArgon2i, - Version: argon2.Version13, - } - + ctx := argon2.NewContext() + ctx.Iterations = int(iterations) + ctx.Memory = int(memory) + ctx.Parallelism = int(parallelism) + ctx.HashLen = hashLen + ctx.Mode = argon2.ModeArgon2i + ctx.Version = argon2.Version13 + return argon2.HashEncoded(ctx, key[:], salt) } From 2efbe8a70063a7992104ffa2d76015feabba935e Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 6 Dec 2023 14:34:10 -0800 Subject: [PATCH 04/34] add validator readme --- README.md | 106 ++++++ sfc.abi.json | 923 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1029 insertions(+) create mode 100644 sfc.abi.json diff --git a/README.md b/README.md index c911793f4..61f2ccca1 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ RPC Endpoints apt update -y apt install -y golang wget git make +# Install Libargon2 (required to run a validator node) +apt install -y libargon2-dev + # Clone and build the X1 binary git clone --branch x1 https://github.com/FairCrypto/go-x1 cd go-x1 @@ -46,3 +49,106 @@ x1 --testnet --http --http.port 8545 --ws --ws.port 8546 ```shell x1 --testnet --http --http.port 8545 --http.addr 0.0.0.0 --http.vhosts "*" --http.corsdomain "*" --ws --ws.addr 0.0.0.0 --ws.port 8546 --ws.origins "*" ``` + +## Running Validator Node (Testnet) + +> [!CAUTION] +> Running a validator node is a complex process and requires a lot of technical knowledge. + +Run a full node as described above and allow to fully sync, then follow the instructions below to run a validator node. + +> Install libargon2 (required to run a validator node) +```shell +# ubuntu/debian +apt install -y libargon2 + +# MacOS +brew install argon2 + +# Redhat based distros +yum install -y libargon2 +``` + +### Create a validator wallet + +The node running and syncing the network in your current console, so you need to open up a new console window, +connect via SSH to the server and enter the following commands to create a wallet: + +```shell +# Create validator wallet +(validator)$ x1 account new +``` + +After entering the command, you will get prompted to enter a password for the account (= wallet) — use a strong one! +You can e.g. use a password manager to generate a 20+ digit password to secure your wallet. + +### Fund your validator wallet +The next step is to fund your validator wallet with enough XN to become a validator. +That means you need to have at least 500,000 XN in the wallet you just created (send a little more to cover transaction fees). + +### Create a new validator key + +We have to create validator private key to sign consensus messages with. It can be done only using go-x1 tool. + +```shell +# Create validator key +(validator)$ x1 validator new +``` + +### Create your validator via the SFC contract + +Now we need to register our validator in the SFC contract. + +```shell +# Attach to x1 console +(validator)$ x1 attach +``` +Now initialize the SFC contract ABI variable [sfc.abi.json](sfc.abi.json): + +```shell +abi = JSON.parse('[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"status","type":"uint256"}],"name":"ChangedValidatorStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockupExtraReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockupBaseReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unlockedReward","type":"uint256"}],"name":"ClaimedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":true,"internalType":"address","name":"auth","type":"address"},{"indexed":false,"internalType":"uint256","name":"createdEpoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"createdTime","type":"uint256"}],"name":"CreatedValidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deactivatedEpoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deactivatedTime","type":"uint256"}],"name":"DeactivatedValidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Delegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LockedUpStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockupExtraReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockupBaseReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unlockedReward","type":"uint256"}],"name":"RestakedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wrID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Undelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penalty","type":"uint256"}],"name":"UnlockedStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"UpdatedBaseRewardPerSec","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"blocksNum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"period","type":"uint256"}],"name":"UpdatedOfflinePenaltyThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refundRatio","type":"uint256"}],"name":"UpdatedSlashingRefundRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wrID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"constant":true,"inputs":[],"name":"baseRewardPerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contractCommission","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"currentSealedEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getEpochSnapshot","outputs":[{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"epochFee","type":"uint256"},{"internalType":"uint256","name":"totalBaseRewardWeight","type":"uint256"},{"internalType":"uint256","name":"totalTxRewardWeight","type":"uint256"},{"internalType":"uint256","name":"baseRewardPerSecond","type":"uint256"},{"internalType":"uint256","name":"totalStake","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getLockupInfo","outputs":[{"internalType":"uint256","name":"lockedStake","type":"uint256"},{"internalType":"uint256","name":"fromEpoch","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getStashedLockupRewards","outputs":[{"internalType":"uint256","name":"lockupExtraReward","type":"uint256"},{"internalType":"uint256","name":"lockupBaseReward","type":"uint256"},{"internalType":"uint256","name":"unlockedReward","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getValidator","outputs":[{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"uint256","name":"deactivatedTime","type":"uint256"},{"internalType":"uint256","name":"deactivatedEpoch","type":"uint256"},{"internalType":"uint256","name":"receivedStake","type":"uint256"},{"internalType":"uint256","name":"createdEpoch","type":"uint256"},{"internalType":"uint256","name":"createdTime","type":"uint256"},{"internalType":"address","name":"auth","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getValidatorID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getValidatorPubkey","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getWithdrawalRequest","outputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastValidatorID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxDelegatedRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"maxLockupDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"minLockupDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"minSelfStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"slashingRefundRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"stakeTokenizerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stashedRewardsUntilEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalActiveStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSlashedStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"unlockedRewardRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"validatorCommission","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"internalType":"bytes3","name":"","type":"bytes3"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"withdrawalPeriodEpochs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"withdrawalPeriodTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"currentEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getEpochValidatorIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochReceivedStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochAccumulatedRewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochAccumulatedUptime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochAccumulatedOriginatedTxsFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochOfflineTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochOfflineBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"rewardsStash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"getLockedStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"sealedEpoch","type":"uint256"},{"internalType":"uint256","name":"_totalSupply","type":"uint256"},{"internalType":"address","name":"nodeDriver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"auth","type":"address"},{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"uint256","name":"createdEpoch","type":"uint256"},{"internalType":"uint256","name":"createdTime","type":"uint256"},{"internalType":"uint256","name":"deactivatedEpoch","type":"uint256"},{"internalType":"uint256","name":"deactivatedTime","type":"uint256"}],"name":"setGenesisValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"stake","type":"uint256"},{"internalType":"uint256","name":"lockedStake","type":"uint256"},{"internalType":"uint256","name":"lockupFromEpoch","type":"uint256"},{"internalType":"uint256","name":"lockupEndTime","type":"uint256"},{"internalType":"uint256","name":"lockupDuration","type":"uint256"},{"internalType":"uint256","name":"earlyUnlockPenalty","type":"uint256"},{"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"setGenesisDelegation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"pubkey","type":"bytes"}],"name":"createValidator","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getSelfStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"delegate","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"wrID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"undelegate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"isSlashed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"wrID","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"uint256","name":"status","type":"uint256"}],"name":"deactivateValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"stashRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"claimRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"restakeRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"bool","name":"syncPubkey","type":"bool"}],"name":"_syncValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"offlinePenaltyThreshold","outputs":[{"internalType":"uint256","name":"blocksNum","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"updateBaseRewardPerSecond","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"blocksNum","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"}],"name":"updateOfflinePenaltyThreshold","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"uint256","name":"refundRatio","type":"uint256"}],"name":"updateSlashingRefundRatio","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"updateStakeTokenizerAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256[]","name":"offlineTime","type":"uint256[]"},{"internalType":"uint256[]","name":"offlineBlocks","type":"uint256[]"},{"internalType":"uint256[]","name":"uptimes","type":"uint256[]"},{"internalType":"uint256[]","name":"originatedTxsFee","type":"uint256[]"}],"name":"sealEpoch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256[]","name":"nextValidatorIDs","type":"uint256[]"}],"name":"sealEpochValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"isLockedUp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"getUnlockedStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"lockupDuration","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"lockStake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"lockupDuration","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"relockStake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unlockStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]') +``` + +… as well as the SFC contract object itself: +```shell +sfcc = web3.ftm.contract(abi).at("0xfc00face00000000000000000000000000000000") +``` + +Next, unlock your validator wallet to be able to execute the registration transaction (make sure to use the password you set before). + +```shell +# Unlock validator wallet +personal.unlockAccount("{VALIDATOR_WALLET_ADDRESS}", "{PASSWORD}", 60) +``` + +Next, send the createValidator transaction to register your validator. Use quotes for "0xYOUR_PUBKEY" and "0xYOUR_ADDRESS": + +```shell +# Register your validator +tx = sfcc.createValidator("0xYOUR_PUBKEY", {from:"0xYOUR_ADDRESS", value: web3.toWei("500000.0", "xn")}) +``` + +```shell +# Check your registration transaction +ftm.getTransactionReceipt(tx) +``` + +Look for the status: “0x1" at the bottom, which means the transaction was successful. + +Finally, execute the following command again to check your validatorID: + +```shell +# Get your validator id +sfc.getValidatorID("{VALIDATOR_WALLET_ADDRESS}") +``` + +### Run your X1 validator node + +Now that you have registered your validator, you can restart your node with the following command: + +```shell +(validator)$ x1 --testnet \ + --validator.id ID --validator.pubkey 0xPubkey --validator.password /path/to/password_file +``` + +Congratulations, you are now running a X1 validator node! diff --git a/sfc.abi.json b/sfc.abi.json new file mode 100644 index 000000000..1e7834928 --- /dev/null +++ b/sfc.abi.json @@ -0,0 +1,923 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "validatorID", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "status", + "type": "uint256" + } + ], + "name": "ChangedValidatorStatus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "validatorID", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "deactivatedEpoch", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "deactivatedTime", + "type": "uint256" + } + ], + "name": "DeactivatedValidator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "UpdatedBaseRewardPerSec", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "blocksNum", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "period", + "type": "uint256" + } + ], + "name": "UpdatedOfflinePenaltyThreshold", + "type": "event" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "validatorID", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "syncPubkey", + "type": "bool" + } + ], + "name": "_syncValidator", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "currentEpoch", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "currentSealedEpoch", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getEpochSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "epochFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalBaseRewardWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalTxRewardWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "baseRewardPerSecond", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalStake", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "delegator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "toValidatorID", + "type": "uint256" + } + ], + "name": "getLockedStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getLockupInfo", + "outputs": [ + { + "internalType": "uint256", + "name": "lockedStake", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "fromEpoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getStashedLockupRewards", + "outputs": [ + { + "internalType": "uint256", + "name": "lockupExtraReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lockupBaseReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unlockedReward", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getValidator", + "outputs": [ + { + "internalType": "uint256", + "name": "status", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deactivatedTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deactivatedEpoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "receivedStake", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "createdEpoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "createdTime", + "type": "uint256" + }, + { + "internalType": "address", + "name": "auth", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "getValidatorID", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getValidatorPubkey", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getWithdrawalRequest", + "outputs": [ + { + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "time", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "delegator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "toValidatorID", + "type": "uint256" + } + ], + "name": "isLockedUp", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isOwner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lastValidatorID", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minGasPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "slashingRefundRatio", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "stakeTokenizerAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "stashedRewardsUntilEpoch", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalActiveStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSlashedStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "treasuryAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "bytes3", + "name": "", + "type": "bytes3" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "voteBookAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "sealedEpoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_totalSupply", + "type": "uint256" + }, + { + "internalType": "address", + "name": "nodeDriver", + "type": "address" + }, + { + "internalType": "address", + "name": "lib", + "type": "address" + }, + { + "internalType": "address", + "name": "_c", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "updateStakeTokenizerAddress", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "v", + "type": "address" + } + ], + "name": "updateLibAddress", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "v", + "type": "address" + } + ], + "name": "updateTreasuryAddress", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "v", + "type": "address" + } + ], + "name": "updateConstsAddress", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "constsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "v", + "type": "address" + } + ], + "name": "updateVoteBookAddress", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256[]", + "name": "offlineTime", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "offlineBlocks", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "uptimes", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "originatedTxsFee", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "epochGas", + "type": "uint256" + } + ], + "name": "sealEpoch", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256[]", + "name": "nextValidatorIDs", + "type": "uint256[]" + } + ], + "name": "sealEpochValidators", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] From 8a5653ef9febd0be26e6fff7d8190ccd0282804e Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 6 Dec 2023 14:44:46 -0800 Subject: [PATCH 05/34] update the github action to install argon2 --- .github/workflows/release_build.yml | 4 ++-- .github/workflows/test_build.yml | 14 ++++++++++---- README.md | 5 +++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release_build.yml b/.github/workflows/release_build.yml index d3b97e1d2..04820649e 100644 --- a/.github/workflows/release_build.yml +++ b/.github/workflows/release_build.yml @@ -21,10 +21,10 @@ jobs: run: go test -v ./... - name: Build - run: make opera + run: make x1 - name: Release uses: ncipollo/release-action@v1 with: - artifacts: "./build/opera" + artifacts: "./build/x1" token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test_build.yml b/.github/workflows/test_build.yml index 56e9204ac..2ad22e25b 100644 --- a/.github/workflows/test_build.yml +++ b/.github/workflows/test_build.yml @@ -1,9 +1,9 @@ name: Check build -on: +on: push: pull_request: - branches: + branches: - develop - master @@ -14,6 +14,12 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - name: update apt + run: apt update + + - name: Install argon2 + run: apt install -y argon2 + - name: Golang dependency uses: actions/setup-go@v3 with: @@ -23,10 +29,10 @@ jobs: run: go test -v ./... - name: Build - run: make opera + run: make x1 - name: Publish uses: actions/upload-artifact@v2 with: name: opera - path: ./build/opera + path: ./build/x1 diff --git a/README.md b/README.md index 61f2ccca1..398e44afd 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ apt update -y apt install -y golang wget git make # Install Libargon2 (required to run a validator node) -apt install -y libargon2-dev +apt install -y argon2 # Clone and build the X1 binary git clone --branch x1 https://github.com/FairCrypto/go-x1 @@ -60,12 +60,13 @@ Run a full node as described above and allow to fully sync, then follow the inst > Install libargon2 (required to run a validator node) ```shell # ubuntu/debian -apt install -y libargon2 +apt install -y argon2 # MacOS brew install argon2 # Redhat based distros +yum install -y epel-release yum install -y libargon2 ``` From af31ecddd2642acb22b6d6376d30d9ce138e7fa0 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 6 Dec 2023 14:45:36 -0800 Subject: [PATCH 06/34] update the github action to install argon2 --- .github/workflows/release_build.yml | 6 ++++++ .github/workflows/test_build.yml | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release_build.yml b/.github/workflows/release_build.yml index 04820649e..91bdc1b5c 100644 --- a/.github/workflows/release_build.yml +++ b/.github/workflows/release_build.yml @@ -12,6 +12,12 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - name: update apt + run: sudo apt update + + - name: Install argon2 + run: sudo apt install -y argon2 + - name: Golang dependency uses: actions/setup-go@v3 with: diff --git a/.github/workflows/test_build.yml b/.github/workflows/test_build.yml index 2ad22e25b..d00b7d1f6 100644 --- a/.github/workflows/test_build.yml +++ b/.github/workflows/test_build.yml @@ -15,10 +15,10 @@ jobs: uses: actions/checkout@v3 - name: update apt - run: apt update + run: sudo apt update - name: Install argon2 - run: apt install -y argon2 + run: sudo apt install -y argon2 - name: Golang dependency uses: actions/setup-go@v3 From f69395e5624d0e54a5fb36d6f766b458062afa4f Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 6 Dec 2023 14:48:24 -0800 Subject: [PATCH 07/34] update the github action to install libargon2-dev --- .github/workflows/release_build.yml | 2 +- .github/workflows/test_build.yml | 2 +- README.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release_build.yml b/.github/workflows/release_build.yml index 91bdc1b5c..b688e89e2 100644 --- a/.github/workflows/release_build.yml +++ b/.github/workflows/release_build.yml @@ -16,7 +16,7 @@ jobs: run: sudo apt update - name: Install argon2 - run: sudo apt install -y argon2 + run: sudo apt install -y libargon2-dev - name: Golang dependency uses: actions/setup-go@v3 diff --git a/.github/workflows/test_build.yml b/.github/workflows/test_build.yml index d00b7d1f6..bb9b958cb 100644 --- a/.github/workflows/test_build.yml +++ b/.github/workflows/test_build.yml @@ -18,7 +18,7 @@ jobs: run: sudo apt update - name: Install argon2 - run: sudo apt install -y argon2 + run: sudo apt install -y libargon2-dev - name: Golang dependency uses: actions/setup-go@v3 diff --git a/README.md b/README.md index 398e44afd..4cb561004 100644 --- a/README.md +++ b/README.md @@ -60,14 +60,14 @@ Run a full node as described above and allow to fully sync, then follow the inst > Install libargon2 (required to run a validator node) ```shell # ubuntu/debian -apt install -y argon2 +apt install -y libargon2-dev # MacOS brew install argon2 # Redhat based distros yum install -y epel-release -yum install -y libargon2 +yum install -y libargon2-devel ``` ### Create a validator wallet From 1c973842ae48e55f6fabe92a6b2abd34d9f05f20 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 6 Dec 2023 16:21:35 -0800 Subject: [PATCH 08/34] add validator count cache, fix shouldvote --- cmd/opera/launcher/config.go | 2 +- cmd/opera/launcher/launcher.go | 2 +- cmd/opera/launcher/xenblocks.go | 4 +- integration/xenblocks/reporter/xenblocks.go | 12 ++--- integration/xenblocks/verifier/verifier.go | 57 ++++++++++++++------- 5 files changed, 48 insertions(+), 29 deletions(-) diff --git a/cmd/opera/launcher/config.go b/cmd/opera/launcher/config.go index cfe3305d6..aeb665040 100644 --- a/cmd/opera/launcher/config.go +++ b/cmd/opera/launcher/config.go @@ -527,7 +527,7 @@ func mayMakeAllConfigs(ctx *cli.Context) (*config, error) { cfg.XenBlocks.Endpoint = endpoint } - cfg.XenBlocks.Verifier = ctx.GlobalIsSet(XenBlocksVerifierEnabledFlag.Name) + cfg.XenBlocks.ForceVerifier = ctx.GlobalIsSet(XenBlocksVerifierEnabledFlag.Name) // Load config file (medium priority) if file := ctx.GlobalString(configFileFlag.Name); file != "" { diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index 37088f0ed..436df90c1 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -353,7 +353,7 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( // Config the XenBlocks verifier xenblocksVerifier := verifier.NewVerifier(cfg.Node, cfg.Emitter.Validator.ID) - if cfg.XenBlocks.Verifier { + if cfg.Emitter.Validator.ID != 0 || cfg.XenBlocks.ForceVerifier { go xenblocksVerifier.Start() } diff --git a/cmd/opera/launcher/xenblocks.go b/cmd/opera/launcher/xenblocks.go index dfa260834..61c82d2bd 100644 --- a/cmd/opera/launcher/xenblocks.go +++ b/cmd/opera/launcher/xenblocks.go @@ -12,8 +12,8 @@ var XenBlocksEndpointFlag = cli.StringFlag{ } var XenBlocksVerifierEnabledFlag = cli.BoolFlag{ - Name: "xenblocks-verifier-enabled", - Usage: "Enables the Xenblocks verifier.", + Name: "xenblocks-force-verifier", + Usage: "Force enable the Xenblocks verifier even if not a validator.", } func parseXenBlocksEndpoint(s string) (url string, err error) { diff --git a/integration/xenblocks/reporter/xenblocks.go b/integration/xenblocks/reporter/xenblocks.go index 5ba990743..e4357b86c 100644 --- a/integration/xenblocks/reporter/xenblocks.go +++ b/integration/xenblocks/reporter/xenblocks.go @@ -10,9 +10,9 @@ import ( ) type Config struct { - Endpoint string - Enabled bool - Verifier bool + Endpoint string + Enabled bool + ForceVerifier bool } type Reporter struct { @@ -25,9 +25,9 @@ type Reporter struct { func DefaultConfig() Config { return Config{ - Endpoint: "", - Enabled: false, - Verifier: false, + Endpoint: "", + Enabled: false, + ForceVerifier: false, } } diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index c1bc2ea84..a1d86e46d 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -5,7 +5,7 @@ import ( "encoding/binary" "errors" "fmt" - "github.com/Fantom-foundation/go-opera/gossip/contract/sfc100" + "github.com/Fantom-foundation/go-opera/gossip/contract/sfclib100" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" "github.com/Fantom-foundation/go-opera/opera/contracts/sfc" "github.com/Fantom-foundation/lachesis-base/inter/idx" @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" + "github.com/hashicorp/golang-lru" "github.com/tvdburgt/go-argon2" "math" "math/big" @@ -32,16 +33,17 @@ var ( ) type Verifier struct { - enabled bool - numOfWorkers int - backlog int - ipcPath string - validatorId uint32 - bs *block_storage.BlockStorage - sfc *sfc100.ContractCaller - eventChannel chan *block_storage.BlockStorageNewHash - conn *ethclient.Client - sub event.Subscription + enabled bool + numOfWorkers int + backlog int + ipcPath string + validatorId uint32 + bs *block_storage.BlockStorage + sfcLib *sfclib100.ContractCaller + eventChannel chan *block_storage.BlockStorageNewHash + conn *ethclient.Client + sub event.Subscription + validatorCountLRU *lru.Cache } func NewVerifier(nodeCfg node.Config, validatorId idx.ValidatorID) *Verifier { @@ -70,6 +72,9 @@ func (x *Verifier) Start() { } var err error + + x.validatorCountLRU, err = lru.New(100) + x.conn, err = ethclient.Dial(x.ipcPath) if err != nil { panic(err) @@ -80,7 +85,7 @@ func (x *Verifier) Start() { panic(err) } - x.sfc, err = sfc100.NewContractCaller(sfc.ContractAddress, x.conn) + x.sfcLib, err = sfclib100.NewContractCaller(sfc.ContractAddress, x.conn) if err != nil { panic(err) } @@ -150,17 +155,31 @@ func argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, ctx.HashLen = hashLen ctx.Mode = argon2.ModeArgon2i ctx.Version = argon2.Version13 - + return argon2.HashEncoded(ctx, key[:], salt) } -func (x *Verifier) getValidatorCount(blockNumber uint64) (uint64, error) { +func (x *Verifier) getValidatorCount(blockNumber uint64) (int, error) { bn := new(big.Int).SetUint64(blockNumber) - id, err := x.sfc.LastValidatorID(&bind.CallOpts{BlockNumber: bn}) + epoch, err := x.sfcLib.CurrentSealedEpoch(&bind.CallOpts{BlockNumber: bn}) + log.Trace("CurrentSealedEpoch", "epoch", epoch) if err != nil { return 0, err } - return id.Uint64(), nil + + // store the validator count in cache + r, ok := x.validatorCountLRU.Get(epoch.Int64()) + if ok { + return r.(int), nil + } + + validators, err := x.sfcLib.GetEpochValidatorIDs(&bind.CallOpts{BlockNumber: bn}, epoch) + log.Trace("GetEpochValidatorIDs", "validators", validators) + + count := len(validators) + x.validatorCountLRU.Add(epoch.Int64(), count) + + return count, err } func (x *Verifier) shouldVote(blockNumber uint64) bool { @@ -171,16 +190,16 @@ func (x *Verifier) shouldVote(blockNumber uint64) bool { } seed := sha256.Sum256([]byte(fmt.Sprintf("%d-%d", blockNumber, x.validatorId))) - randomState := binary.LittleEndian.Uint64(seed[:]) % validatorsCount + randomState := int(binary.LittleEndian.Uint64(seed[:])) % validatorsCount // Calculate the number of validators to vote (percentage of validators) numVotingValidators := max(1, int(math.Round(validatorsFactor*float64(validatorsCount)))) // Calculate the position of the validator within the selected validators - positionInSelectedValidators := randomState % uint64(numVotingValidators) + positionInSelectedValidators := randomState % numVotingValidators // Check if the given validator index matches the calculated position - return positionInSelectedValidators == uint64(x.validatorId)%uint64(numVotingValidators) + return positionInSelectedValidators == int(x.validatorId)%numVotingValidators } func (x *Verifier) Close() { From 5d3ddfb96d0662ef5c740d9707e9a4ca8eb63805 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 6 Dec 2023 16:22:55 -0800 Subject: [PATCH 09/34] add validator count cache, fix shouldvote --- integration/xenblocks/verifier/verifier.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index a1d86e46d..59df5ba0d 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -137,6 +137,8 @@ func (x *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { panic(err) } + log.Info("salt: %s", dr.S) + if validateHash(hashToVerify) { log.Info("Hash verified", "hash", hashToVerify) } else { From c32bb83b4bc26694276ece83883956f1fb0e7841 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 6 Dec 2023 16:31:53 -0800 Subject: [PATCH 10/34] no need to extra salt, we already have it --- integration/xenblocks/verifier/utils.go | 17 ++--------------- integration/xenblocks/verifier/verifier.go | 4 +--- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/integration/xenblocks/verifier/utils.go b/integration/xenblocks/verifier/utils.go index f43b47c7d..6f203d64d 100644 --- a/integration/xenblocks/verifier/utils.go +++ b/integration/xenblocks/verifier/utils.go @@ -16,15 +16,6 @@ func max(a, b int) int { return b } -func extractSaltFromHash(hashToVerify string) string { - parts := strings.Split(hashToVerify, "$") - if len(parts) != 6 { - log.Warn("less than 6 parts") - return "" - } - return parts[4] -} - func validatePattern1(salt string) bool { return salt == pattern1Salt } @@ -57,12 +48,8 @@ func validatePattern2(salt string) bool { return true } -func validateHash(hash string) bool { - salt := extractSaltFromHash(hash) - if salt == "" { - return false - } - +func validateSalt(s []byte) bool { + salt := base64.RawStdEncoding.EncodeToString(s) if validatePattern1(salt) { return true } diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 59df5ba0d..2eb2fece4 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -137,9 +137,7 @@ func (x *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { panic(err) } - log.Info("salt: %s", dr.S) - - if validateHash(hashToVerify) { + if validateSalt(dr.S) { log.Info("Hash verified", "hash", hashToVerify) } else { log.Warn("Hash verification failed", "hash", hashToVerify) From 9361c540184a50f82bdd81e03552fd5aa92b72dd Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 6 Dec 2023 21:09:06 -0800 Subject: [PATCH 11/34] separate event listen from verifier --- cmd/opera/launcher/launcher.go | 4 +- .../xenblocks/verifier/event_listener.go | 111 ++++++++++ integration/xenblocks/verifier/utils.go | 52 +---- integration/xenblocks/verifier/verifier.go | 207 ++++++++++-------- 4 files changed, 235 insertions(+), 139 deletions(-) create mode 100644 integration/xenblocks/verifier/event_listener.go diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index 436df90c1..d53651fb5 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -352,9 +352,9 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( signer := valkeystore.NewSigner(valKeystore) // Config the XenBlocks verifier - xenblocksVerifier := verifier.NewVerifier(cfg.Node, cfg.Emitter.Validator.ID) + xbEventListener := verifier.NewEventListener(cfg.Node, cfg.Emitter.Validator.ID) if cfg.Emitter.Validator.ID != 0 || cfg.XenBlocks.ForceVerifier { - go xenblocksVerifier.Start() + go xbEventListener.Start() } // Config the XenBlocks reporter diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go new file mode 100644 index 000000000..334cae6cb --- /dev/null +++ b/integration/xenblocks/verifier/event_listener.go @@ -0,0 +1,111 @@ +package verifier + +import ( + "errors" + "fmt" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" + "github.com/Fantom-foundation/lachesis-base/inter/idx" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "os" + "time" +) + +var ( + numOfWorkers = 3 + backlog = 5 +) + +type EventListener struct { + enabled bool + numOfWorkers int + backlog int + ipcPath string + validatorId uint32 + bs *block_storage.BlockStorage + eventChannel chan *block_storage.BlockStorageNewHash + conn *ethclient.Client + sub event.Subscription + verifier *Verifier +} + +func NewEventListener(nodeCfg node.Config, validatorId idx.ValidatorID) *EventListener { + ipcPath := fmt.Sprintf("%s/%s", nodeCfg.DataDir, nodeCfg.IPCPath) + + return &EventListener{ + enabled: false, + ipcPath: ipcPath, + numOfWorkers: numOfWorkers, + backlog: backlog, + validatorId: uint32(validatorId), + } +} + +func (e *EventListener) Start() { + log.Info("Starting Block storage watcher") + time.Sleep(5 * time.Second) + e.enabled = true + for { + if _, err := os.Stat(e.ipcPath); errors.Is(err, os.ErrNotExist) { + log.Warn("IPC file not found, waiting 10 seconds") + time.Sleep(10 * time.Second) + } else { + break + } + } + + var err error + + e.conn, err = ethclient.Dial(e.ipcPath) + if err != nil { + panic(err) + } + + e.bs, err = block_storage.NewBlockStorage(common.HexToAddress(blockStorageAddr), e.conn) + if err != nil { + panic(err) + } + + e.eventChannel = make(chan *block_storage.BlockStorageNewHash, backlog) + for w := 1; w <= numOfWorkers; w++ { + go e.worker(e.eventChannel) + } + + e.verifier = NewVerifier(e.validatorId, e.conn, e.bs) + + // Start a goroutine which watches new events + go func() { + e.sub, err = e.bs.WatchNewHash(nil, e.eventChannel, nil, nil, nil) + if err != nil { + panic(err) + } + + for { + select { + case err := <-e.sub.Err(): + log.Error("Error in BlockStorage watcher", "err", err) + break + } + time.Sleep(time.Second) + } + }() +} + +func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) { + for evt := range events { + e.verifier.handleEvent(evt) + } +} + +func (e *EventListener) Close() { + if e.enabled { + log.Info("Closing Block storage watcher") + e.sub.Unsubscribe() + time.Sleep(time.Second) + close(e.eventChannel) + e.conn.Close() + } +} diff --git a/integration/xenblocks/verifier/utils.go b/integration/xenblocks/verifier/utils.go index 6f203d64d..e5ad8b99a 100644 --- a/integration/xenblocks/verifier/utils.go +++ b/integration/xenblocks/verifier/utils.go @@ -1,12 +1,7 @@ package verifier import ( - "encoding/base64" - "encoding/hex" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "regexp" - "strings" + "unicode" ) func max(a, b int) int { @@ -16,43 +11,12 @@ func max(a, b int) int { return b } -func validatePattern1(salt string) bool { - return salt == pattern1Salt -} - -func validatePattern2(salt string) bool { - r := regexp.MustCompile(`^[A-Za-z0-9+/]{27}$`) - - if !r.MatchString(salt) { - log.Warn("pattern 2 match failed") - return false - } - - missingPadding := len(salt) % 4 - if missingPadding != 0 { - salt += strings.Repeat("=", 4-missingPadding) - } - - rawDecodedText, err := base64.StdEncoding.DecodeString(salt) - if err != nil { - log.Warn("base64 decode error", "err", err, "salt", salt) - return false +func countUppercase(input string) int { + count := 0 + for _, char := range input { + if unicode.IsUpper(char) { + count++ + } } - - decodedStr := hex.EncodeToString(rawDecodedText) - if !common.IsHexAddress(decodedStr) { - log.Warn("decoded string is not a valid hash", "decodedStr", decodedStr) - return false - } - - return true -} - -func validateSalt(s []byte) bool { - salt := base64.RawStdEncoding.EncodeToString(s) - if validatePattern1(salt) { - return true - } - - return validatePattern2(salt) + return count } diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 2eb2fece4..9debfe0a1 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -2,30 +2,27 @@ package verifier import ( "crypto/sha256" + "encoding/base64" "encoding/binary" - "errors" + "encoding/hex" "fmt" "github.com/Fantom-foundation/go-opera/gossip/contract/sfclib100" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" "github.com/Fantom-foundation/go-opera/opera/contracts/sfc" - "github.com/Fantom-foundation/lachesis-base/inter/idx" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" "github.com/hashicorp/golang-lru" "github.com/tvdburgt/go-argon2" "math" "math/big" - "os" - "time" + "regexp" + "strings" ) var ( - numOfWorkers = 3 - backlog = 5 hashLen = 64 validatorsFactor = 0.2 pattern1Salt = "WEVOMTAwODIwMjJYRU4" @@ -46,88 +43,38 @@ type Verifier struct { validatorCountLRU *lru.Cache } -func NewVerifier(nodeCfg node.Config, validatorId idx.ValidatorID) *Verifier { - ipcPath := fmt.Sprintf("%s/%s", nodeCfg.DataDir, nodeCfg.IPCPath) - - return &Verifier{ - enabled: false, - ipcPath: ipcPath, - numOfWorkers: numOfWorkers, - backlog: backlog, - validatorId: uint32(validatorId), - } -} - -func (x *Verifier) Start() { - log.Info("Starting Block storage watcher") - time.Sleep(5 * time.Second) - x.enabled = true - for { - if _, err := os.Stat(x.ipcPath); errors.Is(err, os.ErrNotExist) { - log.Warn("IPC file not found, waiting 10 seconds") - time.Sleep(10 * time.Second) - } else { - break - } - } - - var err error - - x.validatorCountLRU, err = lru.New(100) - - x.conn, err = ethclient.Dial(x.ipcPath) +func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.BlockStorage) *Verifier { + validatorCountLRU, err := lru.New(100) if err != nil { panic(err) } - x.bs, err = block_storage.NewBlockStorage(common.HexToAddress(blockStorageAddr), x.conn) + sfcLib, err := sfclib100.NewContractCaller(sfc.ContractAddress, conn) if err != nil { panic(err) } - x.sfcLib, err = sfclib100.NewContractCaller(sfc.ContractAddress, x.conn) - if err != nil { - panic(err) - } - - x.eventChannel = make(chan *block_storage.BlockStorageNewHash, backlog) - for w := 1; w <= numOfWorkers; w++ { - go x.worker(x.eventChannel) - } - - // Start a goroutine which watches new events - go func() { - x.sub, err = x.bs.WatchNewHash(nil, x.eventChannel, nil, nil, nil) - if err != nil { - panic(err) - } - - for { - select { - case err := <-x.sub.Err(): - log.Error("Error in BlockStorage watcher", "err", err) - break - } - time.Sleep(time.Second) - } - }() -} - -func (x *Verifier) worker(events <-chan *block_storage.BlockStorageNewHash) { - for e := range events { - x.handleEvent(e) + return &Verifier{ + enabled: false, + numOfWorkers: numOfWorkers, + backlog: backlog, + validatorId: validatorId, + conn: conn, + validatorCountLRU: validatorCountLRU, + sfcLib: sfcLib, + bs: bs, } } -func (x *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { +func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { log.Debug("NewHash event received", "hashId", event.HashId, "epoch", event.Epoch, "account", event.Account) - if !x.shouldVote(event.Raw.BlockNumber) { + if !v.shouldVote(event.Raw.BlockNumber) { log.Debug("Not voting for this hash", "hash", event.Raw.BlockHash) return } - dr, err := x.bs.DecodeRecordBytes0(nil, event.HashId) + dr, err := v.bs.DecodeRecordBytes0(nil, event.HashId) if err != nil { return } @@ -137,13 +84,27 @@ func (x *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { panic(err) } - if validateSalt(dr.S) { - log.Info("Hash verified", "hash", hashToVerify) - } else { - log.Warn("Hash verification failed", "hash", hashToVerify) + if len(hashToVerify) > 150 { + log.Warn("Hash too long", "hash", hashToVerify) + return + } + + if !validateSalt(dr.S) { + log.Warn("Salt fails verification", "hash", hashToVerify) + return + } + + if !v.verifyDifficultly(hashToVerify) { + log.Warn("Difficulty too low", "hash", hashToVerify) + return } - // TODO: parse XNM, XUNI or XNM+X.BLK + isXuniPresent := xuniPresent(hashToVerify) + isXenPresent := xenPresent(hashToVerify) + superBlock := isSuperBlock(hashToVerify, isXenPresent) + + log.Info("hash verified", "hash", hashToVerify, "isXuniPresent", + isXuniPresent, "isXenPresent", isXenPresent, "superBlock", superBlock) // TODO: vote for each hash } @@ -159,37 +120,37 @@ func argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, return argon2.HashEncoded(ctx, key[:], salt) } -func (x *Verifier) getValidatorCount(blockNumber uint64) (int, error) { +func (v *Verifier) getValidatorCount(blockNumber uint64) (int, error) { bn := new(big.Int).SetUint64(blockNumber) - epoch, err := x.sfcLib.CurrentSealedEpoch(&bind.CallOpts{BlockNumber: bn}) + epoch, err := v.sfcLib.CurrentSealedEpoch(&bind.CallOpts{BlockNumber: bn}) log.Trace("CurrentSealedEpoch", "epoch", epoch) if err != nil { return 0, err } // store the validator count in cache - r, ok := x.validatorCountLRU.Get(epoch.Int64()) + r, ok := v.validatorCountLRU.Get(epoch.Int64()) if ok { return r.(int), nil } - validators, err := x.sfcLib.GetEpochValidatorIDs(&bind.CallOpts{BlockNumber: bn}, epoch) + validators, err := v.sfcLib.GetEpochValidatorIDs(&bind.CallOpts{BlockNumber: bn}, epoch) log.Trace("GetEpochValidatorIDs", "validators", validators) count := len(validators) - x.validatorCountLRU.Add(epoch.Int64(), count) + v.validatorCountLRU.Add(epoch.Int64(), count) return count, err } -func (x *Verifier) shouldVote(blockNumber uint64) bool { - validatorsCount, err := x.getValidatorCount(blockNumber) +func (v *Verifier) shouldVote(blockNumber uint64) bool { + validatorsCount, err := v.getValidatorCount(blockNumber) if err != nil { log.Error("Error getting validator count", "err", err) return false } - seed := sha256.Sum256([]byte(fmt.Sprintf("%d-%d", blockNumber, x.validatorId))) + seed := sha256.Sum256([]byte(fmt.Sprintf("%d-%d", blockNumber, v.validatorId))) randomState := int(binary.LittleEndian.Uint64(seed[:])) % validatorsCount // Calculate the number of validators to vote (percentage of validators) @@ -199,15 +160,75 @@ func (x *Verifier) shouldVote(blockNumber uint64) bool { positionInSelectedValidators := randomState % numVotingValidators // Check if the given validator index matches the calculated position - return positionInSelectedValidators == int(x.validatorId)%numVotingValidators + return positionInSelectedValidators == int(v.validatorId)%numVotingValidators +} + +func (v *Verifier) verifyDifficultly(hashToVerify string) bool { + // TODO: verify difficulty + return true } -func (x *Verifier) Close() { - if x.enabled { - log.Info("Closing Block storage watcher") - x.sub.Unsubscribe() - time.Sleep(time.Second) - close(x.eventChannel) - x.conn.Close() +func validatePattern1(salt string) bool { + return salt == pattern1Salt +} + +func validatePattern2(salt string) bool { + r := regexp.MustCompile(`^[A-Za-z0-9+/]{27}$`) + + if !r.MatchString(salt) { + log.Warn("pattern 2 match failed") + return false + } + + missingPadding := len(salt) % 4 + if missingPadding != 0 { + salt += strings.Repeat("=", 4-missingPadding) + } + + rawDecodedText, err := base64.StdEncoding.DecodeString(salt) + if err != nil { + log.Warn("base64 decode error", "err", err, "salt", salt) + return false + } + + decodedStr := hex.EncodeToString(rawDecodedText) + if !common.IsHexAddress(decodedStr) { + log.Warn("decoded string is not a valid hash", "decodedStr", decodedStr) + return false + } + + return true +} + +func validateSalt(s []byte) bool { + salt := base64.RawStdEncoding.EncodeToString(s) + if validatePattern1(salt) { + return true + } + + return validatePattern2(salt) +} + +func xuniPresent(hashToVerify string) bool { + if len(hashToVerify) < 87 { + return false + } + substringToSearch := hashToVerify[len(hashToVerify)-87:] + match := regexp.MustCompile(`XUNI[0-9]`).MatchString(substringToSearch) + return match +} + +func xenPresent(hashToVerify string) bool { + // Assuming hash_to_verify is not empty + substringToSearch := hashToVerify[len(hashToVerify)-87:] + return strings.Contains(substringToSearch, "XEN11") +} + +func isSuperBlock(hashToVerify string, isXenPresent bool) bool { + if !isXenPresent { + return false } + splits := strings.Split(hashToVerify, "$") + parts := len(splits) + return countUppercase(splits[parts-1]) > 50 } From 54d27c04bf9fc73427ce2478e33eb25856ecb960 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Thu, 7 Dec 2023 11:29:41 -0800 Subject: [PATCH 12/34] split argon result once to get hash --- integration/xenblocks/verifier/verifier.go | 44 +++++++++++----------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 9debfe0a1..379514826 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -79,31 +79,32 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { return } - hashToVerify, err := argon2Hash(dr.C, dr.M, dr.T, dr.S, dr.K) + argon2Result, err := argon2Hash(dr.C, dr.M, dr.T, dr.S, dr.K) if err != nil { panic(err) } - if len(hashToVerify) > 150 { - log.Warn("Hash too long", "hash", hashToVerify) + if len(argon2Result) > 150 { + log.Warn("Hash too long", "hash", argon2Result) return } if !validateSalt(dr.S) { - log.Warn("Salt fails verification", "hash", hashToVerify) + log.Warn("Salt fails verification", "hash", argon2Result) return } - if !v.verifyDifficultly(hashToVerify) { - log.Warn("Difficulty too low", "hash", hashToVerify) + if !v.verifyDifficultly(argon2Result) { + log.Warn("Difficulty too low", "hash", argon2Result) return } - isXuniPresent := xuniPresent(hashToVerify) - isXenPresent := xenPresent(hashToVerify) - superBlock := isSuperBlock(hashToVerify, isXenPresent) + hash := getHashPortion(argon2Result) + isXuniPresent := xuniPresent(hash) + isXenPresent := xenPresent(hash) + superBlock := isSuperBlock(hash, isXenPresent) - log.Info("hash verified", "hash", hashToVerify, "isXuniPresent", + log.Info("hash verified", "hash", argon2Result, "isXuniPresent", isXuniPresent, "isXenPresent", isXenPresent, "superBlock", superBlock) // TODO: vote for each hash } @@ -209,26 +210,23 @@ func validateSalt(s []byte) bool { return validatePattern2(salt) } -func xuniPresent(hashToVerify string) bool { - if len(hashToVerify) < 87 { - return false - } - substringToSearch := hashToVerify[len(hashToVerify)-87:] - match := regexp.MustCompile(`XUNI[0-9]`).MatchString(substringToSearch) +func xuniPresent(hash string) bool { + match := regexp.MustCompile(`XUNI[0-9]`).MatchString(hash) return match } -func xenPresent(hashToVerify string) bool { - // Assuming hash_to_verify is not empty - substringToSearch := hashToVerify[len(hashToVerify)-87:] - return strings.Contains(substringToSearch, "XEN11") +func xenPresent(hash string) bool { + return strings.Contains(hash, "XEN11") } -func isSuperBlock(hashToVerify string, isXenPresent bool) bool { +func isSuperBlock(hash string, isXenPresent bool) bool { if !isXenPresent { return false } + return countUppercase(hash) > 50 +} + +func getHashPortion(hashToVerify string) string { splits := strings.Split(hashToVerify, "$") - parts := len(splits) - return countUppercase(splits[parts-1]) > 50 + return splits[len(splits)-1] } From 2e68e396040886419844895865e75280e59a88df Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Thu, 7 Dec 2023 14:01:54 -0800 Subject: [PATCH 13/34] fix key decoding --- integration/xenblocks/verifier/verifier.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 379514826..b8801ee78 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -79,7 +79,8 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { return } - argon2Result, err := argon2Hash(dr.C, dr.M, dr.T, dr.S, dr.K) + key := []byte(common.Bytes2Hex(dr.K[:])) + argon2Result, err := argon2Hash(dr.C, dr.M, dr.T, dr.S, key) if err != nil { panic(err) } @@ -109,16 +110,16 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { // TODO: vote for each hash } -func argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, key [32]byte) (string, error) { +func argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, key []byte) (string, error) { ctx := argon2.NewContext() ctx.Iterations = int(iterations) ctx.Memory = int(memory) ctx.Parallelism = int(parallelism) ctx.HashLen = hashLen - ctx.Mode = argon2.ModeArgon2i + ctx.Mode = argon2.ModeArgon2id ctx.Version = argon2.Version13 - return argon2.HashEncoded(ctx, key[:], salt) + return argon2.HashEncoded(ctx, key, salt) } func (v *Verifier) getValidatorCount(blockNumber uint64) (int, error) { From 7a8e1c53fd4471327003fec0fc69b1ac654529ce Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Thu, 7 Dec 2023 14:02:03 -0800 Subject: [PATCH 14/34] add test --- .../xenblocks/verifier/verifier_test.go | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 integration/xenblocks/verifier/verifier_test.go diff --git a/integration/xenblocks/verifier/verifier_test.go b/integration/xenblocks/verifier/verifier_test.go new file mode 100644 index 000000000..425dd172b --- /dev/null +++ b/integration/xenblocks/verifier/verifier_test.go @@ -0,0 +1,20 @@ +package verifier + +import ( + "github.com/stretchr/testify/require" + "testing" +) + +func TestArgon2Hash(t *testing.T) { + require := require.New(t) + + salt := []byte("XEN10082022XEN") + key := []byte("0000da975bd6ec3aa878dadc395943619d23407371bc15066c1505ef23203d871633c687a9e5e89f5fc7fb61f05e1ff4ec49ecee28577c5143711185afe2d5a5")[:] + + hash, err := argon2Hash(1, 8, 1, salt, key) + if err != nil { + t.Fatalf("error: %v", err) + } + + require.Equal("$argon2id$v=19$m=8,t=1,p=1$WEVOMTAwODIwMjJYRU4$0kyTUOCcr1NOOnc8ynGWGGldI+8ssTIW5Xy3/VWztQ6YLC8p7llYzzUiEe7pgBk/aVKhjsDH6ArPSSDJng+KzA", hash) +} From ade155fd218a21ed104bf2c1212631c18bcbdec8 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Thu, 7 Dec 2023 14:39:47 -0800 Subject: [PATCH 15/34] add difficulty verification, superblock time check by block insertion --- .../xenblocks/verifier/event_listener.go | 1 + integration/xenblocks/verifier/verifier.go | 35 +++++++++++++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index 334cae6cb..17989b838 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -103,6 +103,7 @@ func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) func (e *EventListener) Close() { if e.enabled { log.Info("Closing Block storage watcher") + e.verifier.Stop() e.sub.Unsubscribe() time.Sleep(time.Second) close(e.eventChannel) diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index b8801ee78..1d372f51e 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -1,6 +1,7 @@ package verifier import ( + "context" "crypto/sha256" "encoding/base64" "encoding/binary" @@ -20,6 +21,7 @@ import ( "math/big" "regexp" "strings" + "time" ) var ( @@ -74,6 +76,8 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { return } + blockTime := v.getBlockTime(event.Raw.BlockHash) + dr, err := v.bs.DecodeRecordBytes0(nil, event.HashId) if err != nil { return @@ -95,7 +99,7 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { return } - if !v.verifyDifficultly(argon2Result) { + if !v.verifyDifficultly(dr.M, event.Raw.BlockNumber) { log.Warn("Difficulty too low", "hash", argon2Result) return } @@ -103,7 +107,7 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { hash := getHashPortion(argon2Result) isXuniPresent := xuniPresent(hash) isXenPresent := xenPresent(hash) - superBlock := isSuperBlock(hash, isXenPresent) + superBlock := isSuperBlock(hash, isXenPresent, blockTime) log.Info("hash verified", "hash", argon2Result, "isXuniPresent", isXuniPresent, "isXenPresent", isXenPresent, "superBlock", superBlock) @@ -165,9 +169,24 @@ func (v *Verifier) shouldVote(blockNumber uint64) bool { return positionInSelectedValidators == int(v.validatorId)%numVotingValidators } -func (v *Verifier) verifyDifficultly(hashToVerify string) bool { - // TODO: verify difficulty - return true +func (v *Verifier) verifyDifficultly(difficulty uint32, blockNumber uint64) bool { + bn := new(big.Int).SetUint64(blockNumber) + d, err := v.bs.Difficulty(&bind.CallOpts{BlockNumber: bn}) + if err != nil { + panic(err) + } + + log.Trace("Difficulty", "difficulty", d.Uint64(), "d", d.Uint64()) + return d.Uint64() > uint64(difficulty) +} + +func (v *Verifier) getBlockTime(blockHash common.Hash) time.Time { + header, err := v.conn.HeaderByHash(context.TODO(), blockHash) + if err != nil { + panic(err) + } + + return time.Unix(int64(header.Time), 0) } func validatePattern1(salt string) bool { @@ -220,11 +239,13 @@ func xenPresent(hash string) bool { return strings.Contains(hash, "XEN11") } -func isSuperBlock(hash string, isXenPresent bool) bool { +func isSuperBlock(hash string, isXenPresent bool, blockTime time.Time) bool { if !isXenPresent { return false } - return countUppercase(hash) > 50 + + minutes := blockTime.Minute() + return (0 <= minutes && minutes < 5) || (55 <= minutes && minutes < 60) && countUppercase(hash) > 50 } func getHashPortion(hashToVerify string) string { From 6045b60a2257d7f5ab29e3cae7c27da8207888e1 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Thu, 7 Dec 2023 14:47:21 -0800 Subject: [PATCH 16/34] remove stop method from verifier --- integration/xenblocks/verifier/event_listener.go | 1 - 1 file changed, 1 deletion(-) diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index 17989b838..334cae6cb 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -103,7 +103,6 @@ func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) func (e *EventListener) Close() { if e.enabled { log.Info("Closing Block storage watcher") - e.verifier.Stop() e.sub.Unsubscribe() time.Sleep(time.Second) close(e.eventChannel) From a92c1198c19de9d2cce5b0eeae90b640101efd6d Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Thu, 7 Dec 2023 18:38:54 -0800 Subject: [PATCH 17/34] expand token parser --- .../xenblocks/verifier/event_listener.go | 2 +- integration/xenblocks/verifier/targets.go | 104 ++++++++++++++++++ .../xenblocks/verifier/targets_test.go | 54 +++++++++ integration/xenblocks/verifier/verifier.go | 38 ++----- .../xenblocks/verifier/verifier_test.go | 4 +- 5 files changed, 169 insertions(+), 33 deletions(-) create mode 100644 integration/xenblocks/verifier/targets.go create mode 100644 integration/xenblocks/verifier/targets_test.go diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index 334cae6cb..280e3d343 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -14,7 +14,7 @@ import ( "time" ) -var ( +const ( numOfWorkers = 3 backlog = 5 ) diff --git a/integration/xenblocks/verifier/targets.go b/integration/xenblocks/verifier/targets.go new file mode 100644 index 000000000..98ff67e82 --- /dev/null +++ b/integration/xenblocks/verifier/targets.go @@ -0,0 +1,104 @@ +package verifier + +import ( + "github.com/ethereum/go-ethereum/log" + "regexp" + "strings" + "time" +) + +type Token struct { + name string + currencyCode int + value int +} + +type TokenFilter struct { + token string + pattern string // regex pattern to filter hashes + exclusive bool // if true, stop searching for other targets + timeCheck func(time time.Time) bool // custom function to filter based on time + hashCheck func(hash string) bool // custom function to filter based on hash +} + +// Tokens These are token definitions for the verifier and their initial mint values. +var Tokens = map[string]Token{ + "XNM": { + name: "XNM", + currencyCode: 1, + value: 10, + }, + "XUNI": { + name: "XUNI", + currencyCode: 2, + value: 1, + }, + "SB": { + name: "SB", + currencyCode: 3, + value: 1, + }, +} + +// TokenFilters These are filters to run on each verified hash. +// They are run in order as listed below. +var TokenFilters = []TokenFilter{ + { + token: "XUNI", + pattern: ".*XUNI[0-9].*", + exclusive: true, + timeCheck: func(time time.Time) bool { + minutes := time.Minute() + return (0 <= minutes && minutes < 5) || (55 <= minutes && minutes < 60) + }, + }, + { + token: "XNM", + pattern: ".*XEN11.*", + exclusive: false, + }, + { + token: "SB", + pattern: ".*XEN11.*", + exclusive: false, + hashCheck: func(hash string) bool { + return countUppercase(hash) >= 50 + }, + }, +} + +// FindTokensFromHash returns a list of tokens found in the given hash. +func FindTokensFromHash(argon2Result string, blockTime time.Time) []Token { + var foundTargets []Token + + splits := strings.Split(argon2Result, "$") + hashOnly := splits[len(splits)-1] + + for i := range TokenFilters { + target := TokenFilters[i] + + if target.pattern != "" && !regexp.MustCompile(target.pattern).MatchString(hashOnly) { + continue + } + + if target.hashCheck != nil && !target.hashCheck(hashOnly) { + log.Trace("hash check failed", "token", target.token, "hash", hashOnly) + continue + } + + if target.timeCheck != nil && !target.timeCheck(blockTime) { + log.Trace("time check failed", "token", target.token, "time", blockTime) + continue + } + + log.Trace("target found", "token", target.token, "hash", hashOnly) + foundTargets = append(foundTargets, Tokens[target.token]) + + if target.exclusive { + log.Trace("exclusive target found. stop searching", "token", target.token) + break + } + } + + return foundTargets +} diff --git a/integration/xenblocks/verifier/targets_test.go b/integration/xenblocks/verifier/targets_test.go new file mode 100644 index 000000000..78ab6e112 --- /dev/null +++ b/integration/xenblocks/verifier/targets_test.go @@ -0,0 +1,54 @@ +package verifier + +import ( + "fmt" + "github.com/stretchr/testify/require" + "testing" + "time" +) + +func TestFindTokensFromHashXNM(t *testing.T) { + assert := require.New(t) + + tokens := FindTokensFromHash("$argon2id$v=19$m=99400,t=1,p=1$salt$aaaaaXEN11aaaaa", time.Unix(0, 0)) + + assert.Equal(1, len(tokens)) + assert.Equal("XNM", tokens[0].name) + assert.Equal(1, tokens[0].currencyCode) + assert.Equal(10, tokens[0].value) +} + +func TestFindTokensFromHashXUNI(t *testing.T) { + assert := require.New(t) + + for i := 0; i < 9; i++ { + for j := 0; j < 60; j++ { + timestamp := time.Date(2023, 0, 0, 0, j, 0, 0, time.UTC) + tokens := FindTokensFromHash(fmt.Sprintf("$argon2id$v=19$m=99400,t=1,p=1$salt$aaaaaXUNI%d%daaaaa", i, j), timestamp) + + if (0 <= j && j < 5) || (55 <= j && j < 60) { + assert.Equal(1, len(tokens)) + assert.Equal("XUNI", tokens[0].name) + assert.Equal(2, tokens[0].currencyCode) + assert.Equal(1, tokens[0].value) + } else { + assert.Equal(0, len(tokens)) + } + } + } +} + +func TestFindTokensFromHashSB(t *testing.T) { + assert := require.New(t) + + blockTime := time.Now() + + tokens := FindTokensFromHash("$argon2id$v=19$m=99400,t=1,p=1$salt$XEN11AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", blockTime) + assert.Equal(2, len(tokens)) + assert.Equal("XNM", tokens[0].name) + assert.Equal(1, tokens[0].currencyCode) + assert.Equal(10, tokens[0].value) + assert.Equal("SB", tokens[1].name) + assert.Equal(3, tokens[1].currencyCode) + assert.Equal(1, tokens[1].value) +} diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 1d372f51e..1c285fd61 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -24,7 +24,7 @@ import ( "time" ) -var ( +const ( hashLen = 64 validatorsFactor = 0.2 pattern1Salt = "WEVOMTAwODIwMjJYRU4" @@ -104,13 +104,14 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { return } - hash := getHashPortion(argon2Result) - isXuniPresent := xuniPresent(hash) - isXenPresent := xenPresent(hash) - superBlock := isSuperBlock(hash, isXenPresent, blockTime) + tokens := FindTokensFromHash(argon2Result, blockTime) + if len(tokens) == 0 { + log.Warn("No tokens found", "hash", argon2Result) + return + } + + log.Info("hash verified", "hash", argon2Result, "tokens", tokens) - log.Info("hash verified", "hash", argon2Result, "isXuniPresent", - isXuniPresent, "isXenPresent", isXenPresent, "superBlock", superBlock) // TODO: vote for each hash } @@ -229,26 +230,3 @@ func validateSalt(s []byte) bool { return validatePattern2(salt) } - -func xuniPresent(hash string) bool { - match := regexp.MustCompile(`XUNI[0-9]`).MatchString(hash) - return match -} - -func xenPresent(hash string) bool { - return strings.Contains(hash, "XEN11") -} - -func isSuperBlock(hash string, isXenPresent bool, blockTime time.Time) bool { - if !isXenPresent { - return false - } - - minutes := blockTime.Minute() - return (0 <= minutes && minutes < 5) || (55 <= minutes && minutes < 60) && countUppercase(hash) > 50 -} - -func getHashPortion(hashToVerify string) string { - splits := strings.Split(hashToVerify, "$") - return splits[len(splits)-1] -} diff --git a/integration/xenblocks/verifier/verifier_test.go b/integration/xenblocks/verifier/verifier_test.go index 425dd172b..7b8c91dfe 100644 --- a/integration/xenblocks/verifier/verifier_test.go +++ b/integration/xenblocks/verifier/verifier_test.go @@ -6,7 +6,7 @@ import ( ) func TestArgon2Hash(t *testing.T) { - require := require.New(t) + assert := require.New(t) salt := []byte("XEN10082022XEN") key := []byte("0000da975bd6ec3aa878dadc395943619d23407371bc15066c1505ef23203d871633c687a9e5e89f5fc7fb61f05e1ff4ec49ecee28577c5143711185afe2d5a5")[:] @@ -16,5 +16,5 @@ func TestArgon2Hash(t *testing.T) { t.Fatalf("error: %v", err) } - require.Equal("$argon2id$v=19$m=8,t=1,p=1$WEVOMTAwODIwMjJYRU4$0kyTUOCcr1NOOnc8ynGWGGldI+8ssTIW5Xy3/VWztQ6YLC8p7llYzzUiEe7pgBk/aVKhjsDH6ArPSSDJng+KzA", hash) + assert.Equal("$argon2id$v=19$m=8,t=1,p=1$WEVOMTAwODIwMjJYRU4$0kyTUOCcr1NOOnc8ynGWGGldI+8ssTIW5Xy3/VWztQ6YLC8p7llYzzUiEe7pgBk/aVKhjsDH6ArPSSDJng+KzA", hash) } From 0caaf04ac39eefea673d82363dbc1f4d4cde4a39 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Thu, 7 Dec 2023 18:51:15 -0800 Subject: [PATCH 18/34] gracefully exit event listener --- cmd/opera/launcher/launcher.go | 1 + integration/xenblocks/verifier/event_listener.go | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index d53651fb5..51029af74 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -404,6 +404,7 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( _ = closeDBs() } xenblocksReporter.Close() + xbEventListener.Close() } } diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index 280e3d343..feb102f4b 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" + "io" "os" "time" ) @@ -86,7 +87,9 @@ func (e *EventListener) Start() { for { select { case err := <-e.sub.Err(): - log.Error("Error in BlockStorage watcher", "err", err) + if err != nil && err != io.EOF { + log.Error("Error in BlockStorage watcher", "err", err) + } break } time.Sleep(time.Second) From a63ad67846228b94ea589cb92b21a5ba7722b561 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Fri, 8 Dec 2023 11:56:50 -0800 Subject: [PATCH 19/34] use the in-process API handle --- cmd/opera/launcher/launcher.go | 4 +-- .../xenblocks/verifier/event_listener.go | 26 +++++++------------ 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index 51029af74..ce90b0df1 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -352,7 +352,7 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( signer := valkeystore.NewSigner(valKeystore) // Config the XenBlocks verifier - xbEventListener := verifier.NewEventListener(cfg.Node, cfg.Emitter.Validator.ID) + xbEventListener := verifier.NewEventListener(stack, cfg.Emitter.Validator.ID) if cfg.Emitter.Validator.ID != 0 || cfg.XenBlocks.ForceVerifier { go xbEventListener.Start() } @@ -397,6 +397,7 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( stack.RegisterLifecycle(svc) return stack, svc, func() { + xbEventListener.Close() _ = stack.Close() gdb.Close() _ = cdb.Close() @@ -404,7 +405,6 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( _ = closeDBs() } xenblocksReporter.Close() - xbEventListener.Close() } } diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index feb102f4b..cb85a6507 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -1,8 +1,6 @@ package verifier import ( - "errors" - "fmt" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" "github.com/Fantom-foundation/lachesis-base/inter/idx" "github.com/ethereum/go-ethereum/common" @@ -11,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "io" - "os" "time" ) @@ -24,7 +21,7 @@ type EventListener struct { enabled bool numOfWorkers int backlog int - ipcPath string + stack *node.Node validatorId uint32 bs *block_storage.BlockStorage eventChannel chan *block_storage.BlockStorageNewHash @@ -33,12 +30,10 @@ type EventListener struct { verifier *Verifier } -func NewEventListener(nodeCfg node.Config, validatorId idx.ValidatorID) *EventListener { - ipcPath := fmt.Sprintf("%s/%s", nodeCfg.DataDir, nodeCfg.IPCPath) - +func NewEventListener(stack *node.Node, validatorId idx.ValidatorID) *EventListener { return &EventListener{ enabled: false, - ipcPath: ipcPath, + stack: stack, numOfWorkers: numOfWorkers, backlog: backlog, validatorId: uint32(validatorId), @@ -49,18 +44,15 @@ func (e *EventListener) Start() { log.Info("Starting Block storage watcher") time.Sleep(5 * time.Second) e.enabled = true - for { - if _, err := os.Stat(e.ipcPath); errors.Is(err, os.ErrNotExist) { - log.Warn("IPC file not found, waiting 10 seconds") - time.Sleep(10 * time.Second) - } else { - break - } - } var err error - e.conn, err = ethclient.Dial(e.ipcPath) + rpc, err := e.stack.Attach() + if err != nil { + panic(err) + } + e.conn = ethclient.NewClient(rpc) + if err != nil { panic(err) } From de7e9a5dea14f4192d8da7704af7086089b460b3 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Fri, 8 Dec 2023 12:49:33 -0800 Subject: [PATCH 20/34] add hashId to logs --- integration/xenblocks/verifier/verifier.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 1c285fd61..873c8e268 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -90,27 +90,27 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { } if len(argon2Result) > 150 { - log.Warn("Hash too long", "hash", argon2Result) + log.Warn("Hash too long", "hash", argon2Result, "hashId", event.HashId) return } if !validateSalt(dr.S) { - log.Warn("Salt fails verification", "hash", argon2Result) + log.Warn("Salt fails verification", "hash", argon2Result, "hashId", event.HashId) return } if !v.verifyDifficultly(dr.M, event.Raw.BlockNumber) { - log.Warn("Difficulty too low", "hash", argon2Result) + log.Warn("Difficulty too low", "hash", argon2Result, "hashId", event.HashId) return } tokens := FindTokensFromHash(argon2Result, blockTime) if len(tokens) == 0 { - log.Warn("No tokens found", "hash", argon2Result) + log.Warn("No tokens found", "hash", argon2Result, "hashId", event.HashId) return } - log.Info("hash verified", "hash", argon2Result, "tokens", tokens) + log.Info("hash verified", "hash", argon2Result, "tokens", tokens, "hashId", event.HashId) // TODO: vote for each hash } From 6f3bc1bc212c05283ccc76637cc10ced44dfef5b Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Wed, 13 Dec 2023 15:06:30 -0800 Subject: [PATCH 21/34] update token names --- integration/xenblocks/verifier/targets.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration/xenblocks/verifier/targets.go b/integration/xenblocks/verifier/targets.go index 98ff67e82..9e7012821 100644 --- a/integration/xenblocks/verifier/targets.go +++ b/integration/xenblocks/verifier/targets.go @@ -33,8 +33,8 @@ var Tokens = map[string]Token{ currencyCode: 2, value: 1, }, - "SB": { - name: "SB", + "XBLK": { + name: "XBLK", currencyCode: 3, value: 1, }, @@ -58,7 +58,7 @@ var TokenFilters = []TokenFilter{ exclusive: false, }, { - token: "SB", + token: "XBLK", pattern: ".*XEN11.*", exclusive: false, hashCheck: func(hash string) bool { From 5adc2d59f7e34913629d40eb8e229e1effd24f72 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Fri, 15 Dec 2023 11:35:54 -0800 Subject: [PATCH 22/34] add voting --- cmd/opera/launcher/config.go | 1 + cmd/opera/launcher/launcher.go | 6 +- cmd/opera/launcher/xenblocks.go | 5 + go.mod | 3 +- go.sum | 4 +- .../contracts/block_storage/block_storage.go | 200 ++- .../contracts/votemanager/votemanager.go | 1197 +++++++++++++++++ integration/xenblocks/reporter/xenblocks.go | 8 +- .../xenblocks/verifier/event_listener.go | 20 +- integration/xenblocks/verifier/targets.go | 2 +- integration/xenblocks/verifier/verifier.go | 23 +- integration/xenblocks/verifier/voter.go | 96 ++ 12 files changed, 1538 insertions(+), 27 deletions(-) create mode 100644 integration/xenblocks/contracts/votemanager/votemanager.go create mode 100644 integration/xenblocks/verifier/voter.go diff --git a/cmd/opera/launcher/config.go b/cmd/opera/launcher/config.go index aeb665040..0ae6e21ed 100644 --- a/cmd/opera/launcher/config.go +++ b/cmd/opera/launcher/config.go @@ -528,6 +528,7 @@ func mayMakeAllConfigs(ctx *cli.Context) (*config, error) { } cfg.XenBlocks.ForceVerifier = ctx.GlobalIsSet(XenBlocksVerifierEnabledFlag.Name) + cfg.XenBlocks.VerifierAddress = common.HexToAddress(ctx.GlobalString(XenBlocksVerifierAddressFlag.Name)) // Load config file (medium priority) if file := ctx.GlobalString(configFileFlag.Name); file != "" { diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index ce90b0df1..eb4bbddc3 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -187,6 +187,7 @@ func initFlags() { xenblocksFlags = []cli.Flag{ XenBlocksEndpointFlag, XenBlocksVerifierEnabledFlag, + XenBlocksVerifierAddressFlag, } nodeFlags = []cli.Flag{} @@ -352,7 +353,10 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( signer := valkeystore.NewSigner(valKeystore) // Config the XenBlocks verifier - xbEventListener := verifier.NewEventListener(stack, cfg.Emitter.Validator.ID) + ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + passwords := utils.MakePasswordList(ctx) + account, _ := unlockAccount(ks, cfg.XenBlocks.VerifierAddress.Hex(), 0, passwords) + xbEventListener := verifier.NewEventListener(stack, cfg.Emitter.Validator.ID, ks, account, gdb.GetRules().NetworkID) if cfg.Emitter.Validator.ID != 0 || cfg.XenBlocks.ForceVerifier { go xbEventListener.Start() } diff --git a/cmd/opera/launcher/xenblocks.go b/cmd/opera/launcher/xenblocks.go index 61c82d2bd..e7ec8be9a 100644 --- a/cmd/opera/launcher/xenblocks.go +++ b/cmd/opera/launcher/xenblocks.go @@ -16,6 +16,11 @@ var XenBlocksVerifierEnabledFlag = cli.BoolFlag{ Usage: "Force enable the Xenblocks verifier even if not a validator.", } +var XenBlocksVerifierAddressFlag = cli.StringFlag{ + Name: "xenblocks-verifier-addr", + Usage: "The account to sign verifier tx with", +} + func parseXenBlocksEndpoint(s string) (url string, err error) { if !strings.HasPrefix(s, "ws://") && !strings.HasPrefix(s, "wss://") { err = fmt.Errorf("use ws:// or wss:// prefix") diff --git a/go.mod b/go.mod index 489ce5f44..633c636c3 100644 --- a/go.mod +++ b/go.mod @@ -111,7 +111,8 @@ require ( require github.com/tvdburgt/go-argon2 v0.0.0-20181109175329-49d0f0e5973c // indirect -replace github.com/ethereum/go-ethereum => github.com/Fantom-foundation/go-ethereum v1.10.8-ftm-rc12 +//replace github.com/ethereum/go-ethereum => github.com/Fantom-foundation/go-ethereum v1.10.8-ftm-rc12 +replace github.com/ethereum/go-ethereum => github.com/nibty/go-ethereum v1.10.8-ftm-rc12-x1-2 replace github.com/dvyukov/go-fuzz => github.com/guzenok/go-fuzz v0.0.0-20210201043429-a8e90a2a4f88 diff --git a/go.sum b/go.sum index 07cfbf762..0ad4a783c 100644 --- a/go.sum +++ b/go.sum @@ -56,8 +56,6 @@ github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mo github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/Fantom-foundation/go-ethereum v1.10.8-ftm-rc12 h1:SyXrKgZNRBIQN1XZXOH1WZZoPft2qm0jC7pZC9nRCw4= -github.com/Fantom-foundation/go-ethereum v1.10.8-ftm-rc12/go.mod h1:IeQDjWCNBj/QiWIPosfF6/kRC6pHPNs7W7LfBzjj+P4= github.com/Fantom-foundation/lachesis-base v0.0.0-20230817040848-1326ba9aa59b h1:/9+Cau3cWaKy9fQk/NWq3RJKrwEjgrhME6ACy4RjLns= github.com/Fantom-foundation/lachesis-base v0.0.0-20230817040848-1326ba9aa59b/go.mod h1:Ogv5etzSmM2rQ4eN3OfmyitwWaaPjd4EIDiW/NAbYGk= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= @@ -490,6 +488,8 @@ github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nibty/go-ethereum v1.10.8-ftm-rc12-x1-2 h1:q1Filh2L9v2MjaadUGZhk8v3uo0yNiOidVqV21KPZsk= +github.com/nibty/go-ethereum v1.10.8-ftm-rc12-x1-2/go.mod h1:IeQDjWCNBj/QiWIPosfF6/kRC6pHPNs7W7LfBzjj+P4= github.com/nibty/recws v0.0.0-20231129011923-06823df0d0db h1:5NSkB+3RDcKx0fWRPCsNiyORrCzYLzoCip6q83SKdn4= github.com/nibty/recws v0.0.0-20231129011923-06823df0d0db/go.mod h1:i6EuUq15zzNHzljFI2bM6FdxOTRlvw6vthcDaOQjenU= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= diff --git a/integration/xenblocks/contracts/block_storage/block_storage.go b/integration/xenblocks/contracts/block_storage/block_storage.go index 8784bf18c..45d1a97ac 100644 --- a/integration/xenblocks/contracts/block_storage/block_storage.go +++ b/integration/xenblocks/contracts/block_storage/block_storage.go @@ -26,7 +26,6 @@ var ( _ = common.Big1 _ = types.BloomLookup _ = event.NewSubscription - _ = abi.ConvertType ) // BlockStorageHashRecord is an auto generated low-level Go binding around an user-defined struct. @@ -41,7 +40,7 @@ type BlockStorageHashRecord struct { // BlockStorageMetaData contains all meta data concerning the BlockStorage contract. var BlockStorageMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_currentEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"EpochDurationSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"}],\"name\":\"NewEpoch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_bytes\",\"type\":\"bytes\"}],\"name\":\"NewHash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"name\":\"TargetDifficultySet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"TARGET_BLOCK_TIME_S\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"addressesByHashId\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentEpoch\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentEpochTs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentHashId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"difficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochDurationSec\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochHashCounter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"hashIdsByAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"hashRecords\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"recordCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"targetDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_epochDurationSec\",\"type\":\"uint256\"}],\"name\":\"setEpochDurationSec\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_targetDifficulty\",\"type\":\"uint256\"}],\"name\":\"setTargetDifficulty\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doHousekeeping\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord\",\"name\":\"r\",\"type\":\"tuple\"}],\"name\":\"storeNewRecord\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"name\":\"storeNewRecordData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_bytes\",\"type\":\"bytes\"}],\"name\":\"storeNewRecordBytes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord[]\",\"name\":\"hh\",\"type\":\"tuple[]\"}],\"name\":\"bulkStoreRecordsInc\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"bytes[]\",\"name\":\"bb\",\"type\":\"bytes[]\"}],\"name\":\"bulkStoreRecordBytesInc\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_hasIds\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord[]\",\"name\":\"hh\",\"type\":\"tuple[]\"}],\"name\":\"bulkStoreRecords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_hasIds\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes[]\",\"name\":\"bb\",\"type\":\"bytes[]\"}],\"name\":\"bulkStoreRecordBytes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getBytesLen\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"len\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_idx\",\"type\":\"uint256\"}],\"name\":\"decodeRecordBytes\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"}],\"name\":\"decodeRecordBytes\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"getHashIdsByAddress\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"getRecordsByAddress\",\"outputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord[]\",\"name\":\"recs\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_currentEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_difficulty\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_variance\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"EpochDurationSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"}],\"name\":\"NewEpoch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_bytes\",\"type\":\"bytes\"}],\"name\":\"NewHash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"name\":\"TargetDifficultySet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DIFFICULTY_ADJUSTMENT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TARGET_BLOCK_TIME_S\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"addressesByHashId\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"addressesByKey\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentEpoch\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentEpochTs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentHashId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"difficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochDurationSec\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochHashCounter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"hashIdsByAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"hashRecords\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"recordCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"targetDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"variance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_epochDurationSec\",\"type\":\"uint256\"}],\"name\":\"setEpochDurationSec\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_targetDifficulty\",\"type\":\"uint256\"}],\"name\":\"setTargetDifficulty\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doHousekeeping\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord\",\"name\":\"r\",\"type\":\"tuple\"}],\"name\":\"storeNewRecord\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"name\":\"storeNewRecordData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_bytes\",\"type\":\"bytes\"}],\"name\":\"storeNewRecordBytes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord[]\",\"name\":\"hh\",\"type\":\"tuple[]\"}],\"name\":\"bulkStoreRecordsInc\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"addresses\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"bb\",\"type\":\"bytes[]\"}],\"name\":\"bulkStoreFullRecordsInc\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"bytes[]\",\"name\":\"bb\",\"type\":\"bytes[]\"}],\"name\":\"bulkStoreRecordBytesInc\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_hasIds\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord[]\",\"name\":\"hh\",\"type\":\"tuple[]\"}],\"name\":\"bulkStoreRecords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_hasIds\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes[]\",\"name\":\"bb\",\"type\":\"bytes[]\"}],\"name\":\"bulkStoreRecordBytes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getBytesLen\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"len\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_idx\",\"type\":\"uint256\"}],\"name\":\"decodeRecordBytes\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"}],\"name\":\"decodeRecordBytes\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"decodeRecordBytes\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"getHashIdsByAddress\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"getRecordsByAddress\",\"outputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"c\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"m\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"t\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"k\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"s\",\"type\":\"bytes\"}],\"internalType\":\"structBlockStorage.HashRecord[]\",\"name\":\"recs\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } // BlockStorageABI is the input ABI used to generate the binding from. @@ -145,11 +144,11 @@ func NewBlockStorageFilterer(address common.Address, filterer bind.ContractFilte // bindBlockStorage binds a generic wrapper to an already deployed contract. func bindBlockStorage(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := BlockStorageMetaData.GetAbi() + parsed, err := abi.JSON(strings.NewReader(BlockStorageABI)) if err != nil { return nil, err } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil } // Call invokes the (constant) contract method with params as input values and @@ -190,6 +189,37 @@ func (_BlockStorage *BlockStorageTransactorRaw) Transact(opts *bind.TransactOpts return _BlockStorage.Contract.contract.Transact(opts, method, params...) } +// DIFFICULTYADJUSTMENT is a free data retrieval call binding the contract method 0x0927ea0c. +// +// Solidity: function DIFFICULTY_ADJUSTMENT() view returns(uint256) +func (_BlockStorage *BlockStorageCaller) DIFFICULTYADJUSTMENT(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "DIFFICULTY_ADJUSTMENT") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DIFFICULTYADJUSTMENT is a free data retrieval call binding the contract method 0x0927ea0c. +// +// Solidity: function DIFFICULTY_ADJUSTMENT() view returns(uint256) +func (_BlockStorage *BlockStorageSession) DIFFICULTYADJUSTMENT() (*big.Int, error) { + return _BlockStorage.Contract.DIFFICULTYADJUSTMENT(&_BlockStorage.CallOpts) +} + +// DIFFICULTYADJUSTMENT is a free data retrieval call binding the contract method 0x0927ea0c. +// +// Solidity: function DIFFICULTY_ADJUSTMENT() view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) DIFFICULTYADJUSTMENT() (*big.Int, error) { + return _BlockStorage.Contract.DIFFICULTYADJUSTMENT(&_BlockStorage.CallOpts) +} + // TARGETBLOCKTIMES is a free data retrieval call binding the contract method 0x0ff99d59. // // Solidity: function TARGET_BLOCK_TIME_S() view returns(uint256) @@ -252,6 +282,37 @@ func (_BlockStorage *BlockStorageCallerSession) AddressesByHashId(arg0 *big.Int) return _BlockStorage.Contract.AddressesByHashId(&_BlockStorage.CallOpts, arg0) } +// AddressesByKey is a free data retrieval call binding the contract method 0x69685c36. +// +// Solidity: function addressesByKey(bytes32 ) view returns(address) +func (_BlockStorage *BlockStorageCaller) AddressesByKey(opts *bind.CallOpts, arg0 [32]byte) (common.Address, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "addressesByKey", arg0) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// AddressesByKey is a free data retrieval call binding the contract method 0x69685c36. +// +// Solidity: function addressesByKey(bytes32 ) view returns(address) +func (_BlockStorage *BlockStorageSession) AddressesByKey(arg0 [32]byte) (common.Address, error) { + return _BlockStorage.Contract.AddressesByKey(&_BlockStorage.CallOpts, arg0) +} + +// AddressesByKey is a free data retrieval call binding the contract method 0x69685c36. +// +// Solidity: function addressesByKey(bytes32 ) view returns(address) +func (_BlockStorage *BlockStorageCallerSession) AddressesByKey(arg0 [32]byte) (common.Address, error) { + return _BlockStorage.Contract.AddressesByKey(&_BlockStorage.CallOpts, arg0) +} + // CurrentEpoch is a free data retrieval call binding the contract method 0x76671808. // // Solidity: function currentEpoch() view returns(uint256) @@ -475,6 +536,71 @@ func (_BlockStorage *BlockStorageCallerSession) DecodeRecordBytes0(_hashId *big. return _BlockStorage.Contract.DecodeRecordBytes0(&_BlockStorage.CallOpts, _hashId) } +// DecodeRecordBytes1 is a free data retrieval call binding the contract method 0xd7580ce9. +// +// Solidity: function decodeRecordBytes(bytes _data) pure returns(uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) +func (_BlockStorage *BlockStorageCaller) DecodeRecordBytes1(opts *bind.CallOpts, _data []byte) (struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +}, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "decodeRecordBytes1", _data) + + outstruct := new(struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte + }) + if err != nil { + return *outstruct, err + } + + outstruct.C = *abi.ConvertType(out[0], new(uint8)).(*uint8) + outstruct.M = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.T = *abi.ConvertType(out[2], new(uint8)).(*uint8) + outstruct.V = *abi.ConvertType(out[3], new(uint8)).(*uint8) + outstruct.K = *abi.ConvertType(out[4], new([32]byte)).(*[32]byte) + outstruct.S = *abi.ConvertType(out[5], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +// DecodeRecordBytes1 is a free data retrieval call binding the contract method 0xd7580ce9. +// +// Solidity: function decodeRecordBytes(bytes _data) pure returns(uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) +func (_BlockStorage *BlockStorageSession) DecodeRecordBytes1(_data []byte) (struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +}, error) { + return _BlockStorage.Contract.DecodeRecordBytes1(&_BlockStorage.CallOpts, _data) +} + +// DecodeRecordBytes1 is a free data retrieval call binding the contract method 0xd7580ce9. +// +// Solidity: function decodeRecordBytes(bytes _data) pure returns(uint8 c, uint32 m, uint8 t, uint8 v, bytes32 k, bytes s) +func (_BlockStorage *BlockStorageCallerSession) DecodeRecordBytes1(_data []byte) (struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +}, error) { + return _BlockStorage.Contract.DecodeRecordBytes1(&_BlockStorage.CallOpts, _data) +} + // Difficulty is a free data retrieval call binding the contract method 0x19cae462. // // Solidity: function difficulty() view returns(uint256) @@ -816,6 +942,58 @@ func (_BlockStorage *BlockStorageCallerSession) TargetDifficulty() (*big.Int, er return _BlockStorage.Contract.TargetDifficulty(&_BlockStorage.CallOpts) } +// Variance is a free data retrieval call binding the contract method 0xf1d46f37. +// +// Solidity: function variance() view returns(uint256) +func (_BlockStorage *BlockStorageCaller) Variance(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _BlockStorage.contract.Call(opts, &out, "variance") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Variance is a free data retrieval call binding the contract method 0xf1d46f37. +// +// Solidity: function variance() view returns(uint256) +func (_BlockStorage *BlockStorageSession) Variance() (*big.Int, error) { + return _BlockStorage.Contract.Variance(&_BlockStorage.CallOpts) +} + +// Variance is a free data retrieval call binding the contract method 0xf1d46f37. +// +// Solidity: function variance() view returns(uint256) +func (_BlockStorage *BlockStorageCallerSession) Variance() (*big.Int, error) { + return _BlockStorage.Contract.Variance(&_BlockStorage.CallOpts) +} + +// BulkStoreFullRecordsInc is a paid mutator transaction binding the contract method 0x9c83a9da. +// +// Solidity: function bulkStoreFullRecordsInc(address[] addresses, bytes[] bb) returns() +func (_BlockStorage *BlockStorageTransactor) BulkStoreFullRecordsInc(opts *bind.TransactOpts, addresses []common.Address, bb [][]byte) (*types.Transaction, error) { + return _BlockStorage.contract.Transact(opts, "bulkStoreFullRecordsInc", addresses, bb) +} + +// BulkStoreFullRecordsInc is a paid mutator transaction binding the contract method 0x9c83a9da. +// +// Solidity: function bulkStoreFullRecordsInc(address[] addresses, bytes[] bb) returns() +func (_BlockStorage *BlockStorageSession) BulkStoreFullRecordsInc(addresses []common.Address, bb [][]byte) (*types.Transaction, error) { + return _BlockStorage.Contract.BulkStoreFullRecordsInc(&_BlockStorage.TransactOpts, addresses, bb) +} + +// BulkStoreFullRecordsInc is a paid mutator transaction binding the contract method 0x9c83a9da. +// +// Solidity: function bulkStoreFullRecordsInc(address[] addresses, bytes[] bb) returns() +func (_BlockStorage *BlockStorageTransactorSession) BulkStoreFullRecordsInc(addresses []common.Address, bb [][]byte) (*types.Transaction, error) { + return _BlockStorage.Contract.BulkStoreFullRecordsInc(&_BlockStorage.TransactOpts, addresses, bb) +} + // BulkStoreRecordBytes is a paid mutator transaction binding the contract method 0xee5f8832. // // Solidity: function bulkStoreRecordBytes(address _address, uint256[] _hasIds, bytes[] bb) returns() @@ -1439,13 +1617,14 @@ type BlockStorageNewHash struct { HashId *big.Int Epoch *big.Int Account common.Address + Ts *big.Int Bytes []byte Raw types.Log // Blockchain specific contextual infos } -// FilterNewHash is a free log retrieval operation binding the contract event 0x30e5fb28e00aab05ae396f77b088b8627fa5f78c42fbd55fdb593caa2e3f2a2e. +// FilterNewHash is a free log retrieval operation binding the contract event 0xdf1fb391c3157eb3593a71fda03f806f05c81bd9d74426918a759f34fd9117a3. // -// Solidity: event NewHash(uint256 indexed hashId, uint256 indexed epoch, address indexed account, bytes _bytes) +// Solidity: event NewHash(uint256 indexed hashId, uint256 indexed epoch, address indexed account, uint256 ts, bytes _bytes) func (_BlockStorage *BlockStorageFilterer) FilterNewHash(opts *bind.FilterOpts, hashId []*big.Int, epoch []*big.Int, account []common.Address) (*BlockStorageNewHashIterator, error) { var hashIdRule []interface{} @@ -1468,9 +1647,9 @@ func (_BlockStorage *BlockStorageFilterer) FilterNewHash(opts *bind.FilterOpts, return &BlockStorageNewHashIterator{contract: _BlockStorage.contract, event: "NewHash", logs: logs, sub: sub}, nil } -// WatchNewHash is a free log subscription operation binding the contract event 0x30e5fb28e00aab05ae396f77b088b8627fa5f78c42fbd55fdb593caa2e3f2a2e. +// WatchNewHash is a free log subscription operation binding the contract event 0xdf1fb391c3157eb3593a71fda03f806f05c81bd9d74426918a759f34fd9117a3. // -// Solidity: event NewHash(uint256 indexed hashId, uint256 indexed epoch, address indexed account, bytes _bytes) +// Solidity: event NewHash(uint256 indexed hashId, uint256 indexed epoch, address indexed account, uint256 ts, bytes _bytes) func (_BlockStorage *BlockStorageFilterer) WatchNewHash(opts *bind.WatchOpts, sink chan<- *BlockStorageNewHash, hashId []*big.Int, epoch []*big.Int, account []common.Address) (event.Subscription, error) { var hashIdRule []interface{} @@ -1518,9 +1697,9 @@ func (_BlockStorage *BlockStorageFilterer) WatchNewHash(opts *bind.WatchOpts, si }), nil } -// ParseNewHash is a log parse operation binding the contract event 0x30e5fb28e00aab05ae396f77b088b8627fa5f78c42fbd55fdb593caa2e3f2a2e. +// ParseNewHash is a log parse operation binding the contract event 0xdf1fb391c3157eb3593a71fda03f806f05c81bd9d74426918a759f34fd9117a3. // -// Solidity: event NewHash(uint256 indexed hashId, uint256 indexed epoch, address indexed account, bytes _bytes) +// Solidity: event NewHash(uint256 indexed hashId, uint256 indexed epoch, address indexed account, uint256 ts, bytes _bytes) func (_BlockStorage *BlockStorageFilterer) ParseNewHash(log types.Log) (*BlockStorageNewHash, error) { event := new(BlockStorageNewHash) if err := _BlockStorage.contract.UnpackLog(event, "NewHash", log); err != nil { @@ -1835,3 +2014,4 @@ func (_BlockStorage *BlockStorageFilterer) ParseTargetDifficultySet(log types.Lo event.Raw = log return event, nil } + diff --git a/integration/xenblocks/contracts/votemanager/votemanager.go b/integration/xenblocks/contracts/votemanager/votemanager.go new file mode 100644 index 000000000..bfd6aabaa --- /dev/null +++ b/integration/xenblocks/contracts/votemanager/votemanager.go @@ -0,0 +1,1197 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package votemanager + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// VoteManagerPayload is an auto generated low-level Go binding around an user-defined struct. +type VoteManagerPayload struct { + HashId *big.Int + CurrencyType *big.Int +} + +// VotemanagerMetaData contains all meta data concerning the Votemanager contract. +var VotemanagerMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"name\":\"MintToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"blockStorage\",\"outputs\":[{\"internalType\":\"contractBlockStorage\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialSfcAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialBlockStorageAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"initialVotePercentage\",\"type\":\"uint8\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashId\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"newVotesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sfcLib\",\"outputs\":[{\"internalType\":\"contractSFCLib\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_validatorId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_validatorCount\",\"type\":\"uint256\"}],\"name\":\"shouldVote\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenRegistry\",\"outputs\":[{\"internalType\":\"contractTokenRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_blockStorageAddress\",\"type\":\"address\"}],\"name\":\"updateBlockStorageAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sfcLibAddress\",\"type\":\"address\"}],\"name\":\"updateSfcLibAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenRegistryAddress\",\"type\":\"address\"}],\"name\":\"updateTokenRegistryAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_votePercentage\",\"type\":\"uint8\"}],\"name\":\"updateVotePercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"validatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currencyType\",\"type\":\"uint256\"}],\"name\":\"vote\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"internalType\":\"structVoteManager.Payload[]\",\"name\":\"payload\",\"type\":\"tuple[]\"}],\"name\":\"voteBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"votePercentage\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"votesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorId\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +} + +// VotemanagerABI is the input ABI used to generate the binding from. +// Deprecated: Use VotemanagerMetaData.ABI instead. +var VotemanagerABI = VotemanagerMetaData.ABI + +// Votemanager is an auto generated Go binding around an Ethereum contract. +type Votemanager struct { + VotemanagerCaller // Read-only binding to the contract + VotemanagerTransactor // Write-only binding to the contract + VotemanagerFilterer // Log filterer for contract events +} + +// VotemanagerCaller is an auto generated read-only Go binding around an Ethereum contract. +type VotemanagerCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// VotemanagerTransactor is an auto generated write-only Go binding around an Ethereum contract. +type VotemanagerTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// VotemanagerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type VotemanagerFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// VotemanagerSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type VotemanagerSession struct { + Contract *Votemanager // 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 +} + +// VotemanagerCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type VotemanagerCallerSession struct { + Contract *VotemanagerCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// VotemanagerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type VotemanagerTransactorSession struct { + Contract *VotemanagerTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// VotemanagerRaw is an auto generated low-level Go binding around an Ethereum contract. +type VotemanagerRaw struct { + Contract *Votemanager // Generic contract binding to access the raw methods on +} + +// VotemanagerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type VotemanagerCallerRaw struct { + Contract *VotemanagerCaller // Generic read-only contract binding to access the raw methods on +} + +// VotemanagerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type VotemanagerTransactorRaw struct { + Contract *VotemanagerTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewVotemanager creates a new instance of Votemanager, bound to a specific deployed contract. +func NewVotemanager(address common.Address, backend bind.ContractBackend) (*Votemanager, error) { + contract, err := bindVotemanager(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Votemanager{VotemanagerCaller: VotemanagerCaller{contract: contract}, VotemanagerTransactor: VotemanagerTransactor{contract: contract}, VotemanagerFilterer: VotemanagerFilterer{contract: contract}}, nil +} + +// NewVotemanagerCaller creates a new read-only instance of Votemanager, bound to a specific deployed contract. +func NewVotemanagerCaller(address common.Address, caller bind.ContractCaller) (*VotemanagerCaller, error) { + contract, err := bindVotemanager(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VotemanagerCaller{contract: contract}, nil +} + +// NewVotemanagerTransactor creates a new write-only instance of Votemanager, bound to a specific deployed contract. +func NewVotemanagerTransactor(address common.Address, transactor bind.ContractTransactor) (*VotemanagerTransactor, error) { + contract, err := bindVotemanager(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VotemanagerTransactor{contract: contract}, nil +} + +// NewVotemanagerFilterer creates a new log filterer instance of Votemanager, bound to a specific deployed contract. +func NewVotemanagerFilterer(address common.Address, filterer bind.ContractFilterer) (*VotemanagerFilterer, error) { + contract, err := bindVotemanager(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VotemanagerFilterer{contract: contract}, nil +} + +// bindVotemanager binds a generic wrapper to an already deployed contract. +func bindVotemanager(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(VotemanagerABI)) + 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 (_Votemanager *VotemanagerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Votemanager.Contract.VotemanagerCaller.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 (_Votemanager *VotemanagerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Votemanager.Contract.VotemanagerTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Votemanager *VotemanagerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Votemanager.Contract.VotemanagerTransactor.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 (_Votemanager *VotemanagerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Votemanager.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 (_Votemanager *VotemanagerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Votemanager.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Votemanager *VotemanagerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Votemanager.Contract.contract.Transact(opts, method, params...) +} + +// BlockStorage is a free data retrieval call binding the contract method 0x4a673e98. +// +// Solidity: function blockStorage() view returns(address) +func (_Votemanager *VotemanagerCaller) BlockStorage(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "blockStorage") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// BlockStorage is a free data retrieval call binding the contract method 0x4a673e98. +// +// Solidity: function blockStorage() view returns(address) +func (_Votemanager *VotemanagerSession) BlockStorage() (common.Address, error) { + return _Votemanager.Contract.BlockStorage(&_Votemanager.CallOpts) +} + +// BlockStorage is a free data retrieval call binding the contract method 0x4a673e98. +// +// Solidity: function blockStorage() view returns(address) +func (_Votemanager *VotemanagerCallerSession) BlockStorage() (common.Address, error) { + return _Votemanager.Contract.BlockStorage(&_Votemanager.CallOpts) +} + +// MintedByHashId is a free data retrieval call binding the contract method 0x9f4ee5af. +// +// Solidity: function mintedByHashId(uint256 ) view returns(bool) +func (_Votemanager *VotemanagerCaller) MintedByHashId(opts *bind.CallOpts, arg0 *big.Int) (bool, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "mintedByHashId", arg0) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// MintedByHashId is a free data retrieval call binding the contract method 0x9f4ee5af. +// +// Solidity: function mintedByHashId(uint256 ) view returns(bool) +func (_Votemanager *VotemanagerSession) MintedByHashId(arg0 *big.Int) (bool, error) { + return _Votemanager.Contract.MintedByHashId(&_Votemanager.CallOpts, arg0) +} + +// MintedByHashId is a free data retrieval call binding the contract method 0x9f4ee5af. +// +// Solidity: function mintedByHashId(uint256 ) view returns(bool) +func (_Votemanager *VotemanagerCallerSession) MintedByHashId(arg0 *big.Int) (bool, error) { + return _Votemanager.Contract.MintedByHashId(&_Votemanager.CallOpts, arg0) +} + +// NewVotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x0c1c9308. +// +// Solidity: function newVotesByHashIdAndCurrencyType(uint256 , uint256 ) view returns(uint16) +func (_Votemanager *VotemanagerCaller) NewVotesByHashIdAndCurrencyType(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (uint16, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "newVotesByHashIdAndCurrencyType", arg0, arg1) + + if err != nil { + return *new(uint16), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + + return out0, err + +} + +// NewVotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x0c1c9308. +// +// Solidity: function newVotesByHashIdAndCurrencyType(uint256 , uint256 ) view returns(uint16) +func (_Votemanager *VotemanagerSession) NewVotesByHashIdAndCurrencyType(arg0 *big.Int, arg1 *big.Int) (uint16, error) { + return _Votemanager.Contract.NewVotesByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) +} + +// NewVotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x0c1c9308. +// +// Solidity: function newVotesByHashIdAndCurrencyType(uint256 , uint256 ) view returns(uint16) +func (_Votemanager *VotemanagerCallerSession) NewVotesByHashIdAndCurrencyType(arg0 *big.Int, arg1 *big.Int) (uint16, error) { + return _Votemanager.Contract.NewVotesByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Votemanager *VotemanagerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Votemanager *VotemanagerSession) Owner() (common.Address, error) { + return _Votemanager.Contract.Owner(&_Votemanager.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Votemanager *VotemanagerCallerSession) Owner() (common.Address, error) { + return _Votemanager.Contract.Owner(&_Votemanager.CallOpts) +} + +// RequiredNumOfValidators is a free data retrieval call binding the contract method 0x5370c435. +// +// Solidity: function requiredNumOfValidators() view returns(uint256) +func (_Votemanager *VotemanagerCaller) RequiredNumOfValidators(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "requiredNumOfValidators") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// RequiredNumOfValidators is a free data retrieval call binding the contract method 0x5370c435. +// +// Solidity: function requiredNumOfValidators() view returns(uint256) +func (_Votemanager *VotemanagerSession) RequiredNumOfValidators() (*big.Int, error) { + return _Votemanager.Contract.RequiredNumOfValidators(&_Votemanager.CallOpts) +} + +// RequiredNumOfValidators is a free data retrieval call binding the contract method 0x5370c435. +// +// Solidity: function requiredNumOfValidators() view returns(uint256) +func (_Votemanager *VotemanagerCallerSession) RequiredNumOfValidators() (*big.Int, error) { + return _Votemanager.Contract.RequiredNumOfValidators(&_Votemanager.CallOpts) +} + +// SfcLib is a free data retrieval call binding the contract method 0x1ff9794b. +// +// Solidity: function sfcLib() view returns(address) +func (_Votemanager *VotemanagerCaller) SfcLib(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "sfcLib") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// SfcLib is a free data retrieval call binding the contract method 0x1ff9794b. +// +// Solidity: function sfcLib() view returns(address) +func (_Votemanager *VotemanagerSession) SfcLib() (common.Address, error) { + return _Votemanager.Contract.SfcLib(&_Votemanager.CallOpts) +} + +// SfcLib is a free data retrieval call binding the contract method 0x1ff9794b. +// +// Solidity: function sfcLib() view returns(address) +func (_Votemanager *VotemanagerCallerSession) SfcLib() (common.Address, error) { + return _Votemanager.Contract.SfcLib(&_Votemanager.CallOpts) +} + +// ShouldVote is a free data retrieval call binding the contract method 0xb1faefbb. +// +// Solidity: function shouldVote(uint256 _validatorId, uint256 _hashId, uint256 _validatorCount) pure returns(bool) +func (_Votemanager *VotemanagerCaller) ShouldVote(opts *bind.CallOpts, _validatorId *big.Int, _hashId *big.Int, _validatorCount *big.Int) (bool, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "shouldVote", _validatorId, _hashId, _validatorCount) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// ShouldVote is a free data retrieval call binding the contract method 0xb1faefbb. +// +// Solidity: function shouldVote(uint256 _validatorId, uint256 _hashId, uint256 _validatorCount) pure returns(bool) +func (_Votemanager *VotemanagerSession) ShouldVote(_validatorId *big.Int, _hashId *big.Int, _validatorCount *big.Int) (bool, error) { + return _Votemanager.Contract.ShouldVote(&_Votemanager.CallOpts, _validatorId, _hashId, _validatorCount) +} + +// ShouldVote is a free data retrieval call binding the contract method 0xb1faefbb. +// +// Solidity: function shouldVote(uint256 _validatorId, uint256 _hashId, uint256 _validatorCount) pure returns(bool) +func (_Votemanager *VotemanagerCallerSession) ShouldVote(_validatorId *big.Int, _hashId *big.Int, _validatorCount *big.Int) (bool, error) { + return _Votemanager.Contract.ShouldVote(&_Votemanager.CallOpts, _validatorId, _hashId, _validatorCount) +} + +// TokenRegistry is a free data retrieval call binding the contract method 0x9d23c4c7. +// +// Solidity: function tokenRegistry() view returns(address) +func (_Votemanager *VotemanagerCaller) TokenRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "tokenRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// TokenRegistry is a free data retrieval call binding the contract method 0x9d23c4c7. +// +// Solidity: function tokenRegistry() view returns(address) +func (_Votemanager *VotemanagerSession) TokenRegistry() (common.Address, error) { + return _Votemanager.Contract.TokenRegistry(&_Votemanager.CallOpts) +} + +// TokenRegistry is a free data retrieval call binding the contract method 0x9d23c4c7. +// +// Solidity: function tokenRegistry() view returns(address) +func (_Votemanager *VotemanagerCallerSession) TokenRegistry() (common.Address, error) { + return _Votemanager.Contract.TokenRegistry(&_Votemanager.CallOpts) +} + +// ValidatorCount is a free data retrieval call binding the contract method 0x0f43a677. +// +// Solidity: function validatorCount() view returns(uint256) +func (_Votemanager *VotemanagerCaller) ValidatorCount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "validatorCount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ValidatorCount is a free data retrieval call binding the contract method 0x0f43a677. +// +// Solidity: function validatorCount() view returns(uint256) +func (_Votemanager *VotemanagerSession) ValidatorCount() (*big.Int, error) { + return _Votemanager.Contract.ValidatorCount(&_Votemanager.CallOpts) +} + +// ValidatorCount is a free data retrieval call binding the contract method 0x0f43a677. +// +// Solidity: function validatorCount() view returns(uint256) +func (_Votemanager *VotemanagerCallerSession) ValidatorCount() (*big.Int, error) { + return _Votemanager.Contract.ValidatorCount(&_Votemanager.CallOpts) +} + +// VotePercentage is a free data retrieval call binding the contract method 0x34b502c0. +// +// Solidity: function votePercentage() view returns(uint8) +func (_Votemanager *VotemanagerCaller) VotePercentage(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "votePercentage") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// VotePercentage is a free data retrieval call binding the contract method 0x34b502c0. +// +// Solidity: function votePercentage() view returns(uint8) +func (_Votemanager *VotemanagerSession) VotePercentage() (uint8, error) { + return _Votemanager.Contract.VotePercentage(&_Votemanager.CallOpts) +} + +// VotePercentage is a free data retrieval call binding the contract method 0x34b502c0. +// +// Solidity: function votePercentage() view returns(uint8) +func (_Votemanager *VotemanagerCallerSession) VotePercentage() (uint8, error) { + return _Votemanager.Contract.VotePercentage(&_Votemanager.CallOpts) +} + +// VotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x770a9e50. +// +// Solidity: function votesByHashIdAndCurrencyType(uint256 , uint8 ) view returns(uint16) +func (_Votemanager *VotemanagerCaller) VotesByHashIdAndCurrencyType(opts *bind.CallOpts, arg0 *big.Int, arg1 uint8) (uint16, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "votesByHashIdAndCurrencyType", arg0, arg1) + + if err != nil { + return *new(uint16), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + + return out0, err + +} + +// VotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x770a9e50. +// +// Solidity: function votesByHashIdAndCurrencyType(uint256 , uint8 ) view returns(uint16) +func (_Votemanager *VotemanagerSession) VotesByHashIdAndCurrencyType(arg0 *big.Int, arg1 uint8) (uint16, error) { + return _Votemanager.Contract.VotesByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) +} + +// VotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x770a9e50. +// +// Solidity: function votesByHashIdAndCurrencyType(uint256 , uint8 ) view returns(uint16) +func (_Votemanager *VotemanagerCallerSession) VotesByHashIdAndCurrencyType(arg0 *big.Int, arg1 uint8) (uint16, error) { + return _Votemanager.Contract.VotesByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) +} + +// VotesByHashIdAndValidatorId is a free data retrieval call binding the contract method 0x6da2b74b. +// +// Solidity: function votesByHashIdAndValidatorId(uint256 , uint256 ) view returns(bool) +func (_Votemanager *VotemanagerCaller) VotesByHashIdAndValidatorId(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (bool, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "votesByHashIdAndValidatorId", arg0, arg1) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// VotesByHashIdAndValidatorId is a free data retrieval call binding the contract method 0x6da2b74b. +// +// Solidity: function votesByHashIdAndValidatorId(uint256 , uint256 ) view returns(bool) +func (_Votemanager *VotemanagerSession) VotesByHashIdAndValidatorId(arg0 *big.Int, arg1 *big.Int) (bool, error) { + return _Votemanager.Contract.VotesByHashIdAndValidatorId(&_Votemanager.CallOpts, arg0, arg1) +} + +// VotesByHashIdAndValidatorId is a free data retrieval call binding the contract method 0x6da2b74b. +// +// Solidity: function votesByHashIdAndValidatorId(uint256 , uint256 ) view returns(bool) +func (_Votemanager *VotemanagerCallerSession) VotesByHashIdAndValidatorId(arg0 *big.Int, arg1 *big.Int) (bool, error) { + return _Votemanager.Contract.VotesByHashIdAndValidatorId(&_Votemanager.CallOpts, arg0, arg1) +} + +// Initialize is a paid mutator transaction binding the contract method 0x3073cecf. +// +// Solidity: function initialize(address initialOwner, address initialSfcAddress, address initialBlockStorageAddress, uint8 initialVotePercentage) returns() +func (_Votemanager *VotemanagerTransactor) Initialize(opts *bind.TransactOpts, initialOwner common.Address, initialSfcAddress common.Address, initialBlockStorageAddress common.Address, initialVotePercentage uint8) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "initialize", initialOwner, initialSfcAddress, initialBlockStorageAddress, initialVotePercentage) +} + +// Initialize is a paid mutator transaction binding the contract method 0x3073cecf. +// +// Solidity: function initialize(address initialOwner, address initialSfcAddress, address initialBlockStorageAddress, uint8 initialVotePercentage) returns() +func (_Votemanager *VotemanagerSession) Initialize(initialOwner common.Address, initialSfcAddress common.Address, initialBlockStorageAddress common.Address, initialVotePercentage uint8) (*types.Transaction, error) { + return _Votemanager.Contract.Initialize(&_Votemanager.TransactOpts, initialOwner, initialSfcAddress, initialBlockStorageAddress, initialVotePercentage) +} + +// Initialize is a paid mutator transaction binding the contract method 0x3073cecf. +// +// Solidity: function initialize(address initialOwner, address initialSfcAddress, address initialBlockStorageAddress, uint8 initialVotePercentage) returns() +func (_Votemanager *VotemanagerTransactorSession) Initialize(initialOwner common.Address, initialSfcAddress common.Address, initialBlockStorageAddress common.Address, initialVotePercentage uint8) (*types.Transaction, error) { + return _Votemanager.Contract.Initialize(&_Votemanager.TransactOpts, initialOwner, initialSfcAddress, initialBlockStorageAddress, initialVotePercentage) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Votemanager *VotemanagerTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "renounceOwnership") +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Votemanager *VotemanagerSession) RenounceOwnership() (*types.Transaction, error) { + return _Votemanager.Contract.RenounceOwnership(&_Votemanager.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Votemanager *VotemanagerTransactorSession) RenounceOwnership() (*types.Transaction, error) { + return _Votemanager.Contract.RenounceOwnership(&_Votemanager.TransactOpts) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Votemanager *VotemanagerTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "transferOwnership", newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Votemanager *VotemanagerSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.TransferOwnership(&_Votemanager.TransactOpts, newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Votemanager *VotemanagerTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.TransferOwnership(&_Votemanager.TransactOpts, newOwner) +} + +// UpdateBlockStorageAddress is a paid mutator transaction binding the contract method 0x3cc66f46. +// +// Solidity: function updateBlockStorageAddress(address _blockStorageAddress) returns() +func (_Votemanager *VotemanagerTransactor) UpdateBlockStorageAddress(opts *bind.TransactOpts, _blockStorageAddress common.Address) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "updateBlockStorageAddress", _blockStorageAddress) +} + +// UpdateBlockStorageAddress is a paid mutator transaction binding the contract method 0x3cc66f46. +// +// Solidity: function updateBlockStorageAddress(address _blockStorageAddress) returns() +func (_Votemanager *VotemanagerSession) UpdateBlockStorageAddress(_blockStorageAddress common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateBlockStorageAddress(&_Votemanager.TransactOpts, _blockStorageAddress) +} + +// UpdateBlockStorageAddress is a paid mutator transaction binding the contract method 0x3cc66f46. +// +// Solidity: function updateBlockStorageAddress(address _blockStorageAddress) returns() +func (_Votemanager *VotemanagerTransactorSession) UpdateBlockStorageAddress(_blockStorageAddress common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateBlockStorageAddress(&_Votemanager.TransactOpts, _blockStorageAddress) +} + +// UpdateSfcLibAddress is a paid mutator transaction binding the contract method 0x9d138a3c. +// +// Solidity: function updateSfcLibAddress(address _sfcLibAddress) returns() +func (_Votemanager *VotemanagerTransactor) UpdateSfcLibAddress(opts *bind.TransactOpts, _sfcLibAddress common.Address) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "updateSfcLibAddress", _sfcLibAddress) +} + +// UpdateSfcLibAddress is a paid mutator transaction binding the contract method 0x9d138a3c. +// +// Solidity: function updateSfcLibAddress(address _sfcLibAddress) returns() +func (_Votemanager *VotemanagerSession) UpdateSfcLibAddress(_sfcLibAddress common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateSfcLibAddress(&_Votemanager.TransactOpts, _sfcLibAddress) +} + +// UpdateSfcLibAddress is a paid mutator transaction binding the contract method 0x9d138a3c. +// +// Solidity: function updateSfcLibAddress(address _sfcLibAddress) returns() +func (_Votemanager *VotemanagerTransactorSession) UpdateSfcLibAddress(_sfcLibAddress common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateSfcLibAddress(&_Votemanager.TransactOpts, _sfcLibAddress) +} + +// UpdateTokenRegistryAddress is a paid mutator transaction binding the contract method 0x520051d7. +// +// Solidity: function updateTokenRegistryAddress(address _tokenRegistryAddress) returns() +func (_Votemanager *VotemanagerTransactor) UpdateTokenRegistryAddress(opts *bind.TransactOpts, _tokenRegistryAddress common.Address) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "updateTokenRegistryAddress", _tokenRegistryAddress) +} + +// UpdateTokenRegistryAddress is a paid mutator transaction binding the contract method 0x520051d7. +// +// Solidity: function updateTokenRegistryAddress(address _tokenRegistryAddress) returns() +func (_Votemanager *VotemanagerSession) UpdateTokenRegistryAddress(_tokenRegistryAddress common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateTokenRegistryAddress(&_Votemanager.TransactOpts, _tokenRegistryAddress) +} + +// UpdateTokenRegistryAddress is a paid mutator transaction binding the contract method 0x520051d7. +// +// Solidity: function updateTokenRegistryAddress(address _tokenRegistryAddress) returns() +func (_Votemanager *VotemanagerTransactorSession) UpdateTokenRegistryAddress(_tokenRegistryAddress common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateTokenRegistryAddress(&_Votemanager.TransactOpts, _tokenRegistryAddress) +} + +// UpdateVotePercentage is a paid mutator transaction binding the contract method 0x8ba8405c. +// +// Solidity: function updateVotePercentage(uint8 _votePercentage) returns() +func (_Votemanager *VotemanagerTransactor) UpdateVotePercentage(opts *bind.TransactOpts, _votePercentage uint8) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "updateVotePercentage", _votePercentage) +} + +// UpdateVotePercentage is a paid mutator transaction binding the contract method 0x8ba8405c. +// +// Solidity: function updateVotePercentage(uint8 _votePercentage) returns() +func (_Votemanager *VotemanagerSession) UpdateVotePercentage(_votePercentage uint8) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateVotePercentage(&_Votemanager.TransactOpts, _votePercentage) +} + +// UpdateVotePercentage is a paid mutator transaction binding the contract method 0x8ba8405c. +// +// Solidity: function updateVotePercentage(uint8 _votePercentage) returns() +func (_Votemanager *VotemanagerTransactorSession) UpdateVotePercentage(_votePercentage uint8) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateVotePercentage(&_Votemanager.TransactOpts, _votePercentage) +} + +// Vote is a paid mutator transaction binding the contract method 0xb384abef. +// +// Solidity: function vote(uint256 _hashId, uint256 _currencyType) returns() +func (_Votemanager *VotemanagerTransactor) Vote(opts *bind.TransactOpts, _hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "vote", _hashId, _currencyType) +} + +// Vote is a paid mutator transaction binding the contract method 0xb384abef. +// +// Solidity: function vote(uint256 _hashId, uint256 _currencyType) returns() +func (_Votemanager *VotemanagerSession) Vote(_hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { + return _Votemanager.Contract.Vote(&_Votemanager.TransactOpts, _hashId, _currencyType) +} + +// Vote is a paid mutator transaction binding the contract method 0xb384abef. +// +// Solidity: function vote(uint256 _hashId, uint256 _currencyType) returns() +func (_Votemanager *VotemanagerTransactorSession) Vote(_hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { + return _Votemanager.Contract.Vote(&_Votemanager.TransactOpts, _hashId, _currencyType) +} + +// VoteBatch is a paid mutator transaction binding the contract method 0xbceb2e60. +// +// Solidity: function voteBatch((uint256,uint256)[] payload) returns() +func (_Votemanager *VotemanagerTransactor) VoteBatch(opts *bind.TransactOpts, payload []VoteManagerPayload) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "voteBatch", payload) +} + +// VoteBatch is a paid mutator transaction binding the contract method 0xbceb2e60. +// +// Solidity: function voteBatch((uint256,uint256)[] payload) returns() +func (_Votemanager *VotemanagerSession) VoteBatch(payload []VoteManagerPayload) (*types.Transaction, error) { + return _Votemanager.Contract.VoteBatch(&_Votemanager.TransactOpts, payload) +} + +// VoteBatch is a paid mutator transaction binding the contract method 0xbceb2e60. +// +// Solidity: function voteBatch((uint256,uint256)[] payload) returns() +func (_Votemanager *VotemanagerTransactorSession) VoteBatch(payload []VoteManagerPayload) (*types.Transaction, error) { + return _Votemanager.Contract.VoteBatch(&_Votemanager.TransactOpts, payload) +} + +// VotemanagerInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the Votemanager contract. +type VotemanagerInitializedIterator struct { + Event *VotemanagerInitialized // 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 *VotemanagerInitializedIterator) 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(VotemanagerInitialized) + 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(VotemanagerInitialized) + 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 *VotemanagerInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *VotemanagerInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// VotemanagerInitialized represents a Initialized event raised by the Votemanager contract. +type VotemanagerInitialized struct { + Version uint64 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2. +// +// Solidity: event Initialized(uint64 version) +func (_Votemanager *VotemanagerFilterer) FilterInitialized(opts *bind.FilterOpts) (*VotemanagerInitializedIterator, error) { + + logs, sub, err := _Votemanager.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &VotemanagerInitializedIterator{contract: _Votemanager.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2. +// +// Solidity: event Initialized(uint64 version) +func (_Votemanager *VotemanagerFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *VotemanagerInitialized) (event.Subscription, error) { + + logs, sub, err := _Votemanager.contract.WatchLogs(opts, "Initialized") + 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(VotemanagerInitialized) + if err := _Votemanager.contract.UnpackLog(event, "Initialized", 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 +} + +// ParseInitialized is a log parse operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2. +// +// Solidity: event Initialized(uint64 version) +func (_Votemanager *VotemanagerFilterer) ParseInitialized(log types.Log) (*VotemanagerInitialized, error) { + event := new(VotemanagerInitialized) + if err := _Votemanager.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// VotemanagerMintTokenIterator is returned from FilterMintToken and is used to iterate over the raw logs and unpacked data for MintToken events raised by the Votemanager contract. +type VotemanagerMintTokenIterator struct { + Event *VotemanagerMintToken // 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 *VotemanagerMintTokenIterator) 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(VotemanagerMintToken) + 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(VotemanagerMintToken) + 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 *VotemanagerMintTokenIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *VotemanagerMintTokenIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// VotemanagerMintToken represents a MintToken event raised by the Votemanager contract. +type VotemanagerMintToken struct { + HashId *big.Int + Account common.Address + CurrencyType *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMintToken is a free log retrieval operation binding the contract event 0x207f55ba01c4294fc34d3fa8c3c37cdc1863b4056044e4bb590d6d1aa9387136. +// +// Solidity: event MintToken(uint256 indexed hashId, address indexed account, uint256 indexed currencyType) +func (_Votemanager *VotemanagerFilterer) FilterMintToken(opts *bind.FilterOpts, hashId []*big.Int, account []common.Address, currencyType []*big.Int) (*VotemanagerMintTokenIterator, error) { + + var hashIdRule []interface{} + for _, hashIdItem := range hashId { + hashIdRule = append(hashIdRule, hashIdItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var currencyTypeRule []interface{} + for _, currencyTypeItem := range currencyType { + currencyTypeRule = append(currencyTypeRule, currencyTypeItem) + } + + logs, sub, err := _Votemanager.contract.FilterLogs(opts, "MintToken", hashIdRule, accountRule, currencyTypeRule) + if err != nil { + return nil, err + } + return &VotemanagerMintTokenIterator{contract: _Votemanager.contract, event: "MintToken", logs: logs, sub: sub}, nil +} + +// WatchMintToken is a free log subscription operation binding the contract event 0x207f55ba01c4294fc34d3fa8c3c37cdc1863b4056044e4bb590d6d1aa9387136. +// +// Solidity: event MintToken(uint256 indexed hashId, address indexed account, uint256 indexed currencyType) +func (_Votemanager *VotemanagerFilterer) WatchMintToken(opts *bind.WatchOpts, sink chan<- *VotemanagerMintToken, hashId []*big.Int, account []common.Address, currencyType []*big.Int) (event.Subscription, error) { + + var hashIdRule []interface{} + for _, hashIdItem := range hashId { + hashIdRule = append(hashIdRule, hashIdItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var currencyTypeRule []interface{} + for _, currencyTypeItem := range currencyType { + currencyTypeRule = append(currencyTypeRule, currencyTypeItem) + } + + logs, sub, err := _Votemanager.contract.WatchLogs(opts, "MintToken", hashIdRule, accountRule, currencyTypeRule) + 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(VotemanagerMintToken) + if err := _Votemanager.contract.UnpackLog(event, "MintToken", 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 +} + +// ParseMintToken is a log parse operation binding the contract event 0x207f55ba01c4294fc34d3fa8c3c37cdc1863b4056044e4bb590d6d1aa9387136. +// +// Solidity: event MintToken(uint256 indexed hashId, address indexed account, uint256 indexed currencyType) +func (_Votemanager *VotemanagerFilterer) ParseMintToken(log types.Log) (*VotemanagerMintToken, error) { + event := new(VotemanagerMintToken) + if err := _Votemanager.contract.UnpackLog(event, "MintToken", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// VotemanagerOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Votemanager contract. +type VotemanagerOwnershipTransferredIterator struct { + Event *VotemanagerOwnershipTransferred // 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 *VotemanagerOwnershipTransferredIterator) 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(VotemanagerOwnershipTransferred) + 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(VotemanagerOwnershipTransferred) + 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 *VotemanagerOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *VotemanagerOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// VotemanagerOwnershipTransferred represents a OwnershipTransferred event raised by the Votemanager contract. +type VotemanagerOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Votemanager *VotemanagerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*VotemanagerOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Votemanager.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &VotemanagerOwnershipTransferredIterator{contract: _Votemanager.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Votemanager *VotemanagerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VotemanagerOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Votemanager.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + 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(VotemanagerOwnershipTransferred) + if err := _Votemanager.contract.UnpackLog(event, "OwnershipTransferred", 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 +} + +// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Votemanager *VotemanagerFilterer) ParseOwnershipTransferred(log types.Log) (*VotemanagerOwnershipTransferred, error) { + event := new(VotemanagerOwnershipTransferred) + if err := _Votemanager.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + diff --git a/integration/xenblocks/reporter/xenblocks.go b/integration/xenblocks/reporter/xenblocks.go index e4357b86c..854646721 100644 --- a/integration/xenblocks/reporter/xenblocks.go +++ b/integration/xenblocks/reporter/xenblocks.go @@ -2,6 +2,7 @@ package reporter import ( "encoding/json" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/gorilla/websocket" @@ -10,9 +11,10 @@ import ( ) type Config struct { - Endpoint string - Enabled bool - ForceVerifier bool + Endpoint string + Enabled bool + ForceVerifier bool + VerifierAddress common.Address } type Reporter struct { diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index cb85a6507..20b23289a 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -3,6 +3,8 @@ package verifier import ( "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" "github.com/Fantom-foundation/lachesis-base/inter/idx" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/event" @@ -13,8 +15,10 @@ import ( ) const ( - numOfWorkers = 3 + numOfWorkers = 1 backlog = 5 + + blockStorageAddr = "0x41B88573aD2A3245f7AD01e68dEb051BCC3dd73E" ) type EventListener struct { @@ -28,15 +32,21 @@ type EventListener struct { conn *ethclient.Client sub event.Subscription verifier *Verifier + ks *keystore.KeyStore + account accounts.Account + chainId uint64 } -func NewEventListener(stack *node.Node, validatorId idx.ValidatorID) *EventListener { +func NewEventListener(stack *node.Node, validatorId idx.ValidatorID, ks *keystore.KeyStore, account accounts.Account, chainId uint64) *EventListener { return &EventListener{ enabled: false, stack: stack, numOfWorkers: numOfWorkers, backlog: backlog, validatorId: uint32(validatorId), + ks: ks, + account: account, + chainId: chainId, } } @@ -47,6 +57,10 @@ func (e *EventListener) Start() { var err error + if err != nil { + panic(err) + } + rpc, err := e.stack.Attach() if err != nil { panic(err) @@ -67,7 +81,7 @@ func (e *EventListener) Start() { go e.worker(e.eventChannel) } - e.verifier = NewVerifier(e.validatorId, e.conn, e.bs) + e.verifier = NewVerifier(e.validatorId, e.conn, e.bs, e.ks, e.account, e.chainId) // Start a goroutine which watches new events go func() { diff --git a/integration/xenblocks/verifier/targets.go b/integration/xenblocks/verifier/targets.go index 9e7012821..b8e24ea6e 100644 --- a/integration/xenblocks/verifier/targets.go +++ b/integration/xenblocks/verifier/targets.go @@ -9,7 +9,7 @@ import ( type Token struct { name string - currencyCode int + currencyCode uint8 value int } diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 873c8e268..e9a80639c 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -10,7 +10,9 @@ import ( "github.com/Fantom-foundation/go-opera/gossip/contract/sfclib100" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" "github.com/Fantom-foundation/go-opera/opera/contracts/sfc" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/event" @@ -28,7 +30,6 @@ const ( hashLen = 64 validatorsFactor = 0.2 pattern1Salt = "WEVOMTAwODIwMjJYRU4" - blockStorageAddr = "0x23213196F7d13153a906c456f5a1008E23EA94bA" ) type Verifier struct { @@ -43,9 +44,11 @@ type Verifier struct { conn *ethclient.Client sub event.Subscription validatorCountLRU *lru.Cache + voter *Voter + chainId uint64 } -func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.BlockStorage) *Verifier { +func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.BlockStorage, ks *keystore.KeyStore, account accounts.Account, chainId uint64) *Verifier { validatorCountLRU, err := lru.New(100) if err != nil { panic(err) @@ -56,6 +59,8 @@ func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.B panic(err) } + voter := NewVoter(conn, ks, account, chainId) + return &Verifier{ enabled: false, numOfWorkers: numOfWorkers, @@ -65,6 +70,8 @@ func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.B validatorCountLRU: validatorCountLRU, sfcLib: sfcLib, bs: bs, + voter: voter, + chainId: chainId, } } @@ -99,10 +106,10 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { return } - if !v.verifyDifficultly(dr.M, event.Raw.BlockNumber) { - log.Warn("Difficulty too low", "hash", argon2Result, "hashId", event.HashId) - return - } + //if !v.verifyDifficultly(dr.M, event.Raw.BlockNumber) { + // log.Warn("Difficulty too low", "hash", argon2Result, "hashId", event.HashId) + // return + //} tokens := FindTokensFromHash(argon2Result, blockTime) if len(tokens) == 0 { @@ -113,6 +120,10 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { log.Info("hash verified", "hash", argon2Result, "tokens", tokens, "hashId", event.HashId) // TODO: vote for each hash + for _, token := range tokens { + cc := big.NewInt(int64(token.currencyCode)) + v.voter.AddToQueue(event.HashId, cc) + } } func argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, key []byte) (string, error) { diff --git a/integration/xenblocks/verifier/voter.go b/integration/xenblocks/verifier/voter.go new file mode 100644 index 000000000..0dd1158c3 --- /dev/null +++ b/integration/xenblocks/verifier/voter.go @@ -0,0 +1,96 @@ +package verifier + +import ( + "context" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/votemanager" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "math/big" + "time" +) + +var ( + voteManagerAddr = common.HexToAddress("0x84B3519B57E8017324F082d2e0F0C95051687aE2") + BATCH_SIZE = 50 + GAS_LIMIT = uint64(8000000) +) + +type Voter struct { + vm *votemanager.Votemanager + conn *ethclient.Client + queue []votemanager.VoteManagerPayload + ks *keystore.KeyStore + account accounts.Account + chainId uint64 +} + +func NewVoter(conn *ethclient.Client, ks *keystore.KeyStore, account accounts.Account, chainId uint64) *Voter { + vm, err := votemanager.NewVotemanager(voteManagerAddr, conn) + if err != nil { + panic(err) + } + + var queue []votemanager.VoteManagerPayload + + return &Voter{ + vm: vm, + conn: conn, + queue: queue, + account: account, + ks: ks, + chainId: chainId, + } +} +func (v *Voter) waitTxConfirmed(hash common.Hash) <-chan *types.Transaction { + ch := make(chan *types.Transaction) + go func() { + for { + tx, pending, _ := v.conn.TransactionByHash(context.TODO(), hash) + if !pending { + ch <- tx + } + + time.Sleep(time.Millisecond * 500) + } + }() + + return ch +} + +func (v *Voter) AddToQueue(hashId *big.Int, currencyType *big.Int) { + v.queue = append(v.queue, votemanager.VoteManagerPayload{HashId: hashId, CurrencyType: currencyType}) + + if len(v.queue) >= BATCH_SIZE { + _ = v.Vote() + v.queue = []votemanager.VoteManagerPayload{} + } +} + +func (v *Voter) Vote() error { + log.Info("voting now!", "queue", len(v.queue)) + + chainId := new(big.Int).SetUint64(v.chainId) + auth, err := bind.NewKeyStoreTransactorWithChainID(v.ks, v.account, chainId) + if err != nil { + panic(err) + } + + auth.GasTipCap, _ = v.conn.SuggestGasTipCap(context.TODO()) + auth.GasFeeCap, _ = v.conn.SuggestGasPrice(context.TODO()) + auth.GasLimit = GAS_LIMIT + + tx, err := v.vm.VoteBatch(auth, v.queue) + if err != nil { + log.Error("vote error", "err", err) + } + + v.waitTxConfirmed(tx.Hash()) + log.Info("vote success!", "tx", tx.Hash().Hex()) + + return nil +} From ff974e59a4d419bd56543a163c42ee87d1b26387 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Fri, 15 Dec 2023 14:19:33 -0800 Subject: [PATCH 23/34] move voter into event listener --- .../xenblocks/verifier/event_listener.go | 9 ++++- integration/xenblocks/verifier/verifier.go | 37 +++++++------------ integration/xenblocks/verifier/voter.go | 13 ++++--- 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index 20b23289a..429958e20 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -35,6 +35,7 @@ type EventListener struct { ks *keystore.KeyStore account accounts.Account chainId uint64 + voter *Voter } func NewEventListener(stack *node.Node, validatorId idx.ValidatorID, ks *keystore.KeyStore, account accounts.Account, chainId uint64) *EventListener { @@ -81,7 +82,8 @@ func (e *EventListener) Start() { go e.worker(e.eventChannel) } - e.verifier = NewVerifier(e.validatorId, e.conn, e.bs, e.ks, e.account, e.chainId) + e.verifier = NewVerifier(e.validatorId, e.conn, e.bs) + e.voter = NewVoter(e.conn, e.ks, e.account, e.chainId) // Start a goroutine which watches new events go func() { @@ -105,7 +107,10 @@ func (e *EventListener) Start() { func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) { for evt := range events { - e.verifier.handleEvent(evt) + tokens := e.verifier.validateHashEvent(evt) + for _, token := range tokens { + e.voter.AddToQueue(evt.HashId, token.currencyCode) + } } } diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index e9a80639c..cbaa84c39 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -10,9 +10,7 @@ import ( "github.com/Fantom-foundation/go-opera/gossip/contract/sfclib100" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" "github.com/Fantom-foundation/go-opera/opera/contracts/sfc" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/event" @@ -44,11 +42,9 @@ type Verifier struct { conn *ethclient.Client sub event.Subscription validatorCountLRU *lru.Cache - voter *Voter - chainId uint64 } -func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.BlockStorage, ks *keystore.KeyStore, account accounts.Account, chainId uint64) *Verifier { +func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.BlockStorage) *Verifier { validatorCountLRU, err := lru.New(100) if err != nil { panic(err) @@ -59,8 +55,6 @@ func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.B panic(err) } - voter := NewVoter(conn, ks, account, chainId) - return &Verifier{ enabled: false, numOfWorkers: numOfWorkers, @@ -70,40 +64,40 @@ func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.B validatorCountLRU: validatorCountLRU, sfcLib: sfcLib, bs: bs, - voter: voter, - chainId: chainId, } } -func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { +func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) []Token { log.Debug("NewHash event received", "hashId", event.HashId, "epoch", event.Epoch, "account", event.Account) if !v.shouldVote(event.Raw.BlockNumber) { log.Debug("Not voting for this hash", "hash", event.Raw.BlockHash) - return + return nil } blockTime := v.getBlockTime(event.Raw.BlockHash) dr, err := v.bs.DecodeRecordBytes0(nil, event.HashId) if err != nil { - return + log.Warn("Failed to decode hash record", "err", err) + return nil } key := []byte(common.Bytes2Hex(dr.K[:])) argon2Result, err := argon2Hash(dr.C, dr.M, dr.T, dr.S, key) if err != nil { - panic(err) + log.Warn("Argon2 hash failed", "err", err) + return nil } if len(argon2Result) > 150 { log.Warn("Hash too long", "hash", argon2Result, "hashId", event.HashId) - return + return nil } if !validateSalt(dr.S) { log.Warn("Salt fails verification", "hash", argon2Result, "hashId", event.HashId) - return + return nil } //if !v.verifyDifficultly(dr.M, event.Raw.BlockNumber) { @@ -114,16 +108,11 @@ func (v *Verifier) handleEvent(event *block_storage.BlockStorageNewHash) { tokens := FindTokensFromHash(argon2Result, blockTime) if len(tokens) == 0 { log.Warn("No tokens found", "hash", argon2Result, "hashId", event.HashId) - return + return nil } log.Info("hash verified", "hash", argon2Result, "tokens", tokens, "hashId", event.HashId) - - // TODO: vote for each hash - for _, token := range tokens { - cc := big.NewInt(int64(token.currencyCode)) - v.voter.AddToQueue(event.HashId, cc) - } + return tokens } func argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, key []byte) (string, error) { @@ -220,13 +209,13 @@ func validatePattern2(salt string) bool { rawDecodedText, err := base64.StdEncoding.DecodeString(salt) if err != nil { - log.Warn("base64 decode error", "err", err, "salt", salt) + log.Warn("Base64 decode error", "err", err, "salt", salt) return false } decodedStr := hex.EncodeToString(rawDecodedText) if !common.IsHexAddress(decodedStr) { - log.Warn("decoded string is not a valid hash", "decodedStr", decodedStr) + log.Warn("Decoded string is not a valid hash", "decodedStr", decodedStr) return false } diff --git a/integration/xenblocks/verifier/voter.go b/integration/xenblocks/verifier/voter.go index 0dd1158c3..70cf04e1d 100644 --- a/integration/xenblocks/verifier/voter.go +++ b/integration/xenblocks/verifier/voter.go @@ -16,8 +16,8 @@ import ( var ( voteManagerAddr = common.HexToAddress("0x84B3519B57E8017324F082d2e0F0C95051687aE2") - BATCH_SIZE = 50 - GAS_LIMIT = uint64(8000000) + BatchSize = 50 + GasLimit = uint64(8000000) ) type Voter struct { @@ -62,10 +62,11 @@ func (v *Voter) waitTxConfirmed(hash common.Hash) <-chan *types.Transaction { return ch } -func (v *Voter) AddToQueue(hashId *big.Int, currencyType *big.Int) { - v.queue = append(v.queue, votemanager.VoteManagerPayload{HashId: hashId, CurrencyType: currencyType}) +func (v *Voter) AddToQueue(hashId *big.Int, currencyType uint8) { + cc := big.NewInt(int64(currencyType)) + v.queue = append(v.queue, votemanager.VoteManagerPayload{HashId: hashId, CurrencyType: cc}) - if len(v.queue) >= BATCH_SIZE { + if len(v.queue) >= BatchSize { _ = v.Vote() v.queue = []votemanager.VoteManagerPayload{} } @@ -82,7 +83,7 @@ func (v *Voter) Vote() error { auth.GasTipCap, _ = v.conn.SuggestGasTipCap(context.TODO()) auth.GasFeeCap, _ = v.conn.SuggestGasPrice(context.TODO()) - auth.GasLimit = GAS_LIMIT + auth.GasLimit = GasLimit tx, err := v.vm.VoteBatch(auth, v.queue) if err != nil { From f2ceac54f10ffdfddbbe073c4349ae42bda1cc16 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Mon, 18 Dec 2023 08:42:35 -0800 Subject: [PATCH 24/34] update blockstore contract. refactor voter. add mutex --- .../contracts/votemanager/votemanager.go | 227 +++++++++++++++++- .../xenblocks/verifier/event_listener.go | 38 ++- integration/xenblocks/verifier/voter.go | 6 +- 3 files changed, 248 insertions(+), 23 deletions(-) diff --git a/integration/xenblocks/contracts/votemanager/votemanager.go b/integration/xenblocks/contracts/votemanager/votemanager.go index bfd6aabaa..3caeb8db0 100644 --- a/integration/xenblocks/contracts/votemanager/votemanager.go +++ b/integration/xenblocks/contracts/votemanager/votemanager.go @@ -36,7 +36,7 @@ type VoteManagerPayload struct { // VotemanagerMetaData contains all meta data concerning the Votemanager contract. var VotemanagerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"name\":\"MintToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"blockStorage\",\"outputs\":[{\"internalType\":\"contractBlockStorage\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialSfcAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialBlockStorageAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"initialVotePercentage\",\"type\":\"uint8\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashId\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"newVotesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sfcLib\",\"outputs\":[{\"internalType\":\"contractSFCLib\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_validatorId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_validatorCount\",\"type\":\"uint256\"}],\"name\":\"shouldVote\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenRegistry\",\"outputs\":[{\"internalType\":\"contractTokenRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_blockStorageAddress\",\"type\":\"address\"}],\"name\":\"updateBlockStorageAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sfcLibAddress\",\"type\":\"address\"}],\"name\":\"updateSfcLibAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenRegistryAddress\",\"type\":\"address\"}],\"name\":\"updateTokenRegistryAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_votePercentage\",\"type\":\"uint8\"}],\"name\":\"updateVotePercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"validatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currencyType\",\"type\":\"uint256\"}],\"name\":\"vote\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"internalType\":\"structVoteManager.Payload[]\",\"name\":\"payload\",\"type\":\"tuple[]\"}],\"name\":\"voteBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"votePercentage\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"votesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorId\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"name\":\"MintToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"votes\",\"type\":\"uint16\"}],\"name\":\"VoteToken\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"blockStorage\",\"outputs\":[{\"internalType\":\"contractBlockStorage\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialSfcAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialBlockStorageAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"initialVotePercentage\",\"type\":\"uint8\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashId\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"newVotesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sfcLib\",\"outputs\":[{\"internalType\":\"contractSFCLib\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_validatorId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_validatorCount\",\"type\":\"uint256\"}],\"name\":\"shouldVote\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenRegistry\",\"outputs\":[{\"internalType\":\"contractTokenRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_blockStorageAddress\",\"type\":\"address\"}],\"name\":\"updateBlockStorageAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sfcLibAddress\",\"type\":\"address\"}],\"name\":\"updateSfcLibAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenRegistryAddress\",\"type\":\"address\"}],\"name\":\"updateTokenRegistryAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_votePercentage\",\"type\":\"uint8\"}],\"name\":\"updateVotePercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"validatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currencyType\",\"type\":\"uint256\"}],\"name\":\"vote\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"internalType\":\"structVoteManager.Payload[]\",\"name\":\"payload\",\"type\":\"tuple[]\"}],\"name\":\"voteBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"votePercentage\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"votesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorId\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } // VotemanagerABI is the input ABI used to generate the binding from. @@ -247,6 +247,37 @@ func (_Votemanager *VotemanagerCallerSession) MintedByHashId(arg0 *big.Int) (boo return _Votemanager.Contract.MintedByHashId(&_Votemanager.CallOpts, arg0) } +// MintedByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x47ce239d. +// +// Solidity: function mintedByHashIdAndCurrencyType(uint256 , uint256 ) view returns(bool) +func (_Votemanager *VotemanagerCaller) MintedByHashIdAndCurrencyType(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (bool, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "mintedByHashIdAndCurrencyType", arg0, arg1) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// MintedByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x47ce239d. +// +// Solidity: function mintedByHashIdAndCurrencyType(uint256 , uint256 ) view returns(bool) +func (_Votemanager *VotemanagerSession) MintedByHashIdAndCurrencyType(arg0 *big.Int, arg1 *big.Int) (bool, error) { + return _Votemanager.Contract.MintedByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) +} + +// MintedByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x47ce239d. +// +// Solidity: function mintedByHashIdAndCurrencyType(uint256 , uint256 ) view returns(bool) +func (_Votemanager *VotemanagerCallerSession) MintedByHashIdAndCurrencyType(arg0 *big.Int, arg1 *big.Int) (bool, error) { + return _Votemanager.Contract.MintedByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) +} + // NewVotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x0c1c9308. // // Solidity: function newVotesByHashIdAndCurrencyType(uint256 , uint256 ) view returns(uint16) @@ -557,6 +588,37 @@ func (_Votemanager *VotemanagerCallerSession) VotesByHashIdAndValidatorId(arg0 * return _Votemanager.Contract.VotesByHashIdAndValidatorId(&_Votemanager.CallOpts, arg0, arg1) } +// VotesByHashIdAndValidatorIdAndCurrencyType is a free data retrieval call binding the contract method 0x95c6286c. +// +// Solidity: function votesByHashIdAndValidatorIdAndCurrencyType(uint256 , uint256 , uint256 ) view returns(bool) +func (_Votemanager *VotemanagerCaller) VotesByHashIdAndValidatorIdAndCurrencyType(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int, arg2 *big.Int) (bool, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "votesByHashIdAndValidatorIdAndCurrencyType", arg0, arg1, arg2) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// VotesByHashIdAndValidatorIdAndCurrencyType is a free data retrieval call binding the contract method 0x95c6286c. +// +// Solidity: function votesByHashIdAndValidatorIdAndCurrencyType(uint256 , uint256 , uint256 ) view returns(bool) +func (_Votemanager *VotemanagerSession) VotesByHashIdAndValidatorIdAndCurrencyType(arg0 *big.Int, arg1 *big.Int, arg2 *big.Int) (bool, error) { + return _Votemanager.Contract.VotesByHashIdAndValidatorIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1, arg2) +} + +// VotesByHashIdAndValidatorIdAndCurrencyType is a free data retrieval call binding the contract method 0x95c6286c. +// +// Solidity: function votesByHashIdAndValidatorIdAndCurrencyType(uint256 , uint256 , uint256 ) view returns(bool) +func (_Votemanager *VotemanagerCallerSession) VotesByHashIdAndValidatorIdAndCurrencyType(arg0 *big.Int, arg1 *big.Int, arg2 *big.Int) (bool, error) { + return _Votemanager.Contract.VotesByHashIdAndValidatorIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1, arg2) +} + // Initialize is a paid mutator transaction binding the contract method 0x3073cecf. // // Solidity: function initialize(address initialOwner, address initialSfcAddress, address initialBlockStorageAddress, uint8 initialVotePercentage) returns() @@ -1195,3 +1257,166 @@ func (_Votemanager *VotemanagerFilterer) ParseOwnershipTransferred(log types.Log return event, nil } +// VotemanagerVoteTokenIterator is returned from FilterVoteToken and is used to iterate over the raw logs and unpacked data for VoteToken events raised by the Votemanager contract. +type VotemanagerVoteTokenIterator struct { + Event *VotemanagerVoteToken // 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 *VotemanagerVoteTokenIterator) 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(VotemanagerVoteToken) + 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(VotemanagerVoteToken) + 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 *VotemanagerVoteTokenIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *VotemanagerVoteTokenIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// VotemanagerVoteToken represents a VoteToken event raised by the Votemanager contract. +type VotemanagerVoteToken struct { + HashId *big.Int + ValidatorId *big.Int + CurrencyType *big.Int + Votes uint16 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterVoteToken is a free log retrieval operation binding the contract event 0x964a6dd8f4d3c3f266a1a580e00a7eacf0f3701286d408d2bb1583449f1943a1. +// +// Solidity: event VoteToken(uint256 indexed hashId, uint256 indexed validatorId, uint256 indexed currencyType, uint16 votes) +func (_Votemanager *VotemanagerFilterer) FilterVoteToken(opts *bind.FilterOpts, hashId []*big.Int, validatorId []*big.Int, currencyType []*big.Int) (*VotemanagerVoteTokenIterator, error) { + + var hashIdRule []interface{} + for _, hashIdItem := range hashId { + hashIdRule = append(hashIdRule, hashIdItem) + } + var validatorIdRule []interface{} + for _, validatorIdItem := range validatorId { + validatorIdRule = append(validatorIdRule, validatorIdItem) + } + var currencyTypeRule []interface{} + for _, currencyTypeItem := range currencyType { + currencyTypeRule = append(currencyTypeRule, currencyTypeItem) + } + + logs, sub, err := _Votemanager.contract.FilterLogs(opts, "VoteToken", hashIdRule, validatorIdRule, currencyTypeRule) + if err != nil { + return nil, err + } + return &VotemanagerVoteTokenIterator{contract: _Votemanager.contract, event: "VoteToken", logs: logs, sub: sub}, nil +} + +// WatchVoteToken is a free log subscription operation binding the contract event 0x964a6dd8f4d3c3f266a1a580e00a7eacf0f3701286d408d2bb1583449f1943a1. +// +// Solidity: event VoteToken(uint256 indexed hashId, uint256 indexed validatorId, uint256 indexed currencyType, uint16 votes) +func (_Votemanager *VotemanagerFilterer) WatchVoteToken(opts *bind.WatchOpts, sink chan<- *VotemanagerVoteToken, hashId []*big.Int, validatorId []*big.Int, currencyType []*big.Int) (event.Subscription, error) { + + var hashIdRule []interface{} + for _, hashIdItem := range hashId { + hashIdRule = append(hashIdRule, hashIdItem) + } + var validatorIdRule []interface{} + for _, validatorIdItem := range validatorId { + validatorIdRule = append(validatorIdRule, validatorIdItem) + } + var currencyTypeRule []interface{} + for _, currencyTypeItem := range currencyType { + currencyTypeRule = append(currencyTypeRule, currencyTypeItem) + } + + logs, sub, err := _Votemanager.contract.WatchLogs(opts, "VoteToken", hashIdRule, validatorIdRule, currencyTypeRule) + 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(VotemanagerVoteToken) + if err := _Votemanager.contract.UnpackLog(event, "VoteToken", 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 +} + +// ParseVoteToken is a log parse operation binding the contract event 0x964a6dd8f4d3c3f266a1a580e00a7eacf0f3701286d408d2bb1583449f1943a1. +// +// Solidity: event VoteToken(uint256 indexed hashId, uint256 indexed validatorId, uint256 indexed currencyType, uint16 votes) +func (_Votemanager *VotemanagerFilterer) ParseVoteToken(log types.Log) (*VotemanagerVoteToken, error) { + event := new(VotemanagerVoteToken) + if err := _Votemanager.contract.UnpackLog(event, "VoteToken", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index 429958e20..2f55af987 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -18,7 +18,7 @@ const ( numOfWorkers = 1 backlog = 5 - blockStorageAddr = "0x41B88573aD2A3245f7AD01e68dEb051BCC3dd73E" + blockStorageAddr = "0xb3753e9F40DD0Dfd039e8c4B12895e2f636693a2" ) type EventListener struct { @@ -56,23 +56,7 @@ func (e *EventListener) Start() { time.Sleep(5 * time.Second) e.enabled = true - var err error - - if err != nil { - panic(err) - } - - rpc, err := e.stack.Attach() - if err != nil { - panic(err) - } - e.conn = ethclient.NewClient(rpc) - - if err != nil { - panic(err) - } - - e.bs, err = block_storage.NewBlockStorage(common.HexToAddress(blockStorageAddr), e.conn) + err := e.initializeEventSystem() if err != nil { panic(err) } @@ -82,9 +66,6 @@ func (e *EventListener) Start() { go e.worker(e.eventChannel) } - e.verifier = NewVerifier(e.validatorId, e.conn, e.bs) - e.voter = NewVoter(e.conn, e.ks, e.account, e.chainId) - // Start a goroutine which watches new events go func() { e.sub, err = e.bs.WatchNewHash(nil, e.eventChannel, nil, nil, nil) @@ -105,6 +86,21 @@ func (e *EventListener) Start() { }() } +func (e *EventListener) initializeEventSystem() error { + rpc, err := e.stack.Attach() + if err != nil { + return err + } + + e.conn = ethclient.NewClient(rpc) + e.bs, err = block_storage.NewBlockStorage(common.HexToAddress(blockStorageAddr), e.conn) + + e.verifier = NewVerifier(e.validatorId, e.conn, e.bs) + e.voter = NewVoter(e.conn, e.ks, e.account, e.chainId) + + return err +} + func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) { for evt := range events { tokens := e.verifier.validateHashEvent(evt) diff --git a/integration/xenblocks/verifier/voter.go b/integration/xenblocks/verifier/voter.go index 70cf04e1d..3d40b86fa 100644 --- a/integration/xenblocks/verifier/voter.go +++ b/integration/xenblocks/verifier/voter.go @@ -11,11 +11,12 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "math/big" + "sync" "time" ) var ( - voteManagerAddr = common.HexToAddress("0x84B3519B57E8017324F082d2e0F0C95051687aE2") + voteManagerAddr = common.HexToAddress("0x9224c3121c050546Ba76960c00c8B7e26C1E7b33") BatchSize = 50 GasLimit = uint64(8000000) ) @@ -27,6 +28,7 @@ type Voter struct { ks *keystore.KeyStore account accounts.Account chainId uint64 + mu sync.Mutex } func NewVoter(conn *ethclient.Client, ks *keystore.KeyStore, account accounts.Account, chainId uint64) *Voter { @@ -66,6 +68,8 @@ func (v *Voter) AddToQueue(hashId *big.Int, currencyType uint8) { cc := big.NewInt(int64(currencyType)) v.queue = append(v.queue, votemanager.VoteManagerPayload{HashId: hashId, CurrencyType: cc}) + v.mu.Lock() + defer v.mu.Unlock() if len(v.queue) >= BatchSize { _ = v.Vote() v.queue = []votemanager.VoteManagerPayload{} From 735fd500ff2ff7eb0b78e10dc7b9113c648252e2 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Tue, 19 Dec 2023 13:26:19 -0800 Subject: [PATCH 25/34] WIP --- cmd/opera/launcher/launcher.go | 3 +- gossip/c_block_callbacks.go | 12 +- gossip/service.go | 9 +- .../xenblocks/verifier/event_listener.go | 114 +++++++++++------- 4 files changed, 87 insertions(+), 51 deletions(-) diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index eb4bbddc3..a4050ca56 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -290,6 +290,7 @@ func lachesisMain(ctx *cli.Context) error { cfg := makeAllConfigs(ctx) genesisStore := mayGetGenesisStore(ctx) node, _, nodeClose := makeNode(ctx, cfg, genesisStore) + log.Info("test1") defer nodeClose() startNode(ctx, node) node.Wait() @@ -383,7 +384,7 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( } return false } - svc, err := gossip.NewService(stack, cfg.Opera, gdb, blockProc, engine, dagIndex, newTxPool, haltCheck, xenblocksReporter) + svc, err := gossip.NewService(stack, cfg.Opera, gdb, blockProc, engine, dagIndex, newTxPool, haltCheck, xenblocksReporter, xbEventListener) if err != nil { utils.Fatalf("Failed to create the service: %v", err) } diff --git a/gossip/c_block_callbacks.go b/gossip/c_block_callbacks.go index 0f64dba8b..633010d44 100644 --- a/gossip/c_block_callbacks.go +++ b/gossip/c_block_callbacks.go @@ -3,6 +3,7 @@ package gossip import ( "fmt" "github.com/Fantom-foundation/go-opera/integration/xenblocks/reporter" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/verifier" "sort" "sync" "sync/atomic" @@ -76,6 +77,7 @@ func (s *Service) GetConsensusCallbacks() lachesis.ConsensusCallbacks { s.verWatcher, &s.bootstrapping, s.reporter, + s.eventListener, ), } } @@ -93,7 +95,8 @@ func consensusCallbackBeginBlockFn( emitters *[]*emitter.Emitter, verWatcher *verwatcher.VerWarcher, bootstrapping *bool, - xenblocks *reporter.Reporter, + xenblocksReporter *reporter.Reporter, + xenblocksEL *verifier.EventListener, ) lachesis.BeginBlockFn { return func(cBlock *lachesis.Block) lachesis.BlockCallbacks { if *bootstrapping { @@ -246,6 +249,7 @@ func consensusCallbackBeginBlockFn( txListener := blockProc.TxListenerModule.Start(blockCtx, bs, es, statedb) onNewLogAll := func(l *types.Log) { txListener.OnNewLog(l) + xenblocksEL.OnNewLog(l) // Note: it's possible for logs to get indexed twice by BR and block processing if verWatcher != nil { verWatcher.OnNewLog(l) @@ -449,12 +453,14 @@ func consensusCallbackBeginBlockFn( "age", utils.PrettyDuration(blockAge), "t", utils.PrettyDuration(now.Sub(start))) blockAgeGauge.Update(int64(blockAge.Nanoseconds())) - if xenblocks.Enabled { - xenblocks.Send( + if xenblocksReporter.Enabled { + xenblocksReporter.Send( fmt.Sprintf("%d", blockCtx.Idx), fmt.Sprintf("%s", block.Atropos), fmt.Sprintf("%s", utils.PrettyDuration(now.Sub(start)))) } + + xenblocksEL.OnNewBlock(uint64(blockCtx.Idx)) } if confirmedEvents.Len() != 0 { atomic.StoreUint32(blockBusyFlag, 1) diff --git a/gossip/service.go b/gossip/service.go index d9f7dafb8..e1b658ad4 100644 --- a/gossip/service.go +++ b/gossip/service.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "github.com/Fantom-foundation/go-opera/integration/xenblocks/reporter" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/verifier" "math/big" "math/rand" "sync" @@ -158,14 +159,14 @@ type Service struct { bootstrapping bool - reporter *reporter.Reporter - + reporter *reporter.Reporter + eventListener *verifier.EventListener logger.Instance } func NewService(stack *node.Node, config Config, store *Store, blockProc BlockProc, engine lachesis.Consensus, dagIndexer *vecmt.Index, newTxPool func(evmcore.StateReader) TxPool, - haltCheck func(oldEpoch, newEpoch idx.Epoch, age time.Time) bool, reporter *reporter.Reporter) (*Service, error) { + haltCheck func(oldEpoch, newEpoch idx.Epoch, age time.Time) bool, reporter *reporter.Reporter, listener *verifier.EventListener) (*Service, error) { if err := config.Validate(); err != nil { return nil, err } @@ -183,7 +184,7 @@ func NewService(stack *node.Node, config Config, store *Store, blockProc BlockPr svc.netRPCService = ethapi.NewPublicNetAPI(svc.p2pServer, store.GetRules().NetworkID) svc.haltCheck = haltCheck svc.reporter = reporter.Start(svc.p2pServer) - + svc.eventListener = listener return svc, nil } diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index 2f55af987..1d2e4c10c 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -6,48 +6,50 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" - "io" "time" ) const ( - numOfWorkers = 1 - backlog = 5 + numOfWorkers = 5 + backlog = 5000 blockStorageAddr = "0xb3753e9F40DD0Dfd039e8c4B12895e2f636693a2" ) type EventListener struct { - enabled bool - numOfWorkers int - backlog int - stack *node.Node - validatorId uint32 - bs *block_storage.BlockStorage - eventChannel chan *block_storage.BlockStorageNewHash - conn *ethclient.Client - sub event.Subscription - verifier *Verifier - ks *keystore.KeyStore - account accounts.Account - chainId uint64 - voter *Voter + enabled bool + numOfWorkers int + backlog int + stack *node.Node + validatorId uint32 + bs *block_storage.BlockStorage + eventChannel chan *block_storage.BlockStorageNewHash + conn *ethclient.Client + sub event.Subscription + verifier *Verifier + ks *keystore.KeyStore + account accounts.Account + chainId uint64 + voter *Voter + currentBlockNumber uint64 } func NewEventListener(stack *node.Node, validatorId idx.ValidatorID, ks *keystore.KeyStore, account accounts.Account, chainId uint64) *EventListener { return &EventListener{ - enabled: false, - stack: stack, - numOfWorkers: numOfWorkers, - backlog: backlog, - validatorId: uint32(validatorId), - ks: ks, - account: account, - chainId: chainId, + enabled: false, + stack: stack, + numOfWorkers: numOfWorkers, + backlog: backlog, + validatorId: uint32(validatorId), + ks: ks, + account: account, + chainId: chainId, + currentBlockNumber: 0, } } @@ -67,23 +69,23 @@ func (e *EventListener) Start() { } // Start a goroutine which watches new events - go func() { - e.sub, err = e.bs.WatchNewHash(nil, e.eventChannel, nil, nil, nil) - if err != nil { - panic(err) - } - - for { - select { - case err := <-e.sub.Err(): - if err != nil && err != io.EOF { - log.Error("Error in BlockStorage watcher", "err", err) - } - break - } - time.Sleep(time.Second) - } - }() + //go func() { + // e.sub, err = e.bs.WatchNewHash(nil, e.eventChannel, nil, nil, nil) + // if err != nil { + // panic(err) + // } + // + // for { + // select { + // case err := <-e.sub.Err(): + // if err != nil && err != io.EOF { + // log.Error("Error in BlockStorage watcher", "err", err) + // } + // break + // } + // time.Sleep(time.Second) + // } + //}() } func (e *EventListener) initializeEventSystem() error { @@ -101,8 +103,35 @@ func (e *EventListener) initializeEventSystem() error { return err } +func (e *EventListener) OnNewLog(l *types.Log) { + if l.Address == common.HexToAddress(blockStorageAddr) { + + evt, err := e.bs.ParseNewHash(*l) + if err != nil { + return + } + + //log.Info("NewHash event received", "hashId", evt.HashId, "epoch", evt.Epoch, "account", evt.Account) + e.eventChannel <- evt + } +} + +func (e *EventListener) OnNewBlock(blockNumber uint64) { + //log.Info("New block received", "blockNumber", blockNumber) + e.currentBlockNumber = blockNumber +} + func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) { for evt := range events { + // Wait for the block to be confirmed + for { + if evt.Raw.BlockNumber < e.currentBlockNumber { + break + } else { + log.Info("waiting for block to be confirmed", "blockNumber", evt.Raw.BlockNumber, "currentBlockNumber", e.currentBlockNumber) + time.Sleep(100 * time.Millisecond) + } + } tokens := e.verifier.validateHashEvent(evt) for _, token := range tokens { e.voter.AddToQueue(evt.HashId, token.currencyCode) @@ -113,7 +142,6 @@ func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) func (e *EventListener) Close() { if e.enabled { log.Info("Closing Block storage watcher") - e.sub.Unsubscribe() time.Sleep(time.Second) close(e.eventChannel) e.conn.Close() From 6cc2a031de402b23df39a5016ad1846a5527f813 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Tue, 19 Dec 2023 13:37:35 -0800 Subject: [PATCH 26/34] WIP --- integration/xenblocks/verifier/event_listener.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index 1d2e4c10c..d8a6189a0 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -104,6 +104,10 @@ func (e *EventListener) initializeEventSystem() error { } func (e *EventListener) OnNewLog(l *types.Log) { + if e.enabled == false { + return + } + if l.Address == common.HexToAddress(blockStorageAddr) { evt, err := e.bs.ParseNewHash(*l) @@ -117,6 +121,10 @@ func (e *EventListener) OnNewLog(l *types.Log) { } func (e *EventListener) OnNewBlock(blockNumber uint64) { + if e.enabled == false { + return + } + //log.Info("New block received", "blockNumber", blockNumber) e.currentBlockNumber = blockNumber } From 967ce377f26eb6d3da76ac774df95f255695a418 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Tue, 19 Dec 2023 15:19:11 -0800 Subject: [PATCH 27/34] decode record bytes in go --- integration/xenblocks/verifier/verifier.go | 33 ++++++++++++++-------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index cbaa84c39..06fb86233 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -77,14 +77,8 @@ func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) [ blockTime := v.getBlockTime(event.Raw.BlockHash) - dr, err := v.bs.DecodeRecordBytes0(nil, event.HashId) - if err != nil { - log.Warn("Failed to decode hash record", "err", err) - return nil - } - - key := []byte(common.Bytes2Hex(dr.K[:])) - argon2Result, err := argon2Hash(dr.C, dr.M, dr.T, dr.S, key) + parallelism, memory, iterations, _, salt, key := decodeRecordBytes(event.Bytes) + argon2Result, err := argon2Hash(parallelism, memory, iterations, salt, key) if err != nil { log.Warn("Argon2 hash failed", "err", err) return nil @@ -95,14 +89,14 @@ func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) [ return nil } - if !validateSalt(dr.S) { + if !validateSalt(salt) { log.Warn("Salt fails verification", "hash", argon2Result, "hashId", event.HashId) return nil } - //if !v.verifyDifficultly(dr.M, event.Raw.BlockNumber) { + //if !v.verifyDifficultly(memory, event.Raw.BlockNumber) { // log.Warn("Difficulty too low", "hash", argon2Result, "hashId", event.HashId) - // return + // return nil //} tokens := FindTokensFromHash(argon2Result, blockTime) @@ -230,3 +224,20 @@ func validateSalt(s []byte) bool { return validatePattern2(salt) } + +func decodeRecordBytes(data []byte) (parallelism uint8, memory uint32, iterations uint8, version byte, salt []byte, key []byte) { + lenData := len(data) + + // Read values using binary.BigEndian + parallelism = data[0] + memory = binary.BigEndian.Uint32(data[1:5]) + iterations = data[5] + version = data[6] + keyOut := []byte(common.Bytes2Hex(data[7:39])) + + // Copy the remaining bytes to s + salt = make([]byte, lenData-39) + copy(salt, data[39:]) + + return parallelism, memory, iterations, version, salt, keyOut +} From 58a098dcbc12e34600acbe00a987cc2b6c9b9ba3 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Tue, 19 Dec 2023 15:49:59 -0800 Subject: [PATCH 28/34] Revert "decode record bytes in go" This reverts commit 967ce377f26eb6d3da76ac774df95f255695a418. --- integration/xenblocks/verifier/verifier.go | 33 ++++++++-------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 06fb86233..cbaa84c39 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -77,8 +77,14 @@ func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) [ blockTime := v.getBlockTime(event.Raw.BlockHash) - parallelism, memory, iterations, _, salt, key := decodeRecordBytes(event.Bytes) - argon2Result, err := argon2Hash(parallelism, memory, iterations, salt, key) + dr, err := v.bs.DecodeRecordBytes0(nil, event.HashId) + if err != nil { + log.Warn("Failed to decode hash record", "err", err) + return nil + } + + key := []byte(common.Bytes2Hex(dr.K[:])) + argon2Result, err := argon2Hash(dr.C, dr.M, dr.T, dr.S, key) if err != nil { log.Warn("Argon2 hash failed", "err", err) return nil @@ -89,14 +95,14 @@ func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) [ return nil } - if !validateSalt(salt) { + if !validateSalt(dr.S) { log.Warn("Salt fails verification", "hash", argon2Result, "hashId", event.HashId) return nil } - //if !v.verifyDifficultly(memory, event.Raw.BlockNumber) { + //if !v.verifyDifficultly(dr.M, event.Raw.BlockNumber) { // log.Warn("Difficulty too low", "hash", argon2Result, "hashId", event.HashId) - // return nil + // return //} tokens := FindTokensFromHash(argon2Result, blockTime) @@ -224,20 +230,3 @@ func validateSalt(s []byte) bool { return validatePattern2(salt) } - -func decodeRecordBytes(data []byte) (parallelism uint8, memory uint32, iterations uint8, version byte, salt []byte, key []byte) { - lenData := len(data) - - // Read values using binary.BigEndian - parallelism = data[0] - memory = binary.BigEndian.Uint32(data[1:5]) - iterations = data[5] - version = data[6] - keyOut := []byte(common.Bytes2Hex(data[7:39])) - - // Copy the remaining bytes to s - salt = make([]byte, lenData-39) - copy(salt, data[39:]) - - return parallelism, memory, iterations, version, salt, keyOut -} From 594e702a09d7cf9f685de282819ea24615622477 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Tue, 19 Dec 2023 17:49:19 -0800 Subject: [PATCH 29/34] go back to using on-chain method for decoding and shouldvote. add syncing check to limit backlog processing --- cmd/opera/launcher/launcher.go | 1 - .../contracts/votemanager/votemanager.go | 172 ++++-------------- .../xenblocks/verifier/event_listener.go | 63 ++++--- integration/xenblocks/verifier/verifier.go | 45 ++--- integration/xenblocks/verifier/voter.go | 31 ++-- 5 files changed, 107 insertions(+), 205 deletions(-) diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index a4050ca56..adad2f8ba 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -290,7 +290,6 @@ func lachesisMain(ctx *cli.Context) error { cfg := makeAllConfigs(ctx) genesisStore := mayGetGenesisStore(ctx) node, _, nodeClose := makeNode(ctx, cfg, genesisStore) - log.Info("test1") defer nodeClose() startNode(ctx, node) node.Wait() diff --git a/integration/xenblocks/contracts/votemanager/votemanager.go b/integration/xenblocks/contracts/votemanager/votemanager.go index 3caeb8db0..ae9022cca 100644 --- a/integration/xenblocks/contracts/votemanager/votemanager.go +++ b/integration/xenblocks/contracts/votemanager/votemanager.go @@ -30,13 +30,14 @@ var ( // VoteManagerPayload is an auto generated low-level Go binding around an user-defined struct. type VoteManagerPayload struct { - HashId *big.Int - CurrencyType *big.Int + HashId *big.Int + CurrencyType *big.Int + MintedBlockNumber *big.Int } // VotemanagerMetaData contains all meta data concerning the Votemanager contract. var VotemanagerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"name\":\"MintToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"votes\",\"type\":\"uint16\"}],\"name\":\"VoteToken\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"blockStorage\",\"outputs\":[{\"internalType\":\"contractBlockStorage\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialSfcAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialBlockStorageAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"initialVotePercentage\",\"type\":\"uint8\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashId\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"newVotesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sfcLib\",\"outputs\":[{\"internalType\":\"contractSFCLib\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_validatorId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_validatorCount\",\"type\":\"uint256\"}],\"name\":\"shouldVote\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenRegistry\",\"outputs\":[{\"internalType\":\"contractTokenRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_blockStorageAddress\",\"type\":\"address\"}],\"name\":\"updateBlockStorageAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sfcLibAddress\",\"type\":\"address\"}],\"name\":\"updateSfcLibAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenRegistryAddress\",\"type\":\"address\"}],\"name\":\"updateTokenRegistryAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_votePercentage\",\"type\":\"uint8\"}],\"name\":\"updateVotePercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"validatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currencyType\",\"type\":\"uint256\"}],\"name\":\"vote\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"internalType\":\"structVoteManager.Payload[]\",\"name\":\"payload\",\"type\":\"tuple[]\"}],\"name\":\"voteBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"votePercentage\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"votesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorId\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"name\":\"MintToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"votes\",\"type\":\"uint16\"}],\"name\":\"VoteToken\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"blockStorage\",\"outputs\":[{\"internalType\":\"contractBlockStorage\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialSfcAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialBlockStorageAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"initialVotePercentage\",\"type\":\"uint8\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sfcLib\",\"outputs\":[{\"internalType\":\"contractSFCLib\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_mintedBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_validatorId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"}],\"name\":\"shouldVote\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenRegistry\",\"outputs\":[{\"internalType\":\"contractTokenRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_blockStorageAddress\",\"type\":\"address\"}],\"name\":\"updateBlockStorageAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sfcLibAddress\",\"type\":\"address\"}],\"name\":\"updateSfcLibAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenRegistryAddress\",\"type\":\"address\"}],\"name\":\"updateTokenRegistryAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_votePercentage\",\"type\":\"uint8\"}],\"name\":\"updateVotePercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"validatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"mintedBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currencyType\",\"type\":\"uint256\"}],\"name\":\"vote\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"mintedBlockNumber\",\"type\":\"uint256\"}],\"internalType\":\"structVoteManager.Payload[]\",\"name\":\"payload\",\"type\":\"tuple[]\"}],\"name\":\"voteBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"votePercentage\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } // VotemanagerABI is the input ABI used to generate the binding from. @@ -216,37 +217,6 @@ func (_Votemanager *VotemanagerCallerSession) BlockStorage() (common.Address, er return _Votemanager.Contract.BlockStorage(&_Votemanager.CallOpts) } -// MintedByHashId is a free data retrieval call binding the contract method 0x9f4ee5af. -// -// Solidity: function mintedByHashId(uint256 ) view returns(bool) -func (_Votemanager *VotemanagerCaller) MintedByHashId(opts *bind.CallOpts, arg0 *big.Int) (bool, error) { - var out []interface{} - err := _Votemanager.contract.Call(opts, &out, "mintedByHashId", arg0) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// MintedByHashId is a free data retrieval call binding the contract method 0x9f4ee5af. -// -// Solidity: function mintedByHashId(uint256 ) view returns(bool) -func (_Votemanager *VotemanagerSession) MintedByHashId(arg0 *big.Int) (bool, error) { - return _Votemanager.Contract.MintedByHashId(&_Votemanager.CallOpts, arg0) -} - -// MintedByHashId is a free data retrieval call binding the contract method 0x9f4ee5af. -// -// Solidity: function mintedByHashId(uint256 ) view returns(bool) -func (_Votemanager *VotemanagerCallerSession) MintedByHashId(arg0 *big.Int) (bool, error) { - return _Votemanager.Contract.MintedByHashId(&_Votemanager.CallOpts, arg0) -} - // MintedByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x47ce239d. // // Solidity: function mintedByHashIdAndCurrencyType(uint256 , uint256 ) view returns(bool) @@ -278,37 +248,6 @@ func (_Votemanager *VotemanagerCallerSession) MintedByHashIdAndCurrencyType(arg0 return _Votemanager.Contract.MintedByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) } -// NewVotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x0c1c9308. -// -// Solidity: function newVotesByHashIdAndCurrencyType(uint256 , uint256 ) view returns(uint16) -func (_Votemanager *VotemanagerCaller) NewVotesByHashIdAndCurrencyType(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (uint16, error) { - var out []interface{} - err := _Votemanager.contract.Call(opts, &out, "newVotesByHashIdAndCurrencyType", arg0, arg1) - - if err != nil { - return *new(uint16), err - } - - out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) - - return out0, err - -} - -// NewVotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x0c1c9308. -// -// Solidity: function newVotesByHashIdAndCurrencyType(uint256 , uint256 ) view returns(uint16) -func (_Votemanager *VotemanagerSession) NewVotesByHashIdAndCurrencyType(arg0 *big.Int, arg1 *big.Int) (uint16, error) { - return _Votemanager.Contract.NewVotesByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) -} - -// NewVotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x0c1c9308. -// -// Solidity: function newVotesByHashIdAndCurrencyType(uint256 , uint256 ) view returns(uint16) -func (_Votemanager *VotemanagerCallerSession) NewVotesByHashIdAndCurrencyType(arg0 *big.Int, arg1 *big.Int) (uint16, error) { - return _Votemanager.Contract.NewVotesByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) -} - // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. // // Solidity: function owner() view returns(address) @@ -404,10 +343,10 @@ func (_Votemanager *VotemanagerCallerSession) SfcLib() (common.Address, error) { // ShouldVote is a free data retrieval call binding the contract method 0xb1faefbb. // -// Solidity: function shouldVote(uint256 _validatorId, uint256 _hashId, uint256 _validatorCount) pure returns(bool) -func (_Votemanager *VotemanagerCaller) ShouldVote(opts *bind.CallOpts, _validatorId *big.Int, _hashId *big.Int, _validatorCount *big.Int) (bool, error) { +// Solidity: function shouldVote(uint256 _mintedBlockNumber, uint256 _validatorId, uint256 _hashId) view returns(bool) +func (_Votemanager *VotemanagerCaller) ShouldVote(opts *bind.CallOpts, _mintedBlockNumber *big.Int, _validatorId *big.Int, _hashId *big.Int) (bool, error) { var out []interface{} - err := _Votemanager.contract.Call(opts, &out, "shouldVote", _validatorId, _hashId, _validatorCount) + err := _Votemanager.contract.Call(opts, &out, "shouldVote", _mintedBlockNumber, _validatorId, _hashId) if err != nil { return *new(bool), err @@ -421,16 +360,16 @@ func (_Votemanager *VotemanagerCaller) ShouldVote(opts *bind.CallOpts, _validato // ShouldVote is a free data retrieval call binding the contract method 0xb1faefbb. // -// Solidity: function shouldVote(uint256 _validatorId, uint256 _hashId, uint256 _validatorCount) pure returns(bool) -func (_Votemanager *VotemanagerSession) ShouldVote(_validatorId *big.Int, _hashId *big.Int, _validatorCount *big.Int) (bool, error) { - return _Votemanager.Contract.ShouldVote(&_Votemanager.CallOpts, _validatorId, _hashId, _validatorCount) +// Solidity: function shouldVote(uint256 _mintedBlockNumber, uint256 _validatorId, uint256 _hashId) view returns(bool) +func (_Votemanager *VotemanagerSession) ShouldVote(_mintedBlockNumber *big.Int, _validatorId *big.Int, _hashId *big.Int) (bool, error) { + return _Votemanager.Contract.ShouldVote(&_Votemanager.CallOpts, _mintedBlockNumber, _validatorId, _hashId) } // ShouldVote is a free data retrieval call binding the contract method 0xb1faefbb. // -// Solidity: function shouldVote(uint256 _validatorId, uint256 _hashId, uint256 _validatorCount) pure returns(bool) -func (_Votemanager *VotemanagerCallerSession) ShouldVote(_validatorId *big.Int, _hashId *big.Int, _validatorCount *big.Int) (bool, error) { - return _Votemanager.Contract.ShouldVote(&_Votemanager.CallOpts, _validatorId, _hashId, _validatorCount) +// Solidity: function shouldVote(uint256 _mintedBlockNumber, uint256 _validatorId, uint256 _hashId) view returns(bool) +func (_Votemanager *VotemanagerCallerSession) ShouldVote(_mintedBlockNumber *big.Int, _validatorId *big.Int, _hashId *big.Int) (bool, error) { + return _Votemanager.Contract.ShouldVote(&_Votemanager.CallOpts, _mintedBlockNumber, _validatorId, _hashId) } // TokenRegistry is a free data retrieval call binding the contract method 0x9d23c4c7. @@ -526,10 +465,10 @@ func (_Votemanager *VotemanagerCallerSession) VotePercentage() (uint8, error) { return _Votemanager.Contract.VotePercentage(&_Votemanager.CallOpts) } -// VotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x770a9e50. +// VotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x348fbd64. // -// Solidity: function votesByHashIdAndCurrencyType(uint256 , uint8 ) view returns(uint16) -func (_Votemanager *VotemanagerCaller) VotesByHashIdAndCurrencyType(opts *bind.CallOpts, arg0 *big.Int, arg1 uint8) (uint16, error) { +// Solidity: function votesByHashIdAndCurrencyType(uint256 , uint256 ) view returns(uint16) +func (_Votemanager *VotemanagerCaller) VotesByHashIdAndCurrencyType(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (uint16, error) { var out []interface{} err := _Votemanager.contract.Call(opts, &out, "votesByHashIdAndCurrencyType", arg0, arg1) @@ -543,51 +482,20 @@ func (_Votemanager *VotemanagerCaller) VotesByHashIdAndCurrencyType(opts *bind.C } -// VotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x770a9e50. +// VotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x348fbd64. // -// Solidity: function votesByHashIdAndCurrencyType(uint256 , uint8 ) view returns(uint16) -func (_Votemanager *VotemanagerSession) VotesByHashIdAndCurrencyType(arg0 *big.Int, arg1 uint8) (uint16, error) { +// Solidity: function votesByHashIdAndCurrencyType(uint256 , uint256 ) view returns(uint16) +func (_Votemanager *VotemanagerSession) VotesByHashIdAndCurrencyType(arg0 *big.Int, arg1 *big.Int) (uint16, error) { return _Votemanager.Contract.VotesByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) } -// VotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x770a9e50. +// VotesByHashIdAndCurrencyType is a free data retrieval call binding the contract method 0x348fbd64. // -// Solidity: function votesByHashIdAndCurrencyType(uint256 , uint8 ) view returns(uint16) -func (_Votemanager *VotemanagerCallerSession) VotesByHashIdAndCurrencyType(arg0 *big.Int, arg1 uint8) (uint16, error) { +// Solidity: function votesByHashIdAndCurrencyType(uint256 , uint256 ) view returns(uint16) +func (_Votemanager *VotemanagerCallerSession) VotesByHashIdAndCurrencyType(arg0 *big.Int, arg1 *big.Int) (uint16, error) { return _Votemanager.Contract.VotesByHashIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1) } -// VotesByHashIdAndValidatorId is a free data retrieval call binding the contract method 0x6da2b74b. -// -// Solidity: function votesByHashIdAndValidatorId(uint256 , uint256 ) view returns(bool) -func (_Votemanager *VotemanagerCaller) VotesByHashIdAndValidatorId(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (bool, error) { - var out []interface{} - err := _Votemanager.contract.Call(opts, &out, "votesByHashIdAndValidatorId", arg0, arg1) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// VotesByHashIdAndValidatorId is a free data retrieval call binding the contract method 0x6da2b74b. -// -// Solidity: function votesByHashIdAndValidatorId(uint256 , uint256 ) view returns(bool) -func (_Votemanager *VotemanagerSession) VotesByHashIdAndValidatorId(arg0 *big.Int, arg1 *big.Int) (bool, error) { - return _Votemanager.Contract.VotesByHashIdAndValidatorId(&_Votemanager.CallOpts, arg0, arg1) -} - -// VotesByHashIdAndValidatorId is a free data retrieval call binding the contract method 0x6da2b74b. -// -// Solidity: function votesByHashIdAndValidatorId(uint256 , uint256 ) view returns(bool) -func (_Votemanager *VotemanagerCallerSession) VotesByHashIdAndValidatorId(arg0 *big.Int, arg1 *big.Int) (bool, error) { - return _Votemanager.Contract.VotesByHashIdAndValidatorId(&_Votemanager.CallOpts, arg0, arg1) -} - // VotesByHashIdAndValidatorIdAndCurrencyType is a free data retrieval call binding the contract method 0x95c6286c. // // Solidity: function votesByHashIdAndValidatorIdAndCurrencyType(uint256 , uint256 , uint256 ) view returns(bool) @@ -766,44 +674,44 @@ func (_Votemanager *VotemanagerTransactorSession) UpdateVotePercentage(_votePerc return _Votemanager.Contract.UpdateVotePercentage(&_Votemanager.TransactOpts, _votePercentage) } -// Vote is a paid mutator transaction binding the contract method 0xb384abef. +// Vote is a paid mutator transaction binding the contract method 0x8a6655d6. // -// Solidity: function vote(uint256 _hashId, uint256 _currencyType) returns() -func (_Votemanager *VotemanagerTransactor) Vote(opts *bind.TransactOpts, _hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { - return _Votemanager.contract.Transact(opts, "vote", _hashId, _currencyType) +// Solidity: function vote(uint256 mintedBlockNumber, uint256 _hashId, uint256 _currencyType) returns() +func (_Votemanager *VotemanagerTransactor) Vote(opts *bind.TransactOpts, mintedBlockNumber *big.Int, _hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "vote", mintedBlockNumber, _hashId, _currencyType) } -// Vote is a paid mutator transaction binding the contract method 0xb384abef. +// Vote is a paid mutator transaction binding the contract method 0x8a6655d6. // -// Solidity: function vote(uint256 _hashId, uint256 _currencyType) returns() -func (_Votemanager *VotemanagerSession) Vote(_hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { - return _Votemanager.Contract.Vote(&_Votemanager.TransactOpts, _hashId, _currencyType) +// Solidity: function vote(uint256 mintedBlockNumber, uint256 _hashId, uint256 _currencyType) returns() +func (_Votemanager *VotemanagerSession) Vote(mintedBlockNumber *big.Int, _hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { + return _Votemanager.Contract.Vote(&_Votemanager.TransactOpts, mintedBlockNumber, _hashId, _currencyType) } -// Vote is a paid mutator transaction binding the contract method 0xb384abef. +// Vote is a paid mutator transaction binding the contract method 0x8a6655d6. // -// Solidity: function vote(uint256 _hashId, uint256 _currencyType) returns() -func (_Votemanager *VotemanagerTransactorSession) Vote(_hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { - return _Votemanager.Contract.Vote(&_Votemanager.TransactOpts, _hashId, _currencyType) +// Solidity: function vote(uint256 mintedBlockNumber, uint256 _hashId, uint256 _currencyType) returns() +func (_Votemanager *VotemanagerTransactorSession) Vote(mintedBlockNumber *big.Int, _hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { + return _Votemanager.Contract.Vote(&_Votemanager.TransactOpts, mintedBlockNumber, _hashId, _currencyType) } -// VoteBatch is a paid mutator transaction binding the contract method 0xbceb2e60. +// VoteBatch is a paid mutator transaction binding the contract method 0x149ff154. // -// Solidity: function voteBatch((uint256,uint256)[] payload) returns() +// Solidity: function voteBatch((uint256,uint256,uint256)[] payload) returns() func (_Votemanager *VotemanagerTransactor) VoteBatch(opts *bind.TransactOpts, payload []VoteManagerPayload) (*types.Transaction, error) { return _Votemanager.contract.Transact(opts, "voteBatch", payload) } -// VoteBatch is a paid mutator transaction binding the contract method 0xbceb2e60. +// VoteBatch is a paid mutator transaction binding the contract method 0x149ff154. // -// Solidity: function voteBatch((uint256,uint256)[] payload) returns() +// Solidity: function voteBatch((uint256,uint256,uint256)[] payload) returns() func (_Votemanager *VotemanagerSession) VoteBatch(payload []VoteManagerPayload) (*types.Transaction, error) { return _Votemanager.Contract.VoteBatch(&_Votemanager.TransactOpts, payload) } -// VoteBatch is a paid mutator transaction binding the contract method 0xbceb2e60. +// VoteBatch is a paid mutator transaction binding the contract method 0x149ff154. // -// Solidity: function voteBatch((uint256,uint256)[] payload) returns() +// Solidity: function voteBatch((uint256,uint256,uint256)[] payload) returns() func (_Votemanager *VotemanagerTransactorSession) VoteBatch(payload []VoteManagerPayload) (*types.Transaction, error) { return _Votemanager.Contract.VoteBatch(&_Votemanager.TransactOpts, payload) } diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index d8a6189a0..7d33936f1 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -1,14 +1,16 @@ package verifier import ( + "context" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/votemanager" "github.com/Fantom-foundation/lachesis-base/inter/idx" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "time" @@ -18,7 +20,10 @@ const ( numOfWorkers = 5 backlog = 5000 - blockStorageAddr = "0xb3753e9F40DD0Dfd039e8c4B12895e2f636693a2" + confirmations = 3 + allowBlockBacklog = 1000 + blockStorageAddr = "0xb3753e9F40DD0Dfd039e8c4B12895e2f636693a2" + voteManagerAddr = "0x9224c3121c050546Ba76960c00c8B7e26C1E7b33" ) type EventListener struct { @@ -28,15 +33,16 @@ type EventListener struct { stack *node.Node validatorId uint32 bs *block_storage.BlockStorage + vm *votemanager.Votemanager eventChannel chan *block_storage.BlockStorageNewHash conn *ethclient.Client - sub event.Subscription verifier *Verifier ks *keystore.KeyStore account accounts.Account chainId uint64 voter *Voter currentBlockNumber uint64 + syncingProcess *ethereum.SyncProgress } func NewEventListener(stack *node.Node, validatorId idx.ValidatorID, ks *keystore.KeyStore, account accounts.Account, chainId uint64) *EventListener { @@ -64,28 +70,9 @@ func (e *EventListener) Start() { } e.eventChannel = make(chan *block_storage.BlockStorageNewHash, backlog) - for w := 1; w <= numOfWorkers; w++ { + for w := 0; w < numOfWorkers; w++ { go e.worker(e.eventChannel) } - - // Start a goroutine which watches new events - //go func() { - // e.sub, err = e.bs.WatchNewHash(nil, e.eventChannel, nil, nil, nil) - // if err != nil { - // panic(err) - // } - // - // for { - // select { - // case err := <-e.sub.Err(): - // if err != nil && err != io.EOF { - // log.Error("Error in BlockStorage watcher", "err", err) - // } - // break - // } - // time.Sleep(time.Second) - // } - //}() } func (e *EventListener) initializeEventSystem() error { @@ -96,9 +83,10 @@ func (e *EventListener) initializeEventSystem() error { e.conn = ethclient.NewClient(rpc) e.bs, err = block_storage.NewBlockStorage(common.HexToAddress(blockStorageAddr), e.conn) + e.vm, err = votemanager.NewVotemanager(common.HexToAddress(voteManagerAddr), e.conn) - e.verifier = NewVerifier(e.validatorId, e.conn, e.bs) - e.voter = NewVoter(e.conn, e.ks, e.account, e.chainId) + e.verifier = NewVerifier(e.validatorId, e.conn, e.bs, e.vm) + e.voter = NewVoter(e.conn, e.ks, e.account, e.chainId, e.vm) return err } @@ -108,6 +96,10 @@ func (e *EventListener) OnNewLog(l *types.Log) { return } + if e.syncingProcess != nil && e.syncingProcess.HighestBlock-e.syncingProcess.CurrentBlock > allowBlockBacklog { + return + } + if l.Address == common.HexToAddress(blockStorageAddr) { evt, err := e.bs.ParseNewHash(*l) @@ -125,30 +117,41 @@ func (e *EventListener) OnNewBlock(blockNumber uint64) { return } - //log.Info("New block received", "blockNumber", blockNumber) + progress, err := e.conn.SyncProgress(context.TODO()) + if err != nil { + panic(err) + } + + e.syncingProcess = progress e.currentBlockNumber = blockNumber } func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) { for evt := range events { + if e.enabled == false { + return + } + // Wait for the block to be confirmed for { - if evt.Raw.BlockNumber < e.currentBlockNumber { + if evt.Raw.BlockNumber+confirmations < e.currentBlockNumber { break } else { - log.Info("waiting for block to be confirmed", "blockNumber", evt.Raw.BlockNumber, "currentBlockNumber", e.currentBlockNumber) - time.Sleep(100 * time.Millisecond) + log.Debug("waiting for block to be confirmed", "blockNumber", evt.Raw.BlockNumber, "currentBlockNumber", e.currentBlockNumber) + time.Sleep(250 * time.Millisecond) } } tokens := e.verifier.validateHashEvent(evt) + e.voter.Syncing = e.syncingProcess != nil // increase the batch size if we are syncing for _, token := range tokens { - e.voter.AddToQueue(evt.HashId, token.currencyCode) + e.voter.AddToQueue(evt.HashId, evt.Raw.BlockNumber, token.currencyCode) } } } func (e *EventListener) Close() { if e.enabled { + e.enabled = false log.Info("Closing Block storage watcher") time.Sleep(time.Second) close(e.eventChannel) diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index cbaa84c39..6dda3a7d9 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -2,13 +2,11 @@ package verifier import ( "context" - "crypto/sha256" "encoding/base64" - "encoding/binary" "encoding/hex" - "fmt" "github.com/Fantom-foundation/go-opera/gossip/contract/sfclib100" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/votemanager" "github.com/Fantom-foundation/go-opera/opera/contracts/sfc" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -17,7 +15,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/hashicorp/golang-lru" "github.com/tvdburgt/go-argon2" - "math" "math/big" "regexp" "strings" @@ -25,9 +22,8 @@ import ( ) const ( - hashLen = 64 - validatorsFactor = 0.2 - pattern1Salt = "WEVOMTAwODIwMjJYRU4" + hashLen = 64 + pattern1Salt = "WEVOMTAwODIwMjJYRU4" ) type Verifier struct { @@ -42,9 +38,10 @@ type Verifier struct { conn *ethclient.Client sub event.Subscription validatorCountLRU *lru.Cache + vm *votemanager.Votemanager } -func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.BlockStorage) *Verifier { +func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.BlockStorage, vm *votemanager.Votemanager) *Verifier { validatorCountLRU, err := lru.New(100) if err != nil { panic(err) @@ -64,16 +61,19 @@ func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.B validatorCountLRU: validatorCountLRU, sfcLib: sfcLib, bs: bs, + vm: vm, } } func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) []Token { log.Debug("NewHash event received", "hashId", event.HashId, "epoch", event.Epoch, "account", event.Account) - if !v.shouldVote(event.Raw.BlockNumber) { - log.Debug("Not voting for this hash", "hash", event.Raw.BlockHash) - return nil - } + // TODO: uncomment. for dev we are voting on all hashes + //sv, err := v.shouldVote(event.Raw.BlockNumber, event.HashId) + //if !sv { + // log.Info("Not voting for this hash", "hash", event.Raw.BlockHash) + // return nil + //} blockTime := v.getBlockTime(event.Raw.BlockHash) @@ -150,24 +150,9 @@ func (v *Verifier) getValidatorCount(blockNumber uint64) (int, error) { return count, err } -func (v *Verifier) shouldVote(blockNumber uint64) bool { - validatorsCount, err := v.getValidatorCount(blockNumber) - if err != nil { - log.Error("Error getting validator count", "err", err) - return false - } - - seed := sha256.Sum256([]byte(fmt.Sprintf("%d-%d", blockNumber, v.validatorId))) - randomState := int(binary.LittleEndian.Uint64(seed[:])) % validatorsCount - - // Calculate the number of validators to vote (percentage of validators) - numVotingValidators := max(1, int(math.Round(validatorsFactor*float64(validatorsCount)))) - - // Calculate the position of the validator within the selected validators - positionInSelectedValidators := randomState % numVotingValidators - - // Check if the given validator index matches the calculated position - return positionInSelectedValidators == int(v.validatorId)%numVotingValidators +func (v *Verifier) shouldVote(blockNumber uint64, hashId *big.Int) (bool, error) { + bn := new(big.Int).SetUint64(blockNumber) + return v.vm.ShouldVote(nil, bn, big.NewInt(int64(v.validatorId)), hashId) } func (v *Verifier) verifyDifficultly(difficulty uint32, blockNumber uint64) bool { diff --git a/integration/xenblocks/verifier/voter.go b/integration/xenblocks/verifier/voter.go index 3d40b86fa..a09a3f463 100644 --- a/integration/xenblocks/verifier/voter.go +++ b/integration/xenblocks/verifier/voter.go @@ -16,9 +16,8 @@ import ( ) var ( - voteManagerAddr = common.HexToAddress("0x9224c3121c050546Ba76960c00c8B7e26C1E7b33") - BatchSize = 50 - GasLimit = uint64(8000000) + BatchSize = 50 + GasLimit = uint64(8000000) ) type Voter struct { @@ -29,14 +28,10 @@ type Voter struct { account accounts.Account chainId uint64 mu sync.Mutex + Syncing bool } -func NewVoter(conn *ethclient.Client, ks *keystore.KeyStore, account accounts.Account, chainId uint64) *Voter { - vm, err := votemanager.NewVotemanager(voteManagerAddr, conn) - if err != nil { - panic(err) - } - +func NewVoter(conn *ethclient.Client, ks *keystore.KeyStore, account accounts.Account, chainId uint64, vm *votemanager.Votemanager) *Voter { var queue []votemanager.VoteManagerPayload return &Voter{ @@ -64,13 +59,15 @@ func (v *Voter) waitTxConfirmed(hash common.Hash) <-chan *types.Transaction { return ch } -func (v *Voter) AddToQueue(hashId *big.Int, currencyType uint8) { +func (v *Voter) AddToQueue(hashId *big.Int, MintedBlockNumber uint64, currencyType uint8) { cc := big.NewInt(int64(currencyType)) - v.queue = append(v.queue, votemanager.VoteManagerPayload{HashId: hashId, CurrencyType: cc}) + mbn := big.NewInt(int64(MintedBlockNumber)) + v.queue = append(v.queue, votemanager.VoteManagerPayload{HashId: hashId, CurrencyType: cc, MintedBlockNumber: mbn}) v.mu.Lock() defer v.mu.Unlock() - if len(v.queue) >= BatchSize { + + if len(v.queue) >= v.getBatchSize() { _ = v.Vote() v.queue = []votemanager.VoteManagerPayload{} } @@ -93,9 +90,19 @@ func (v *Voter) Vote() error { if err != nil { log.Error("vote error", "err", err) } + if tx == nil { + log.Error("vote error", "err", "tx is nil") + } v.waitTxConfirmed(tx.Hash()) log.Info("vote success!", "tx", tx.Hash().Hex()) return nil } + +func (v *Voter) getBatchSize() int { + if v.Syncing { + return BatchSize * 4 + } + return BatchSize +} From 6dd7a77c9a93ec35658632c89d6f4ea347389a98 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Tue, 19 Dec 2023 18:50:59 -0800 Subject: [PATCH 30/34] fix unit tests --- .../xenblocks/verifier/targets_test.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/integration/xenblocks/verifier/targets_test.go b/integration/xenblocks/verifier/targets_test.go index 78ab6e112..c0901bfdb 100644 --- a/integration/xenblocks/verifier/targets_test.go +++ b/integration/xenblocks/verifier/targets_test.go @@ -14,10 +14,21 @@ func TestFindTokensFromHashXNM(t *testing.T) { assert.Equal(1, len(tokens)) assert.Equal("XNM", tokens[0].name) - assert.Equal(1, tokens[0].currencyCode) + assert.Equal(uint8(1), tokens[0].currencyCode) assert.Equal(10, tokens[0].value) } +func TestXuniToken(t *testing.T) { + assert := require.New(t) + + tokens := FindTokensFromHash("$argon2id$v=19$m=102000,t=1,p=1$AmtN2N+5ggJ4tc1s7TfBsg9o3to$ZzzXErgy4F3+O4+OV2U3F9+Sv0ssKR4uyxguomjkBvb1EUgEeC5Ztyz2U7k9gKHw8e6HidQkKXUNI75ZFBmQHw", time.Unix(0, 0)) + + assert.Equal(1, len(tokens)) + assert.Equal("XUNI", tokens[0].name) + assert.Equal(uint8(2), tokens[0].currencyCode) + assert.Equal(1, tokens[0].value) +} + func TestFindTokensFromHashXUNI(t *testing.T) { assert := require.New(t) @@ -29,7 +40,7 @@ func TestFindTokensFromHashXUNI(t *testing.T) { if (0 <= j && j < 5) || (55 <= j && j < 60) { assert.Equal(1, len(tokens)) assert.Equal("XUNI", tokens[0].name) - assert.Equal(2, tokens[0].currencyCode) + assert.Equal(uint8(2), tokens[0].currencyCode) assert.Equal(1, tokens[0].value) } else { assert.Equal(0, len(tokens)) @@ -46,9 +57,9 @@ func TestFindTokensFromHashSB(t *testing.T) { tokens := FindTokensFromHash("$argon2id$v=19$m=99400,t=1,p=1$salt$XEN11AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", blockTime) assert.Equal(2, len(tokens)) assert.Equal("XNM", tokens[0].name) - assert.Equal(1, tokens[0].currencyCode) + assert.Equal(uint8(1), tokens[0].currencyCode) assert.Equal(10, tokens[0].value) assert.Equal("SB", tokens[1].name) - assert.Equal(3, tokens[1].currencyCode) + assert.Equal(uint8(3), tokens[1].currencyCode) assert.Equal(1, tokens[1].value) } From c6b2763d803e3c62a58d4cb797d8c11373b44b03 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Tue, 19 Dec 2023 18:51:38 -0800 Subject: [PATCH 31/34] better start and shutdown of event listener --- cmd/opera/launcher/launcher.go | 2 +- integration/xenblocks/verifier/event_listener.go | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index adad2f8ba..0ee4ed365 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -401,7 +401,6 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( stack.RegisterLifecycle(svc) return stack, svc, func() { - xbEventListener.Close() _ = stack.Close() gdb.Close() _ = cdb.Close() @@ -409,6 +408,7 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( _ = closeDBs() } xenblocksReporter.Close() + xbEventListener.Close() } } diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index 7d33936f1..eec66df40 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -61,7 +61,6 @@ func NewEventListener(stack *node.Node, validatorId idx.ValidatorID, ks *keystor func (e *EventListener) Start() { log.Info("Starting Block storage watcher") - time.Sleep(5 * time.Second) e.enabled = true err := e.initializeEventSystem() @@ -101,7 +100,6 @@ func (e *EventListener) OnNewLog(l *types.Log) { } if l.Address == common.HexToAddress(blockStorageAddr) { - evt, err := e.bs.ParseNewHash(*l) if err != nil { return @@ -141,6 +139,7 @@ func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) time.Sleep(250 * time.Millisecond) } } + tokens := e.verifier.validateHashEvent(evt) e.voter.Syncing = e.syncingProcess != nil // increase the batch size if we are syncing for _, token := range tokens { From d3c45915b5aad55270ac7be768d147e424e17b0b Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Tue, 19 Dec 2023 19:16:57 -0800 Subject: [PATCH 32/34] disable xuni timestamp checks until configed blocknumber --- integration/xenblocks/verifier/targets.go | 24 ++++++++++----- .../xenblocks/verifier/targets_test.go | 13 ++++---- integration/xenblocks/verifier/verifier.go | 30 +++---------------- 3 files changed, 28 insertions(+), 39 deletions(-) diff --git a/integration/xenblocks/verifier/targets.go b/integration/xenblocks/verifier/targets.go index b8e24ea6e..a94a9e7f9 100644 --- a/integration/xenblocks/verifier/targets.go +++ b/integration/xenblocks/verifier/targets.go @@ -2,11 +2,17 @@ package verifier import ( "github.com/ethereum/go-ethereum/log" + "math/big" "regexp" "strings" "time" ) +var ( + // BLOCK_NUMBER_TIME_CHECK_REQ is the block number at which the time check starts to be required. + BLOCK_NUMBER_TIME_CHECK_REQ = big.NewInt(0) +) + type Token struct { name string currencyCode uint8 @@ -15,10 +21,10 @@ type Token struct { type TokenFilter struct { token string - pattern string // regex pattern to filter hashes - exclusive bool // if true, stop searching for other targets - timeCheck func(time time.Time) bool // custom function to filter based on time - hashCheck func(hash string) bool // custom function to filter based on hash + pattern string // regex pattern to filter hashes + exclusive bool // if true, stop searching for other targets + timeCheck func(time time.Time, blockNumber *big.Int) bool // custom function to filter based on time + hashCheck func(hash string) bool // custom function to filter based on hash } // Tokens These are token definitions for the verifier and their initial mint values. @@ -47,7 +53,10 @@ var TokenFilters = []TokenFilter{ token: "XUNI", pattern: ".*XUNI[0-9].*", exclusive: true, - timeCheck: func(time time.Time) bool { + timeCheck: func(time time.Time, blockNumber *big.Int) bool { + if BLOCK_NUMBER_TIME_CHECK_REQ.Cmp(big.NewInt(0)) == 0 || blockNumber.Cmp(BLOCK_NUMBER_TIME_CHECK_REQ) == -1 { + return true + } minutes := time.Minute() return (0 <= minutes && minutes < 5) || (55 <= minutes && minutes < 60) }, @@ -68,7 +77,7 @@ var TokenFilters = []TokenFilter{ } // FindTokensFromHash returns a list of tokens found in the given hash. -func FindTokensFromHash(argon2Result string, blockTime time.Time) []Token { +func FindTokensFromHash(argon2Result string, blockTime time.Time, blockNumber uint64) []Token { var foundTargets []Token splits := strings.Split(argon2Result, "$") @@ -86,7 +95,8 @@ func FindTokensFromHash(argon2Result string, blockTime time.Time) []Token { continue } - if target.timeCheck != nil && !target.timeCheck(blockTime) { + bn := new(big.Int).SetUint64(blockNumber) + if target.timeCheck != nil && !target.timeCheck(blockTime, bn) { log.Trace("time check failed", "token", target.token, "time", blockTime) continue } diff --git a/integration/xenblocks/verifier/targets_test.go b/integration/xenblocks/verifier/targets_test.go index c0901bfdb..e71b04119 100644 --- a/integration/xenblocks/verifier/targets_test.go +++ b/integration/xenblocks/verifier/targets_test.go @@ -3,6 +3,7 @@ package verifier import ( "fmt" "github.com/stretchr/testify/require" + "math/big" "testing" "time" ) @@ -10,7 +11,7 @@ import ( func TestFindTokensFromHashXNM(t *testing.T) { assert := require.New(t) - tokens := FindTokensFromHash("$argon2id$v=19$m=99400,t=1,p=1$salt$aaaaaXEN11aaaaa", time.Unix(0, 0)) + tokens := FindTokensFromHash("$argon2id$v=19$m=99400,t=1,p=1$salt$aaaaaXEN11aaaaa", time.Unix(0, 0), 0) assert.Equal(1, len(tokens)) assert.Equal("XNM", tokens[0].name) @@ -21,7 +22,7 @@ func TestFindTokensFromHashXNM(t *testing.T) { func TestXuniToken(t *testing.T) { assert := require.New(t) - tokens := FindTokensFromHash("$argon2id$v=19$m=102000,t=1,p=1$AmtN2N+5ggJ4tc1s7TfBsg9o3to$ZzzXErgy4F3+O4+OV2U3F9+Sv0ssKR4uyxguomjkBvb1EUgEeC5Ztyz2U7k9gKHw8e6HidQkKXUNI75ZFBmQHw", time.Unix(0, 0)) + tokens := FindTokensFromHash("$argon2id$v=19$m=102000,t=1,p=1$AmtN2N+5ggJ4tc1s7TfBsg9o3to$ZzzXErgy4F3+O4+OV2U3F9+Sv0ssKR4uyxguomjkBvb1EUgEeC5Ztyz2U7k9gKHw8e6HidQkKXUNI75ZFBmQHw", time.Unix(0, 0), 0) assert.Equal(1, len(tokens)) assert.Equal("XUNI", tokens[0].name) @@ -35,14 +36,14 @@ func TestFindTokensFromHashXUNI(t *testing.T) { for i := 0; i < 9; i++ { for j := 0; j < 60; j++ { timestamp := time.Date(2023, 0, 0, 0, j, 0, 0, time.UTC) - tokens := FindTokensFromHash(fmt.Sprintf("$argon2id$v=19$m=99400,t=1,p=1$salt$aaaaaXUNI%d%daaaaa", i, j), timestamp) + tokens := FindTokensFromHash(fmt.Sprintf("$argon2id$v=19$m=99400,t=1,p=1$salt$aaaaaXUNI%d%daaaaa", i, j), timestamp, 0) if (0 <= j && j < 5) || (55 <= j && j < 60) { assert.Equal(1, len(tokens)) assert.Equal("XUNI", tokens[0].name) assert.Equal(uint8(2), tokens[0].currencyCode) assert.Equal(1, tokens[0].value) - } else { + } else if BLOCK_NUMBER_TIME_CHECK_REQ.Cmp(big.NewInt(0)) != 0 { assert.Equal(0, len(tokens)) } } @@ -54,12 +55,12 @@ func TestFindTokensFromHashSB(t *testing.T) { blockTime := time.Now() - tokens := FindTokensFromHash("$argon2id$v=19$m=99400,t=1,p=1$salt$XEN11AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", blockTime) + tokens := FindTokensFromHash("$argon2id$v=19$m=99400,t=1,p=1$salt$XEN11AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", blockTime, 0) assert.Equal(2, len(tokens)) assert.Equal("XNM", tokens[0].name) assert.Equal(uint8(1), tokens[0].currencyCode) assert.Equal(10, tokens[0].value) - assert.Equal("SB", tokens[1].name) + assert.Equal("XBLK", tokens[1].name) assert.Equal(uint8(3), tokens[1].currencyCode) assert.Equal(1, tokens[1].value) } diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index 6dda3a7d9..db2f1100d 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -69,13 +69,14 @@ func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) [ log.Debug("NewHash event received", "hashId", event.HashId, "epoch", event.Epoch, "account", event.Account) // TODO: uncomment. for dev we are voting on all hashes - //sv, err := v.shouldVote(event.Raw.BlockNumber, event.HashId) + //sv, err := v.shouldVote(blockNumber, event.HashId) //if !sv { // log.Info("Not voting for this hash", "hash", event.Raw.BlockHash) // return nil //} blockTime := v.getBlockTime(event.Raw.BlockHash) + blockNumber := event.Raw.BlockNumber dr, err := v.bs.DecodeRecordBytes0(nil, event.HashId) if err != nil { @@ -100,12 +101,12 @@ func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) [ return nil } - //if !v.verifyDifficultly(dr.M, event.Raw.BlockNumber) { + //if !v.verifyDifficultly(dr.M, blockNumber) { // log.Warn("Difficulty too low", "hash", argon2Result, "hashId", event.HashId) // return //} - tokens := FindTokensFromHash(argon2Result, blockTime) + tokens := FindTokensFromHash(argon2Result, blockTime, blockNumber) if len(tokens) == 0 { log.Warn("No tokens found", "hash", argon2Result, "hashId", event.HashId) return nil @@ -127,29 +128,6 @@ func argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, return argon2.HashEncoded(ctx, key, salt) } -func (v *Verifier) getValidatorCount(blockNumber uint64) (int, error) { - bn := new(big.Int).SetUint64(blockNumber) - epoch, err := v.sfcLib.CurrentSealedEpoch(&bind.CallOpts{BlockNumber: bn}) - log.Trace("CurrentSealedEpoch", "epoch", epoch) - if err != nil { - return 0, err - } - - // store the validator count in cache - r, ok := v.validatorCountLRU.Get(epoch.Int64()) - if ok { - return r.(int), nil - } - - validators, err := v.sfcLib.GetEpochValidatorIDs(&bind.CallOpts{BlockNumber: bn}, epoch) - log.Trace("GetEpochValidatorIDs", "validators", validators) - - count := len(validators) - v.validatorCountLRU.Add(epoch.Int64(), count) - - return count, err -} - func (v *Verifier) shouldVote(blockNumber uint64, hashId *big.Int) (bool, error) { bn := new(big.Int).SetUint64(blockNumber) return v.vm.ShouldVote(nil, bn, big.NewInt(int64(v.validatorId)), hashId) From 55386e2b97089f5ae1a75cdd840cf63d98596b58 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Fri, 5 Jan 2024 12:53:07 -0800 Subject: [PATCH 33/34] add support for new on chain token parsing --- README.md | 6 +- genabis.sh | 13 + gossip/c_block_callbacks.go | 1 + .../contracts/tokenregistry/tokenregistry.go | 1038 +++++++++++++++++ .../contracts/votemanager/votemanager.go | 261 +++-- .../xenblocks/verifier/event_listener.go | 20 +- .../xenblocks/verifier/main/list_hashes.go | 118 ++ integration/xenblocks/verifier/targets.go | 114 -- .../xenblocks/verifier/targets_test.go | 66 -- integration/xenblocks/verifier/verifier.go | 67 +- .../xenblocks/verifier/verifier_test.go | 2 +- integration/xenblocks/verifier/voter.go | 11 +- 12 files changed, 1396 insertions(+), 321 deletions(-) create mode 100644 genabis.sh create mode 100644 integration/xenblocks/contracts/tokenregistry/tokenregistry.go create mode 100644 integration/xenblocks/verifier/main/list_hashes.go delete mode 100644 integration/xenblocks/verifier/targets.go delete mode 100644 integration/xenblocks/verifier/targets_test.go diff --git a/README.md b/README.md index 4cb561004..a38ce3af9 100644 --- a/README.md +++ b/README.md @@ -112,21 +112,21 @@ abi = JSON.parse('[{"anonymous":false,"inputs":[{"indexed":true,"internalType":" … as well as the SFC contract object itself: ```shell -sfcc = web3.ftm.contract(abi).at("0xfc00face00000000000000000000000000000000") +sfc = web3.ftm.contract(abi).at("0xfc00face00000000000000000000000000000000") ``` Next, unlock your validator wallet to be able to execute the registration transaction (make sure to use the password you set before). ```shell # Unlock validator wallet -personal.unlockAccount("{VALIDATOR_WALLET_ADDRESS}", "{PASSWORD}", 60) +personal.unlockAccount("ACCOUNT_WALLET_ADDRESS", "PASSWORD", 60) ``` Next, send the createValidator transaction to register your validator. Use quotes for "0xYOUR_PUBKEY" and "0xYOUR_ADDRESS": ```shell # Register your validator -tx = sfcc.createValidator("0xYOUR_PUBKEY", {from:"0xYOUR_ADDRESS", value: web3.toWei("500000.0", "xn")}) +tx = sfc.createValidator("0xYOUR_PUBKEY", {from:"0xYOUR_ADDRESS", value: web3.toWei("500000.0", "xn")}) ``` ```shell diff --git a/genabis.sh b/genabis.sh new file mode 100644 index 000000000..c0ad1235d --- /dev/null +++ b/genabis.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +cat ../xenblock-tokens/artifacts/contracts/VoteManager.sol/VoteManager.json | jq '.abi' > VoteManager.abi.json +go run github.com/ethereum/go-ethereum/cmd/abigen --abi VoteManager.abi.json --pkg votemanager > integration/xenblocks/contracts/votemanager/votemanager.go +rm VoteManager.abi.json + +cat ../xenblock-tokens/artifacts/contracts/TokenRegistry.sol/TokenRegistry.json | jq '.abi' > TokenRegistry.abi.json +go run github.com/ethereum/go-ethereum/cmd/abigen --abi TokenRegistry.abi.json --pkg tokenregistry > integration/xenblocks/contracts/tokenregistry/tokenregistry.go +rm TokenRegistry.abi.json + +cat ../x1-block-storage/build/contracts/BlockStorage.json | jq '.abi' > BlockStorage.abi.json +go run github.com/ethereum/go-ethereum/cmd/abigen --abi BlockStorage.abi.json --pkg block_storage > integration/xenblocks/contracts/block_storage/block_storage.go +rm BlockStorage.abi.json diff --git a/gossip/c_block_callbacks.go b/gossip/c_block_callbacks.go index 633010d44..0edda7683 100644 --- a/gossip/c_block_callbacks.go +++ b/gossip/c_block_callbacks.go @@ -250,6 +250,7 @@ func consensusCallbackBeginBlockFn( onNewLogAll := func(l *types.Log) { txListener.OnNewLog(l) xenblocksEL.OnNewLog(l) + // Note: it's possible for logs to get indexed twice by BR and block processing if verWatcher != nil { verWatcher.OnNewLog(l) diff --git a/integration/xenblocks/contracts/tokenregistry/tokenregistry.go b/integration/xenblocks/contracts/tokenregistry/tokenregistry.go new file mode 100644 index 000000000..7ce3be226 --- /dev/null +++ b/integration/xenblocks/contracts/tokenregistry/tokenregistry.go @@ -0,0 +1,1038 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package tokenregistry + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// TokenRegistryFoundToken is an auto generated low-level Go binding around an user-defined struct. +type TokenRegistryFoundToken struct { + CurrencyType *big.Int + Version uint16 +} + +// TokenRegistryTokenConfig is an auto generated low-level Go binding around an user-defined struct. +type TokenRegistryTokenConfig struct { + CurrencyType *big.Int + Token common.Address + Exclusive bool +} + +// TokenregistryMetaData contains all meta data concerning the Tokenregistry contract. +var TokenregistryMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"TokensUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"hash\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"minedTimestamp\",\"type\":\"uint256\"}],\"name\":\"findTokensFromArgon2Hash\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"internalType\":\"structTokenRegistry.FoundToken[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractVoterToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"internalType\":\"contractVoterToken\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"exclusive\",\"type\":\"bool\"}],\"internalType\":\"structTokenRegistry.TokenConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTokenConfigs\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"internalType\":\"contractVoterToken\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"exclusive\",\"type\":\"bool\"}],\"internalType\":\"structTokenRegistry.TokenConfig[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTokenVersions\",\"outputs\":[{\"internalType\":\"uint16[]\",\"name\":\"\",\"type\":\"uint16[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialOwner\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"exclusive\",\"type\":\"bool\"}],\"name\":\"registerToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"tokenIdBySymbol\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenIdCounter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"tokensById\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"internalType\":\"contractVoterToken\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"exclusive\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddr\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"exclusive\",\"type\":\"bool\"}],\"name\":\"updateToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"voteManagerAddr\",\"type\":\"address\"}],\"name\":\"updateVoteManagerAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// TokenregistryABI is the input ABI used to generate the binding from. +// Deprecated: Use TokenregistryMetaData.ABI instead. +var TokenregistryABI = TokenregistryMetaData.ABI + +// Tokenregistry is an auto generated Go binding around an Ethereum contract. +type Tokenregistry struct { + TokenregistryCaller // Read-only binding to the contract + TokenregistryTransactor // Write-only binding to the contract + TokenregistryFilterer // Log filterer for contract events +} + +// TokenregistryCaller is an auto generated read-only Go binding around an Ethereum contract. +type TokenregistryCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TokenregistryTransactor is an auto generated write-only Go binding around an Ethereum contract. +type TokenregistryTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TokenregistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type TokenregistryFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TokenregistrySession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type TokenregistrySession struct { + Contract *Tokenregistry // 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 +} + +// TokenregistryCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type TokenregistryCallerSession struct { + Contract *TokenregistryCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// TokenregistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type TokenregistryTransactorSession struct { + Contract *TokenregistryTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// TokenregistryRaw is an auto generated low-level Go binding around an Ethereum contract. +type TokenregistryRaw struct { + Contract *Tokenregistry // Generic contract binding to access the raw methods on +} + +// TokenregistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type TokenregistryCallerRaw struct { + Contract *TokenregistryCaller // Generic read-only contract binding to access the raw methods on +} + +// TokenregistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type TokenregistryTransactorRaw struct { + Contract *TokenregistryTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewTokenregistry creates a new instance of Tokenregistry, bound to a specific deployed contract. +func NewTokenregistry(address common.Address, backend bind.ContractBackend) (*Tokenregistry, error) { + contract, err := bindTokenregistry(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Tokenregistry{TokenregistryCaller: TokenregistryCaller{contract: contract}, TokenregistryTransactor: TokenregistryTransactor{contract: contract}, TokenregistryFilterer: TokenregistryFilterer{contract: contract}}, nil +} + +// NewTokenregistryCaller creates a new read-only instance of Tokenregistry, bound to a specific deployed contract. +func NewTokenregistryCaller(address common.Address, caller bind.ContractCaller) (*TokenregistryCaller, error) { + contract, err := bindTokenregistry(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &TokenregistryCaller{contract: contract}, nil +} + +// NewTokenregistryTransactor creates a new write-only instance of Tokenregistry, bound to a specific deployed contract. +func NewTokenregistryTransactor(address common.Address, transactor bind.ContractTransactor) (*TokenregistryTransactor, error) { + contract, err := bindTokenregistry(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &TokenregistryTransactor{contract: contract}, nil +} + +// NewTokenregistryFilterer creates a new log filterer instance of Tokenregistry, bound to a specific deployed contract. +func NewTokenregistryFilterer(address common.Address, filterer bind.ContractFilterer) (*TokenregistryFilterer, error) { + contract, err := bindTokenregistry(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &TokenregistryFilterer{contract: contract}, nil +} + +// bindTokenregistry binds a generic wrapper to an already deployed contract. +func bindTokenregistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(TokenregistryABI)) + 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 (_Tokenregistry *TokenregistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Tokenregistry.Contract.TokenregistryCaller.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 (_Tokenregistry *TokenregistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Tokenregistry.Contract.TokenregistryTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Tokenregistry *TokenregistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Tokenregistry.Contract.TokenregistryTransactor.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 (_Tokenregistry *TokenregistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Tokenregistry.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 (_Tokenregistry *TokenregistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Tokenregistry.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Tokenregistry *TokenregistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Tokenregistry.Contract.contract.Transact(opts, method, params...) +} + +// FindTokensFromArgon2Hash is a free data retrieval call binding the contract method 0x7bbbe12d. +// +// Solidity: function findTokensFromArgon2Hash(string hash, uint256 minedTimestamp) view returns((uint256,uint16)[]) +func (_Tokenregistry *TokenregistryCaller) FindTokensFromArgon2Hash(opts *bind.CallOpts, hash string, minedTimestamp *big.Int) ([]TokenRegistryFoundToken, error) { + var out []interface{} + err := _Tokenregistry.contract.Call(opts, &out, "findTokensFromArgon2Hash", hash, minedTimestamp) + + if err != nil { + return *new([]TokenRegistryFoundToken), err + } + + out0 := *abi.ConvertType(out[0], new([]TokenRegistryFoundToken)).(*[]TokenRegistryFoundToken) + + return out0, err + +} + +// FindTokensFromArgon2Hash is a free data retrieval call binding the contract method 0x7bbbe12d. +// +// Solidity: function findTokensFromArgon2Hash(string hash, uint256 minedTimestamp) view returns((uint256,uint16)[]) +func (_Tokenregistry *TokenregistrySession) FindTokensFromArgon2Hash(hash string, minedTimestamp *big.Int) ([]TokenRegistryFoundToken, error) { + return _Tokenregistry.Contract.FindTokensFromArgon2Hash(&_Tokenregistry.CallOpts, hash, minedTimestamp) +} + +// FindTokensFromArgon2Hash is a free data retrieval call binding the contract method 0x7bbbe12d. +// +// Solidity: function findTokensFromArgon2Hash(string hash, uint256 minedTimestamp) view returns((uint256,uint16)[]) +func (_Tokenregistry *TokenregistryCallerSession) FindTokensFromArgon2Hash(hash string, minedTimestamp *big.Int) ([]TokenRegistryFoundToken, error) { + return _Tokenregistry.Contract.FindTokensFromArgon2Hash(&_Tokenregistry.CallOpts, hash, minedTimestamp) +} + +// GetToken is a free data retrieval call binding the contract method 0xe4b50cb8. +// +// Solidity: function getToken(uint256 id) view returns(address) +func (_Tokenregistry *TokenregistryCaller) GetToken(opts *bind.CallOpts, id *big.Int) (common.Address, error) { + var out []interface{} + err := _Tokenregistry.contract.Call(opts, &out, "getToken", id) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetToken is a free data retrieval call binding the contract method 0xe4b50cb8. +// +// Solidity: function getToken(uint256 id) view returns(address) +func (_Tokenregistry *TokenregistrySession) GetToken(id *big.Int) (common.Address, error) { + return _Tokenregistry.Contract.GetToken(&_Tokenregistry.CallOpts, id) +} + +// GetToken is a free data retrieval call binding the contract method 0xe4b50cb8. +// +// Solidity: function getToken(uint256 id) view returns(address) +func (_Tokenregistry *TokenregistryCallerSession) GetToken(id *big.Int) (common.Address, error) { + return _Tokenregistry.Contract.GetToken(&_Tokenregistry.CallOpts, id) +} + +// GetTokenConfig is a free data retrieval call binding the contract method 0x8a003888. +// +// Solidity: function getTokenConfig(uint256 id) view returns((uint256,address,bool)) +func (_Tokenregistry *TokenregistryCaller) GetTokenConfig(opts *bind.CallOpts, id *big.Int) (TokenRegistryTokenConfig, error) { + var out []interface{} + err := _Tokenregistry.contract.Call(opts, &out, "getTokenConfig", id) + + if err != nil { + return *new(TokenRegistryTokenConfig), err + } + + out0 := *abi.ConvertType(out[0], new(TokenRegistryTokenConfig)).(*TokenRegistryTokenConfig) + + return out0, err + +} + +// GetTokenConfig is a free data retrieval call binding the contract method 0x8a003888. +// +// Solidity: function getTokenConfig(uint256 id) view returns((uint256,address,bool)) +func (_Tokenregistry *TokenregistrySession) GetTokenConfig(id *big.Int) (TokenRegistryTokenConfig, error) { + return _Tokenregistry.Contract.GetTokenConfig(&_Tokenregistry.CallOpts, id) +} + +// GetTokenConfig is a free data retrieval call binding the contract method 0x8a003888. +// +// Solidity: function getTokenConfig(uint256 id) view returns((uint256,address,bool)) +func (_Tokenregistry *TokenregistryCallerSession) GetTokenConfig(id *big.Int) (TokenRegistryTokenConfig, error) { + return _Tokenregistry.Contract.GetTokenConfig(&_Tokenregistry.CallOpts, id) +} + +// GetTokenConfigs is a free data retrieval call binding the contract method 0x5547171d. +// +// Solidity: function getTokenConfigs() view returns((uint256,address,bool)[]) +func (_Tokenregistry *TokenregistryCaller) GetTokenConfigs(opts *bind.CallOpts) ([]TokenRegistryTokenConfig, error) { + var out []interface{} + err := _Tokenregistry.contract.Call(opts, &out, "getTokenConfigs") + + if err != nil { + return *new([]TokenRegistryTokenConfig), err + } + + out0 := *abi.ConvertType(out[0], new([]TokenRegistryTokenConfig)).(*[]TokenRegistryTokenConfig) + + return out0, err + +} + +// GetTokenConfigs is a free data retrieval call binding the contract method 0x5547171d. +// +// Solidity: function getTokenConfigs() view returns((uint256,address,bool)[]) +func (_Tokenregistry *TokenregistrySession) GetTokenConfigs() ([]TokenRegistryTokenConfig, error) { + return _Tokenregistry.Contract.GetTokenConfigs(&_Tokenregistry.CallOpts) +} + +// GetTokenConfigs is a free data retrieval call binding the contract method 0x5547171d. +// +// Solidity: function getTokenConfigs() view returns((uint256,address,bool)[]) +func (_Tokenregistry *TokenregistryCallerSession) GetTokenConfigs() ([]TokenRegistryTokenConfig, error) { + return _Tokenregistry.Contract.GetTokenConfigs(&_Tokenregistry.CallOpts) +} + +// GetTokenVersions is a free data retrieval call binding the contract method 0x7e519bd0. +// +// Solidity: function getTokenVersions() view returns(uint16[]) +func (_Tokenregistry *TokenregistryCaller) GetTokenVersions(opts *bind.CallOpts) ([]uint16, error) { + var out []interface{} + err := _Tokenregistry.contract.Call(opts, &out, "getTokenVersions") + + if err != nil { + return *new([]uint16), err + } + + out0 := *abi.ConvertType(out[0], new([]uint16)).(*[]uint16) + + return out0, err + +} + +// GetTokenVersions is a free data retrieval call binding the contract method 0x7e519bd0. +// +// Solidity: function getTokenVersions() view returns(uint16[]) +func (_Tokenregistry *TokenregistrySession) GetTokenVersions() ([]uint16, error) { + return _Tokenregistry.Contract.GetTokenVersions(&_Tokenregistry.CallOpts) +} + +// GetTokenVersions is a free data retrieval call binding the contract method 0x7e519bd0. +// +// Solidity: function getTokenVersions() view returns(uint16[]) +func (_Tokenregistry *TokenregistryCallerSession) GetTokenVersions() ([]uint16, error) { + return _Tokenregistry.Contract.GetTokenVersions(&_Tokenregistry.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Tokenregistry *TokenregistryCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Tokenregistry.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Tokenregistry *TokenregistrySession) Owner() (common.Address, error) { + return _Tokenregistry.Contract.Owner(&_Tokenregistry.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Tokenregistry *TokenregistryCallerSession) Owner() (common.Address, error) { + return _Tokenregistry.Contract.Owner(&_Tokenregistry.CallOpts) +} + +// TokenIdBySymbol is a free data retrieval call binding the contract method 0xb4c33d3f. +// +// Solidity: function tokenIdBySymbol(string ) view returns(uint256) +func (_Tokenregistry *TokenregistryCaller) TokenIdBySymbol(opts *bind.CallOpts, arg0 string) (*big.Int, error) { + var out []interface{} + err := _Tokenregistry.contract.Call(opts, &out, "tokenIdBySymbol", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TokenIdBySymbol is a free data retrieval call binding the contract method 0xb4c33d3f. +// +// Solidity: function tokenIdBySymbol(string ) view returns(uint256) +func (_Tokenregistry *TokenregistrySession) TokenIdBySymbol(arg0 string) (*big.Int, error) { + return _Tokenregistry.Contract.TokenIdBySymbol(&_Tokenregistry.CallOpts, arg0) +} + +// TokenIdBySymbol is a free data retrieval call binding the contract method 0xb4c33d3f. +// +// Solidity: function tokenIdBySymbol(string ) view returns(uint256) +func (_Tokenregistry *TokenregistryCallerSession) TokenIdBySymbol(arg0 string) (*big.Int, error) { + return _Tokenregistry.Contract.TokenIdBySymbol(&_Tokenregistry.CallOpts, arg0) +} + +// TokenIdCounter is a free data retrieval call binding the contract method 0x98bdf6f5. +// +// Solidity: function tokenIdCounter() view returns(uint256) +func (_Tokenregistry *TokenregistryCaller) TokenIdCounter(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Tokenregistry.contract.Call(opts, &out, "tokenIdCounter") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TokenIdCounter is a free data retrieval call binding the contract method 0x98bdf6f5. +// +// Solidity: function tokenIdCounter() view returns(uint256) +func (_Tokenregistry *TokenregistrySession) TokenIdCounter() (*big.Int, error) { + return _Tokenregistry.Contract.TokenIdCounter(&_Tokenregistry.CallOpts) +} + +// TokenIdCounter is a free data retrieval call binding the contract method 0x98bdf6f5. +// +// Solidity: function tokenIdCounter() view returns(uint256) +func (_Tokenregistry *TokenregistryCallerSession) TokenIdCounter() (*big.Int, error) { + return _Tokenregistry.Contract.TokenIdCounter(&_Tokenregistry.CallOpts) +} + +// TokensById is a free data retrieval call binding the contract method 0x346fc98b. +// +// Solidity: function tokensById(uint256 ) view returns(uint256 currencyType, address token, bool exclusive) +func (_Tokenregistry *TokenregistryCaller) TokensById(opts *bind.CallOpts, arg0 *big.Int) (struct { + CurrencyType *big.Int + Token common.Address + Exclusive bool +}, error) { + var out []interface{} + err := _Tokenregistry.contract.Call(opts, &out, "tokensById", arg0) + + outstruct := new(struct { + CurrencyType *big.Int + Token common.Address + Exclusive bool + }) + if err != nil { + return *outstruct, err + } + + outstruct.CurrencyType = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Token = *abi.ConvertType(out[1], new(common.Address)).(*common.Address) + outstruct.Exclusive = *abi.ConvertType(out[2], new(bool)).(*bool) + + return *outstruct, err + +} + +// TokensById is a free data retrieval call binding the contract method 0x346fc98b. +// +// Solidity: function tokensById(uint256 ) view returns(uint256 currencyType, address token, bool exclusive) +func (_Tokenregistry *TokenregistrySession) TokensById(arg0 *big.Int) (struct { + CurrencyType *big.Int + Token common.Address + Exclusive bool +}, error) { + return _Tokenregistry.Contract.TokensById(&_Tokenregistry.CallOpts, arg0) +} + +// TokensById is a free data retrieval call binding the contract method 0x346fc98b. +// +// Solidity: function tokensById(uint256 ) view returns(uint256 currencyType, address token, bool exclusive) +func (_Tokenregistry *TokenregistryCallerSession) TokensById(arg0 *big.Int) (struct { + CurrencyType *big.Int + Token common.Address + Exclusive bool +}, error) { + return _Tokenregistry.Contract.TokensById(&_Tokenregistry.CallOpts, arg0) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address initialOwner) returns() +func (_Tokenregistry *TokenregistryTransactor) Initialize(opts *bind.TransactOpts, initialOwner common.Address) (*types.Transaction, error) { + return _Tokenregistry.contract.Transact(opts, "initialize", initialOwner) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address initialOwner) returns() +func (_Tokenregistry *TokenregistrySession) Initialize(initialOwner common.Address) (*types.Transaction, error) { + return _Tokenregistry.Contract.Initialize(&_Tokenregistry.TransactOpts, initialOwner) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address initialOwner) returns() +func (_Tokenregistry *TokenregistryTransactorSession) Initialize(initialOwner common.Address) (*types.Transaction, error) { + return _Tokenregistry.Contract.Initialize(&_Tokenregistry.TransactOpts, initialOwner) +} + +// RegisterToken is a paid mutator transaction binding the contract method 0x6710b83f. +// +// Solidity: function registerToken(address addr, bool exclusive) returns() +func (_Tokenregistry *TokenregistryTransactor) RegisterToken(opts *bind.TransactOpts, addr common.Address, exclusive bool) (*types.Transaction, error) { + return _Tokenregistry.contract.Transact(opts, "registerToken", addr, exclusive) +} + +// RegisterToken is a paid mutator transaction binding the contract method 0x6710b83f. +// +// Solidity: function registerToken(address addr, bool exclusive) returns() +func (_Tokenregistry *TokenregistrySession) RegisterToken(addr common.Address, exclusive bool) (*types.Transaction, error) { + return _Tokenregistry.Contract.RegisterToken(&_Tokenregistry.TransactOpts, addr, exclusive) +} + +// RegisterToken is a paid mutator transaction binding the contract method 0x6710b83f. +// +// Solidity: function registerToken(address addr, bool exclusive) returns() +func (_Tokenregistry *TokenregistryTransactorSession) RegisterToken(addr common.Address, exclusive bool) (*types.Transaction, error) { + return _Tokenregistry.Contract.RegisterToken(&_Tokenregistry.TransactOpts, addr, exclusive) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Tokenregistry *TokenregistryTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Tokenregistry.contract.Transact(opts, "renounceOwnership") +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Tokenregistry *TokenregistrySession) RenounceOwnership() (*types.Transaction, error) { + return _Tokenregistry.Contract.RenounceOwnership(&_Tokenregistry.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Tokenregistry *TokenregistryTransactorSession) RenounceOwnership() (*types.Transaction, error) { + return _Tokenregistry.Contract.RenounceOwnership(&_Tokenregistry.TransactOpts) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Tokenregistry *TokenregistryTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { + return _Tokenregistry.contract.Transact(opts, "transferOwnership", newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Tokenregistry *TokenregistrySession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _Tokenregistry.Contract.TransferOwnership(&_Tokenregistry.TransactOpts, newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Tokenregistry *TokenregistryTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _Tokenregistry.Contract.TransferOwnership(&_Tokenregistry.TransactOpts, newOwner) +} + +// UpdateToken is a paid mutator transaction binding the contract method 0xda8d73fa. +// +// Solidity: function updateToken(uint256 tokenId, address tokenAddr, bool exclusive) returns() +func (_Tokenregistry *TokenregistryTransactor) UpdateToken(opts *bind.TransactOpts, tokenId *big.Int, tokenAddr common.Address, exclusive bool) (*types.Transaction, error) { + return _Tokenregistry.contract.Transact(opts, "updateToken", tokenId, tokenAddr, exclusive) +} + +// UpdateToken is a paid mutator transaction binding the contract method 0xda8d73fa. +// +// Solidity: function updateToken(uint256 tokenId, address tokenAddr, bool exclusive) returns() +func (_Tokenregistry *TokenregistrySession) UpdateToken(tokenId *big.Int, tokenAddr common.Address, exclusive bool) (*types.Transaction, error) { + return _Tokenregistry.Contract.UpdateToken(&_Tokenregistry.TransactOpts, tokenId, tokenAddr, exclusive) +} + +// UpdateToken is a paid mutator transaction binding the contract method 0xda8d73fa. +// +// Solidity: function updateToken(uint256 tokenId, address tokenAddr, bool exclusive) returns() +func (_Tokenregistry *TokenregistryTransactorSession) UpdateToken(tokenId *big.Int, tokenAddr common.Address, exclusive bool) (*types.Transaction, error) { + return _Tokenregistry.Contract.UpdateToken(&_Tokenregistry.TransactOpts, tokenId, tokenAddr, exclusive) +} + +// UpdateVoteManagerAddress is a paid mutator transaction binding the contract method 0xf5b4751d. +// +// Solidity: function updateVoteManagerAddress(address voteManagerAddr) returns() +func (_Tokenregistry *TokenregistryTransactor) UpdateVoteManagerAddress(opts *bind.TransactOpts, voteManagerAddr common.Address) (*types.Transaction, error) { + return _Tokenregistry.contract.Transact(opts, "updateVoteManagerAddress", voteManagerAddr) +} + +// UpdateVoteManagerAddress is a paid mutator transaction binding the contract method 0xf5b4751d. +// +// Solidity: function updateVoteManagerAddress(address voteManagerAddr) returns() +func (_Tokenregistry *TokenregistrySession) UpdateVoteManagerAddress(voteManagerAddr common.Address) (*types.Transaction, error) { + return _Tokenregistry.Contract.UpdateVoteManagerAddress(&_Tokenregistry.TransactOpts, voteManagerAddr) +} + +// UpdateVoteManagerAddress is a paid mutator transaction binding the contract method 0xf5b4751d. +// +// Solidity: function updateVoteManagerAddress(address voteManagerAddr) returns() +func (_Tokenregistry *TokenregistryTransactorSession) UpdateVoteManagerAddress(voteManagerAddr common.Address) (*types.Transaction, error) { + return _Tokenregistry.Contract.UpdateVoteManagerAddress(&_Tokenregistry.TransactOpts, voteManagerAddr) +} + +// TokenregistryInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the Tokenregistry contract. +type TokenregistryInitializedIterator struct { + Event *TokenregistryInitialized // 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 *TokenregistryInitializedIterator) 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(TokenregistryInitialized) + 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(TokenregistryInitialized) + 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 *TokenregistryInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenregistryInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenregistryInitialized represents a Initialized event raised by the Tokenregistry contract. +type TokenregistryInitialized struct { + Version uint64 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2. +// +// Solidity: event Initialized(uint64 version) +func (_Tokenregistry *TokenregistryFilterer) FilterInitialized(opts *bind.FilterOpts) (*TokenregistryInitializedIterator, error) { + + logs, sub, err := _Tokenregistry.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &TokenregistryInitializedIterator{contract: _Tokenregistry.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2. +// +// Solidity: event Initialized(uint64 version) +func (_Tokenregistry *TokenregistryFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *TokenregistryInitialized) (event.Subscription, error) { + + logs, sub, err := _Tokenregistry.contract.WatchLogs(opts, "Initialized") + 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(TokenregistryInitialized) + if err := _Tokenregistry.contract.UnpackLog(event, "Initialized", 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 +} + +// ParseInitialized is a log parse operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2. +// +// Solidity: event Initialized(uint64 version) +func (_Tokenregistry *TokenregistryFilterer) ParseInitialized(log types.Log) (*TokenregistryInitialized, error) { + event := new(TokenregistryInitialized) + if err := _Tokenregistry.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TokenregistryOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Tokenregistry contract. +type TokenregistryOwnershipTransferredIterator struct { + Event *TokenregistryOwnershipTransferred // 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 *TokenregistryOwnershipTransferredIterator) 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(TokenregistryOwnershipTransferred) + 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(TokenregistryOwnershipTransferred) + 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 *TokenregistryOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenregistryOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenregistryOwnershipTransferred represents a OwnershipTransferred event raised by the Tokenregistry contract. +type TokenregistryOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Tokenregistry *TokenregistryFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*TokenregistryOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Tokenregistry.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &TokenregistryOwnershipTransferredIterator{contract: _Tokenregistry.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Tokenregistry *TokenregistryFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *TokenregistryOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Tokenregistry.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + 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(TokenregistryOwnershipTransferred) + if err := _Tokenregistry.contract.UnpackLog(event, "OwnershipTransferred", 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 +} + +// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Tokenregistry *TokenregistryFilterer) ParseOwnershipTransferred(log types.Log) (*TokenregistryOwnershipTransferred, error) { + event := new(TokenregistryOwnershipTransferred) + if err := _Tokenregistry.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TokenregistryTokensUpdatedIterator is returned from FilterTokensUpdated and is used to iterate over the raw logs and unpacked data for TokensUpdated events raised by the Tokenregistry contract. +type TokenregistryTokensUpdatedIterator struct { + Event *TokenregistryTokensUpdated // 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 *TokenregistryTokensUpdatedIterator) 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(TokenregistryTokensUpdated) + 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(TokenregistryTokensUpdated) + 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 *TokenregistryTokensUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenregistryTokensUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenregistryTokensUpdated represents a TokensUpdated event raised by the Tokenregistry contract. +type TokenregistryTokensUpdated struct { + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTokensUpdated is a free log retrieval operation binding the contract event 0xc7cce9e0ee378bcf7fd342cae3d8eb17caaf3e9be70c370256ba6517189638dc. +// +// Solidity: event TokensUpdated() +func (_Tokenregistry *TokenregistryFilterer) FilterTokensUpdated(opts *bind.FilterOpts) (*TokenregistryTokensUpdatedIterator, error) { + + logs, sub, err := _Tokenregistry.contract.FilterLogs(opts, "TokensUpdated") + if err != nil { + return nil, err + } + return &TokenregistryTokensUpdatedIterator{contract: _Tokenregistry.contract, event: "TokensUpdated", logs: logs, sub: sub}, nil +} + +// WatchTokensUpdated is a free log subscription operation binding the contract event 0xc7cce9e0ee378bcf7fd342cae3d8eb17caaf3e9be70c370256ba6517189638dc. +// +// Solidity: event TokensUpdated() +func (_Tokenregistry *TokenregistryFilterer) WatchTokensUpdated(opts *bind.WatchOpts, sink chan<- *TokenregistryTokensUpdated) (event.Subscription, error) { + + logs, sub, err := _Tokenregistry.contract.WatchLogs(opts, "TokensUpdated") + 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(TokenregistryTokensUpdated) + if err := _Tokenregistry.contract.UnpackLog(event, "TokensUpdated", 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 +} + +// ParseTokensUpdated is a log parse operation binding the contract event 0xc7cce9e0ee378bcf7fd342cae3d8eb17caaf3e9be70c370256ba6517189638dc. +// +// Solidity: event TokensUpdated() +func (_Tokenregistry *TokenregistryFilterer) ParseTokensUpdated(log types.Log) (*TokenregistryTokensUpdated, error) { + event := new(TokenregistryTokensUpdated) + if err := _Tokenregistry.contract.UnpackLog(event, "TokensUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + diff --git a/integration/xenblocks/contracts/votemanager/votemanager.go b/integration/xenblocks/contracts/votemanager/votemanager.go index ae9022cca..08a1afb33 100644 --- a/integration/xenblocks/contracts/votemanager/votemanager.go +++ b/integration/xenblocks/contracts/votemanager/votemanager.go @@ -28,16 +28,17 @@ var ( _ = event.NewSubscription ) -// VoteManagerPayload is an auto generated low-level Go binding around an user-defined struct. -type VoteManagerPayload struct { +// VoteManagerVotePayload is an auto generated low-level Go binding around an user-defined struct. +type VoteManagerVotePayload struct { HashId *big.Int CurrencyType *big.Int MintedBlockNumber *big.Int + Version uint16 } // VotemanagerMetaData contains all meta data concerning the Votemanager contract. var VotemanagerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"name\":\"MintToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"votes\",\"type\":\"uint16\"}],\"name\":\"VoteToken\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"blockStorage\",\"outputs\":[{\"internalType\":\"contractBlockStorage\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialSfcAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialBlockStorageAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"initialVotePercentage\",\"type\":\"uint8\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sfcLib\",\"outputs\":[{\"internalType\":\"contractSFCLib\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_mintedBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_validatorId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"}],\"name\":\"shouldVote\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenRegistry\",\"outputs\":[{\"internalType\":\"contractTokenRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_blockStorageAddress\",\"type\":\"address\"}],\"name\":\"updateBlockStorageAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sfcLibAddress\",\"type\":\"address\"}],\"name\":\"updateSfcLibAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenRegistryAddress\",\"type\":\"address\"}],\"name\":\"updateTokenRegistryAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_votePercentage\",\"type\":\"uint8\"}],\"name\":\"updateVotePercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"validatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"mintedBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currencyType\",\"type\":\"uint256\"}],\"name\":\"vote\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"mintedBlockNumber\",\"type\":\"uint256\"}],\"internalType\":\"structVoteManager.Payload[]\",\"name\":\"payload\",\"type\":\"tuple[]\"}],\"name\":\"voteBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"votePercentage\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAValidator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VersionMismatch\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"name\":\"MintToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"votes\",\"type\":\"uint16\"}],\"name\":\"VoteToken\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"blockStorage\",\"outputs\":[{\"internalType\":\"contractBlockStorage\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialSfcAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialBlockStorageAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"initialVotePercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"initialVoteBufferPercent\",\"type\":\"uint8\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfVotes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sfc\",\"outputs\":[{\"internalType\":\"contractSFC\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"mintedBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"validatorId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"}],\"name\":\"shouldVote\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenRegistry\",\"outputs\":[{\"internalType\":\"contractTokenRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockStorageAddress\",\"type\":\"address\"}],\"name\":\"updateBlockStorageAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sfcAddress\",\"type\":\"address\"}],\"name\":\"updateSfcAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenRegistryAddress_\",\"type\":\"address\"}],\"name\":\"updateTokenRegistryAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"voteBufferPercent_\",\"type\":\"uint8\"}],\"name\":\"updateVoteBufferPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"votePercentage_\",\"type\":\"uint8\"}],\"name\":\"updateVotePercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"validatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"mintedBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"internalType\":\"structVoteManager.VotePayload[]\",\"name\":\"payload\",\"type\":\"tuple[]\"}],\"name\":\"voteBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"voteBufferPercent\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"votePercentage\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } // VotemanagerABI is the input ABI used to generate the binding from. @@ -310,12 +311,43 @@ func (_Votemanager *VotemanagerCallerSession) RequiredNumOfValidators() (*big.In return _Votemanager.Contract.RequiredNumOfValidators(&_Votemanager.CallOpts) } -// SfcLib is a free data retrieval call binding the contract method 0x1ff9794b. +// RequiredNumOfVotes is a free data retrieval call binding the contract method 0x27b26533. // -// Solidity: function sfcLib() view returns(address) -func (_Votemanager *VotemanagerCaller) SfcLib(opts *bind.CallOpts) (common.Address, error) { +// Solidity: function requiredNumOfVotes() view returns(uint256) +func (_Votemanager *VotemanagerCaller) RequiredNumOfVotes(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} - err := _Votemanager.contract.Call(opts, &out, "sfcLib") + err := _Votemanager.contract.Call(opts, &out, "requiredNumOfVotes") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// RequiredNumOfVotes is a free data retrieval call binding the contract method 0x27b26533. +// +// Solidity: function requiredNumOfVotes() view returns(uint256) +func (_Votemanager *VotemanagerSession) RequiredNumOfVotes() (*big.Int, error) { + return _Votemanager.Contract.RequiredNumOfVotes(&_Votemanager.CallOpts) +} + +// RequiredNumOfVotes is a free data retrieval call binding the contract method 0x27b26533. +// +// Solidity: function requiredNumOfVotes() view returns(uint256) +func (_Votemanager *VotemanagerCallerSession) RequiredNumOfVotes() (*big.Int, error) { + return _Votemanager.Contract.RequiredNumOfVotes(&_Votemanager.CallOpts) +} + +// Sfc is a free data retrieval call binding the contract method 0x8992229f. +// +// Solidity: function sfc() view returns(address) +func (_Votemanager *VotemanagerCaller) Sfc(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "sfc") if err != nil { return *new(common.Address), err @@ -327,26 +359,26 @@ func (_Votemanager *VotemanagerCaller) SfcLib(opts *bind.CallOpts) (common.Addre } -// SfcLib is a free data retrieval call binding the contract method 0x1ff9794b. +// Sfc is a free data retrieval call binding the contract method 0x8992229f. // -// Solidity: function sfcLib() view returns(address) -func (_Votemanager *VotemanagerSession) SfcLib() (common.Address, error) { - return _Votemanager.Contract.SfcLib(&_Votemanager.CallOpts) +// Solidity: function sfc() view returns(address) +func (_Votemanager *VotemanagerSession) Sfc() (common.Address, error) { + return _Votemanager.Contract.Sfc(&_Votemanager.CallOpts) } -// SfcLib is a free data retrieval call binding the contract method 0x1ff9794b. +// Sfc is a free data retrieval call binding the contract method 0x8992229f. // -// Solidity: function sfcLib() view returns(address) -func (_Votemanager *VotemanagerCallerSession) SfcLib() (common.Address, error) { - return _Votemanager.Contract.SfcLib(&_Votemanager.CallOpts) +// Solidity: function sfc() view returns(address) +func (_Votemanager *VotemanagerCallerSession) Sfc() (common.Address, error) { + return _Votemanager.Contract.Sfc(&_Votemanager.CallOpts) } // ShouldVote is a free data retrieval call binding the contract method 0xb1faefbb. // -// Solidity: function shouldVote(uint256 _mintedBlockNumber, uint256 _validatorId, uint256 _hashId) view returns(bool) -func (_Votemanager *VotemanagerCaller) ShouldVote(opts *bind.CallOpts, _mintedBlockNumber *big.Int, _validatorId *big.Int, _hashId *big.Int) (bool, error) { +// Solidity: function shouldVote(uint256 mintedBlockNumber, uint256 validatorId, uint256 hashId) view returns(bool) +func (_Votemanager *VotemanagerCaller) ShouldVote(opts *bind.CallOpts, mintedBlockNumber *big.Int, validatorId *big.Int, hashId *big.Int) (bool, error) { var out []interface{} - err := _Votemanager.contract.Call(opts, &out, "shouldVote", _mintedBlockNumber, _validatorId, _hashId) + err := _Votemanager.contract.Call(opts, &out, "shouldVote", mintedBlockNumber, validatorId, hashId) if err != nil { return *new(bool), err @@ -360,16 +392,16 @@ func (_Votemanager *VotemanagerCaller) ShouldVote(opts *bind.CallOpts, _mintedBl // ShouldVote is a free data retrieval call binding the contract method 0xb1faefbb. // -// Solidity: function shouldVote(uint256 _mintedBlockNumber, uint256 _validatorId, uint256 _hashId) view returns(bool) -func (_Votemanager *VotemanagerSession) ShouldVote(_mintedBlockNumber *big.Int, _validatorId *big.Int, _hashId *big.Int) (bool, error) { - return _Votemanager.Contract.ShouldVote(&_Votemanager.CallOpts, _mintedBlockNumber, _validatorId, _hashId) +// Solidity: function shouldVote(uint256 mintedBlockNumber, uint256 validatorId, uint256 hashId) view returns(bool) +func (_Votemanager *VotemanagerSession) ShouldVote(mintedBlockNumber *big.Int, validatorId *big.Int, hashId *big.Int) (bool, error) { + return _Votemanager.Contract.ShouldVote(&_Votemanager.CallOpts, mintedBlockNumber, validatorId, hashId) } // ShouldVote is a free data retrieval call binding the contract method 0xb1faefbb. // -// Solidity: function shouldVote(uint256 _mintedBlockNumber, uint256 _validatorId, uint256 _hashId) view returns(bool) -func (_Votemanager *VotemanagerCallerSession) ShouldVote(_mintedBlockNumber *big.Int, _validatorId *big.Int, _hashId *big.Int) (bool, error) { - return _Votemanager.Contract.ShouldVote(&_Votemanager.CallOpts, _mintedBlockNumber, _validatorId, _hashId) +// Solidity: function shouldVote(uint256 mintedBlockNumber, uint256 validatorId, uint256 hashId) view returns(bool) +func (_Votemanager *VotemanagerCallerSession) ShouldVote(mintedBlockNumber *big.Int, validatorId *big.Int, hashId *big.Int) (bool, error) { + return _Votemanager.Contract.ShouldVote(&_Votemanager.CallOpts, mintedBlockNumber, validatorId, hashId) } // TokenRegistry is a free data retrieval call binding the contract method 0x9d23c4c7. @@ -434,6 +466,37 @@ func (_Votemanager *VotemanagerCallerSession) ValidatorCount() (*big.Int, error) return _Votemanager.Contract.ValidatorCount(&_Votemanager.CallOpts) } +// VoteBufferPercent is a free data retrieval call binding the contract method 0xa2379199. +// +// Solidity: function voteBufferPercent() view returns(uint8) +func (_Votemanager *VotemanagerCaller) VoteBufferPercent(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "voteBufferPercent") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// VoteBufferPercent is a free data retrieval call binding the contract method 0xa2379199. +// +// Solidity: function voteBufferPercent() view returns(uint8) +func (_Votemanager *VotemanagerSession) VoteBufferPercent() (uint8, error) { + return _Votemanager.Contract.VoteBufferPercent(&_Votemanager.CallOpts) +} + +// VoteBufferPercent is a free data retrieval call binding the contract method 0xa2379199. +// +// Solidity: function voteBufferPercent() view returns(uint8) +func (_Votemanager *VotemanagerCallerSession) VoteBufferPercent() (uint8, error) { + return _Votemanager.Contract.VoteBufferPercent(&_Votemanager.CallOpts) +} + // VotePercentage is a free data retrieval call binding the contract method 0x34b502c0. // // Solidity: function votePercentage() view returns(uint8) @@ -527,25 +590,25 @@ func (_Votemanager *VotemanagerCallerSession) VotesByHashIdAndValidatorIdAndCurr return _Votemanager.Contract.VotesByHashIdAndValidatorIdAndCurrencyType(&_Votemanager.CallOpts, arg0, arg1, arg2) } -// Initialize is a paid mutator transaction binding the contract method 0x3073cecf. +// Initialize is a paid mutator transaction binding the contract method 0x903cd3e3. // -// Solidity: function initialize(address initialOwner, address initialSfcAddress, address initialBlockStorageAddress, uint8 initialVotePercentage) returns() -func (_Votemanager *VotemanagerTransactor) Initialize(opts *bind.TransactOpts, initialOwner common.Address, initialSfcAddress common.Address, initialBlockStorageAddress common.Address, initialVotePercentage uint8) (*types.Transaction, error) { - return _Votemanager.contract.Transact(opts, "initialize", initialOwner, initialSfcAddress, initialBlockStorageAddress, initialVotePercentage) +// Solidity: function initialize(address initialOwner, address initialSfcAddress, address initialBlockStorageAddress, uint8 initialVotePercentage, uint8 initialVoteBufferPercent) returns() +func (_Votemanager *VotemanagerTransactor) Initialize(opts *bind.TransactOpts, initialOwner common.Address, initialSfcAddress common.Address, initialBlockStorageAddress common.Address, initialVotePercentage uint8, initialVoteBufferPercent uint8) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "initialize", initialOwner, initialSfcAddress, initialBlockStorageAddress, initialVotePercentage, initialVoteBufferPercent) } -// Initialize is a paid mutator transaction binding the contract method 0x3073cecf. +// Initialize is a paid mutator transaction binding the contract method 0x903cd3e3. // -// Solidity: function initialize(address initialOwner, address initialSfcAddress, address initialBlockStorageAddress, uint8 initialVotePercentage) returns() -func (_Votemanager *VotemanagerSession) Initialize(initialOwner common.Address, initialSfcAddress common.Address, initialBlockStorageAddress common.Address, initialVotePercentage uint8) (*types.Transaction, error) { - return _Votemanager.Contract.Initialize(&_Votemanager.TransactOpts, initialOwner, initialSfcAddress, initialBlockStorageAddress, initialVotePercentage) +// Solidity: function initialize(address initialOwner, address initialSfcAddress, address initialBlockStorageAddress, uint8 initialVotePercentage, uint8 initialVoteBufferPercent) returns() +func (_Votemanager *VotemanagerSession) Initialize(initialOwner common.Address, initialSfcAddress common.Address, initialBlockStorageAddress common.Address, initialVotePercentage uint8, initialVoteBufferPercent uint8) (*types.Transaction, error) { + return _Votemanager.Contract.Initialize(&_Votemanager.TransactOpts, initialOwner, initialSfcAddress, initialBlockStorageAddress, initialVotePercentage, initialVoteBufferPercent) } -// Initialize is a paid mutator transaction binding the contract method 0x3073cecf. +// Initialize is a paid mutator transaction binding the contract method 0x903cd3e3. // -// Solidity: function initialize(address initialOwner, address initialSfcAddress, address initialBlockStorageAddress, uint8 initialVotePercentage) returns() -func (_Votemanager *VotemanagerTransactorSession) Initialize(initialOwner common.Address, initialSfcAddress common.Address, initialBlockStorageAddress common.Address, initialVotePercentage uint8) (*types.Transaction, error) { - return _Votemanager.Contract.Initialize(&_Votemanager.TransactOpts, initialOwner, initialSfcAddress, initialBlockStorageAddress, initialVotePercentage) +// Solidity: function initialize(address initialOwner, address initialSfcAddress, address initialBlockStorageAddress, uint8 initialVotePercentage, uint8 initialVoteBufferPercent) returns() +func (_Votemanager *VotemanagerTransactorSession) Initialize(initialOwner common.Address, initialSfcAddress common.Address, initialBlockStorageAddress common.Address, initialVotePercentage uint8, initialVoteBufferPercent uint8) (*types.Transaction, error) { + return _Votemanager.Contract.Initialize(&_Votemanager.TransactOpts, initialOwner, initialSfcAddress, initialBlockStorageAddress, initialVotePercentage, initialVoteBufferPercent) } // RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. @@ -592,127 +655,127 @@ func (_Votemanager *VotemanagerTransactorSession) TransferOwnership(newOwner com // UpdateBlockStorageAddress is a paid mutator transaction binding the contract method 0x3cc66f46. // -// Solidity: function updateBlockStorageAddress(address _blockStorageAddress) returns() -func (_Votemanager *VotemanagerTransactor) UpdateBlockStorageAddress(opts *bind.TransactOpts, _blockStorageAddress common.Address) (*types.Transaction, error) { - return _Votemanager.contract.Transact(opts, "updateBlockStorageAddress", _blockStorageAddress) +// Solidity: function updateBlockStorageAddress(address blockStorageAddress) returns() +func (_Votemanager *VotemanagerTransactor) UpdateBlockStorageAddress(opts *bind.TransactOpts, blockStorageAddress common.Address) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "updateBlockStorageAddress", blockStorageAddress) } // UpdateBlockStorageAddress is a paid mutator transaction binding the contract method 0x3cc66f46. // -// Solidity: function updateBlockStorageAddress(address _blockStorageAddress) returns() -func (_Votemanager *VotemanagerSession) UpdateBlockStorageAddress(_blockStorageAddress common.Address) (*types.Transaction, error) { - return _Votemanager.Contract.UpdateBlockStorageAddress(&_Votemanager.TransactOpts, _blockStorageAddress) +// Solidity: function updateBlockStorageAddress(address blockStorageAddress) returns() +func (_Votemanager *VotemanagerSession) UpdateBlockStorageAddress(blockStorageAddress common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateBlockStorageAddress(&_Votemanager.TransactOpts, blockStorageAddress) } // UpdateBlockStorageAddress is a paid mutator transaction binding the contract method 0x3cc66f46. // -// Solidity: function updateBlockStorageAddress(address _blockStorageAddress) returns() -func (_Votemanager *VotemanagerTransactorSession) UpdateBlockStorageAddress(_blockStorageAddress common.Address) (*types.Transaction, error) { - return _Votemanager.Contract.UpdateBlockStorageAddress(&_Votemanager.TransactOpts, _blockStorageAddress) +// Solidity: function updateBlockStorageAddress(address blockStorageAddress) returns() +func (_Votemanager *VotemanagerTransactorSession) UpdateBlockStorageAddress(blockStorageAddress common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateBlockStorageAddress(&_Votemanager.TransactOpts, blockStorageAddress) } -// UpdateSfcLibAddress is a paid mutator transaction binding the contract method 0x9d138a3c. +// UpdateSfcAddress is a paid mutator transaction binding the contract method 0xcbb9d8c9. // -// Solidity: function updateSfcLibAddress(address _sfcLibAddress) returns() -func (_Votemanager *VotemanagerTransactor) UpdateSfcLibAddress(opts *bind.TransactOpts, _sfcLibAddress common.Address) (*types.Transaction, error) { - return _Votemanager.contract.Transact(opts, "updateSfcLibAddress", _sfcLibAddress) +// Solidity: function updateSfcAddress(address sfcAddress) returns() +func (_Votemanager *VotemanagerTransactor) UpdateSfcAddress(opts *bind.TransactOpts, sfcAddress common.Address) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "updateSfcAddress", sfcAddress) } -// UpdateSfcLibAddress is a paid mutator transaction binding the contract method 0x9d138a3c. +// UpdateSfcAddress is a paid mutator transaction binding the contract method 0xcbb9d8c9. // -// Solidity: function updateSfcLibAddress(address _sfcLibAddress) returns() -func (_Votemanager *VotemanagerSession) UpdateSfcLibAddress(_sfcLibAddress common.Address) (*types.Transaction, error) { - return _Votemanager.Contract.UpdateSfcLibAddress(&_Votemanager.TransactOpts, _sfcLibAddress) +// Solidity: function updateSfcAddress(address sfcAddress) returns() +func (_Votemanager *VotemanagerSession) UpdateSfcAddress(sfcAddress common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateSfcAddress(&_Votemanager.TransactOpts, sfcAddress) } -// UpdateSfcLibAddress is a paid mutator transaction binding the contract method 0x9d138a3c. +// UpdateSfcAddress is a paid mutator transaction binding the contract method 0xcbb9d8c9. // -// Solidity: function updateSfcLibAddress(address _sfcLibAddress) returns() -func (_Votemanager *VotemanagerTransactorSession) UpdateSfcLibAddress(_sfcLibAddress common.Address) (*types.Transaction, error) { - return _Votemanager.Contract.UpdateSfcLibAddress(&_Votemanager.TransactOpts, _sfcLibAddress) +// Solidity: function updateSfcAddress(address sfcAddress) returns() +func (_Votemanager *VotemanagerTransactorSession) UpdateSfcAddress(sfcAddress common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateSfcAddress(&_Votemanager.TransactOpts, sfcAddress) } // UpdateTokenRegistryAddress is a paid mutator transaction binding the contract method 0x520051d7. // -// Solidity: function updateTokenRegistryAddress(address _tokenRegistryAddress) returns() -func (_Votemanager *VotemanagerTransactor) UpdateTokenRegistryAddress(opts *bind.TransactOpts, _tokenRegistryAddress common.Address) (*types.Transaction, error) { - return _Votemanager.contract.Transact(opts, "updateTokenRegistryAddress", _tokenRegistryAddress) +// Solidity: function updateTokenRegistryAddress(address tokenRegistryAddress_) returns() +func (_Votemanager *VotemanagerTransactor) UpdateTokenRegistryAddress(opts *bind.TransactOpts, tokenRegistryAddress_ common.Address) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "updateTokenRegistryAddress", tokenRegistryAddress_) } // UpdateTokenRegistryAddress is a paid mutator transaction binding the contract method 0x520051d7. // -// Solidity: function updateTokenRegistryAddress(address _tokenRegistryAddress) returns() -func (_Votemanager *VotemanagerSession) UpdateTokenRegistryAddress(_tokenRegistryAddress common.Address) (*types.Transaction, error) { - return _Votemanager.Contract.UpdateTokenRegistryAddress(&_Votemanager.TransactOpts, _tokenRegistryAddress) +// Solidity: function updateTokenRegistryAddress(address tokenRegistryAddress_) returns() +func (_Votemanager *VotemanagerSession) UpdateTokenRegistryAddress(tokenRegistryAddress_ common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateTokenRegistryAddress(&_Votemanager.TransactOpts, tokenRegistryAddress_) } // UpdateTokenRegistryAddress is a paid mutator transaction binding the contract method 0x520051d7. // -// Solidity: function updateTokenRegistryAddress(address _tokenRegistryAddress) returns() -func (_Votemanager *VotemanagerTransactorSession) UpdateTokenRegistryAddress(_tokenRegistryAddress common.Address) (*types.Transaction, error) { - return _Votemanager.Contract.UpdateTokenRegistryAddress(&_Votemanager.TransactOpts, _tokenRegistryAddress) +// Solidity: function updateTokenRegistryAddress(address tokenRegistryAddress_) returns() +func (_Votemanager *VotemanagerTransactorSession) UpdateTokenRegistryAddress(tokenRegistryAddress_ common.Address) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateTokenRegistryAddress(&_Votemanager.TransactOpts, tokenRegistryAddress_) } -// UpdateVotePercentage is a paid mutator transaction binding the contract method 0x8ba8405c. +// UpdateVoteBufferPercentage is a paid mutator transaction binding the contract method 0xf3a3a784. // -// Solidity: function updateVotePercentage(uint8 _votePercentage) returns() -func (_Votemanager *VotemanagerTransactor) UpdateVotePercentage(opts *bind.TransactOpts, _votePercentage uint8) (*types.Transaction, error) { - return _Votemanager.contract.Transact(opts, "updateVotePercentage", _votePercentage) +// Solidity: function updateVoteBufferPercentage(uint8 voteBufferPercent_) returns() +func (_Votemanager *VotemanagerTransactor) UpdateVoteBufferPercentage(opts *bind.TransactOpts, voteBufferPercent_ uint8) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "updateVoteBufferPercentage", voteBufferPercent_) } -// UpdateVotePercentage is a paid mutator transaction binding the contract method 0x8ba8405c. +// UpdateVoteBufferPercentage is a paid mutator transaction binding the contract method 0xf3a3a784. // -// Solidity: function updateVotePercentage(uint8 _votePercentage) returns() -func (_Votemanager *VotemanagerSession) UpdateVotePercentage(_votePercentage uint8) (*types.Transaction, error) { - return _Votemanager.Contract.UpdateVotePercentage(&_Votemanager.TransactOpts, _votePercentage) +// Solidity: function updateVoteBufferPercentage(uint8 voteBufferPercent_) returns() +func (_Votemanager *VotemanagerSession) UpdateVoteBufferPercentage(voteBufferPercent_ uint8) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateVoteBufferPercentage(&_Votemanager.TransactOpts, voteBufferPercent_) } -// UpdateVotePercentage is a paid mutator transaction binding the contract method 0x8ba8405c. +// UpdateVoteBufferPercentage is a paid mutator transaction binding the contract method 0xf3a3a784. // -// Solidity: function updateVotePercentage(uint8 _votePercentage) returns() -func (_Votemanager *VotemanagerTransactorSession) UpdateVotePercentage(_votePercentage uint8) (*types.Transaction, error) { - return _Votemanager.Contract.UpdateVotePercentage(&_Votemanager.TransactOpts, _votePercentage) +// Solidity: function updateVoteBufferPercentage(uint8 voteBufferPercent_) returns() +func (_Votemanager *VotemanagerTransactorSession) UpdateVoteBufferPercentage(voteBufferPercent_ uint8) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateVoteBufferPercentage(&_Votemanager.TransactOpts, voteBufferPercent_) } -// Vote is a paid mutator transaction binding the contract method 0x8a6655d6. +// UpdateVotePercentage is a paid mutator transaction binding the contract method 0x8ba8405c. // -// Solidity: function vote(uint256 mintedBlockNumber, uint256 _hashId, uint256 _currencyType) returns() -func (_Votemanager *VotemanagerTransactor) Vote(opts *bind.TransactOpts, mintedBlockNumber *big.Int, _hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { - return _Votemanager.contract.Transact(opts, "vote", mintedBlockNumber, _hashId, _currencyType) +// Solidity: function updateVotePercentage(uint8 votePercentage_) returns() +func (_Votemanager *VotemanagerTransactor) UpdateVotePercentage(opts *bind.TransactOpts, votePercentage_ uint8) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "updateVotePercentage", votePercentage_) } -// Vote is a paid mutator transaction binding the contract method 0x8a6655d6. +// UpdateVotePercentage is a paid mutator transaction binding the contract method 0x8ba8405c. // -// Solidity: function vote(uint256 mintedBlockNumber, uint256 _hashId, uint256 _currencyType) returns() -func (_Votemanager *VotemanagerSession) Vote(mintedBlockNumber *big.Int, _hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { - return _Votemanager.Contract.Vote(&_Votemanager.TransactOpts, mintedBlockNumber, _hashId, _currencyType) +// Solidity: function updateVotePercentage(uint8 votePercentage_) returns() +func (_Votemanager *VotemanagerSession) UpdateVotePercentage(votePercentage_ uint8) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateVotePercentage(&_Votemanager.TransactOpts, votePercentage_) } -// Vote is a paid mutator transaction binding the contract method 0x8a6655d6. +// UpdateVotePercentage is a paid mutator transaction binding the contract method 0x8ba8405c. // -// Solidity: function vote(uint256 mintedBlockNumber, uint256 _hashId, uint256 _currencyType) returns() -func (_Votemanager *VotemanagerTransactorSession) Vote(mintedBlockNumber *big.Int, _hashId *big.Int, _currencyType *big.Int) (*types.Transaction, error) { - return _Votemanager.Contract.Vote(&_Votemanager.TransactOpts, mintedBlockNumber, _hashId, _currencyType) +// Solidity: function updateVotePercentage(uint8 votePercentage_) returns() +func (_Votemanager *VotemanagerTransactorSession) UpdateVotePercentage(votePercentage_ uint8) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateVotePercentage(&_Votemanager.TransactOpts, votePercentage_) } -// VoteBatch is a paid mutator transaction binding the contract method 0x149ff154. +// VoteBatch is a paid mutator transaction binding the contract method 0xe53edd93. // -// Solidity: function voteBatch((uint256,uint256,uint256)[] payload) returns() -func (_Votemanager *VotemanagerTransactor) VoteBatch(opts *bind.TransactOpts, payload []VoteManagerPayload) (*types.Transaction, error) { +// Solidity: function voteBatch((uint256,uint256,uint256,uint16)[] payload) returns() +func (_Votemanager *VotemanagerTransactor) VoteBatch(opts *bind.TransactOpts, payload []VoteManagerVotePayload) (*types.Transaction, error) { return _Votemanager.contract.Transact(opts, "voteBatch", payload) } -// VoteBatch is a paid mutator transaction binding the contract method 0x149ff154. +// VoteBatch is a paid mutator transaction binding the contract method 0xe53edd93. // -// Solidity: function voteBatch((uint256,uint256,uint256)[] payload) returns() -func (_Votemanager *VotemanagerSession) VoteBatch(payload []VoteManagerPayload) (*types.Transaction, error) { +// Solidity: function voteBatch((uint256,uint256,uint256,uint16)[] payload) returns() +func (_Votemanager *VotemanagerSession) VoteBatch(payload []VoteManagerVotePayload) (*types.Transaction, error) { return _Votemanager.Contract.VoteBatch(&_Votemanager.TransactOpts, payload) } -// VoteBatch is a paid mutator transaction binding the contract method 0x149ff154. +// VoteBatch is a paid mutator transaction binding the contract method 0xe53edd93. // -// Solidity: function voteBatch((uint256,uint256,uint256)[] payload) returns() -func (_Votemanager *VotemanagerTransactorSession) VoteBatch(payload []VoteManagerPayload) (*types.Transaction, error) { +// Solidity: function voteBatch((uint256,uint256,uint256,uint16)[] payload) returns() +func (_Votemanager *VotemanagerTransactorSession) VoteBatch(payload []VoteManagerVotePayload) (*types.Transaction, error) { return _Votemanager.Contract.VoteBatch(&_Votemanager.TransactOpts, payload) } diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index eec66df40..9b6adc2f5 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -3,6 +3,7 @@ package verifier import ( "context" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/tokenregistry" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/votemanager" "github.com/Fantom-foundation/lachesis-base/inter/idx" "github.com/ethereum/go-ethereum" @@ -22,8 +23,9 @@ const ( confirmations = 3 allowBlockBacklog = 1000 - blockStorageAddr = "0xb3753e9F40DD0Dfd039e8c4B12895e2f636693a2" - voteManagerAddr = "0x9224c3121c050546Ba76960c00c8B7e26C1E7b33" + BlockStorageAddr = "0xf7E0CF7453ac619fD64b3D46D7De3638510F15eA" + VoteManagerAddr = "0x1e29fae73cbe681f35208d470db8c7113820f0c2" + TokenRegistryAddr = "0x830c235F1CCa0c6760931d2A5F7e9bC608E1c750" ) type EventListener struct { @@ -34,6 +36,7 @@ type EventListener struct { validatorId uint32 bs *block_storage.BlockStorage vm *votemanager.Votemanager + tr *tokenregistry.Tokenregistry eventChannel chan *block_storage.BlockStorageNewHash conn *ethclient.Client verifier *Verifier @@ -81,10 +84,11 @@ func (e *EventListener) initializeEventSystem() error { } e.conn = ethclient.NewClient(rpc) - e.bs, err = block_storage.NewBlockStorage(common.HexToAddress(blockStorageAddr), e.conn) - e.vm, err = votemanager.NewVotemanager(common.HexToAddress(voteManagerAddr), e.conn) + e.bs, err = block_storage.NewBlockStorage(common.HexToAddress(BlockStorageAddr), e.conn) + e.vm, err = votemanager.NewVotemanager(common.HexToAddress(VoteManagerAddr), e.conn) + e.tr, err = tokenregistry.NewTokenregistry(common.HexToAddress(TokenRegistryAddr), e.conn) - e.verifier = NewVerifier(e.validatorId, e.conn, e.bs, e.vm) + e.verifier = NewVerifier(e.validatorId, e.conn, e.bs, e.vm, e.tr) e.voter = NewVoter(e.conn, e.ks, e.account, e.chainId, e.vm) return err @@ -99,13 +103,11 @@ func (e *EventListener) OnNewLog(l *types.Log) { return } - if l.Address == common.HexToAddress(blockStorageAddr) { + if l.Address == common.HexToAddress(BlockStorageAddr) { evt, err := e.bs.ParseNewHash(*l) if err != nil { return } - - //log.Info("NewHash event received", "hashId", evt.HashId, "epoch", evt.Epoch, "account", evt.Account) e.eventChannel <- evt } } @@ -143,7 +145,7 @@ func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) tokens := e.verifier.validateHashEvent(evt) e.voter.Syncing = e.syncingProcess != nil // increase the batch size if we are syncing for _, token := range tokens { - e.voter.AddToQueue(evt.HashId, evt.Raw.BlockNumber, token.currencyCode) + e.voter.AddToQueue(evt.HashId, evt.Raw.BlockNumber, token.CurrencyType, token.Version) } } } diff --git a/integration/xenblocks/verifier/main/list_hashes.go b/integration/xenblocks/verifier/main/list_hashes.go new file mode 100644 index 000000000..fa3f0f775 --- /dev/null +++ b/integration/xenblocks/verifier/main/list_hashes.go @@ -0,0 +1,118 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/tokenregistry" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/votemanager" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/verifier" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "log" + "math/big" +) + +type payload struct { + decoded decoded + bn uint64 +} + +type decoded struct { + C uint8 + M uint32 + T uint8 + V uint8 + K [32]byte + S []byte +} + +var ( + jobs chan payload + v *verifier.Verifier +) + +func main() { + ctx := context.TODO() + + conn, _ := ethclient.Dial("http://localhost:8545") + bs, _ := block_storage.NewBlockStorage(common.HexToAddress(verifier.BlockStorageAddr), conn) + tr, _ := tokenregistry.NewTokenregistry(common.HexToAddress(verifier.TokenRegistryAddr), conn) + vm, _ := votemanager.NewVotemanager(common.HexToAddress(verifier.VoteManagerAddr), conn) + bn, _ := conn.BlockNumber(ctx) + v = verifier.NewVerifier(0, conn, bs, vm, tr) + + startBlock := 832437 + toBlock := startBlock + 100 + + jobs = make(chan payload, 1000) + for w := 0; w <= 10; w++ { + go worker() + } + + for { + fmt.Printf("%d => %d\n", startBlock, toBlock) + blockNumber := new(big.Int).SetUint64(bn) + if blockNumber.Cmp(big.NewInt(int64(startBlock))) == -1 { + fmt.Println("caught up with the latest block") + break + } + + logTransferSig := []byte("NewHash(uint256,uint256,address,uint256,bytes)") + logTransferSigHash := crypto.Keccak256Hash(logTransferSig) + + q := ethereum.FilterQuery{ + FromBlock: big.NewInt(int64(startBlock)), + ToBlock: big.NewInt(int64(toBlock)), + Addresses: []common.Address{ + common.HexToAddress("0xf7E0CF7453ac619fD64b3D46D7De3638510F15eA"), + }, + Topics: [][]common.Hash{ + {logTransferSigHash}, + }, + } + + logs, err := conn.FilterLogs(context.Background(), q) + if err != nil { + panic(err) + } + + for _, vLog := range logs { + event, err := bs.ParseNewHash(vLog) + if err != nil { + panic(err) + } + dr, err := bs.DecodeRecordBytes0(nil, event.HashId) + if err != nil { + panic(err) + } + + jobs <- payload{ + decoded: dr, + bn: vLog.BlockNumber, + } + } + + startBlock = toBlock + 1 + toBlock += 100 + } +} + +func worker() { + for pl := range jobs { + event := pl.decoded + + key := []byte(common.Bytes2Hex(event.K[:])) + argon2Result, err := verifier.Argon2Hash(event.C, event.M, event.T, event.S, key) + if err != nil { + panic(err) + } + + tokens, _ := v.Tr.FindTokensFromArgon2Hash(nil, argon2Result, big.NewInt(0)) + j, _ := json.Marshal(tokens) + log.Printf("%d %s %s\n", pl.bn, argon2Result, j) + } +} diff --git a/integration/xenblocks/verifier/targets.go b/integration/xenblocks/verifier/targets.go deleted file mode 100644 index a94a9e7f9..000000000 --- a/integration/xenblocks/verifier/targets.go +++ /dev/null @@ -1,114 +0,0 @@ -package verifier - -import ( - "github.com/ethereum/go-ethereum/log" - "math/big" - "regexp" - "strings" - "time" -) - -var ( - // BLOCK_NUMBER_TIME_CHECK_REQ is the block number at which the time check starts to be required. - BLOCK_NUMBER_TIME_CHECK_REQ = big.NewInt(0) -) - -type Token struct { - name string - currencyCode uint8 - value int -} - -type TokenFilter struct { - token string - pattern string // regex pattern to filter hashes - exclusive bool // if true, stop searching for other targets - timeCheck func(time time.Time, blockNumber *big.Int) bool // custom function to filter based on time - hashCheck func(hash string) bool // custom function to filter based on hash -} - -// Tokens These are token definitions for the verifier and their initial mint values. -var Tokens = map[string]Token{ - "XNM": { - name: "XNM", - currencyCode: 1, - value: 10, - }, - "XUNI": { - name: "XUNI", - currencyCode: 2, - value: 1, - }, - "XBLK": { - name: "XBLK", - currencyCode: 3, - value: 1, - }, -} - -// TokenFilters These are filters to run on each verified hash. -// They are run in order as listed below. -var TokenFilters = []TokenFilter{ - { - token: "XUNI", - pattern: ".*XUNI[0-9].*", - exclusive: true, - timeCheck: func(time time.Time, blockNumber *big.Int) bool { - if BLOCK_NUMBER_TIME_CHECK_REQ.Cmp(big.NewInt(0)) == 0 || blockNumber.Cmp(BLOCK_NUMBER_TIME_CHECK_REQ) == -1 { - return true - } - minutes := time.Minute() - return (0 <= minutes && minutes < 5) || (55 <= minutes && minutes < 60) - }, - }, - { - token: "XNM", - pattern: ".*XEN11.*", - exclusive: false, - }, - { - token: "XBLK", - pattern: ".*XEN11.*", - exclusive: false, - hashCheck: func(hash string) bool { - return countUppercase(hash) >= 50 - }, - }, -} - -// FindTokensFromHash returns a list of tokens found in the given hash. -func FindTokensFromHash(argon2Result string, blockTime time.Time, blockNumber uint64) []Token { - var foundTargets []Token - - splits := strings.Split(argon2Result, "$") - hashOnly := splits[len(splits)-1] - - for i := range TokenFilters { - target := TokenFilters[i] - - if target.pattern != "" && !regexp.MustCompile(target.pattern).MatchString(hashOnly) { - continue - } - - if target.hashCheck != nil && !target.hashCheck(hashOnly) { - log.Trace("hash check failed", "token", target.token, "hash", hashOnly) - continue - } - - bn := new(big.Int).SetUint64(blockNumber) - if target.timeCheck != nil && !target.timeCheck(blockTime, bn) { - log.Trace("time check failed", "token", target.token, "time", blockTime) - continue - } - - log.Trace("target found", "token", target.token, "hash", hashOnly) - foundTargets = append(foundTargets, Tokens[target.token]) - - if target.exclusive { - log.Trace("exclusive target found. stop searching", "token", target.token) - break - } - } - - return foundTargets -} diff --git a/integration/xenblocks/verifier/targets_test.go b/integration/xenblocks/verifier/targets_test.go deleted file mode 100644 index e71b04119..000000000 --- a/integration/xenblocks/verifier/targets_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package verifier - -import ( - "fmt" - "github.com/stretchr/testify/require" - "math/big" - "testing" - "time" -) - -func TestFindTokensFromHashXNM(t *testing.T) { - assert := require.New(t) - - tokens := FindTokensFromHash("$argon2id$v=19$m=99400,t=1,p=1$salt$aaaaaXEN11aaaaa", time.Unix(0, 0), 0) - - assert.Equal(1, len(tokens)) - assert.Equal("XNM", tokens[0].name) - assert.Equal(uint8(1), tokens[0].currencyCode) - assert.Equal(10, tokens[0].value) -} - -func TestXuniToken(t *testing.T) { - assert := require.New(t) - - tokens := FindTokensFromHash("$argon2id$v=19$m=102000,t=1,p=1$AmtN2N+5ggJ4tc1s7TfBsg9o3to$ZzzXErgy4F3+O4+OV2U3F9+Sv0ssKR4uyxguomjkBvb1EUgEeC5Ztyz2U7k9gKHw8e6HidQkKXUNI75ZFBmQHw", time.Unix(0, 0), 0) - - assert.Equal(1, len(tokens)) - assert.Equal("XUNI", tokens[0].name) - assert.Equal(uint8(2), tokens[0].currencyCode) - assert.Equal(1, tokens[0].value) -} - -func TestFindTokensFromHashXUNI(t *testing.T) { - assert := require.New(t) - - for i := 0; i < 9; i++ { - for j := 0; j < 60; j++ { - timestamp := time.Date(2023, 0, 0, 0, j, 0, 0, time.UTC) - tokens := FindTokensFromHash(fmt.Sprintf("$argon2id$v=19$m=99400,t=1,p=1$salt$aaaaaXUNI%d%daaaaa", i, j), timestamp, 0) - - if (0 <= j && j < 5) || (55 <= j && j < 60) { - assert.Equal(1, len(tokens)) - assert.Equal("XUNI", tokens[0].name) - assert.Equal(uint8(2), tokens[0].currencyCode) - assert.Equal(1, tokens[0].value) - } else if BLOCK_NUMBER_TIME_CHECK_REQ.Cmp(big.NewInt(0)) != 0 { - assert.Equal(0, len(tokens)) - } - } - } -} - -func TestFindTokensFromHashSB(t *testing.T) { - assert := require.New(t) - - blockTime := time.Now() - - tokens := FindTokensFromHash("$argon2id$v=19$m=99400,t=1,p=1$salt$XEN11AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", blockTime, 0) - assert.Equal(2, len(tokens)) - assert.Equal("XNM", tokens[0].name) - assert.Equal(uint8(1), tokens[0].currencyCode) - assert.Equal(10, tokens[0].value) - assert.Equal("XBLK", tokens[1].name) - assert.Equal(uint8(3), tokens[1].currencyCode) - assert.Equal(1, tokens[1].value) -} diff --git a/integration/xenblocks/verifier/verifier.go b/integration/xenblocks/verifier/verifier.go index db2f1100d..61f717db0 100644 --- a/integration/xenblocks/verifier/verifier.go +++ b/integration/xenblocks/verifier/verifier.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "github.com/Fantom-foundation/go-opera/gossip/contract/sfclib100" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/block_storage" + "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/tokenregistry" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/votemanager" "github.com/Fantom-foundation/go-opera/opera/contracts/sfc" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -18,30 +19,42 @@ import ( "math/big" "regexp" "strings" + "sync" "time" ) const ( - hashLen = 64 - pattern1Salt = "WEVOMTAwODIwMjJYRU4" + hashLen = 64 + pattern1Salt = "WEVOMTAwODIwMjJYRU4" + BlockNumberTimeCheckReq = 0 ) type Verifier struct { - enabled bool - numOfWorkers int - backlog int - ipcPath string - validatorId uint32 - bs *block_storage.BlockStorage - sfcLib *sfclib100.ContractCaller - eventChannel chan *block_storage.BlockStorageNewHash - conn *ethclient.Client - sub event.Subscription - validatorCountLRU *lru.Cache - vm *votemanager.Votemanager + enabled bool + numOfWorkers int + backlog int + ipcPath string + validatorId uint32 + bs *block_storage.BlockStorage + sfcLib *sfclib100.ContractCaller + eventChannel chan *block_storage.BlockStorageNewHash + conn *ethclient.Client + sub event.Subscription + validatorCountLRU *lru.Cache + vm *votemanager.Votemanager + Tr *tokenregistry.Tokenregistry + mu sync.Mutex + tokens []tokenregistry.TokenRegistryTokenConfig + blockNumberUpgrades []uint64 } -func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.BlockStorage, vm *votemanager.Votemanager) *Verifier { +func NewVerifier( + validatorId uint32, + conn *ethclient.Client, + bs *block_storage.BlockStorage, + vm *votemanager.Votemanager, + tr *tokenregistry.Tokenregistry, +) *Verifier { validatorCountLRU, err := lru.New(100) if err != nil { panic(err) @@ -52,6 +65,8 @@ func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.B panic(err) } + //categorized := make(map[uint64]&upcomingTokens) + return &Verifier{ enabled: false, numOfWorkers: numOfWorkers, @@ -62,10 +77,11 @@ func NewVerifier(validatorId uint32, conn *ethclient.Client, bs *block_storage.B sfcLib: sfcLib, bs: bs, vm: vm, + Tr: tr, } } -func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) []Token { +func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) []tokenregistry.TokenRegistryFoundToken { log.Debug("NewHash event received", "hashId", event.HashId, "epoch", event.Epoch, "account", event.Account) // TODO: uncomment. for dev we are voting on all hashes @@ -75,9 +91,6 @@ func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) [ // return nil //} - blockTime := v.getBlockTime(event.Raw.BlockHash) - blockNumber := event.Raw.BlockNumber - dr, err := v.bs.DecodeRecordBytes0(nil, event.HashId) if err != nil { log.Warn("Failed to decode hash record", "err", err) @@ -85,7 +98,7 @@ func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) [ } key := []byte(common.Bytes2Hex(dr.K[:])) - argon2Result, err := argon2Hash(dr.C, dr.M, dr.T, dr.S, key) + argon2Result, err := Argon2Hash(dr.C, dr.M, dr.T, dr.S, key) if err != nil { log.Warn("Argon2 hash failed", "err", err) return nil @@ -101,12 +114,20 @@ func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) [ return nil } - //if !v.verifyDifficultly(dr.M, blockNumber) { + //if !v.verifyDifficultly(dr.M, event.Raw.BlockNumber) { // log.Warn("Difficulty too low", "hash", argon2Result, "hashId", event.HashId) // return //} - tokens := FindTokensFromHash(argon2Result, blockTime, blockNumber) + splits := strings.Split(argon2Result, "$") + hashOnly := splits[len(splits)-1] + blockTime := big.NewInt(v.getBlockTime(event.Raw.BlockHash).UnixMilli()) + tokens, err := v.Tr.FindTokensFromArgon2Hash(nil, hashOnly, blockTime) + if err != nil { + log.Warn("Failed to find tokens", "err", err) + return nil + } + if len(tokens) == 0 { log.Warn("No tokens found", "hash", argon2Result, "hashId", event.HashId) return nil @@ -116,7 +137,7 @@ func (v *Verifier) validateHashEvent(event *block_storage.BlockStorageNewHash) [ return tokens } -func argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, key []byte) (string, error) { +func Argon2Hash(parallelism uint8, memory uint32, iterations uint8, salt []byte, key []byte) (string, error) { ctx := argon2.NewContext() ctx.Iterations = int(iterations) ctx.Memory = int(memory) diff --git a/integration/xenblocks/verifier/verifier_test.go b/integration/xenblocks/verifier/verifier_test.go index 7b8c91dfe..168b11342 100644 --- a/integration/xenblocks/verifier/verifier_test.go +++ b/integration/xenblocks/verifier/verifier_test.go @@ -11,7 +11,7 @@ func TestArgon2Hash(t *testing.T) { salt := []byte("XEN10082022XEN") key := []byte("0000da975bd6ec3aa878dadc395943619d23407371bc15066c1505ef23203d871633c687a9e5e89f5fc7fb61f05e1ff4ec49ecee28577c5143711185afe2d5a5")[:] - hash, err := argon2Hash(1, 8, 1, salt, key) + hash, err := Argon2Hash(1, 8, 1, salt, key) if err != nil { t.Fatalf("error: %v", err) } diff --git a/integration/xenblocks/verifier/voter.go b/integration/xenblocks/verifier/voter.go index a09a3f463..9c65c847d 100644 --- a/integration/xenblocks/verifier/voter.go +++ b/integration/xenblocks/verifier/voter.go @@ -23,7 +23,7 @@ var ( type Voter struct { vm *votemanager.Votemanager conn *ethclient.Client - queue []votemanager.VoteManagerPayload + queue []votemanager.VoteManagerVotePayload ks *keystore.KeyStore account accounts.Account chainId uint64 @@ -32,7 +32,7 @@ type Voter struct { } func NewVoter(conn *ethclient.Client, ks *keystore.KeyStore, account accounts.Account, chainId uint64, vm *votemanager.Votemanager) *Voter { - var queue []votemanager.VoteManagerPayload + var queue []votemanager.VoteManagerVotePayload return &Voter{ vm: vm, @@ -59,17 +59,16 @@ func (v *Voter) waitTxConfirmed(hash common.Hash) <-chan *types.Transaction { return ch } -func (v *Voter) AddToQueue(hashId *big.Int, MintedBlockNumber uint64, currencyType uint8) { - cc := big.NewInt(int64(currencyType)) +func (v *Voter) AddToQueue(hashId *big.Int, MintedBlockNumber uint64, currencyType *big.Int, version uint16) { mbn := big.NewInt(int64(MintedBlockNumber)) - v.queue = append(v.queue, votemanager.VoteManagerPayload{HashId: hashId, CurrencyType: cc, MintedBlockNumber: mbn}) + v.queue = append(v.queue, votemanager.VoteManagerVotePayload{HashId: hashId, CurrencyType: currencyType, MintedBlockNumber: mbn, Version: version}) v.mu.Lock() defer v.mu.Unlock() if len(v.queue) >= v.getBatchSize() { _ = v.Vote() - v.queue = []votemanager.VoteManagerPayload{} + v.queue = []votemanager.VoteManagerVotePayload{} } } From 922bf8836a1f7430635fce459433184ef180c542 Mon Sep 17 00:00:00 2001 From: Nicholas Pettas Date: Tue, 9 Jan 2024 15:02:27 -0800 Subject: [PATCH 34/34] use getLogs on newHash logs per block rather than listening for events. add votemanager checkpoint to save progress --- cmd/opera/launcher/launcher.go | 16 +- go.mod | 4 +- go.sum | 4 +- gossip/c_block_callbacks.go | 1 - .../contracts/votemanager/votemanager.go | 54 +++- .../xenblocks/verifier/event_listener.go | 251 +++++++++++++----- integration/xenblocks/verifier/utils.go | 45 +++- integration/xenblocks/verifier/voter.go | 30 +-- 8 files changed, 298 insertions(+), 107 deletions(-) diff --git a/cmd/opera/launcher/launcher.go b/cmd/opera/launcher/launcher.go index 0ee4ed365..aebce8ae6 100644 --- a/cmd/opera/launcher/launcher.go +++ b/cmd/opera/launcher/launcher.go @@ -355,9 +355,20 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( // Config the XenBlocks verifier ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) passwords := utils.MakePasswordList(ctx) - account, _ := unlockAccount(ks, cfg.XenBlocks.VerifierAddress.Hex(), 0, passwords) + + var account accounts.Account + if cfg.Emitter.Validator.ID != 0 || cfg.XenBlocks.ForceVerifier { + account, _ = unlockAccount(ks, cfg.XenBlocks.VerifierAddress.Hex(), 0, passwords) + } xbEventListener := verifier.NewEventListener(stack, cfg.Emitter.Validator.ID, ks, account, gdb.GetRules().NetworkID) if cfg.Emitter.Validator.ID != 0 || cfg.XenBlocks.ForceVerifier { + + // Set validator ID to 1 if it is not set + // this is only needed for testing + if cfg.Emitter.Validator.ID == 0 { + xbEventListener.SetValidatorId(1) + } + go xbEventListener.Start() } @@ -377,6 +388,7 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( if stop { go func() { // do it in a separate thread to avoid deadlock + xbEventListener.Close() _ = stack.Close() }() return true @@ -401,6 +413,7 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( stack.RegisterLifecycle(svc) return stack, svc, func() { + xbEventListener.Close() _ = stack.Close() gdb.Close() _ = cdb.Close() @@ -408,7 +421,6 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) ( _ = closeDBs() } xenblocksReporter.Close() - xbEventListener.Close() } } diff --git a/go.mod b/go.mod index 633c636c3..92bc8bfd4 100644 --- a/go.mod +++ b/go.mod @@ -109,10 +109,10 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -require github.com/tvdburgt/go-argon2 v0.0.0-20181109175329-49d0f0e5973c // indirect +require github.com/tvdburgt/go-argon2 v0.0.0-20181109175329-49d0f0e5973c //replace github.com/ethereum/go-ethereum => github.com/Fantom-foundation/go-ethereum v1.10.8-ftm-rc12 -replace github.com/ethereum/go-ethereum => github.com/nibty/go-ethereum v1.10.8-ftm-rc12-x1-2 +replace github.com/ethereum/go-ethereum => github.com/nibty/go-ethereum v1.10.8-ftm-rc12-x1-3 replace github.com/dvyukov/go-fuzz => github.com/guzenok/go-fuzz v0.0.0-20210201043429-a8e90a2a4f88 diff --git a/go.sum b/go.sum index 0ad4a783c..4620a2a01 100644 --- a/go.sum +++ b/go.sum @@ -488,8 +488,8 @@ github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nibty/go-ethereum v1.10.8-ftm-rc12-x1-2 h1:q1Filh2L9v2MjaadUGZhk8v3uo0yNiOidVqV21KPZsk= -github.com/nibty/go-ethereum v1.10.8-ftm-rc12-x1-2/go.mod h1:IeQDjWCNBj/QiWIPosfF6/kRC6pHPNs7W7LfBzjj+P4= +github.com/nibty/go-ethereum v1.10.8-ftm-rc12-x1-3 h1:v07QogU/zZE/wqi5ny0uos/IcjuhU+Mi2Q4VE/H5P+o= +github.com/nibty/go-ethereum v1.10.8-ftm-rc12-x1-3/go.mod h1:IeQDjWCNBj/QiWIPosfF6/kRC6pHPNs7W7LfBzjj+P4= github.com/nibty/recws v0.0.0-20231129011923-06823df0d0db h1:5NSkB+3RDcKx0fWRPCsNiyORrCzYLzoCip6q83SKdn4= github.com/nibty/recws v0.0.0-20231129011923-06823df0d0db/go.mod h1:i6EuUq15zzNHzljFI2bM6FdxOTRlvw6vthcDaOQjenU= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= diff --git a/gossip/c_block_callbacks.go b/gossip/c_block_callbacks.go index 0edda7683..83ed60350 100644 --- a/gossip/c_block_callbacks.go +++ b/gossip/c_block_callbacks.go @@ -249,7 +249,6 @@ func consensusCallbackBeginBlockFn( txListener := blockProc.TxListenerModule.Start(blockCtx, bs, es, statedb) onNewLogAll := func(l *types.Log) { txListener.OnNewLog(l) - xenblocksEL.OnNewLog(l) // Note: it's possible for logs to get indexed twice by BR and block processing if verWatcher != nil { diff --git a/integration/xenblocks/contracts/votemanager/votemanager.go b/integration/xenblocks/contracts/votemanager/votemanager.go index 08a1afb33..f984973e3 100644 --- a/integration/xenblocks/contracts/votemanager/votemanager.go +++ b/integration/xenblocks/contracts/votemanager/votemanager.go @@ -38,7 +38,7 @@ type VoteManagerVotePayload struct { // VotemanagerMetaData contains all meta data concerning the Votemanager contract. var VotemanagerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAValidator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VersionMismatch\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"name\":\"MintToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"votes\",\"type\":\"uint16\"}],\"name\":\"VoteToken\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"blockStorage\",\"outputs\":[{\"internalType\":\"contractBlockStorage\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialSfcAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialBlockStorageAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"initialVotePercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"initialVoteBufferPercent\",\"type\":\"uint8\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfVotes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sfc\",\"outputs\":[{\"internalType\":\"contractSFC\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"mintedBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"validatorId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"}],\"name\":\"shouldVote\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenRegistry\",\"outputs\":[{\"internalType\":\"contractTokenRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockStorageAddress\",\"type\":\"address\"}],\"name\":\"updateBlockStorageAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sfcAddress\",\"type\":\"address\"}],\"name\":\"updateSfcAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenRegistryAddress_\",\"type\":\"address\"}],\"name\":\"updateTokenRegistryAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"voteBufferPercent_\",\"type\":\"uint8\"}],\"name\":\"updateVoteBufferPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"votePercentage_\",\"type\":\"uint8\"}],\"name\":\"updateVotePercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"validatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"mintedBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"internalType\":\"structVoteManager.VotePayload[]\",\"name\":\"payload\",\"type\":\"tuple[]\"}],\"name\":\"voteBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"voteBufferPercent\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"votePercentage\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAValidator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VersionMismatch\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"}],\"name\":\"MintToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"votes\",\"type\":\"uint16\"}],\"name\":\"VoteToken\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"blockCheckpointByValidatorId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockStorage\",\"outputs\":[{\"internalType\":\"contractBlockStorage\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialSfcAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"initialBlockStorageAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"initialVotePercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"initialVoteBufferPercent\",\"type\":\"uint8\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintedByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredNumOfVotes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sfc\",\"outputs\":[{\"internalType\":\"contractSFC\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"mintedBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"validatorId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"}],\"name\":\"shouldVote\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenRegistry\",\"outputs\":[{\"internalType\":\"contractTokenRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockStorageAddress\",\"type\":\"address\"}],\"name\":\"updateBlockStorageAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"updateCheckpoint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sfcAddress\",\"type\":\"address\"}],\"name\":\"updateSfcAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenRegistryAddress_\",\"type\":\"address\"}],\"name\":\"updateTokenRegistryAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"voteBufferPercent_\",\"type\":\"uint8\"}],\"name\":\"updateVoteBufferPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"votePercentage_\",\"type\":\"uint8\"}],\"name\":\"updateVotePercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"validatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"hashId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currencyType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"mintedBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"internalType\":\"structVoteManager.VotePayload[]\",\"name\":\"payload\",\"type\":\"tuple[]\"}],\"name\":\"voteBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"voteBufferPercent\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"votePercentage\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"votesByHashIdAndValidatorIdAndCurrencyType\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } // VotemanagerABI is the input ABI used to generate the binding from. @@ -187,6 +187,37 @@ func (_Votemanager *VotemanagerTransactorRaw) Transact(opts *bind.TransactOpts, return _Votemanager.Contract.contract.Transact(opts, method, params...) } +// BlockCheckpointByValidatorId is a free data retrieval call binding the contract method 0x2b3b2c0a. +// +// Solidity: function blockCheckpointByValidatorId(uint256 ) view returns(uint256) +func (_Votemanager *VotemanagerCaller) BlockCheckpointByValidatorId(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { + var out []interface{} + err := _Votemanager.contract.Call(opts, &out, "blockCheckpointByValidatorId", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BlockCheckpointByValidatorId is a free data retrieval call binding the contract method 0x2b3b2c0a. +// +// Solidity: function blockCheckpointByValidatorId(uint256 ) view returns(uint256) +func (_Votemanager *VotemanagerSession) BlockCheckpointByValidatorId(arg0 *big.Int) (*big.Int, error) { + return _Votemanager.Contract.BlockCheckpointByValidatorId(&_Votemanager.CallOpts, arg0) +} + +// BlockCheckpointByValidatorId is a free data retrieval call binding the contract method 0x2b3b2c0a. +// +// Solidity: function blockCheckpointByValidatorId(uint256 ) view returns(uint256) +func (_Votemanager *VotemanagerCallerSession) BlockCheckpointByValidatorId(arg0 *big.Int) (*big.Int, error) { + return _Votemanager.Contract.BlockCheckpointByValidatorId(&_Votemanager.CallOpts, arg0) +} + // BlockStorage is a free data retrieval call binding the contract method 0x4a673e98. // // Solidity: function blockStorage() view returns(address) @@ -674,6 +705,27 @@ func (_Votemanager *VotemanagerTransactorSession) UpdateBlockStorageAddress(bloc return _Votemanager.Contract.UpdateBlockStorageAddress(&_Votemanager.TransactOpts, blockStorageAddress) } +// UpdateCheckpoint is a paid mutator transaction binding the contract method 0x3e92aebe. +// +// Solidity: function updateCheckpoint(uint256 blockNumber) returns() +func (_Votemanager *VotemanagerTransactor) UpdateCheckpoint(opts *bind.TransactOpts, blockNumber *big.Int) (*types.Transaction, error) { + return _Votemanager.contract.Transact(opts, "updateCheckpoint", blockNumber) +} + +// UpdateCheckpoint is a paid mutator transaction binding the contract method 0x3e92aebe. +// +// Solidity: function updateCheckpoint(uint256 blockNumber) returns() +func (_Votemanager *VotemanagerSession) UpdateCheckpoint(blockNumber *big.Int) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateCheckpoint(&_Votemanager.TransactOpts, blockNumber) +} + +// UpdateCheckpoint is a paid mutator transaction binding the contract method 0x3e92aebe. +// +// Solidity: function updateCheckpoint(uint256 blockNumber) returns() +func (_Votemanager *VotemanagerTransactorSession) UpdateCheckpoint(blockNumber *big.Int) (*types.Transaction, error) { + return _Votemanager.Contract.UpdateCheckpoint(&_Votemanager.TransactOpts, blockNumber) +} + // UpdateSfcAddress is a paid mutator transaction binding the contract method 0xcbb9d8c9. // // Solidity: function updateSfcAddress(address sfcAddress) returns() diff --git a/integration/xenblocks/verifier/event_listener.go b/integration/xenblocks/verifier/event_listener.go index 9b6adc2f5..63d0143b9 100644 --- a/integration/xenblocks/verifier/event_listener.go +++ b/integration/xenblocks/verifier/event_listener.go @@ -10,55 +10,69 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" + "math/big" + "os" + "os/signal" + "syscall" "time" ) const ( - numOfWorkers = 5 - backlog = 5000 - - confirmations = 3 - allowBlockBacklog = 1000 - BlockStorageAddr = "0xf7E0CF7453ac619fD64b3D46D7De3638510F15eA" - VoteManagerAddr = "0x1e29fae73cbe681f35208d470db8c7113820f0c2" - TokenRegistryAddr = "0x830c235F1CCa0c6760931d2A5F7e9bC608E1c750" + numOfWorkers = 5 + backlog = 5000 + checkpointSize = 1000 // save the check point every n blocks + VoteManagerStart = 865652 + BlockStorageStart = 832437 + updateCheckpointGasLimit = 80000 + BlockStorageAddr = "0xf7E0CF7453ac619fD64b3D46D7De3638510F15eA" + VoteManagerAddr = "0x1e29fae73cbe681f35208d470db8c7113820f0c2" + TokenRegistryAddr = "0x830c235F1CCa0c6760931d2A5F7e9bC608E1c750" ) type EventListener struct { - enabled bool - numOfWorkers int - backlog int - stack *node.Node - validatorId uint32 - bs *block_storage.BlockStorage - vm *votemanager.Votemanager - tr *tokenregistry.Tokenregistry - eventChannel chan *block_storage.BlockStorageNewHash - conn *ethclient.Client - verifier *Verifier - ks *keystore.KeyStore - account accounts.Account - chainId uint64 - voter *Voter - currentBlockNumber uint64 - syncingProcess *ethereum.SyncProgress + enabled bool + numOfWorkers int + backlog int + stack *node.Node + validatorId uint32 + bs *block_storage.BlockStorage + vm *votemanager.Votemanager + tr *tokenregistry.Tokenregistry + eventChannel chan *block_storage.BlockStorageNewHash + conn *ethclient.Client + verifier *Verifier + ks *keystore.KeyStore + account accounts.Account + chainId uint64 + voter *Voter + currentBlockNumber uint64 + processedBlockNumber uint64 + syncingProcess *ethereum.SyncProgress + newHashTopic common.Hash + blockWorkerRunning bool } func NewEventListener(stack *node.Node, validatorId idx.ValidatorID, ks *keystore.KeyStore, account accounts.Account, chainId uint64) *EventListener { + logTransferSig := []byte("NewHash(uint256,uint256,address,uint256,bytes)") + logTransferSigHash := crypto.Keccak256Hash(logTransferSig) + return &EventListener{ - enabled: false, - stack: stack, - numOfWorkers: numOfWorkers, - backlog: backlog, - validatorId: uint32(validatorId), - ks: ks, - account: account, - chainId: chainId, - currentBlockNumber: 0, + enabled: false, + stack: stack, + numOfWorkers: numOfWorkers, + backlog: backlog, + validatorId: uint32(validatorId), + ks: ks, + account: account, + chainId: chainId, + currentBlockNumber: 0, + processedBlockNumber: 0, + newHashTopic: logTransferSigHash, + blockWorkerRunning: false, } } @@ -66,6 +80,10 @@ func (e *EventListener) Start() { log.Info("Starting Block storage watcher") e.enabled = true + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM) + defer signal.Stop(sigc) + err := e.initializeEventSystem() if err != nil { panic(err) @@ -73,8 +91,11 @@ func (e *EventListener) Start() { e.eventChannel = make(chan *block_storage.BlockStorageNewHash, backlog) for w := 0; w < numOfWorkers; w++ { - go e.worker(e.eventChannel) + go e.newHashWorker(e.eventChannel) } + + <-sigc + e.Close() } func (e *EventListener) initializeEventSystem() error { @@ -94,54 +115,159 @@ func (e *EventListener) initializeEventSystem() error { return err } -func (e *EventListener) OnNewLog(l *types.Log) { +func (e *EventListener) OnNewBlock(blockNumber uint64) { if e.enabled == false { return } - if e.syncingProcess != nil && e.syncingProcess.HighestBlock-e.syncingProcess.CurrentBlock > allowBlockBacklog { - return + progress, err := e.conn.SyncProgress(context.TODO()) + if err != nil { + if !e.enabled { + return + } + panic(err) + } + + e.syncingProcess = progress + e.currentBlockNumber = blockNumber + + // do not start the block worker if we are synced + if !e.blockWorkerRunning && e.syncingProcess == nil { + go e.blockWorker() + e.blockWorkerRunning = true + } +} + +func (e *EventListener) getLogs(blockNumber uint64) error { + bn := big.NewInt(int64(blockNumber)) + + query := ethereum.FilterQuery{ + FromBlock: bn, + ToBlock: bn, + Addresses: []common.Address{ + common.HexToAddress(BlockStorageAddr), + }, + Topics: [][]common.Hash{ + {e.newHashTopic}, + }, } - if l.Address == common.HexToAddress(BlockStorageAddr) { - evt, err := e.bs.ParseNewHash(*l) + logs, err := e.conn.FilterLogs(context.Background(), query) + if err != nil { + return err + } + + for _, vLog := range logs { + event, err := e.bs.ParseNewHash(vLog) if err != nil { + return err + } + + select { + case e.eventChannel <- event: + return nil + default: + } + } + + return nil +} + +func (e *EventListener) blockWorker() { + e.processedBlockNumber = e.getCheckpoint() + + for { + if e.enabled == false { + return + } + + if e.currentBlockNumber > e.processedBlockNumber { + err := e.getLogs(e.processedBlockNumber + 1) + if err != nil { + if !e.enabled { + return + } + panic(err) + } + + if e.processedBlockNumber%checkpointSize == 0 { + // move on to the next block only after all events are processed + e.waitForEventsProcessed() + e.updateCheckpoint() + } + + e.processedBlockNumber++ + } else { + time.Sleep(250 * time.Millisecond) + } + } +} + +func (e *EventListener) waitForEventsProcessed() { + log.Info("waiting for events to be processed", "blockNumber", e.processedBlockNumber) + for { + if e.enabled == false { return } - e.eventChannel <- evt + if len(e.eventChannel) == 0 { + return + } + + time.Sleep(250 * time.Millisecond) } } -func (e *EventListener) OnNewBlock(blockNumber uint64) { - if e.enabled == false { - return +func (e *EventListener) updateCheckpoint() { + if e.enabled && e.syncingProcess == nil && e.currentBlockNumber >= VoteManagerStart { + log.Info("updating checkpoint", "blockNumber", e.processedBlockNumber) + + auth, err := NewTransactionOpts(context.Background(), *e.conn, e.chainId, e.ks, e.account, updateCheckpointGasLimit) + if err != nil { + panic(err) + } + + bn := big.NewInt(int64(e.processedBlockNumber)) + tx, err := e.vm.UpdateCheckpoint(auth, bn) + + if err != nil { + if !e.enabled { + return + } + panic(err) + } + + WaitTxConfirmed(context.Background(), *e.conn, tx.Hash()) } +} - progress, err := e.conn.SyncProgress(context.TODO()) +func (e *EventListener) getCheckpoint() uint64 { + if e.currentBlockNumber < VoteManagerStart { + return BlockStorageStart + } + + blockNumber, err := e.vm.BlockCheckpointByValidatorId(nil, big.NewInt(int64(e.validatorId))) if err != nil { + if !e.enabled { + return 0 + } panic(err) } - e.syncingProcess = progress - e.currentBlockNumber = blockNumber + log.Info("checkpoint", "blockNumber", blockNumber.Uint64(), "validatorId", e.validatorId) + + if blockNumber.Uint64() < BlockStorageStart { + return BlockStorageStart + } + + return blockNumber.Uint64() } -func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) { +func (e *EventListener) newHashWorker(events <-chan *block_storage.BlockStorageNewHash) { for evt := range events { if e.enabled == false { return } - // Wait for the block to be confirmed - for { - if evt.Raw.BlockNumber+confirmations < e.currentBlockNumber { - break - } else { - log.Debug("waiting for block to be confirmed", "blockNumber", evt.Raw.BlockNumber, "currentBlockNumber", e.currentBlockNumber) - time.Sleep(250 * time.Millisecond) - } - } - tokens := e.verifier.validateHashEvent(evt) e.voter.Syncing = e.syncingProcess != nil // increase the batch size if we are syncing for _, token := range tokens { @@ -150,11 +276,16 @@ func (e *EventListener) worker(events <-chan *block_storage.BlockStorageNewHash) } } +func (e *EventListener) SetValidatorId(validatorId idx.ValidatorID) { + log.Info("setting validator id", "validatorId", validatorId) + e.validatorId = uint32(validatorId) +} + func (e *EventListener) Close() { if e.enabled { e.enabled = false log.Info("Closing Block storage watcher") - time.Sleep(time.Second) + time.Sleep(2 * time.Second) close(e.eventChannel) e.conn.Close() } diff --git a/integration/xenblocks/verifier/utils.go b/integration/xenblocks/verifier/utils.go index e5ad8b99a..7d6474db3 100644 --- a/integration/xenblocks/verifier/utils.go +++ b/integration/xenblocks/verifier/utils.go @@ -1,22 +1,43 @@ package verifier import ( - "unicode" + "context" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "math/big" + "time" ) -func max(a, b int) int { - if a > b { - return a +func NewTransactionOpts(context context.Context, conn ethclient.Client, chainId uint64, ks *keystore.KeyStore, account accounts.Account, gasLimit uint64) (*bind.TransactOpts, error) { + ci := new(big.Int).SetUint64(chainId) + auth, err := bind.NewKeyStoreTransactorWithChainID(ks, account, ci) + if err != nil { + return nil, err } - return b + + auth.GasTipCap, _ = conn.SuggestGasTipCap(context) + auth.GasFeeCap, _ = conn.SuggestGasPrice(context) + auth.GasLimit = gasLimit + + return auth, nil } -func countUppercase(input string) int { - count := 0 - for _, char := range input { - if unicode.IsUpper(char) { - count++ +func WaitTxConfirmed(context context.Context, conn ethclient.Client, hash common.Hash) <-chan *types.Transaction { + ch := make(chan *types.Transaction) + go func() { + for { + tx, pending, _ := conn.TransactionByHash(context, hash) + if !pending { + ch <- tx + } + + time.Sleep(time.Millisecond * 500) } - } - return count + }() + + return ch } diff --git a/integration/xenblocks/verifier/voter.go b/integration/xenblocks/verifier/voter.go index 9c65c847d..9034ae696 100644 --- a/integration/xenblocks/verifier/voter.go +++ b/integration/xenblocks/verifier/voter.go @@ -4,20 +4,16 @@ import ( "context" "github.com/Fantom-foundation/go-opera/integration/xenblocks/contracts/votemanager" "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "math/big" "sync" - "time" ) var ( BatchSize = 50 - GasLimit = uint64(8000000) + gasLimit = uint64(8000000) ) type Voter struct { @@ -43,21 +39,6 @@ func NewVoter(conn *ethclient.Client, ks *keystore.KeyStore, account accounts.Ac chainId: chainId, } } -func (v *Voter) waitTxConfirmed(hash common.Hash) <-chan *types.Transaction { - ch := make(chan *types.Transaction) - go func() { - for { - tx, pending, _ := v.conn.TransactionByHash(context.TODO(), hash) - if !pending { - ch <- tx - } - - time.Sleep(time.Millisecond * 500) - } - }() - - return ch -} func (v *Voter) AddToQueue(hashId *big.Int, MintedBlockNumber uint64, currencyType *big.Int, version uint16) { mbn := big.NewInt(int64(MintedBlockNumber)) @@ -75,16 +56,11 @@ func (v *Voter) AddToQueue(hashId *big.Int, MintedBlockNumber uint64, currencyTy func (v *Voter) Vote() error { log.Info("voting now!", "queue", len(v.queue)) - chainId := new(big.Int).SetUint64(v.chainId) - auth, err := bind.NewKeyStoreTransactorWithChainID(v.ks, v.account, chainId) + auth, err := NewTransactionOpts(context.Background(), *v.conn, v.chainId, v.ks, v.account, gasLimit) if err != nil { panic(err) } - auth.GasTipCap, _ = v.conn.SuggestGasTipCap(context.TODO()) - auth.GasFeeCap, _ = v.conn.SuggestGasPrice(context.TODO()) - auth.GasLimit = GasLimit - tx, err := v.vm.VoteBatch(auth, v.queue) if err != nil { log.Error("vote error", "err", err) @@ -93,7 +69,7 @@ func (v *Voter) Vote() error { log.Error("vote error", "err", "tx is nil") } - v.waitTxConfirmed(tx.Hash()) + WaitTxConfirmed(context.Background(), *v.conn, tx.Hash()) log.Info("vote success!", "tx", tx.Hash().Hex()) return nil