├── Makefile ├── common ├── types.go ├── reflect_tool.go └── log.go ├── config ├── const.go ├── config.json ├── utils.go └── config.go ├── executor ├── utils.go ├── mirror_converter.go ├── const.go ├── btc_executor_test.go ├── core_executor_test.go ├── btc_executor.go ├── core_executor.go ├── cc │ └── cgccaller.go └── relayerhub │ └── relayerhub.go ├── relayer ├── register.go ├── relayer.go ├── alert.go └── daemon.go ├── main.go ├── README.md ├── go.mod ├── LICENSE └── go.sum /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | ifeq ($(OS),Windows_NT) 3 | go build -o build/btc-relayer.exe main.go 4 | else 5 | go build -o build/btc-relayer main.go 6 | endif 7 | 8 | install: 9 | ifeq ($(OS),Windows_NT) 10 | go install main.go 11 | else 12 | go install main.go 13 | endif 14 | 15 | .PHONY: build install 16 | -------------------------------------------------------------------------------- /common/types.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/btcsuite/btcd/chaincfg/chainhash" 5 | "github.com/btcsuite/btcd/wire" 6 | ) 7 | 8 | type Task struct { 9 | Height int64 10 | BlockHash *chainhash.Hash 11 | BLOCK *wire.MsgBlock 12 | } 13 | 14 | type TaskSet struct { 15 | TaskList []Task 16 | } 17 | -------------------------------------------------------------------------------- /config/const.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | const ( 4 | DBDialectMysql = "mysql" 5 | DBDialectSqlite3 = "sqlite3" 6 | LocalConfig = "local" 7 | AWSConfig = "aws" 8 | KeyTypeLocalPrivateKey = "local_private_key" 9 | KeyTypeAWSPrivateKey = "aws_private_key" 10 | 11 | KeyTypeMnemonic = "local_mnemonic" 12 | KeyTypeAWSMnemonic = "aws_mnemonic" 13 | ) 14 | -------------------------------------------------------------------------------- /executor/utils.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | import ( 4 | "github.com/btcsuite/btcd/chaincfg/chainhash" 5 | "strconv" 6 | ) 7 | 8 | 9 | func RevertHash(blockHash *chainhash.Hash) (*chainhash.Hash) { 10 | 11 | bHash := *blockHash 12 | 13 | for i := 0; i < 16; i++ { 14 | bHash[i], bHash[32-1-i] = bHash[32-1-i], bHash[i] 15 | } 16 | 17 | return &bHash 18 | } 19 | 20 | func Int64ToString(value int64) string{ 21 | return strconv.FormatInt(value,10) 22 | } 23 | -------------------------------------------------------------------------------- /common/reflect_tool.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | func ReflectField(v interface{}, searchFieldName string) reflect.Value { 9 | 10 | var fieldValue reflect.Value 11 | 12 | t := reflect.TypeOf(v) 13 | o := reflect.ValueOf(v) 14 | 15 | if t.Kind() == reflect.Ptr { 16 | t = t.Elem() 17 | o = o.Elem() 18 | } 19 | 20 | num := t.NumField() 21 | for i := 0; i < num; i++ { 22 | value := o.Field(i) 23 | fieldName := t.Field(i).Name 24 | if fieldName == searchFieldName { 25 | fieldValue = value 26 | break 27 | } 28 | } 29 | 30 | fieldValue = reflect.NewAt(fieldValue.Type(), unsafe.Pointer(fieldValue.UnsafeAddr())) 31 | return fieldValue 32 | } 33 | -------------------------------------------------------------------------------- /executor/mirror_converter.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | import ( 4 | "github.com/btcsuite/btcd/chaincfg/chainhash" 5 | "github.com/btcsuite/btcd/wire" 6 | "github.com/coredao-org/btcpowermirror/lightmirror" 7 | "github.com/jinzhu/copier" 8 | ) 9 | 10 | func NewBtcLightMirror(block *wire.MsgBlock) *lightmirror.BtcLightMirrorV2 { 11 | return lightmirror.CreateBtcLightMirrorV2(&block.Header, 12 | block.Transactions[0], 13 | fillTxHashes(block.Transactions), 14 | ) 15 | } 16 | 17 | func fillTxHashes(transactions []*wire.MsgTx) []chainhash.Hash { 18 | txHashes := make([]chainhash.Hash, len(transactions)) 19 | 20 | for i := range transactions { 21 | copier.Copy(&txHashes[i], transactions[i].TxHash()) 22 | } 23 | 24 | return txHashes 25 | } 26 | -------------------------------------------------------------------------------- /executor/const.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | ) 6 | 7 | const ( 8 | DefaultGasPrice = 20000000000 // 20 GWei 9 | 10 | FallBehindThreshold = 5 11 | DataSeedDenyServiceThreshold = 60 12 | ) 13 | 14 | var ( 15 | prefixForCrossChainPackageKey = []byte{0x00} 16 | prefixForSequenceKey = []byte{0xf0} 17 | 18 | relayerIncentivizeContractAddr = common.HexToAddress("0x0000000000000000000000000000000000001005") 19 | relayerHubContractAddr = common.HexToAddress("0x0000000000000000000000000000000000001004") 20 | crossChainContractAddr = common.HexToAddress("0x0000000000000000000000000000000000002000") 21 | pcsAddr = common.HexToAddress("0x0000000000000000000000000000000000001003") 22 | ) 23 | -------------------------------------------------------------------------------- /relayer/register.go: -------------------------------------------------------------------------------- 1 | package relayer 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/coredao-org/btc-relayer/common" 7 | ) 8 | 9 | func (r *Relayer) registerRelayerHub() { 10 | isRelayer, err := r.coreExecutor.IsRelayer() 11 | if err != nil { 12 | panic(err) 13 | } 14 | if isRelayer { 15 | common.Logger.Info("This relayer has already been registered") 16 | return 17 | } 18 | 19 | common.Logger.Info("Register this relayer to RelayerHub") 20 | _, err = r.coreExecutor.RegisterRelayer() 21 | if err != nil { 22 | panic(err) 23 | } 24 | common.Logger.Info("Waiting for registration tx to be confirmed") 25 | time.Sleep(20 * time.Second) 26 | 27 | isRelayer, err = r.coreExecutor.IsRelayer() 28 | if err != nil { 29 | panic(err) 30 | } 31 | if !isRelayer { 32 | panic("Failed to register relayer") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /relayer/relayer.go: -------------------------------------------------------------------------------- 1 | package relayer 2 | 3 | import ( 4 | config "github.com/coredao-org/btc-relayer/config" 5 | "github.com/coredao-org/btc-relayer/executor" 6 | ) 7 | 8 | type Relayer struct { 9 | cfg *config.Config 10 | btcExecutor *executor.BTCExecutor 11 | coreExecutor *executor.COREExecutor 12 | } 13 | 14 | func NewRelayer(cfg *config.Config, BTCExecutor *executor.BTCExecutor, coreExecutor *executor.COREExecutor) *Relayer { 15 | return &Relayer{ 16 | cfg: cfg, 17 | btcExecutor: BTCExecutor, 18 | coreExecutor: coreExecutor, 19 | } 20 | } 21 | 22 | func (r *Relayer) Start() { 23 | 24 | //register relayer 25 | r.registerRelayerHub() 26 | 27 | go r.RelayerCompetitionDaemon() 28 | 29 | go r.btcExecutor.UpdateClients() 30 | go r.coreExecutor.UpdateClients() 31 | 32 | go r.alert() 33 | } 34 | -------------------------------------------------------------------------------- /executor/btc_executor_test.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestBTCExecutor_GetLatestBlockHeight(t *testing.T) { 10 | executor, err := NewBTCExecutor(cfg) 11 | require.NoError(t, err) 12 | 13 | height, err := executor.GetLatestBlockHeight(executor.GetClient()) 14 | require.NotNilf(t, height, "error") 15 | } 16 | 17 | func TestGetBlockHash(t *testing.T) { 18 | executor, err := NewBTCExecutor(cfg) 19 | require.NoError(t, err) 20 | 21 | hash, err := executor.GetBlockHash(executor.GetClient(), 0) 22 | require.NotNilf(t, hash, "error") 23 | } 24 | 25 | func TestGetBlock(t *testing.T) { 26 | 27 | BTCExecutor, err := NewBTCExecutor(cfg) 28 | require.NoError(t, err) 29 | 30 | height, err := BTCExecutor.GetLatestBlockHeight(BTCExecutor.GetClient()) 31 | require.NoError(t, err) 32 | require.Greaterf(t, height, int64(0), "must be greater then 0") 33 | 34 | hash, err := BTCExecutor.GetBlockHash(BTCExecutor.GetClient(), height) 35 | require.NoError(t, err) 36 | 37 | block, err := BTCExecutor.GetBlock(BTCExecutor.GetClient(), hash) 38 | require.NotNilf(t, block, "error") 39 | } 40 | -------------------------------------------------------------------------------- /config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "cross_chain_config": { 3 | "recursion_height": 10 4 | }, 5 | "btc_config": { 6 | "rpc_addrs": [ 7 | {"host": "btc_rpc_address", "user": "user", "pass": "pwd"} 8 | ], 9 | "sleep_second": 1, 10 | "data_seed_deny_service_threshold": 60 11 | }, 12 | "core_config": { 13 | "private_key": "core_privateKey", 14 | "providers": [ 15 | "core_rpcaddress" 16 | ], 17 | "gas_limit": 4700000, 18 | "gas_increase": 1000000, 19 | "gas_price": 1000000000, 20 | "sleep_second": 1, 21 | "data_seed_deny_service_threshold": 60 22 | }, 23 | "log_config": { 24 | "level": "DEBUG", 25 | "filename": "relay.log", 26 | "max_file_size_in_mb": 500, 27 | "max_backups_of_log_files": 10, 28 | "max_age_to_retain_log_files_in_days": 0, 29 | "use_console_logger": false, 30 | "use_file_logger": true, 31 | "compress": false 32 | }, 33 | "alert_config": { 34 | "enable_alert": false, 35 | "enable_heart_beat": false, 36 | "interval": 300, 37 | "identity": "your_service_name", 38 | "telegram_bot_id": "your_telegram_bot_id", 39 | "telegram_chat_id": "your_telegram_chat_id", 40 | "balance_threshold": "1000000000000000000", 41 | "sequence_gap_threshold": 10 42 | } 43 | } -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/coredao-org/btc-relayer/common" 6 | config "github.com/coredao-org/btc-relayer/config" 7 | "github.com/coredao-org/btc-relayer/executor" 8 | "github.com/coredao-org/btc-relayer/relayer" 9 | ) 10 | 11 | const ( 12 | flagConfigPath = "config.json" 13 | ) 14 | 15 | func printUsage() { 16 | fmt.Print("usage: ./btc-relayer --config-path configFile\n") 17 | } 18 | 19 | /** 20 | init cfg 21 | */ 22 | func initCfg() *config.Config { 23 | 24 | var cfg *config.Config 25 | 26 | cfg = config.ParseConfigFromFile(flagConfigPath) 27 | 28 | if cfg == nil { 29 | common.Logger.Infof("failed to get configuration") 30 | } 31 | 32 | return cfg 33 | } 34 | 35 | func main() { 36 | 37 | //init cfg 38 | cfg := initCfg() 39 | 40 | //init logger 41 | common.InitLogger(&cfg.LogConfig) 42 | 43 | //init executors 44 | btcExecutor, err := executor.NewBTCExecutor(cfg) 45 | if err != nil { 46 | common.Logger.Error(err.Error()) 47 | return 48 | } 49 | 50 | coreExecutor, err := executor.NewCOREExecutor(cfg) 51 | if err != nil { 52 | common.Logger.Error(err.Error()) 53 | return 54 | } 55 | 56 | relayerInstance := relayer.NewRelayer(cfg, btcExecutor, coreExecutor) 57 | 58 | common.Logger.Info("Starting relayer") 59 | relayerInstance.Start() 60 | 61 | select {} 62 | } 63 | -------------------------------------------------------------------------------- /relayer/alert.go: -------------------------------------------------------------------------------- 1 | package relayer 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/shopspring/decimal" 8 | 9 | "github.com/coredao-org/btc-relayer/common" 10 | util "github.com/coredao-org/btc-relayer/config" 11 | ) 12 | 13 | const ( 14 | RetryInterval = 5 * time.Second 15 | ) 16 | 17 | func (r *Relayer) alert() { 18 | if !r.cfg.AlertConfig.EnableAlert { 19 | return 20 | } 21 | balanceThreshold, err := decimal.NewFromString(r.cfg.AlertConfig.BalanceThreshold) 22 | if err != nil { 23 | panic(err) 24 | } 25 | for { 26 | balance, err := r.coreExecutor.GetRelayerBalance() 27 | if err != nil { 28 | time.Sleep(RetryInterval) 29 | continue 30 | } else { 31 | balance, err := decimal.NewFromString(balance.String()) 32 | if err != nil { 33 | common.Logger.Error(err.Error()) 34 | } 35 | if r.cfg.AlertConfig.EnableHeartBeat { 36 | util.SendTelegramMessage(r.cfg.AlertConfig.Identity, r.cfg.AlertConfig.TelegramBotId, r.cfg.AlertConfig.TelegramChatId, fmt.Sprintf("Info: heartbeat message: relayer balance: %s", balance.String())) 37 | } 38 | if balance.Cmp(balanceThreshold) <= 0 { 39 | msg := fmt.Sprintf("Alert: btc-relayer balance (%s:Core) on Core Chain is less than threshold (%s:Core)", 40 | balance.Div(decimal.NewFromInt(1e18)).String(), balanceThreshold.Div(decimal.NewFromInt(1e18)).String()) 41 | util.SendTelegramMessage(r.cfg.AlertConfig.Identity, r.cfg.AlertConfig.TelegramBotId, r.cfg.AlertConfig.TelegramChatId, msg) 42 | } 43 | } 44 | 45 | time.Sleep(time.Duration(r.cfg.AlertConfig.Interval) * time.Second) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /config/utils.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | 9 | "github.com/aws/aws-sdk-go/aws" 10 | "github.com/aws/aws-sdk-go/aws/session" 11 | "github.com/aws/aws-sdk-go/service/secretsmanager" 12 | ) 13 | 14 | func GetSecret(secretName, region string) (string, error) { 15 | //Create a Secrets Manager client 16 | sess, err := session.NewSession(&aws.Config{ 17 | Region: ®ion, 18 | }) 19 | if err != nil { 20 | return "", err 21 | } 22 | 23 | svc := secretsmanager.New(sess) 24 | input := &secretsmanager.GetSecretValueInput{ 25 | SecretId: aws.String(secretName), 26 | VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified 27 | } 28 | 29 | result, err := svc.GetSecretValue(input) 30 | if err != nil { 31 | return "", err 32 | } 33 | 34 | var secretString, decodedBinarySecret string 35 | if result.SecretString != nil { 36 | secretString = *result.SecretString 37 | return secretString, nil 38 | } else { 39 | decodedBinarySecretBytes := make([]byte, base64.StdEncoding.DecodedLen(len(result.SecretBinary))) 40 | length, err := base64.StdEncoding.Decode(decodedBinarySecretBytes, result.SecretBinary) 41 | if err != nil { 42 | fmt.Println("Base64 Decode Error:", err) 43 | return "", err 44 | } 45 | decodedBinarySecret = string(decodedBinarySecretBytes[:length]) 46 | return decodedBinarySecret, nil 47 | } 48 | } 49 | 50 | func SendTelegramMessage(identity string, botId string, chatId string, msg string) { 51 | if botId == "" || chatId == "" || msg == "" { 52 | return 53 | } 54 | 55 | endPoint := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", botId) 56 | formData := url.Values{ 57 | "chat_id": {chatId}, 58 | "parse_mode": {"html"}, 59 | "text": {fmt.Sprintf("%s: %s", identity, msg)}, 60 | } 61 | _, err := http.PostForm(endPoint, formData) 62 | if err != nil { 63 | fmt.Println(fmt.Sprintf("send telegram message error, bot_id=%s, chat_id=%s, msg=%s, err=%s", botId, chatId, msg, err.Error())) 64 | return 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Relayer service from BTC to CORE 2 | 3 | ## Relayers in Core 4 | 5 | Relayers in Core are responsible for relaying BTC block headers onto the network via the on-chain light client. Relayers must both register and pass verification in order to receive rewards. 6 | 7 | For more information about relayers, please read [PoW in Core blockchain](https://docs.coredao.org/core-white-paper-v1.0.5/satoshi-plus-consensus/proof-of-work). 8 | 9 | ## Quick Start 10 | 11 | **Note**: Requires [Go 1.17+](https://golang.org/dl/) 12 | 13 | ### Setup config 14 | 15 | 1. Edit `config/config.json` 16 | 1. Fill in your private key to `core_config.private_key`. 17 | 2. Edit btc_config.rpc_addrs, fill in btc rpc address. Modify sleep_second, which is the interval to refresh btc highestHeight. Modify data_seed_deny_service_threshold, which is the interval to send telegram alert when refreshing btc highestHeight fails. 18 | 3. Edit core_config.providers, fill in core rpc address. Modify sleep_second, which is the interval to refresh core highestHeight. Modify data_seed_deny_service_threshold, which is the interval to send telegram alert when refreshing core highestHeight fails. 19 | 4. If gas_limit is not enough, gas_increase will be added and a retry will be taken. 20 | 5. Recursion_height is the number of blocks to go back and check on btc network based on the newest height. 21 | 2. Transfer enough CORE to the relayer account. 22 | 1. 100 CORE as relayer registration fees. 23 | 2. More than 10 CORE as transaction fees. 24 | 3. Send telegram message when the balance of relayer account is too low. This is an example config: 25 | ```json 26 | { 27 | "enable_alert": true, 28 | "enable_heart_beat": false, 29 | "interval": 300, 30 | "telegram_bot_id": "your_bot_id", 31 | "telegram_chat_id": "your_chat_id", 32 | "balance_threshold": "1000000000000000000", 33 | "sequence_gap_threshold": 10 34 | } 35 | ``` 36 | Please refer to [telegram_bot](https://www.home-assistant.io/integrations/telegram_bot) to setup your telegram bot. If you don't want this feature, just set `enable_alert` to false. 37 | 38 | ### Build 39 | 40 | #### Build Binary: 41 | ```shell script 42 | make build 43 | ``` 44 | 45 | ### Run 46 | 47 | Run locally: 48 | ```shell script 49 | ./btc-relayer 50 | ``` 51 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/coredao-org/btc-relayer 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/aws/aws-sdk-go v1.27.0 7 | github.com/btcsuite/btcd v0.23.3 8 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 9 | github.com/coredao-org/btcpowermirror v1.1.0 10 | 11 | github.com/ethereum/go-ethereum v1.10.20 12 | github.com/jinzhu/copier v0.3.2 13 | github.com/jinzhu/gorm v1.9.12 14 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 15 | github.com/shopspring/decimal v1.2.0 16 | github.com/stretchr/testify v1.7.2 17 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 18 | ) 19 | 20 | require ( 21 | github.com/BurntSushi/toml v1.1.0 // indirect 22 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect 23 | github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect 24 | github.com/btcsuite/btcd/btcutil v1.1.0 // indirect 25 | github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect 26 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect 27 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect 28 | github.com/cespare/cp v1.1.1 // indirect 29 | github.com/davecgh/go-spew v1.1.1 // indirect 30 | github.com/deckarep/golang-set v1.8.0 // indirect 31 | github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect 32 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect 33 | github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect 34 | github.com/go-ole/go-ole v1.2.1 // indirect 35 | github.com/go-stack/stack v1.8.0 // indirect 36 | github.com/google/uuid v1.2.0 // indirect 37 | github.com/gorilla/websocket v1.4.2 // indirect 38 | github.com/jinzhu/inflection v1.0.0 // indirect 39 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect 40 | github.com/kr/pretty v0.3.0 // indirect 41 | github.com/pmezard/go-difflib v1.0.0 // indirect 42 | github.com/rjeczalik/notify v0.9.2 // indirect 43 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect 44 | github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 // indirect 45 | github.com/tklauser/go-sysconf v0.3.5 // indirect 46 | github.com/tklauser/numcpus v0.2.2 // indirect 47 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect 48 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect 49 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect 50 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect 51 | gopkg.in/yaml.v3 v3.0.1 // indirect 52 | ) 53 | -------------------------------------------------------------------------------- /common/log.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "os" 5 | 6 | config "github.com/coredao-org/btc-relayer/config" 7 | "github.com/op/go-logging" 8 | "gopkg.in/natefinch/lumberjack.v2" 9 | ) 10 | 11 | var ( 12 | // Logger instance for quick declarative logging levels 13 | Logger = logging.MustGetLogger("relayer") 14 | SdkLogger = &sdkLogger{} 15 | 16 | // log levels that are available 17 | levels = map[string]logging.Level{ 18 | "CRITICAL": logging.CRITICAL, 19 | "ERROR": logging.ERROR, 20 | "WARNING": logging.WARNING, 21 | "NOTICE": logging.NOTICE, 22 | "INFO": logging.INFO, 23 | "DEBUG": logging.DEBUG, 24 | } 25 | ) 26 | 27 | // InitLogger initializes the logger. 28 | func InitLogger(config *config.LogConfig) { 29 | backends := make([]logging.Backend, 0) 30 | 31 | if config.UseConsoleLogger { 32 | consoleFormat := logging.MustStringFormatter(`%{time:2006-01-02 15:04:05} %{level} %{shortfunc} %{message}`) 33 | consoleLogger := logging.NewLogBackend(os.Stdout, "", 0) 34 | consoleFormatter := logging.NewBackendFormatter(consoleLogger, consoleFormat) 35 | consoleLoggerLeveled := logging.AddModuleLevel(consoleFormatter) 36 | consoleLoggerLeveled.SetLevel(levels[config.Level], "") 37 | backends = append(backends, consoleLoggerLeveled) 38 | } 39 | 40 | if config.UseFileLogger { 41 | fileLogger := logging.NewLogBackend(&lumberjack.Logger{ 42 | Filename: config.Filename, 43 | MaxSize: config.MaxFileSizeInMB, // MaxSize is the maximum size in megabytes of the log file 44 | MaxBackups: config.MaxBackupsOfLogFiles, // MaxBackups is the maximum number of old log files to retain 45 | MaxAge: config.MaxAgeToRetainLogFilesInDays, // MaxAge is the maximum number of days to retain old log files 46 | Compress: config.Compress, 47 | }, "", 0) 48 | fileFormat := logging.MustStringFormatter(`%{time:2006-01-02 15:04:05} %{level} %{shortfunc} %{message}`) 49 | fileFormatter := logging.NewBackendFormatter(fileLogger, fileFormat) 50 | fileLoggerLeveled := logging.AddModuleLevel(fileFormatter) 51 | fileLoggerLeveled.SetLevel(levels[config.Level], "") 52 | backends = append(backends, fileLoggerLeveled) 53 | } 54 | 55 | logging.SetBackend(backends...) 56 | } 57 | 58 | type sdkLogger struct { 59 | } 60 | 61 | func (l *sdkLogger) Debug(msg string, keyvals ...interface{}) { 62 | Logger.Debug(msg) 63 | } 64 | 65 | func (l *sdkLogger) Info(msg string, keyvals ...interface{}) { 66 | Logger.Info(msg) 67 | } 68 | 69 | func (l *sdkLogger) Error(msg string, keyvals ...interface{}) { 70 | Logger.Error(msg) 71 | } 72 | -------------------------------------------------------------------------------- /executor/core_executor_test.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | import ( 4 | "bytes" 5 | "crypto/ecdsa" 6 | "encoding/hex" 7 | "github.com/btcsuite/btcd/chaincfg/chainhash" 8 | "github.com/coredao-org/btcpowermirror/lightmirror" 9 | "github.com/ethereum/go-ethereum/crypto" 10 | "log" 11 | "testing" 12 | 13 | relayercommon "github.com/coredao-org/btc-relayer/common" 14 | 15 | config "github.com/coredao-org/btc-relayer/config" 16 | "github.com/stretchr/testify/require" 17 | ) 18 | 19 | const ( 20 | provider = "http://{coreRpcAddress}" 21 | privateKey = "" 22 | ) 23 | 24 | var ( 25 | cfg = &config.Config{ 26 | CrossChainConfig: config.CrossChainConfig{ 27 | RecursionHeight: 10, 28 | }, 29 | BTCConfig: config.BTCConfig{ 30 | RpcAddrs: []config.BTCRpcAddrs{{Host: "btc_address}", User: "", Pass: ""}}, 31 | }, 32 | COREConfig: config.COREConfig{ 33 | GasLimit: 4700000, 34 | Providers: []string{provider}, 35 | PrivateKey: privateKey, 36 | }, 37 | } 38 | ) 39 | 40 | func TestCOREExecutor_NewBTCExecutor(t *testing.T) { 41 | BTCExecutor, err := NewBTCExecutor(cfg) 42 | require.NoError(t, err) 43 | require.NotNilf(t, BTCExecutor, "error") 44 | } 45 | 46 | func TestCOREExecutor_GetLatestBlockHeight(t *testing.T) { 47 | executor, err := NewCOREExecutor(cfg) 48 | require.NoError(t, err) 49 | 50 | height, err := executor.GetLatestBlockHeight(executor.GetClient()) 51 | require.NoError(t, err) 52 | require.Greaterf(t, height, int64(0), "") 53 | } 54 | 55 | func TestCOREExecutor_UpdateClients(t *testing.T) { 56 | executor, err := NewCOREExecutor(cfg) 57 | require.NoError(t, err) 58 | 59 | executor.UpdateClients() 60 | require.NoError(t, err) 61 | } 62 | 63 | func TestCOREExecutor_RegisterRelayer(t *testing.T) { 64 | executor, err := NewCOREExecutor(cfg) 65 | require.NoError(t, err) 66 | 67 | txHash, err := executor.RegisterRelayer() 68 | require.NoError(t, err) 69 | require.NotNil(t, txHash) 70 | } 71 | 72 | func TestCOREExecutor_IsRelayer(t *testing.T) { 73 | executor, err := NewCOREExecutor(cfg) 74 | require.NoError(t, err) 75 | 76 | isRelayer, err := executor.IsRelayer() 77 | require.NoError(t, err) 78 | require.Equal(t, isRelayer, true, "") 79 | } 80 | 81 | func TestCOREExecutor_CheckBlockRelayed(t *testing.T) { 82 | executor, err := NewCOREExecutor(cfg) 83 | require.NoError(t, err) 84 | 85 | result, err := executor.CheckBlockRelayed(&chainhash.Hash{}) 86 | require.NoError(t, err) 87 | require.Equal(t, false, result, "") 88 | } 89 | 90 | func TestCOREExecutor_SyncBTCLightMirror(t *testing.T) { 91 | BTCExecutor, err := NewBTCExecutor(cfg) 92 | require.NoError(t, err) 93 | executor, err := NewCOREExecutor(cfg) 94 | require.NoError(t, err) 95 | 96 | hash, err := BTCExecutor.GetBlockHash(BTCExecutor.GetClient(), 717696) 97 | require.NoError(t, err) 98 | 99 | block, err := BTCExecutor.GetBlock(BTCExecutor.GetClient(), hash) 100 | require.NoError(t, err) 101 | 102 | task := relayercommon.Task{BLOCK: block, BlockHash: hash, Height: 717696} 103 | txHash, err := executor.SyncBTCLightMirror(&task) 104 | require.NoError(t, err) 105 | t.Log(txHash.String()) 106 | } 107 | 108 | func TestCOREExecutor_testGeneratorPublicKey(t *testing.T) { 109 | privateKey := "" 110 | privKey, err := crypto.HexToECDSA(privateKey) 111 | require.NoError(t, err) 112 | 113 | publicKey := privKey.Public() 114 | publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey) 115 | pub := hex.EncodeToString(crypto.FromECDSAPub(publicKeyECDSA)) 116 | require.NotNil(t, pub) 117 | } 118 | 119 | func TestCOREExecutor_testCore2(t *testing.T) { 120 | btcExecutor, err := NewBTCExecutor(cfg) 121 | btcHash, err := btcExecutor.GetClient().GetBlockHash(766080) 122 | if err != nil { 123 | return 124 | } 125 | 126 | log.Println(btcHash.String()) 127 | 128 | header, err := btcExecutor.GetClient().GetBlock(btcHash) 129 | 130 | var b bytes.Buffer 131 | header.Serialize(&b) 132 | bb := b.Bytes() 133 | ss := hex.EncodeToString(bb) 134 | log.Println(ss) 135 | 136 | printMirror(NewBtcLightMirror(header)) 137 | 138 | require.NotNil(t, ss) 139 | } 140 | 141 | func printMirror(mirror *lightmirror.BtcLightMirrorV2) { 142 | var b bytes.Buffer 143 | mirror.Serialize(&b) 144 | bb := b.Bytes() 145 | 146 | ss := hex.EncodeToString(bb) 147 | log.Println(ss) 148 | } 149 | -------------------------------------------------------------------------------- /executor/btc_executor.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "sync" 7 | "time" 8 | 9 | "github.com/btcsuite/btcd/chaincfg/chainhash" 10 | "github.com/btcsuite/btcd/wire" 11 | 12 | "github.com/btcsuite/btcd/rpcclient" 13 | "github.com/coredao-org/btc-relayer/common" 14 | config "github.com/coredao-org/btc-relayer/config" 15 | ) 16 | 17 | type BTCClient struct { 18 | BTCClient *rpcclient.Client 19 | Provider string 20 | CurrentHeight int64 21 | UpdatedAt time.Time 22 | } 23 | 24 | type BTCExecutor struct { 25 | mutex sync.RWMutex 26 | clientIdx int 27 | HighestHeight int64 28 | BTCClients []*BTCClient 29 | Config *config.Config 30 | } 31 | 32 | func initBTCClients(providers []config.BTCRpcAddrs) []*BTCClient { 33 | btcClients := make([]*BTCClient, 0) 34 | for _, provider := range providers { 35 | 36 | // create new client instance 37 | btcClient, err := rpcclient.New(&rpcclient.ConnConfig{ 38 | HTTPPostMode: true, 39 | DisableTLS: true, 40 | Host: provider.Host, 41 | User: provider.User, 42 | Pass: provider.Pass, 43 | }, nil) 44 | if err != nil { 45 | log.Fatalf("error creating new btc client: %v", err) 46 | } 47 | 48 | btcClients = append(btcClients, &BTCClient{ 49 | BTCClient: btcClient, 50 | Provider: provider.Host, 51 | UpdatedAt: time.Now(), 52 | }) 53 | } 54 | return btcClients 55 | } 56 | 57 | func NewBTCExecutor(cfg *config.Config) (*BTCExecutor, error) { 58 | return &BTCExecutor{ 59 | clientIdx: 0, 60 | BTCClients: initBTCClients(cfg.BTCConfig.RpcAddrs), 61 | Config: cfg, 62 | }, nil 63 | } 64 | 65 | func (executor *BTCExecutor) GetClient() *rpcclient.Client { 66 | executor.mutex.RLock() 67 | defer executor.mutex.RUnlock() 68 | return executor.BTCClients[executor.clientIdx].BTCClient 69 | } 70 | 71 | func (executor *BTCExecutor) SwitchBTClient() { 72 | executor.mutex.Lock() 73 | defer executor.mutex.Unlock() 74 | executor.clientIdx++ 75 | if executor.clientIdx >= len(executor.BTCClients) { 76 | executor.clientIdx = 0 77 | } 78 | common.Logger.Infof("Switch to RPC endpoint: %s", executor.Config.BTCConfig.RpcAddrs[executor.clientIdx]) 79 | } 80 | 81 | func (executor *BTCExecutor) GetLatestBlockHeight(client *rpcclient.Client) (int64, error) { 82 | height, err := client.GetBlockCount() 83 | if err != nil { 84 | return 0, err 85 | } 86 | return height, nil 87 | } 88 | 89 | func (executor *BTCExecutor) GetBlockHash(client *rpcclient.Client, height int64) (*chainhash.Hash, error) { 90 | hash, err := client.GetBlockHash(height) 91 | if err != nil { 92 | return nil, err 93 | } 94 | return hash, nil 95 | } 96 | 97 | func (executor *BTCExecutor) GetBlock(client *rpcclient.Client, hash *chainhash.Hash) (*wire.MsgBlock, error) { 98 | block, err := client.GetBlock(hash) 99 | if err != nil { 100 | return nil, err 101 | } 102 | return block, nil 103 | } 104 | 105 | func (executor *BTCExecutor) UpdateClients() { 106 | for { 107 | for _, btcClient := range executor.BTCClients { 108 | if time.Since(btcClient.UpdatedAt).Seconds() > executor.Config.BTCConfig.DataSeedDenyServiceThreshold { 109 | msg := fmt.Sprintf("data seed %s is not accessible", btcClient.Provider) 110 | common.Logger.Error(msg) 111 | config.SendTelegramMessage(executor.Config.AlertConfig.Identity, executor.Config.AlertConfig.TelegramBotId, executor.Config.AlertConfig.TelegramChatId, msg) 112 | } 113 | height, err := executor.GetLatestBlockHeight(btcClient.BTCClient) 114 | if err != nil { 115 | common.Logger.Errorf("get latest block height error, err=%s", err.Error()) 116 | continue 117 | } 118 | btcClient.CurrentHeight = height 119 | btcClient.UpdatedAt = time.Now() 120 | } 121 | highestHeight := int64(0) 122 | highestIdx := 0 123 | for idx := 0; idx < len(executor.BTCClients); idx++ { 124 | if executor.BTCClients[idx].CurrentHeight > highestHeight { 125 | highestHeight = executor.BTCClients[idx].CurrentHeight 126 | highestIdx = idx 127 | } 128 | } 129 | 130 | //if executor.BTCClients[executor.clientIdx].CurrentHeight+FallBehindThreshold < highestHeight { 131 | if highestHeight > executor.HighestHeight { 132 | common.Logger.Infof("new height:" + Int64ToString(highestHeight)) 133 | 134 | executor.mutex.Lock() 135 | executor.clientIdx = highestIdx 136 | executor.HighestHeight = highestHeight 137 | executor.mutex.Unlock() 138 | } 139 | time.Sleep(time.Duration(executor.Config.BTCConfig.SleepSecond) * time.Second) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "math/big" 8 | "os" 9 | "path" 10 | "path/filepath" 11 | "runtime" 12 | "strings" 13 | ) 14 | 15 | type Config struct { 16 | CrossChainConfig CrossChainConfig `json:"cross_chain_config"` 17 | BTCConfig BTCConfig `json:"btc_config"` 18 | COREConfig COREConfig `json:"core_config"` 19 | LogConfig LogConfig `json:"log_config"` 20 | AlertConfig AlertConfig `json:"alert_config"` 21 | } 22 | 23 | type CrossChainConfig struct { 24 | RecursionHeight int64 `json:"recursion_height"` 25 | } 26 | 27 | func (cfg *CrossChainConfig) Validate() { 28 | } 29 | 30 | type BTCRpcAddrs struct { 31 | Host string `json:"host"` 32 | User string `json:"user"` 33 | Pass string `json:"pass"` 34 | } 35 | 36 | type BTCConfig struct { 37 | RpcAddrs []BTCRpcAddrs `json:"rpc_addrs"` 38 | SleepSecond uint64 `json:"sleep_second"` 39 | DataSeedDenyServiceThreshold float64 `json:"data_seed_deny_service_threshold"` 40 | } 41 | 42 | func (cfg *BTCConfig) Validate() { 43 | if len(cfg.RpcAddrs) == 0 { 44 | panic("rpc endpoint of BTC chain should not be empty") 45 | } 46 | } 47 | 48 | type COREConfig struct { 49 | PrivateKey string `json:"private_key"` 50 | Providers []string `json:"providers"` 51 | GasLimit uint64 `json:"gas_limit"` 52 | GasPrice uint64 `json:"gas_price"` 53 | GasIncrease uint64 `json:"gas_increase"` 54 | SleepSecond uint64 `json:"sleep_second"` 55 | DataSeedDenyServiceThreshold float64 `json:"data_seed_deny_service_threshold"` 56 | } 57 | 58 | func (cfg *COREConfig) Validate() { 59 | if len(cfg.Providers) == 0 { 60 | panic(fmt.Sprintf("provider address of Core Chain should not be empty")) 61 | } 62 | 63 | if cfg.GasLimit == 0 { 64 | panic(fmt.Sprintf("gas_limit of Core Chain should be larger than 0")) 65 | } 66 | } 67 | 68 | type LogConfig struct { 69 | Level string `json:"level"` 70 | Filename string `json:"filename"` 71 | MaxFileSizeInMB int `json:"max_file_size_in_mb"` 72 | MaxBackupsOfLogFiles int `json:"max_backups_of_log_files"` 73 | MaxAgeToRetainLogFilesInDays int `json:"max_age_to_retain_log_files_in_days"` 74 | UseConsoleLogger bool `json:"use_console_logger"` 75 | UseFileLogger bool `json:"use_file_logger"` 76 | Compress bool `json:"compress"` 77 | } 78 | 79 | func (cfg *LogConfig) Validate() { 80 | if cfg.UseFileLogger { 81 | if cfg.Filename == "" { 82 | panic("filename should not be empty if using file logger") 83 | } 84 | if cfg.MaxFileSizeInMB <= 0 { 85 | panic("max_file_size_in_mb should be larger than 0 if using file logger") 86 | } 87 | if cfg.MaxBackupsOfLogFiles <= 0 { 88 | panic("max_backups_off_log_files should be larger than 0 if using file logger") 89 | } 90 | } 91 | } 92 | 93 | type AlertConfig struct { 94 | EnableAlert bool `json:"enable_alert"` 95 | EnableHeartBeat bool `json:"enable_heart_beat"` 96 | Interval int64 `json:"interval"` 97 | 98 | Identity string `json:"identity"` 99 | TelegramBotId string `json:"telegram_bot_id"` 100 | TelegramChatId string `json:"telegram_chat_id"` 101 | 102 | BalanceThreshold string `json:"balance_threshold"` 103 | SequenceGapThreshold uint64 `json:"sequence_gap_threshold"` 104 | } 105 | 106 | func (cfg *AlertConfig) Validate() { 107 | if !cfg.EnableAlert { 108 | return 109 | } 110 | if cfg.Interval <= 0 { 111 | panic("alert interval should be positive") 112 | } 113 | balanceThreshold, ok := big.NewInt(1).SetString(cfg.BalanceThreshold, 10) 114 | if !ok { 115 | panic(fmt.Sprintf("unrecognized balance_threshold")) 116 | } 117 | 118 | if balanceThreshold.Cmp(big.NewInt(0)) <= 0 { 119 | panic(fmt.Sprintf("balance_threshold should be positive")) 120 | } 121 | 122 | if cfg.SequenceGapThreshold <= 0 { 123 | panic(fmt.Sprintf("sequence_gap_threshold should be positive")) 124 | } 125 | } 126 | 127 | func (cfg *Config) Validate() { 128 | cfg.CrossChainConfig.Validate() 129 | cfg.LogConfig.Validate() 130 | cfg.BTCConfig.Validate() 131 | cfg.COREConfig.Validate() 132 | cfg.AlertConfig.Validate() 133 | //cfg.DBConfig.Validate() 134 | } 135 | 136 | func ParseConfigFromJson(content string) *Config { 137 | var config Config 138 | if err := json.Unmarshal([]byte(content), &config); err != nil { 139 | panic(err) 140 | } 141 | return &config 142 | } 143 | 144 | func ParseConfigFromFile(filePath string) *Config { 145 | 146 | fullFilePath := path.Join(GetCurrentAbPath(), string(os.PathSeparator)+filePath) 147 | 148 | fmt.Println("config path:" + fullFilePath) 149 | //fullFilePath := dir + string(os.PathSeparator) + filePath 150 | bz, err := ioutil.ReadFile(fullFilePath) 151 | if err != nil { 152 | panic(err) 153 | } 154 | 155 | var config Config 156 | 157 | if err := json.Unmarshal(bz, &config); err != nil { 158 | panic(err) 159 | } 160 | 161 | config.Validate() 162 | 163 | return &config 164 | } 165 | 166 | //getCurrentAbPath 167 | func GetCurrentAbPath() string { 168 | dir := getCurrentAbPathByExecutable() 169 | tmpDir, _ := filepath.EvalSymlinks(os.TempDir()) 170 | if strings.Contains(dir, tmpDir) { 171 | return getCurrentAbPathByCaller() 172 | } 173 | return dir 174 | } 175 | 176 | // go build path 177 | func getCurrentAbPathByExecutable() string { 178 | exePath, err := os.Executable() 179 | if err != nil { 180 | panic(err) 181 | } 182 | res, _ := filepath.EvalSymlinks(filepath.Dir(exePath)) 183 | res = res + string(os.PathSeparator) + "config" 184 | return res 185 | } 186 | 187 | // go run path 188 | func getCurrentAbPathByCaller() string { 189 | var abPath string 190 | _, filename, _, ok := runtime.Caller(2) 191 | if ok { 192 | abPath = path.Dir(filename) 193 | } 194 | return abPath 195 | } 196 | -------------------------------------------------------------------------------- /relayer/daemon.go: -------------------------------------------------------------------------------- 1 | package relayer 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/btcsuite/btcd/chaincfg/chainhash" 9 | "github.com/coredao-org/btc-relayer/common" 10 | "github.com/coredao-org/btc-relayer/executor" 11 | ) 12 | 13 | var ( 14 | ZERO_HASH = chainhash.Hash{00000000000000000000000000000000} 15 | ) 16 | 17 | func (r *Relayer) getLatestHeight() uint64 { 18 | height, err := r.btcExecutor.GetLatestBlockHeight(r.btcExecutor.GetClient()) 19 | if err != nil { 20 | common.Logger.Errorf("Query latest height error: %s", err.Error()) 21 | return 0 22 | } 23 | return uint64(height) 24 | } 25 | 26 | func (r *Relayer) getLastRelayHeight() (int64, error) { 27 | //last relayed btc block hash 28 | chainTip, err := r.coreExecutor.GetChainTip() 29 | if err != nil { 30 | return 0, err 31 | } 32 | 33 | chainTip = executor.RevertHash(chainTip) 34 | 35 | blockHeaderVerbose, err := r.btcExecutor.GetClient().GetBlockHeaderVerbose(chainTip) 36 | if err != nil { 37 | return 0, err 38 | } 39 | 40 | height := int64(blockHeaderVerbose.Height) 41 | blockHash, err := r.btcExecutor.GetClient().GetBlockHash(height) 42 | if err != nil { 43 | return 0, err 44 | } 45 | blockHeaderVerboseNew, err := r.btcExecutor.GetClient().GetBlockHeaderVerbose(blockHash) 46 | 47 | //Forked, need to push backwards 48 | if chainTip.String() != blockHeaderVerboseNew.Hash { 49 | lastHeight, err := r.recursionGetLastHeight(height) 50 | if err == nil { 51 | height = lastHeight 52 | } 53 | } 54 | 55 | return height, nil 56 | } 57 | 58 | func (r *Relayer) recursionGetLastHeight(height int64) (int64, error) { 59 | for { 60 | blockHash, err := r.btcExecutor.GetClient().GetBlockHash(height) 61 | if err != nil { 62 | return height, err 63 | } 64 | 65 | relayed, err := r.coreExecutor.CheckBlockRelayed(blockHash) 66 | if err != nil { 67 | return height, err 68 | } 69 | 70 | if relayed { 71 | return height, nil 72 | } 73 | 74 | height -= 1 75 | } 76 | } 77 | 78 | func (r *Relayer) recursionUnCommitTasks(height int64, lastBlockHash *chainhash.Hash) (*common.TaskSet, error) { 79 | var taskSet common.TaskSet 80 | 81 | //get HighestHeight block hash 82 | blockHash, err := r.btcExecutor.GetClient().GetBlockHash(r.btcExecutor.HighestHeight) 83 | if err != nil { 84 | return nil, fmt.Errorf("error") 85 | } 86 | 87 | for { 88 | if blockHash.IsEqual(lastBlockHash) { 89 | break 90 | } 91 | 92 | //check if this block is relayed 93 | relayed, err := r.CheckBlockRelayed(blockHash) 94 | if err != nil { 95 | return nil, fmt.Errorf("error") 96 | } 97 | 98 | if relayed { 99 | break 100 | } 101 | 102 | //get block 103 | block, err := r.btcExecutor.GetClient().GetBlock(blockHash) 104 | 105 | json, _ := json.Marshal(block) 106 | print(json) 107 | 108 | if err != nil { 109 | break 110 | } 111 | 112 | //new block 113 | task := common.Task{ 114 | Height: height, 115 | BlockHash: blockHash, 116 | BLOCK: block, 117 | } 118 | 119 | //append to head 120 | taskSet.TaskList = append([]common.Task{task}, taskSet.TaskList...) 121 | 122 | if r.cfg.CrossChainConfig.RecursionHeight > 0 && int64(len(taskSet.TaskList)) >= r.cfg.CrossChainConfig.RecursionHeight { 123 | break 124 | } 125 | 126 | //get pre block hash 127 | blockHash = &block.Header.PrevBlock 128 | //Genesis Block 129 | if blockHash.IsEqual(&ZERO_HASH) { 130 | break 131 | } 132 | 133 | height-- 134 | } 135 | 136 | return &taskSet, nil 137 | } 138 | 139 | func (r *Relayer) RelayerCompetitionDaemon() { 140 | 141 | //var err error 142 | common.Logger.Info("Start relayer daemon") 143 | 144 | for { 145 | //no new block, sleep 146 | if r.btcExecutor.HighestHeight == (int64(0)) { 147 | time.Sleep(time.Second) 148 | continue 149 | } 150 | 151 | lastRelayHeight, err := r.getLastRelayHeight() 152 | 153 | if err != nil { 154 | continue 155 | } 156 | 157 | //no new block, sleep 1s 158 | if lastRelayHeight == r.btcExecutor.HighestHeight { 159 | common.Logger.Infof("no new block, current height:" + executor.Int64ToString(lastRelayHeight)) 160 | time.Sleep(1 * time.Second) 161 | continue 162 | } 163 | 164 | common.Logger.Infof("find last relayed height:" + executor.Int64ToString(lastRelayHeight)) 165 | 166 | for i := lastRelayHeight + 1; i <= r.btcExecutor.HighestHeight; { 167 | common.Logger.Infof("start relaying, height:" + executor.Int64ToString(i)) 168 | 169 | _, err := r.DoRelayWithHeight(i) 170 | if err == nil { 171 | common.Logger.Infof("successfully relayed, height:" + executor.Int64ToString(i)) 172 | i++ 173 | continue 174 | } else { 175 | time.Sleep(3 * time.Second) 176 | common.Logger.Infof("relay failed, height:"+executor.Int64ToString(i), err) 177 | } 178 | } 179 | } 180 | } 181 | 182 | /** 183 | do relay 184 | */ 185 | func (r *Relayer) DoRelayWithHeight(blockHeight int64) (bool, error) { 186 | blockHash, err := r.btcExecutor.GetClient().GetBlockHash(blockHeight) 187 | if err != nil { 188 | return false, err 189 | } 190 | 191 | //check if this block is relayed 192 | relayed, err := r.CheckBlockRelayed(blockHash) 193 | if err != nil { 194 | return false, err 195 | } 196 | 197 | if relayed { 198 | common.Logger.Infof("block is relayed, height:" + executor.Int64ToString(blockHeight)) 199 | return true, nil 200 | } 201 | 202 | //get block 203 | block, err := r.btcExecutor.GetClient().GetBlock(blockHash) 204 | 205 | if err != nil { 206 | return false, err 207 | } 208 | 209 | //new block 210 | task := common.Task{ 211 | Height: blockHeight, 212 | BlockHash: blockHash, 213 | BLOCK: block, 214 | } 215 | 216 | err = r.doRelay(&task) 217 | 218 | return err == nil, err 219 | } 220 | func (r *Relayer) doRelay(task *common.Task) error { 221 | _, err := r.coreExecutor.SyncBTCLightMirror(task) 222 | 223 | return err 224 | } 225 | 226 | func (r *Relayer) CheckBlockRelayed(blockHash *chainhash.Hash) (bool, error) { 227 | //check if this block if relayed 228 | checkResult, err := r.coreExecutor.CheckBlockRelayed(blockHash) 229 | if err != nil { 230 | return true, fmt.Errorf("error") 231 | } 232 | 233 | return checkResult, nil 234 | } 235 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2022 Core 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /executor/core_executor.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "crypto/ecdsa" 7 | "fmt" 8 | "log" 9 | "math/big" 10 | "strconv" 11 | "sync" 12 | "time" 13 | 14 | "github.com/btcsuite/btcd/chaincfg/chainhash" 15 | cgccaller "github.com/coredao-org/btc-relayer/executor/cc" 16 | "github.com/coredao-org/btcpowermirror/lightmirror" 17 | "github.com/ethereum/go-ethereum" 18 | "github.com/ethereum/go-ethereum/rpc" 19 | 20 | brcommon "github.com/coredao-org/btc-relayer/common" 21 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 22 | "github.com/ethereum/go-ethereum/common" 23 | "github.com/ethereum/go-ethereum/core/types" 24 | "github.com/ethereum/go-ethereum/crypto" 25 | "github.com/ethereum/go-ethereum/ethclient" 26 | 27 | "github.com/jinzhu/gorm" 28 | 29 | relayercommon "github.com/coredao-org/btc-relayer/common" 30 | config "github.com/coredao-org/btc-relayer/config" 31 | "github.com/coredao-org/btc-relayer/executor/relayerhub" 32 | ) 33 | 34 | type COREClient struct { 35 | COREClient *ethclient.Client 36 | Provider string 37 | CurrentHeight int64 38 | UpdatedAt time.Time 39 | } 40 | 41 | type COREExecutor struct { 42 | mutex sync.RWMutex 43 | db *gorm.DB 44 | btcExecutor *BTCExecutor 45 | clientIdx int 46 | coreClients []*COREClient 47 | privateKey *ecdsa.PrivateKey 48 | txSender common.Address 49 | cfg *config.Config 50 | } 51 | 52 | func getPrivateKey(cfg *config.COREConfig) (*ecdsa.PrivateKey, error) { 53 | var privateKey string 54 | 55 | privateKey = cfg.PrivateKey 56 | 57 | privKey, err := crypto.HexToECDSA(privateKey) 58 | if err != nil { 59 | return nil, err 60 | } 61 | return privKey, nil 62 | } 63 | 64 | func initClients(providers []string) []*COREClient { 65 | clients := make([]*COREClient, 0) 66 | 67 | for _, provider := range providers { 68 | client, err := ethclient.Dial(provider) 69 | if err != nil { 70 | panic("new eth client error") 71 | } 72 | clients = append(clients, &COREClient{ 73 | COREClient: client, 74 | Provider: provider, 75 | UpdatedAt: time.Now(), 76 | }) 77 | } 78 | 79 | return clients 80 | } 81 | 82 | func NewCOREExecutor(cfg *config.Config) (*COREExecutor, error) { 83 | privKey, err := getPrivateKey(&cfg.COREConfig) 84 | if err != nil { 85 | return nil, err 86 | } 87 | publicKey := privKey.Public() 88 | publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) 89 | if !ok { 90 | return nil, fmt.Errorf("get public key error") 91 | } 92 | txSender := crypto.PubkeyToAddress(*publicKeyECDSA) 93 | 94 | return &COREExecutor{ 95 | db: nil, 96 | btcExecutor: nil, 97 | clientIdx: 0, 98 | coreClients: initClients(cfg.COREConfig.Providers), 99 | privateKey: privKey, 100 | txSender: txSender, 101 | cfg: cfg, 102 | }, nil 103 | } 104 | 105 | func (executor *COREExecutor) GetClient() *ethclient.Client { 106 | executor.mutex.RLock() 107 | defer executor.mutex.RUnlock() 108 | return executor.coreClients[executor.clientIdx].COREClient 109 | } 110 | 111 | func (executor *COREExecutor) SwitchCOREClient() { 112 | executor.mutex.Lock() 113 | defer executor.mutex.Unlock() 114 | executor.clientIdx++ 115 | if executor.clientIdx >= len(executor.coreClients) { 116 | executor.clientIdx = 0 117 | } 118 | relayercommon.Logger.Infof("Switch to provider: %s", executor.cfg.COREConfig.Providers[executor.clientIdx]) 119 | } 120 | 121 | func (executor *COREExecutor) GetLatestBlockHeight(client *ethclient.Client) (int64, error) { 122 | ctxWithTimeout, cancel := context.WithTimeout(context.Background(), 5*time.Second) 123 | defer cancel() 124 | 125 | block, err := client.BlockByNumber(ctxWithTimeout, nil) 126 | if err != nil { 127 | return 0, err 128 | } 129 | return block.Number().Int64(), nil 130 | } 131 | 132 | func (executor *COREExecutor) UpdateClients() { 133 | for { 134 | for _, client := range executor.coreClients { 135 | if time.Since(client.UpdatedAt).Seconds() > executor.cfg.COREConfig.DataSeedDenyServiceThreshold { 136 | msg := fmt.Sprintf("data seed %s is not accessible", client.Provider) 137 | relayercommon.Logger.Error(msg) 138 | config.SendTelegramMessage(executor.cfg.AlertConfig.Identity, executor.cfg.AlertConfig.TelegramBotId, executor.cfg.AlertConfig.TelegramChatId, msg) 139 | } 140 | height, err := executor.GetLatestBlockHeight(client.COREClient) 141 | if err != nil { 142 | relayercommon.Logger.Errorf("get latest block height error, err=%s", err.Error()) 143 | continue 144 | } 145 | client.CurrentHeight = height 146 | client.UpdatedAt = time.Now() 147 | } 148 | //relayercommon.Logger.Infof("Start to monitor core data-seeds health") 149 | 150 | highestHeight := int64(0) 151 | highestIdx := 0 152 | for idx := 0; idx < len(executor.coreClients); idx++ { 153 | if executor.coreClients[idx].CurrentHeight > highestHeight { 154 | highestHeight = executor.coreClients[idx].CurrentHeight 155 | highestIdx = idx 156 | } 157 | } 158 | 159 | if executor.coreClients[executor.clientIdx].CurrentHeight+FallBehindThreshold < highestHeight { 160 | executor.mutex.Lock() 161 | executor.clientIdx = highestIdx 162 | executor.mutex.Unlock() 163 | } 164 | time.Sleep(time.Duration(executor.cfg.COREConfig.SleepSecond) * time.Second) 165 | } 166 | } 167 | 168 | func (executor *COREExecutor) getTransactor(nonce uint64) (*bind.TransactOpts, error) { 169 | chainId, err := executor.GetClient().ChainID(context.Background()) 170 | if err != nil { 171 | return nil, nil 172 | } 173 | 174 | txOpts, err := bind.NewKeyedTransactorWithChainID(executor.privateKey, chainId) 175 | txOpts.Nonce = big.NewInt(int64(nonce)) 176 | txOpts.Value = big.NewInt(0) 177 | txOpts.GasLimit = executor.cfg.COREConfig.GasLimit 178 | if executor.cfg.COREConfig.GasPrice == 0 { 179 | txOpts.GasPrice = big.NewInt(DefaultGasPrice) 180 | } else { 181 | txOpts.GasPrice = big.NewInt(int64(executor.cfg.COREConfig.GasPrice)) 182 | } 183 | return txOpts, nil 184 | } 185 | 186 | func (executor *COREExecutor) GetChainTip() (*chainhash.Hash, error) { 187 | callOpts, err := executor.getCallOpts() 188 | instance, err := cgccaller.NewCGCCaller(pcsAddr, executor.GetClient()) 189 | chainTip, err := instance.GetChainTip(callOpts) 190 | 191 | return chainTip, err 192 | } 193 | 194 | func (executor *COREExecutor) getCallOpts() (*bind.CallOpts, error) { 195 | callOpts := &bind.CallOpts{ 196 | Pending: true, 197 | Context: context.Background(), 198 | } 199 | return callOpts, nil 200 | } 201 | 202 | /** 203 | sync BTCLightMirror 204 | */ 205 | func (executor *COREExecutor) SyncBTCLightMirror(task *relayercommon.Task) (common.Hash, error) { 206 | nonce, err := executor.GetClient().PendingNonceAt(context.Background(), executor.txSender) 207 | if err != nil { 208 | return common.Hash{}, err 209 | } 210 | txOpts, err := executor.getTransactor(nonce) 211 | if err != nil && txOpts != nil { 212 | return common.Hash{}, err 213 | } 214 | 215 | mirror := NewBtcLightMirror(task.BLOCK) 216 | 217 | for { 218 | txHash, err := executor.syncBtcHeader(mirror, task.BlockHash) 219 | if err != nil { 220 | return common.Hash{}, err 221 | } 222 | 223 | brcommon.Logger.Infof("submit transaction, blockHash:" + task.BlockHash.String() + " height:" + Int64ToString(task.Height) + ",txHash:" + txHash.String() + ", start to check relaying result") 224 | 225 | relayed, retry, err := executor.CheckSuccessRelayed(task.BlockHash, txHash) 226 | 227 | if relayed || !retry { 228 | return common.Hash{}, err 229 | } 230 | 231 | if retry { 232 | executor.IncreaseGas() 233 | } 234 | 235 | } 236 | 237 | return common.Hash{}, err 238 | } 239 | 240 | /** 241 | increase gas 242 | */ 243 | func (executor *COREExecutor) IncreaseGas() { 244 | executor.cfg.COREConfig.GasLimit += executor.cfg.COREConfig.GasIncrease 245 | brcommon.Logger.Infof("gas not enough, increase gas to:" + strconv.FormatUint(executor.cfg.COREConfig.GasLimit, 10)) 246 | } 247 | 248 | /** 249 | check if btc block is successfully relayed 250 | return bool:relayed success bool:retry 251 | */ 252 | func (executor *COREExecutor) CheckSuccessRelayed(btcBlockHash *chainhash.Hash, coreTxHash common.Hash) (bool, bool, error) { 253 | 254 | for { 255 | //CheckBlockRelayed 256 | relayed, err := executor.CheckBlockRelayed(btcBlockHash) 257 | if err == nil && relayed { 258 | submitter, err := executor.QuerySubmitters(btcBlockHash) 259 | if err == nil && submitter != "" { 260 | brcommon.Logger.Infof("successful, relayed by:[" + submitter + "]") 261 | } else { 262 | brcommon.Logger.Infof("successful") 263 | } 264 | return true, false, nil 265 | } 266 | 267 | //Check TX 268 | txRecipient, err := executor.GetTxRecipient(coreTxHash) 269 | 270 | //failed, get revert reason 271 | if err == nil { 272 | if txRecipient.Status == 0 { 273 | tx, _, err := executor.TransactionByHash(coreTxHash) 274 | if err == nil { 275 | 276 | //out of gas 277 | if tx.Gas() == txRecipient.GasUsed { 278 | brcommon.Logger.Infof("out of gas, retry") 279 | return false, true, nil 280 | } 281 | brcommon.Logger.Infof("failed") 282 | return false, false, fmt.Errorf("tx failed") 283 | } 284 | } 285 | } 286 | 287 | relayercommon.Logger.Infof("relaying, continue to check") 288 | time.Sleep(time.Duration(500) * time.Millisecond) 289 | } 290 | 291 | } 292 | 293 | func serializeBtcLightMirror(mirror *lightmirror.BtcLightMirrorV2) ([]byte, error) { 294 | var b bytes.Buffer 295 | mirror.Serialize(&b) 296 | bb := b.Bytes() 297 | 298 | return bb, nil 299 | } 300 | 301 | func (executor *COREExecutor) IsRelayer() (bool, error) { 302 | instance, err := relayerhub.NewRelayerhub(relayerHubContractAddr, executor.GetClient()) 303 | if err != nil { 304 | return false, err 305 | } 306 | 307 | callOpts, err := executor.getCallOpts() 308 | if err != nil { 309 | return false, err 310 | } 311 | 312 | isRelayer, err := instance.IsRelayer(callOpts, executor.txSender) 313 | if err != nil { 314 | return false, err 315 | } 316 | return isRelayer, nil 317 | } 318 | 319 | func (executor *COREExecutor) RegisterRelayer() (common.Hash, error) { 320 | nonce, err := executor.GetClient().PendingNonceAt(context.Background(), executor.txSender) 321 | if err != nil { 322 | return common.Hash{}, err 323 | } 324 | txOpts, err := executor.getTransactor(nonce) 325 | if err != nil { 326 | return common.Hash{}, err 327 | } 328 | 329 | instance, err := relayerhub.NewRelayerhub(relayerHubContractAddr, executor.GetClient()) 330 | if err != nil { 331 | return common.Hash{}, err 332 | } 333 | 334 | txOpts.Value = big.NewInt(1).Mul(big.NewInt(100), big.NewInt(1e18)) //100 Core 335 | tx, err := instance.Register(txOpts) 336 | if err != nil { 337 | return common.Hash{}, err 338 | } 339 | return tx.Hash(), nil 340 | } 341 | 342 | func (executor *COREExecutor) EthCall(tx *types.Transaction, blockNumber *big.Int) ([]byte, error) { 343 | msg := ethereum.CallMsg{ 344 | From: executor.txSender, 345 | To: tx.To(), 346 | GasPrice: tx.GasPrice(), 347 | Gas: tx.Gas(), 348 | //GasTipCap: tx.GasTipCap(), 349 | //GasFeeCap: tx.GasFeeCap(), 350 | Value: tx.Value(), 351 | Data: tx.Data(), 352 | } 353 | return executor.GetClient().CallContract(context.Background(), msg, blockNumber) 354 | } 355 | 356 | func (executor *COREExecutor) TransactionByHash(txHash common.Hash) (*types.Transaction, bool, error) { 357 | return executor.GetClient().TransactionByHash(context.Background(), txHash) 358 | } 359 | 360 | func (executor *COREExecutor) GetTxRecipient(txHash common.Hash) (*types.Receipt, error) { 361 | return executor.GetClient().TransactionReceipt(context.Background(), txHash) 362 | } 363 | 364 | func (executor *COREExecutor) GetRelayerBalance() (*big.Int, error) { 365 | return executor.GetClient().BalanceAt(context.Background(), executor.txSender, nil) 366 | } 367 | 368 | func (executor *COREExecutor) CheckBlockRelayed(blockHash *chainhash.Hash) (bool, error) { 369 | 370 | bHash := RevertHash(blockHash) 371 | 372 | callOpts, err := executor.getCallOpts() 373 | instance, err := cgccaller.NewCGCCaller(pcsAddr, executor.GetClient()) 374 | result, err := instance.IsHeaderSynced(callOpts, bHash) 375 | //_, err := executor.CallContext(executor.GetClient(), result, context.Background(), "isHeaderSynced", blockHash) 376 | 377 | return result, err 378 | } 379 | 380 | func (executor *COREExecutor) QuerySubmitters(blockHash *chainhash.Hash) (string, error) { 381 | 382 | bHash := RevertHash(blockHash) 383 | 384 | callOpts, err := executor.getCallOpts() 385 | instance, err := cgccaller.NewCGCCaller(pcsAddr, executor.GetClient()) 386 | result, err := instance.QuerySubmitters(callOpts, bHash) 387 | 388 | return result, err 389 | } 390 | 391 | func (executor *COREExecutor) syncBtcHeader(btcLightMirror *lightmirror.BtcLightMirrorV2, blockHash *chainhash.Hash) (common.Hash, error) { 392 | nonce, err := executor.GetClient().PendingNonceAt(context.Background(), executor.txSender) 393 | callOpts, err := executor.getTransactor(nonce) 394 | 395 | instance, err := cgccaller.NewCGCCaller(pcsAddr, executor.GetClient()) 396 | 397 | bts, err := serializeBtcLightMirror(btcLightMirror) 398 | txHash, err := instance.SyncBtcHeader(callOpts, bts) 399 | 400 | if err != nil { 401 | log.Println("sync btc header failed, hash:" + blockHash.String()) 402 | } 403 | 404 | return txHash, err 405 | } 406 | 407 | // callContext 408 | func (executor *COREExecutor) CallContext(ec *ethclient.Client, result interface{}, ctx context.Context, method string, args ...interface{}) (interface{}, error) { 409 | client := relayercommon.ReflectField(ec, "c").Elem().Interface().(*rpc.Client) 410 | err := client.CallContext(ctx, &result, method, args) 411 | if err != nil { 412 | return nil, err 413 | } 414 | return result, err 415 | } 416 | -------------------------------------------------------------------------------- /executor/cc/cgccaller.go: -------------------------------------------------------------------------------- 1 | // Code generated - DO NOT EDIT. 2 | // This file is a generated binding and any manual changes will be lost. 3 | 4 | package cgccaller 5 | 6 | import ( 7 | "fmt" 8 | "github.com/btcsuite/btcd/chaincfg/chainhash" 9 | "math/big" 10 | "strconv" 11 | "strings" 12 | 13 | ethereum "github.com/ethereum/go-ethereum" 14 | "github.com/ethereum/go-ethereum/accounts/abi" 15 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 16 | "github.com/ethereum/go-ethereum/common" 17 | "github.com/ethereum/go-ethereum/core/types" 18 | "github.com/ethereum/go-ethereum/event" 19 | ) 20 | 21 | // Reference imports to suppress errors if they are not otherwise used. 22 | var ( 23 | _ = big.NewInt 24 | _ = strings.NewReader 25 | _ = ethereum.NotFound 26 | _ = abi.MaxUint256 27 | _ = bind.Bind 28 | _ = common.Big1 29 | _ = types.BloomLookup 30 | _ = event.NewSubscription 31 | ) 32 | 33 | // CGCABI is the core-genesis-cotract input ABI used to generate the binding from. 34 | const CGCABI = "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"int256\",\"name\":\"returnCode\",\"type\":\"int256\"}],\"name\":\"StoreHeader\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"initHeight\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"appHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coinbaseAddr\",\"type\":\"address\"}],\"name\":\"initBlock\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"value\",\"type\":\"bytes\"}],\"name\":\"paramChange\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANDIDATE_HUB_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"CODE_OK\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DIFFICULTY_ADJUSTMENT_INTERVAL\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERROR_FAIL_DECODE\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERR_BLOCK_ALREADY_EXISTS\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERR_DIFFICULTY\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERR_MERKLE\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERR_NO_PREV_BLOCK\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERR_PROOF_OF_WORK\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERR_RETARGET\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOV_HUB_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INIT_CHAIN_HEIGHT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INIT_CONSENSUS_STATE_BYTES\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INIT_REWARD_FOR_SYNC_HEADER\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LIGHT_CLIENT_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_HUB_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SLASH_CONTRACT_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SYSTEM_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SYSTEM_REWARD_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TARGET_TIMESPAN\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TARGET_TIMESPAN_DIV_4\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TARGET_TIMESPAN_MUL_4\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TESTNET3_POW_LIMIT\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UNROUNDED_MAX_TARGET\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VALIDATOR_CONTRACT_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"name\":\"adjustmentHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"alreadyInit\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"blockChain\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getAdjustmentHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getAdjustmentIndex\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getBits\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainTip\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getCoinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getHeight\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getPrevHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"preroundTailHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"roundTimestamp\",\"type\":\"uint64\"}],\"name\":\"getRoundPower\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"miners\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"newRoundTailHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getScore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"appHash\",\"type\":\"bytes32\"}],\"name\":\"getSubmitter\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getTimestamp\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"heaviestBlock\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"highScore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initAdjustment\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"appHash\",\"type\":\"bytes32\"}],\"name\":\"isHeaderSynced\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardForSyncHeader\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"blockBytes\",\"type\":\"bytes\"}],\"name\":\"storeBlockHeader\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"submitters\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"valAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"slashAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rewardAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"lightAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"relayerHubAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"candidateHubAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"govHub\",\"type\":\"address\"}],\"name\":\"updateContractAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"value\",\"type\":\"bytes\"}],\"name\":\"updateParam\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" 35 | 36 | // CGCCaller is an auto generated read-only Go binding around an Ethereum contract. 37 | type CGCCaller struct { 38 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 39 | } 40 | 41 | // NewCGC creates a new instance of CGC, bound to a specific deployed contract. 42 | func NewCGCCaller(address common.Address, backend bind.ContractBackend) (*CGCCaller, error) { 43 | contract, err := bindCGCCaller(address, backend, backend, backend) 44 | if err != nil { 45 | return nil, err 46 | } 47 | return &CGCCaller{contract: contract}, nil 48 | } 49 | 50 | // bindCGCCaller binds a generic wrapper to an already deployed contract. 51 | func bindCGCCaller(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { 52 | parsed, err := abi.JSON(strings.NewReader(CGCABI)) 53 | if err != nil { 54 | return nil, err 55 | } 56 | return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil 57 | } 58 | 59 | /** 60 | relayed btc block 61 | */ 62 | func (_CGC *CGCCaller) SyncBtcHeader(opts *bind.TransactOpts, lightClient []byte) (common.Hash, error) { 63 | out, err := _CGC.contract.Transact(opts, "storeBlockHeader", lightClient) 64 | if err != nil { 65 | return common.Hash{}, err 66 | } 67 | return out.Hash(), err 68 | } 69 | 70 | /** 71 | check whether the block is relayed 72 | */ 73 | func (_CGC *CGCCaller) IsHeaderSynced(opts *bind.CallOpts, appHash *chainhash.Hash) (bool, error) { 74 | retval := make([]interface{}, 0, 1) 75 | err := _CGC.contract.Call(opts, &retval, "isHeaderSynced", appHash) 76 | if err != nil { 77 | return false, err 78 | } 79 | 80 | ret0, err := strconv.ParseBool(fmt.Sprint(retval[0])) 81 | return ret0, err 82 | } 83 | 84 | /** 85 | query the last relayed block hash 86 | */ 87 | func (_CGC *CGCCaller) GetChainTip(opts *bind.CallOpts) (*chainhash.Hash, error) { 88 | retval := make([]interface{}, 0, 1) 89 | 90 | err := _CGC.contract.Call(opts, &retval, "getChainTip") 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | bts := retval[0].([32]byte) 96 | chainTip := chainhash.Hash{} 97 | err = chainTip.SetBytes(bts[:]) 98 | 99 | return &chainTip, err 100 | } 101 | 102 | /** 103 | query who submitted the block 104 | */ 105 | func (_CGC *CGCCaller) QuerySubmitters(opts *bind.CallOpts, appHash *chainhash.Hash) (string, error) { 106 | retval := make([]interface{}, 0, 1) 107 | err := _CGC.contract.Call(opts, &retval, "submitters", appHash) 108 | if err != nil { 109 | return "", err 110 | } 111 | 112 | ret0 := fmt.Sprint(retval[0]) 113 | return ret0, nil 114 | } 115 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= 2 | github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 3 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= 4 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= 5 | github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= 6 | github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= 7 | github.com/aws/aws-sdk-go v1.27.0 h1:0xphMHGMLBrPMfxR2AmVjZKcMEESEgWF8Kru94BNByk= 8 | github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 9 | github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= 10 | github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= 11 | github.com/btcsuite/btcd v0.23.1 h1:IB8cVQcC2X5mHbnfirLG5IZnkWYNTPlLZVrxUYSotbE= 12 | github.com/btcsuite/btcd v0.23.1/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= 13 | github.com/btcsuite/btcd v0.23.2 h1:/YOgUp25sdCnP5ho6Hl3s0E438zlX+Kak7E6TgBgoT0= 14 | github.com/btcsuite/btcd v0.23.2/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= 15 | github.com/btcsuite/btcd v0.23.3 h1:4KH/JKy9WiCd+iUS9Mu0Zp7Dnj17TGdKrg9xc/FGj24= 16 | github.com/btcsuite/btcd v0.23.3/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= 17 | github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= 18 | github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= 19 | github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= 20 | github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= 21 | github.com/btcsuite/btcd/btcutil v1.1.0 h1:MO4klnGY+EWJdoWF12Wkuf4AWDBPMpZNeN/jRLrklUU= 22 | github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= 23 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= 24 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= 25 | github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= 26 | github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= 27 | github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= 28 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= 29 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= 30 | github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= 31 | github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= 32 | github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= 33 | github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= 34 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= 35 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= 36 | github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= 37 | github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= 38 | github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= 39 | github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= 40 | github.com/coredao-org/btcpowermirror v1.0.1 h1:4WgHIquehfjiSzIR1QJxgpM49P8KCgFuhR/E0NN9o4k= 41 | github.com/coredao-org/btcpowermirror v1.0.1/go.mod h1:D5HxwSmC7PIRF8ohZX+lcNLxq/eAhHYA3Ot1nemd228= 42 | github.com/coredao-org/btcpowermirror v1.1.0 h1:69g1s0kUo3NNLx9cHSCgLQxrwCH5drtmlqyFv6Tu+zw= 43 | github.com/coredao-org/btcpowermirror v1.1.0/go.mod h1:D5HxwSmC7PIRF8ohZX+lcNLxq/eAhHYA3Ot1nemd228= 44 | github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= 45 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 46 | github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 47 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 48 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 49 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 50 | github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= 51 | github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= 52 | github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= 53 | github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= 54 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= 55 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= 56 | github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= 57 | github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= 58 | github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= 59 | github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= 60 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= 61 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= 62 | github.com/ethereum/go-ethereum v1.10.20 h1:75IW830ClSS40yrQC1ZCMZCt5I+zU16oqId2SiQwdQ4= 63 | github.com/ethereum/go-ethereum v1.10.20/go.mod h1:LWUN82TCHGpxB3En5HVmLLzPD7YSrEUFmFfN1nKkVN0= 64 | github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= 65 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 66 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 67 | github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= 68 | github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= 69 | github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= 70 | github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= 71 | github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= 72 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 73 | github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= 74 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 75 | github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= 76 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= 77 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 78 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 79 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 80 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 81 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 82 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 83 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 84 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 85 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 86 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 87 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 88 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 89 | github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= 90 | github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 91 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 92 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 93 | github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= 94 | github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= 95 | github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= 96 | github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= 97 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 98 | github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= 99 | github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= 100 | github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 101 | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 102 | github.com/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w= 103 | github.com/jinzhu/copier v0.3.2/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= 104 | github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= 105 | github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= 106 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 107 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 108 | github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= 109 | github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 110 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= 111 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 112 | github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= 113 | github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= 114 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 115 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 116 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 117 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 118 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 119 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 120 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 121 | github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= 122 | github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 123 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= 124 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 125 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 126 | github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= 127 | github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 128 | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= 129 | github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= 130 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 131 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 132 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 133 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 134 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 135 | github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= 136 | github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 137 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 138 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 139 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 140 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= 141 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= 142 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 143 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 144 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 145 | github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= 146 | github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= 147 | github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= 148 | github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= 149 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 150 | github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= 151 | github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= 152 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= 153 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 154 | github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= 155 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 156 | github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 h1:Oo2KZNP70KE0+IUJSidPj/BFS/RXNHmKIJOdckzml2E= 157 | github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= 158 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 159 | github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= 160 | github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= 161 | github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= 162 | github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= 163 | github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= 164 | github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= 165 | github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= 166 | github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= 167 | github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y= 168 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= 169 | golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 170 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 171 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 172 | golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 173 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 174 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= 175 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 176 | golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 177 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 178 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 179 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 180 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 181 | golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 182 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 183 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= 184 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 185 | golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 186 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 187 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 188 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 189 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 190 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 191 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 192 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 193 | golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 194 | golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 195 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= 196 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 197 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 198 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 199 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 200 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 201 | golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= 202 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 203 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 204 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 205 | google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= 206 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 207 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 208 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 209 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 210 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 211 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 212 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 213 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 214 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 215 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 216 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 217 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 218 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= 219 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 220 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= 221 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= 222 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 223 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 224 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 225 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 226 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 227 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 228 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 229 | -------------------------------------------------------------------------------- /executor/relayerhub/relayerhub.go: -------------------------------------------------------------------------------- 1 | // Code generated - DO NOT EDIT. 2 | // This file is a generated binding and any manual changes will be lost. 3 | 4 | package relayerhub 5 | 6 | import ( 7 | "fmt" 8 | "math/big" 9 | "strconv" 10 | "strings" 11 | 12 | ethereum "github.com/ethereum/go-ethereum" 13 | "github.com/ethereum/go-ethereum/accounts/abi" 14 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 15 | "github.com/ethereum/go-ethereum/common" 16 | "github.com/ethereum/go-ethereum/core/types" 17 | "github.com/ethereum/go-ethereum/event" 18 | ) 19 | 20 | // Reference imports to suppress errors if they are not otherwise used. 21 | var ( 22 | _ = big.NewInt 23 | _ = strings.NewReader 24 | _ = ethereum.NotFound 25 | _ = abi.MaxUint256 26 | _ = bind.Bind 27 | _ = common.Big1 28 | _ = types.BloomLookup 29 | _ = event.NewSubscription 30 | ) 31 | 32 | // RelayerhubABI is the input ABI used to generate the binding from. 33 | const RelayerhubABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"value\",\"type\":\"bytes\"}],\"name\":\"paramChange\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_relayer\",\"type\":\"address\"}],\"name\":\"relayerRegister\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_relayer\",\"type\":\"address\"}],\"name\":\"relayerUnRegister\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANDIDATE_HUB_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"CODE_OK\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERROR_FAIL_DECODE\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOV_HUB_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INIT_DUES\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INIT_REQUIRED_DEPOSIT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LIGHT_CLIENT_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PLEDGE_AGENT_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_HUB_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SLASH_CONTRACT_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SYSTEM_REWARD_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VALIDATOR_CONTRACT_ADDR\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"alreadyInit\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dues\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isRelayer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requiredDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unregister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"value\",\"type\":\"bytes\"}],\"name\":\"updateParam\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" 34 | 35 | // Relayerhub is an auto generated Go binding around an Ethereum contract. 36 | type Relayerhub struct { 37 | RelayerhubCaller // Read-only binding to the contract 38 | RelayerhubTransactor // Write-only binding to the contract 39 | RelayerhubFilterer // Log filterer for contract events 40 | } 41 | 42 | // RelayerhubCaller is an auto generated read-only Go binding around an Ethereum contract. 43 | type RelayerhubCaller struct { 44 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 45 | } 46 | 47 | // RelayerhubTransactor is an auto generated write-only Go binding around an Ethereum contract. 48 | type RelayerhubTransactor struct { 49 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 50 | } 51 | 52 | // RelayerhubFilterer is an auto generated log filtering Go binding around an Ethereum contract events. 53 | type RelayerhubFilterer struct { 54 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 55 | } 56 | 57 | // RelayerhubSession is an auto generated Go binding around an Ethereum contract, 58 | // with pre-set call and transact options. 59 | type RelayerhubSession struct { 60 | Contract *Relayerhub // Generic contract binding to set the session for 61 | CallOpts bind.CallOpts // Call options to use throughout this session 62 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 63 | } 64 | 65 | // RelayerhubCallerSession is an auto generated read-only Go binding around an Ethereum contract, 66 | // with pre-set call options. 67 | type RelayerhubCallerSession struct { 68 | Contract *RelayerhubCaller // Generic contract caller binding to set the session for 69 | CallOpts bind.CallOpts // Call options to use throughout this session 70 | } 71 | 72 | // RelayerhubTransactorSession is an auto generated write-only Go binding around an Ethereum contract, 73 | // with pre-set transact options. 74 | type RelayerhubTransactorSession struct { 75 | Contract *RelayerhubTransactor // Generic contract transactor binding to set the session for 76 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 77 | } 78 | 79 | // RelayerhubRaw is an auto generated low-level Go binding around an Ethereum contract. 80 | type RelayerhubRaw struct { 81 | Contract *Relayerhub // Generic contract binding to access the raw methods on 82 | } 83 | 84 | // RelayerhubCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. 85 | type RelayerhubCallerRaw struct { 86 | Contract *RelayerhubCaller // Generic read-only contract binding to access the raw methods on 87 | } 88 | 89 | // RelayerhubTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. 90 | type RelayerhubTransactorRaw struct { 91 | Contract *RelayerhubTransactor // Generic write-only contract binding to access the raw methods on 92 | } 93 | 94 | // NewRelayerhub creates a new instance of Relayerhub, bound to a specific deployed contract. 95 | func NewRelayerhub(address common.Address, backend bind.ContractBackend) (*Relayerhub, error) { 96 | contract, err := bindRelayerhub(address, backend, backend, backend) 97 | if err != nil { 98 | return nil, err 99 | } 100 | return &Relayerhub{RelayerhubCaller: RelayerhubCaller{contract: contract}, RelayerhubTransactor: RelayerhubTransactor{contract: contract}, RelayerhubFilterer: RelayerhubFilterer{contract: contract}}, nil 101 | } 102 | 103 | // NewRelayerhubCaller creates a new read-only instance of Relayerhub, bound to a specific deployed contract. 104 | func NewRelayerhubCaller(address common.Address, caller bind.ContractCaller) (*RelayerhubCaller, error) { 105 | contract, err := bindRelayerhub(address, caller, nil, nil) 106 | if err != nil { 107 | return nil, err 108 | } 109 | return &RelayerhubCaller{contract: contract}, nil 110 | } 111 | 112 | // NewRelayerhubTransactor creates a new write-only instance of Relayerhub, bound to a specific deployed contract. 113 | func NewRelayerhubTransactor(address common.Address, transactor bind.ContractTransactor) (*RelayerhubTransactor, error) { 114 | contract, err := bindRelayerhub(address, nil, transactor, nil) 115 | if err != nil { 116 | return nil, err 117 | } 118 | return &RelayerhubTransactor{contract: contract}, nil 119 | } 120 | 121 | // NewRelayerhubFilterer creates a new log filterer instance of Relayerhub, bound to a specific deployed contract. 122 | func NewRelayerhubFilterer(address common.Address, filterer bind.ContractFilterer) (*RelayerhubFilterer, error) { 123 | contract, err := bindRelayerhub(address, nil, nil, filterer) 124 | if err != nil { 125 | return nil, err 126 | } 127 | return &RelayerhubFilterer{contract: contract}, nil 128 | } 129 | 130 | // bindRelayerhub binds a generic wrapper to an already deployed contract. 131 | func bindRelayerhub(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { 132 | parsed, err := abi.JSON(strings.NewReader(RelayerhubABI)) 133 | if err != nil { 134 | return nil, err 135 | } 136 | return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil 137 | } 138 | 139 | // Call invokes the (constant) contract method with params as input values and 140 | // sets the output to result. The result type might be a single field for simple 141 | // returns, a slice of interfaces for anonymous returns and a struct for named 142 | // returns. 143 | //func (_Relayerhub *RelayerhubRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { 144 | // return _Relayerhub.Contract.RelayerhubCaller.contract.Call(opts, result, method, params...) 145 | //} 146 | 147 | // Transfer initiates a plain transaction to move funds to the contract, calling 148 | // its default method if one is available. 149 | func (_Relayerhub *RelayerhubRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 150 | return _Relayerhub.Contract.RelayerhubTransactor.contract.Transfer(opts) 151 | } 152 | 153 | // Transact invokes the (paid) contract method with params as input values. 154 | func (_Relayerhub *RelayerhubRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 155 | return _Relayerhub.Contract.RelayerhubTransactor.contract.Transact(opts, method, params...) 156 | } 157 | 158 | // Call invokes the (constant) contract method with params as input values and 159 | // sets the output to result. The result type might be a single field for simple 160 | // returns, a slice of interfaces for anonymous returns and a struct for named 161 | // returns. 162 | //func (_Relayerhub *RelayerhubCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { 163 | // return _Relayerhub.Contract.contract.Call(opts, result, method, params...) 164 | //} 165 | 166 | // Transfer initiates a plain transaction to move funds to the contract, calling 167 | // its default method if one is available. 168 | func (_Relayerhub *RelayerhubTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 169 | return _Relayerhub.Contract.contract.Transfer(opts) 170 | } 171 | 172 | // Transact invokes the (paid) contract method with params as input values. 173 | func (_Relayerhub *RelayerhubTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 174 | return _Relayerhub.Contract.contract.Transact(opts, method, params...) 175 | } 176 | 177 | // IsRelayer is a free data retrieval call binding the contract method 0x541d5548. 178 | // 179 | // Solidity: function isRelayer(address sender) constant returns(bool) 180 | func (_Relayerhub *RelayerhubCaller) IsRelayer(opts *bind.CallOpts, sender common.Address) (bool, error) { 181 | retval := make([]interface{}, 0, 1) 182 | err := _Relayerhub.contract.Call(opts, &retval, "isRelayer", sender) 183 | if err == nil { 184 | ret0, err := strconv.ParseBool(fmt.Sprint(retval[0])) 185 | return ret0, err 186 | } 187 | return false, err 188 | } 189 | 190 | // IsRelayer is a free data retrieval call binding the contract method 0x541d5548. 191 | // 192 | // Solidity: function isRelayer(address sender) constant returns(bool) 193 | func (_Relayerhub *RelayerhubSession) IsRelayer(sender common.Address) (bool, error) { 194 | return _Relayerhub.Contract.IsRelayer(&_Relayerhub.CallOpts, sender) 195 | } 196 | 197 | // IsRelayer is a free data retrieval call binding the contract method 0x541d5548. 198 | // 199 | // Solidity: function isRelayer(address sender) constant returns(bool) 200 | func (_Relayerhub *RelayerhubCallerSession) IsRelayer(sender common.Address) (bool, error) { 201 | return _Relayerhub.Contract.IsRelayer(&_Relayerhub.CallOpts, sender) 202 | } 203 | 204 | // Init is a paid mutator transaction binding the contract method 0xe1c7392a. 205 | // 206 | // Solidity: function init() returns() 207 | func (_Relayerhub *RelayerhubTransactor) Init(opts *bind.TransactOpts) (*types.Transaction, error) { 208 | return _Relayerhub.contract.Transact(opts, "init") 209 | } 210 | 211 | // Init is a paid mutator transaction binding the contract method 0xe1c7392a. 212 | // 213 | // Solidity: function init() returns() 214 | func (_Relayerhub *RelayerhubSession) Init() (*types.Transaction, error) { 215 | return _Relayerhub.Contract.Init(&_Relayerhub.TransactOpts) 216 | } 217 | 218 | // Init is a paid mutator transaction binding the contract method 0xe1c7392a. 219 | // 220 | // Solidity: function init() returns() 221 | func (_Relayerhub *RelayerhubTransactorSession) Init() (*types.Transaction, error) { 222 | return _Relayerhub.Contract.Init(&_Relayerhub.TransactOpts) 223 | } 224 | 225 | // Register is a paid mutator transaction binding the contract method 0x1aa3a008. 226 | // 227 | // Solidity: function register() returns() 228 | func (_Relayerhub *RelayerhubTransactor) Register(opts *bind.TransactOpts) (*types.Transaction, error) { 229 | return _Relayerhub.contract.Transact(opts, "register") 230 | } 231 | 232 | // Register is a paid mutator transaction binding the contract method 0x1aa3a008. 233 | // 234 | // Solidity: function register() returns() 235 | func (_Relayerhub *RelayerhubSession) Register() (*types.Transaction, error) { 236 | return _Relayerhub.Contract.Register(&_Relayerhub.TransactOpts) 237 | } 238 | 239 | // Register is a paid mutator transaction binding the contract method 0x1aa3a008. 240 | // 241 | // Solidity: function register() returns() 242 | func (_Relayerhub *RelayerhubTransactorSession) Register() (*types.Transaction, error) { 243 | return _Relayerhub.Contract.Register(&_Relayerhub.TransactOpts) 244 | } 245 | 246 | // Unregister is a paid mutator transaction binding the contract method 0xe79a198f. 247 | // 248 | // Solidity: function unregister() returns() 249 | func (_Relayerhub *RelayerhubTransactor) Unregister(opts *bind.TransactOpts) (*types.Transaction, error) { 250 | return _Relayerhub.contract.Transact(opts, "unregister") 251 | } 252 | 253 | // Unregister is a paid mutator transaction binding the contract method 0xe79a198f. 254 | // 255 | // Solidity: function unregister() returns() 256 | func (_Relayerhub *RelayerhubSession) Unregister() (*types.Transaction, error) { 257 | return _Relayerhub.Contract.Unregister(&_Relayerhub.TransactOpts) 258 | } 259 | 260 | // Unregister is a paid mutator transaction binding the contract method 0xe79a198f. 261 | // 262 | // Solidity: function unregister() returns() 263 | func (_Relayerhub *RelayerhubTransactorSession) Unregister() (*types.Transaction, error) { 264 | return _Relayerhub.Contract.Unregister(&_Relayerhub.TransactOpts) 265 | } 266 | 267 | // UpdateParam is a paid mutator transaction binding the contract method 0xac431751. 268 | // 269 | // Solidity: function updateParam(string key, bytes value) returns() 270 | func (_Relayerhub *RelayerhubTransactor) UpdateParam(opts *bind.TransactOpts, key string, value []byte) (*types.Transaction, error) { 271 | return _Relayerhub.contract.Transact(opts, "updateParam", key, value) 272 | } 273 | 274 | // UpdateParam is a paid mutator transaction binding the contract method 0xac431751. 275 | // 276 | // Solidity: function updateParam(string key, bytes value) returns() 277 | func (_Relayerhub *RelayerhubSession) UpdateParam(key string, value []byte) (*types.Transaction, error) { 278 | return _Relayerhub.Contract.UpdateParam(&_Relayerhub.TransactOpts, key, value) 279 | } 280 | 281 | // UpdateParam is a paid mutator transaction binding the contract method 0xac431751. 282 | // 283 | // Solidity: function updateParam(string key, bytes value) returns() 284 | func (_Relayerhub *RelayerhubTransactorSession) UpdateParam(key string, value []byte) (*types.Transaction, error) { 285 | return _Relayerhub.Contract.UpdateParam(&_Relayerhub.TransactOpts, key, value) 286 | } 287 | 288 | // RelayerhubParamChangeIterator is returned from FilterParamChange and is used to iterate over the raw logs and unpacked data for ParamChange events raised by the Relayerhub contract. 289 | type RelayerhubParamChangeIterator struct { 290 | Event *RelayerhubParamChange // Event containing the contract specifics and raw log 291 | 292 | contract *bind.BoundContract // Generic contract to use for unpacking event data 293 | event string // Event name to use for unpacking event data 294 | 295 | logs chan types.Log // Log channel receiving the found contract events 296 | sub ethereum.Subscription // Subscription for errors, completion and termination 297 | done bool // Whether the subscription completed delivering logs 298 | fail error // Occurred error to stop iteration 299 | } 300 | 301 | // Next advances the iterator to the subsequent event, returning whether there 302 | // are any more events found. In case of a retrieval or parsing error, false is 303 | // returned and Error() can be queried for the exact failure. 304 | func (it *RelayerhubParamChangeIterator) Next() bool { 305 | // If the iterator failed, stop iterating 306 | if it.fail != nil { 307 | return false 308 | } 309 | // If the iterator completed, deliver directly whatever's available 310 | if it.done { 311 | select { 312 | case log := <-it.logs: 313 | it.Event = new(RelayerhubParamChange) 314 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 315 | it.fail = err 316 | return false 317 | } 318 | it.Event.Raw = log 319 | return true 320 | 321 | default: 322 | return false 323 | } 324 | } 325 | // Iterator still in progress, wait for either a data or an error event 326 | select { 327 | case log := <-it.logs: 328 | it.Event = new(RelayerhubParamChange) 329 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 330 | it.fail = err 331 | return false 332 | } 333 | it.Event.Raw = log 334 | return true 335 | 336 | case err := <-it.sub.Err(): 337 | it.done = true 338 | it.fail = err 339 | return it.Next() 340 | } 341 | } 342 | 343 | // Error returns any retrieval or parsing error occurred during filtering. 344 | func (it *RelayerhubParamChangeIterator) Error() error { 345 | return it.fail 346 | } 347 | 348 | // Close terminates the iteration process, releasing any pending underlying 349 | // resources. 350 | func (it *RelayerhubParamChangeIterator) Close() error { 351 | it.sub.Unsubscribe() 352 | return nil 353 | } 354 | 355 | // RelayerhubParamChange represents a ParamChange event raised by the Relayerhub contract. 356 | type RelayerhubParamChange struct { 357 | Key string 358 | Value []byte 359 | Raw types.Log // Blockchain specific contextual infos 360 | } 361 | 362 | // FilterParamChange is a free log retrieval operation binding the contract event 0x6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a. 363 | // 364 | // Solidity: event paramChange(string key, bytes value) 365 | func (_Relayerhub *RelayerhubFilterer) FilterParamChange(opts *bind.FilterOpts) (*RelayerhubParamChangeIterator, error) { 366 | 367 | logs, sub, err := _Relayerhub.contract.FilterLogs(opts, "paramChange") 368 | if err != nil { 369 | return nil, err 370 | } 371 | return &RelayerhubParamChangeIterator{contract: _Relayerhub.contract, event: "paramChange", logs: logs, sub: sub}, nil 372 | } 373 | 374 | // WatchParamChange is a free log subscription operation binding the contract event 0x6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a. 375 | // 376 | // Solidity: event paramChange(string key, bytes value) 377 | func (_Relayerhub *RelayerhubFilterer) WatchParamChange(opts *bind.WatchOpts, sink chan<- *RelayerhubParamChange) (event.Subscription, error) { 378 | 379 | logs, sub, err := _Relayerhub.contract.WatchLogs(opts, "paramChange") 380 | if err != nil { 381 | return nil, err 382 | } 383 | return event.NewSubscription(func(quit <-chan struct{}) error { 384 | defer sub.Unsubscribe() 385 | for { 386 | select { 387 | case log := <-logs: 388 | // New log arrived, parse the event and forward to the user 389 | event := new(RelayerhubParamChange) 390 | if err := _Relayerhub.contract.UnpackLog(event, "paramChange", log); err != nil { 391 | return err 392 | } 393 | event.Raw = log 394 | 395 | select { 396 | case sink <- event: 397 | case err := <-sub.Err(): 398 | return err 399 | case <-quit: 400 | return nil 401 | } 402 | case err := <-sub.Err(): 403 | return err 404 | case <-quit: 405 | return nil 406 | } 407 | } 408 | }), nil 409 | } 410 | 411 | // ParseParamChange is a log parse operation binding the contract event 0x6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a. 412 | // 413 | // Solidity: event paramChange(string key, bytes value) 414 | func (_Relayerhub *RelayerhubFilterer) ParseParamChange(log types.Log) (*RelayerhubParamChange, error) { 415 | event := new(RelayerhubParamChange) 416 | if err := _Relayerhub.contract.UnpackLog(event, "paramChange", log); err != nil { 417 | return nil, err 418 | } 419 | return event, nil 420 | } 421 | 422 | // RelayerhubRelayerRegisterIterator is returned from FilterRelayerRegister and is used to iterate over the raw logs and unpacked data for RelayerRegister events raised by the Relayerhub contract. 423 | type RelayerhubRelayerRegisterIterator struct { 424 | Event *RelayerhubRelayerRegister // Event containing the contract specifics and raw log 425 | 426 | contract *bind.BoundContract // Generic contract to use for unpacking event data 427 | event string // Event name to use for unpacking event data 428 | 429 | logs chan types.Log // Log channel receiving the found contract events 430 | sub ethereum.Subscription // Subscription for errors, completion and termination 431 | done bool // Whether the subscription completed delivering logs 432 | fail error // Occurred error to stop iteration 433 | } 434 | 435 | // Next advances the iterator to the subsequent event, returning whether there 436 | // are any more events found. In case of a retrieval or parsing error, false is 437 | // returned and Error() can be queried for the exact failure. 438 | func (it *RelayerhubRelayerRegisterIterator) Next() bool { 439 | // If the iterator failed, stop iterating 440 | if it.fail != nil { 441 | return false 442 | } 443 | // If the iterator completed, deliver directly whatever's available 444 | if it.done { 445 | select { 446 | case log := <-it.logs: 447 | it.Event = new(RelayerhubRelayerRegister) 448 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 449 | it.fail = err 450 | return false 451 | } 452 | it.Event.Raw = log 453 | return true 454 | 455 | default: 456 | return false 457 | } 458 | } 459 | // Iterator still in progress, wait for either a data or an error event 460 | select { 461 | case log := <-it.logs: 462 | it.Event = new(RelayerhubRelayerRegister) 463 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 464 | it.fail = err 465 | return false 466 | } 467 | it.Event.Raw = log 468 | return true 469 | 470 | case err := <-it.sub.Err(): 471 | it.done = true 472 | it.fail = err 473 | return it.Next() 474 | } 475 | } 476 | 477 | // Error returns any retrieval or parsing error occurred during filtering. 478 | func (it *RelayerhubRelayerRegisterIterator) Error() error { 479 | return it.fail 480 | } 481 | 482 | // Close terminates the iteration process, releasing any pending underlying 483 | // resources. 484 | func (it *RelayerhubRelayerRegisterIterator) Close() error { 485 | it.sub.Unsubscribe() 486 | return nil 487 | } 488 | 489 | // RelayerhubRelayerRegister represents a RelayerRegister event raised by the Relayerhub contract. 490 | type RelayerhubRelayerRegister struct { 491 | Relayer common.Address 492 | Raw types.Log // Blockchain specific contextual infos 493 | } 494 | 495 | // FilterRelayerRegister is a free log retrieval operation binding the contract event 0xdb33a09d38b59a8fa8b7d92a1d82c8015e99f05f67ae9c9ae623157767959496. 496 | // 497 | // Solidity: event relayerRegister(address _relayer) 498 | func (_Relayerhub *RelayerhubFilterer) FilterRelayerRegister(opts *bind.FilterOpts) (*RelayerhubRelayerRegisterIterator, error) { 499 | 500 | logs, sub, err := _Relayerhub.contract.FilterLogs(opts, "relayerRegister") 501 | if err != nil { 502 | return nil, err 503 | } 504 | return &RelayerhubRelayerRegisterIterator{contract: _Relayerhub.contract, event: "relayerRegister", logs: logs, sub: sub}, nil 505 | } 506 | 507 | // WatchRelayerRegister is a free log subscription operation binding the contract event 0xdb33a09d38b59a8fa8b7d92a1d82c8015e99f05f67ae9c9ae623157767959496. 508 | // 509 | // Solidity: event relayerRegister(address _relayer) 510 | func (_Relayerhub *RelayerhubFilterer) WatchRelayerRegister(opts *bind.WatchOpts, sink chan<- *RelayerhubRelayerRegister) (event.Subscription, error) { 511 | 512 | logs, sub, err := _Relayerhub.contract.WatchLogs(opts, "relayerRegister") 513 | if err != nil { 514 | return nil, err 515 | } 516 | return event.NewSubscription(func(quit <-chan struct{}) error { 517 | defer sub.Unsubscribe() 518 | for { 519 | select { 520 | case log := <-logs: 521 | // New log arrived, parse the event and forward to the user 522 | event := new(RelayerhubRelayerRegister) 523 | if err := _Relayerhub.contract.UnpackLog(event, "relayerRegister", log); err != nil { 524 | return err 525 | } 526 | event.Raw = log 527 | 528 | select { 529 | case sink <- event: 530 | case err := <-sub.Err(): 531 | return err 532 | case <-quit: 533 | return nil 534 | } 535 | case err := <-sub.Err(): 536 | return err 537 | case <-quit: 538 | return nil 539 | } 540 | } 541 | }), nil 542 | } 543 | 544 | // ParseRelayerRegister is a log parse operation binding the contract event 0xdb33a09d38b59a8fa8b7d92a1d82c8015e99f05f67ae9c9ae623157767959496. 545 | // 546 | // Solidity: event relayerRegister(address _relayer) 547 | func (_Relayerhub *RelayerhubFilterer) ParseRelayerRegister(log types.Log) (*RelayerhubRelayerRegister, error) { 548 | event := new(RelayerhubRelayerRegister) 549 | if err := _Relayerhub.contract.UnpackLog(event, "relayerRegister", log); err != nil { 550 | return nil, err 551 | } 552 | return event, nil 553 | } 554 | 555 | // RelayerhubRelayerUnRegisterIterator is returned from FilterRelayerUnRegister and is used to iterate over the raw logs and unpacked data for RelayerUnRegister events raised by the Relayerhub contract. 556 | type RelayerhubRelayerUnRegisterIterator struct { 557 | Event *RelayerhubRelayerUnRegister // Event containing the contract specifics and raw log 558 | 559 | contract *bind.BoundContract // Generic contract to use for unpacking event data 560 | event string // Event name to use for unpacking event data 561 | 562 | logs chan types.Log // Log channel receiving the found contract events 563 | sub ethereum.Subscription // Subscription for errors, completion and termination 564 | done bool // Whether the subscription completed delivering logs 565 | fail error // Occurred error to stop iteration 566 | } 567 | 568 | // Next advances the iterator to the subsequent event, returning whether there 569 | // are any more events found. In case of a retrieval or parsing error, false is 570 | // returned and Error() can be queried for the exact failure. 571 | func (it *RelayerhubRelayerUnRegisterIterator) Next() bool { 572 | // If the iterator failed, stop iterating 573 | if it.fail != nil { 574 | return false 575 | } 576 | // If the iterator completed, deliver directly whatever's available 577 | if it.done { 578 | select { 579 | case log := <-it.logs: 580 | it.Event = new(RelayerhubRelayerUnRegister) 581 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 582 | it.fail = err 583 | return false 584 | } 585 | it.Event.Raw = log 586 | return true 587 | 588 | default: 589 | return false 590 | } 591 | } 592 | // Iterator still in progress, wait for either a data or an error event 593 | select { 594 | case log := <-it.logs: 595 | it.Event = new(RelayerhubRelayerUnRegister) 596 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 597 | it.fail = err 598 | return false 599 | } 600 | it.Event.Raw = log 601 | return true 602 | 603 | case err := <-it.sub.Err(): 604 | it.done = true 605 | it.fail = err 606 | return it.Next() 607 | } 608 | } 609 | 610 | // Error returns any retrieval or parsing error occurred during filtering. 611 | func (it *RelayerhubRelayerUnRegisterIterator) Error() error { 612 | return it.fail 613 | } 614 | 615 | // Close terminates the iteration process, releasing any pending underlying 616 | // resources. 617 | func (it *RelayerhubRelayerUnRegisterIterator) Close() error { 618 | it.sub.Unsubscribe() 619 | return nil 620 | } 621 | 622 | // RelayerhubRelayerUnRegister represents a RelayerUnRegister event raised by the Relayerhub contract. 623 | type RelayerhubRelayerUnRegister struct { 624 | Relayer common.Address 625 | Raw types.Log // Blockchain specific contextual infos 626 | } 627 | 628 | // FilterRelayerUnRegister is a free log retrieval operation binding the contract event 0xd17202129b83db7880d6b9f25df81c58ad46f7e0e2c92236b1aa10663a487667. 629 | // 630 | // Solidity: event relayerUnRegister(address _relayer) 631 | func (_Relayerhub *RelayerhubFilterer) FilterRelayerUnRegister(opts *bind.FilterOpts) (*RelayerhubRelayerUnRegisterIterator, error) { 632 | 633 | logs, sub, err := _Relayerhub.contract.FilterLogs(opts, "relayerUnRegister") 634 | if err != nil { 635 | return nil, err 636 | } 637 | return &RelayerhubRelayerUnRegisterIterator{contract: _Relayerhub.contract, event: "relayerUnRegister", logs: logs, sub: sub}, nil 638 | } 639 | 640 | // WatchRelayerUnRegister is a free log subscription operation binding the contract event 0xd17202129b83db7880d6b9f25df81c58ad46f7e0e2c92236b1aa10663a487667. 641 | // 642 | // Solidity: event relayerUnRegister(address _relayer) 643 | func (_Relayerhub *RelayerhubFilterer) WatchRelayerUnRegister(opts *bind.WatchOpts, sink chan<- *RelayerhubRelayerUnRegister) (event.Subscription, error) { 644 | 645 | logs, sub, err := _Relayerhub.contract.WatchLogs(opts, "relayerUnRegister") 646 | if err != nil { 647 | return nil, err 648 | } 649 | return event.NewSubscription(func(quit <-chan struct{}) error { 650 | defer sub.Unsubscribe() 651 | for { 652 | select { 653 | case log := <-logs: 654 | // New log arrived, parse the event and forward to the user 655 | event := new(RelayerhubRelayerUnRegister) 656 | if err := _Relayerhub.contract.UnpackLog(event, "relayerUnRegister", log); err != nil { 657 | return err 658 | } 659 | event.Raw = log 660 | 661 | select { 662 | case sink <- event: 663 | case err := <-sub.Err(): 664 | return err 665 | case <-quit: 666 | return nil 667 | } 668 | case err := <-sub.Err(): 669 | return err 670 | case <-quit: 671 | return nil 672 | } 673 | } 674 | }), nil 675 | } 676 | 677 | // ParseRelayerUnRegister is a log parse operation binding the contract event 0xd17202129b83db7880d6b9f25df81c58ad46f7e0e2c92236b1aa10663a487667. 678 | // 679 | // Solidity: event relayerUnRegister(address _relayer) 680 | func (_Relayerhub *RelayerhubFilterer) ParseRelayerUnRegister(log types.Log) (*RelayerhubRelayerUnRegister, error) { 681 | event := new(RelayerhubRelayerUnRegister) 682 | if err := _Relayerhub.contract.UnpackLog(event, "relayerUnRegister", log); err != nil { 683 | return nil, err 684 | } 685 | return event, nil 686 | } 687 | --------------------------------------------------------------------------------