diff --git a/.gitmodules b/.gitmodules index a243561ba..22067b9b1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,3 +12,6 @@ [submodule "oasys-genesis-contract-6037082"] path = consensus/oasys/oasys-genesis-contract-6037082 url = https://github.com/oasysgames/oasys-genesis-contract.git +[submodule "consensus/oasys/oasys-genesis-contract-5675779"] + path = consensus/oasys/oasys-genesis-contract-5675779 + url = https://github.com/oasysgames/oasys-genesis-contract.git diff --git a/Dockerfile b/Dockerfile index c8bf8998e..58757b499 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build Geth in a stock Go builder container -FROM golang:1.20.14-bookworm as builder +FROM golang:1.21.13-bookworm as builder # Support setting various labels on the final image ARG COMMIT="" diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 2faf274db..905a68763 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -941,6 +941,10 @@ func (fb *filterBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Su return fb.bc.SubscribeChainEvent(ch) } +func (fb *filterBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription { + return nil +} + func (fb *filterBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { return fb.bc.SubscribeRemovedLogsEvent(ch) } @@ -953,6 +957,10 @@ func (fb *filterBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event return nullSubscription() } +func (fb *filterBackend) SubscribeNewVoteEvent(ch chan<- core.NewVoteEvent) event.Subscription { + return nil +} + func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 } func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) { diff --git a/accounts/scwallet/securechannel.go b/accounts/scwallet/securechannel.go index bbd8b2264..60f629210 100644 --- a/accounts/scwallet/securechannel.go +++ b/accounts/scwallet/securechannel.go @@ -76,7 +76,7 @@ func NewSecureChannelSession(card *pcsc.Card, keyData []byte) (*SecureChannelSes return &SecureChannelSession{ card: card, secret: secret.Bytes(), - publicKey: elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y), + publicKey: elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y), //nolint:all //TODO }, nil } diff --git a/cmd/geth/blsaccountcmd.go b/cmd/geth/blsaccountcmd.go new file mode 100644 index 000000000..2ffe1b8d2 --- /dev/null +++ b/cmd/geth/blsaccountcmd.go @@ -0,0 +1,703 @@ +package main + +import ( + "context" + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + "os" + "path/filepath" + "strings" + + "github.com/google/uuid" + "github.com/logrusorgru/aurora" + "github.com/prysmaticlabs/prysm/v5/crypto/bls" + "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + "github.com/prysmaticlabs/prysm/v5/io/prompt" + validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client" + "github.com/prysmaticlabs/prysm/v5/validator/accounts" + "github.com/prysmaticlabs/prysm/v5/validator/accounts/iface" + "github.com/prysmaticlabs/prysm/v5/validator/accounts/petnames" + "github.com/prysmaticlabs/prysm/v5/validator/accounts/wallet" + "github.com/prysmaticlabs/prysm/v5/validator/keymanager" + "github.com/prysmaticlabs/prysm/v5/validator/keymanager/local" + "github.com/urfave/cli/v2" + keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/signer/core" +) + +const ( + BLSWalletPath = "bls/wallet" + BLSKeystorePath = "bls/keystore" +) + +var ( + au = aurora.NewAurora(true) + showPrivateKeyFlag = &cli.BoolFlag{ + Name: "show-private-key", + Usage: "Show the BLS12-381 private key you will encrypt into a keystore file", + Category: flags.AccountCategory, + } + importedAccountPasswordFileFlag = &cli.StringFlag{ + Name: "importedaccountpassword", + Usage: "Password file path for the imported BLS account , which contains the password to get the private key by decrypting the keystore file", + Category: flags.AccountCategory, + } + chainIdFlag = &cli.Int64Flag{ + Name: "chain-id", + Usage: "The chain id of the network that the validator will be created at", + } +) + +var ( + blsCommand = &cli.Command{ + Name: "bls", + Usage: "Manage BLS wallet and accounts", + ArgsUsage: "", + Category: "BLS ACCOUNT COMMANDS", + Description: ` + +Manage BLS wallet and accounts, before creating or importing BLS accounts, create +BLS wallet first. One BLS wallet is enough for all BLS accounts, the first BLS +account in the wallet will be used to vote for fast finality now. + +It only supports interactive mode now, when you are prompted for password, please +input your password, and take care the wallet password which is different from accounts' +password. + +There are generally two steps to manage a BLS account: +1.Create a BLS wallet: geth bls wallet create +2.Create a BLS account: geth bls account new + or import a BLS account: geth bls account import `, + Subcommands: []*cli.Command{ + { + Name: "wallet", + Usage: "Manage BLS wallet", + ArgsUsage: "", + Category: "BLS ACCOUNT COMMANDS", + Description: ` + +Create a BLS wallet to manage BLS accounts, this should before creating +or import a BLS account. The BLS wallet dir should be "/bls/wallet".`, + Subcommands: []*cli.Command{ + { + Name: "create", + Usage: "Create BLS wallet", + Action: blsWalletCreate, + ArgsUsage: "", + Category: "BLS ACCOUNT COMMANDS", + Flags: []cli.Flag{ + utils.DataDirFlag, + utils.BLSPasswordFileFlag, + }, + Description: ` + geth bls wallet create + +will prompt for your password then create a BLS wallet in "/bls/wallet", +don't create BLS wallet repeatedly'.`, + }, + }, + }, + { + Name: "account", + Usage: "Manage BLS accounts", + ArgsUsage: "", + Category: "BLS ACCOUNT COMMANDS", + Description: ` + +Manage BLS accounts,list all existing accounts, import a BLS private key into +a new account, create a new account or delete an existing account. + +Make sure you remember the password you gave when creating a new account. +Without it you are not able to unlock your account. And this password is +different from the wallet password, please take care. + +Note that exporting your key in unencrypted format is NOT supported. + +Keys are stored under /bls/keystore. +It is safe to transfer the entire directory or the individual keys therein +between ethereum nodes by simply copying. + +Make sure you backup your BLS keys regularly.`, + Subcommands: []*cli.Command{ + { + Name: "new", + Usage: "Create a BLS account", + Action: blsAccountCreate, + ArgsUsage: "", + Category: "BLS ACCOUNT COMMANDS", + Flags: []cli.Flag{ + utils.DataDirFlag, + showPrivateKeyFlag, + utils.BLSPasswordFileFlag, + }, + Description: ` + geth bls account new + +Creates a new BLS account and imports the account into the BLS wallet. + +If the BLS wallet not created yet, it will try to create BLS wallet first. + +The account is saved in encrypted format, you are prompted for a password. +You must remember this password to unlock your account in the future.`, + }, + { + Name: "import", + Usage: "Import a BLS account", + Action: blsAccountImport, + ArgsUsage: "", + Category: "BLS ACCOUNT COMMANDS", + Flags: []cli.Flag{ + utils.DataDirFlag, + utils.BLSPasswordFileFlag, + importedAccountPasswordFileFlag, + }, + Description: ` + geth bls account import + +Import a encrypted BLS account or a BLS12-381 private key from file into the BLS wallet. + +If the BLS wallet not created yet, it will try to create BLS wallet first.`, + }, + { + Name: "list", + Usage: "Print summary of existing BLS accounts", + Action: blsAccountList, + ArgsUsage: "", + Category: "BLS ACCOUNT COMMANDS", + Flags: []cli.Flag{ + utils.DataDirFlag, + utils.BLSPasswordFileFlag, + }, + Description: ` + geth bls account list + +Print summary of existing BLS accounts in the current BLS wallet.`, + }, + { + Name: "delete", + Usage: "Delete the selected BLS account from the BLS wallet", + Action: blsAccountDelete, + ArgsUsage: "", + Category: "BLS ACCOUNT COMMANDS", + Flags: []cli.Flag{ + utils.DataDirFlag, + utils.BLSPasswordFileFlag, + }, + Description: ` + geth bls account delete + +Delete the selected BLS account from the BLS wallet.`, + }, + { + Name: "generate-proof", + Usage: "Generate ownership proof for the selected BLS account from the BLS wallet", + Action: blsAccountGenerateProof, + ArgsUsage: " ", + Category: "BLS ACCOUNT COMMANDS", + Flags: []cli.Flag{ + utils.DataDirFlag, + utils.BLSPasswordFileFlag, + chainIdFlag, + }, + Description: ` + geth bls account generate-proof + +Generate ownership proof for the selected BLS account from the BLS wallet. The proof is used to prove the ownership of the BLS account when creating validator on BSC after feynman upgrade.`, + }, + }, + }, + }, + } +) + +// blsWalletCreate creates a BLS wallet in /bls/wallet. +func blsWalletCreate(ctx *cli.Context) error { + cfg := gethConfig{Node: defaultNodeConfig()} + // Load config file. + if file := ctx.String(configFileFlag.Name); file != "" { + if err := loadConfig(file, &cfg); err != nil { + utils.Fatalf("%v", err) + } + } + utils.SetNodeConfig(ctx, &cfg.Node) + + dir := filepath.Join(cfg.Node.DataDir, BLSWalletPath) + dirExists, err := wallet.Exists(dir) + if err != nil { + utils.Fatalf("Check BLS wallet exists error: %v.", err) + } + if dirExists { + utils.Fatalf("BLS wallet already exists in /bls/wallet.") + } + + password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) + if err := core.ValidatePasswordFormat(password); err != nil { + utils.Fatalf("Password invalid: %v.", err) + } + + opts := []accounts.Option{} + opts = append(opts, accounts.WithWalletDir(dir)) + opts = append(opts, accounts.WithWalletPassword(password)) + opts = append(opts, accounts.WithKeymanagerType(keymanager.Local)) + opts = append(opts, accounts.WithSkipMnemonicConfirm(true)) + acc, err := accounts.NewCLIManager(opts...) + if err != nil { + utils.Fatalf("New Accounts CLI Manager failed: %v.", err) + } + if _, err := acc.WalletCreate(context.Background()); err != nil { + utils.Fatalf("Create BLS wallet failed: %v.", err) + } + + fmt.Println("Create BLS wallet successfully!") + return nil +} + +// openOrCreateBLSWallet opens BLS wallet in /bls/wallet, if wallet +// not exists, then creates BLS wallet in /bls/wallet. +func openOrCreateBLSWallet(ctx *cli.Context, cfg *gethConfig) (*wallet.Wallet, error) { + var w *wallet.Wallet + walletDir := filepath.Join(cfg.Node.DataDir, BLSWalletPath) + dirExists, err := wallet.Exists(walletDir) + if err != nil { + utils.Fatalf("Check dir %s failed: %v.", walletDir, err) + } + if !dirExists { + fmt.Println("BLS wallet not exists, creating BLS wallet...") + password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) + if err := core.ValidatePasswordFormat(password); err != nil { + utils.Fatalf("Password invalid: %v.", err) + } + + opts := []accounts.Option{} + opts = append(opts, accounts.WithWalletDir(walletDir)) + opts = append(opts, accounts.WithWalletPassword(password)) + opts = append(opts, accounts.WithKeymanagerType(keymanager.Local)) + opts = append(opts, accounts.WithSkipMnemonicConfirm(true)) + acc, err := accounts.NewCLIManager(opts...) + if err != nil { + utils.Fatalf("New Accounts CLI Manager failed: %v.", err) + } + w, err := acc.WalletCreate(context.Background()) + if err != nil { + utils.Fatalf("Create BLS wallet failed: %v.", err) + } + + fmt.Println("Create BLS wallet successfully!") + return w, nil + } + + walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) + w, err = wallet.OpenWallet(context.Background(), &wallet.Config{ + WalletDir: walletDir, + WalletPassword: walletPassword, + }) + if err != nil { + utils.Fatalf("Open BLS wallet failed: %v.", err) + } + return w, nil +} + +// blsAccountCreate creates a BLS account in /bls/keystore, +// and import the created account into the BLS wallet. +func blsAccountCreate(ctx *cli.Context) error { + cfg := gethConfig{Node: defaultNodeConfig()} + // Load config file. + if file := ctx.String(configFileFlag.Name); file != "" { + if err := loadConfig(file, &cfg); err != nil { + utils.Fatalf("%v", err) + } + } + utils.SetNodeConfig(ctx, &cfg.Node) + + w, _ := openOrCreateBLSWallet(ctx, &cfg) + if w.KeymanagerKind() != keymanager.Local { + utils.Fatalf("BLS wallet has wrong key manager kind.") + } + km, err := w.InitializeKeymanager(context.Background(), iface.InitKeymanagerConfig{ListenForChanges: false}) + if err != nil { + utils.Fatalf("Initialize key manager failed: %v.", err) + } + k, ok := km.(keymanager.Importer) + if !ok { + utils.Fatalf("The BLS keymanager cannot import keystores") + } + + keystoreDir := filepath.Join(cfg.Node.DataDir, BLSKeystorePath) + if err := os.MkdirAll(keystoreDir, 0755); err != nil { + utils.Fatalf("Could not access keystore dir: %v.", err) + } + accountPassword := w.Password() + + encryptor := keystorev4.New() + secretKey, err := bls.RandKey() + if err != nil { + utils.Fatalf("Could not generate BLS secret key: %v.", err) + } + + showPrivateKey := ctx.Bool(showPrivateKeyFlag.Name) + if showPrivateKey { + fmt.Printf("private key used: 0x%s\n", common.Bytes2Hex(secretKey.Marshal())) + } + + pubKeyBytes := secretKey.PublicKey().Marshal() + cryptoFields, err := encryptor.Encrypt(secretKey.Marshal(), accountPassword) + if err != nil { + utils.Fatalf("Could not encrypt secret key: %v.", err) + } + id, err := uuid.NewRandom() + if err != nil { + utils.Fatalf("Could not generate uuid: %v.", err) + } + keystore := &keymanager.Keystore{ + Crypto: cryptoFields, + ID: id.String(), + Pubkey: fmt.Sprintf("%x", pubKeyBytes), + Version: encryptor.Version(), + Name: encryptor.Name(), + } + + encodedFile, err := json.MarshalIndent(keystore, "", "\t") + if err != nil { + utils.Fatalf("Could not marshal keystore to JSON file: %v.", err) + } + keystoreFile, err := os.Create(fmt.Sprintf("%s/keystore-%s.json", keystoreDir, petnames.DeterministicName(pubKeyBytes, "-"))) + if err != nil { + utils.Fatalf("Could not create keystore file: %v.", err) + } + if _, err := keystoreFile.Write(encodedFile); err != nil { + utils.Fatalf("Could not write keystore file contents: %v.", err) + } + fmt.Println("Successfully create a BLS account.") + + fmt.Println("Importing BLS account, this may take a while...") + _, err = accounts.ImportAccounts(context.Background(), &accounts.ImportAccountsConfig{ + Importer: k, + Keystores: []*keymanager.Keystore{keystore}, + AccountPassword: accountPassword, + }) + if err != nil { + utils.Fatalf("Import BLS account failed: %v.", err) + } + fmt.Printf("Successfully import created BLS account.\n") + return nil +} + +// blsAccountImport imports a BLS account into the BLS wallet. +func blsAccountImport(ctx *cli.Context) error { + cfg := gethConfig{Node: defaultNodeConfig()} + // Load config file. + if file := ctx.String(configFileFlag.Name); file != "" { + if err := loadConfig(file, &cfg); err != nil { + utils.Fatalf("%v", err) + } + } + utils.SetNodeConfig(ctx, &cfg.Node) + + w, _ := openOrCreateBLSWallet(ctx, &cfg) + if w.KeymanagerKind() != keymanager.Local { + utils.Fatalf("BLS wallet has wrong key manager kind.") + } + km, err := w.InitializeKeymanager(context.Background(), iface.InitKeymanagerConfig{ListenForChanges: false}) + if err != nil { + utils.Fatalf("Initialize key manager failed: %v.", err) + } + k, ok := km.(keymanager.Importer) + if !ok { + utils.Fatalf("The BLS keymanager cannot import keystores") + } + + keyfile := ctx.Args().First() + if len(keyfile) == 0 { + utils.Fatalf("The keystore file must be given as argument.") + } + keyInfo, err := os.ReadFile(keyfile) + if err != nil { + utils.Fatalf("Could not read keystore file: %v", err) + } + keystore := &keymanager.Keystore{} + var importedAccountPassword string + if err := json.Unmarshal(keyInfo, keystore); err != nil { + secretKey, err := bls.SecretKeyFromBytes(common.FromHex(strings.TrimRight(string(keyInfo), "\r\n"))) + if err != nil { + utils.Fatalf("keyFile is neither a keystore file or include a valid BLS12-381 private key: %v.", err) + } + pubKeyBytes := secretKey.PublicKey().Marshal() + encryptor := keystorev4.New() + importedAccountPassword = w.Password() + cryptoFields, err := encryptor.Encrypt(secretKey.Marshal(), importedAccountPassword) + if err != nil { + utils.Fatalf("Could not encrypt secret key: %v.", err) + } + id, err := uuid.NewRandom() + if err != nil { + utils.Fatalf("Could not generate uuid: %v.", err) + } + keystore = &keymanager.Keystore{ + Crypto: cryptoFields, + ID: id.String(), + Pubkey: fmt.Sprintf("%x", pubKeyBytes), + Version: encryptor.Version(), + Name: encryptor.Name(), + } + } + if keystore.Pubkey == "" { + utils.Fatalf(" Missing public key, wrong keystore file.") + } + + if importedAccountPassword == "" { + importedAccountPassword = utils.GetPassPhraseWithList("Enter the password for your imported account.", false, 0, utils.MakePasswordListFromPath(ctx.String(importedAccountPasswordFileFlag.Name))) + } + + fmt.Println("Importing BLS account, this may take a while...") + statuses, err := accounts.ImportAccounts(context.Background(), &accounts.ImportAccountsConfig{ + Importer: k, + Keystores: []*keymanager.Keystore{keystore}, + AccountPassword: importedAccountPassword, + }) + if err != nil { + utils.Fatalf("Import BLS account failed: %v.", err) + } + // len(statuses)==len(Keystores) when err==nil + if statuses[0].Status == keymanager.StatusError { + fmt.Printf("Could not import keystore: %v.", statuses[0].Message) + } else { + fmt.Println("Successfully import BLS account.") + } + return nil +} + +// blsAccountList prints existing BLS accounts in the BLS wallet. +func blsAccountList(ctx *cli.Context) error { + cfg := gethConfig{Node: defaultNodeConfig()} + // Load config file. + if file := ctx.String(configFileFlag.Name); file != "" { + if err := loadConfig(file, &cfg); err != nil { + utils.Fatalf("%v", err) + } + } + utils.SetNodeConfig(ctx, &cfg.Node) + + walletDir := filepath.Join(cfg.Node.DataDir, BLSWalletPath) + dirExists, err := wallet.Exists(walletDir) + if err != nil || !dirExists { + utils.Fatalf("BLS wallet not exists.") + } + + walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) + w, err := wallet.OpenWallet(context.Background(), &wallet.Config{ + WalletDir: walletDir, + WalletPassword: walletPassword, + }) + if err != nil { + utils.Fatalf("Open BLS wallet failed: %v.", err) + } + km, err := w.InitializeKeymanager(context.Background(), iface.InitKeymanagerConfig{ListenForChanges: false}) + if err != nil { + utils.Fatalf("Initialize key manager failed: %v.", err) + } + + ikm, ok := km.(*local.Keymanager) + if !ok { + utils.Fatalf("Could not assert keymanager interface to concrete type.") + } + accountNames, err := ikm.ValidatingAccountNames() + if err != nil { + utils.Fatalf("Could not fetch account names: %v.", err) + } + numAccounts := au.BrightYellow(len(accountNames)) + fmt.Printf("(keymanager kind) %s\n", au.BrightGreen("imported wallet").Bold()) + fmt.Println("") + if len(accountNames) == 1 { + fmt.Printf("Showing %d BLS account\n", numAccounts) + } else { + fmt.Printf("Showing %d BLS accounts\n", numAccounts) + } + pubKeys, err := km.FetchValidatingPublicKeys(context.Background()) + if err != nil { + utils.Fatalf("Could not fetch BLS public keys: %v.", err) + } + for i := 0; i < len(accountNames); i++ { + fmt.Println("") + fmt.Printf("%s | %s\n", au.BrightBlue(fmt.Sprintf("Account %d", i)).Bold(), au.BrightGreen(accountNames[i]).Bold()) + fmt.Printf("%s %#x\n", au.BrightMagenta("[BLS public key]").Bold(), pubKeys[i]) + } + fmt.Println("") + return nil +} + +// blsAccountDelete deletes a selected BLS account from the BLS wallet. +func blsAccountDelete(ctx *cli.Context) error { + if ctx.Args().Len() == 0 { + utils.Fatalf("No BLS account specified to delete.") + } + var filteredPubKeys []bls.PublicKey + for _, str := range ctx.Args().Slice() { + pkString := str + if strings.Contains(pkString, "0x") { + pkString = pkString[2:] + } + pubKeyBytes, err := hex.DecodeString(pkString) + if err != nil { + utils.Fatalf("Could not decode string %s as hex.", pkString) + } + blsPublicKey, err := bls.PublicKeyFromBytes(pubKeyBytes) + if err != nil { + utils.Fatalf("%#x is not a valid BLS public key.", pubKeyBytes) + } + filteredPubKeys = append(filteredPubKeys, blsPublicKey) + } + + cfg := gethConfig{Node: defaultNodeConfig()} + // Load config file. + if file := ctx.String(configFileFlag.Name); file != "" { + if err := loadConfig(file, &cfg); err != nil { + utils.Fatalf("%v", err) + } + } + utils.SetNodeConfig(ctx, &cfg.Node) + + walletDir := filepath.Join(cfg.Node.DataDir, BLSWalletPath) + dirExists, err := wallet.Exists(walletDir) + if err != nil || !dirExists { + utils.Fatalf("BLS wallet not exists.") + } + + walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) + w, err := wallet.OpenWallet(context.Background(), &wallet.Config{ + WalletDir: walletDir, + WalletPassword: walletPassword, + }) + if err != nil { + utils.Fatalf("Open BLS wallet failed: %v.", err) + } + km, err := w.InitializeKeymanager(context.Background(), iface.InitKeymanagerConfig{ListenForChanges: false}) + if err != nil { + utils.Fatalf("Initialize key manager failed: %v.", err) + } + pubkeys, err := km.FetchValidatingPublicKeys(context.Background()) + if err != nil { + utils.Fatalf("Could not fetch BLS public keys: %v.", err) + } + + rawPublicKeys := make([][]byte, len(filteredPubKeys)) + formattedPubKeys := make([]string, len(filteredPubKeys)) + for i, pk := range filteredPubKeys { + pubKeyBytes := pk.Marshal() + rawPublicKeys[i] = pubKeyBytes + formattedPubKeys[i] = fmt.Sprintf("%#x", bytesutil.Trunc(pubKeyBytes)) + } + allAccountStr := strings.Join(formattedPubKeys, ", ") + if len(filteredPubKeys) == 1 { + promptText := "Are you sure you want to delete 1 account? (%s) Y/N" + resp, err := prompt.ValidatePrompt( + os.Stdin, fmt.Sprintf(promptText, au.BrightGreen(formattedPubKeys[0])), prompt.ValidateYesOrNo, + ) + if err != nil { + return err + } + if strings.EqualFold(resp, "n") { + return nil + } + } else { + promptText := "Are you sure you want to delete %d accounts? (%s) Y/N" + if len(filteredPubKeys) == len(pubkeys) { + promptText = fmt.Sprintf("Are you sure you want to delete all accounts? Y/N (%s)", au.BrightGreen(allAccountStr)) + } else { + promptText = fmt.Sprintf(promptText, len(filteredPubKeys), au.BrightGreen(allAccountStr)) + } + resp, err := prompt.ValidatePrompt(os.Stdin, promptText, prompt.ValidateYesOrNo) + if err != nil { + return err + } + if strings.EqualFold(resp, "n") { + return nil + } + } + + if err := accounts.DeleteAccount(context.Background(), &accounts.DeleteConfig{ + Keymanager: km, + DeletePublicKeys: rawPublicKeys, + }); err != nil { + utils.Fatalf("Delete account failed: %v.", err) + } + + return nil +} + +// blsAccountGenerateProof generate ownership proof for a selected BLS account. +func blsAccountGenerateProof(ctx *cli.Context) error { + addrString := ctx.Args().First() + if addrString == "" { + utils.Fatalf("Operator account must be given as argument.") + } + addr := common.HexToAddress(addrString) + + blsPubkeyString := ctx.Args().Get(1) + if blsPubkeyString == "" { + utils.Fatalf("BLS pubkey must be given as argument.") + } + blsPubkeyBz, err := hex.DecodeString(strings.TrimPrefix(blsPubkeyString, "0x")) + if err != nil { + utils.Fatalf("Could not decode string %s as hex.", blsPubkeyString) + } + blsPublicKey, err := bls.PublicKeyFromBytes(blsPubkeyBz) + if err != nil { + utils.Fatalf("%#x is not a valid BLS public key.", blsPubkeyBz) + } + + cfg := gethConfig{Node: defaultNodeConfig()} + // Load config file. + if file := ctx.String(configFileFlag.Name); file != "" { + if err := loadConfig(file, &cfg); err != nil { + utils.Fatalf("%v", err) + } + } + utils.SetNodeConfig(ctx, &cfg.Node) + + walletDir := filepath.Join(cfg.Node.DataDir, BLSWalletPath) + dirExists, err := wallet.Exists(walletDir) + if err != nil || !dirExists { + utils.Fatalf("BLS wallet not exists.") + } + + walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) + w, err := wallet.OpenWallet(context.Background(), &wallet.Config{ + WalletDir: walletDir, + WalletPassword: walletPassword, + }) + if err != nil { + utils.Fatalf("Open BLS wallet failed: %v.", err) + } + km, err := w.InitializeKeymanager(context.Background(), iface.InitKeymanagerConfig{ListenForChanges: false}) + if err != nil { + utils.Fatalf("Initialize key manager failed: %v.", err) + } + + chainIdInt64 := ctx.Int64(chainIdFlag.Name) + if chainIdInt64 == 0 { + utils.Fatalf("Chain id is required.") + } + chainId := new(big.Int).SetInt64(chainIdInt64) + paddedChainIdBytes := make([]byte, 32) + copy(paddedChainIdBytes[32-len(chainId.Bytes()):], chainId.Bytes()) + msgHash := crypto.Keccak256(append(addr.Bytes(), append(blsPublicKey.Marshal(), paddedChainIdBytes...)...)) + + req := &validatorpb.SignRequest{ + PublicKey: blsPublicKey.Marshal(), + SigningRoot: msgHash, + } + sig, err := km.Sign(context.Background(), req) + if err != nil { + utils.Fatalf("Generate signature failed: %v.", err) + } + fmt.Printf("Proof: %#x\n", sig.Marshal()) + + return nil +} diff --git a/cmd/geth/main.go b/cmd/geth/main.go index d46f70cc2..b46283e69 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -144,6 +144,13 @@ var ( utils.GpoMaxGasPriceFlag, utils.GpoIgnoreGasPriceFlag, configFileFlag, + utils.VotingEnabledFlag, + utils.DisableVoteAttestationFlag, + utils.EnableMaliciousVoteMonitorFlag, + utils.BLSPasswordFileFlag, + utils.BLSWalletDirFlag, + utils.VoteJournalDirFlag, + utils.VoteKeyNameFlag, utils.LogDebugFlag, utils.LogBacktraceAtFlag, }, utils.NetworkFlags, utils.DatabaseFlags) @@ -235,6 +242,7 @@ func init() { snapshotCommand, // See verkle.go verkleCommand, + blsCommand, } if logTestCommand != nil { app.Commands = append(app.Commands, logTestCommand) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index f5c4397b5..c42c5185a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -908,6 +908,47 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server. Value: metrics.DefaultConfig.InfluxDBOrganization, Category: flags.MetricsCategory, } + + VotingEnabledFlag = &cli.BoolFlag{ + Name: "vote", + Usage: "Enable voting when mining", + Category: flags.FastFinalityCategory, + } + + DisableVoteAttestationFlag = &cli.BoolFlag{ + Name: "disablevoteattestation", + Usage: "Disable assembling vote attestation ", + Category: flags.FastFinalityCategory, + } + + BLSPasswordFileFlag = &cli.StringFlag{ + Name: "blspassword", + Usage: "Password file path for the BLS wallet, which contains the password to unlock BLS wallet for managing votes in fast_finality feature", + Category: flags.AccountCategory, + } + + EnableMaliciousVoteMonitorFlag = &cli.BoolFlag{ + Name: "monitor.maliciousvote", + Usage: "Enable malicious vote monitor to check whether any validator violates the voting rules of fast finality", + Category: flags.FastFinalityCategory, + } + + BLSWalletDirFlag = &flags.DirectoryFlag{ + Name: "blswallet", + Usage: "Path for the blsWallet dir in fast finality feature (default = inside the datadir)", + Category: flags.AccountCategory, + } + + VoteJournalDirFlag = &flags.DirectoryFlag{ + Name: "vote-journal-path", + Usage: "Path for the voteJournal dir in fast finality feature (default = inside the datadir)", + Category: flags.FastFinalityCategory, + } + VoteKeyNameFlag = &cli.StringFlag{ + Name: "vote-key-name", + Usage: "Name of the BLS public key used for voting (default = first found key)", + Category: flags.FastFinalityCategory, + } ) var ( @@ -1214,6 +1255,13 @@ func setLes(ctx *cli.Context, cfg *ethconfig.Config) { } } +// setMonitors enable monitors from the command line flags. +func setMonitors(ctx *cli.Context, cfg *node.Config) { + if ctx.Bool(EnableMaliciousVoteMonitorFlag.Name) { + cfg.EnableMaliciousVoteMonitor = true + } +} + // MakeDatabaseHandles raises out the number of allowed file handles per process // for Geth and returns half of the allowance to assign to the database. func MakeDatabaseHandles(max int) int { @@ -1301,6 +1349,22 @@ func MakePasswordList(ctx *cli.Context) []string { return lines } +func MakePasswordListFromPath(path string) []string { + if path == "" { + return nil + } + text, err := os.ReadFile(path) + if err != nil { + Fatalf("Failed to read password file: %v", err) + } + lines := strings.Split(string(text), "\n") + // Sanitise DOS line endings. + for i := range lines { + lines[i] = strings.TrimRight(lines[i], "\r") + } + return lines +} + func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { setNodeKey(ctx, cfg) setNAT(ctx, cfg) @@ -1354,6 +1418,9 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { setNodeUserIdent(ctx, cfg) SetDataDir(ctx, cfg) setSmartCard(ctx, cfg) + setMonitors(ctx, cfg) + setBLSWalletDir(ctx, cfg) + setVoteJournalDir(ctx, cfg) if ctx.IsSet(JWTSecretFlag.Name) { cfg.JWTSecret = ctx.String(JWTSecretFlag.Name) @@ -1385,6 +1452,12 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { if ctx.IsSet(InsecureUnlockAllowedFlag.Name) { cfg.InsecureUnlockAllowed = ctx.Bool(InsecureUnlockAllowedFlag.Name) } + if ctx.IsSet(BLSPasswordFileFlag.Name) { + cfg.BLSPasswordFile = ctx.String(BLSPasswordFileFlag.Name) + } + if ctx.IsSet(VoteKeyNameFlag.Name) { + cfg.VoteKeyName = ctx.String(VoteKeyNameFlag.Name) + } if ctx.IsSet(DBEngineFlag.Name) { dbEngine := ctx.String(DBEngineFlag.Name) if dbEngine != "leveldb" && dbEngine != "pebble" { @@ -1437,6 +1510,24 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) { } } +func setVoteJournalDir(ctx *cli.Context, cfg *node.Config) { + dataDir := cfg.DataDir + if ctx.IsSet(VoteJournalDirFlag.Name) { + cfg.VoteJournalDir = ctx.String(VoteJournalDirFlag.Name) + } else if cfg.VoteJournalDir == "" { + cfg.VoteJournalDir = filepath.Join(dataDir, "voteJournal") + } +} + +func setBLSWalletDir(ctx *cli.Context, cfg *node.Config) { + dataDir := cfg.DataDir + if ctx.IsSet(BLSWalletDirFlag.Name) { + cfg.BLSWalletDir = ctx.String(BLSWalletDirFlag.Name) + } else if cfg.BLSWalletDir == "" { + cfg.BLSWalletDir = filepath.Join(dataDir, "bls/wallet") + } +} + func setGPO(ctx *cli.Context, cfg *gasprice.Config) { if ctx.IsSet(GpoBlocksFlag.Name) { cfg.Blocks = ctx.Int(GpoBlocksFlag.Name) @@ -1511,6 +1602,12 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) { if ctx.IsSet(MinerNewPayloadTimeout.Name) { cfg.NewPayloadTimeout = ctx.Duration(MinerNewPayloadTimeout.Name) } + if ctx.Bool(VotingEnabledFlag.Name) { + cfg.VoteEnable = true + } + if ctx.Bool(DisableVoteAttestationFlag.Name) { + cfg.DisableVoteAttestation = true + } } func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) { diff --git a/common/gopool/pool.go b/common/gopool/pool.go new file mode 100644 index 000000000..bfcc618e4 --- /dev/null +++ b/common/gopool/pool.go @@ -0,0 +1,60 @@ +package gopool + +import ( + "runtime" + "time" + + "github.com/panjf2000/ants/v2" +) + +var ( + // Init a instance pool when importing ants. + defaultPool, _ = ants.NewPool(ants.DefaultAntsPoolSize, ants.WithExpiryDuration(10*time.Second)) + minNumberPerTask = 5 +) + +// Logger is used for logging formatted messages. +type Logger interface { + // Printf must have the same semantics as log.Printf. + Printf(format string, args ...interface{}) +} + +// Submit submits a task to pool. +func Submit(task func()) error { + return defaultPool.Submit(task) +} + +// Running returns the number of the currently running goroutines. +func Running() int { + return defaultPool.Running() +} + +// Cap returns the capacity of this default pool. +func Cap() int { + return defaultPool.Cap() +} + +// Free returns the available goroutines to work. +func Free() int { + return defaultPool.Free() +} + +// Release Closes the default pool. +func Release() { + defaultPool.Release() +} + +// Reboot reboots the default pool. +func Reboot() { + defaultPool.Reboot() +} + +func Threads(tasks int) int { + threads := tasks / minNumberPerTask + if threads > runtime.NumCPU() { + threads = runtime.NumCPU() + } else if threads == 0 { + threads = 1 + } + return threads +} diff --git a/consensus/consensus.go b/consensus/consensus.go index feb545ac6..cf5384714 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -52,6 +52,10 @@ type ChainHeaderReader interface { GetCanonicalHash(number uint64) common.Hash } +type VotePool interface { + FetchVoteByBlockHash(blockHash common.Hash) []*types.VoteEnvelope +} + // ChainReader defines a small collection of methods needed to access the local // blockchain during header and/or uncle verification. type ChainReader interface { @@ -135,4 +139,9 @@ type PoS interface { Engine IsSystemTransaction(tx *types.Transaction, header *types.Header) (bool, error) + GetJustifiedNumberAndHash(chain ChainHeaderReader, headers []*types.Header) (uint64, common.Hash, error) + GetFinalizedHeader(chain ChainHeaderReader, header *types.Header) *types.Header + VerifyVote(chain ChainHeaderReader, vote *types.VoteEnvelope) error + DecodeVoteAttestation(header *types.Header) *types.VoteAttestation + IsActiveValidatorAt(chain ChainHeaderReader, header *types.Header, checkVoteKeyFn func(bLSPublicKey *types.BLSPublicKey) bool) bool } diff --git a/consensus/oasys/contract.go b/consensus/oasys/contract.go index b4ee65469..8ee246f23 100644 --- a/consensus/oasys/contract.go +++ b/consensus/oasys/contract.go @@ -11,6 +11,8 @@ import ( "math" "math/big" "path/filepath" + "reflect" + "sort" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" @@ -40,6 +42,7 @@ var ( //go:embed oasys-genesis-contract-cfb3cd0/artifacts/contracts/Environment.sol/Environment.json //go:embed oasys-genesis-contract-cfb3cd0/artifacts/contracts/StakeManager.sol/StakeManager.json //go:embed oasys-genesis-contract-6037082/artifacts/contracts/CandidateValidatorManager.sol/CandidateValidatorManager.json + //go:embed oasys-genesis-contract-5675779/artifacts/contracts/CandidateValidatorManager.sol/CandidateValidatorManager.json artifacts embed.FS // Oasys genesis contracts @@ -55,19 +58,27 @@ var ( path: filepath.FromSlash("oasys-genesis-contract-cfb3cd0/artifacts/contracts/StakeManager.sol/StakeManager.json"), }, } - systemMethods = map[*genesisContract]map[string]int{ - // Methods with the `onlyCoinbase` modifier are system methods. - // See: https://github.com/oasysgames/oasys-genesis-contract/search?q=onlyCoinbase - environment: {"initialize": 0, "updateValue": 0}, - stakeManager: {"initialize": 0, "slash": 0}, - } - candidateManager = &builtinContract{ address: common.HexToAddress(candidateManagerAddress), artifact: &artifact{ path: filepath.FromSlash("oasys-genesis-contract-6037082/artifacts/contracts/CandidateValidatorManager.sol/CandidateValidatorManager.json"), }, } + // This contract corresponds to v1.6.0 of the genesis contract. + // `2` is not majar version of the genesis contract. + // Just increment the version number to avoid the conflict. + candidateManager2 = &builtinContract{ + address: common.HexToAddress(candidateManagerAddress), + artifact: &artifact{ + path: filepath.FromSlash("oasys-genesis-contract-5675779/artifacts/contracts/CandidateValidatorManager.sol/CandidateValidatorManager.json"), + }, + } + systemMethods = map[*genesisContract]map[string]int{ + // Methods with the `onlyCoinbase` modifier are system methods. + // See: https://github.com/oasysgames/oasys-genesis-contract/search?q=onlyCoinbase + environment: {"initialize": 0, "updateValue": 0}, + stakeManager: {"initialize": 0, "slash": 0}, + } ) func init() { @@ -81,6 +92,9 @@ func init() { if err := candidateManager.parseABI(); err != nil { panic(err) } + if err := candidateManager2.parseABI(); err != nil { + panic(err) + } // Check if the ABI includes system methods for contract, methods := range systemMethods { @@ -155,16 +169,20 @@ type nextValidators struct { Owners []common.Address Operators []common.Address Stakes []*big.Int + // for finality, vote address is unique in validators + VoteAddresses []types.BLSPublicKey } func (p *nextValidators) Copy() *nextValidators { cpy := nextValidators{ - Owners: make([]common.Address, len(p.Owners)), - Operators: make([]common.Address, len(p.Operators)), - Stakes: make([]*big.Int, len(p.Stakes)), + Owners: make([]common.Address, len(p.Owners)), + Operators: make([]common.Address, len(p.Operators)), + Stakes: make([]*big.Int, len(p.Stakes)), + VoteAddresses: make([]types.BLSPublicKey, len(p.VoteAddresses)), } copy(cpy.Owners, p.Owners) copy(cpy.Operators, p.Operators) + copy(cpy.VoteAddresses, p.VoteAddresses) for i, v := range p.Stakes { cpy.Stakes[i] = new(big.Int).Set(v) } @@ -180,6 +198,39 @@ func (p *nextValidators) Exists(validator common.Address) bool { return false } +func (p *nextValidators) SortByOwner() { + // Create a slice of indices based on the length of the Owners slice + indices := make([]int, len(p.Owners)) + for i := range indices { + indices[i] = i + } + + // Sort the indices based on the Owners slice + sort.Slice(indices, func(i, j int) bool { + return bytes.Compare(p.Owners[indices[i]][:], p.Owners[indices[j]][:]) < 0 + }) + + // Create new slices to hold the sorted data + sortedOwners := make([]common.Address, len(p.Owners)) + sortedOperators := make([]common.Address, len(p.Owners)) + sortedStakes := make([]*big.Int, len(p.Owners)) + sortedVoteAddresses := make([]types.BLSPublicKey, len(p.Owners)) + + // Rearrange all slices according to the sorted indices + for i, idx := range indices { + sortedOwners[i] = p.Owners[idx] + sortedOperators[i] = p.Operators[idx] + sortedStakes[i] = p.Stakes[idx] + sortedVoteAddresses[i] = p.VoteAddresses[idx] + } + + // Assign sorted slices back to the struct fields + p.Owners = sortedOwners + p.Operators = sortedOperators + p.Stakes = sortedStakes + p.VoteAddresses = sortedVoteAddresses +} + // callmsg type callmsg struct { ethereum.CallMsg @@ -307,6 +358,14 @@ func getNextValidators( epoch uint64, block uint64, ) (*nextValidators, error) { + if config.IsFastFinalityEnabled(new(big.Int).SetUint64(block)) { + validators, err := callGetHighStakes2(ethAPI, hash, epoch) + if err != nil { + return nil, err + } + validators.SortByOwner() // sort by owner for fast finality + return validators, nil + } if config.IsForkedOasysPublication(new(big.Int).SetUint64(block)) { return callGetHighStakes(ethAPI, hash, epoch) } @@ -366,6 +425,8 @@ func callGetValidators(ethAPI blockchainAPI, hash common.Hash, epoch uint64) (*n result.Owners = append(result.Owners, recv.Owners[i]) result.Operators = append(result.Operators, recv.Operators[i]) result.Stakes = append(result.Stakes, recv.Stakes[i]) + // set empty key, as the older than v1.6.0 stake manager does not return bls pub key + result.VoteAddresses = append(result.VoteAddresses, types.BLSPublicKey{}) } } } @@ -375,20 +436,86 @@ func callGetValidators(ethAPI blockchainAPI, hash common.Hash, epoch uint64) (*n // Call the `CandidateValidatorManager.getHighStakes` method. func callGetHighStakes(ethAPI blockchainAPI, hash common.Hash, epoch uint64) (*nextValidators, error) { + var ( + recv struct { + Owners []common.Address + Operators []common.Address + Stakes []*big.Int + Candidates []bool + NewCursor *big.Int + Actives, Jailed []bool // unused + } + result nextValidators + processCallResult = func() { + for i := range recv.Owners { + if recv.Candidates[i] { + result.Owners = append(result.Owners, recv.Owners[i]) + result.Operators = append(result.Operators, recv.Operators[i]) + result.Stakes = append(result.Stakes, recv.Stakes[i]) + // set empty key, as the older than v1.6.0 stake manager does not return bls pub key + result.VoteAddresses = append(result.VoteAddresses, types.BLSPublicKey{}) + } + } + } + ) + if err := callGetHighStakesCommon(ethAPI, hash, epoch, candidateManager, &recv, processCallResult); err != nil { + return nil, err + } + + return &result, nil +} + +// Call the `CandidateValidatorManager.getHighStakes` method. +// This function is for the v1.6.0 contract. +func callGetHighStakes2(ethAPI blockchainAPI, hash common.Hash, epoch uint64) (*nextValidators, error) { + var ( + recv struct { + Owners []common.Address + Operators []common.Address + Stakes []*big.Int + BlsPublicKeys [][]byte + Candidates []bool + NewCursor *big.Int + Actives, Jailed []bool // unused + } + result nextValidators + processCallResult = func() { + for i := range recv.Owners { + if recv.Candidates[i] { + result.Owners = append(result.Owners, recv.Owners[i]) + result.Operators = append(result.Operators, recv.Operators[i]) + result.Stakes = append(result.Stakes, recv.Stakes[i]) + if len(recv.BlsPublicKeys[i]) == types.BLSPublicKeyLength { + result.VoteAddresses = append(result.VoteAddresses, types.BLSPublicKey(recv.BlsPublicKeys[i])) + } else { + // set empty key if bls pub key is not registered on contract + result.VoteAddresses = append(result.VoteAddresses, types.BLSPublicKey{}) + } + } + } + } + ) + if err := callGetHighStakesCommon(ethAPI, hash, epoch, candidateManager2, &recv, processCallResult); err != nil { + return nil, err + } + + return &result, nil +} + +func callGetHighStakesCommon(ethAPI blockchainAPI, hash common.Hash, epoch uint64, manager *builtinContract, v interface{}, processCallResult func()) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() var ( method = "getHighStakes" - result nextValidators bpoch = new(big.Int).SetUint64(epoch) cursor = big.NewInt(0) howMany = big.NewInt(100) ) for { - data, err := candidateManager.abi.Pack(method, bpoch, cursor, howMany) + data, err := manager.abi.Pack(method, bpoch, cursor, howMany) if err != nil { - return nil, err + return err } hexData := (hexutil.Bytes)(data) @@ -396,7 +523,7 @@ func callGetHighStakes(ethAPI blockchainAPI, hash common.Hash, epoch uint64) (*n rbytes, err := ethAPI.Call( ctx, ethapi.TransactionArgs{ - To: &candidateManager.address, + To: &manager.address, Data: &hexData, }, &blockNrOrHash, @@ -404,36 +531,29 @@ func callGetHighStakes(ethAPI blockchainAPI, hash common.Hash, epoch uint64) (*n nil, ) if err != nil { - return nil, err + return err } - var recv struct { - Owners []common.Address - Operators []common.Address - Stakes []*big.Int - Candidates []bool - NewCursor *big.Int + if err := manager.abi.UnpackIntoInterface(v, method, rbytes); err != nil { + return err + } - // unused - Actives, Jailed []bool + // we assume that the `Owners` field and the `NewCursor` field are always present + vOwners := reflect.ValueOf(v).Elem().FieldByName("Owners") + vCursor := reflect.ValueOf(v).Elem().FieldByName("NewCursor") + if !vOwners.IsValid() || !vCursor.IsValid() { + panic("Owners or NewCursor field are not found. unexpected value is present as getHighStakes's output") } - if err := candidateManager.abi.UnpackIntoInterface(&recv, method, rbytes); err != nil { - return nil, err - } else if len(recv.Owners) == 0 { + + if vOwners.Len() == 0 { break } - cursor = recv.NewCursor - for i := range recv.Owners { - if recv.Candidates[i] { - result.Owners = append(result.Owners, recv.Owners[i]) - result.Operators = append(result.Operators, recv.Operators[i]) - result.Stakes = append(result.Stakes, recv.Stakes[i]) - } - } + cursor, _ = vCursor.Interface().(*big.Int) + processCallResult() // callback to process the received data } - return &result, nil + return nil } // Call the `StakeManager.getValidatorOwners` method. diff --git a/consensus/oasys/contract_test.go b/consensus/oasys/contract_test.go index 18432758c..d976f7f71 100644 --- a/consensus/oasys/contract_test.go +++ b/consensus/oasys/contract_test.go @@ -6,6 +6,7 @@ import ( "fmt" "math/big" "os" + "reflect" "testing" "github.com/ethereum/go-ethereum/accounts" @@ -161,6 +162,7 @@ func TestGetNextValidators(t *testing.T) { uint256ArrTy, _ := abi.NewType("uint256[]", "", nil) boolArrTy, _ := abi.NewType("bool[]", "", nil) uint256Ty, _ := abi.NewType("uint256", "", nil) + bytesTy, _ := abi.NewType("bytes[]", "", nil) // Return value of the `StakeManager.getValidators` method. returnTy1 := abi.Arguments{ @@ -178,6 +180,7 @@ func TestGetNextValidators(t *testing.T) { {Type: boolArrTy}, // actives {Type: boolArrTy}, // jailed {Type: uint256ArrTy}, // stakes + {Type: bytesTy}, // blsPubKeys {Type: boolArrTy}, // candidates {Type: uint256Ty}, // newCursor } @@ -216,6 +219,7 @@ func TestGetNextValidators(t *testing.T) { actives = make([]bool, howMany) jailed = make([]bool, howMany) stakes = make([]*big.Int, howMany) + blsPubKeys = make([][]byte, howMany) candidates = make([]bool, howMany) ) for j := 0; j < howMany; j++ { @@ -226,6 +230,7 @@ func TestGetNextValidators(t *testing.T) { actives[j] = true jailed[j] = false stakes[j] = wantStakes[idx] + blsPubKeys[j] = []byte{0x0} candidates[j] = true } else { owners[j] = common.Address{} @@ -233,6 +238,7 @@ func TestGetNextValidators(t *testing.T) { actives[j] = true jailed[j] = false stakes[j] = big.NewInt(0) + blsPubKeys[j] = []byte{0x0} candidates[j] = false } } @@ -242,14 +248,14 @@ func TestGetNextValidators(t *testing.T) { rbyte, _ := returnTy1.Pack(owners, operators, stakes, candidates, bnewCursor) rbytes[stakeManager.address][i] = rbyte - rbyte, _ = returnTy2.Pack(owners, operators, actives, jailed, stakes, candidates, bnewCursor) + rbyte, _ = returnTy2.Pack(owners, operators, actives, jailed, stakes, blsPubKeys, candidates, bnewCursor) rbytes[candidateManager.address][i] = rbyte if i == page-1 { rbyte, _ := returnTy1.Pack([]common.Address{}, []common.Address{}, []*big.Int{}, []bool{}, bnewCursor) rbytes[stakeManager.address] = append(rbytes[stakeManager.address], rbyte) - rbyte, _ = returnTy2.Pack([]common.Address{}, []common.Address{}, []bool{}, []bool{}, []*big.Int{}, []bool{}, bnewCursor) + rbyte, _ = returnTy2.Pack([]common.Address{}, []common.Address{}, []bool{}, []bool{}, []*big.Int{}, [][]byte{}, []bool{}, bnewCursor) rbytes[candidateManager.address] = append(rbytes[candidateManager.address], rbyte) break @@ -262,7 +268,10 @@ func TestGetNextValidators(t *testing.T) { ethapi := &testBlockchainAPI{rbytes: rbytes} for _, block := range []uint64{1, 10} { - got, _ := getNextValidators(config, ethapi, common.Hash{}, 1, block) + got, err := getNextValidators(config, ethapi, common.Hash{}, 1, block) + if err != nil { + t.Fatalf("failed to call getNextValidators method: %v", err) + } if len(got.Owners) != len(wantOwners) { t.Errorf("invalid owners length, got: %d, want: %d", len(got.Owners), len(wantOwners)) @@ -395,6 +404,47 @@ func TestGetNextEnvironmentValue(t *testing.T) { } } +func TestSortByOwner(t *testing.T) { + // Initialize the nextValidators struct with unsorted data + nv := nextValidators{ + Owners: []common.Address{ + common.Address([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3}), + common.Address([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}), + common.Address([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}), + }, + Operators: make([]common.Address, 3), + Stakes: make([]*big.Int, 3), + VoteAddresses: []types.BLSPublicKey{ + types.BLSPublicKey([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}), + types.BLSPublicKey([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}), + types.BLSPublicKey([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3}), + }, + } + + // Expected sorted data + expectedOwners := []common.Address{ + common.Address([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}), + common.Address([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}), + common.Address([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3}), + } + expectedVoteAddresses := []types.BLSPublicKey{ + types.BLSPublicKey([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}), + types.BLSPublicKey([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3}), + types.BLSPublicKey([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}), + } + + // Sort the struct based on Owners + nv.SortByOwner() + + // Verify the sorting + if !reflect.DeepEqual(nv.Owners, expectedOwners) { + t.Errorf("Owners not sorted correctly, got %x, want %x", nv.Owners, expectedOwners) + } + if !reflect.DeepEqual(nv.VoteAddresses, expectedVoteAddresses) { + t.Errorf("VoteAddresses not sorted correctly, got %x, want %x", nv.VoteAddresses, expectedVoteAddresses) + } +} + var _ blockchainAPI = (*testBlockchainAPI)(nil) type testBlockchainAPI struct { diff --git a/consensus/oasys/oasys-genesis-contract-5675779 b/consensus/oasys/oasys-genesis-contract-5675779 new file mode 160000 index 000000000..567577925 --- /dev/null +++ b/consensus/oasys/oasys-genesis-contract-5675779 @@ -0,0 +1 @@ +Subproject commit 567577925fd8ca17dcc857c473d282a94f2d9069 diff --git a/consensus/oasys/oasys.go b/consensus/oasys/oasys.go index 9a4dc782f..d413d1e3d 100644 --- a/consensus/oasys/oasys.go +++ b/consensus/oasys/oasys.go @@ -4,7 +4,6 @@ import ( "bytes" "errors" "fmt" - "io" "math" "math/big" "sort" @@ -23,11 +22,14 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" lru "github.com/hashicorp/golang-lru" + "github.com/prysmaticlabs/prysm/v5/crypto/bls" + "github.com/willf/bitset" "golang.org/x/crypto/sha3" ) @@ -36,6 +38,15 @@ const ( inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory inmemorySignatures = 4096 // Number of recent block signatures to keep in memory + extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity + extraSeal = crypto.SignatureLength // Fixed number of extra-data suffix bytes reserved for signer seal + + envValuesLen = 32 * 9 + addressBytesLen = common.AddressLength + stakeBytesLen = 32 + validatorInfoBytesLen = addressBytesLen*2 + stakeBytesLen + types.BLSPublicKeyLength + validatorNumberSize = 1 // Fixed number of extra prefix bytes reserved for validator number + backoffWiggleTime = uint64(1) // second ) @@ -43,18 +54,18 @@ const ( var ( epochLength = uint64(30000) // Default number of blocks after which to checkpoint and reset the pending votes - extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity - extraSeal = crypto.SignatureLength // Fixed number of extra-data suffix bytes reserved for signer seal - uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW. diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures + bigMaxInt64 = big.NewInt(math.MaxInt64) ether = big.NewInt(1_000_000_000_000_000_000) totalSupply = new(big.Int).Mul(big.NewInt(10_000_000_000), ether) // From WhitePaper - BigMaxInt64 = big.NewInt(math.MaxInt64) + verifyVoteAttestationErrorCounter = metrics.NewRegisteredCounter("oasys/verifyVoteAttestation/error", nil) + updateAttestationErrorCounter = metrics.NewRegisteredCounter("oasys/updateAttestation/error", nil) + validVotesfromSelfCounter = metrics.NewRegisteredCounter("oasys/VerifyVote/self", nil) ) // Various error messages to mark blocks invalid. These should be private to @@ -115,6 +126,9 @@ var ( // errCoinBaseMisMatch is returned if a header's coinbase do not match with signature errCoinBaseMisMatch = errors.New("coinbase do not match with signature") + + // errNoEnvironmentValue is returned if the extra data does not contain the environment value + errNoEnvironmentValue = errors.New("no environment value in the extra data") ) var ( @@ -146,7 +160,7 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, er signature := header.Extra[len(header.Extra)-extraSeal:] // Recover the public key and the Ethereum address - pubkey, err := crypto.Ecrecover(SealHash(header).Bytes(), signature) + pubkey, err := crypto.Ecrecover(types.SealHash(header).Bytes(), signature) if err != nil { return common.Address{}, err } @@ -173,6 +187,7 @@ type Oasys struct { lock sync.RWMutex // Protects the signer fields ethAPI *ethapi.BlockChainAPI + VotePool consensus.VotePool txSigner types.Signer txSignFn TxSignerFn @@ -258,17 +273,23 @@ func (c *Oasys) verifyHeader(chain consensus.ChainHeaderReader, header *types.He if len(header.Extra) < extraVanity+extraSeal { return errMissingSignature } - // Ensure that the extra-data contains a validator list on checkpoint, but none otherwise - env, err := c.environment(chain, header, parents) + // Apply parent headers to the snapshot, the snapshot updates is only processed here. + snap, err := c.snapshot(chain, number-1, header.ParentHash, parents) if err != nil { - return err + return fmt.Errorf("failed to retrieve snapshot, in: verifyHeader, blockNumber: %d, parentHash: %x, err: %v", number, header.ParentHash, err) } - validatorBytes := len(header.Extra) - extraVanity - extraSeal + // Get the environment value from snapshot except the block is epoch block + env, err := c.environment(chain, header, snap, true) + if err != nil { + return fmt.Errorf("failed to get environment value, in: verifyHeader, err: %v", err) + } + // Ensure that the extra-data contains extra data aside from the vanity and seal + extraLenExceptVanityAndSeal := len(header.Extra) - extraVanity - extraSeal if env.IsEpoch(number) { - if err := c.verifyExtraHeaderLengthInEpoch(header.Number, validatorBytes); err != nil { + if err := c.verifyExtraHeaderLengthInEpoch(header.Number, extraLenExceptVanityAndSeal); err != nil { return err } - } else if validatorBytes != 0 { + } else if !c.chainConfig.IsFastFinalityEnabled(header.Number) && extraLenExceptVanityAndSeal != 0 { return errExtraSigners } // Ensure that the mix digest is zero as we don't have fork protection currently @@ -304,14 +325,14 @@ func (c *Oasys) verifyHeader(chain consensus.ChainHeaderReader, header *types.He return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot) } // All basic checks passed, verify cascading fields - return c.verifyCascadingFields(chain, header, parents, env) + return c.verifyCascadingFields(chain, header, parents, snap, env) } // verifyCascadingFields verifies all the header fields that are not standalone, // rather depend on a batch of previous headers. The caller may optionally pass // in a batch of parents (ascending order) to avoid looking those up from the // database. This is useful for concurrently verifying a batch of new headers. -func (c *Oasys) verifyCascadingFields(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, env *params.EnvironmentValue) error { +func (c *Oasys) verifyCascadingFields(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, snap *Snapshot, env *params.EnvironmentValue) error { // The genesis block is the always valid dead-end number := header.Number.Uint64() if number == 0 { @@ -329,33 +350,15 @@ func (c *Oasys) verifyCascadingFields(chain consensus.ChainHeaderReader, header return consensus.ErrUnknownAncestor } - // Ensure that the block's timestamp is older than the scheduled validator backoff time - var ( - validators []common.Address - stakes []*big.Int - ) - if number > 0 && env.IsEpoch(number) { - // TODO: Extract the validators from header extra data - // Now the keccak256 hash of the validators is stored in the extra data. - // To avoid ethapi call, we need to store each validator's address and stake amount. - result, err := getNextValidators(c.chainConfig, c.ethAPI, header.ParentHash, env.Epoch(number), number) - if err != nil { - log.Error("Failed to get validators", "in", "verifyCascadingFields", "hash", header.ParentHash, "number", number, "err", err) - return err - } - validators, stakes = result.Operators, result.Stakes - } else { - // Retrieve the snapshot needed to verify this header and cache it - snap, err := c.snapshot(chain, number-1, header.ParentHash, parents) - if err != nil { - return err - } - validators, stakes = snap.validatorsToTuple() + // Get the validators from snapshot except the block is epoch block + validators, err := c.getNextValidators(chain, header, snap, true) + if err != nil { + return fmt.Errorf("failed to get validators, in: verifyCascadingFields, err: %v", err) } - scheduler, err := c.scheduler(chain, header, env, validators, stakes) + // Ensure that the block's timestamp is older than the scheduled validator backoff time + scheduler, err := c.scheduler(chain, header, env, validators.Operators, validators.Stakes) if err != nil { - log.Error("Failed to get scheduler", "in", "verifyCascadingFields", "number", number, "err", err) - return err + return fmt.Errorf("failed to get scheduler. blockNumber: %d, in: verifyCascadingFields, err: %v", number, err) } if header.Time < parent.Time+env.BlockPeriod.Uint64()+scheduler.backOffTime(number, header.Coinbase) { return consensus.ErrFutureBlock @@ -378,11 +381,254 @@ func (c *Oasys) verifyCascadingFields(chain consensus.ChainHeaderReader, header return err } + // Verify vote attestation for fast finality. + if err := c.verifyVoteAttestation(chain, header, parents, env); err != nil { + log.Warn("Verify vote attestation failed", "error", err, "hash", header.Hash(), "number", header.Number, + "parent", header.ParentHash, "coinbase", header.Coinbase, "extra", common.Bytes2Hex(header.Extra)) + verifyVoteAttestationErrorCounter.Inc(1) + if chain.Config().IsFastFinalityEnabled(header.Number) { + return err + } + } + // All basic checks passed, verify the seal and return return c.verifySeal(chain, header, parents, scheduler) } +// getParent returns the parent of a given block. +func (o *Oasys) getParent(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) (*types.Header, error) { + var parent *types.Header + number := header.Number.Uint64() + if len(parents) > 0 { + parent = parents[len(parents)-1] + } else { + parent = chain.GetHeader(header.ParentHash, number-1) + } + + if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { + return nil, consensus.ErrUnknownAncestor + } + return parent, nil +} + +// verifyVoteAttestation checks whether the vote attestation in the header is valid. +func (o *Oasys) verifyVoteAttestation(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, env *params.EnvironmentValue) error { + attestation, err := getVoteAttestationFromHeader(header, o.chainConfig, o.config, env.IsEpoch(header.Number.Uint64())) + if err != nil { + return err + } + if attestation == nil { + return nil + } + if attestation.Data == nil { + return errors.New("invalid attestation, vote data is nil") + } + if len(attestation.Extra) > types.MaxAttestationExtraLength { + return fmt.Errorf("invalid attestation, too large extra length: %d", len(attestation.Extra)) + } + + // Get parent block + parent, err := o.getParent(chain, header, parents) + if err != nil { + return err + } + + // The target block should be direct parent. + targetNumber := attestation.Data.TargetNumber + targetHash := attestation.Data.TargetHash + if targetNumber != parent.Number.Uint64() || targetHash != parent.Hash() { + return fmt.Errorf("invalid attestation, target mismatch, expected block: %d, hash: %s; real block: %d, hash: %s", + parent.Number.Uint64(), parent.Hash(), targetNumber, targetHash) + } + + // The source block should be the highest justified block. + sourceNumber := attestation.Data.SourceNumber + sourceHash := attestation.Data.SourceHash + headers := []*types.Header{parent} + if len(parents) > 0 { + headers = parents + } + justifiedBlockNumber, justifiedBlockHash, err := o.GetJustifiedNumberAndHash(chain, headers) + if err != nil { + return errors.New("unexpected error when getting the highest justified number and hash") + } + if sourceNumber != justifiedBlockNumber || sourceHash != justifiedBlockHash { + return fmt.Errorf("invalid attestation, source mismatch, expected block: %d, hash: %s; real block: %d, hash: %s", + justifiedBlockNumber, justifiedBlockHash, sourceNumber, sourceHash) + } + + // The snapshot should be the targetNumber-1 block's snapshot. + snap, err := o.snapshot(chain, parent.Number.Uint64()-1, parent.ParentHash, nil) + if err != nil { + return err + } + validators, err := o.getNextValidators(chain, header, snap, true) + if err != nil { + return fmt.Errorf("failed to get validators, in: verifyVoteAttestation, err: %v", err) + } + + // Filter out valid validator from attestation. + validatorsBitSet := bitset.From([]uint64{uint64(attestation.VoteAddressSet)}) + if validatorsBitSet.Count() > uint(len(validators.Operators)) { + return fmt.Errorf("invalid attestation, vote number(=%d) larger than validators number(=%d)", validatorsBitSet.Count(), len(validators.Operators)) + } + votedAddrs := make([]types.BLSPublicKey, 0, validatorsBitSet.Count()) + votedPubKeys := make([]bls.PublicKey, 0, validatorsBitSet.Count()) + for i := range validators.Operators { + voterIndex := i + 1 + if !validatorsBitSet.Test(uint(voterIndex)) { + continue + } + votedAddrs = append(votedAddrs, validators.VoteAddresses[i]) + votedPubKey, err := bls.PublicKeyFromBytes(validators.VoteAddresses[i][:]) + if err != nil { + return fmt.Errorf("BLS public key converts failed: %v", err) + } + votedPubKeys = append(votedPubKeys, votedPubKey) + } + + // The valid voted validators should be no less than 2/3 voting power. + if !isSufficientVotes(votedAddrs, validators) { + return errors.New("invalid attestation, not enough voting power voted") + } + + // Verify the aggregated signature. + aggSig, err := bls.SignatureFromBytes(attestation.AggSignature[:]) + if err != nil { + return fmt.Errorf("BLS signature converts failed: %v", err) + } + if !aggSig.FastAggregateVerify(votedPubKeys, attestation.Data.Hash()) { + return errors.New("invalid attestation, signature verify failed") + } + + return nil +} + +func isSufficientVotes(votedAddrs []types.BLSPublicKey, validators *nextValidators) bool { + totalStake := big.NewInt(0) + voterTotalStake := big.NewInt(0) + for i, stake := range validators.Stakes { + totalStake.Add(totalStake, stake) + for _, voteAddr := range votedAddrs { + if voteAddr == validators.VoteAddresses[i] { + voterTotalStake.Add(voterTotalStake, stake) + break + } + } + } + // the voter's total stake should be greater than 2/3 of the total stake + threshold := new(big.Int).Mul(totalStake, big.NewInt(2)) + threshold.Div(threshold, big.NewInt(3)) + return voterTotalStake.Cmp(threshold) >= 0 +} + +// getValidatorsFromHeader returns the next validators extracted from the header's extra field if exists. +// The validators bytes would be contained only in the epoch block's header, and its each validator bytes length is fixed. +// Layout: |--Extra Vanity--|--EnvironmentValue--| --Validator Number--|--Owner(or Empty)--|--Operator(or Empty)--|---Stake(or Empty)--|--Vote Address(or Empty)--|--Vote Attestation(or Empty)--|--Extra Seal--| +func getValidatorsFromHeader(header *types.Header) (*nextValidators, error) { + if len(header.Extra) <= extraVanity+extraSeal { + return nil, fmt.Errorf("no validators in the extra data, extra length: %d", len(header.Extra)) + } + + num := int(header.Extra[extraVanity+envValuesLen]) + lenNoAttestation := extraVanity + envValuesLen + validatorNumberSize + num*validatorInfoBytesLen + if num == 0 || len(header.Extra) < lenNoAttestation { + return nil, fmt.Errorf("missing validator info in the extra data, extra length: %d", len(header.Extra)) + } + + vals := &nextValidators{ + Owners: make([]common.Address, num), + Operators: make([]common.Address, num), + Stakes: make([]*big.Int, num), + VoteAddresses: make([]types.BLSPublicKey, num), + } + start := extraVanity + envValuesLen + validatorNumberSize + for i := 0; i < num; i++ { + copy(vals.Owners[i][:], header.Extra[start:start+addressBytesLen]) + start += addressBytesLen + copy(vals.Operators[i][:], header.Extra[start:start+addressBytesLen]) + start += addressBytesLen + vals.Stakes[i] = new(big.Int).SetBytes(header.Extra[start : start+stakeBytesLen]) + start += stakeBytesLen + copy(vals.VoteAddresses[i][:], header.Extra[start:start+types.BLSPublicKeyLength]) + start += types.BLSPublicKeyLength + } + + return vals, nil +} + +func getEnvironmentFromHeader(header *types.Header) (*params.EnvironmentValue, error) { + // As the vote attestation length is not determistically fixed, we omit the vote attestation info + // even if the vote attestations are included, the length is enough smaller than the environment value + if len(header.Extra) < extraVanity+envValuesLen+extraSeal { + return nil, errNoEnvironmentValue + } + + start := extraVanity + end := start + envValuesLen + env := new(params.EnvironmentValue) + if err := environment.abi.UnpackIntoInterface(&env, "value", header.Extra[start:end]); err != nil { + return nil, err + } + return env, nil +} + +// getVoteAttestationFromHeader returns the vote attestation extracted from the header's extra field if exists. +func getVoteAttestationFromHeader(header *types.Header, chainConfig *params.ChainConfig, oasysConfig *params.OasysConfig, isEpoch bool) (*types.VoteAttestation, error) { + if len(header.Extra) <= extraVanity+extraSeal { + return nil, nil + } + + if !chainConfig.IsFastFinalityEnabled(header.Number) { + return nil, nil + } + + var attestationBytes []byte + if isEpoch { + // Strictly check the length because it might be called from the + // `DecodeVoteAttestation(...)` even though it is not actually an epoch block. + var num int + if len(header.Extra) >= extraVanity+envValuesLen { + num = int(header.Extra[extraVanity+envValuesLen]) + } + if len(header.Extra) <= extraVanity+extraSeal+validatorNumberSize+num*validatorInfoBytesLen { + return nil, nil + } + start := extraVanity + envValuesLen + validatorNumberSize + num*validatorInfoBytesLen + end := len(header.Extra) - extraSeal + attestationBytes = header.Extra[start:end] + } else { + attestationBytes = header.Extra[extraVanity : len(header.Extra)-extraSeal] + } + + // exit if no attestation info + if len(attestationBytes) == 0 { + return nil, nil + } + + var attestation types.VoteAttestation + if err := rlp.Decode(bytes.NewReader(attestationBytes), &attestation); err != nil { + return nil, fmt.Errorf("block %d has vote attestation info, decode err: %s", header.Number.Uint64(), err) + } + return &attestation, nil +} + +// Decode vote atestation from the block header. It is a wrapper method that allows +// calls from outside the consensus engine. The provided block header may depend on +// an unknown ancestor, so it must not access the Environment or Snapshot. +func (o *Oasys) DecodeVoteAttestation(header *types.Header) *types.VoteAttestation { + attestation, _ := getVoteAttestationFromHeader(header, o.chainConfig, o.config, false) + if attestation == nil { + // Possible epoch block. + attestation, _ = getVoteAttestationFromHeader(header, o.chainConfig, o.config, true) + } + return attestation +} + // snapshot retrieves the authorization snapshot at a given point in time. +// !!! be careful +// the block with `number` and `hash` is just the last element of `parents`, +// unlike other interfaces such as verifyCascadingFields, `parents` are real parents func (c *Oasys) snapshot(chain consensus.ChainHeaderReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) { // Search for a snapshot in memory or on disk for checkpoints var ( @@ -454,7 +700,7 @@ func (c *Oasys) snapshot(chain consensus.ChainHeaderReader, number uint64, hash for i := 0; i < len(headers)/2; i++ { headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i] } - snap, err := snap.apply(headers, chain) + snap, err := snap.apply(headers, chain, c.config) if err != nil { return nil, err } @@ -512,6 +758,149 @@ func (c *Oasys) verifySeal(chain consensus.ChainHeaderReader, header *types.Head return nil } +func assembleValidators(validators *nextValidators) []byte { + extra := make([]byte, 0, validatorNumberSize+len(validators.Operators)*common.AddressLength) + // add validator number + extra = append(extra, byte(len(validators.Operators))) + // sanity check + if 256 <= len(validators.Operators) { + // As the number of validators is stored in a single byte, it should be less than 256 + // Though the logically max number of validators is 1000(10M*1000=supply), + // the practical max is around 100, as the average staking of a validator is 100M. + panic("too many validators") + } + // add validator info + for i := 0; i < len(validators.Operators); i++ { + extra = append(extra, validators.Owners[i].Bytes()...) + extra = append(extra, validators.Operators[i].Bytes()...) + extra = append(extra, common.LeftPadBytes(validators.Stakes[i].Bytes(), 32)...) + extra = append(extra, validators.VoteAddresses[i][:]...) + } + return extra +} + +func assembleEnvironmentValue(env *params.EnvironmentValue) []byte { + extra := make([]byte, 0, envValuesLen) + extra = append(extra, common.LeftPadBytes(env.StartBlock.Bytes(), 32)...) + extra = append(extra, common.LeftPadBytes(env.StartEpoch.Bytes(), 32)...) + extra = append(extra, common.LeftPadBytes(env.BlockPeriod.Bytes(), 32)...) + extra = append(extra, common.LeftPadBytes(env.EpochPeriod.Bytes(), 32)...) + extra = append(extra, common.LeftPadBytes(env.RewardRate.Bytes(), 32)...) + extra = append(extra, common.LeftPadBytes(env.CommissionRate.Bytes(), 32)...) + extra = append(extra, common.LeftPadBytes(env.ValidatorThreshold.Bytes(), 32)...) + extra = append(extra, common.LeftPadBytes(env.JailThreshold.Bytes(), 32)...) + extra = append(extra, common.LeftPadBytes(env.JailPeriod.Bytes(), 32)...) + return extra +} + +func (c *Oasys) assembleVoteAttestation(chain consensus.ChainHeaderReader, header *types.Header) error { + if !c.chainConfig.IsFastFinalityEnabled(header.Number) || header.Number.Uint64() < 2 { + return nil + } + + if c.VotePool == nil { + return nil + } + + // Fetch direct parent's votes + parent := chain.GetHeaderByHash(header.ParentHash) + if parent == nil { + return errors.New("parent not found") + } + votes := c.VotePool.FetchVoteByBlockHash(parent.Hash()) + if len(votes) == 0 { + log.Debug("no votes found, skip assemble vote attestation", "header", header.Hash(), "number", header.Number, "parent", parent.Hash()) + return nil + } + + // Get validators of target block(=parent block) + snap, err := c.snapshot(chain, parent.Number.Uint64()-1, parent.ParentHash, nil) + if err != nil { + return err + } + validators, err := c.getNextValidators(chain, header, snap, true) + if err != nil { + return fmt.Errorf("failed to get validators, in: assembleVoteAttestation, err: %v", err) + } + + // Check if the number of votes is sufficient + votedAddrs := make([]types.BLSPublicKey, 0, len(votes)) + for _, vote := range votes { + votedAddrs = append(votedAddrs, vote.VoteAddress) + } + if !isSufficientVotes(votedAddrs, validators) { + log.Debug("vote number less than 2/3 voting power, skip assemble vote attestation", "header", header.Hash(), "number", header.Number, "parent", parent.Hash(), "votes", len(votes)) + return nil + } + + // Prepare vote attestation + // Prepare vote data + justifiedBlockNumber, justifiedBlockHash, err := c.GetJustifiedNumberAndHash(chain, []*types.Header{parent}) + if err != nil { + return errors.New("unexpected error when getting the highest justified number and hash") + } + attestation := &types.VoteAttestation{ + Data: &types.VoteData{ + SourceNumber: justifiedBlockNumber, + SourceHash: justifiedBlockHash, + TargetNumber: parent.Number.Uint64(), + TargetHash: parent.Hash(), + }, + } + // Check vote data from votes + for _, vote := range votes { + if vote.Data.Hash() != attestation.Data.Hash() { + return fmt.Errorf("vote check error, expected: %v, real: %v", attestation.Data, vote) + } + } + // Prepare aggregated vote signature + voteAddrSet := make(map[types.BLSPublicKey]struct{}, len(votes)) + signatures := make([][]byte, 0, len(votes)) + for _, vote := range votes { + voteAddrSet[vote.VoteAddress] = struct{}{} + signatures = append(signatures, vote.Signature[:]) + } + sigs, err := bls.MultipleSignaturesFromBytes(signatures) + if err != nil { + return err + } + copy(attestation.AggSignature[:], bls.AggregateSignatures(sigs).Marshal()) + // Prepare vote address bitset. + for i, voteAddr := range validators.VoteAddresses { + if _, ok := voteAddrSet[voteAddr]; ok { + voterIndex := i + 1 + // sanity check + if 64 <= voterIndex { + // As the bitset is uint64, it should be less than 64 + return errors.New("too many validators") + } + attestation.VoteAddressSet |= 1 << voterIndex + } + } + validatorsBitSet := bitset.From([]uint64{uint64(attestation.VoteAddressSet)}) + if validatorsBitSet.Count() < uint(len(signatures)) { + log.Warn(fmt.Sprintf("assembleVoteAttestation, check VoteAddress Set failed, expected:%d, real:%d", len(signatures), validatorsBitSet.Count())) + return errors.New("invalid attestation, check VoteAddress Set failed") + } + + // Append attestation to header extra field. + buf := new(bytes.Buffer) + err = rlp.Encode(buf, attestation) + if err != nil { + return err + } + + // Insert vote attestation into header extra ahead extra seal. + extraSealStart := len(header.Extra) - extraSeal + extraSealBytes := header.Extra[extraSealStart:] + header.Extra = append(header.Extra[0:extraSealStart], buf.Bytes()...) + header.Extra = append(header.Extra, extraSealBytes...) + + log.Debug("successfully assemble vote attestation", "header", header.Hash(), "number", header.Number, "justifiedBlockNumber", attestation.Data.TargetNumber, "finalizeBlockNumber", attestation.Data.SourceNumber) + + return nil +} + // Prepare implements consensus.Engine, preparing all the consensus fields of the // header for running the transactions on top. func (c *Oasys) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { @@ -522,48 +911,43 @@ func (c *Oasys) Prepare(chain consensus.ChainHeaderReader, header *types.Header) // Mix digest is reserved for now, set to empty header.MixDigest = common.Hash{} - env, err := c.environment(chain, header, nil) - if err != nil { - return err - } - // Ensure the extra data has all its components if len(header.Extra) < extraVanity { header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...) } header.Extra = header.Extra[:extraVanity] - var ( - validators []common.Address - stakes []*big.Int - ) - if number > 0 && env.IsEpoch(number) { - result, err := getNextValidators(c.chainConfig, c.ethAPI, header.ParentHash, env.Epoch(number), number) - if err != nil { - log.Error("Failed to get validators", "in", "Prepare", "hash", header.ParentHash, "number", number, "err", err) - return err - } - validators, stakes = result.Operators, result.Stakes - header.Extra = append(header.Extra, c.getExtraHeaderValueInEpoch(header.Number, validators)...) - } else { - snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) - if err != nil { - return err - } - validators, stakes = snap.validatorsToTuple() + snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) + if err != nil { + return fmt.Errorf("failed to retrieve snapshot, in: Prepare, blockNumber: %d, parentHash: %x, err: %v", number, header.ParentHash, err) } - scheduler, err := c.scheduler(chain, header, env, validators, stakes) + env, err := c.environment(chain, header, snap, false) if err != nil { - log.Error("Failed to get scheduler", "in", "Prepare", "number", number, "err", err) - return err + return fmt.Errorf("failed to get environment, in: Prepare, err: %v", err) + } + validators, err := c.getNextValidators(chain, header, snap, false) + if err != nil { + return fmt.Errorf("failed to get validators, in: Prepare, err: %v", err) } - - // Add extra seal - header.Extra = append(header.Extra, make([]byte, extraSeal)...) // Add the difficulty + scheduler, err := c.scheduler(chain, header, env, validators.Operators, validators.Stakes) + if err != nil { + return fmt.Errorf("failed to get scheduler, in: Prepare, blockNumber: %d, err: %v", number, err) + } header.Difficulty = scheduler.difficulty(number, c.signer, c.chainConfig.IsForkedOasysExtendDifficulty(header.Number)) + // Add validators to the extra data + if env.IsEpoch(number) { + if c.chainConfig.IsFastFinalityEnabled(header.Number) { + header.Extra = append(header.Extra, assembleEnvironmentValue(env)...) + } + header.Extra = append(header.Extra, c.getExtraHeaderValueInEpoch(header.Number, validators)...) + } + + // Add extra seal + header.Extra = append(header.Extra, make([]byte, extraSeal)...) + // Ensure the timestamp has the correct delay parent := chain.GetHeader(header.ParentHash, number-1) if parent == nil { @@ -596,61 +980,50 @@ func (c *Oasys) Finalize(chain consensus.ChainHeaderReader, header *types.Header if number == 1 { err := c.initializeSystemContracts(state, header, cx, txs, receipts, systemTxs, usedGas, false) if err != nil { - log.Error("Failed to initialize system contracts", "in", "Finalize", "hash", hash, "number", number, "err", err) - return err + return fmt.Errorf("failed to initialize system contracts, in: Finalize, blockNumber: %d, blockHash: %s, err: %v", number, hash, err) } } - env, err := c.environment(chain, header, nil) + snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) if err != nil { - return err + return fmt.Errorf("failed to retrieve snapshot, in: Finalize, blockNumber: %d, parentHash: %x, err: %v", number, header.ParentHash, err) } - - var ( - validators []common.Address - stakes []*big.Int - ) - if env.IsEpoch(number) { - result, err := getNextValidators(c.chainConfig, c.ethAPI, header.ParentHash, env.Epoch(number), number) - if err != nil { - log.Error("Failed to get validators", "in", "Finalize", "hash", header.ParentHash, "number", number, "err", err) - return err - } - validators, stakes = result.Operators, result.Stakes - } else { - snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) - if err != nil { - return err - } - validators, stakes = snap.validatorsToTuple() - } - scheduler, err := c.scheduler(chain, header, env, validators, stakes) + // Get from contract, not from header. + // This value is made sure to be the same as the value from header in verifyExtraHeaderValueInEpoch. + fromHeader := false + env, err := c.environment(chain, header, snap, fromHeader) if err != nil { - log.Error("Failed to get scheduler", "in", "Finalize", "number", number, "err", err) - return err + return fmt.Errorf("failed to get environment, in: Finalize, err: %v", err) } - - if err := c.addBalanceToStakeManager(state, header.ParentHash, number, env); err != nil { - log.Error("Failed to add balance to staking contract", "in", "Finalize", "hash", header.ParentHash, "number", number, "err", err) - return err + validators, err := c.getNextValidators(chain, header, snap, fromHeader) + if err != nil { + return fmt.Errorf("failed to get validators, in: Finalize, err: %v", err) } + // If the block is a epoch block, verify the validator list or hash if env.IsEpoch(number) { - // If the block is a epoch block, verify the validator list or hash actual := header.Extra[extraVanity : len(header.Extra)-extraSeal] - if err := c.verifyExtraHeaderValueInEpoch(header.Number, actual, validators); err != nil { + if err := c.verifyExtraHeaderValueInEpoch(header, actual, env, validators); err != nil { return err } } + if err := c.addBalanceToStakeManager(state, header.ParentHash, number, env); err != nil { + return fmt.Errorf("failed to add balance to staking contract, in: Finalize, blockNumber: %d, blockHash: %s, err: %v", number, hash, err) + } + if number >= c.config.Epoch { validator, err := ecrecover(header, c.signatures) if err != nil { return err } + scheduler, err := c.scheduler(chain, header, env, validators.Operators, validators.Stakes) + if err != nil { + return fmt.Errorf("failed to get scheduler, in: Finalize, blockNumber: %d, blockHash: %s, err: %v", number, hash, err) + } if expected := *scheduler.expect(number); expected != validator { if err := c.slash(expected, scheduler.schedules(), state, header, cx, txs, receipts, systemTxs, usedGas, false); err != nil { - log.Error("Failed to slash validator", "in", "Finalize", "hash", hash, "number", number, "address", expected, "err", err) + log.Warn("failed to slash validator", "in", "Finalize", "hash", hash, "number", number, "address", expected, "err", err) } } } @@ -687,49 +1060,37 @@ func (c *Oasys) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *t if number == 1 { err := c.initializeSystemContracts(state, header, cx, &txs, &receipts, nil, &header.GasUsed, true) if err != nil { - log.Error("Failed to initialize system contracts", "in", "FinalizeAndAssemble", "hash", hash, "err", err) - return nil, nil, err + return nil, nil, fmt.Errorf("failed to initialize system contracts, in: FinalizeAndAssemble, blockNumber: %d, blockHash: %s, err: %v", number, hash, err) } } - env, err := c.environment(chain, header, nil) + snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to retrieve snapshot, in: FinalizeAndAssemble, blockNumber: %d, parentHash: %x, err: %v", number, header.ParentHash, err) } - - var ( - validators []common.Address - stakes []*big.Int - ) - if env.IsEpoch(number) { - result, err := getNextValidators(c.chainConfig, c.ethAPI, header.ParentHash, env.Epoch(number), number) - if err != nil { - log.Error("Failed to get validators", "in", "FinalizeAndAssemble", "hash", header.ParentHash, "number", number, "err", err) - return nil, nil, err - } - validators, stakes = result.Operators, result.Stakes - } else { - snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) - if err != nil { - return nil, nil, err - } - validators, stakes = snap.validatorsToTuple() + fromHeader := false // Not retrieve from header to be safe, even it's already in the header + env, err := c.environment(chain, header, snap, fromHeader) + if err != nil { + return nil, nil, fmt.Errorf("failed to get environment, in: FinalizeAndAssemble, err: %v", err) } - scheduler, err := c.scheduler(chain, header, env, validators, stakes) + validators, err := c.getNextValidators(chain, header, snap, fromHeader) if err != nil { - log.Error("Failed to get scheduler", "in", "FinalizeAndAssemble", "number", number, "err", err) - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get validators, in: FinalizeAndAssemble, err: %v", err) + } + + scheduler, err := c.scheduler(chain, header, env, validators.Operators, validators.Stakes) + if err != nil { + return nil, nil, fmt.Errorf("failed to get scheduler, in: FinalizeAndAssemble, blockNumber: %d, blockHash: %s, err: %v", number, hash, err) } if err := c.addBalanceToStakeManager(state, header.ParentHash, number, env); err != nil { - log.Error("Failed to add balance to staking contract", "in", "FinalizeAndAssemble", "hash", hash, "number", number, "err", err) - return nil, nil, err + return nil, nil, fmt.Errorf("failed to add balance to staking contract, in: FinalizeAndAssemble, blockNumber: %d, blockHash: %s, err: %v", number, hash, err) } if number >= c.config.Epoch { if expected := *scheduler.expect(number); expected != header.Coinbase { if err := c.slash(expected, scheduler.schedules(), state, header, cx, &txs, &receipts, nil, &header.GasUsed, true); err != nil { - log.Error("Failed to slash validator", "in", "FinalizeAndAssemble", "hash", hash, "number", number, "address", expected, "err", err) + log.Warn("failed to slash validator", "in", "FinalizeAndAssemble", "hash", hash, "number", number, "address", expected, "err", err) } } } @@ -743,6 +1104,73 @@ func (c *Oasys) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *t return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), receipts, nil } +func (c *Oasys) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *types.Header, checkVoteKeyFn func(bLSPublicKey *types.BLSPublicKey) bool) bool { + number := header.Number.Uint64() + snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) + if err != nil { + log.Warn("failed to get snapshot", "in", "IsActiveValidatorAt", "parentHash", header.ParentHash, "number", number, "err", err) + return false + } + validators, err := c.getNextValidators(chain, header, snap, true) + if err != nil { + log.Warn("failed to get validators", "in", "IsActiveValidatorAt", "err", err) + return false + } + for i, operator := range validators.Operators { + if operator == c.signer { + if checkVoteKeyFn == nil || checkVoteKeyFn(&validators.VoteAddresses[i]) { + return true + } + } + } + return false +} + +// VerifyVote will verify: 1. If the vote comes from valid validators 2. If the vote's sourceNumber and sourceHash are correct +func (c *Oasys) VerifyVote(chain consensus.ChainHeaderReader, vote *types.VoteEnvelope) error { + targetNumber := vote.Data.TargetNumber + targetHash := vote.Data.TargetHash + header := chain.GetHeaderByHash(targetHash) + if header == nil { + log.Warn("BlockHeader at current voteBlockNumber is nil", "targetNumber", targetNumber, "targetHash", targetHash) + return errors.New("BlockHeader at current voteBlockNumber is nil") + } + if header.Number.Uint64() != targetNumber { + log.Warn("unexpected target number", "expect", header.Number.Uint64(), "real", targetNumber) + return errors.New("target number mismatch") + } + + justifiedBlockNumber, justifiedBlockHash, err := c.GetJustifiedNumberAndHash(chain, []*types.Header{header}) + if err != nil { + log.Warn("failed to get the highest justified number and hash", "headerNumber", header.Number, "headerHash", header.Hash()) + return errors.New("unexpected error when getting the highest justified number and hash") + } + if vote.Data.SourceNumber != justifiedBlockNumber || vote.Data.SourceHash != justifiedBlockHash { + return errors.New("vote source block mismatch") + } + + number := header.Number.Uint64() + snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) + if err != nil { + return fmt.Errorf("failed to get the snapshot, in: VerifyVote, blockNumber: %d, parentHash: %s, err: %v", number, header.ParentHash, err) + } + validators, err := c.getNextValidators(chain, header, snap, true) + if err != nil { + return fmt.Errorf("failed to get the validators, in: VerifyVote, err: %v", err) + } + for i := range validators.Operators { + if validators.VoteAddresses[i] == vote.VoteAddress { + if validators.Operators[i] == c.signer { + validVotesfromSelfCounter.Inc(1) + } + metrics.GetOrRegisterCounter(fmt.Sprintf("oasys/VerifyVote/%s", validators.Operators[i].String()), nil).Inc(1) + return nil + } + } + + return errors.New("vote verification failed") +} + // Authorize injects a private key into the consensus engine to mint new blocks // with. func (c *Oasys) Authorize(signer common.Address, signFn SignerFn, txSignFn TxSignerFn) { @@ -773,40 +1201,23 @@ func (c *Oasys) Seal(chain consensus.ChainHeaderReader, block *types.Block, resu validator, signFn := c.signer, c.signFn c.lock.RUnlock() - env, err := c.environment(chain, header, nil) + // Bail out if we're unauthorized to sign a block + snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) if err != nil { - return err + return fmt.Errorf("failed to retrieve snapshot, in: Seal, blockNumber: %d, parentHash: %s, err: %v", number, header.ParentHash, err) } - - // Bail out if we're unauthorized to sign a block - var exists bool - if number > 0 && env.IsEpoch(number) { - result, err := getNextValidators(c.chainConfig, c.ethAPI, header.ParentHash, env.Epoch(number), number) - if err != nil { - log.Error("Failed to get validators", "in", "Seal", "hash", header.ParentHash, "number", number, "err", err) - return err - } - exists = result.Exists(validator) - } else { - snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) - if err != nil { - return err - } - exists = snap.exists(validator) + fromHeader := true // ok from header as the validators are assembled in `Prepare` phase + validators, err := c.getNextValidators(chain, header, snap, fromHeader) + if err != nil { + return fmt.Errorf("failed to get validators, in: Seal, err: %v", err) } - - if !exists { + if !validators.Exists(validator) { return errUnauthorizedValidator } // Sweet, the protocol permits us to sign the block, wait for our time delay := time.Until(time.Unix(int64(header.Time), 0)) - // Sign all the things! - sighash, err := signFn(accounts.Account{Address: validator}, accounts.MimetypeOasys, OasysRLP(header)) - if err != nil { - return err - } - copy(header.Extra[len(header.Extra)-extraSeal:], sighash) + // Wait until sealing is terminated or delay timeout. log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay)) go func() { @@ -816,10 +1227,25 @@ func (c *Oasys) Seal(chain consensus.ChainHeaderReader, block *types.Block, resu case <-time.After(delay): } + err := c.assembleVoteAttestation(chain, header) + if err != nil { + /* If the vote attestation can't be assembled successfully, the blockchain won't get + fast finalized, but it can be tolerated, so just report this error here. */ + log.Error("Assemble vote attestation failed when sealing", "err", err) + } + + // Sign all the things! + sighash, err := signFn(accounts.Account{Address: validator}, accounts.MimetypeOasys, OasysRLP(header)) + if err != nil { + log.Error("Sign for the block header failed when sealing", "err", err) + return + } + copy(header.Extra[len(header.Extra)-extraSeal:], sighash) + select { case results <- block.WithSeal(header): default: - log.Warn("Sealing result is not read by miner", "sealhash", SealHash(header)) + log.Warn("Sealing result is not read by miner", "sealhash", types.SealHash(header)) } }() @@ -831,41 +1257,37 @@ func (c *Oasys) Seal(chain consensus.ChainHeaderReader, block *types.Block, resu func (c *Oasys) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { number := parent.Number.Uint64() - env, err := c.environment(chain, parent, nil) + snap, err := c.snapshot(chain, number, parent.Hash(), nil) if err != nil { + log.Error("failed to get the snapshot", "in", "CalcDifficulty", "hash", parent.Hash(), "number", number, "err", err) return nil } - - var ( - validators []common.Address - stakes []*big.Int - ) - if env.IsEpoch(number) { - result, err := getNextValidators(c.chainConfig, c.ethAPI, parent.Hash(), env.Epoch(number), number) - if err != nil { - log.Error("Failed to get validators", "in", "Seal", "hash", parent.Hash(), "number", number, "err", err) - return nil - } - validators, stakes = result.Operators, result.Stakes - } else { - snap, err := c.snapshot(chain, number, parent.Hash(), nil) - if err != nil { - return nil - } - validators, stakes = snap.validatorsToTuple() + env, err := c.environment(chain, parent, snap, true) + if err != nil { + log.Error("failed to get the environment value", "in", "CalcDifficulty", "hash", parent.Hash(), "number", number, "err", err) + return nil } - scheduler, err := c.scheduler(chain, parent, env, validators, stakes) + validators, err := c.getNextValidators(chain, parent, snap, true) if err != nil { - log.Error("Failed to get scheduler", "in", "CalcDifficulty", "number", number, "err", err) + log.Error("failed to get validators", "in", "CalcDifficulty", "hash", parent.Hash(), "number", number, "err", err) + return nil + } + scheduler, err := c.scheduler(chain, parent, env, validators.Operators, validators.Stakes) + if err != nil { + log.Error("failed to get scheduler", "in", "CalcDifficulty", "hash", parent.Hash(), "number", number, "err", err) return nil } return scheduler.difficulty(number, c.signer, c.chainConfig.IsForkedOasysExtendDifficulty(parent.Number)) } -// SealHash returns the hash of a block prior to it being sealed. -func (c *Oasys) SealHash(header *types.Header) common.Hash { - return SealHash(header) +// SealHash returns the hash of a block without vote attestation prior to it being sealed. +// So it's not the real hash of a block, just used as unique id to distinguish task +func (c *Oasys) SealHash(header *types.Header) (hash common.Hash) { + hasher := sha3.NewLegacyKeccak256() + types.EncodeSigHeaderWithoutVoteAttestation(hasher, header) + hasher.Sum(hash[:0]) + return hash } // Close implements consensus.Engine. It's a noop for oasys as there are no background threads. @@ -884,59 +1306,163 @@ func (c *Oasys) APIs(chain consensus.ChainHeaderReader) []rpc.API { }} } -// Converting the validator list for the extra header field. -func (c *Oasys) getExtraHeaderValueInEpoch(number *big.Int, validators []common.Address) []byte { - cpy := make([]common.Address, len(validators)) - copy(cpy, validators) +// GetJustifiedNumberAndHash retrieves the number and hash of the highest justified block +// within the branch including `headers` and utilizing the latest element as the head. +func (c *Oasys) GetJustifiedNumberAndHash(chain consensus.ChainHeaderReader, headers []*types.Header) (uint64, common.Hash, error) { + if chain == nil || len(headers) == 0 || headers[len(headers)-1] == nil { + return 0, common.Hash{}, errors.New("illegal chain or header") + } + head := headers[len(headers)-1] + if !chain.Config().IsFastFinalityEnabled(head.Number) { + return 0, chain.GetHeaderByNumber(0).Hash(), nil + } + snap, err := c.snapshot(chain, head.Number.Uint64(), head.Hash(), nil) + if err != nil { + return 0, common.Hash{}, fmt.Errorf("unexpected error when getting snapshot in GetJustifiedNumberAndHash, blockNumber: %d, blockHash: %s, error: %v", head.Number.Uint64(), head.Hash(), err) + } - forked := c.chainConfig.IsForkedOasysPublication(number) - if !forked { - sort.Sort(validatorsAscending(cpy)) + if snap.Attestation == nil { + if c.chainConfig.IsFastFinalityEnabled(head.Number) { + log.Debug("once one attestation generated, attestation of snap would not be nil forever basically") + } + return 0, chain.GetHeaderByNumber(0).Hash(), nil } + return snap.Attestation.TargetNumber, snap.Attestation.TargetHash, nil +} - extra := make([]byte, len(cpy)*common.AddressLength) - for i, v := range cpy { - copy(extra[i*common.AddressLength:], v.Bytes()) +// GetFinalizedHeader returns highest finalized block header. +func (c *Oasys) GetFinalizedHeader(chain consensus.ChainHeaderReader, header *types.Header) *types.Header { + if chain == nil || header == nil { + return nil + } + if !chain.Config().IsFastFinalityEnabled(header.Number) { + return chain.GetHeaderByNumber(0) + } + snap, err := c.snapshot(chain, header.Number.Uint64(), header.Hash(), nil) + if err != nil { + log.Warn("Unexpected error when getting snapshot in GetFinalizedHeader", + "error", err, "blockNumber", header.Number.Uint64(), "blockHash", header.Hash()) + return nil } - // Convert to hash because there may be many validators. - if forked { - extra = crypto.Keccak256(extra) + if snap.Attestation == nil { + return chain.GetHeaderByNumber(0) // keep consistent with GetJustifiedNumberAndHash } - return extra + return chain.GetHeader(snap.Attestation.SourceHash, snap.Attestation.SourceNumber) +} + +func (c *Oasys) getNextValidators(chain consensus.ChainHeaderReader, header *types.Header, snap *Snapshot, fromHeader bool) (validators *nextValidators, err error) { + number := header.Number.Uint64() + if snap.Environment.IsEpoch(number) { + if fromHeader && c.chainConfig.IsFastFinalityEnabled(header.Number) { + if validators, err = getValidatorsFromHeader(header); err != nil { + log.Warn("failed to get validators from header", "in", "getNextValidators", "hash", header.Hash(), "number", number, "err", err) + } + } + // If not fast finality or failed to get validators from header + if validators == nil { + if validators, err = getNextValidators(c.chainConfig, c.ethAPI, header.ParentHash, snap.Environment.Epoch(number), number); err != nil { + err = fmt.Errorf("failed to get next validators, blockNumber: %d, parentHash: %s, error: %v", number, header.ParentHash, err) + return + } + } + } else { + // Notice! The owner list is empty, Don't access owners from validators taken from the snapshot. + validators = snap.ToNextValidators() + } + return +} + +// Converting the validator list for the extra header field. +func (c *Oasys) getExtraHeaderValueInEpoch(number *big.Int, validators *nextValidators) []byte { + if !c.chainConfig.IsFastFinalityEnabled(number) { + cpy := make([]common.Address, len(validators.Operators)) + copy(cpy, validators.Operators) + + forked := c.chainConfig.IsForkedOasysPublication(number) + if !forked { + sort.Sort(validatorsAscending(cpy)) + } + + extra := make([]byte, len(cpy)*common.AddressLength) + for i, v := range cpy { + copy(extra[i*common.AddressLength:], v.Bytes()) + } + + // Convert to hash because there may be many validators. + if forked { + extra = crypto.Keccak256(extra) + } + return extra + } + + return assembleValidators(validators) } // Verify the length of the Extra header field. func (c *Oasys) verifyExtraHeaderLengthInEpoch(number *big.Int, length int) error { - if c.chainConfig.IsForkedOasysPublication(number) { - if length != crypto.DigestLength { - return errInvalidEpochHash + if !c.chainConfig.IsFastFinalityEnabled(number) { + if c.chainConfig.IsForkedOasysPublication(number) { + if length != crypto.DigestLength { + return errInvalidEpochHash + } + } else if length%common.AddressLength != 0 { + return errInvalidCheckpointValidators } - } else if length%common.AddressLength != 0 { - return errInvalidCheckpointValidators + return nil + } + + // After Fast Finality enabled, go through following checks. + if length < envValuesLen { + return fmt.Errorf("missing environment value in extra header, length: %d", length) + } + // at least one validator info in extra header + // The exact extra header validation will be done in verifyExtraHeaderValueInEpoch during Finalize + if length < envValuesLen+validatorNumberSize+validatorInfoBytesLen { + return fmt.Errorf("missing validator info in extra header, length: %d", length) } return nil } // Verify the value of the Extra header field. -func (c *Oasys) verifyExtraHeaderValueInEpoch(number *big.Int, actual []byte, validators []common.Address) error { - expect := c.getExtraHeaderValueInEpoch(number, validators) - if bytes.Equal(actual, expect) { - return nil +func (c *Oasys) verifyExtraHeaderValueInEpoch(header *types.Header, actual []byte, actualEnv *params.EnvironmentValue, actualValidators *nextValidators) error { + if !c.chainConfig.IsFastFinalityEnabled(header.Number) { + expect := c.getExtraHeaderValueInEpoch(header.Number, actualValidators) + if bytes.Equal(actual, expect) { + return nil + } + if c.chainConfig.IsForkedOasysPublication(header.Number) { + return errMismatchingEpochHash + } + return errMismatchingEpochValidators } - if c.chainConfig.IsForkedOasysPublication(number) { - return errMismatchingEpochHash + // After Fast Finality enabled, go through following checks. + env, err := getEnvironmentFromHeader(header) + if err != nil { + return err + } + if err = actualEnv.Equal(env); err != nil { + return err } - return errMismatchingEpochValidators -} -// SealHash returns the hash of a block prior to it being sealed. -func SealHash(header *types.Header) (hash common.Hash) { - hasher := sha3.NewLegacyKeccak256() - encodeSigHeader(hasher, header) - hasher.(crypto.KeccakState).Read(hash[:]) - return hash + validators, err := getValidatorsFromHeader(header) + if err != nil { + return err + } + for i := 0; i < len(validators.Operators); i++ { + if !bytes.Equal(actualValidators.Operators[i].Bytes(), validators.Operators[i].Bytes()) { + return fmt.Errorf("mismatching operator, i: %d, expected: %v, real: %v", i, validators.Operators[i], actualValidators.Operators[i]) + } + if !bytes.Equal(actualValidators.Stakes[i].Bytes(), validators.Stakes[i].Bytes()) { + return fmt.Errorf("mismatching stake, i: %d, expected: %v, real: %v", i, validators.Stakes[i], actualValidators.Stakes[i]) + } + if !bytes.Equal(actualValidators.VoteAddresses[i][:], validators.VoteAddresses[i][:]) { + return fmt.Errorf("mismatching vote address, i: %d, expected: %v, real: %v", i, validators.VoteAddresses[i], actualValidators.VoteAddresses[i]) + } + } + + return nil } // OasysRLP returns the rlp bytes which needs to be signed for the proof-of-stake @@ -948,48 +1474,10 @@ func SealHash(header *types.Header) (hash common.Hash) { // or not), which could be abused to produce different hashes for the same header. func OasysRLP(header *types.Header) []byte { b := new(bytes.Buffer) - encodeSigHeader(b, header) + types.EncodeSigHeader(b, header) return b.Bytes() } -func encodeSigHeader(w io.Writer, header *types.Header) { - enc := []interface{}{ - header.ParentHash, - header.UncleHash, - header.Coinbase, - header.Root, - header.TxHash, - header.ReceiptHash, - header.Bloom, - header.Difficulty, - header.Number, - header.GasLimit, - header.GasUsed, - header.Time, - header.Extra[:len(header.Extra)-crypto.SignatureLength], // Yes, this will panic if extra is too short - header.MixDigest, - header.Nonce, - } - if header.BaseFee != nil { - enc = append(enc, header.BaseFee) - } - if header.WithdrawalsHash != nil { - panic("unexpected withdrawal hash value in oasys") - } - if header.ExcessBlobGas != nil { - panic("unexpected excess blob gas value in oasys") - } - if header.BlobGasUsed != nil { - panic("unexpected blob gas used value in oasys") - } - if header.ParentBeaconRoot != nil { - panic("unexpected parent beacon root value in oasys") - } - if err := rlp.Encode(w, enc); err != nil { - panic("can't encode: " + err.Error()) - } -} - func (c *Oasys) addBalanceToStakeManager(state *state.StateDB, hash common.Hash, number uint64, env *params.EnvironmentValue) error { if !env.IsEpoch(number) || env.Epoch(number) < 3 || env.Epoch(number) > 60 { return nil @@ -999,10 +1487,8 @@ func (c *Oasys) addBalanceToStakeManager(state *state.StateDB, hash common.Hash, rewards *big.Int err error ) - if rewards, err = getRewards(c.ethAPI, hash); err != nil { - log.Error("Failed to get rewards", "hash", hash, "err", err) - return err + return fmt.Errorf("failed to get rewards, blockNumber: %d, blockHash: %s, error: %v", number, hash, err) } if rewards.Cmp(common.Big0) == 0 { return nil @@ -1013,22 +1499,23 @@ func (c *Oasys) addBalanceToStakeManager(state *state.StateDB, hash common.Hash, return nil } -func (c *Oasys) environment(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) (*params.EnvironmentValue, error) { +func (c *Oasys) environment(chain consensus.ChainHeaderReader, header *types.Header, snap *Snapshot, fromHeader bool) (env *params.EnvironmentValue, err error) { number := header.Number.Uint64() if number < c.config.Epoch { return params.InitialEnvironmentValue(c.config), nil } - snap, err := c.snapshot(chain, number-1, header.ParentHash, parents) - if err != nil { - return nil, err - } - - var env *params.EnvironmentValue if snap.Environment.IsEpoch(number) { - if env, err = getNextEnvironmentValue(c.ethAPI, header.ParentHash); err != nil { - log.Error("Failed to get environment value", "in", "environment", "hash", header.ParentHash, "number", number, "err", err) - return nil, err + if fromHeader && chain.Config().IsFastFinalityEnabled(header.Number) { + if env, err = getEnvironmentFromHeader(header); err != nil { + log.Warn("failed to get environment value from header", "in", "environment", "hash", header.Hash(), "number", number, "err", err) + } + } + // If not fast finality or failed to get environment from header + if env == nil { + if env, err = getNextEnvironmentValue(c.ethAPI, header.ParentHash); err != nil { + return nil, fmt.Errorf("failed to get environment value, blockNumber: %d, parentHash: %s, error: %v", number, header.ParentHash, err) + } } } else { env = snap.Environment @@ -1072,7 +1559,7 @@ func (c *Oasys) scheduler(chain consensus.ChainHeaderReader, header *types.Heade var seed int64 if env.Epoch(number) >= c.chainConfig.OasysShortenedBlockTimeStartEpoch().Uint64() { // This has nothing to do with reducing block time, but it has been fixed for possible overflow. - seed = new(big.Int).Mod(seedHash.Big(), BigMaxInt64).Int64() + seed = new(big.Int).Mod(seedHash.Big(), bigMaxInt64).Int64() } else { seed = seedHash.Big().Int64() } diff --git a/consensus/oasys/oasys_test.go b/consensus/oasys/oasys_test.go new file mode 100644 index 000000000..c8f326b60 --- /dev/null +++ b/consensus/oasys/oasys_test.go @@ -0,0 +1,113 @@ +package oasys + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie/testutil" + "github.com/stretchr/testify/require" +) + +func TestAssembleEnvAndValidators(t *testing.T) { + var ( + header = &types.Header{Extra: make([]byte, extraVanity)} + config = ¶ms.OasysConfig{Period: 15, Epoch: 5760} + env = params.InitialEnvironmentValue(config) + size = 20 + validators = &nextValidators{ + Owners: make([]common.Address, size), + Operators: make([]common.Address, size), + Stakes: make([]*big.Int, size), + VoteAddresses: make([]types.BLSPublicKey, size), + } + ) + + for i := 0; i < size; i++ { + validators.Owners[i] = testutil.RandomAddress() + validators.Operators[i] = testutil.RandomAddress() + validators.Stakes[i] = newEth(int64(i)) + validators.VoteAddresses[i] = randomBLSPublicKey() + } + + // assemble + header.Extra = append(header.Extra, assembleEnvironmentValue(env)...) + require.Len(t, header.Extra, extraVanity+envValuesLen) + header.Extra = append(header.Extra, assembleValidators(validators)...) + require.Len(t, header.Extra, extraVanity+envValuesLen+validatorNumberSize+size*validatorInfoBytesLen) + + // disassemble + acturalEnv, err := getEnvironmentFromHeader(header) + require.NoError(t, err) + actualVals, err := getValidatorsFromHeader(header) + require.NoError(t, err) + + // assert env + require.ElementsMatch(t, env.StartBlock.Bytes(), acturalEnv.StartBlock.Bytes()) + require.ElementsMatch(t, env.StartEpoch.Bytes(), acturalEnv.StartEpoch.Bytes()) + require.ElementsMatch(t, env.BlockPeriod.Bytes(), acturalEnv.BlockPeriod.Bytes()) + require.ElementsMatch(t, env.EpochPeriod.Bytes(), acturalEnv.EpochPeriod.Bytes()) + require.ElementsMatch(t, env.RewardRate.Bytes(), acturalEnv.RewardRate.Bytes()) + require.ElementsMatch(t, env.CommissionRate.Bytes(), acturalEnv.CommissionRate.Bytes()) + require.ElementsMatch(t, env.ValidatorThreshold.Bytes(), acturalEnv.ValidatorThreshold.Bytes()) + require.ElementsMatch(t, env.JailThreshold.Bytes(), acturalEnv.JailThreshold.Bytes()) + require.ElementsMatch(t, env.JailPeriod.Bytes(), acturalEnv.JailPeriod.Bytes()) + // assert validators + for i := 0; i < size; i++ { + // require.ElementsMatch(t, validators.Owners[i]) + require.ElementsMatch(t, validators.Operators[i].Bytes(), actualVals.Operators[i].Bytes()) + require.ElementsMatch(t, validators.Owners[i].Bytes(), actualVals.Owners[i].Bytes()) + require.ElementsMatch(t, validators.Stakes[i].Bytes(), actualVals.Stakes[i].Bytes()) + require.ElementsMatch(t, validators.VoteAddresses[i].Bytes(), actualVals.VoteAddresses[i].Bytes()) + } +} + +func TestIsSufficientVotes(t *testing.T) { + var ( + size = 5 + validators = &nextValidators{ + Stakes: make([]*big.Int, 0, size), + VoteAddresses: make([]types.BLSPublicKey, 0, size), + } + ) + for i := 1; i <= size; i++ { + validators.Stakes = append(validators.Stakes, newEth(int64(i))) + validators.VoteAddresses = append(validators.VoteAddresses, randomBLSPublicKey()) + } + + tests := []struct { + name string + validators *nextValidators + votedAddrs []types.BLSPublicKey + expected bool + }{ + { + name: "sufficient votes", + validators: validators, + votedAddrs: []types.BLSPublicKey{validators.VoteAddresses[0], validators.VoteAddresses[3], validators.VoteAddresses[4]}, + expected: true, + }, + { + name: "insufficient votes", + validators: validators, + votedAddrs: []types.BLSPublicKey{validators.VoteAddresses[3], validators.VoteAddresses[4]}, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, isSufficientVotes(tt.votedAddrs, tt.validators)) + }) + } +} + +func newEth(n int64) *big.Int { + return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.Ether)) +} + +func randomBLSPublicKey() types.BLSPublicKey { + return types.BLSPublicKey(testutil.RandBytes(types.BLSPublicKeyLength)) +} diff --git a/consensus/oasys/snapshot.go b/consensus/oasys/snapshot.go index e0146c843..ce6099483 100644 --- a/consensus/oasys/snapshot.go +++ b/consensus/oasys/snapshot.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "errors" + "fmt" "math/big" "sort" @@ -23,13 +24,43 @@ type Snapshot struct { sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover ethAPI *ethapi.BlockChainAPI - Number uint64 `json:"number"` // Block number where the snapshot was created - Hash common.Hash `json:"hash"` // Block hash where the snapshot was created - Validators map[common.Address]*big.Int `json:"validators"` // Set of authorized validators and stakes at this moment + Number uint64 `json:"number"` // Block number where the snapshot was created + Hash common.Hash `json:"hash"` // Block hash where the snapshot was created + Validators map[common.Address]*ValidatorInfo `json:"validators"` // Set of authorized validators and stakes at this moment + Attestation *types.VoteData `json:"attestation,omitempty"` // Attestation for fast finality, but `Source` used as `Finalized` Environment *params.EnvironmentValue `json:"environment"` } +type ValidatorInfo struct { + // The index is determined by the sorted order of the validator owner address + Stake *big.Int `json:"stake,omitempty"` // The stake amount + Index int `json:"index,omitempty"` // The index should offset by 1 + VoteAddress types.BLSPublicKey `json:"vote_address,omitempty"` // The vote address +} + +// Note: This code can be removed after each validators has been upgraded to v1.6.0. +func (info *ValidatorInfo) UnmarshalJSON(b []byte) error { + // v1.5.0 or earlier + bigint := new(big.Int) + if err := json.Unmarshal(b, bigint); err == nil { + info.Stake = bigint + return nil + } + + // v1.6.0 or later + type Alias ValidatorInfo + alias := new(Alias) + if err := json.Unmarshal(b, alias); err != nil { + return err + } + + info.Stake = alias.Stake + info.Index = alias.Index + info.VoteAddress = alias.VoteAddress + return nil +} + // validatorsAscending implements the sort interface to allow sorting a list of addresses type validatorsAscending []common.Address @@ -48,11 +79,14 @@ func newSnapshot(config *params.ChainConfig, sigcache *lru.ARCCache, ethAPI *eth ethAPI: ethAPI, Number: number, Hash: hash, - Validators: make(map[common.Address]*big.Int), + Validators: make(map[common.Address]*ValidatorInfo), Environment: environment.Copy(), } - for _, address := range validators { - snap.Validators[address] = new(big.Int).Set(common.Big0) + for i, address := range validators { + snap.Validators[address] = &ValidatorInfo{ + Index: i + 1, + Stake: new(big.Int).Set(common.Big0), + } } return snap } @@ -92,18 +126,66 @@ func (s *Snapshot) copy() *Snapshot { ethAPI: s.ethAPI, Number: s.Number, Hash: s.Hash, - Validators: make(map[common.Address]*big.Int), + Validators: make(map[common.Address]*ValidatorInfo), Environment: s.Environment.Copy(), } - for address, stake := range s.Validators { - cpy.Validators[address] = new(big.Int).Set(stake) + for address, info := range s.Validators { + var voteAddress types.BLSPublicKey + copy(voteAddress[:], info.VoteAddress.Bytes()) + cpy.Validators[address] = &ValidatorInfo{ + Index: info.Index, + Stake: new(big.Int).Set(info.Stake), + VoteAddress: voteAddress, + } + } + if s.Attestation != nil { + cpy.Attestation = &types.VoteData{ + SourceNumber: s.Attestation.SourceNumber, + SourceHash: s.Attestation.SourceHash, + TargetNumber: s.Attestation.TargetNumber, + TargetHash: s.Attestation.TargetHash, + } } return cpy } +func (s *Snapshot) updateAttestation(header *types.Header, chainConfig *params.ChainConfig, oasysConfig *params.OasysConfig) { + if !chainConfig.IsFastFinalityEnabled(header.Number) { + return + } + + // The attestation should have been checked in verify header, update directly + attestation, _ := getVoteAttestationFromHeader(header, chainConfig, oasysConfig, s.Environment.IsEpoch(header.Number.Uint64())) + if attestation == nil { + return + } + + // Headers with bad attestation are accepted before Plato upgrade, + // but Attestation of snapshot is only updated when the target block is direct parent of the header + targetNumber := attestation.Data.TargetNumber + targetHash := attestation.Data.TargetHash + if targetHash != header.ParentHash || targetNumber+1 != header.Number.Uint64() { + log.Warn("updateAttestation failed", "error", fmt.Errorf("invalid attestation, target mismatch, expected block: %d, hash: %s; real block: %d, hash: %s", + header.Number.Uint64()-1, header.ParentHash, targetNumber, targetHash)) + updateAttestationErrorCounter.Inc(1) + return + } + + // Update attestation + // Two scenarios for s.Attestation being nil: + // 1) The first attestation is assembled. + // 2) The snapshot on disk is missing, prompting the creation of a new snapshot using `newSnapshot`. + if s.Attestation != nil && attestation.Data.SourceNumber+1 != attestation.Data.TargetNumber { + s.Attestation.TargetNumber = attestation.Data.TargetNumber + s.Attestation.TargetHash = attestation.Data.TargetHash + } else { + s.Attestation = attestation.Data + } +} + // apply creates a new authorization snapshot by applying the given headers to // the original one. -func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderReader) (*Snapshot, error) { +func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderReader, oasysConfig *params.OasysConfig) (*Snapshot, error) { // Allow passing in no headers for cleaner code if len(headers) == 0 { return s, nil @@ -130,21 +212,38 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea var exists bool if number > 0 && snap.Environment.IsEpoch(number) { - nextValidator, err := getNextValidators(s.config, s.ethAPI, header.ParentHash, snap.Environment.Epoch(number), number) - if err != nil { - log.Error("Failed to get validators", "in", "Snapshot.apply", "hash", header.ParentHash, "number", number, "err", err) - return nil, err + var nextValidator *nextValidators + if s.config.IsFastFinalityEnabled(header.Number) { + if nextValidator, err = getValidatorsFromHeader(header); err != nil { + log.Warn("failed to get validators from header", "in", "Snapshot.apply", "hash", header.Hash(), "number", number, "err", err) + } + } + // If not fast finality or failed to get validators from header + if nextValidator == nil { + if nextValidator, err = getNextValidators(s.config, s.ethAPI, header.ParentHash, snap.Environment.Epoch(number), number); err != nil { + return nil, fmt.Errorf("failed to get validators, in Snapshot.apply, err: %w", err) + } + } + var nextEnv *params.EnvironmentValue + if s.config.IsFastFinalityEnabled(header.Number) { + nextEnv, err = getEnvironmentFromHeader(header) + } else { + nextEnv, err = getNextEnvironmentValue(s.ethAPI, header.ParentHash) } - nextEnv, err := getNextEnvironmentValue(s.ethAPI, header.ParentHash) if err != nil { log.Error("Failed to get environment value", "in", "Snapshot.apply", "hash", header.ParentHash, "number", number, "err", err) return nil, err } snap.Environment = nextEnv.Copy() - snap.Validators = map[common.Address]*big.Int{} + snap.Validators = make(map[common.Address]*ValidatorInfo, len(nextValidator.Operators)) for i, address := range nextValidator.Operators { - snap.Validators[address] = nextValidator.Stakes[i] + voterIndex := i + 1 + snap.Validators[address] = &ValidatorInfo{ + Index: voterIndex, + Stake: nextValidator.Stakes[i], + VoteAddress: nextValidator.VoteAddresses[i], + } } exists = nextValidator.Exists(validator) @@ -155,6 +254,8 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea if !exists { return nil, errUnauthorizedValidator } + + snap.updateAttestation(header, s.config, oasysConfig) } snap.Number += uint64(len(headers)) snap.Hash = headers[len(headers)-1].Hash() @@ -177,16 +278,30 @@ func (s *Snapshot) exists(validator common.Address) bool { return ok } -func (s *Snapshot) validatorsToTuple() ([]common.Address, []*big.Int) { +func (s *Snapshot) ToNextValidators() *nextValidators { operators := make([]common.Address, len(s.Validators)) stakes := make([]*big.Int, len(s.Validators)) - i := 0 - for address, stake := range s.Validators { + voteAddresses := make([]types.BLSPublicKey, len(s.Validators)) + var counter int + for address, info := range s.Validators { + // Basically, voterIndex is assured when creating snapshot + i := info.Index - 1 + if info.Index == 0 { + // The is one scenario that the index is 0, which is the first run after the upgrade(v1.6.0). + // In this case, As the snapshot is loaded from disk, the format is old one. + i = counter + counter++ + } operators[i] = address - stakes[i] = new(big.Int).Set(stake) - i++ + stakes[i] = new(big.Int).Set(info.Stake) + copy(voteAddresses[i][:], info.VoteAddress[:]) + } + return &nextValidators{ + Owners: make([]common.Address, 0), // take care the owners are empty + Operators: operators, + Stakes: stakes, + VoteAddresses: voteAddresses, } - return operators, stakes } func parseValidatorBytes(validatorBytes []byte) ([]common.Address, error) { diff --git a/consensus/oasys/snapshot_test.go b/consensus/oasys/snapshot_test.go new file mode 100644 index 000000000..c6d793e92 --- /dev/null +++ b/consensus/oasys/snapshot_test.go @@ -0,0 +1,44 @@ +package oasys + +import ( + "encoding/json" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" +) + +func TestUnmarshalValidatorInfo(t *testing.T) { + jsonbody := []byte(`[ + 1, + { + "stake": 2, + "index": 3, + "vote_address": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004" + } + ]`) + + expects := []*ValidatorInfo{ + &ValidatorInfo{ + Stake: big.NewInt(1), + Index: 0, + VoteAddress: types.BLSPublicKey{}, + }, + &ValidatorInfo{ + Stake: big.NewInt(2), + Index: 3, + VoteAddress: types.BLSPublicKey([]byte{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, + }), + }, + } + + var actuals []*ValidatorInfo + err := json.Unmarshal(jsonbody, &actuals) + require.NoError(t, err) + require.Equal(t, expects, actuals) +} diff --git a/contracts/oasys/deployments.go b/contracts/oasys/deployments.go index dd98663ff..3f9acfc23 100644 --- a/contracts/oasys/deployments.go +++ b/contracts/oasys/deployments.go @@ -20,7 +20,8 @@ var deploymentSets = map[common.Hash]map[uint64]deploymentSet{ 971800: deploymentSet{deployments7}, 1529980: deploymentSet{deployments9}, 1892000: deploymentSet{deployments10}, - 9999999: deploymentSet{deployments11}, // TODO + 4089588: deploymentSet{deployments11}, + 9999998: deploymentSet{deployments12}, // TODO }, params.OasysTestnetGenesisHash: { 1: deploymentSet{deployments0}, @@ -34,6 +35,7 @@ var deploymentSets = map[common.Hash]map[uint64]deploymentSet{ 1519840: deploymentSet{deployments9}, 1880660: deploymentSet{deployments10}, 4017600: deploymentSet{deployments11}, + 4958700: deploymentSet{deployments12}, }, defaultGenesisHash: { 2: deploymentSet{ @@ -48,7 +50,8 @@ var deploymentSets = map[common.Hash]map[uint64]deploymentSet{ deployments8, deployments9, deployments10, - deployments11, + // deployments11, // Disable this feature as it changes the epoch, which can impact development. + deployments12, }, }, } diff --git a/contracts/oasys/deployments12.go b/contracts/oasys/deployments12.go new file mode 100644 index 000000000..55911bfe3 --- /dev/null +++ b/contracts/oasys/deployments12.go @@ -0,0 +1,19 @@ +package oasys + +var deployments12 = []*deployment{ + { + // https://github.com/oasysgames/oasys-genesis-contract/blob/v1.6.1/contracts/StakeManager.sol + contract: stakeManager, + code: mustDecodeCode(`0x60806040526004361061027c5760003560e01c806374e2b63c1161014f578063cf5c13db116100c1578063e4b2477b1161007a578063e4b2477b14610880578063f3621e43146108b6578063f65a5ed2146108d6578063f8d6b1ab146108f6578063fa52c7d814610916578063ff3d3f601461094657600080fd5b8063cf5c13db14610784578063d0051adf146107a4578063d1f18ee1146107d5578063dbd61d8714610807578063df93c84214610827578063e1aca3411461086057600080fd5b80639168ae72116101135780639168ae72146106ae5780639c508219146106e4578063a6a41f4414610704578063ac7475ed14610724578063ad71bd3614610744578063cbc0fac61461076457600080fd5b806374e2b63c146105fd5780637b520aa8146106225780637befa74f14610658578063883252341461066b5780639043150b146106a657600080fd5b80632b47da52116101f3578063485cc955116101ac578063485cc9551461051b5780635c4fc4c51461053b5780635d94ccf61461056b5780635efc766e1461058b5780636b2b3369146105ab57806372431991146105cb57600080fd5b80632b47da52146104345780632ee462b31461046c57806333f32d781461048c578063428e8562146104ac57806345367f23146104cc57806346dfce7b146104ec57600080fd5b8063190b925711610245578063190b925714610332578063195afea1146103605780631c1b4f3a146103805780632168e8b4146103a057806322226367146103ce5780632b42ed8c1461040357600080fd5b8062c8ae891461028157806302fb4d85146102a35780630ddda63c146102c3578063158ef93e146102e35780631903cf1614610312575b600080fd5b34801561028d57600080fd5b506102a161029c3660046150d9565b610966565b005b3480156102af57600080fd5b506102a16102be36600461515f565b610b1d565b3480156102cf57600080fd5b506102a16102de36600461518b565b610d23565b3480156102ef57600080fd5b506000546102fd9060ff1681565b60405190151581526020015b60405180910390f35b34801561031e57600080fd5b506102a161032d366004615236565b610f2e565b34801561033e57600080fd5b5061035261034d36600461518b565b611127565b604051908152602001610309565b34801561036c57600080fd5b5061035261037b36600461515f565b611148565b34801561038c57600080fd5b5061035261039b36600461518b565b61117f565b3480156103ac57600080fd5b506103c06103bb3660046152e0565b61118f565b604051610309929190615346565b3480156103da57600080fd5b506103ee6103e936600461515f565b611275565b60408051928352602083019190915201610309565b34801561040f57600080fd5b5061042361041e366004615368565b611343565b6040516103099594939291906153d3565b34801561044057600080fd5b50600154610454906001600160a01b031681565b6040516001600160a01b039091168152602001610309565b34801561047857600080fd5b5061035261048736600461515f565b611690565b34801561049857600080fd5b506103526104a7366004615433565b611743565b3480156104b857600080fd5b506102a16104c7366004615236565b611909565b3480156104d857600080fd5b506103526104e736600461518b565b611b02565b3480156104f857600080fd5b5061050c610507366004615368565b611b98565b604051610309939291906154d2565b34801561052757600080fd5b506102a1610536366004615508565b611df5565b34801561054757600080fd5b5061055b61055636600461515f565b611e74565b6040516103099493929190615579565b34801561057757600080fd5b506102a161058636600461518b565b611f40565b34801561059757600080fd5b506104546105a636600461518b565b61204a565b3480156105b757600080fd5b506102a16105c63660046155a4565b612074565b3480156105d757600080fd5b506105eb6105e63660046155c1565b61216d565b60405161030996959493929190615677565b34801561060957600080fd5b506000546104549061010090046001600160a01b031681565b34801561062e57600080fd5b5061045461063d3660046155a4565b6006602052600090815260409020546001600160a01b031681565b6102a161066636600461572e565b612229565b34801561067757600080fd5b5061068b6106863660046155a4565b6123f4565b60408051938452602084019290925290820152606001610309565b6102a1612474565b3480156106ba57600080fd5b506104546106c93660046155a4565b6007602052600090815260409020546001600160a01b031681565b3480156106f057600080fd5b506103526106ff36600461515f565b6124a9565b34801561071057600080fd5b50600954610454906001600160a01b031681565b34801561073057600080fd5b506102a161073f3660046155a4565b612585565b34801561075057600080fd5b506103c061075f3660046152e0565b61268b565b34801561077057600080fd5b506102a161077f36600461515f565b612769565b34801561079057600080fd5b506102a161079f36600461515f565b612811565b3480156107b057600080fd5b506107c46107bf366004615773565b612a10565b6040516103099594939291906157a8565b3480156107e157600080fd5b506107f56107f036600461515f565b612cc8565b60405161030996959493929190615825565b34801561081357600080fd5b50610352610822366004615870565b612ed3565b34801561083357600080fd5b506103526108423660046155a4565b6001600160a01b031660009081526007602052604090206006015490565b34801561086c57600080fd5b506102a161087b36600461572e565b612f19565b34801561088c57600080fd5b5061045461089b36600461518b565b600a602052600090815260409020546001600160a01b031681565b3480156108c257600080fd5b506102a16108d1366004615870565b612f32565b3480156108e257600080fd5b506104546108f136600461518b565b61303e565b34801561090257600080fd5b506102a16109113660046155a4565b61304e565b34801561092257600080fd5b506109366109313660046155a4565b6130b0565b60405161030994939291906158a0565b34801561095257600080fd5b506102a161096136600461572e565b61316f565b336000818152600460205260409020546001600160a01b031661099c576040516372898ae960e11b815260040160405180910390fd5b3360006109ac60208286886158dd565b6109b591615907565b6000818152600a60205260409020549091506001600160a01b0316156109ee5760405163055ee1f160e31b815260040160405180910390fd5b6001600160a01b0382166000908152600460205260408120600b81018054919291610a1890615925565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4490615925565b8015610a915780601f10610a6657610100808354040283529160200191610a91565b820191906000526020600020905b815481529060010190602001808311610a7457829003601f168201915b50505050509050610aad8787846134af9092919063ffffffff16565b6000838152600a60205260409081902080546001600160a01b0319166001600160a01b03871690811790915590517f7ea7e12060119574f657de08c5ef0970a24d7734612fb00c418ad40c7d4a84fd90610b0c9084908b908b90615960565b60405180910390a250505050505050565b6001600160a01b038083166000908152600660209081526040808320548416808452600490925290912054909116610b68576040516372898ae960e11b815260040160405180910390fd5b334114610b8857604051631cf4735960e01b815260040160405180910390fd5b6001600160a01b038084166000908152600660209081526040808320548416835260049182905280832083548251633fa4f24560e01b815292519195610c9b946101009092041692633fa4f2459281830192610120928290030181865afa158015610bf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1b91906159a6565b600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c929190615a21565b84919087613537565b82546040519192506001600160a01b0316907f1647efd0ce9727dc31dc201c9d8d35ac687f7370adcacbd454afc6485ddabfda90600090a28015610d1c5781546040518281526001600160a01b03909116907feb7d7a49847ec491969db21a0e31b234565a9923145a2d1b56a75c9e95825802906020015b60405180910390a25b5050505050565b336000818152600460205260409020546001600160a01b0316610d59576040516372898ae960e11b815260040160405180910390fd5b336000818152600760205260409020546001600160a01b0316610d8f5760405163cf83d93d60e01b815260040160405180910390fd5b600060019054906101000a90046001600160a01b03166001600160a01b031663d4a536866040518163ffffffff1660e01b8152600401602060405180830381865afa158015610de2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e069190615a4f565b15610e2457604051631e59ccd960e01b815260040160405180910390fd5b60008054338252600460205260408220610e4c9161010090046001600160a01b031686613616565b905080610e6c57604051637bc90c0560e11b815260040160405180910390fd5b610ef03333600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee89190615a21565b600085613636565b604051818152339081907fddd8e3ffe5c76cd1a7cca4b98662cb0a4e3da53ee24a873da632d28ba1043836906020015b60405180910390a350505050565b6001600160a01b03828116600090815260046020526040902080548492163314801590610f68575060018101546001600160a01b03163314155b15610f8657604051630101292160e31b815260040160405180910390fd5b6001600160a01b03808516600090815260046020526040902054859116610fc0576040516372898ae960e11b815260040160405180910390fd5b600060019054906101000a90046001600160a01b03166001600160a01b031663d4a536866040518163ffffffff1660e01b8152600401602060405180830381865afa158015611013573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110379190615a4f565b1561105557604051631e59ccd960e01b815260040160405180910390fd5b6110ee600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110cf9190615a21565b6001600160a01b0387166000908152600460205260409020908661374b565b846001600160a01b03167fc11dfc9c24621433bb10587dc4bbae26a33a4aff53914e0d4c9fddf224a8cb7d85604051610d139190615a6a565b6002818154811061113757600080fd5b600091825260209091200154905081565b600080546001600160a01b038481168352600460205260408320611175929091610100909104168461375d565b5090505b92915050565b6003818154811061113757600080fd5b606060006111a384846005805490506138f1565b9093509050826001600160401b038111156111c0576111c06151a4565b6040519080825280602002602001820160405280156111e9578160200160208202803683370190505b50915060005b8381101561126d5760056112038287615a93565b8154811061121357611213615aab565b9060005260206000200160009054906101000a90046001600160a01b031683828151811061124357611243615aab565b6001600160a01b03909216602092830291909101909101528061126581615ac1565b9150506111ef565b509250929050565b600080611338600084116112ff57600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fa9190615a21565b611301565b835b6001600160a01b038616600090815260046020908152604080832093835260098401825280832054600a9094019091529020549091565b909590945092505050565b6001600160a01b0384166000908152600760205260408120606091829182918291886113e557600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e09190615a21565b6113e7565b885b98506113f988886005805490506138f1565b9097509150866001600160401b03811115611416576114166151a4565b60405190808252806020026020018201604052801561143f578160200160208202803683370190505b509550866001600160401b0381111561145a5761145a6151a4565b604051908082528060200260200182016040528015611483578160200160208202803683370190505b509450866001600160401b0381111561149e5761149e6151a4565b6040519080825280602002602001820160405280156114c7578160200160208202803683370190505b509350866001600160401b038111156114e2576114e26151a4565b60405190808252806020026020018201604052801561150b578160200160208202803683370190505b50925060005b87811015611683576005611525828b615a93565b8154811061153557611535615aab565b9060005260206000200160009054906101000a90046001600160a01b031687828151811061156557611565615aab565b60200260200101906001600160a01b031690816001600160a01b0316815250506115b687828151811061159a5761159a615aab565b602002602001015160008c85613929909392919063ffffffff16565b8682815181106115c8576115c8615aab565b6020026020010181815250506116058782815181106115e9576115e9615aab565b602002602001015160018c85613929909392919063ffffffff16565b85828151811061161757611617615aab565b60200260200101818152505061165487828151811061163857611638615aab565b602002602001015160028c85613929909392919063ffffffff16565b84828151811061166657611666615aab565b60209081029190910101528061167b81615ac1565b915050611511565b5050945094509450945094565b600080821161171557600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117109190615a21565b611717565b815b6001600160a01b038416600090815260046020526040902090925061173c90836139e8565b9392505050565b600080600183600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561179c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c09190615a21565b6117ca9190615adc565b6117d49190615adc565b845190915060005b84811015611900576117ef600184615a93565b6000805460405163fcbb371b60e01b81526004810184905292955090916101009091046001600160a01b03169063fcbb371b9060240161012060405180830381865afa158015611843573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186791906159a6565b905060005b838110156118eb5760006118c88387600460008d878151811061189157611891615aab565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206139fb9092919063ffffffff16565b5090506118d58188615a93565b96505080806118e390615ac1565b91505061186c565b505080806118f890615ac1565b9150506117dc565b50505092915050565b6001600160a01b03828116600090815260046020526040902080548492163314801590611943575060018101546001600160a01b03163314155b1561196157604051630101292160e31b815260040160405180910390fd5b6001600160a01b0380851660009081526004602052604090205485911661199b576040516372898ae960e11b815260040160405180910390fd5b600060019054906101000a90046001600160a01b03166001600160a01b031663d4a536866040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a129190615a4f565b15611a3057604051631e59ccd960e01b815260040160405180910390fd5b611ac9600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aaa9190615a21565b6001600160a01b03871660009081526004602052604090209086613b6a565b846001600160a01b03167f0ad9bf1b8c026a174a2f30954417002a6ea00c9b08c1b8846c7951c687be809585604051610d139190615a6a565b6000808211611b8757600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b829190615a21565b611b89565b815b91506111796002600384613b77565b6001600160a01b0384166000908152600460205260408120606091829186611c3657600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c319190615a21565b611c38565b865b9650611c4c868683600701805490506138f1565b9095509150846001600160401b03811115611c6957611c696151a4565b604051908082528060200260200182016040528015611c92578160200160208202803683370190505b509350846001600160401b03811115611cad57611cad6151a4565b604051908082528060200260200182016040528015611cd6578160200160208202803683370190505b50925060005b85811015611de9576000600781848201611cf6858c615a93565b81548110611d0657611d06615aab565b60009182526020808320909101546001600160a01b03908116845290830193909352604090910190208054885191935090911690879084908110611d4c57611d4c615aab565b6001600160a01b0392831660209182029290920101528354611d739183911660028c613929565b8354611d8c9083906001600160a01b031660018d613929565b8454611da59084906001600160a01b031660008e613929565b611daf9190615a93565b611db99190615a93565b858381518110611dcb57611dcb615aab565b60209081029190910101525080611de181615ac1565b915050611cdc565b50509450945094915050565b334114611e1557604051631cf4735960e01b815260040160405180910390fd5b60005460ff1615611e385760405162dc149f60e41b815260040160405180910390fd5b6000805460016001600160a81b03199091166101006001600160a01b039586160217811790915580546001600160a01b03191691909216179055565b6001600160a01b03821660009081526007602052604081206006018054829182918291829187908110611ea957611ea9615aab565b6000918252602090912060408051606081019091526003909202018054829060ff166002811115611edc57611edc615541565b6002811115611eed57611eed615541565b81526020016001820154815260200160028201548152505090508060000151816020015182604001518360400151600014158015611f2f575083604001514210155b929a91995097509095509350505050565b336000818152600760205260409020546001600160a01b0316611f765760405163cf83d93d60e01b815260040160405180910390fd5b336000908152600760205260408120600601805484908110611f9a57611f9a615aab565b9060005260206000209060030201905060008160020154905080421015611fd4576040516303cb96db60e21b815260040160405180910390fd5b80611ff257604051630c8d9eab60e31b815260040160405180910390fd5b6000600283015560405184815233907fbf5f92dc2b945251eadf78c2ca629ae64053d979bfbc43a7b17a463707906bf99060200160405180910390a2815460018301546120449160ff16903390613c90565b50505050565b6005818154811061205a57600080fd5b6000918252602090912001546001600160a01b0316905081565b6001600160a01b03818116600090815260066020526040902054339116156120af5760405163055ee1f160e31b815260040160405180910390fd5b6001600160a01b03811660009081526004602052604090206120d19083613daf565b60058054600181019091557f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b038381166001600160a01b03199283168117909355841660009081526006602090815260409182902080549093168417909255519182527fd5828184f48f65962d10eac907318df85953d4e3542a0f09b5932ee3fe398bdd910160405180910390a15050565b600954604051632d73a02f60e01b815260048101859052602481018490526044810183905260609182918291829182916000916001600160a01b0390911690632d73a02f90606401600060405180830381865afa1580156121d2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121fa9190810190615cf6565b9091929394509091929350809650819750829850839950849a50859b5050505050505093975093979195509350565b6001600160a01b03808416600090815260046020526040902054849116612263576040516372898ae960e11b815260040160405180910390fd5b600060019054906101000a90046001600160a01b03166001600160a01b031663d4a536866040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122da9190615a4f565b156122f857604051631e59ccd960e01b815260040160405180910390fd5b8161231657604051637bc90c0560e11b815260040160405180910390fd5b612321833384613df1565b6123af3385600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612379573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239d9190615a21565b6123a8906001615a93565b8686613636565b836001600160a01b0316336001600160a01b03167f8fc656e319452025372383dc27d933046d412b8253de50a10739eeaa59862be68585604051610f20929190615e1a565b6001600160a01b0380821660009081526007602052604081208154919283928392916124299183916101009091041684613e92565b60005490945061244a90829061010090046001600160a01b03166001613e92565b60005490935061246b90829061010090046001600160a01b03166002613e92565b93959294505050565b6040513481527f1de49774d094a85fc1bbbd16e8d09a865fb848218f41e2da4369f528c42ee42e9060200160405180910390a1565b6001600160a01b0380831660008181526006602090815260408083205485168352600490915281206001810154919390929116146124eb576000915050611179565b6000831161256f57600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256a9190615a21565b612571565b825b925061257d81846139e8565b949350505050565b336000818152600460205260409020546001600160a01b03166125bb576040516372898ae960e11b815260040160405180910390fd5b6001600160a01b03828116600090815260066020526040902054339116156125f65760405163055ee1f160e31b815260040160405180910390fd5b6001600160a01b038082166000908152600460205260409020600181015490911661262182866140b8565b6001600160a01b0385811660008181526006602090815260409182902080546001600160a01b031916888616908117909155825194861685529084019290925290917f758820d0b14a01c1fa60b8d2bbef25ed1b6a5af4802e5dec3f08679255ba8bf39101610d13565b6060600061269f84846008805490506138f1565b9093509050826001600160401b038111156126bc576126bc6151a4565b6040519080825280602002602001820160405280156126e5578160200160208202803683370190505b50915060005b8381101561126d5760086126ff8287615a93565b8154811061270f5761270f615aab565b9060005260206000200160009054906101000a90046001600160a01b031683828151811061273f5761273f615aab565b6001600160a01b03909216602092830291909101909101528061276181615ac1565b9150506126eb565b336000818152600460205260409020546001600160a01b031661279f576040516372898ae960e11b815260040160405180910390fd5b600080543382526004602052604082206127c79161010090046001600160a01b031685613616565b60405181815290915033907f882d5671e5b36af50883197c33d48ba56ce337589958e871ba82fb0a54adf3e89060200160405180910390a280156120445761204460003383613c90565b6001600160a01b0380831660009081526004602052604090205483911661284b576040516372898ae960e11b815260040160405180910390fd5b336000818152600760205260409020546001600160a01b03166128815760405163cf83d93d60e01b815260040160405180910390fd5b600060019054906101000a90046001600160a01b03166001600160a01b031663d4a536866040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f89190615a4f565b1561291657604051631e59ccd960e01b815260040160405180910390fd5b600080546001600160a01b03868116835260046020908152604080852033865260079092528420612951939092610100909104169087614132565b90508061297157604051637bc90c0560e11b815260040160405180910390fd5b6129c93386600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ec4573d6000803e3d6000fd5b6040518181526001600160a01b0386169033907fddd8e3ffe5c76cd1a7cca4b98662cb0a4e3da53ee24a873da632d28ba10438369060200160405180910390a35050505050565b6001600160a01b038316600090815260076020526040812060068101546060928392839283929190612a4590899089906138f1565b9097509150866001600160401b03811115612a6257612a626151a4565b604051908082528060200260200182016040528015612a8b578160200160208202803683370190505b509550866001600160401b03811115612aa657612aa66151a4565b604051908082528060200260200182016040528015612acf578160200160208202803683370190505b509450866001600160401b03811115612aea57612aea6151a4565b604051908082528060200260200182016040528015612b13578160200160208202803683370190505b509350866001600160401b03811115612b2e57612b2e6151a4565b604051908082528060200260200182016040528015612b57578160200160208202803683370190505b50925060005b87811015612cbb57600060068301612b75838c615a93565b81548110612b8557612b85615aab565b6000918252602090912060408051606081019091526003909202018054829060ff166002811115612bb857612bb8615541565b6002811115612bc957612bc9615541565b81526020016001820154815260200160028201548152505090508060000151888381518110612bfa57612bfa615aab565b60200260200101906002811115612c1357612c13615541565b90816002811115612c2657612c26615541565b815250508060200151878381518110612c4157612c41615aab565b6020026020010181815250508060400151868381518110612c6457612c64615aab565b6020908102919091010152604081015115801590612c86575080604001514210155b858381518110612c9857612c98615aab565b911515602092830291909101909101525080612cb381615ac1565b915050612b5d565b5050939792965093509350565b600080808080606086612d4f57600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4c9190615a21565b96505b6001600160a01b03888116600090815260046020908152604080832060018101548c855260028201909352922054921697509060ff1660008981526003830160205260409020549015965060ff169450612da981896139e8565b925080600b018054612dba90615925565b80601f0160208091040260200160405190810160405280929190818152602001828054612de690615925565b8015612e335780601f10612e0857610100808354040283529160200191612e33565b820191906000526020600020905b815481529060010190602001808311612e1657829003601f168201915b50505050509150858015612e45575084155b8015612ec6575060005460405163fcbb371b60e01b8152600481018a90526101009091046001600160a01b03169063fcbb371b9060240161012060405180830381865afa158015612e9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ebe91906159a6565b60c001518310155b9350509295509295509295565b600080546001600160a01b038481168352600460209081526040808520888416865260079092528420612f1093909261010090910416908561416b565b50949350505050565b604051634ee5a1b960e01b815260040160405180910390fd5b6001600160a01b03808316600090815260046020526040902054839116612f6c576040516372898ae960e11b815260040160405180910390fd5b336000818152600760205260409020546001600160a01b0316612fa25760405163cf83d93d60e01b815260040160405180910390fd5b600080546001600160a01b03868116835260046020908152604080852033865260079092528420612fdd939092610100909104169087614132565b604080516001600160a01b03881681526020810183905291925033917f2ef606d064225d24c1514dc94907c134faee1237445c2f63f410cce0852b2054910160405180910390a280156130365761303660003383613c90565b505050505050565b6008818154811061205a57600080fd5b336000818152600760205260409020546001600160a01b03166130845760405163cf83d93d60e01b815260040160405180910390fd5b60008054338252600760205260409091206130ac9161010090046001600160a01b0316614379565b5050565b6004602052600090815260409020805460018201546006830154600b840180546001600160a01b0394851695949093169391926130ec90615925565b80601f016020809104026020016040519081016040528092919081815260200182805461311890615925565b80156131655780601f1061313a57610100808354040283529160200191613165565b820191906000526020600020905b81548152906001019060200180831161314857829003601f168201915b5050505050905084565b6001600160a01b038084166000908152600460205260409020548491166131a9576040516372898ae960e11b815260040160405180910390fd5b336000818152600760205260409020546001600160a01b03166131df5760405163cf83d93d60e01b815260040160405180910390fd5b600060019054906101000a90046001600160a01b03166001600160a01b031663d4a536866040518163ffffffff1660e01b8152600401602060405180830381865afa158015613232573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132569190615a4f565b1561327457604051631e59ccd960e01b815260040160405180910390fd5b33600090815260076020908152604080832083546001600160a01b038a811686526004909452919093206132b292849261010090041690888861439d565b9350836132d257604051637bc90c0560e11b815260040160405180910390fd5b8060060160405180606001604052808760028111156132f3576132f3615541565b81526020810187905260400161330c42620d2f00615a93565b9052815460018181018455600093845260209093208251600390920201805492939092839160ff199091169083600281111561334a5761334a615541565b0217905550602082015181600101556040820151816002015550506133f66003600060019054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e19190615a21565b6133ec906001615a93565b60029190876144d3565b50600954604051635692619d60e11b81526001600160a01b0388811660048301529091169063ad24c33a90602401600060405180830381600087803b15801561343e57600080fd5b505af1158015613452573d6000803e3d6000fd5b50505060068201546001600160a01b038816915033907fb649014faa7a0e23357e091fb8a67a128c33dc9480f846f7e41cb3a6c9d806109061349690600190615adc565b60405190815260200160405180910390a3505050505050565b603081146134d057604051637477579960e11b815260040160405180910390fd5b6134de6020600083856158dd565b6134e791615907565b15801561350b57506134fd6030602083856158dd565b61350691615e35565b60801c155b1561352957604051634ee9493360e11b815260040160405180910390fd5b612044600b84018383614fe4565b600082815260098501602052604081205461356057600083815260098601602052604090208290555b6000838152600a8601602052604081205461357c906001615a93565b6000858152600a88016020526040902081905560e086015190915081108015906135c857506003860160006135b2866001615a93565b815260208101919091526040016000205460ff16155b15612f10576101008501516135dd9085615a93565b91505b81841015612f1057836135f281615ac1565b60008181526003890160205260409020805460ff1916600117905594506135e09050565b600080600061362686868661375d565b6006880155925050509392505050565b6001600160a01b03808616600090815260076020526040902080549091166136af5780546001600160a01b0387166001600160a01b031991821681178355600880546001810182556000919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30180549092161790555b6001600160a01b03851660009081526004602052604090206136d6908290869086866145ae565b6136e4600260038685614676565b600954604051635692619d60e11b81526001600160a01b0387811660048301529091169063ad24c33a90602401600060405180830381600087803b15801561372b57600080fd5b505af115801561373f573d6000803e3d6000fd5b50505050505050505050565b613758838383600061475c565b505050565b6000808460060154905060006001856001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137cd9190615a21565b6137d79190615adc565b90508315806137ee5750806137ec8386615a93565b115b15613800576137fd8282615adc565b93505b60005b848110156138e757613816600184615a93565b60405163fcbb371b60e01b8152600481018290529093506000906001600160a01b0388169063fcbb371b9060240161012060405180830381865afa158015613862573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061388691906159a6565b905060006138958983876139fb565b509050806138a45750506138d5565b60a08201516138b45750506138d5565b6138c6818360a00151606460196147e2565b6138d09087615a93565b955050505b806138df81615ac1565b915050613803565b5050935093915050565b600080826138ff8587615a93565b106139115761390e8584615adc565b93505b8361391c8187615a93565b915091505b935093915050565b60006139df85600201600085600281111561394657613946615541565b600281111561395757613957615541565b81526020019081526020016000206000866001600160a01b03166001600160a01b03168152602001908152602001600020838760010160008760028111156139a1576139a1615541565b60028111156139b2576139b2615541565b8152602080820192909252604090810160009081206001600160a01b038b16825290925290209190613b77565b95945050505050565b600061173c600484016005850184613b77565b6000818152600284016020526040812054819060ff1680613a2c5750600083815260038601602052604090205460ff165b15613a3c57506000905080613921565b613a4685846139e8565b905060498310613a86578360c00151811015613a655760009150613921565b62989680613a7582610a34615e6e565b613a7f9190615e8d565b9150613b1f565b80613a9657506000905080613921565b613aa26019600a615f8b565b613ab385608001516064601961480e565b613abd9083615e6e565b613ac79190615e8d565b915081613ad75760009150613921565b613afa84606001518560400151613aee9190615e6e565b6301e13380601961480e565b613b049083615e6e565b9150613b126019600a615f8b565b613b1c9083615e8d565b91505b6000838152600a860160205260409020548015613b61576000848152600987016020526040902054613b5d84613b558484615adc565b8360196147e2565b9350505b50935093915050565b613758838383600161475c565b8254600090801580613ba557508285600081548110613b9857613b98615aab565b9060005260206000200154115b15613bb457600091505061173c565b8285613bc1600184615adc565b81548110613bd157613bd1615aab565b906000526020600020015411613c105783613bed600183615adc565b81548110613bfd57613bfd615aab565b906000526020600020015491505061173c565b600181118015613c4657508285613c28600284615adc565b81548110613c3857613c38615aab565b906000526020600020015411155b15613c575783613bed600283615adc565b6000613c66868560008561484a565b9050848181548110613c7a57613c7a615aab565b9060005260206000200154925050509392505050565b600080846002811115613ca557613ca5615541565b1415613d04576040516001600160a01b038416908390600081818185875af1925050503d8060008114613cf4576040519150601f19603f3d011682016040523d82523d6000602084013e613cf9565b606091505b505080915050613d86565b613d0d846148f2565b60405163a9059cbb60e01b81526001600160a01b03858116600483015260248201859052919091169063a9059cbb906044015b6020604051808303816000875af1158015613d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d839190615a4f565b90505b806120445783604051630db5347560e11b8152600401613da69190615f97565b60405180910390fd5b81546001600160a01b031615613dd757604051621d934160e11b815260040160405180910390fd5b81546001600160a01b031916331782556130ac82826140b8565b6000836002811115613e0557613e05615541565b1415613e2b5780341461375857604051630fe5b06560e11b815260040160405180910390fd5b3415613e4a5760405163a745ac8560e01b815260040160405180910390fd5b6000613e55846148f2565b6040516323b872dd60e01b81526001600160a01b0385811660048301523060248301526044820185905291909116906323b872dd90606401613d40565b600080846003016000846002811115613ead57613ead615541565b6002811115613ebe57613ebe615541565b8152602081019190915260400160002054905080613ee057600091505061173c565b6000846001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f449190615a21565b90506000613f53600184615adc565b9050600081118015613fb6575081876003016000876002811115613f7957613f79615541565b6002811115613f8a57613f8a615541565b81526020019081526020016000208281548110613fa957613fa9615aab565b9060005260206000200154115b15613fc95780613fc581615fa5565b9150505b81876003016000876002811115613fe257613fe2615541565b6002811115613ff357613ff3615541565b8152602001908152602001600020828154811061401257614012615aab565b9060005260206000200154111561402f576000935050505061173c565b6000805b8281116140ac5788600401600088600281111561405257614052615541565b600281111561406357614063615541565b8152602001908152602001600020818154811061408257614082615aab565b9060005260206000200154826140989190615a93565b9150806140a481615ac1565b915050614033565b50979650505050505050565b6001600160a01b0381166140df57604051637138356f60e01b815260040160405180910390fd5b81546001600160a01b038281169116141561410d5760405163e037058f60e01b815260040160405180910390fd5b60019190910180546001600160a01b0319166001600160a01b03909216919091179055565b60008060006141438787878761416b565b86546001600160a01b0316600090815260058a01602052604090205592505050949350505050565b81546001600160a01b039081166000908152600586016020908152604080832054815163900cf0cf60e01b81529151939490938593600193928a169263900cf0cf92600480830193928290030181865afa1580156141cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141f19190615a21565b6141fb9190615adc565b90508315806142125750806142108386615a93565b115b15614224576142218282615adc565b93505b60005b8481101561436e5761423a600184615a93565b8654909350600090614259908a906001600160a01b0316600287613929565b8754614272908b906001600160a01b0316600188613929565b885461428b908c906001600160a01b0316600089613929565b6142959190615a93565b61429f9190615a93565b9050806142ac575061435c565b60008061432a8a6001600160a01b031663fcbb371b886040518263ffffffff1660e01b81526004016142e091815260200190565b61012060405180830381865afa1580156142fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061432291906159a6565b8a908861495d565b91509150816000141561433f5750505061435c565b61434c82848360196147e2565b6143569088615a93565b96505050505b8061436681615ac1565b915050614227565b505094509492505050565b614385828260016149ae565b614391828260026149ae565b6130ac828260006149ae565b60006144b98660020160008560028111156143ba576143ba615541565b60028111156143cb576143cb615541565b81526020808201929092526040908101600090812088546001600160a01b03908116835290845290829020825163900cf0cf60e01b815292519093918a169263900cf0cf9260048083019391928290030181865afa158015614431573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144559190615a21565b614460906001615a93565b8489600101600088600281111561447957614479615541565b600281111561448a5761448a615541565b8152602080820192909252604090810160009081208b546001600160a01b0316825290925290209291906144d3565b9150816144c8575060006139df565b612f10848684614cd4565b835460009080158061450a5750856144ec600183615adc565b815481106144fc576144fc615aab565b906000526020600020015484105b1561452857604051630eae4c9760e01b815260040160405180910390fd5b6000614535878787614d54565b9050600086828154811061454b5761454b615aab565b90600052602060002001549050808511156145665780614568565b845b945084156145a2578487838154811061458357614583615aab565b90600052602060002001600082825461459c9190615adc565b90915550505b50929695505050505050565b61465d8560020160008460028111156145c9576145c9615541565b60028111156145da576145da615541565b81526020808201929092526040908101600090812087546001600160a01b031682529092528120908690849060018a019087600281111561461d5761461d615541565b600281111561462e5761462e615541565b8152602080820192909252604090810160009081208a546001600160a01b031682529092529020929190614676565b8454610d1c90849086906001600160a01b031684614f64565b83546001811180156146ad57508461468f600183615adc565b8154811061469f5761469f615aab565b906000526020600020015483105b80156146de5750846146c0600283615adc565b815481106146d0576146d0615aab565b906000526020600020015483105b156146fc57604051630eae4c9760e01b815260040160405180910390fd5b6000614709868686614d54565b8654925090505b81811015613036578285828154811061472b5761472b615aab565b9060005260206000200160008282546147449190615a93565b9091555081905061475481615ac1565b915050614710565b815160005b8181101561303657600084828151811061477d5761477d615aab565b6020026020010151905085811180156147ad5750600081815260028801602052604090205460ff16151584151514155b156147cf5760008181526002880160205260409020805460ff19168515151790555b50806147da81615ac1565b915050614761565b60006147ef82600a615f8b565b6147fa85858561480e565b6148049087615e6e565b6139df9190615e8d565b60008061481c836001615a93565b61482790600a615f8b565b6148319086615e6e565b9050600a61483f8583615e8d565b614804906005615a93565b6000818314156148665761485f600183615adc565b905061257d565b600060026148748486615a93565b61487e9190615e8d565b90508486828154811061489357614893615aab565b906000526020600020015411156148b8576148b08686868461484a565b91505061257d565b848682815481106148cb576148cb615aab565b906000526020600020015410156139df576148b086866148ec846001615a93565b8661484a565b6000600182600281111561490857614908615541565b141561491c57506001602960991b01919050565b600282600281111561493057614930615541565b141561494457506002602960991b01919050565b604051638698bf3760e01b815260040160405180910390fd5b60008061496b8585856139fb565b90925090508161497e5760009150613921565b60a0840151156139215761499a828560a00151606460196147e2565b6149a49083615adc565b9150935093915050565b60006149bb848484613e92565b9050806149c85750505050565b60008460030160008460028111156149e2576149e2615541565b60028111156149f3576149f3615541565b8152602001908152602001600020805490509050836001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614a45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a699190615a21565b856003016000856002811115614a8157614a81615541565b6002811115614a9257614a92615541565b8152602001908152602001600020600183614aad9190615adc565b81548110614abd57614abd615aab565b906000526020600020015411614b5857846003016000846002811115614ae557614ae5615541565b6002811115614af657614af6615541565b81526020019081526020016000206000614b109190615068565b846004016000846002811115614b2857614b28615541565b6002811115614b3957614b39615541565b81526020019081526020016000206000614b539190615068565b614cbd565b6040518060200160405280866003016000866002811115614b7b57614b7b615541565b6002811115614b8c57614b8c615541565b8152602001908152602001600020600184614ba79190615adc565b81548110614bb757614bb7615aab565b9060005260206000200154815250856003016000856002811115614bdd57614bdd615541565b6002811115614bee57614bee615541565b81526020810191909152604001600020614c09916001615089565b506040518060200160405280866004016000866002811115614c2d57614c2d615541565b6002811115614c3e57614c3e615541565b8152602001908152602001600020600184614c599190615adc565b81548110614c6957614c69615aab565b9060005260206000200154815250856004016000856002811115614c8f57614c8f615541565b6002811115614ca057614ca0615541565b81526020810191909152604001600020614cbb916001615089565b505b8454610d1c9084906001600160a01b031684613c90565b61204483600501836001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614d19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d3d9190615a21565b614d48906001615a93565b600486019190846144d3565b825460009080614d8f57505082546001818101855560008581526020808220909301849055845491820185558481529182200181905561173c565b6000614d9c600183615adc565b90506000868281548110614db257614db2615aab565b9060005260206000200154905080851415614dd15750915061173c9050565b80851115614e395786546001810188556000888152602090200185905585548690819084908110614e0457614e04615aab565b6000918252602080832090910154835460018181018655948452919092200155614e2f908390615a93565b935050505061173c565b600082118015614e6e575086614e50600184615adc565b81548110614e6057614e60615aab565b906000526020600020015485145b15614e7e57614e2f600183615adc565b86878381548110614e9157614e91615aab565b6000918252602080832090910154835460018101855593835291209091015585548690819084908110614ec657614ec6615aab565b6000918252602080832090910154835460018101855593835291209091015586548590889084908110614efb57614efb615aab565b6000918252602090912001558115614f395785614f19600184615adc565b81548110614f2957614f29615aab565b9060005260206000200154614f3c565b60005b868381548110614f4e57614f4e615aab565b60009182526020909120015550915061173c9050565b6001600160a01b038216600090815260088501602052604090205460ff16614fd2576001600160a01b038216600081815260088601602090815260408220805460ff191660019081179091556007880180549182018155835291200180546001600160a01b03191690911790555b61204460048501600586018584614676565b828054614ff090615925565b90600052602060002090601f0160209004810192826150125760008555615058565b82601f1061502b5782800160ff19823516178555615058565b82800160010185558215615058579182015b8281111561505857823582559160200191906001019061503d565b506150649291506150c4565b5090565b508054600082559060005260206000209081019061508691906150c4565b50565b828054828255906000526020600020908101928215615058579160200282015b828111156150585782518255916020019190600101906150a9565b5b8082111561506457600081556001016150c5565b600080602083850312156150ec57600080fd5b82356001600160401b038082111561510357600080fd5b818501915085601f83011261511757600080fd5b81358181111561512657600080fd5b86602082850101111561513857600080fd5b60209290920196919550909350505050565b6001600160a01b038116811461508657600080fd5b6000806040838503121561517257600080fd5b823561517d8161514a565b946020939093013593505050565b60006020828403121561519d57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b03811182821017156151dd576151dd6151a4565b60405290565b604051601f8201601f191681016001600160401b038111828210171561520b5761520b6151a4565b604052919050565b60006001600160401b0382111561522c5761522c6151a4565b5060051b60200190565b6000806040838503121561524957600080fd5b82356152548161514a565b91506020838101356001600160401b0381111561527057600080fd5b8401601f8101861361528157600080fd5b803561529461528f82615213565b6151e3565b81815260059190911b820183019083810190888311156152b357600080fd5b928401925b828410156152d1578335825292840192908401906152b8565b80955050505050509250929050565b600080604083850312156152f357600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b8381101561533b5781516001600160a01b031687529582019590820190600101615316565b509495945050505050565b6040815260006153596040830185615302565b90508260208301529392505050565b6000806000806080858703121561537e57600080fd5b84356153898161514a565b966020860135965060408601359560600135945092505050565b600081518084526020808501945080840160005b8381101561533b578151875295820195908201906001016153b7565b60a0815260006153e660a0830188615302565b82810360208401526153f881886153a3565b9050828103604084015261540c81876153a3565b9050828103606084015261542081866153a3565b9150508260808301529695505050505050565b6000806040838503121561544657600080fd5b82356001600160401b0381111561545c57600080fd5b8301601f8101851361546d57600080fd5b8035602061547d61528f83615213565b82815260059290921b8301810191818101908884111561549c57600080fd5b938201935b838510156154c35784356154b48161514a565b825293820193908201906154a1565b98969091013596505050505050565b6060815260006154e56060830186615302565b82810360208401526154f781866153a3565b915050826040830152949350505050565b6000806040838503121561551b57600080fd5b82356155268161514a565b915060208301356155368161514a565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b6003811061557557634e487b7160e01b600052602160045260246000fd5b9052565b608081016155878287615557565b846020830152836040830152821515606083015295945050505050565b6000602082840312156155b657600080fd5b813561173c8161514a565b6000806000606084860312156155d657600080fd5b505081359360208301359350604090920135919050565b60005b838110156156085781810151838201526020016155f0565b838111156120445750506000910152565b600081518084526156318160208601602086016155ed565b601f01601f19169290920160200192915050565b600081518084526020808501945080840160005b8381101561533b578151151587529582019590820190600101615659565b60c08152600061568a60c0830189615302565b60208382038185015261569d828a615302565b915083820360408501526156b182896153a3565b915083820360608501528187518084528284019150828160051b850101838a0160005b8381101561570257601f198784030185526156f0838351615619565b948601949250908501906001016156d4565b50508681036080880152615716818a615645565b955050505050508260a0830152979650505050505050565b60008060006060848603121561574357600080fd5b833561574e8161514a565b925060208401356003811061576257600080fd5b929592945050506040919091013590565b60008060006060848603121561578857600080fd5b83356157938161514a565b95602085013595506040909401359392505050565b60a0808252865190820181905260009060209060c0840190828a01845b828110156157e8576157d8848351615557565b92840192908401906001016157c5565b505050838103828501526157fc81896153a3565b915050828103604084015261581181876153a3565b905082810360608401526154208186615645565b60018060a01b038716815285151560208201528415156040820152831515606082015282608082015260c060a0820152600061586460c0830184615619565b98975050505050505050565b60008060006060848603121561588557600080fd5b83356158908161514a565b925060208401356157628161514a565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906158d390830184615619565b9695505050505050565b600080858511156158ed57600080fd5b838611156158fa57600080fd5b5050820193919092039150565b8035602083101561117957600019602084900360031b1b1692915050565b600181811c9082168061593957607f821691505b6020821081141561595a57634e487b7160e01b600052602260045260246000fd5b50919050565b6040815260006159736040830186615619565b8281036020840152838152838560208301376000602085830101526020601f19601f860116820101915050949350505050565b600061012082840312156159b957600080fd5b6159c16151ba565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b600060208284031215615a3357600080fd5b5051919050565b80518015158114615a4a57600080fd5b919050565b600060208284031215615a6157600080fd5b61173c82615a3a565b60208152600061173c60208301846153a3565b634e487b7160e01b600052601160045260246000fd5b60008219821115615aa657615aa6615a7d565b500190565b634e487b7160e01b600052603260045260246000fd5b6000600019821415615ad557615ad5615a7d565b5060010190565b600082821015615aee57615aee615a7d565b500390565b600082601f830112615b0457600080fd5b81516020615b1461528f83615213565b82815260059290921b84018101918181019086841115615b3357600080fd5b8286015b84811015615b57578051615b4a8161514a565b8352918301918301615b37565b509695505050505050565b600082601f830112615b7357600080fd5b81516020615b8361528f83615213565b82815260059290921b84018101918181019086841115615ba257600080fd5b8286015b84811015615b5757615bb781615a3a565b8352918301918301615ba6565b600082601f830112615bd557600080fd5b81516020615be561528f83615213565b82815260059290921b84018101918181019086841115615c0457600080fd5b8286015b84811015615b575780518352918301918301615c08565b6000601f8381840112615c3157600080fd5b82516020615c4161528f83615213565b82815260059290921b85018101918181019087841115615c6057600080fd5b8287015b848110156140ac5780516001600160401b0380821115615c845760008081fd5b818a0191508a603f830112615c995760008081fd5b85820151604082821115615caf57615caf6151a4565b615cc0828b01601f191689016151e3565b92508183528c81838601011115615cd75760008081fd5b615ce6828985018387016155ed565b5050845250918301918301615c64565b600080600080600080600080610100898b031215615d1357600080fd5b88516001600160401b0380821115615d2a57600080fd5b615d368c838d01615af3565b995060208b0151915080821115615d4c57600080fd5b615d588c838d01615af3565b985060408b0151915080821115615d6e57600080fd5b615d7a8c838d01615b62565b975060608b0151915080821115615d9057600080fd5b615d9c8c838d01615b62565b965060808b0151915080821115615db257600080fd5b615dbe8c838d01615bc4565b955060a08b0151915080821115615dd457600080fd5b615de08c838d01615c1f565b945060c08b0151915080821115615df657600080fd5b50615e038b828c01615b62565b92505060e089015190509295985092959890939650565b60408101615e288285615557565b8260208301529392505050565b6fffffffffffffffffffffffffffffffff198135818116916010851015615e665780818660100360031b1b83161692505b505092915050565b6000816000190483118215151615615e8857615e88615a7d565b500290565b600082615eaa57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561126d578160001904821115615ed057615ed0615a7d565b80851615615edd57918102915b93841c9390800290615eb4565b600082615ef957506001611179565b81615f0657506000611179565b8160018114615f1c5760028114615f2657615f42565b6001915050611179565b60ff841115615f3757615f37615a7d565b50506001821b611179565b5060208310610133831016604e8410600b8410161715615f65575081810a611179565b615f6f8383615eaf565b8060001904821115615f8357615f83615a7d565b029392505050565b600061173c8383615eea565b602081016111798284615557565b600081615fb457615fb4615a7d565b50600019019056fea2646970667358221220b3c1bc7342f8d8fdc7ee0ce718b653ec3c77c2df6b236ed9e233f78255c3dd6a64736f6c634300080c0033`), + }, + { + // https://github.com/oasysgames/oasys-genesis-contract/blob/v1.6.0/contracts/CandidateValidatorManager.sol + contract: candidateValidatorManager, + code: mustDecodeCode(`0x608060405234801561001057600080fd5b50600436106100625760003560e01c80630c53b46c1461006757806321b81652146100ab5780632d73a02f146100d257806374e2b63c146100e55780637542ff951461010c578063ad24c33a14610133575b600080fd5b61008e7f000000000000000000000000520000000000000000000000000000000000002d81565b6040516001600160a01b0390911681526020015b60405180910390f35b6100be6100b9366004610d6c565b610148565b6040516100a2989796959493929190610eae565b6100be6100e0366004610d6c565b6102c0565b61008e7f000000000000000000000000000000000000000000000000000000000000100081565b61008e7f000000000000000000000000000000000000000000000000000000000000100181565b610146610141366004610f89565b6103a8565b005b606080606080606080606060007f00000000000000000000000000000000000000000000000000000000000010006001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190610fad565b8b10156101f757604051630eae4c9760e01b815260040160405180910390fd5b6040516350fd736760e01b8152600481018b9052602481018a90527f000000000000000000000000520000000000000000000000000000000000002d6001600160a01b0316906350fd7367906044015b600060405180830381865afa158015610264573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261028c9190810190611037565b909850905061029b888c610424565b809750819850829950839a50849b50859c505050505050509397509397509397509397565b606080808080808060008a610354577f00000000000000000000000000000000000000000000000000000000000010006001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103519190610fad565b9a505b60405163085a3a2d60e21b8152600481018b9052602481018a90527f00000000000000000000000000000000000000000000000000000000000010016001600160a01b031690632168e8b490604401610247565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000100116146103f157604051630101292160e31b815260040160405180910390fd5b6001600160a01b0381166104185760405163e99d5ac560e01b815260040160405180910390fd5b61042181610784565b50565b6060806060806060806000885190508067ffffffffffffffff81111561044c5761044c610fc6565b604051908082528060200260200182016040528015610475578160200160208202803683370190505b5096508067ffffffffffffffff81111561049157610491610fc6565b6040519080825280602002602001820160405280156104ba578160200160208202803683370190505b5095508067ffffffffffffffff8111156104d6576104d6610fc6565b6040519080825280602002602001820160405280156104ff578160200160208202803683370190505b5094508067ffffffffffffffff81111561051b5761051b610fc6565b604051908082528060200260200182016040528015610544578160200160208202803683370190505b5093508067ffffffffffffffff81111561056057610560610fc6565b60405190808252806020026020018201604052801561059357816020015b606081526020019060019003908161057e5790505b5092508067ffffffffffffffff8111156105af576105af610fc6565b6040519080825280602002602001820160405280156105d8578160200160208202803683370190505b50915060005b81811015610778577f00000000000000000000000000000000000000000000000000000000000010016001600160a01b031663d1f18ee18b8381518110610627576106276110f1565b60200260200101518b6040518363ffffffff1660e01b81526004016106619291906001600160a01b03929092168252602082015260400190565b600060405180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106a6919081019061111c565b8d87815181106106b8576106b86110f1565b602002602001018d88815181106106d1576106d16110f1565b602002602001018d89815181106106ea576106ea6110f1565b602002602001018b8a81518110610703576107036110f1565b602002602001018e8b8151811061071c5761071c6110f1565b602002602001018e8c81518110610735576107356110f1565b6020908102919091010195909552949093529315159092529215159092529115159091526001600160a01b0390911690528061077081611215565b9150506105de565b50509295509295509295565b60007f00000000000000000000000000000000000000000000000000000000000010006001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108089190610fad565b90506000610817826001611230565b60405163fcbb371b60e01b8152600481018490529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000001000169063fcbb371b9060240161012060405180830381865afa158015610883573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a79190611248565b60c0015160405163fcbb371b60e01b8152600481018490529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000001000169063fcbb371b9060240161012060405180830381865afa158015610917573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093b9190611248565b60c00151604080516060810182526001600160a01b0380891680835292516322bc467160e11b81526004810193909352929350600092909160208301917f000000000000000000000000520000000000000000000000000000000000002d16906345788ce290602401602060405180830381865afa1580156109c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e591906112c3565b6001600160a01b0390811682526040516355b9f18b60e11b815289821660048201526020909201917f000000000000000000000000520000000000000000000000000000000000002d9091169063ab73e31690602401602060405180830381865afa158015610a58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7c91906112c3565b6001600160a01b03169052905060005b60038160ff161015610d63576000828260ff1660038110610aaf57610aaf6110f1565b602002015190506001600160a01b038116610aca5750610d51565b604051632ee462b360e01b81526001600160a01b0382811660048301526024820189905260009187917f00000000000000000000000000000000000000000000000000000000000010011690632ee462b390604401602060405180830381865afa158015610b3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b609190610fad565b101590506000857f00000000000000000000000000000000000000000000000000000000000010016001600160a01b0316632ee462b3858b6040518363ffffffff1660e01b8152600401610bc99291906001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610be6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0a9190610fad565b101590508180610c175750805b15610cae57604051630a3b0a4f60e01b81526001600160a01b0384811660048301527f000000000000000000000000520000000000000000000000000000000000002d1690630a3b0a4f906024016020604051808303816000875af1158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca891906112e0565b50610d4d565b81158015610cba575080155b15610d4d57604051631484968760e11b81526001600160a01b0384811660048301527f000000000000000000000000520000000000000000000000000000000000002d16906329092d0e906024016020604051808303816000875af1158015610d27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4b91906112e0565b505b5050505b80610d5b816112fb565b915050610a8c565b50505050505050565b600080600060608486031215610d8157600080fd5b505081359360208301359350604090920135919050565b600081518084526020808501945080840160005b83811015610dd15781516001600160a01b031687529582019590820190600101610dac565b509495945050505050565b600081518084526020808501945080840160005b83811015610dd1578151151587529582019590820190600101610df0565b60005b83811015610e29578181015183820152602001610e11565b83811115610e38576000848401525b50505050565b600082825180855260208086019550808260051b84010181860160005b84811015610ea157601f1980878503018a5282518051808652610e8381888801898501610e0e565b9a86019a601f01909116939093018401925090830190600101610e5b565b5090979650505050505050565b6000610100808352610ec28184018c610d98565b9050602083820381850152610ed7828c610d98565b91508382036040850152610eeb828b610ddc565b91508382036060850152610eff828a610ddc565b84810360808601528851808252828a0193509082019060005b81811015610f3457845183529383019391830191600101610f18565b505084810360a0860152610f488189610e3e565b9250505082810360c0840152610f5e8186610ddc565b9150508260e08301529998505050505050505050565b6001600160a01b038116811461042157600080fd5b600060208284031215610f9b57600080fd5b8135610fa681610f74565b9392505050565b600060208284031215610fbf57600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561100057611000610fc6565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561102f5761102f610fc6565b604052919050565b6000806040838503121561104a57600080fd5b825167ffffffffffffffff8082111561106257600080fd5b818501915085601f83011261107657600080fd5b815160208282111561108a5761108a610fc6565b8160051b925061109b818401611006565b82815292840181019281810190898511156110b557600080fd5b948201945b848610156110df57855193506110cf84610f74565b83825294820194908201906110ba565b97909101519698969750505050505050565b634e487b7160e01b600052603260045260246000fd5b8051801515811461111757600080fd5b919050565b60008060008060008060c0878903121561113557600080fd5b865161114081610f74565b955061114e60208801611107565b945061115c60408801611107565b935061116a60608801611107565b92506080870151915060a087015167ffffffffffffffff8082111561118e57600080fd5b818901915089601f8301126111a257600080fd5b8151818111156111b4576111b4610fc6565b6111c7601f8201601f1916602001611006565b91508082528a60208285010111156111de57600080fd5b6111ef816020840160208601610e0e565b5080925050509295509295509295565b634e487b7160e01b600052601160045260246000fd5b6000600019821415611229576112296111ff565b5060010190565b60008219821115611243576112436111ff565b500190565b6000610120828403121561125b57600080fd5b611263610fdc565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b6000602082840312156112d557600080fd5b8151610fa681610f74565b6000602082840312156112f257600080fd5b610fa682611107565b600060ff821660ff811415611312576113126111ff565b6001019291505056fea2646970667358221220cf36b09d27ae2cf5294c9fc90733263156cdad217c239cb0cd8f26dded4d224f64736f6c634300080c0033`), + }, + { + // https://github.com/oasysgames/oasys-genesis-contract/blob/v1.7.0/contracts/token/LOAS.sol + contract: lockedOAS, + code: mustDecodeCode(`0x6080604052600436106101355760003560e01c8063775ad527116100ab578063a9059cbb1161006f578063a9059cbb1461037e578063d97830b11461039e578063dd62ed3e14610448578063eac449d91461048e578063f94a138b146104ae578063ffc3a769146104ce57600080fd5b8063775ad527146102bb5780637de6b1db146102db57806392de7482146102fb57806395d89b4114610349578063a457c2d71461035e57600080fd5b8063313ce567116100fd578063313ce567146101f6578063379607f5146102125780633950935114610232578063546cec3e146102525780636dec93f11461026557806370a082311461028557600080fd5b806306fdde031461013a578063095ea7b31461016557806318160ddd1461019557806323b872dd146101b45780632e87d48c146101d4575b600080fd5b34801561014657600080fd5b5061014f6104ee565b60405161015c91906117d5565b60405180910390f35b34801561017157600080fd5b50610185610180366004611846565b610580565b604051901515815260200161015c565b3480156101a157600080fd5b506002545b60405190815260200161015c565b3480156101c057600080fd5b506101856101cf366004611870565b610598565b3480156101e057600080fd5b506101f46101ef366004611987565b6105bc565b005b34801561020257600080fd5b506040516012815260200161015c565b34801561021e57600080fd5b506101f461022d3660046119d4565b61063f565b34801561023e57600080fd5b5061018561024d366004611846565b6107ac565b6101f4610260366004611a04565b6107eb565b34801561027157600080fd5b506101a6610280366004611a47565b6109e5565b34801561029157600080fd5b506101a66102a0366004611a47565b6001600160a01b031660009081526020819052604090205490565b3480156102c757600080fd5b506101f46102d6366004611a62565b610aef565b3480156102e757600080fd5b506101f46102f63660046119d4565b610b3a565b34801561030757600080fd5b50610331610316366004611a47565b6006602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161015c565b34801561035557600080fd5b5061014f610c90565b34801561036a57600080fd5b50610185610379366004611846565b610c9f565b34801561038a57600080fd5b50610185610399366004611846565b610d36565b3480156103aa57600080fd5b506104056103b9366004611a47565b60056020526000908152604090208054600182015460028301546003840154600490940154929391926001600160401b0380831693600160401b90930416916001600160a01b03169086565b6040805196875260208701959095526001600160401b0393841694860194909452911660608401526001600160a01b0316608083015260a082015260c00161015c565b34801561045457600080fd5b506101a6610463366004611a62565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b34801561049a57600080fd5b506101f46104a9366004611846565b610d44565b3480156104ba57600080fd5b506101856104c9366004611af0565b610f54565b3480156104da57600080fd5b506101856104e9366004611b77565b61103d565b6060600380546104fd90611bd0565b80601f016020809104026020016040519081016040528092919081815260200182805461052990611bd0565b80156105765780601f1061054b57610100808354040283529160200191610576565b820191906000526020600020905b81548152906001019060200180831161055957829003601f168201915b5050505050905090565b60003361058e8185856110fc565b5060019392505050565b6000336105a6858285611220565b6105b18585856112b2565b506001949350505050565b6001600160a01b038281166000908152600560205260409020600301541633146105f95760405163d8d5894f60e01b815260040160405180910390fd5b60005b815181101561063a576106288383838151811061061b5761061b611c0b565b602002602001015161148b565b8061063281611c37565b9150506105fc565b505050565b8061065d57604051637bc90c0560e11b815260040160405180910390fd5b336000818152600660208181526040808420546001600160a01b03168085526005835290842060018101549585529290915290929061069b906109e5565b6106a59190611c52565b9050808311156106c8576040516377dfdf2160e01b815260040160405180910390fd5b828260010160008282546106dc9190611c69565b909155506106ec9050338461151e565b604051600090339085908381818185875af1925050503d806000811461072e576040519150601f19603f3d011682016040523d82523d6000602084013e610733565b606091505b5050905080610755576040516312171d8360e31b815260040160405180910390fd5b336000908152600660209081526040918290205491518681526001600160a01b03909216917f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d491015b60405180910390a250505050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919061058e90829086906107e6908790611c69565b6110fc565b6001600160a01b0383166108125760405163ac6b05f560e01b815260040160405180910390fd5b6001600160a01b03838116600090815260066020526040902054161561084b57604051630fb356f360e21b815260040160405180910390fd5b42826001600160401b03161115806108755750806001600160401b0316826001600160401b031610155b1561089357604051636385801560e11b815260040160405180910390fd5b346108b157604051637bc90c0560e11b815260040160405180910390fd5b6108bb8334611678565b6040805160c08101825234808252600060208084018281526001600160401b0380891686880190815288821660608801908152336080890190815260a089018781526001600160a01b038e8116808a52600589528c8a209b518c55965160018c0155935160028b01805494518716600160401b026fffffffffffffffffffffffffffffffff199095169190961617929092179093559151600388018054919092166001600160a01b031991821617909155905160049096019590955560069091529084902080549093168117909255915190917fb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb916109d89190869086909283526001600160401b03918216602084015216604082015260600190565b60405180910390a2505050565b6001600160a01b038082166000908152600560209081526040808320815160c081018352815480825260018301549482019490945260028201546001600160401b0380821694830194909452600160401b900490921660608301526003810154909416608082015260049093015460a0840152909190610a685750600092915050565b80604001516001600160401b0316421015610a865750600092915050565b600081604001518260600151610a9c9190611c81565b6001600160401b031682604001516001600160401b031642610abe9190611c52565b8351610aca9190611ca9565b610ad49190611cc8565b8251909150811115610ae857505192915050565b9392505050565b6001600160a01b03828116600090815260056020526040902060030154163314610b2c5760405163d8d5894f60e01b815260040160405180910390fd5b610b36828261148b565b5050565b80610b5857604051637bc90c0560e11b815260040160405180910390fd5b336000908152600660209081526040808320546001600160a01b0316835260059091528120600481015460018201548254929392610b969190611c52565b610ba09190611c52565b905080831115610bc3576040516377dfdf2160e01b815260040160405180910390fd5b610bcd338461151e565b60038201546040516000916001600160a01b03169085908381818185875af1925050503d8060008114610c1c576040519150601f19603f3d011682016040523d82523d6000602084013e610c21565b606091505b5050905080610c43576040516312171d8360e31b815260040160405180910390fd5b336000908152600660209081526040918290205491518681526001600160a01b03909216917f443630e54cc5dd8826c25d7467193a3b7a0a67b4ed73c14fb477e8e7eed3fd48910161079e565b6060600480546104fd90611bd0565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919083811015610d295760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6105b182868684036110fc565b60003361058e8185856112b2565b6001600160a01b038083166000908152600660205260409020541680610d7d5760405163c5723b5160e01b815260040160405180910390fd5b6001600160a01b03808216600090815260056020526040902060038101549091163314610dbd57604051632c8c06e360e11b815260040160405180910390fd5b8280610e335760048201546001830154835460009291610ddc91611c52565b610de69190611c52565b905060008360010154610df8866109e5565b610e029190611c52565b9050808211610e2457604051637bc90c0560e11b815260040160405180910390fd5b610e2e8183611c52565b925050505b80610e53866001600160a01b031660009081526020819052604090205490565b1015610e72576040516377dfdf2160e01b815260040160405180910390fd5b80826004016000828254610e869190611c69565b90915550610e969050858261151e565b604051600090339083908381818185875af1925050503d8060008114610ed8576040519150601f19603f3d011682016040523d82523d6000602084013e610edd565b606091505b5050905080610eff576040516312171d8360e31b815260040160405180910390fd5b856001600160a01b0316846001600160a01b03167fb698e31a2abee5824d0d7bcfd2339aead7f9e9ae413fba50bf554ff3fa470b7b84604051610f4491815260200190565b60405180910390a3505050505050565b600082518451148015610f68575081518351145b610fc85760405162461bcd60e51b815260206004820152602b60248201527f4c4f41533a2062756c6b207472616e7366657246726f6d2061726773206d757360448201526a7420626520657175616c7360a81b6064820152608401610d20565b60005b84518110156105b15761102a858281518110610fe957610fe9611c0b565b602002602001015185838151811061100357611003611c0b565b602002602001015185848151811061101d5761101d611c0b565b6020026020010151610598565b508061103581611c37565b915050610fcb565b600081518351146110a05760405162461bcd60e51b815260206004820152602760248201527f4c4f41533a2062756c6b207472616e736665722061726773206d75737420626560448201526620657175616c7360c81b6064820152608401610d20565b3360005b84518110156105b1576110ea828683815181106110c3576110c3611c0b565b60200260200101518684815181106110dd576110dd611c0b565b60200260200101516112b2565b806110f481611c37565b9150506110a4565b6001600160a01b03831661115e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610d20565b6001600160a01b0382166111bf5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610d20565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146112ac578181101561129f5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610d20565b6112ac84848484036110fc565b50505050565b6001600160a01b0383166113165760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610d20565b6001600160a01b0382166113785760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610d20565b611383838383611763565b6001600160a01b038316600090815260208190526040902054818110156113fb5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610d20565b6001600160a01b03808516600090815260208190526040808220858503905591851681529081208054849290611432908490611c69565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161147e91815260200190565b60405180910390a36112ac565b6001600160a01b0381811660009081526006602052604090205416156114c457604051630fb356f360e21b815260040160405180910390fd5b6001600160a01b0381811660008181526006602052604080822080546001600160a01b0319169487169485179055519192917fdc5d0ac53741544fef2e2ae9b2c8006a9e56f9708377f300d8e825f8d411617d9190a35050565b6001600160a01b03821661157e5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610d20565b61158a82600083611763565b6001600160a01b038216600090815260208190526040902054818110156115fe5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610d20565b6001600160a01b038316600090815260208190526040812083830390556002805484929061162d908490611c52565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b6001600160a01b0382166116ce5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610d20565b6116da60008383611763565b80600260008282546116ec9190611c69565b90915550506001600160a01b03821660009081526020819052604081208054839290611719908490611c69565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6001600160a01b038316158061178057506001600160a01b038216155b1561178a57505050565b6001600160a01b038083166000908152600660205260408082205486841683529120548216911614156117bc57505050565b6040516325cdf54f60e21b815260040160405180910390fd5b600060208083528351808285015260005b81811015611802578581018301518582016040015282016117e6565b81811115611814576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461184157600080fd5b919050565b6000806040838503121561185957600080fd5b6118628361182a565b946020939093013593505050565b60008060006060848603121561188557600080fd5b61188e8461182a565b925061189c6020850161182a565b9150604084013590509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156118ea576118ea6118ac565b604052919050565b60006001600160401b0382111561190b5761190b6118ac565b5060051b60200190565b600082601f83011261192657600080fd5b8135602061193b611936836118f2565b6118c2565b82815260059290921b8401810191818101908684111561195a57600080fd5b8286015b8481101561197c5761196f8161182a565b835291830191830161195e565b509695505050505050565b6000806040838503121561199a57600080fd5b6119a38361182a565b915060208301356001600160401b038111156119be57600080fd5b6119ca85828601611915565b9150509250929050565b6000602082840312156119e657600080fd5b5035919050565b80356001600160401b038116811461184157600080fd5b600080600060608486031215611a1957600080fd5b611a228461182a565b9250611a30602085016119ed565b9150611a3e604085016119ed565b90509250925092565b600060208284031215611a5957600080fd5b610ae88261182a565b60008060408385031215611a7557600080fd5b611a7e8361182a565b9150611a8c6020840161182a565b90509250929050565b600082601f830112611aa657600080fd5b81356020611ab6611936836118f2565b82815260059290921b84018101918181019086841115611ad557600080fd5b8286015b8481101561197c5780358352918301918301611ad9565b600080600060608486031215611b0557600080fd5b83356001600160401b0380821115611b1c57600080fd5b611b2887838801611915565b94506020860135915080821115611b3e57600080fd5b611b4a87838801611915565b93506040860135915080821115611b6057600080fd5b50611b6d86828701611a95565b9150509250925092565b60008060408385031215611b8a57600080fd5b82356001600160401b0380821115611ba157600080fd5b611bad86838701611915565b93506020850135915080821115611bc357600080fd5b506119ca85828601611a95565b600181811c90821680611be457607f821691505b60208210811415611c0557634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415611c4b57611c4b611c21565b5060010190565b600082821015611c6457611c64611c21565b500390565b60008219821115611c7c57611c7c611c21565b500190565b60006001600160401b0383811690831681811015611ca157611ca1611c21565b039392505050565b6000816000190483118215151615611cc357611cc3611c21565b500290565b600082611ce557634e487b7160e01b600052601260045260246000fd5b50049056fea2646970667358221220076c6b49ddc21701856eeaed9f5f37b2a967f8bcf794aaf6efaa16dcdedc001664736f6c634300080c0033`), + }, +} diff --git a/contracts/oasys/oasys_test.go b/contracts/oasys/oasys_test.go index eb1493727..70008f0c9 100644 --- a/contracts/oasys/oasys_test.go +++ b/contracts/oasys/oasys_test.go @@ -1063,11 +1063,11 @@ func _deployments11(genesisHash common.Hash, contracts wantContracts) { contracts["0x0000000000000000000000000000000000001000"].storage = map[string]string{ // uint256[] public updates "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000002", - "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7": "0x00000000000000000000000000000000000000000000000000000000000003e7", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7": "0x00000000000000000000000000000000000000000000000000000000000002c7", // EnvironmentValue[] public values "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad7": "0x000000000000000000000000000000000000000000000000000000000057b700", - "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad8": "0x00000000000000000000000000000000000000000000000000000000000003e7", + "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad7": "0x00000000000000000000000000000000000000000000000000000000003e6700", + "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad8": "0x00000000000000000000000000000000000000000000000000000000000002c7", "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad9": "0x0000000000000000000000000000000000000000000000000000000000000006", "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ada": "0x0000000000000000000000000000000000000000000000000000000000003840", "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5adb": "0x000000000000000000000000000000000000000000000000000000000000000a", @@ -1113,6 +1113,17 @@ func _deployments11(genesisHash common.Hash, contracts wantContracts) { } } +func _deployments12(genesisHash common.Hash, contracts wantContracts) { + // StakeManager + contracts["0x0000000000000000000000000000000000001001"].codeHash = "f0b8fef7ea94ceb9ec2e102f52e4c06c" + + // CandidateValidatorManager + contracts["0x520000000000000000000000000000000000002e"].codeHash = "6de4d098a3297020346dcb7b2ba4914c" + + // LOAS + contracts["0x5200000000000000000000000000000000000023"].codeHash = "044637c8af353e46615765c8755265d6" +} + func TestDeploy(t *testing.T) { type wantDeployments []struct { block uint64 @@ -1140,7 +1151,8 @@ func TestDeploy(t *testing.T) { {971800, []deployFn{_deployments7}}, {1529980, []deployFn{_deployments9}}, {1892000, []deployFn{_deployments10}}, - {9999999, []deployFn{_deployments11}}, + {4089588, []deployFn{_deployments11}}, + {9999998, []deployFn{_deployments12}}, }, }, { @@ -1160,6 +1172,7 @@ func TestDeploy(t *testing.T) { {1519840, []deployFn{_deployments9}}, {1880660, []deployFn{_deployments10}}, {4017600, []deployFn{_deployments11}}, + {4958700, []deployFn{_deployments12}}, }, }, { @@ -1186,7 +1199,8 @@ func TestDeploy(t *testing.T) { _deployments8, _deployments9, _deployments10, - _deployments11, + // _deployments11, + _deployments12, }}, }, }, diff --git a/core/blockchain.go b/core/blockchain.go index c88d79b11..45a112144 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -58,7 +58,8 @@ var ( headHeaderGauge = metrics.NewRegisteredGauge("chain/head/header", nil) headFastBlockGauge = metrics.NewRegisteredGauge("chain/head/receipt", nil) headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil) - headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil) + + justifiedBlockGauge = metrics.NewRegisteredGauge("chain/head/justified", nil) chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil) @@ -228,6 +229,8 @@ type BlockChain struct { blockProcFeed event.Feed scope event.SubscriptionScope genesisBlock *types.Block + // for finality + finalizedHeaderFeed event.Feed // This mutex synchronizes chain write operations. // Readers don't need to take it, they can just read the database. @@ -236,7 +239,6 @@ type BlockChain struct { currentBlock atomic.Pointer[types.Header] // Current head of the chain currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block - currentSafeBlock atomic.Pointer[types.Header] // Latest (consensus) safe block bodyCache *lru.Cache[common.Hash, *types.Body] bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] @@ -323,7 +325,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis bc.currentBlock.Store(nil) bc.currentSnapBlock.Store(nil) bc.currentFinalBlock.Store(nil) - bc.currentSafeBlock.Store(nil) // Update chain info data metrics chainInfoGauge.Update(metrics.GaugeInfoValue{"chain_id": bc.chainConfig.ChainID.String()}) @@ -499,6 +500,19 @@ func (bc *BlockChain) empty() bool { return true } +// GetJustifiedNumber returns the highest justified blockNumber on the branch including and before `header`. +func (bc *BlockChain) GetJustifiedNumber(header *types.Header) uint64 { + if p, ok := bc.engine.(consensus.PoS); ok { + justifiedBlockNumber, _, err := p.GetJustifiedNumberAndHash(bc, []*types.Header{header}) + if err == nil { + return justifiedBlockNumber + } + } + // return 0 when err!=nil + // so the input `header` will at a disadvantage during reorg + return 0 +} + // loadLastState loads the last known chain state from the database. This method // assumes that the chain manager mutex is held. func (bc *BlockChain) loadLastState() error { @@ -547,8 +561,6 @@ func (bc *BlockChain) loadLastState() error { if block := bc.GetBlockByHash(head); block != nil { bc.currentFinalBlock.Store(block.Header()) headFinalizedBlockGauge.Update(int64(block.NumberU64())) - bc.currentSafeBlock.Store(block.Header()) - headSafeBlockGauge.Update(int64(block.NumberU64())) } } // Issue a status log for the user @@ -560,16 +572,16 @@ func (bc *BlockChain) loadLastState() error { blockTd = bc.GetTd(headBlock.Hash(), headBlock.NumberU64()) ) if headHeader.Hash() != headBlock.Hash() { - log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0))) + log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "root", headHeader.Root, "td", headerTd, "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0))) } - log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0))) + log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "root", headBlock.Root(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0))) if headBlock.Hash() != currentSnapBlock.Hash() { snapTd := bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64()) - log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "td", snapTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0))) + log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "root", currentSnapBlock.Root, "td", snapTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0))) } if currentFinalBlock != nil { finalTd := bc.GetTd(currentFinalBlock.Hash(), currentFinalBlock.Number.Uint64()) - log.Info("Loaded most recent local finalized block", "number", currentFinalBlock.Number, "hash", currentFinalBlock.Hash(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalBlock.Time), 0))) + log.Info("Loaded most recent local finalized block", "number", currentFinalBlock.Number, "hash", currentFinalBlock.Hash(), "root", currentFinalBlock.Root, "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalBlock.Time), 0))) } if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil { log.Info("Loaded last snap-sync pivot marker", "number", *pivot) @@ -632,16 +644,6 @@ func (bc *BlockChain) SetFinalized(header *types.Header) { } } -// SetSafe sets the safe block. -func (bc *BlockChain) SetSafe(header *types.Header) { - bc.currentSafeBlock.Store(header) - if header != nil { - headSafeBlockGauge.Update(int64(header.Number.Uint64())) - } else { - headSafeBlockGauge.Update(0) - } -} - // setHeadBeyondRoot rewinds the local chain to a new head with the extra condition // that the rewind must pass the specified state root. This method is meant to be // used when rewinding with snapshots enabled to ensure that we go back further than @@ -813,7 +815,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha // Clear safe block, finalized block if needed if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.Number.Uint64() { log.Warn("SetHead invalidated safe block") - bc.SetSafe(nil) + justifiedBlockGauge.Update(0) } if finalized := bc.CurrentFinalBlock(); finalized != nil && head < finalized.Number.Uint64() { log.Error("SetHead invalidated finalized block") @@ -887,6 +889,8 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error { bc.genesisBlock = genesis bc.currentBlock.Store(bc.genesisBlock.Header()) headBlockGauge.Update(int64(bc.genesisBlock.NumberU64())) + justifiedBlockGauge.Update(int64(bc.genesisBlock.NumberU64())) + headFinalizedBlockGauge.Update(int64(bc.genesisBlock.NumberU64())) bc.hc.SetGenesis(bc.genesisBlock.Header()) bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) bc.currentSnapBlock.Store(bc.genesisBlock.Header()) @@ -1142,7 +1146,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ // Rewind may have occurred, skip in that case. if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 { - reorg, err := bc.forker.ReorgNeeded(bc.CurrentSnapBlock(), head.Header()) + reorg, err := bc.forker.ReorgNeededWithFastFinality(bc.CurrentSnapBlock(), head.Header()) if err != nil { log.Warn("Reorg failed", "err", err) return false @@ -1501,7 +1505,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types return NonStatTy, err } currentBlock := bc.CurrentBlock() - reorg, err := bc.forker.ReorgNeeded(currentBlock, block.Header()) + reorg, err := bc.forker.ReorgNeededWithFastFinality(currentBlock, block.Header()) if err != nil { return NonStatTy, err } @@ -1527,6 +1531,15 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types if len(logs) > 0 { bc.logsFeed.Send(logs) } + var finalizedHeader *types.Header + if pos, ok := bc.Engine().(consensus.PoS); ok { + if finalizedHeader = pos.GetFinalizedHeader(bc, block.Header()); finalizedHeader != nil { + bc.SetFinalized(finalizedHeader) + } + if justifiedBlockNumber, _, err := pos.GetJustifiedNumberAndHash(bc, []*types.Header{block.Header()}); err == nil { + justifiedBlockGauge.Update(int64(justifiedBlockNumber)) + } + } // In theory, we should fire a ChainHeadEvent when we inject // a canonical block, but sometimes we can insert a batch of // canonical blocks. Avoid firing too many ChainHeadEvents, @@ -1534,6 +1547,9 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types // event here. if emitHeadEvent { bc.chainHeadFeed.Send(ChainHeadEvent{Block: block}) + if finalizedHeader != nil { + bc.finalizedHeaderFeed.Send(FinalizedHeaderEvent{finalizedHeader}) + } } } else { bc.chainSideFeed.Send(ChainSideEvent{Block: block}) @@ -1620,6 +1636,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) defer func() { if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() { bc.chainHeadFeed.Send(ChainHeadEvent{lastCanon}) + if pos, ok := bc.Engine().(consensus.PoS); ok { + if finalizedHeader := pos.GetFinalizedHeader(bc, lastCanon.Header()); finalizedHeader != nil { + bc.finalizedHeaderFeed.Send(FinalizedHeaderEvent{finalizedHeader}) + } + } } }() // Start the parallel header verifier @@ -1646,7 +1667,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) current = bc.CurrentBlock() ) for block != nil && bc.skipBlock(err, it) { - reorg, err = bc.forker.ReorgNeeded(current, block.Header()) + reorg, err = bc.forker.ReorgNeededWithFastFinality(current, block.Header()) if err != nil { return it.index, err } @@ -2011,7 +2032,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i // // If the externTd was larger than our local TD, we now need to reimport the previous // blocks to regenerate the required state - reorg, err := bc.forker.ReorgNeeded(current, lastBlock.Header()) + reorg, err := bc.forker.ReorgNeededWithFastFinality(current, lastBlock.Header()) if err != nil { return it.index, err } @@ -2242,6 +2263,12 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { // rewind the canonical chain to a lower point. log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "oldblocks", len(oldChain), "newnum", newBlock.Number(), "newhash", newBlock.Hash(), "newblocks", len(newChain)) } + // Reset the tx lookup cache in case to clear stale txlookups. + // This is done before writing any new chain data to avoid the + // weird scenario that canonical chain is changed while the + // stale lookups are still cached. + bc.txLookupCache.Purge() + // Insert the new chain(except the head block(reverse order)), // taking care of the proper incremental order. for i := len(newChain) - 1; i >= 1; i-- { @@ -2256,11 +2283,13 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { // Delete useless indexes right now which includes the non-canonical // transaction indexes, canonical chain indexes which above the head. - indexesBatch := bc.db.NewBatch() - for _, tx := range types.HashDifference(deletedTxs, addedTxs) { + var ( + indexesBatch = bc.db.NewBatch() + diffs = types.HashDifference(deletedTxs, addedTxs) + ) + for _, tx := range diffs { rawdb.DeleteTxLookupEntry(indexesBatch, tx) } - // Delete all hash markers that are not part of the new canonical chain. // Because the reorg function does not handle new chain head, all hash // markers greater than or equal to new chain head should be deleted. diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 466a86c14..9238ad4e8 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -59,7 +59,17 @@ func (bc *BlockChain) CurrentFinalBlock() *types.Header { // CurrentSafeBlock retrieves the current safe block of the canonical // chain. The block is retrieved from the blockchain's internal cache. func (bc *BlockChain) CurrentSafeBlock() *types.Header { - return bc.currentSafeBlock.Load() + if p, ok := bc.engine.(consensus.PoS); ok { + currentHeader := bc.CurrentHeader() + if currentHeader == nil { + return nil + } + _, justifiedBlockHash, err := p.GetJustifiedNumberAndHash(bc, []*types.Header{currentHeader}) + if err == nil { + return bc.GetHeaderByHash(justifiedBlockHash) + } + } + return nil } // HasHeader checks if a block header is present in the database or not, caching @@ -417,3 +427,8 @@ func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscription { return bc.scope.Track(bc.blockProcFeed.Subscribe(ch)) } + +// SubscribeFinalizedHeaderEvent registers a subscription of FinalizedHeaderEvent. +func (bc *BlockChain) SubscribeFinalizedHeaderEvent(ch chan<- FinalizedHeaderEvent) event.Subscription { + return bc.scope.Track(bc.finalizedHeaderFeed.Subscribe(ch)) +} diff --git a/core/events.go b/core/events.go index ac935a137..a06716299 100644 --- a/core/events.go +++ b/core/events.go @@ -30,6 +30,12 @@ type NewMinedBlockEvent struct{ Block *types.Block } // RemovedLogsEvent is posted when a reorg happens type RemovedLogsEvent struct{ Logs []*types.Log } +// NewVoteEvent is posted when a batch of votes enters the vote pool. +type NewVoteEvent struct{ Vote *types.VoteEnvelope } + +// FinalizedHeaderEvent is posted when a finalized header is reached. +type FinalizedHeaderEvent struct{ Header *types.Header } + type ChainEvent struct { Block *types.Block Hash common.Hash diff --git a/core/forkchoice.go b/core/forkchoice.go index b293c851b..e64c78233 100644 --- a/core/forkchoice.go +++ b/core/forkchoice.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -36,6 +37,12 @@ type ChainReader interface { // Config retrieves the header chain's chain configuration. Config() *params.ChainConfig + // Engine retrieves the blockchain's consensus engine. + Engine() consensus.Engine + + // GetJustifiedNumber returns the highest justified blockNumber on the branch including and before `header` + GetJustifiedNumber(header *types.Header) uint64 + // GetTd returns the total difficulty of a local block. GetTd(common.Hash, uint64) *big.Int } @@ -111,3 +118,28 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b } return reorg, nil } + +// ReorgNeededWithFastFinality compares justified block numbers firstly, backoff to compare tds when equal +func (f *ForkChoice) ReorgNeededWithFastFinality(current *types.Header, header *types.Header) (bool, error) { + _, ok := f.chain.Engine().(consensus.PoS) + if !ok { + return f.ReorgNeeded(current, header) + } + + justifiedNumber, curJustifiedNumber := uint64(0), uint64(0) + if f.chain.Config().IsFastFinalityEnabled(header.Number) { + justifiedNumber = f.chain.GetJustifiedNumber(header) + } + if f.chain.Config().IsFastFinalityEnabled(current.Number) { + curJustifiedNumber = f.chain.GetJustifiedNumber(current) + } + if justifiedNumber == curJustifiedNumber { + return f.ReorgNeeded(current, header) + } + + if justifiedNumber > curJustifiedNumber && header.Number.Cmp(current.Number) <= 0 { + log.Info("Chain find higher justifiedNumber", "fromHeight", current.Number, "fromHash", current.Hash(), "fromMiner", current.Coinbase, "fromJustified", curJustifiedNumber, + "toHeight", header.Number, "toHash", header.Hash(), "toMiner", header.Coinbase, "toJustified", justifiedNumber) + } + return justifiedNumber > curJustifiedNumber, nil +} diff --git a/core/headerchain.go b/core/headerchain.go index 519a32ab8..a0e2b7921 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -104,9 +104,23 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c } hc.currentHeaderHash = hc.CurrentHeader().Hash() headHeaderGauge.Update(hc.CurrentHeader().Number.Int64()) + return hc, nil } +// getJustifiedNumber returns the highest justified blockNumber on the branch including and before `header`. +func (hc *HeaderChain) GetJustifiedNumber(header *types.Header) uint64 { + if p, ok := hc.engine.(consensus.PoS); ok { + justifiedBlockNumber, _, err := p.GetJustifiedNumberAndHash(hc, []*types.Header{header}) + if err == nil { + return justifiedBlockNumber + } + } + // return 0 when err!=nil + // so the input `header` will at a disadvantage during reorg + return 0 +} + // GetBlockNumber retrieves the block number belonging to the given hash // from the cache or database func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 { @@ -279,7 +293,7 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F } ) // Ask the fork choicer if the reorg is necessary - if reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader); err != nil { + if reorg, err := forker.ReorgNeededWithFastFinality(hc.CurrentHeader(), lastHeader); err != nil { return nil, err } else if !reorg { if inserted != 0 { diff --git a/core/monitor/malicious_vote_monitor.go b/core/monitor/malicious_vote_monitor.go new file mode 100644 index 000000000..b622be158 --- /dev/null +++ b/core/monitor/malicious_vote_monitor.go @@ -0,0 +1,97 @@ +package monitor + +import ( + "encoding/json" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + lru "github.com/hashicorp/golang-lru" +) + +// follow define in core/vote +const ( + maxSizeOfRecentEntry = 512 + maliciousVoteSlashScope = 256 + upperLimitOfVoteBlockNumber = 11 +) + +var ( + violateRule1Counter = metrics.NewRegisteredCounter("monitor/maliciousVote/violateRule1", nil) + violateRule2Counter = metrics.NewRegisteredCounter("monitor/maliciousVote/violateRule2", nil) +) + +// two purposes +// 1. monitor whether there are bugs in the voting mechanism, so add metrics to observe it. +// 2. do malicious vote slashing. TODO +type MaliciousVoteMonitor struct { + curVotes map[types.BLSPublicKey]*lru.Cache +} + +func NewMaliciousVoteMonitor() *MaliciousVoteMonitor { + return &MaliciousVoteMonitor{ + curVotes: make(map[types.BLSPublicKey]*lru.Cache), + } +} + +func (m *MaliciousVoteMonitor) ConflictDetect(newVote *types.VoteEnvelope, pendingBlockNumber uint64) bool { + // get votes for specified VoteAddress + if _, ok := m.curVotes[newVote.VoteAddress]; !ok { + voteDataBuffer, err := lru.New(maxSizeOfRecentEntry) + if err != nil { + log.Error("MaliciousVoteMonitor new lru failed", "err", err) + return false + } + m.curVotes[newVote.VoteAddress] = voteDataBuffer + } + voteDataBuffer := m.curVotes[newVote.VoteAddress] + sourceNumber, targetNumber := newVote.Data.SourceNumber, newVote.Data.TargetNumber + + //Basic check + // refer to https://github.com/bnb-chain/bsc-genesis-contract/blob/master/contracts/SlashIndicator.sol#LL207C4-L207C4 + if !(targetNumber+maliciousVoteSlashScope > pendingBlockNumber) { + return false + } + + // UnderRules check + blockNumber := sourceNumber + 1 + if !(blockNumber+maliciousVoteSlashScope > pendingBlockNumber) { + blockNumber = pendingBlockNumber - maliciousVoteSlashScope + 1 + } + newVoteHash := newVote.Data.Hash() + for ; blockNumber <= pendingBlockNumber+upperLimitOfVoteBlockNumber; blockNumber++ { + if voteDataBuffer.Contains(blockNumber) { + voteEnvelope, ok := voteDataBuffer.Get(blockNumber) + if !ok { + log.Error("Failed to get voteData info from LRU cache.") + continue + } + maliciousVote := false + if blockNumber == targetNumber && voteEnvelope.(*types.VoteEnvelope).Data.Hash() != newVoteHash { + violateRule1Counter.Inc(1) + maliciousVote = true + } else if (blockNumber < targetNumber && voteEnvelope.(*types.VoteEnvelope).Data.SourceNumber > sourceNumber) || + (blockNumber > targetNumber && voteEnvelope.(*types.VoteEnvelope).Data.SourceNumber < sourceNumber) { + violateRule2Counter.Inc(1) + maliciousVote = true + } + if maliciousVote { + evidence := types.NewSlashIndicatorFinalityEvidenceWrapper(voteEnvelope.(*types.VoteEnvelope), newVote) + if evidence != nil { + if evidenceJson, err := json.Marshal(evidence); err == nil { + log.Warn("MaliciousVote", "evidence", string(evidenceJson)) + } else { + log.Warn("MaliciousVote, Marshal evidence failed") + } + } else { + log.Warn("MaliciousVote, construct evidence failed") + } + return true + } + } + } + + // for simplicity, Just override even if the targetNumber has existed. + voteDataBuffer.Add(newVote.Data.TargetNumber, newVote) + return false +} diff --git a/core/types/block.go b/core/types/block.go index 1a357baa3..4870802bf 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) // A BlockNonce is a 64-bit hash which proves (combined with the @@ -512,3 +513,76 @@ func HeaderParentHashFromRLP(header []byte) common.Hash { } return common.BytesToHash(parentHash) } + +var ( + extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity + extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal +) + +func SealHash(header *Header) (hash common.Hash) { + hasher := sha3.NewLegacyKeccak256() + EncodeSigHeader(hasher, header) + hasher.Sum(hash[:0]) + return hash +} + +func EncodeSigHeader(w io.Writer, header *Header) { + enc := []interface{}{ + header.ParentHash, + header.UncleHash, + header.Coinbase, + header.Root, + header.TxHash, + header.ReceiptHash, + header.Bloom, + header.Difficulty, + header.Number, + header.GasLimit, + header.GasUsed, + header.Time, + header.Extra[:len(header.Extra)-extraSeal], // this will panic if extra is too short, should check before calling encodeSigHeader + header.MixDigest, + header.Nonce, + } + if header.BaseFee != nil { + enc = append(enc, header.BaseFee) + } + if header.WithdrawalsHash != nil { + panic("unexpected withdrawal hash value in oasys") + } + if header.ExcessBlobGas != nil { + panic("unexpected excess blob gas value in oasys") + } + if header.BlobGasUsed != nil { + panic("unexpected blob gas used value in oasys") + } + if header.ParentBeaconRoot != nil { + panic("unexpected parent beacon root value in oasys") + } + if err := rlp.Encode(w, enc); err != nil { + panic("can't encode: " + err.Error()) + } +} + +func EncodeSigHeaderWithoutVoteAttestation(w io.Writer, header *Header) { + err := rlp.Encode(w, []interface{}{ + header.ParentHash, + header.UncleHash, + header.Coinbase, + header.Root, + header.TxHash, + header.ReceiptHash, + header.Bloom, + header.Difficulty, + header.Number, + header.GasLimit, + header.GasUsed, + header.Time, + header.Extra[:extraVanity], // this will panic if extra is too short, should check before calling encodeSigHeaderWithoutVoteAttestation + header.MixDigest, + header.Nonce, + }) + if err != nil { + panic("can't encode: " + err.Error()) + } +} diff --git a/core/types/vote.go b/core/types/vote.go new file mode 100644 index 000000000..81fe4c794 --- /dev/null +++ b/core/types/vote.go @@ -0,0 +1,149 @@ +package types + +import ( + "bytes" + "math/big" + "reflect" + "sync/atomic" + + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v5/crypto/bls" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +const ( + BLSPublicKeyLength = 48 + BLSSignatureLength = 96 + + MaxAttestationExtraLength = 256 +) + +var ( + blsPublicKeyT = reflect.TypeOf(BLSPublicKey{}) +) + +type BLSPublicKey [BLSPublicKeyLength]byte +type BLSSignature [BLSSignatureLength]byte +type ValidatorsBitSet uint64 + +// VoteData represents the vote range that validator voted for fast finality. +type VoteData struct { + SourceNumber uint64 // The source block number should be the latest justified block number. + SourceHash common.Hash // The block hash of the source block. + TargetNumber uint64 // The target block number which validator wants to vote for. + TargetHash common.Hash // The block hash of the target block. +} + +// Hash returns the hash of the vote data. +func (d *VoteData) Hash() common.Hash { return rlpHash(d) } + +// VoteEnvelope represents the vote of a single validator. +type VoteEnvelope struct { + VoteAddress BLSPublicKey // The BLS public key of the validator. + Signature BLSSignature // Validator's signature for the vote data. + Data *VoteData // The vote data for fast finality. + + // caches + hash atomic.Value +} + +// VoteAttestation represents the votes of super majority validators. +type VoteAttestation struct { + VoteAddressSet ValidatorsBitSet // The bitset marks the voted validators. + AggSignature BLSSignature // The aggregated BLS signature of the voted validators' signatures. + Data *VoteData // The vote data for fast finality. + Extra []byte // Reserved for future usage. +} + +// Hash returns the vote's hash. +func (v *VoteEnvelope) Hash() common.Hash { + if hash := v.hash.Load(); hash != nil { + return hash.(common.Hash) + } + + h := v.calcVoteHash() + v.hash.Store(h) + return h +} + +func (v *VoteEnvelope) calcVoteHash() common.Hash { + vote := struct { + VoteAddress BLSPublicKey + Signature BLSSignature + Data *VoteData + }{v.VoteAddress, v.Signature, v.Data} + return rlpHash(vote) +} + +func (b BLSPublicKey) Bytes() []byte { return b[:] } +func (b BLSPublicKey) String() string { return hexutil.Encode(b[:]) } + +// MarshalText gets implements encoding.TextMarshaler. Since BLSPublicKey is stored as JSON in the +// consensus engine's snapshot db, it is converted to a hex-string to improve readability and reduce size. +func (b BLSPublicKey) MarshalText() ([]byte, error) { + return hexutil.Bytes(b[:]).MarshalText() +} + +// UnmarshalJSON decodes the input as a string with 0x prefix +func (b *BLSPublicKey) UnmarshalJSON(input []byte) error { + return hexutil.UnmarshalFixedJSON(blsPublicKeyT, input, b[:]) +} + +// Verify vote using BLS. +func (vote *VoteEnvelope) Verify() error { + blsPubKey, err := bls.PublicKeyFromBytes(vote.VoteAddress[:]) + if err != nil { + return errors.Wrap(err, "convert public key from bytes to bls failed") + } + + sig, err := bls.SignatureFromBytes(vote.Signature[:]) + if err != nil { + return errors.Wrap(err, "invalid signature") + } + + voteDataHash := vote.Data.Hash() + if !sig.Verify(blsPubKey, voteDataHash[:]) { + return errors.New("verify bls signature failed.") + } + return nil +} + +type SlashIndicatorVoteDataWrapper struct { + SrcNum *big.Int + SrcHash string + TarNum *big.Int + TarHash string + Sig string +} + +type SlashIndicatorFinalityEvidenceWrapper struct { + VoteA SlashIndicatorVoteDataWrapper + VoteB SlashIndicatorVoteDataWrapper + VoteAddr string +} + +func NewSlashIndicatorFinalityEvidenceWrapper(vote1, vote2 *VoteEnvelope) *SlashIndicatorFinalityEvidenceWrapper { + if !bytes.Equal(vote1.VoteAddress[:], vote1.VoteAddress[:]) || + vote1.Data == nil || vote2.Data == nil { + return nil + } + return &SlashIndicatorFinalityEvidenceWrapper{ + VoteA: SlashIndicatorVoteDataWrapper{ + SrcNum: big.NewInt(int64(vote1.Data.SourceNumber)), + SrcHash: common.Bytes2Hex(vote1.Data.SourceHash[:]), + TarNum: big.NewInt(int64(vote1.Data.TargetNumber)), + TarHash: common.Bytes2Hex(vote1.Data.TargetHash[:]), + Sig: common.Bytes2Hex(vote1.Signature[:]), + }, + VoteB: SlashIndicatorVoteDataWrapper{ + SrcNum: big.NewInt(int64(vote2.Data.SourceNumber)), + SrcHash: common.Bytes2Hex(vote2.Data.SourceHash[:]), + TarNum: big.NewInt(int64(vote2.Data.TargetNumber)), + TarHash: common.Bytes2Hex(vote2.Data.TargetHash[:]), + Sig: common.Bytes2Hex(vote2.Signature[:]), + }, + VoteAddr: common.Bytes2Hex(vote1.VoteAddress[:]), + } +} diff --git a/core/vote/vote_journal.go b/core/vote/vote_journal.go new file mode 100644 index 000000000..2b8cc1921 --- /dev/null +++ b/core/vote/vote_journal.go @@ -0,0 +1,125 @@ +package vote + +import ( + "encoding/json" + + lru "github.com/hashicorp/golang-lru" + "github.com/tidwall/wal" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" +) + +const ( + maxSizeOfRecentEntry = 512 + maliciousVoteSlashScope = 256 +) + +type VoteJournal struct { + journalPath string // file path of disk journal for saving the vote. + + walLog *wal.Log + + voteDataBuffer *lru.Cache +} + +var voteJournalErrorCounter = metrics.NewRegisteredCounter("voteJournal/error", nil) + +func NewVoteJournal(filePath string) (*VoteJournal, error) { + walLog, err := wal.Open(filePath, &wal.Options{ + LogFormat: wal.JSON, + SegmentCacheSize: maxSizeOfRecentEntry, + }) + if err != nil { + log.Error("Failed to open vote journal", "err", err) + return nil, err + } + + voteDataBuffer, err := lru.New(maxSizeOfRecentEntry) + if err != nil { + return nil, err + } + + firstIndex, err := walLog.FirstIndex() + if err != nil { + log.Error("Failed to get first index of votes journal", "err", err) + } + + lastIndex, err := walLog.LastIndex() + if err != nil { + log.Error("Failed to get lastIndex of vote journal", "err", err) + return nil, err + } + + voteJournal := &VoteJournal{ + journalPath: filePath, + walLog: walLog, + } + + // Reload all voteData from journal to lru memory everytime node reboot. + for index := firstIndex; index <= lastIndex; index++ { + if voteEnvelop, err := voteJournal.ReadVote(index); err == nil && voteEnvelop != nil { + voteData := voteEnvelop.Data + voteDataBuffer.Add(voteData.TargetNumber, voteData) + } + } + voteJournal.voteDataBuffer = voteDataBuffer + + return voteJournal, nil +} + +func (journal *VoteJournal) WriteVote(voteMessage *types.VoteEnvelope) error { + walLog := journal.walLog + + vote, err := json.Marshal(voteMessage) + if err != nil { + log.Error("Failed to unmarshal vote", "err", err) + return err + } + + lastIndex, err := walLog.LastIndex() + if err != nil { + log.Error("Failed to get lastIndex of vote journal", "err", err) + return err + } + + lastIndex += 1 + if err = walLog.Write(lastIndex, vote); err != nil { + log.Error("Failed to write vote journal", "err", err) + return err + } + + firstIndex, err := walLog.FirstIndex() + if err != nil { + log.Error("Failed to get first index of votes journal", "err", err) + } + + if lastIndex-firstIndex+1 > maxSizeOfRecentEntry { + if err := walLog.TruncateFront(lastIndex - maxSizeOfRecentEntry + 1); err != nil { + log.Error("Failed to truncate votes journal", "err", err) + } + } + + journal.voteDataBuffer.Add(voteMessage.Data.TargetNumber, voteMessage.Data) + return nil +} + +func (journal *VoteJournal) ReadVote(index uint64) (*types.VoteEnvelope, error) { + voteMessage, err := journal.walLog.Read(index) + if err != nil && err != wal.ErrNotFound { + log.Error("Failed to read votes journal", "err", err) + return nil, err + } + + var vote *types.VoteEnvelope + if voteMessage != nil { + vote = &types.VoteEnvelope{} + if err := json.Unmarshal(voteMessage, vote); err != nil { + log.Error("Failed to read vote from voteJournal", "err", err) + return nil, err + } + } + + return vote, nil +} diff --git a/core/vote/vote_manager.go b/core/vote/vote_manager.go new file mode 100644 index 000000000..5b3508ed2 --- /dev/null +++ b/core/vote/vote_manager.go @@ -0,0 +1,264 @@ +package vote + +import ( + "bytes" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/downloader" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" +) + +const blocksNumberSinceMining = 5 // the number of blocks need to wait before voting, counting from the validator begin to mine + +var votesManagerCounter = metrics.NewRegisteredCounter("votesManager/local", nil) + +// Backend wraps all methods required for voting. +type Backend interface { + IsMining() bool + EventMux() *event.TypeMux +} + +// VoteManager will handle the vote produced by self. +type VoteManager struct { + eth Backend + + chain *core.BlockChain + + chainHeadCh chan core.ChainHeadEvent + chainHeadSub event.Subscription + + // used for backup validators to sync votes from corresponding mining validator + syncVoteCh chan core.NewVoteEvent + syncVoteSub event.Subscription + + pool *VotePool + signer *VoteSigner + journal *VoteJournal + + engine consensus.PoS +} + +func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journalPath, blsPasswordPath, blsWalletPath, blsAccountName string, engine consensus.PoS) (*VoteManager, error) { + voteManager := &VoteManager{ + eth: eth, + chain: chain, + chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), + syncVoteCh: make(chan core.NewVoteEvent, voteBufferForPut), + pool: pool, + engine: engine, + } + + // Create voteSigner. + voteSigner, err := NewVoteSigner(blsPasswordPath, blsWalletPath, blsAccountName) + if err != nil { + return nil, err + } + log.Info("Create voteSigner successfully", "pubKey", common.Bytes2Hex(voteSigner.PubKey[:])) + voteManager.signer = voteSigner + + // Create voteJournal + voteJournal, err := NewVoteJournal(journalPath) + if err != nil { + return nil, err + } + log.Info("Create voteJournal successfully") + voteManager.journal = voteJournal + + // Subscribe to chain head event. + voteManager.chainHeadSub = voteManager.chain.SubscribeChainHeadEvent(voteManager.chainHeadCh) + voteManager.syncVoteSub = voteManager.pool.SubscribeNewVoteEvent(voteManager.syncVoteCh) + + go voteManager.loop() + + return voteManager, nil +} + +func (voteManager *VoteManager) loop() { + log.Debug("vote manager routine loop started") + defer voteManager.chainHeadSub.Unsubscribe() + defer voteManager.syncVoteSub.Unsubscribe() + + events := voteManager.eth.EventMux().Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{}) + defer func() { + log.Debug("vote manager loop defer func occur") + if !events.Closed() { + log.Debug("event not closed, unsubscribed by vote manager loop") + events.Unsubscribe() + } + }() + + dlEventCh := events.Chan() + + startVote := true + blockCountSinceMining := 0 + for { + select { + case ev := <-dlEventCh: + if ev == nil { + log.Debug("dlEvent is nil, continue") + continue + } + switch ev.Data.(type) { + case downloader.StartEvent: + log.Debug("downloader is in startEvent mode, will not startVote") + startVote = false + case downloader.FailedEvent: + log.Debug("downloader is in FailedEvent mode, set startVote flag as true") + startVote = true + case downloader.DoneEvent: + log.Debug("downloader is in DoneEvent mode, set the startVote flag to true") + startVote = true + } + case cHead := <-voteManager.chainHeadCh: + if !startVote { + log.Debug("startVote flag is false, continue") + continue + } + if !voteManager.eth.IsMining() { + blockCountSinceMining = 0 + log.Debug("skip voting because mining is disabled, continue") + continue + } + blockCountSinceMining++ + if blockCountSinceMining <= blocksNumberSinceMining { + log.Debug("skip voting", "blockCountSinceMining", blockCountSinceMining, "blocksNumberSinceMining", blocksNumberSinceMining) + continue + } + + if cHead.Block == nil { + log.Debug("cHead.Block is nil, continue") + continue + } + + curHead := cHead.Block.Header() + // Check if cur validator is within the validatorSet at curHead + if !voteManager.engine.IsActiveValidatorAt(voteManager.chain, curHead, + func(bLSPublicKey *types.BLSPublicKey) bool { + return bytes.Equal(voteManager.signer.PubKey[:], bLSPublicKey[:]) + }) { + log.Debug("cur validator is not within the validatorSet at curHead or registered blsPubKey does not match", "signer", common.Bytes2Hex(voteManager.signer.PubKey[:]), "curHead", curHead.Number) + continue + } + + // Vote for curBlockHeader block. + vote := &types.VoteData{ + TargetNumber: curHead.Number.Uint64(), + TargetHash: curHead.Hash(), + } + voteMessage := &types.VoteEnvelope{ + Data: vote, + } + + // Put Vote into journal and VotesPool if we are active validator and allow to sign it. + if ok, sourceNumber, sourceHash := voteManager.UnderRules(curHead); ok { + log.Debug("curHead is underRules for voting") + if sourceHash == (common.Hash{}) { + log.Debug("sourceHash is empty") + continue + } + + voteMessage.Data.SourceNumber = sourceNumber + voteMessage.Data.SourceHash = sourceHash + + if err := voteManager.signer.SignVote(voteMessage); err != nil { + log.Error("Failed to sign vote", "err", err, "votedBlockNumber", voteMessage.Data.TargetNumber, "votedBlockHash", voteMessage.Data.TargetHash, "voteMessageHash", voteMessage.Hash()) + votesSigningErrorCounter.Inc(1) + continue + } + if err := voteManager.journal.WriteVote(voteMessage); err != nil { + log.Error("Failed to write vote into journal", "err", err) + voteJournalErrorCounter.Inc(1) + continue + } + + log.Debug("vote manager produced vote", "votedBlockNumber", voteMessage.Data.TargetNumber, "votedBlockHash", voteMessage.Data.TargetHash, "voteMessageHash", voteMessage.Hash()) + voteManager.pool.PutVote(voteMessage) + votesManagerCounter.Inc(1) + } + case event := <-voteManager.syncVoteCh: + voteMessage := event.Vote + if voteManager.eth.IsMining() || !bytes.Equal(voteManager.signer.PubKey[:], voteMessage.VoteAddress[:]) { + continue + } + if err := voteManager.journal.WriteVote(voteMessage); err != nil { + log.Error("Failed to write vote into journal", "err", err) + voteJournalErrorCounter.Inc(1) + continue + } + log.Debug("vote manager synced vote", "votedBlockNumber", voteMessage.Data.TargetNumber, "votedBlockHash", voteMessage.Data.TargetHash, "voteMessageHash", voteMessage.Hash()) + votesManagerCounter.Inc(1) + case <-voteManager.syncVoteSub.Err(): + log.Debug("voteManager subscribed votes failed") + return + case <-voteManager.chainHeadSub.Err(): + log.Debug("voteManager subscribed chainHead failed") + return + } + } +} + +// UnderRules checks if the produced header under the following rules: +// A validator must not publish two distinct votes for the same height. (Rule 1) +// A validator must not vote within the span of its other votes . (Rule 2) +// Validators always vote for their canonical chain’s latest block. (Rule 3) +func (voteManager *VoteManager) UnderRules(header *types.Header) (bool, uint64, common.Hash) { + sourceNumber, sourceHash, err := voteManager.engine.GetJustifiedNumberAndHash(voteManager.chain, []*types.Header{header}) + if err != nil { + log.Error("failed to get the highest justified number and hash at cur header", "curHeader's BlockNumber", header.Number, "curHeader's BlockHash", header.Hash()) + return false, 0, common.Hash{} + } + + targetNumber := header.Number.Uint64() + + voteDataBuffer := voteManager.journal.voteDataBuffer + //Rule 1: A validator must not publish two distinct votes for the same height. + if voteDataBuffer.Contains(targetNumber) { + log.Debug("err: A validator must not publish two distinct votes for the same height.") + return false, 0, common.Hash{} + } + + //Rule 2: A validator must not vote within the span of its other votes. + blockNumber := sourceNumber + 1 + if blockNumber+maliciousVoteSlashScope < targetNumber { + blockNumber = targetNumber - maliciousVoteSlashScope + } + for ; blockNumber < targetNumber; blockNumber++ { + if voteDataBuffer.Contains(blockNumber) { + voteData, ok := voteDataBuffer.Get(blockNumber) + if !ok { + log.Error("Failed to get voteData info from LRU cache.") + continue + } + if voteData.(*types.VoteData).SourceNumber > sourceNumber { + log.Debug(fmt.Sprintf("error: cur vote %d-->%d is across the span of other votes %d-->%d", + sourceNumber, targetNumber, voteData.(*types.VoteData).SourceNumber, voteData.(*types.VoteData).TargetNumber)) + return false, 0, common.Hash{} + } + } + } + for blockNumber := targetNumber + 1; blockNumber <= targetNumber+upperLimitOfVoteBlockNumber; blockNumber++ { + if voteDataBuffer.Contains(blockNumber) { + voteData, ok := voteDataBuffer.Get(blockNumber) + if !ok { + log.Error("Failed to get voteData info from LRU cache.") + continue + } + if voteData.(*types.VoteData).SourceNumber < sourceNumber { + log.Debug(fmt.Sprintf("error: cur vote %d-->%d is within the span of other votes %d-->%d", + sourceNumber, targetNumber, voteData.(*types.VoteData).SourceNumber, voteData.(*types.VoteData).TargetNumber)) + return false, 0, common.Hash{} + } + } + } + + // Rule 3: Validators always vote for their canonical chain’s latest block. + // Since the header subscribed to is the canonical chain, so this rule is satisfied by default. + log.Debug("All three rules check passed") + return true, sourceNumber, sourceHash +} diff --git a/core/vote/vote_pool.go b/core/vote/vote_pool.go new file mode 100644 index 000000000..d8bf87e5b --- /dev/null +++ b/core/vote/vote_pool.go @@ -0,0 +1,396 @@ +package vote + +import ( + "container/heap" + "sync" + + mapset "github.com/deckarep/golang-set/v2" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" +) + +const ( + maxCurVoteAmountPerBlock = 50 + maxFutureVoteAmountPerBlock = 100 + + voteBufferForPut = 256 + // votes in the range (currentBlockNum-256,currentBlockNum+11] will be stored + lowerLimitOfVoteBlockNumber = 256 + upperLimitOfVoteBlockNumber = 11 // refer to fetcher.maxUncleDist + + chainHeadChanSize = 10 // chainHeadChanSize is the size of channel listening to ChainHeadEvent. +) + +var ( + localCurVotesCounter = metrics.NewRegisteredCounter("curVotes/local", nil) + localFutureVotesCounter = metrics.NewRegisteredCounter("futureVotes/local", nil) + + localReceivedVotesGauge = metrics.NewRegisteredGauge("receivedVotes/local", nil) + + localCurVotesPqGauge = metrics.NewRegisteredGauge("curVotesPq/local", nil) + localFutureVotesPqGauge = metrics.NewRegisteredGauge("futureVotesPq/local", nil) +) + +type VoteBox struct { + blockNumber uint64 + voteMessages []*types.VoteEnvelope +} + +type VotePool struct { + chain *core.BlockChain + mu sync.RWMutex + + votesFeed event.Feed + scope event.SubscriptionScope + + receivedVotes mapset.Set[common.Hash] + + curVotes map[common.Hash]*VoteBox + futureVotes map[common.Hash]*VoteBox + + curVotesPq *votesPriorityQueue + futureVotesPq *votesPriorityQueue + + chainHeadCh chan core.ChainHeadEvent + chainHeadSub event.Subscription + + votesCh chan *types.VoteEnvelope + + engine consensus.PoS +} + +type votesPriorityQueue []*types.VoteData + +func NewVotePool(chain *core.BlockChain, engine consensus.PoS) *VotePool { + votePool := &VotePool{ + chain: chain, + receivedVotes: mapset.NewSet[common.Hash](), + curVotes: make(map[common.Hash]*VoteBox), + futureVotes: make(map[common.Hash]*VoteBox), + curVotesPq: &votesPriorityQueue{}, + futureVotesPq: &votesPriorityQueue{}, + chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), + votesCh: make(chan *types.VoteEnvelope, voteBufferForPut), + engine: engine, + } + + // Subscribe events from blockchain and start the main event loop. + votePool.chainHeadSub = votePool.chain.SubscribeChainHeadEvent(votePool.chainHeadCh) + + go votePool.loop() + return votePool +} + +// loop is the vote pool's main even loop, waiting for and reacting to outside blockchain events and votes channel event. +func (pool *VotePool) loop() { + defer pool.chainHeadSub.Unsubscribe() + + for { + select { + // Handle ChainHeadEvent. + case ev := <-pool.chainHeadCh: + if ev.Block != nil { + latestBlockNumber := ev.Block.NumberU64() + pool.prune(latestBlockNumber) + pool.transferVotesFromFutureToCur(ev.Block.Header()) + } + case <-pool.chainHeadSub.Err(): + return + + // Handle votes channel and put the vote into vote pool. + case vote := <-pool.votesCh: + pool.putIntoVotePool(vote) + } + } +} + +func (pool *VotePool) PutVote(vote *types.VoteEnvelope) { + pool.votesCh <- vote +} + +func (pool *VotePool) putIntoVotePool(vote *types.VoteEnvelope) bool { + targetNumber := vote.Data.TargetNumber + targetHash := vote.Data.TargetHash + header := pool.chain.CurrentBlock() + headNumber := header.Number.Uint64() + + // Make sure in the range (currentHeight-lowerLimitOfVoteBlockNumber, currentHeight+upperLimitOfVoteBlockNumber]. + if targetNumber+lowerLimitOfVoteBlockNumber-1 < headNumber || targetNumber > headNumber+upperLimitOfVoteBlockNumber { + log.Debug("BlockNumber of vote is outside the range of header-256~header+11, will be discarded") + return false + } + + voteData := &types.VoteData{ + TargetNumber: targetNumber, + TargetHash: targetHash, + } + + var votes map[common.Hash]*VoteBox + var votesPq *votesPriorityQueue + isFutureVote := false + + voteBlock := pool.chain.GetHeaderByHash(targetHash) + if voteBlock == nil { + votes = pool.futureVotes + votesPq = pool.futureVotesPq + isFutureVote = true + } else { + votes = pool.curVotes + votesPq = pool.curVotesPq + } + + voteHash := vote.Hash() + if ok := pool.basicVerify(vote, headNumber, votes, isFutureVote, voteHash); !ok { + return false + } + + if !isFutureVote { + // Verify if the vote comes from valid validators based on voteAddress (BLSPublicKey), only verify curVotes here, will verify futureVotes in transfer process. + if err := pool.engine.VerifyVote(pool.chain, vote); err != nil { + log.Warn("invalid vote", "sourceNumber", vote.Data.SourceNumber, "targetNumber", vote.Data.TargetNumber, "err", err) + return false + } + + // Send vote for handler usage of broadcasting to peers. + voteEv := core.NewVoteEvent{Vote: vote} + pool.votesFeed.Send(voteEv) + } + + pool.putVote(votes, votesPq, vote, voteData, voteHash, isFutureVote) + + return true +} + +func (pool *VotePool) SubscribeNewVoteEvent(ch chan<- core.NewVoteEvent) event.Subscription { + return pool.scope.Track(pool.votesFeed.Subscribe(ch)) +} + +func (pool *VotePool) putVote(m map[common.Hash]*VoteBox, votesPq *votesPriorityQueue, vote *types.VoteEnvelope, voteData *types.VoteData, voteHash common.Hash, isFutureVote bool) { + targetHash := vote.Data.TargetHash + targetNumber := vote.Data.TargetNumber + + pool.mu.Lock() + defer pool.mu.Unlock() + if _, ok := m[targetHash]; !ok { + // Push into votes priorityQueue if not exist in corresponding votes Map. + // To be noted: will not put into priorityQueue if exists in map to avoid duplicate element with the same voteData. + heap.Push(votesPq, voteData) + voteBox := &VoteBox{ + blockNumber: targetNumber, + voteMessages: make([]*types.VoteEnvelope, 0, maxFutureVoteAmountPerBlock), + } + m[targetHash] = voteBox + + if isFutureVote { + localFutureVotesPqGauge.Update(int64(votesPq.Len())) + } else { + localCurVotesPqGauge.Update(int64(votesPq.Len())) + } + } + + // Put into corresponding votes map. + m[targetHash].voteMessages = append(m[targetHash].voteMessages, vote) + // Add into received vote to avoid future duplicated vote comes. + pool.receivedVotes.Add(voteHash) + log.Debug("VoteHash put into votepool is:", "voteHash", voteHash, "sourceNumber", vote.Data.SourceNumber, "targetNumber", vote.Data.TargetNumber, "signer", common.Bytes2Hex(vote.VoteAddress[:])) + + if isFutureVote { + localFutureVotesCounter.Inc(1) + } else { + localCurVotesCounter.Inc(1) + } + localReceivedVotesGauge.Update(int64(pool.receivedVotes.Cardinality())) +} + +func (pool *VotePool) transferVotesFromFutureToCur(latestBlockHeader *types.Header) { + pool.mu.Lock() + defer pool.mu.Unlock() + + futurePq := pool.futureVotesPq + latestBlockNumber := latestBlockHeader.Number.Uint64() + + // For vote in the range [,latestBlockNumber-11), transfer to cur if valid. + for futurePq.Len() > 0 && futurePq.Peek().TargetNumber+upperLimitOfVoteBlockNumber < latestBlockNumber { + blockHash := futurePq.Peek().TargetHash + pool.transfer(blockHash) + } + + // For vote in the range [latestBlockNumber-11,latestBlockNumber], only transfer the vote inside the local fork. + futurePqBuffer := make([]*types.VoteData, 0) + for futurePq.Len() > 0 && futurePq.Peek().TargetNumber <= latestBlockNumber { + blockHash := futurePq.Peek().TargetHash + header := pool.chain.GetHeaderByHash(blockHash) + if header == nil { + // Put into pq buffer used for later put again into futurePq + futurePqBuffer = append(futurePqBuffer, heap.Pop(futurePq).(*types.VoteData)) + continue + } + pool.transfer(blockHash) + } + + for _, voteData := range futurePqBuffer { + heap.Push(futurePq, voteData) + } +} + +func (pool *VotePool) transfer(blockHash common.Hash) { + curPq, futurePq := pool.curVotesPq, pool.futureVotesPq + curVotes, futureVotes := pool.curVotes, pool.futureVotes + voteData := heap.Pop(futurePq) + + defer localFutureVotesPqGauge.Update(int64(futurePq.Len())) + + voteBox, ok := futureVotes[blockHash] + if !ok { + return + } + + validVotes := make([]*types.VoteEnvelope, 0, len(voteBox.voteMessages)) + for _, vote := range voteBox.voteMessages { + // Verify if the vote comes from valid validators based on voteAddress (BLSPublicKey). + if err := pool.engine.VerifyVote(pool.chain, vote); err != nil { + log.Warn("invalid vote", "sourceNumber", vote.Data.SourceNumber, "targetNumber", vote.Data.TargetNumber, "err", err) + pool.receivedVotes.Remove(vote.Hash()) + continue + } + + // In the process of transfer, send valid vote to votes channel for handler usage + voteEv := core.NewVoteEvent{Vote: vote} + pool.votesFeed.Send(voteEv) + validVotes = append(validVotes, vote) + } + + // may len(curVotes[blockHash].voteMessages) extra maxCurVoteAmountPerBlock, but it doesn't matter + if _, ok := curVotes[blockHash]; !ok { + heap.Push(curPq, voteData) + curVotes[blockHash] = &VoteBox{voteBox.blockNumber, validVotes} + localCurVotesPqGauge.Update(int64(curPq.Len())) + } else { + curVotes[blockHash].voteMessages = append(curVotes[blockHash].voteMessages, validVotes...) + } + + delete(futureVotes, blockHash) + + localCurVotesCounter.Inc(int64(len(validVotes))) + localFutureVotesCounter.Dec(int64(len(voteBox.voteMessages))) +} + +// Prune old data of duplicationSet, curVotePq and curVotesMap. +func (pool *VotePool) prune(latestBlockNumber uint64) { + pool.mu.Lock() + defer pool.mu.Unlock() + curVotes := pool.curVotes + curVotesPq := pool.curVotesPq + + // delete votes in the range [,latestBlockNumber-lowerLimitOfVoteBlockNumber] + for curVotesPq.Len() > 0 && curVotesPq.Peek().TargetNumber+lowerLimitOfVoteBlockNumber-1 < latestBlockNumber { + // Prune curPriorityQueue. + blockHash := heap.Pop(curVotesPq).(*types.VoteData).TargetHash + localCurVotesPqGauge.Update(int64(curVotesPq.Len())) + if voteBox, ok := curVotes[blockHash]; ok { + voteMessages := voteBox.voteMessages + // Prune duplicationSet. + for _, voteMessage := range voteMessages { + voteHash := voteMessage.Hash() + pool.receivedVotes.Remove(voteHash) + } + // Prune curVotes Map. + delete(curVotes, blockHash) + + localCurVotesCounter.Dec(int64(len(voteMessages))) + localReceivedVotesGauge.Update(int64(pool.receivedVotes.Cardinality())) + } + } +} + +// GetVotes as batch. +func (pool *VotePool) GetVotes() []*types.VoteEnvelope { + pool.mu.RLock() + defer pool.mu.RUnlock() + + votesRes := make([]*types.VoteEnvelope, 0) + curVotes := pool.curVotes + for _, voteBox := range curVotes { + votesRes = append(votesRes, voteBox.voteMessages...) + } + return votesRes +} + +func (pool *VotePool) FetchVoteByBlockHash(blockHash common.Hash) []*types.VoteEnvelope { + pool.mu.RLock() + defer pool.mu.RUnlock() + if _, ok := pool.curVotes[blockHash]; ok { + return pool.curVotes[blockHash].voteMessages + } + return nil +} + +func (pool *VotePool) basicVerify(vote *types.VoteEnvelope, headNumber uint64, m map[common.Hash]*VoteBox, isFutureVote bool, voteHash common.Hash) bool { + targetHash := vote.Data.TargetHash + pool.mu.RLock() + defer pool.mu.RUnlock() + + // Check duplicate voteMessage firstly. + if pool.receivedVotes.Contains(voteHash) { + log.Debug("Vote pool already contained the same vote", "voteHash", voteHash, "sourceNumber", vote.Data.SourceNumber, "targetNumber", vote.Data.TargetNumber) + return false + } + + // To prevent DOS attacks, make sure no more than 50 votes per blockHash if not futureVotes + // and no more than 100 votes per blockHash if futureVotes. + maxVoteAmountPerBlock := maxCurVoteAmountPerBlock + if isFutureVote { + maxVoteAmountPerBlock = maxFutureVoteAmountPerBlock + } + if voteBox, ok := m[targetHash]; ok { + if len(voteBox.voteMessages) >= maxVoteAmountPerBlock { + return false + } + } + + // Verify bls signature. + if err := vote.Verify(); err != nil { + log.Error("Failed to verify voteMessage", "err", err) + return false + } + + return true +} + +func (pq votesPriorityQueue) Less(i, j int) bool { + return pq[i].TargetNumber < pq[j].TargetNumber +} + +func (pq votesPriorityQueue) Len() int { + return len(pq) +} + +func (pq votesPriorityQueue) Swap(i, j int) { + pq[i], pq[j] = pq[j], pq[i] +} + +func (pq *votesPriorityQueue) Push(vote interface{}) { + curVote := vote.(*types.VoteData) + *pq = append(*pq, curVote) +} + +func (pq *votesPriorityQueue) Pop() interface{} { + tmp := *pq + l := len(tmp) + var res interface{} = tmp[l-1] + *pq = tmp[:l-1] + return res +} + +func (pq *votesPriorityQueue) Peek() *types.VoteData { + if pq.Len() == 0 { + return nil + } + return (*pq)[0] +} diff --git a/core/vote/vote_signer.go b/core/vote/vote_signer.go new file mode 100644 index 000000000..90c4c8a26 --- /dev/null +++ b/core/vote/vote_signer.go @@ -0,0 +1,135 @@ +package vote + +import ( + "context" + "os" + "time" + + "github.com/pkg/errors" + + "github.com/prysmaticlabs/prysm/v5/crypto/bls" + validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client" + "github.com/prysmaticlabs/prysm/v5/validator/accounts/iface" + "github.com/prysmaticlabs/prysm/v5/validator/accounts/wallet" + "github.com/prysmaticlabs/prysm/v5/validator/keymanager" + "github.com/prysmaticlabs/prysm/v5/validator/keymanager/local" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" +) + +const ( + voteSignerTimeout = time.Second * 5 +) + +var votesSigningErrorCounter = metrics.NewRegisteredCounter("votesSigner/error", nil) + +type VoteSigner struct { + km *keymanager.IKeymanager + PubKey [48]byte +} + +func NewVoteSigner(blsPasswordPath, blsWalletPath, blsAccountName string) (*VoteSigner, error) { + dirExists, err := wallet.Exists(blsWalletPath) + if err != nil { + log.Error("Check BLS wallet exists", "err", err) + return nil, err + } + if !dirExists { + log.Error("BLS wallet did not exists.") + return nil, errors.New("BLS wallet did not exists") + } + + walletPassword, err := os.ReadFile(blsPasswordPath) + if err != nil { + log.Error("Read BLS wallet password", "err", err) + return nil, err + } + log.Info("Read BLS wallet password successfully") + + w, err := wallet.OpenWallet(context.Background(), &wallet.Config{ + WalletDir: blsWalletPath, + WalletPassword: string(walletPassword), + }) + if err != nil { + log.Error("Open BLS wallet failed", "err", err) + return nil, err + } + log.Info("Open BLS wallet successfully") + + km, err := w.InitializeKeymanager(context.Background(), iface.InitKeymanagerConfig{ListenForChanges: false}) + if err != nil { + log.Error("Initialize key manager failed", "err", err) + return nil, err + } + log.Info("Initialized keymanager successfully") + + ctx, cancel := context.WithTimeout(context.Background(), voteSignerTimeout) + defer cancel() + + pubKeys, err := km.FetchValidatingPublicKeys(ctx) + if err != nil { + return nil, errors.Wrap(err, "could not fetch validating public keys") + } + if len(pubKeys) == 0 { + return nil, errors.New("no public keys in the BLS wallet") + } + + // The default uses the first found key. + pubKey := pubKeys[0] + + // If a key name is specified, find for it, but use the first key if not found. + if blsAccountName != "" { + ikm, ok := km.(*local.Keymanager) + if !ok { + return nil, errors.New("could not assert BLS keymanager interface to concrete type") + } + accountNames, err := ikm.ValidatingAccountNames() + if err != nil { + return nil, errors.Wrap(err, "could not fetch BLS account names") + } + var found bool + for i := 0; i < len(accountNames) && !found; i++ { + found = accountNames[i] == blsAccountName + if found { + pubKey = pubKeys[i] + } + } + if !found { + log.Warn("Configured voting BLS public key was not found, so the default key will be used", + "configured", blsAccountName, "default", accountNames[0]) + } + } + + return &VoteSigner{ + km: &km, + PubKey: pubKey, + }, nil +} + +func (signer *VoteSigner) SignVote(vote *types.VoteEnvelope) error { + // Sign the vote, fetch the first pubKey as validator's bls public key. + pubKey := signer.PubKey + blsPubKey, err := bls.PublicKeyFromBytes(pubKey[:]) + if err != nil { + return errors.Wrap(err, "convert public key from bytes to bls failed") + } + + voteDataHash := vote.Data.Hash() + + ctx, cancel := context.WithTimeout(context.Background(), voteSignerTimeout) + defer cancel() + + signature, err := (*signer.km).Sign(ctx, &validatorpb.SignRequest{ + PublicKey: pubKey[:], + SigningRoot: voteDataHash[:], + }) + if err != nil { + return err + } + + copy(vote.VoteAddress[:], blsPubKey.Marshal()[:]) + copy(vote.Signature[:], signature.Marshal()[:]) + return nil +} diff --git a/crypto/crypto.go b/crypto/crypto.go index 2492165d3..3b9bdec2a 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -165,7 +165,7 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte { // UnmarshalPubkey converts bytes to a secp256k1 public key. func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) { - x, y := elliptic.Unmarshal(S256(), pub) + x, y := elliptic.Unmarshal(S256(), pub) //nolint:all //TODO if x == nil { return nil, errInvalidPubkey } @@ -176,7 +176,7 @@ func FromECDSAPub(pub *ecdsa.PublicKey) []byte { if pub == nil || pub.X == nil || pub.Y == nil { return nil } - return elliptic.Marshal(S256(), pub.X, pub.Y) + return elliptic.Marshal(S256(), pub.X, pub.Y) //nolint:all //TODO } // HexToECDSA parses a secp256k1 private key. diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 738bb8f58..fec6b75e2 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -95,7 +95,7 @@ func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey { // Generate an elliptic curve public / private keypair. If params is nil, // the recommended default parameters for the key will be chosen. func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) { - pb, x, y, err := elliptic.GenerateKey(curve, rand) + pb, x, y, err := elliptic.GenerateKey(curve, rand) //nolint:all //TODO if err != nil { return } @@ -255,7 +255,7 @@ func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err e d := messageTag(params.Hash, Km, em, s2) - Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y) + Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y) //nolint:all //TODO ct = make([]byte, len(Rb)+len(em)+len(d)) copy(ct, Rb) copy(ct[len(Rb):], em) @@ -297,7 +297,7 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) { R := new(PublicKey) R.Curve = prv.PublicKey.Curve - R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen]) + R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen]) //nolint:all //TODO if R.X == nil { return nil, ErrInvalidPublicKey } diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index 74408d06d..a135291a7 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -24,7 +24,7 @@ func generateKeyPair() (pubkey, privkey []byte) { if err != nil { panic(err) } - pubkey = elliptic.Marshal(S256(), key.X, key.Y) + pubkey = elliptic.Marshal(S256(), key.X, key.Y) //nolint:all //TODO privkey = make([]byte, 32) blob := key.D.Bytes() diff --git a/crypto/signature_cgo.go b/crypto/signature_cgo.go index 2339e5201..0cf0599e3 100644 --- a/crypto/signature_cgo.go +++ b/crypto/signature_cgo.go @@ -41,7 +41,7 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { return nil, err } - x, y := elliptic.Unmarshal(S256(), s) + x, y := elliptic.Unmarshal(S256(), s) //nolint:all, TODO return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil } diff --git a/eth/api_backend.go b/eth/api_backend.go index 84eb20009..9982e2bbd 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -279,6 +279,10 @@ func (b *EthAPIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) e return b.eth.BlockChain().SubscribeChainHeadEvent(ch) } +func (b *EthAPIBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription { + return b.eth.BlockChain().SubscribeFinalizedHeaderEvent(ch) +} + func (b *EthAPIBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { return b.eth.BlockChain().SubscribeChainSideEvent(ch) } @@ -337,6 +341,13 @@ func (b *EthAPIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.S return b.eth.txPool.SubscribeTransactions(ch, true) } +func (b *EthAPIBackend) SubscribeNewVoteEvent(ch chan<- core.NewVoteEvent) event.Subscription { + if b.eth.VotePool() == nil { + return nil + } + return b.eth.VotePool().SubscribeNewVoteEvent(ch) +} + func (b *EthAPIBackend) SyncProgress() ethereum.SyncProgress { return b.eth.Downloader().Progress() } diff --git a/eth/backend.go b/eth/backend.go index c3b2fb49a..30f34c5ea 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/oasys" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/monitor" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/pruner" "github.com/ethereum/go-ethereum/core/txpool" @@ -40,9 +41,11 @@ import ( "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/core/vote" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/gasprice" + "github.com/ethereum/go-ethereum/eth/protocols/bsc" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/ethdb" @@ -71,11 +74,12 @@ type Ethereum struct { // Handlers txPool *txpool.TxPool - blockchain *core.BlockChain - handler *handler - ethDialCandidates enode.Iterator - snapDialCandidates enode.Iterator - merger *consensus.Merger + blockchain *core.BlockChain + handler *handler + ethDialCandidates enode.Iterator + snapDialCandidates enode.Iterator + emptyDialCandidates enode.Iterator + merger *consensus.Merger // DB interfaces chainDb ethdb.Database // Block chain database @@ -102,6 +106,8 @@ type Ethereum struct { lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) shutdownTracker *shutdowncheck.ShutdownTracker // Tracks if and when the node has shutdown ungracefully + + votePool *vote.VotePool } // New creates a new Ethereum object (including the @@ -260,6 +266,40 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine, eth.isLocalBlock) eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) + // Create voteManager instance + if posa, ok := eth.engine.(consensus.PoS); ok { + // Create votePool instance + votePool := vote.NewVotePool(eth.blockchain, posa) + eth.votePool = votePool + if oasys, ok := eth.engine.(*oasys.Oasys); ok { + if !config.Miner.DisableVoteAttestation { + // if there is no VotePool in Oasys Engine, the miner can't get votes for assembling + oasys.VotePool = votePool + } + } else { + return nil, errors.New("Engine is not Oasys type") + } + log.Info("Create votePool successfully") + eth.handler.votepool = votePool + if stack.Config().EnableMaliciousVoteMonitor { + eth.handler.maliciousVoteMonitor = monitor.NewMaliciousVoteMonitor() + log.Info("Create MaliciousVoteMonitor successfully") + } + + if config.Miner.VoteEnable { + conf := stack.Config() + blsPasswordPath := stack.ResolvePath(conf.BLSPasswordFile) + blsWalletPath := stack.ResolvePath(conf.BLSWalletDir) + blsAccountName := conf.VoteKeyName + voteJournalPath := stack.ResolvePath(conf.VoteJournalDir) + if _, err := vote.NewVoteManager(eth, eth.blockchain, votePool, voteJournalPath, blsPasswordPath, blsWalletPath, blsAccountName, posa); err != nil { + log.Error("Failed to Initialize voteManager", "err", err) + return nil, err + } + log.Info("Create voteManager successfully") + } + } + gpoParams := config.GPO if gpoParams.Default == nil { gpoParams.Default = config.Miner.GasPrice @@ -276,6 +316,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } + eth.emptyDialCandidates, err = dnsclient.NewIterator() + if err != nil { + return nil, err + } // Start the RPC service eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID) @@ -499,6 +543,7 @@ func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } func (s *Ethereum) TxPool() *txpool.TxPool { return s.txPool } +func (s *Ethereum) VotePool() *vote.VotePool { return s.votePool } func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } func (s *Ethereum) Engine() consensus.Engine { return s.engine } func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } @@ -521,6 +566,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol { if s.config.SnapshotCache > 0 { protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) } + protos = append(protos, bsc.MakeProtocols((*bscHandler)(s.handler), s.emptyDialCandidates)...) return protos } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 37b0248f2..271ceb570 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -358,7 +358,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain")) } // Set the safe block - api.eth.BlockChain().SetSafe(safeBlock.Header()) + // api.eth.BlockChain().SetSafe(safeBlock.Header()) } // If payload generation was requested, create a new block to be potentially // sealed by the beacon client. The payload will be requested later, and we diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index 126eaaea7..4c4ee0cba 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -89,6 +89,9 @@ type blockBroadcasterFn func(block *types.Block, propagate bool) // chainHeightFn is a callback type to retrieve the current chain height. type chainHeightFn func() uint64 +// chainFinalizedHeightFn is a callback type to retrieve the current chain finalized height. +type chainFinalizedHeightFn func() uint64 + // headersInsertFn is a callback type to insert a batch of headers into the local chain. type headersInsertFn func(headers []*types.Header) (int, error) @@ -180,14 +183,15 @@ type BlockFetcher struct { queued map[common.Hash]*blockOrHeaderInject // Set of already queued blocks (to dedup imports) // Callbacks - getHeader HeaderRetrievalFn // Retrieves a header from the local chain - getBlock blockRetrievalFn // Retrieves a block from the local chain - verifyHeader headerVerifierFn // Checks if a block's headers have a valid proof of work - broadcastBlock blockBroadcasterFn // Broadcasts a block to connected peers - chainHeight chainHeightFn // Retrieves the current chain's height - insertHeaders headersInsertFn // Injects a batch of headers into the chain - insertChain chainInsertFn // Injects a batch of blocks into the chain - dropPeer peerDropFn // Drops a peer for misbehaving + getHeader HeaderRetrievalFn // Retrieves a header from the local chain + getBlock blockRetrievalFn // Retrieves a block from the local chain + verifyHeader headerVerifierFn // Checks if a block's headers have a valid proof of work + broadcastBlock blockBroadcasterFn // Broadcasts a block to connected peers + chainHeight chainHeightFn // Retrieves the current chain's height + chainFinalizedHeight chainFinalizedHeightFn // Retrieves the current chain's finalized height + insertHeaders headersInsertFn // Injects a batch of headers into the chain + insertChain chainInsertFn // Injects a batch of blocks into the chain + dropPeer peerDropFn // Drops a peer for misbehaving // Testing hooks announceChangeHook func(common.Hash, bool) // Method to call upon adding or deleting a hash from the blockAnnounce list @@ -198,31 +202,34 @@ type BlockFetcher struct { } // NewBlockFetcher creates a block fetcher to retrieve blocks based on hash announcements. -func NewBlockFetcher(light bool, getHeader HeaderRetrievalFn, getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBlock blockBroadcasterFn, chainHeight chainHeightFn, insertHeaders headersInsertFn, insertChain chainInsertFn, dropPeer peerDropFn) *BlockFetcher { +func NewBlockFetcher(light bool, getHeader HeaderRetrievalFn, getBlock blockRetrievalFn, verifyHeader headerVerifierFn, + broadcastBlock blockBroadcasterFn, chainHeight chainHeightFn, chainFinalizedHeight chainFinalizedHeightFn, + insertHeaders headersInsertFn, insertChain chainInsertFn, dropPeer peerDropFn) *BlockFetcher { return &BlockFetcher{ - light: light, - notify: make(chan *blockAnnounce), - inject: make(chan *blockOrHeaderInject), - headerFilter: make(chan chan *headerFilterTask), - bodyFilter: make(chan chan *bodyFilterTask), - done: make(chan common.Hash), - quit: make(chan struct{}), - announces: make(map[string]int), - announced: make(map[common.Hash][]*blockAnnounce), - fetching: make(map[common.Hash]*blockAnnounce), - fetched: make(map[common.Hash][]*blockAnnounce), - completing: make(map[common.Hash]*blockAnnounce), - queue: prque.New[int64, *blockOrHeaderInject](nil), - queues: make(map[string]int), - queued: make(map[common.Hash]*blockOrHeaderInject), - getHeader: getHeader, - getBlock: getBlock, - verifyHeader: verifyHeader, - broadcastBlock: broadcastBlock, - chainHeight: chainHeight, - insertHeaders: insertHeaders, - insertChain: insertChain, - dropPeer: dropPeer, + light: light, + notify: make(chan *blockAnnounce), + inject: make(chan *blockOrHeaderInject), + headerFilter: make(chan chan *headerFilterTask), + bodyFilter: make(chan chan *bodyFilterTask), + done: make(chan common.Hash), + quit: make(chan struct{}), + announces: make(map[string]int), + announced: make(map[common.Hash][]*blockAnnounce), + fetching: make(map[common.Hash]*blockAnnounce), + fetched: make(map[common.Hash][]*blockAnnounce), + completing: make(map[common.Hash]*blockAnnounce), + queue: prque.New[int64, *blockOrHeaderInject](nil), + queues: make(map[string]int), + queued: make(map[common.Hash]*blockOrHeaderInject), + getHeader: getHeader, + getBlock: getBlock, + verifyHeader: verifyHeader, + broadcastBlock: broadcastBlock, + chainHeight: chainHeight, + chainFinalizedHeight: chainFinalizedHeight, + insertHeaders: insertHeaders, + insertChain: insertChain, + dropPeer: dropPeer, } } @@ -366,7 +373,8 @@ func (f *BlockFetcher) loop() { break } // Otherwise if fresh and still unknown, try and import - if (number+maxUncleDist < height) || (f.light && f.getHeader(hash) != nil) || (!f.light && f.getBlock(hash) != nil) { + finalizedHeight := f.chainFinalizedHeight() + if (number+maxUncleDist < height) || number <= finalizedHeight || (f.light && f.getHeader(hash) != nil) || (!f.light && f.getBlock(hash) != nil) { f.forgetBlock(hash) continue } @@ -397,7 +405,13 @@ func (f *BlockFetcher) loop() { } // If we have a valid block number, check that it's potentially useful if dist := int64(notification.number) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist { - log.Debug("Peer discarded announcement", "peer", notification.origin, "number", notification.number, "hash", notification.hash, "distance", dist) + log.Debug("Peer discarded announcement by distance", "peer", notification.origin, "number", notification.number, "hash", notification.hash, "distance", dist) + blockAnnounceDropMeter.Mark(1) + break + } + finalized := f.chainFinalizedHeight() + if notification.number <= finalized { + log.Debug("Peer discarded announcement by finality", "peer", notification.origin, "number", notification.number, "hash", notification.hash, "finalized", finalized) blockAnnounceDropMeter.Mark(1) break } @@ -782,6 +796,14 @@ func (f *BlockFetcher) enqueue(peer string, header *types.Header, block *types.B f.forgetHash(hash) return } + // Discard any block that is below the current finalized height + finalizedHeight := f.chainFinalizedHeight() + if number <= finalizedHeight { + log.Debug("Discarded delivered header or block, below or equal to finalized", "peer", peer, "number", number, "hash", hash, "finalized", finalizedHeight) + blockBroadcastDropMeter.Mark(1) + f.forgetHash(hash) + return + } // Schedule the block for future importing if _, ok := f.queued[hash]; !ok { op := &blockOrHeaderInject{origin: peer} diff --git a/eth/fetcher/block_fetcher_test.go b/eth/fetcher/block_fetcher_test.go index 6927300b1..42eacc8e6 100644 --- a/eth/fetcher/block_fetcher_test.go +++ b/eth/fetcher/block_fetcher_test.go @@ -101,7 +101,9 @@ func newTester(light bool) *fetcherTester { blocks: map[common.Hash]*types.Block{genesis.Hash(): genesis}, drops: make(map[string]bool), } - tester.fetcher = NewBlockFetcher(light, tester.getHeader, tester.getBlock, tester.verifyHeader, tester.broadcastBlock, tester.chainHeight, tester.insertHeaders, tester.insertChain, tester.dropPeer) + tester.fetcher = NewBlockFetcher(light, tester.getHeader, tester.getBlock, tester.verifyHeader, + tester.broadcastBlock, tester.chainHeight, tester.chainFinalizedHeight, tester.insertHeaders, + tester.insertChain, tester.dropPeer) tester.fetcher.Start() return tester @@ -143,6 +145,18 @@ func (f *fetcherTester) chainHeight() uint64 { return f.blocks[f.hashes[len(f.hashes)-1]].NumberU64() } +func (f *fetcherTester) chainFinalizedHeight() uint64 { + f.lock.RLock() + defer f.lock.RUnlock() + if len(f.hashes) < 3 { + return 0 + } + if f.fetcher.light { + return f.headers[f.hashes[len(f.hashes)-3]].Number.Uint64() + } + return f.blocks[f.hashes[len(f.hashes)-3]].NumberU64() +} + // insertChain injects a new headers into the simulated chain. func (f *fetcherTester) insertHeaders(headers []*types.Header) (int, error) { f.lock.Lock() @@ -735,6 +749,67 @@ func testDistantAnnouncementDiscarding(t *testing.T, light bool) { } } +// Tests that announcements with numbers much lower or equal to the current finalized block +// head get discarded to prevent wasting resources on useless blocks from faulty peers. +func TestFullFinalizedAnnouncementDiscarding(t *testing.T) { + testFinalizedAnnouncementDiscarding(t, false) +} +func TestLightFinalizedAnnouncementDiscarding(t *testing.T) { + testFinalizedAnnouncementDiscarding(t, true) +} + +func testFinalizedAnnouncementDiscarding(t *testing.T, light bool) { + // Create a long chain to import and define the discard boundaries + hashes, blocks := makeChain(3*maxQueueDist, 0, genesis) + + head := hashes[len(hashes)/2] + justified := hashes[len(hashes)/2+1] + finalized := hashes[len(hashes)/2+2] + beforeFinalized := hashes[len(hashes)/2+3] + + low, equal := len(hashes)/2+3, len(hashes)/2+2 + + // Create a tester and simulate a head block being the middle of the above chain + tester := newTester(light) + + tester.lock.Lock() + tester.hashes = []common.Hash{beforeFinalized, finalized, justified, head} + tester.headers = map[common.Hash]*types.Header{ + beforeFinalized: blocks[beforeFinalized].Header(), + finalized: blocks[finalized].Header(), + justified: blocks[justified].Header(), + head: blocks[head].Header(), + } + tester.blocks = map[common.Hash]*types.Block{ + beforeFinalized: blocks[beforeFinalized], + finalized: blocks[finalized], + justified: blocks[justified], + head: blocks[head], + } + tester.lock.Unlock() + + headerFetcher := tester.makeHeaderFetcher("lower", blocks, -gatherSlack) + bodyFetcher := tester.makeBodyFetcher("lower", blocks, 0) + + fetching := make(chan struct{}, 2) + tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- struct{}{} } + + // Ensure that a block with a lower number than the finalized height is discarded + tester.fetcher.Notify("lower", hashes[low], blocks[hashes[low]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + select { + case <-time.After(50 * time.Millisecond): + case <-fetching: + t.Fatalf("fetcher requested stale header") + } + // Ensure that a block with a same number of the finalized height is discarded + tester.fetcher.Notify("equal", hashes[equal], blocks[hashes[equal]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + select { + case <-time.After(50 * time.Millisecond): + case <-fetching: + t.Fatalf("fetcher requested future header") + } +} + // Tests that peers announcing blocks with invalid numbers (i.e. not matching // the headers provided afterwards) get dropped as malicious. func TestFullInvalidNumberAnnouncement(t *testing.T) { testInvalidNumberAnnouncement(t, false) } @@ -775,7 +850,6 @@ func testInvalidNumberAnnouncement(t *testing.T, light bool) { continue case <-time.After(1 * time.Second): t.Fatal("announce timeout") - return } } } diff --git a/eth/filters/api.go b/eth/filters/api.go index a4eaa9cec..013598e31 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -188,6 +189,68 @@ func (api *FilterAPI) NewPendingTransactions(ctx context.Context, fullTx *bool) return rpcSub, nil } +// NewVotesFilter creates a filter that fetches votes that entered the vote pool. +// It is part of the filter package since polling goes with eth_getFilterChanges. +func (api *FilterAPI) NewVotesFilter() rpc.ID { + var ( + votes = make(chan *types.VoteEnvelope) + voteSub = api.events.SubscribeNewVotes(votes) + ) + api.filtersMu.Lock() + api.filters[voteSub.ID] = &filter{typ: VotesSubscription, deadline: time.NewTimer(api.timeout), hashes: make([]common.Hash, 0), s: voteSub} + api.filtersMu.Unlock() + + gopool.Submit(func() { + for { + select { + case vote := <-votes: + api.filtersMu.Lock() + if f, found := api.filters[voteSub.ID]; found { + f.hashes = append(f.hashes, vote.Hash()) + } + api.filtersMu.Unlock() + case <-voteSub.Err(): + api.filtersMu.Lock() + delete(api.filters, voteSub.ID) + api.filtersMu.Unlock() + return + } + } + }) + + return voteSub.ID +} + +// NewVotes creates a subscription that is triggered each time a vote enters the vote pool. +func (api *FilterAPI) NewVotes(ctx context.Context) (*rpc.Subscription, error) { + notifier, supported := rpc.NotifierFromContext(ctx) + if !supported { + return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported + } + + rpcSub := notifier.CreateSubscription() + + gopool.Submit(func() { + votes := make(chan *types.VoteEnvelope, 128) + voteSub := api.events.SubscribeNewVotes(votes) + + for { + select { + case vote := <-votes: + notifier.Notify(rpcSub.ID, vote) + case <-rpcSub.Err(): + voteSub.Unsubscribe() + return + case <-notifier.Closed(): + voteSub.Unsubscribe() + return + } + } + }) + + return rpcSub, nil +} + // NewBlockFilter creates a filter that fetches blocks that are imported into the chain. // It is part of the filter package since polling goes with eth_getFilterChanges. func (api *FilterAPI) NewBlockFilter() rpc.ID { @@ -251,6 +314,68 @@ func (api *FilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, error) { return rpcSub, nil } +// NewFinalizedHeaderFilter creates a filter that fetches finalized headers that are reached. +func (api *FilterAPI) NewFinalizedHeaderFilter() rpc.ID { + var ( + headers = make(chan *types.Header) + headerSub = api.events.SubscribeNewFinalizedHeaders(headers) + ) + + api.filtersMu.Lock() + api.filters[headerSub.ID] = &filter{typ: FinalizedHeadersSubscription, deadline: time.NewTimer(api.timeout), hashes: make([]common.Hash, 0), s: headerSub} + api.filtersMu.Unlock() + + gopool.Submit(func() { + for { + select { + case h := <-headers: + api.filtersMu.Lock() + if f, found := api.filters[headerSub.ID]; found { + f.hashes = append(f.hashes, h.Hash()) + } + api.filtersMu.Unlock() + case <-headerSub.Err(): + api.filtersMu.Lock() + delete(api.filters, headerSub.ID) + api.filtersMu.Unlock() + return + } + } + }) + + return headerSub.ID +} + +// NewFinalizedHeaders send a notification each time a new finalized header is reached. +func (api *FilterAPI) NewFinalizedHeaders(ctx context.Context) (*rpc.Subscription, error) { + notifier, supported := rpc.NotifierFromContext(ctx) + if !supported { + return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported + } + + rpcSub := notifier.CreateSubscription() + + gopool.Submit(func() { + headers := make(chan *types.Header) + headersSub := api.events.SubscribeNewFinalizedHeaders(headers) + + for { + select { + case h := <-headers: + notifier.Notify(rpcSub.ID, h) + case <-rpcSub.Err(): + headersSub.Unsubscribe() + return + case <-notifier.Closed(): + headersSub.Unsubscribe() + return + } + } + }) + + return rpcSub, nil +} + // Logs creates a subscription that fires for all new log that match the given filter criteria. func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) @@ -441,7 +566,7 @@ func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { f.deadline.Reset(api.timeout) switch f.typ { - case BlocksSubscription: + case BlocksSubscription, FinalizedHeadersSubscription, VotesSubscription: hashes := f.hashes f.hashes = nil return returnHashes(hashes), nil diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index f98a1f84c..e701a4940 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -68,9 +68,11 @@ type Backend interface { ChainConfig() *params.ChainConfig SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription + SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription + SubscribeNewVoteEvent(chan<- core.NewVoteEvent) event.Subscription BloomStatus() (uint64, uint64) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) @@ -161,6 +163,10 @@ const ( PendingTransactionsSubscription // BlocksSubscription queries hashes for blocks that are imported BlocksSubscription + // VotesSubscription queries vote hashes for votes entering the vote pool + VotesSubscription + // FinalizedHeadersSubscription queries hashes for finalized headers that are reached + FinalizedHeadersSubscription // LastIndexSubscription keeps track of the last index LastIndexSubscription ) @@ -175,6 +181,11 @@ const ( logsChanSize = 10 // chainEvChanSize is the size of channel listening to ChainEvent. chainEvChanSize = 10 + // finalizedHeaderEvChanSize is the size of channel listening to FinalizedHeaderEvent. + finalizedHeaderEvChanSize = 10 + // voteChanSize is the size of channel listening to NewVoteEvent. + // The number is referenced from the size of vote pool. + voteChanSize = 256 ) type subscription struct { @@ -185,6 +196,7 @@ type subscription struct { logs chan []*types.Log txs chan []*types.Transaction headers chan *types.Header + votes chan *types.VoteEnvelope installed chan struct{} // closed when the filter is installed err chan error // closed when the filter is uninstalled } @@ -203,6 +215,9 @@ type EventSystem struct { rmLogsSub event.Subscription // Subscription for removed log event pendingLogsSub event.Subscription // Subscription for pending log event chainSub event.Subscription // Subscription for new chain event + // for finality + finalizedHeaderSub event.Subscription // Subscription for new finalized header + voteSub event.Subscription // Subscription for new vote event // Channels install chan *subscription // install filter for event notification @@ -212,6 +227,9 @@ type EventSystem struct { pendingLogsCh chan []*types.Log // Channel to receive new log event rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event chainCh chan core.ChainEvent // Channel to receive new chain event + // for finality + finalizedHeaderCh chan core.FinalizedHeaderEvent // Channel to receive new finalized header event + voteCh chan core.NewVoteEvent // Channel to receive new vote event } // NewEventSystem creates a new manager that listens for event on the given mux, @@ -232,6 +250,9 @@ func NewEventSystem(sys *FilterSystem, lightMode bool) *EventSystem { rmLogsCh: make(chan core.RemovedLogsEvent, rmLogsChanSize), pendingLogsCh: make(chan []*types.Log, logsChanSize), chainCh: make(chan core.ChainEvent, chainEvChanSize), + // for finality + finalizedHeaderCh: make(chan core.FinalizedHeaderEvent, finalizedHeaderEvChanSize), + voteCh: make(chan core.NewVoteEvent, voteChanSize), } // Subscribe events @@ -240,11 +261,16 @@ func NewEventSystem(sys *FilterSystem, lightMode bool) *EventSystem { m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh) m.chainSub = m.backend.SubscribeChainEvent(m.chainCh) m.pendingLogsSub = m.backend.SubscribePendingLogsEvent(m.pendingLogsCh) + m.finalizedHeaderSub = m.backend.SubscribeFinalizedHeaderEvent(m.finalizedHeaderCh) + m.voteSub = m.backend.SubscribeNewVoteEvent(m.voteCh) // Make sure none of the subscriptions are empty if m.txsSub == nil || m.logsSub == nil || m.rmLogsSub == nil || m.chainSub == nil || m.pendingLogsSub == nil { log.Crit("Subscribe for event system failed") } + if m.voteSub == nil || m.finalizedHeaderSub == nil { + log.Warn("Subscribe for vote or finalized header event failed") + } go m.eventLoop() return m @@ -278,6 +304,7 @@ func (sub *Subscription) Unsubscribe() { case <-sub.f.logs: case <-sub.f.txs: case <-sub.f.headers: + case <-sub.f.votes: } } @@ -348,6 +375,7 @@ func (es *EventSystem) subscribeMinedPendingLogs(crit ethereum.FilterQuery, logs logs: logs, txs: make(chan []*types.Transaction), headers: make(chan *types.Header), + votes: make(chan *types.VoteEnvelope), installed: make(chan struct{}), err: make(chan error), } @@ -365,6 +393,7 @@ func (es *EventSystem) subscribeLogs(crit ethereum.FilterQuery, logs chan []*typ logs: logs, txs: make(chan []*types.Transaction), headers: make(chan *types.Header), + votes: make(chan *types.VoteEnvelope), installed: make(chan struct{}), err: make(chan error), } @@ -382,6 +411,7 @@ func (es *EventSystem) subscribePendingLogs(crit ethereum.FilterQuery, logs chan logs: logs, txs: make(chan []*types.Transaction), headers: make(chan *types.Header), + votes: make(chan *types.VoteEnvelope), installed: make(chan struct{}), err: make(chan error), } @@ -398,6 +428,24 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti logs: make(chan []*types.Log), txs: make(chan []*types.Transaction), headers: headers, + votes: make(chan *types.VoteEnvelope), + installed: make(chan struct{}), + err: make(chan error), + } + return es.subscribe(sub) +} + +// SubscribeNewFinalizedHeaders creates a subscription that writes the finalized header of a block that is +// reached recently. +func (es *EventSystem) SubscribeNewFinalizedHeaders(headers chan *types.Header) *Subscription { + sub := &subscription{ + id: rpc.NewID(), + typ: FinalizedHeadersSubscription, + created: time.Now(), + logs: make(chan []*types.Log), + txs: make(chan []*types.Transaction), + headers: headers, + votes: make(chan *types.VoteEnvelope), installed: make(chan struct{}), err: make(chan error), } @@ -414,6 +462,24 @@ func (es *EventSystem) SubscribePendingTxs(txs chan []*types.Transaction) *Subsc logs: make(chan []*types.Log), txs: txs, headers: make(chan *types.Header), + votes: make(chan *types.VoteEnvelope), + installed: make(chan struct{}), + err: make(chan error), + } + return es.subscribe(sub) +} + +// SubscribeNewVotes creates a subscription that writes transaction hashes for +// transactions that enter the transaction pool. +func (es *EventSystem) SubscribeNewVotes(votes chan *types.VoteEnvelope) *Subscription { + sub := &subscription{ + id: rpc.NewID(), + typ: VotesSubscription, + created: time.Now(), + logs: make(chan []*types.Log), + txs: make(chan []*types.Transaction), + headers: make(chan *types.Header), + votes: votes, installed: make(chan struct{}), err: make(chan error), } @@ -543,6 +609,18 @@ func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common. return logs } +func (es *EventSystem) handleFinalizedHeaderEvent(filters filterIndex, ev core.FinalizedHeaderEvent) { + for _, f := range filters[FinalizedHeadersSubscription] { + f.headers <- ev.Header + } +} + +func (es *EventSystem) handleVoteEvent(filters filterIndex, ev core.NewVoteEvent) { + for _, f := range filters[VotesSubscription] { + f.votes <- ev.Vote + } +} + // eventLoop (un)installs filters and processes mux events. func (es *EventSystem) eventLoop() { // Ensure all subscriptions get cleaned up @@ -552,6 +630,10 @@ func (es *EventSystem) eventLoop() { es.rmLogsSub.Unsubscribe() es.pendingLogsSub.Unsubscribe() es.chainSub.Unsubscribe() + es.finalizedHeaderSub.Unsubscribe() + if es.voteSub != nil { + es.voteSub.Unsubscribe() + } }() index := make(filterIndex) @@ -559,6 +641,10 @@ func (es *EventSystem) eventLoop() { index[i] = make(map[rpc.ID]*subscription) } + var voteSubErr <-chan error + if es.voteSub != nil { + voteSubErr = es.voteSub.Err() + } for { select { case ev := <-es.txsCh: @@ -571,6 +657,10 @@ func (es *EventSystem) eventLoop() { es.handlePendingLogs(index, ev) case ev := <-es.chainCh: es.handleChainEvent(index, ev) + case ev := <-es.finalizedHeaderCh: + es.handleFinalizedHeaderEvent(index, ev) + case ev := <-es.voteCh: + es.handleVoteEvent(index, ev) case f := <-es.install: if f.typ == MinedAndPendingLogsSubscription { @@ -601,6 +691,10 @@ func (es *EventSystem) eventLoop() { return case <-es.chainSub.Err(): return + case <-es.finalizedHeaderSub.Err(): + return + case <-voteSubErr: + return } } } diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 27cad8826..4b7fdaa55 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -149,6 +149,14 @@ func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subsc return b.chainFeed.Subscribe(ch) } +func (b *testBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription { + return nil +} + +func (b *testBackend) SubscribeNewVoteEvent(ch chan<- core.NewVoteEvent) event.Subscription { + return nil +} + func (b *testBackend) BloomStatus() (uint64, uint64) { return params.BloomBitsBlocks, b.sections } diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 4ee5a0d1b..6b5ebdaf8 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -170,7 +170,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke } chain.InsertChain(blocks) chain.SetFinalized(chain.GetBlockByNumber(25).Header()) - chain.SetSafe(chain.GetBlockByNumber(25).Header()) + // chain.SetSafe(chain.GetBlockByNumber(25).Header()) return &testBackend{chain: chain, pending: pending} } diff --git a/eth/handler.go b/eth/handler.go index a327af611..9704fc373 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -29,11 +29,13 @@ import ( "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/forkid" + "github.com/ethereum/go-ethereum/core/monitor" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/fetcher" + "github.com/ethereum/go-ethereum/eth/protocols/bsc" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/ethdb" @@ -49,6 +51,12 @@ const ( // The number is referenced from the size of tx pool. txChanSize = 4096 + // voteChanSize is the size of channel listening to NewVotesEvent. + voteChanSize = 256 + + // deltaTdThreshold is the threshold of TD difference for peers to broadcast votes. + deltaTdThreshold = 20 + // txMaxBroadcastSize is the max size of a transaction that will be broadcasted. // All transactions with a higher size will be announced and need to be fetched // by the peer. @@ -81,6 +89,17 @@ type txPool interface { SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs bool) event.Subscription } +// votePool defines the methods needed from a votes pool implementation to +// support all the operations needed by the Ethereum chain protocols. +type votePool interface { + PutVote(vote *types.VoteEnvelope) + GetVotes() []*types.VoteEnvelope + + // SubscribeNewVoteEvent should return an event subscription of + // NewVotesEvent and send events to the given channel. + SubscribeNewVoteEvent(ch chan<- core.NewVoteEvent) event.Subscription +} + // handlerConfig is the collection of initialization parameters to create a full // node network handler. type handlerConfig struct { @@ -93,6 +112,8 @@ type handlerConfig struct { BloomCache uint64 // Megabytes to alloc for snap sync bloom EventMux *event.TypeMux // Legacy event mux, deprecate for `feed` RequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges + // for finality + VotePool votePool } type handler struct { @@ -104,6 +125,7 @@ type handler struct { database ethdb.Database txpool txPool + votepool votePool chain *core.BlockChain maxPeers int @@ -117,6 +139,15 @@ type handler struct { txsCh chan core.NewTxsEvent txsSub event.Subscription minedBlockSub *event.TypeMuxSubscription + voteCh chan core.NewVoteEvent + votesSub event.Subscription + + voteMonitorSub event.Subscription + maliciousVoteMonitor *monitor.MaliciousVoteMonitor + + // Used for calcurate average difficulty per block + firstTDInBroadcastVote *big.Int + firstHeightInBroadcastVote uint64 requiredBlocks map[uint64]common.Hash @@ -142,6 +173,7 @@ func newHandler(config *handlerConfig) (*handler, error) { eventMux: config.EventMux, database: config.Database, txpool: config.TxPool, + votepool: config.VotePool, chain: config.Chain, peers: newPeerSet(), merger: config.Merger, @@ -220,6 +252,13 @@ func newHandler(config *handlerConfig) (*handler, error) { heighter := func() uint64 { return h.chain.CurrentBlock().Number.Uint64() } + finalizeHeighter := func() uint64 { + fblock := h.chain.CurrentFinalBlock() + if fblock == nil { + return 0 + } + return fblock.Number.Uint64() + } inserter := func(blocks types.Blocks) (int, error) { // All the block fetcher activities should be disabled // after the transition. Print the warning log. @@ -269,7 +308,8 @@ func newHandler(config *handlerConfig) (*handler, error) { } return h.chain.InsertChain(blocks) } - h.blockFetcher = fetcher.NewBlockFetcher(false, nil, h.chain.GetBlockByHash, validator, h.BroadcastBlock, heighter, nil, inserter, h.removePeer) + h.blockFetcher = fetcher.NewBlockFetcher(false, nil, h.chain.GetBlockByHash, validator, h.BroadcastBlock, + heighter, finalizeHeighter, nil, inserter, h.removePeer) fetchTx := func(peer string, hashes []common.Hash) error { p := h.peers.peer(peer) @@ -337,6 +377,11 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Error("Snapshot extension barrier failed", "err", err) return err } + bsc, err := h.peers.waitBscExtension(peer) + if err != nil { + peer.Log().Error("Bsc extension barrier failed", "err", err) + return err + } // Execute the Ethereum handshake var ( @@ -371,7 +416,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Debug("Ethereum peer connected", "name", peer.Name()) // Register the peer locally - if err := h.peers.registerPeer(peer, snap); err != nil { + if err := h.peers.registerPeer(peer, snap, bsc); err != nil { peer.Log().Error("Ethereum peer registration failed", "err", err) return err } @@ -394,9 +439,12 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { } h.chainSync.handlePeerEvent() - // Propagate existing transactions. new transactions appearing + // Propagate existing transactions and votes. new transactions and votes appearing // after this will be sent via broadcasts. h.syncTransactions(peer) + if h.votepool != nil && p.bscExt != nil { + h.syncVotes(p.bscExt) + } // Create a notification channel for pending requests if the peer goes down dead := make(chan struct{}) @@ -472,6 +520,30 @@ func (h *handler) runSnapExtension(peer *snap.Peer, handler snap.Handler) error return handler(peer) } +// runBscExtension registers a `bsc` peer into the joint eth/bsc peerset and +// starts handling inbound messages. As `bsc` is only a satellite protocol to +// `eth`, all subsystem registrations and lifecycle management will be done by +// the main `eth` handler to prevent strange races. +func (h *handler) runBscExtension(peer *bsc.Peer, handler bsc.Handler) error { + if !h.incHandlers() { + return p2p.DiscQuitting + } + defer h.decHandlers() + + if err := h.peers.registerBscExtension(peer); err != nil { + if metrics.Enabled { + if peer.Inbound() { + bsc.IngressRegistrationErrorMeter.Mark(1) + } else { + bsc.EgressRegistrationErrorMeter.Mark(1) + } + } + peer.Log().Error("Bsc extension registration failed", "err", err) + return err + } + return handler(peer) +} + // removePeer requests disconnection of a peer. func (h *handler) removePeer(id string) { peer := h.peers.peer(id) @@ -520,6 +592,19 @@ func (h *handler) Start(maxPeers int) { h.txsSub = h.txpool.SubscribeTransactions(h.txsCh, false) go h.txBroadcastLoop() + // broadcast votes + if h.votepool != nil { + h.wg.Add(1) + h.voteCh = make(chan core.NewVoteEvent, voteChanSize) + h.votesSub = h.votepool.SubscribeNewVoteEvent(h.voteCh) + go h.voteBroadcastLoop() + + if h.maliciousVoteMonitor != nil { + h.wg.Add(1) + go h.startMaliciousVoteMonitor() + } + } + // broadcast mined blocks h.wg.Add(1) h.minedBlockSub = h.eventMux.Subscribe(core.NewMinedBlockEvent{}) @@ -537,7 +622,12 @@ func (h *handler) Start(maxPeers int) { func (h *handler) Stop() { h.txsSub.Unsubscribe() // quits txBroadcastLoop h.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop - + if h.votepool != nil { + h.votesSub.Unsubscribe() // quits voteBroadcastLoop + if h.maliciousVoteMonitor != nil { + h.voteMonitorSub.Unsubscribe() + } + } // Quit chainSync and txsync64. // After this is done, no new peers will be accepted. close(h.quitSync) @@ -649,6 +739,49 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { "bcastpeers", directPeers, "bcastcount", directCount, "annpeers", annPeers, "anncount", annCount) } +// BroadcastVote will propagate a batch of votes to all peers +// which are not known to already have the given vote. +func (h *handler) BroadcastVote(vote *types.VoteEnvelope) { + var ( + directCount int // Count of announcements made + directPeers int + + voteMap = make(map[*ethPeer]*types.VoteEnvelope) // Set peer->hash to transfer directly + ) + + // Broadcast vote to a batch of peers not knowing about it + peers := h.peers.peersWithoutVote(vote.Hash()) + headBlock := h.chain.CurrentBlock() + currentTD := h.chain.GetTd(headBlock.Hash(), headBlock.Number.Uint64()) + var averageDifficulty *big.Int + if h.firstTDInBroadcastVote == nil || h.firstHeightInBroadcastVote == 0 { + h.firstTDInBroadcastVote = currentTD + h.firstHeightInBroadcastVote = headBlock.Number.Uint64() + } else if headBlock.Number.Uint64() > h.firstHeightInBroadcastVote { + averageDifficulty = new(big.Int).Div(new(big.Int).Sub(currentTD, h.firstTDInBroadcastVote), big.NewInt(int64(headBlock.Number.Uint64()-h.firstHeightInBroadcastVote))) + } + for _, peer := range peers { + _, peerTD := peer.Head() + deltaTD := new(big.Int).Abs(new(big.Int).Sub(currentTD, peerTD)) + // broadcast if + // - bscExt is set + // - the first time (averageDifficulty is not set) + // - The total difficulty of peer is within the [+|-] range of average difficulty per block * deltaTdThreshold (blocks) + broadCasts := peer.bscExt != nil && (averageDifficulty == nil || deltaTD.Cmp(new(big.Int).Mul(big.NewInt(deltaTdThreshold), averageDifficulty)) < 1) + if broadCasts { + voteMap[peer] = vote + } + } + + for peer, _vote := range voteMap { + directPeers++ + directCount += 1 + votes := []*types.VoteEnvelope{_vote} + peer.bscExt.AsyncSendVotes(votes) + } + log.Debug("Vote broadcast", "vote packs", directPeers, "broadcast vote", directCount, "source", vote.Data.SourceNumber, "target", vote.Data.TargetNumber) +} + // minedBroadcastLoop sends mined blocks to connected peers. func (h *handler) minedBroadcastLoop() { defer h.wg.Done() @@ -674,6 +807,36 @@ func (h *handler) txBroadcastLoop() { } } +// voteBroadcastLoop announces new vote to connected peers. +func (h *handler) voteBroadcastLoop() { + defer h.wg.Done() + for { + select { + case event := <-h.voteCh: + // The timeliness of votes is very important, + // so one vote will be sent instantly without waiting for other votes for batch sending by design. + h.BroadcastVote(event.Vote) + case <-h.votesSub.Err(): + return + } + } +} + +func (h *handler) startMaliciousVoteMonitor() { + defer h.wg.Done() + voteCh := make(chan core.NewVoteEvent, voteChanSize) + h.voteMonitorSub = h.votepool.SubscribeNewVoteEvent(voteCh) + for { + select { + case event := <-voteCh: + pendingBlockNumber := h.chain.CurrentHeader().Number.Uint64() + 1 + h.maliciousVoteMonitor.ConflictDetect(event.Vote, pendingBlockNumber) + case <-h.voteMonitorSub.Err(): + return + } + } +} + // enableSyncedFeatures enables the post-sync functionalities when the initial // sync is finished. func (h *handler) enableSyncedFeatures() { diff --git a/eth/handler_bsc.go b/eth/handler_bsc.go new file mode 100644 index 000000000..4fb1824f2 --- /dev/null +++ b/eth/handler_bsc.go @@ -0,0 +1,74 @@ +package eth + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/protocols/bsc" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +// bscHandler implements the bsc.Backend interface to handle the various network +// packets that are sent as broadcasts. +type bscHandler handler + +func (h *bscHandler) Chain() *core.BlockChain { return h.chain } + +// RunPeer is invoked when a peer joins on the `bsc` protocol. +func (h *bscHandler) RunPeer(peer *bsc.Peer, hand bsc.Handler) error { + if err := peer.Handshake(); err != nil { + // ensure that waitBscExtension receives the exit signal normally + // otherwise, can't graceful shutdown + ps := h.peers + id := peer.ID() + + // Ensure nobody can double connect + ps.lock.Lock() + if wait, ok := ps.bscWait[id]; ok { + delete(ps.bscWait, id) + peer.Log().Error("Bsc extension Handshake failed", "err", err) + wait <- nil + } + ps.lock.Unlock() + return err + } + return (*handler)(h).runBscExtension(peer, hand) +} + +// PeerInfo retrieves all known `bsc` information about a peer. +func (h *bscHandler) PeerInfo(id enode.ID) interface{} { + if p := h.peers.peer(id.String()); p != nil && p.bscExt != nil { + return p.bscExt.info() + } + return nil +} + +// Handle is invoked from a peer's message handler when it receives a new remote +// message that the handler couldn't consume and serve itself. +func (h *bscHandler) Handle(peer *bsc.Peer, packet bsc.Packet) error { + // DeliverSnapPacket is invoked from a peer's message handler when it transmits a + // data packet for the local node to consume. + switch packet := packet.(type) { + case *bsc.VotesPacket: + return h.handleVotesBroadcast(peer, packet.Votes) + + default: + return fmt.Errorf("unexpected bsc packet type: %T", packet) + } +} + +// handleVotesBroadcast is invoked from a peer's message handler when it transmits a +// votes broadcast for the local node to process. +func (h *bscHandler) handleVotesBroadcast(peer *bsc.Peer, votes []*types.VoteEnvelope) error { + if peer.IsOverLimitAfterReceiving() { + return nil + } + // Here we only put the first vote, to avoid ddos attack by sending a large batch of votes. + // This won't abandon any valid vote, because one vote is sent every time referring to func voteBroadcastLoop + if len(votes) > 0 { + h.votepool.PutVote(votes[0]) + } + + return nil +} diff --git a/eth/handler_eth.go b/eth/handler_eth.go index 2a839f615..69c9d4788 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -23,6 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/protocols/eth" @@ -138,5 +139,13 @@ func (h *ethHandler) handleBlockBroadcast(peer *eth.Peer, block *types.Block, td peer.SetHead(trueHead, trueTD) h.chainSync.handlePeerEvent() } + // Update the peer's justfied head if better than the previous + if pos, ok := h.chain.Engine().(consensus.PoS); ok { + if attestation := pos.DecodeVoteAttestation(block.Header()); attestation != nil { + if cur := peer.JustifiedBlock(); cur == nil || attestation.Data.SourceNumber > *cur { + peer.SetJustifiedBlock(attestation.Data.SourceNumber) + } + } + } return nil } diff --git a/eth/peer.go b/eth/peer.go index 761877771..da3e4bf6e 100644 --- a/eth/peer.go +++ b/eth/peer.go @@ -17,6 +17,7 @@ package eth import ( + "github.com/ethereum/go-ethereum/eth/protocols/bsc" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" ) @@ -31,6 +32,7 @@ type ethPeerInfo struct { type ethPeer struct { *eth.Peer snapExt *snapPeer // Satellite `snap` connection + bscExt *bscPeer // Satellite `bsc` connection } // info gathers and returns some `eth` protocol metadata known about a peer. @@ -46,14 +48,32 @@ type snapPeerInfo struct { Version uint `json:"version"` // Snapshot protocol version negotiated } +// bscPeerInfo represents a short summary of the `bsc` sub-protocol metadata known +// about a connected peer. +type bscPeerInfo struct { + Version uint `json:"version"` // bsc protocol version negotiated +} + // snapPeer is a wrapper around snap.Peer to maintain a few extra metadata. type snapPeer struct { *snap.Peer } +// bscPeer is a wrapper around bsc.Peer to maintain a few extra metadata. +type bscPeer struct { + *bsc.Peer +} + // info gathers and returns some `snap` protocol metadata known about a peer. func (p *snapPeer) info() *snapPeerInfo { return &snapPeerInfo{ Version: p.Version(), } } + +// info gathers and returns some `bsc` protocol metadata known about a peer. +func (p *bscPeer) info() *bscPeerInfo { + return &bscPeerInfo{ + Version: p.Version(), + } +} diff --git a/eth/peerset.go b/eth/peerset.go index b27d3964a..51898940b 100644 --- a/eth/peerset.go +++ b/eth/peerset.go @@ -21,8 +21,10 @@ import ( "fmt" "math/big" "sync" + "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/eth/protocols/bsc" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/p2p" @@ -37,6 +39,9 @@ var ( // to the peer set, but one with the same id already exists. errPeerAlreadyRegistered = errors.New("peer already registered") + // errPeerWaitTimeout is returned if a peer waits extension for too long + errPeerWaitTimeout = errors.New("peer wait timeout") + // errPeerNotRegistered is returned if a peer is attempted to be removed from // a peer set, but no peer with the given id exists. errPeerNotRegistered = errors.New("peer not registered") @@ -44,6 +49,17 @@ var ( // errSnapWithoutEth is returned if a peer attempts to connect only on the // snap protocol without advertising the eth main protocol. errSnapWithoutEth = errors.New("peer connected on snap without compatible eth support") + + // errBscWithoutEth is returned if a peer attempts to connect only on the + // bsc protocol without advertising the eth main protocol. + errBscWithoutEth = errors.New("peer connected on bsc without compatible eth support") +) + +const ( + // extensionWaitTimeout is the maximum allowed time for the extension wait to + // complete before dropping the connection as malicious. + extensionWaitTimeout = 10 * time.Second + tryWaitTimeout = 100 * time.Millisecond ) // peerSet represents the collection of active peers currently participating in @@ -55,8 +71,12 @@ type peerSet struct { snapWait map[string]chan *snap.Peer // Peers connected on `eth` waiting for their snap extension snapPend map[string]*snap.Peer // Peers connected on the `snap` protocol, but not yet on `eth` + bscWait map[string]chan *bsc.Peer // Peers connected on `eth` waiting for their bsc extension + bscPend map[string]*bsc.Peer // Peers connected on the `bsc` protocol, but not yet on `eth` + lock sync.RWMutex closed bool + quitCh chan struct{} // Quit channel to signal termination } // newPeerSet creates a new peer set to track the active participants. @@ -65,6 +85,9 @@ func newPeerSet() *peerSet { peers: make(map[string]*ethPeer), snapWait: make(map[string]chan *snap.Peer), snapPend: make(map[string]*snap.Peer), + bscWait: make(map[string]chan *bsc.Peer), + bscPend: make(map[string]*bsc.Peer), + quitCh: make(chan struct{}), } } @@ -98,6 +121,36 @@ func (ps *peerSet) registerSnapExtension(peer *snap.Peer) error { return nil } +// registerBscExtension unblocks an already connected `eth` peer waiting for its +// `bsc` extension, or if no such peer exists, tracks the extension for the time +// being until the `eth` main protocol starts looking for it. +func (ps *peerSet) registerBscExtension(peer *bsc.Peer) error { + // Reject the peer if it advertises `bsc` without `eth` as `bsc` is only a + // satellite protocol meaningful with the chain selection of `eth` + if !peer.RunningCap(eth.ProtocolName, eth.ProtocolVersions) { + return errBscWithoutEth + } + // Ensure nobody can double connect + ps.lock.Lock() + defer ps.lock.Unlock() + + id := peer.ID() + if _, ok := ps.peers[id]; ok { + return errPeerAlreadyRegistered // avoid connections with the same id as existing ones + } + if _, ok := ps.bscPend[id]; ok { + return errPeerAlreadyRegistered // avoid connections with the same id as pending ones + } + // Inject the peer into an `eth` counterpart is available, otherwise save for later + if wait, ok := ps.bscWait[id]; ok { + delete(ps.bscWait, id) + wait <- peer + return nil + } + ps.bscPend[id] = peer + return nil +} + // waitExtensions blocks until all satellite protocols are connected and tracked // by the peerset. func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) { @@ -129,12 +182,92 @@ func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) { ps.snapWait[id] = wait ps.lock.Unlock() - return <-wait, nil + select { + case peer := <-wait: + return peer, nil + + case <-time.After(extensionWaitTimeout): + ps.lock.Lock() + delete(ps.snapWait, id) + ps.lock.Unlock() + return nil, errPeerWaitTimeout + + case <-ps.quitCh: + ps.lock.Lock() + delete(ps.snapWait, id) + ps.lock.Unlock() + return nil, errPeerSetClosed + } +} + +// waitBscExtension blocks until all satellite protocols are connected and tracked +// by the peerset. +func (ps *peerSet) waitBscExtension(peer *eth.Peer) (*bsc.Peer, error) { + // If the peer does not support a compatible `bsc`, don't wait + if !peer.RunningCap(bsc.ProtocolName, bsc.ProtocolVersions) { + return nil, nil + } + // Ensure nobody can double connect + ps.lock.Lock() + + id := peer.ID() + if _, ok := ps.peers[id]; ok { + ps.lock.Unlock() + return nil, errPeerAlreadyRegistered // avoid connections with the same id as existing ones + } + if _, ok := ps.bscWait[id]; ok { + ps.lock.Unlock() + return nil, errPeerAlreadyRegistered // avoid connections with the same id as pending ones + } + // If `bsc` already connected, retrieve the peer from the pending set + if bsc, ok := ps.bscPend[id]; ok { + delete(ps.bscPend, id) + + ps.lock.Unlock() + return bsc, nil + } + // Otherwise wait for `bsc` to connect concurrently + wait := make(chan *bsc.Peer) + ps.bscWait[id] = wait + ps.lock.Unlock() + + select { + case peer := <-wait: + return peer, nil + + case <-time.After(extensionWaitTimeout): + // could be deadlock, so we use TryLock to avoid it. + if ps.lock.TryLock() { + delete(ps.bscWait, id) + ps.lock.Unlock() + return nil, errPeerWaitTimeout + } + // if TryLock failed, we wait for a while and try again. + for { + select { + case <-wait: + // discard the peer, even though the peer arrived. + return nil, errPeerWaitTimeout + case <-time.After(tryWaitTimeout): + if ps.lock.TryLock() { + delete(ps.bscWait, id) + ps.lock.Unlock() + return nil, errPeerWaitTimeout + } + } + } + + case <-ps.quitCh: + ps.lock.Lock() + delete(ps.bscWait, id) + ps.lock.Unlock() + return nil, errPeerSetClosed + } } // registerPeer injects a new `eth` peer into the working set, or returns an error // if the peer is already known. -func (ps *peerSet) registerPeer(peer *eth.Peer, ext *snap.Peer) error { +func (ps *peerSet) registerPeer(peer *eth.Peer, ext *snap.Peer, bscExt *bsc.Peer) error { // Start tracking the new peer ps.lock.Lock() defer ps.lock.Unlock() @@ -153,6 +286,9 @@ func (ps *peerSet) registerPeer(peer *eth.Peer, ext *snap.Peer) error { eth.snapExt = &snapPeer{ext} ps.snapPeers++ } + if bscExt != nil { + eth.bscExt = &bscPeer{bscExt} + } ps.peers[id] = eth return nil } @@ -212,6 +348,21 @@ func (ps *peerSet) peersWithoutTransaction(hash common.Hash) []*ethPeer { return list } +// peersWithoutVote retrieves a list of peers that do not have a given +// vote in their set of known hashes. +func (ps *peerSet) peersWithoutVote(hash common.Hash) []*ethPeer { + ps.lock.RLock() + defer ps.lock.RUnlock() + + list := make([]*ethPeer, 0, len(ps.peers)) + for _, p := range ps.peers { + if p.bscExt != nil && !p.bscExt.KnownVote(hash) { + list = append(list, p) + } + } + return list +} + // len returns if the current number of `eth` peers in the set. Since the `snap` // peers are tied to the existence of an `eth` connection, that will always be a // subset of `eth`. @@ -248,6 +399,26 @@ func (ps *peerSet) peerWithHighestTD() *eth.Peer { return bestPeer } +// peerWithHighestJustifiedBlockAndTD() returns the peer with the +// highest justified block height. If multiple peers have the same +// height, the one with the highest total difficulty is returned. +func (ps *peerSet) peerWithHighestJustifiedBlockAndTD() (bestPeer *eth.Peer, bestJustified uint64, bestTd *big.Int) { + ps.lock.RLock() + defer ps.lock.RUnlock() + + for _, p := range ps.peers { + justified := p.JustifiedBlock() + if justified == nil { + continue + } + _, td := p.Head() + if *justified > bestJustified || (*justified == bestJustified && td.Cmp(bestTd) > 0) { + bestPeer, bestJustified, bestTd = p.Peer, *justified, td + } + } + return +} + // close disconnects all peers. func (ps *peerSet) close() { ps.lock.Lock() @@ -256,5 +427,8 @@ func (ps *peerSet) close() { for _, p := range ps.peers { p.Disconnect(p2p.DiscQuitting) } + if !ps.closed { + close(ps.quitCh) + } ps.closed = true } diff --git a/eth/protocols/bsc/discovery.go b/eth/protocols/bsc/discovery.go new file mode 100644 index 000000000..6a4fac346 --- /dev/null +++ b/eth/protocols/bsc/discovery.go @@ -0,0 +1,16 @@ +package bsc + +import ( + "github.com/ethereum/go-ethereum/rlp" +) + +// enrEntry is the ENR entry which advertises `bsc` protocol on the discovery. +type enrEntry struct { + // Ignore additional fields (for forward compatibility). + Rest []rlp.RawValue `rlp:"tail"` +} + +// ENRKey implements enr.Entry. +func (e enrEntry) ENRKey() string { + return "bsc" +} diff --git a/eth/protocols/bsc/handler.go b/eth/protocols/bsc/handler.go new file mode 100644 index 000000000..e993f255f --- /dev/null +++ b/eth/protocols/bsc/handler.go @@ -0,0 +1,145 @@ +package bsc + +import ( + "fmt" + "time" + + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" +) + +// Handler is a callback to invoke from an outside runner after the boilerplate +// exchanges have passed. +type Handler func(peer *Peer) error + +type Backend interface { + // Chain retrieves the blockchain object to serve data. + Chain() *core.BlockChain + + // RunPeer is invoked when a peer joins on the `bsc` protocol. The handler + // should do any peer maintenance work, handshakes and validations. If all + // is passed, control should be given back to the `handler` to process the + // inbound messages going forward. + RunPeer(peer *Peer, handler Handler) error + + // PeerInfo retrieves all known `bsc` information about a peer. + PeerInfo(id enode.ID) interface{} + + // Handle is a callback to be invoked when a data packet is received from + // the remote peer. Only packets not consumed by the protocol handler will + // be forwarded to the backend. + Handle(peer *Peer, packet Packet) error +} + +// MakeProtocols constructs the P2P protocol definitions for `bsc`. +func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol { + // Filter the discovery iterator for nodes advertising vote support. + dnsdisc = enode.Filter(dnsdisc, func(n *enode.Node) bool { + var vote enrEntry + return n.Load(&vote) == nil + }) + + protocols := make([]p2p.Protocol, len(ProtocolVersions)) + for i, version := range ProtocolVersions { + version := version // Closure + + protocols[i] = p2p.Protocol{ + Name: ProtocolName, + Version: version, + Length: protocolLengths[version], + Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { + peer := NewPeer(version, p, rw) + defer peer.Close() + + return backend.RunPeer(peer, func(peer *Peer) error { + return Handle(backend, peer) + }) + }, + NodeInfo: func() interface{} { + return nodeInfo(backend.Chain()) + }, + PeerInfo: func(id enode.ID) interface{} { + return backend.PeerInfo(id) + }, + Attributes: []enr.Entry{&enrEntry{}}, + DialCandidates: dnsdisc, + } + } + return protocols +} + +// Handle is the callback invoked to manage the life cycle of a `bsc` peer. +// When this function terminates, the peer is disconnected. +func Handle(backend Backend, peer *Peer) error { + for { + if err := handleMessage(backend, peer); err != nil { + peer.Log().Debug("Message handling failed in `bsc`", "err", err) + return err + } + } +} + +type msgHandler func(backend Backend, msg Decoder, peer *Peer) error +type Decoder interface { + Decode(val interface{}) error +} + +var bsc1 = map[uint64]msgHandler{ + VotesMsg: handleVotes, +} + +// handleMessage is invoked whenever an inbound message is received from a +// remote peer on the `bsc` protocol. The remote connection is torn down upon +// returning any error. +func handleMessage(backend Backend, peer *Peer) error { + // Read the next message from the remote peer, and ensure it's fully consumed + msg, err := peer.rw.ReadMsg() + if err != nil { + return err + } + if msg.Size > maxMessageSize { + return fmt.Errorf("%w: %v > %v", errMsgTooLarge, msg.Size, maxMessageSize) + } + defer msg.Discard() + + var handlers = bsc1 + + // Track the amount of time it takes to serve the request and run the handler + if metrics.Enabled { + h := fmt.Sprintf("%s/%s/%d/%#02x", p2p.HandleHistName, ProtocolName, peer.Version(), msg.Code) + defer func(start time.Time) { + sampler := func() metrics.Sample { + return metrics.ResettingSample( + metrics.NewExpDecaySample(1028, 0.015), + ) + } + metrics.GetOrRegisterHistogramLazy(h, nil, sampler).Update(time.Since(start).Microseconds()) + }(time.Now()) + } + if handler := handlers[msg.Code]; handler != nil { + return handler(backend, msg, peer) + } + return fmt.Errorf("%w: %v", errInvalidMsgCode, msg.Code) +} + +func handleVotes(backend Backend, msg Decoder, peer *Peer) error { + ann := new(VotesPacket) + if err := msg.Decode(ann); err != nil { + return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) + } + // Schedule all the unknown hashes for retrieval + peer.markVotes(ann.Votes) + return backend.Handle(peer, ann) +} + +// NodeInfo represents a short summary of the `bsc` sub-protocol metadata +// known about the host peer. +type NodeInfo struct{} + +// nodeInfo retrieves some `bsc` protocol metadata about the running host node. +func nodeInfo(_ *core.BlockChain) *NodeInfo { + return &NodeInfo{} +} diff --git a/eth/protocols/bsc/handshake.go b/eth/protocols/bsc/handshake.go new file mode 100644 index 000000000..c8e74f3d1 --- /dev/null +++ b/eth/protocols/bsc/handshake.go @@ -0,0 +1,68 @@ +package bsc + +import ( + "fmt" + "time" + + "github.com/ethereum/go-ethereum/common/gopool" + "github.com/ethereum/go-ethereum/p2p" +) + +const ( + // handshakeTimeout is the maximum allowed time for the `bsc` handshake to + // complete before dropping the connection as malicious. + handshakeTimeout = 5 * time.Second +) + +// Handshake executes the bsc protocol handshake, +func (p *Peer) Handshake() error { + // Send out own handshake in a new thread + errc := make(chan error, 2) + + var cap BscCapPacket // safe to read after two values have been received from errc + + gopool.Submit(func() { + errc <- p2p.Send(p.rw, BscCapMsg, &BscCapPacket{ + ProtocolVersion: p.version, + Extra: defaultExtra, + }) + }) + gopool.Submit(func() { + errc <- p.readCap(&cap) + }) + timeout := time.NewTimer(handshakeTimeout) + defer timeout.Stop() + for i := 0; i < 2; i++ { + select { + case err := <-errc: + if err != nil { + return err + } + case <-timeout.C: + return p2p.DiscReadTimeout + } + } + return nil +} + +// readCap reads the remote handshake message. +func (p *Peer) readCap(cap *BscCapPacket) error { + msg, err := p.rw.ReadMsg() + if err != nil { + return err + } + if msg.Code != BscCapMsg { + return fmt.Errorf("%w: first msg has code %x (!= %x)", errNoBscCapMsg, msg.Code, BscCapMsg) + } + if msg.Size > maxMessageSize { + return fmt.Errorf("%w: %v > %v", errMsgTooLarge, msg.Size, maxMessageSize) + } + // Decode the handshake and make sure everything matches + if err := msg.Decode(cap); err != nil { + return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) + } + if cap.ProtocolVersion != p.version { + return fmt.Errorf("%w: %d (!= %d)", errProtocolVersionMismatch, cap.ProtocolVersion, p.version) + } + return nil +} diff --git a/eth/protocols/bsc/metrics.go b/eth/protocols/bsc/metrics.go new file mode 100644 index 000000000..ec78d4296 --- /dev/null +++ b/eth/protocols/bsc/metrics.go @@ -0,0 +1,29 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package bsc + +import ( + metrics "github.com/ethereum/go-ethereum/metrics" +) + +var ( + ingressRegistrationErrorName = "eth/protocols/bsc/ingress/registration/error" + egressRegistrationErrorName = "eth/protocols/bsc/egress/registration/error" + + IngressRegistrationErrorMeter = metrics.NewRegisteredMeter(ingressRegistrationErrorName, nil) + EgressRegistrationErrorMeter = metrics.NewRegisteredMeter(egressRegistrationErrorName, nil) +) diff --git a/eth/protocols/bsc/peer.go b/eth/protocols/bsc/peer.go new file mode 100644 index 000000000..180b42521 --- /dev/null +++ b/eth/protocols/bsc/peer.go @@ -0,0 +1,189 @@ +package bsc + +import ( + "time" + + mapset "github.com/deckarep/golang-set/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p" +) + +const ( + // maxKnownVotes is the maximum vote hashes to keep in the known list + // before starting to randomly evict them. + maxKnownVotes = 5376 + + // voteBufferSize is the maximum number of batch votes can be hold before sending + voteBufferSize = 21 * 2 + + // used to avoid of DDOS attack + // It's the max number of received votes per second from one peer + receiveRateLimitPerSecond = 10 + + // the time span of one period + secondsPerPeriod = float64(30) +) + +// max is a helper function which returns the larger of the two given integers. +func max(a, b int) int { + if a > b { + return a + } + return b +} + +// Peer is a collection of relevant information we have about a `bsc` peer. +type Peer struct { + id string // Unique ID for the peer, cached + knownVotes *knownCache // Set of vote hashes known to be known by this peer + voteBroadcast chan []*types.VoteEnvelope // Channel used to queue votes propagation requests + periodBegin time.Time // Begin time of the latest period for votes counting + periodCounter uint // Votes number in the latest period + + *p2p.Peer // The embedded P2P package peer + rw p2p.MsgReadWriter // Input/output streams for bsc + version uint // Protocol version negotiated + logger log.Logger // Contextual logger with the peer id injected + term chan struct{} // Termination channel to stop the broadcasters +} + +// NewPeer create a wrapper for a network connection and negotiated protocol +// version. +func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) *Peer { + id := p.ID().String() + peer := &Peer{ + id: id, + knownVotes: newKnownCache(maxKnownVotes), + voteBroadcast: make(chan []*types.VoteEnvelope, voteBufferSize), + periodBegin: time.Now(), + periodCounter: 0, + Peer: p, + rw: rw, + version: version, + logger: log.New("peer", id[:8]), + term: make(chan struct{}), + } + go peer.broadcastVotes() + return peer +} + +// ID retrieves the peer's unique identifier. +func (p *Peer) ID() string { + return p.id +} + +// Version retrieves the peer's negotiated `bsc` protocol version. +func (p *Peer) Version() uint { + return p.version +} + +// Log overrides the P2P logget with the higher level one containing only the id. +func (p *Peer) Log() log.Logger { + return p.logger +} + +// Close signals the broadcast goroutine to terminate. Only ever call this if +// you created the peer yourself via NewPeer. Otherwise let whoever created it +// clean it up! +func (p *Peer) Close() { + close(p.term) +} + +// KnownVote returns whether peer is known to already have a vote. +func (p *Peer) KnownVote(hash common.Hash) bool { + return p.knownVotes.contains(hash) +} + +// markVotes marks votes as known for the peer, ensuring that they +// will never be repropagated to this particular peer. +func (p *Peer) markVotes(votes []*types.VoteEnvelope) { + for _, vote := range votes { + if !p.knownVotes.contains(vote.Hash()) { + // If we reached the memory allowance, drop a previously known vote hash + p.knownVotes.add(vote.Hash()) + } + } +} + +// sendVotes propagates a batch of votes to the remote peer. +func (p *Peer) sendVotes(votes []*types.VoteEnvelope) error { + // Mark all the votes as known, but ensure we don't overflow our limits + p.markVotes(votes) + return p2p.Send(p.rw, VotesMsg, &VotesPacket{votes}) +} + +// AsyncSendVotes queues a batch of vote hashes for propagation to a remote peer. If +// the peer's broadcast queue is full, the event is silently dropped. +func (p *Peer) AsyncSendVotes(votes []*types.VoteEnvelope) { + select { + case p.voteBroadcast <- votes: + case <-p.term: + p.Log().Debug("Dropping vote propagation for closed peer", "count", len(votes)) + default: + p.Log().Debug("Dropping vote propagation for abnormal peer", "count", len(votes)) + } +} + +// Step into the next period when secondsPerPeriod seconds passed, +// Otherwise, check whether the number of received votes extra (secondsPerPeriod * receiveRateLimitPerSecond) +func (p *Peer) IsOverLimitAfterReceiving() bool { + if timeInterval := time.Since(p.periodBegin).Seconds(); timeInterval >= secondsPerPeriod { + if p.periodCounter > uint(secondsPerPeriod*receiveRateLimitPerSecond) { + p.Log().Debug("sending votes too much", "secondsPerPeriod", secondsPerPeriod, "count ", p.periodCounter) + } + p.periodBegin = time.Now() + p.periodCounter = 0 + return false + } + p.periodCounter += 1 + return p.periodCounter > uint(secondsPerPeriod*receiveRateLimitPerSecond) +} + +// broadcastVotes is a write loop that schedules votes broadcasts +// to the remote peer. The goal is to have an async writer that does not lock up +// node internals and at the same time rate limits queued data. +func (p *Peer) broadcastVotes() { + for { + select { + case votes := <-p.voteBroadcast: + if err := p.sendVotes(votes); err != nil { + return + } + p.Log().Trace("Sent votes", "count", len(votes)) + + case <-p.term: + return + } + } +} + +// knownCache is a cache for known hashes. +type knownCache struct { + hashes mapset.Set[common.Hash] + max int +} + +// newKnownCache creates a new knownCache with a max capacity. +func newKnownCache(max int) *knownCache { + return &knownCache{ + max: max, + hashes: mapset.NewSet[common.Hash](), + } +} + +// add adds a list of elements to the set. +func (k *knownCache) add(hashes ...common.Hash) { + for k.hashes.Cardinality() > max(0, k.max-len(hashes)) { + k.hashes.Pop() + } + for _, hash := range hashes { + k.hashes.Add(hash) + } +} + +// contains returns whether the given item is in the set. +func (k *knownCache) contains(hash common.Hash) bool { + return k.hashes.Contains(hash) +} diff --git a/eth/protocols/bsc/protocol.go b/eth/protocols/bsc/protocol.go new file mode 100644 index 000000000..a063531f0 --- /dev/null +++ b/eth/protocols/bsc/protocol.go @@ -0,0 +1,66 @@ +package bsc + +import ( + "errors" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" +) + +// Constants to match up protocol versions and messages +const ( + Bsc1 = 1 +) + +// ProtocolName is the official short name of the `bsc` protocol used during +// devp2p capability negotiation. +const ProtocolName = "bsc" + +// ProtocolVersions are the supported versions of the `bsc` protocol (first +// is primary). +var ProtocolVersions = []uint{Bsc1} + +// protocolLengths are the number of implemented message corresponding to +// different protocol versions. +var protocolLengths = map[uint]uint64{Bsc1: 2} + +// maxMessageSize is the maximum cap on the size of a protocol message. +const maxMessageSize = 10 * 1024 * 1024 + +const ( + BscCapMsg = 0x00 // bsc capability msg used upon handshake + VotesMsg = 0x01 +) + +var defaultExtra = []byte{0x00} + +var ( + errNoBscCapMsg = errors.New("no bsc capability message") + errMsgTooLarge = errors.New("message too long") + errDecode = errors.New("invalid message") + errInvalidMsgCode = errors.New("invalid message code") + errProtocolVersionMismatch = errors.New("protocol version mismatch") +) + +// Packet represents a p2p message in the `bsc` protocol. +type Packet interface { + Name() string // Name returns a string corresponding to the message type. + Kind() byte // Kind returns the message type. +} + +// BscCapPacket is the network packet for bsc capability message. +type BscCapPacket struct { + ProtocolVersion uint + Extra rlp.RawValue // for extension +} + +// VotesPacket is the network packet for votes record. +type VotesPacket struct { + Votes []*types.VoteEnvelope +} + +func (*BscCapPacket) Name() string { return "BscCap" } +func (*BscCapPacket) Kind() byte { return BscCapMsg } + +func (*VotesPacket) Name() string { return "Votes" } +func (*VotesPacket) Kind() byte { return VotesMsg } diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index 0293af420..979005bd2 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -75,6 +75,8 @@ type Peer struct { head common.Hash // Latest advertised head block hash td *big.Int // Latest advertised head block total difficulty + justifiedBlock *uint64 // Latest advertised justified block + knownBlocks *knownCache // Set of block hashes known to be known by this peer queuedBlocks chan *blockPropagation // Queue of blocks to broadcast to the peer queuedBlockAnns chan *types.Block // Queue of blocks to announce to the peer @@ -156,6 +158,22 @@ func (p *Peer) SetHead(hash common.Hash, td *big.Int) { p.td.Set(td) } +// JustifiedBlock retrieves the latest advertised justified block of the peer. +func (p *Peer) JustifiedBlock() *uint64 { + p.lock.Lock() + defer p.lock.Unlock() + + return p.justifiedBlock +} + +// SetJustifiedBlock updates the latest advertised justified block of the peer. +func (p *Peer) SetJustifiedBlock(num uint64) { + p.lock.Lock() + defer p.lock.Unlock() + + p.justifiedBlock = &num +} + // KnownBlock returns whether peer is known to already have a block. func (p *Peer) KnownBlock(hash common.Hash) bool { return p.knownBlocks.Contains(hash) diff --git a/eth/sync.go b/eth/sync.go index c7ba7c93d..75be6cf07 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -22,7 +22,9 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/log" @@ -47,6 +49,15 @@ func (h *handler) syncTransactions(p *eth.Peer) { p.AsyncSendPooledTransactionHashes(hashes) } +// syncVotes starts sending all currently pending votes to the given peer. +func (h *handler) syncVotes(p *bscPeer) { + votes := h.votepool.GetVotes() + if len(votes) == 0 { + return + } + p.AsyncSendVotes(votes) +} + // chainSyncer coordinates blockchain sync components. type chainSyncer struct { handler *handler @@ -162,6 +173,23 @@ func (cs *chainSyncer) nextSyncOp() *chainSyncOp { if cs.handler.peers.len() < minPeers { return nil } + + // Find the peer with the highest justified block height. + mode, ourTD := cs.modeAndLocalHead() + if peer, peerJustified, peerTD := cs.handler.peers.peerWithHighestJustifiedBlockAndTD(); peer != nil { + if ourJustified := cs.getJustifiedBlockNumber(); ourJustified != nil { + // Ignored because justified block height is lower. + if peerJustified < *ourJustified { + return nil + } + // Ignored because justified block height is the same but TD is lower. + if peerJustified == *ourJustified && peerTD.Cmp(ourTD) < 0 { + return nil + } + } + return peerToSyncOp(mode, peer) + } + // We have enough peers, pick the one with the highest TD, but avoid going // over the terminal total difficulty. Above that we expect the consensus // clients to direct the chain head to sync to. @@ -169,7 +197,7 @@ func (cs *chainSyncer) nextSyncOp() *chainSyncOp { if peer == nil { return nil } - mode, ourTD := cs.modeAndLocalHead() + op := peerToSyncOp(mode, peer) if op.td.Cmp(ourTD) <= 0 { // We seem to be in sync according to the legacy rules. In the merge @@ -184,6 +212,25 @@ func (cs *chainSyncer) nextSyncOp() *chainSyncOp { return op } +// Retrieve the justified block number of the canonical chain from the consensus engine. +func (cs *chainSyncer) getJustifiedBlockNumber() *uint64 { + head := cs.handler.chain.CurrentHeader() + if !cs.handler.chain.Config().IsFastFinalityEnabled(head.Number) { + return nil + } + pos, ok := cs.handler.chain.Engine().(consensus.PoS) + if !ok { + return nil + } + // Note: Do not use methods like `(*core.BlockChain).CurrentSafeBlock()`, as they may + // fall back to the latest block if the justified block cannot be retrieved. + justified, _, err := pos.GetJustifiedNumberAndHash(cs.handler.chain, []*types.Header{head}) + if err != nil { + return nil + } + return &justified +} + func peerToSyncOp(mode downloader.SyncMode, p *eth.Peer) *chainSyncOp { peerHead, peerTD := p.Head() return &chainSyncOp{mode: mode, peer: p, td: peerTD, head: peerHead} diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index e8a201f71..21aac088f 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -347,6 +347,17 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) return sub, nil } +// SubscribeNewFinalizedHeader subscribes to notifications about the current blockchain finalized header +// on the given channel. +func (ec *Client) SubscribeNewFinalizedHeader(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) { + return ec.c.EthSubscribe(ctx, ch, "newFinalizedHeaders") +} + +// SubscribeNewVotes subscribes to notifications about the new votes into vote pool +func (ec *Client) SubscribeNewVotes(ctx context.Context, ch chan<- *types.VoteEnvelope) (ethereum.Subscription, error) { + return ec.c.EthSubscribe(ctx, ch, "newVotes") +} + // State Access // NetworkID returns the network ID for this client. diff --git a/go.mod b/go.mod index dc16ffb71..0d6783b50 100644 --- a/go.mod +++ b/go.mod @@ -1,39 +1,39 @@ module github.com/ethereum/go-ethereum -go 1.20 +go 1.21 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 github.com/Microsoft/go-winio v0.6.1 - github.com/VictoriaMetrics/fastcache v1.12.1 + github.com/VictoriaMetrics/fastcache v1.12.2 github.com/aws/aws-sdk-go-v2 v1.21.2 github.com/aws/aws-sdk-go-v2/config v1.18.45 github.com/aws/aws-sdk-go-v2/credentials v1.13.43 github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2 - github.com/btcsuite/btcd/btcec/v2 v2.2.0 - github.com/cespare/cp v0.1.0 + github.com/btcsuite/btcd/btcec/v2 v2.3.2 + github.com/cespare/cp v1.1.1 github.com/cloudflare/cloudflare-go v0.79.0 github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 github.com/consensys/gnark-crypto v0.12.1 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/crate-crypto/go-kzg-4844 v0.7.0 github.com/davecgh/go-spew v1.1.1 - github.com/deckarep/golang-set/v2 v2.1.0 + github.com/deckarep/golang-set/v2 v2.5.0 github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 github.com/ethereum/c-kzg-4844 v0.4.0 github.com/fatih/color v1.13.0 github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/fsnotify/fsnotify v1.6.0 - github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff + github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/protobuf v1.5.3 github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/google/gofuzz v1.2.0 - github.com/google/uuid v1.3.0 - github.com/gorilla/websocket v1.4.2 + github.com/google/uuid v1.4.0 + github.com/gorilla/websocket v1.5.1 github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d @@ -46,39 +46,48 @@ require ( github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 github.com/julienschmidt/httprouter v1.3.0 - github.com/karalabe/usb v0.0.2 + github.com/karalabe/usb v0.0.3-0.20230711191512-61db3e06439c github.com/kylelemons/godebug v1.1.0 + github.com/logrusorgru/aurora v2.0.3+incompatible github.com/mattn/go-colorable v0.1.13 - github.com/mattn/go-isatty v0.0.17 + github.com/mattn/go-isatty v0.0.20 github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 - github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 + github.com/panjf2000/ants/v2 v2.4.5 + github.com/peterh/liner v1.2.0 + github.com/pkg/errors v0.9.1 github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 + github.com/prysmaticlabs/prysm/v5 v5.0.3 github.com/rs/cors v1.7.0 - github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible + github.com/shirou/gopsutil v3.21.11+incompatible github.com/status-im/keycard-go v0.2.0 github.com/stretchr/testify v1.8.4 github.com/supranational/blst v0.3.11 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + github.com/tidwall/wal v1.1.7 github.com/tyler-smith/go-bip39 v1.1.0 - github.com/urfave/cli/v2 v2.25.7 + github.com/urfave/cli/v2 v2.26.0 + github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3 + github.com/willf/bitset v1.1.3 go.uber.org/automaxprocs v1.5.2 - golang.org/x/crypto v0.17.0 - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa - golang.org/x/sync v0.5.0 - golang.org/x/sys v0.15.0 + golang.org/x/crypto v0.19.0 + golang.org/x/exp v0.0.0-20240213143201-ec583247a57a + golang.org/x/sync v0.6.0 + golang.org/x/sys v0.17.0 golang.org/x/text v0.14.0 - golang.org/x/time v0.3.0 - golang.org/x/tools v0.15.0 + golang.org/x/time v0.5.0 + golang.org/x/tools v0.18.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v3 v3.0.1 ) require ( + contrib.go.opencensus.io/exporter/jaeger v0.2.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect - github.com/DataDog/zstd v1.4.5 // indirect - github.com/StackExchange/wmi v1.2.1 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect + github.com/DataDog/zstd v1.5.5 // indirect + github.com/aristanetworks/goarista v0.0.0-20200805130819-fd197cf57d96 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 // indirect @@ -88,57 +97,178 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 // indirect github.com/aws/smithy-go v1.15.0 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/bits-and-blooms/bitset v1.11.0 // indirect + github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cockroachdb/errors v1.8.1 // indirect - github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect - github.com/cockroachdb/redact v1.0.8 // indirect - github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect + github.com/chzyer/readline v1.5.1 // indirect + github.com/cockroachdb/errors v1.11.1 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/consensys/bavard v0.1.13 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect - github.com/deepmap/oapi-codegen v1.6.0 // indirect + github.com/containerd/cgroups v1.1.0 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/deepmap/oapi-codegen v1.8.2 // indirect + github.com/dgraph-io/ristretto v0.0.4-0.20210318174700-74754f61e018 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect + github.com/elastic/gosigar v0.14.2 // indirect + github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9 // indirect + github.com/flynn/noise v1.1.0 // indirect + github.com/francoispqt/gojay v1.2.13 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect - github.com/go-ole/go-ole v1.2.5 // indirect + github.com/getsentry/sentry-go v0.25.0 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.13.0 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 // indirect + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.4 // indirect - github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect + github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e // indirect + github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect + github.com/ipfs/go-cid v0.4.1 // indirect + github.com/ipfs/go-log/v2 v2.5.1 // indirect + github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect + github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect - github.com/klauspost/compress v1.15.15 // indirect + github.com/klauspost/compress v1.17.6 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/koron/go-ssdp v0.0.4 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/mattn/go-runewidth v0.0.13 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/leodido/go-urn v1.2.3 // indirect + github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/libp2p/go-flow-metrics v0.1.0 // indirect + github.com/libp2p/go-libp2p v0.33.1 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect + github.com/libp2p/go-libp2p-mplex v0.9.0 // indirect + github.com/libp2p/go-libp2p-pubsub v0.10.0 // indirect + github.com/libp2p/go-mplex v0.7.0 // indirect + github.com/libp2p/go-msgio v0.3.0 // indirect + github.com/libp2p/go-nat v0.2.0 // indirect + github.com/libp2p/go-netroute v0.2.1 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + github.com/libp2p/go-yamux/v4 v4.0.1 // indirect + github.com/lunixbochs/vtclean v1.0.0 // indirect + github.com/manifoldco/promptui v0.7.0 // indirect + github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/miekg/dns v1.1.58 // indirect + github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect + github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect + github.com/minio/highwayhash v1.0.2 // indirect + github.com/minio/sha256-simd v1.0.1 // indirect + github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect + github.com/multiformats/go-base32 v0.1.0 // indirect + github.com/multiformats/go-base36 v0.2.0 // indirect + github.com/multiformats/go-multiaddr v0.12.2 // indirect + github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect + github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect + github.com/multiformats/go-multibase v0.2.0 // indirect + github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect + github.com/multiformats/go-varint v0.0.7 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect - github.com/opentracing/opentracing-go v1.1.0 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.12.0 // indirect - github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/common v0.47.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/prom2json v1.3.0 // indirect + github.com/prysmaticlabs/fastssz v0.0.0-20221107182844-78142813af44 // indirect + github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 // indirect + github.com/prysmaticlabs/gohashtree v0.0.4-beta // indirect + github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/quic-go v0.42.0 // indirect + github.com/quic-go/webtransport-go v0.6.0 // indirect + github.com/raulk/go-watchdog v1.3.0 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/tklauser/go-sysconf v0.3.12 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect + github.com/schollz/progressbar/v3 v3.3.4 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/spf13/afero v1.10.0 // indirect + github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect + github.com/tidwall/gjson v1.10.2 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/tinylru v1.1.0 // indirect + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect + github.com/trailofbits/go-mutexasserts v0.0.0-20230328101604-8cdbc5f3d279 // indirect + github.com/uber/jaeger-client-go v2.25.0+incompatible // indirect + github.com/wealdtech/go-bytesutil v1.1.1 // indirect + github.com/wealdtech/go-eth2-types/v2 v2.5.2 // indirect + github.com/wealdtech/go-eth2-util v1.6.3 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.18.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect + go.etcd.io/bbolt v1.3.6 // indirect + go.opencensus.io v0.24.0 // indirect + go.uber.org/dig v1.17.1 // indirect + go.uber.org/fx v1.20.1 // indirect + go.uber.org/mock v0.4.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/oauth2 v0.16.0 // indirect + golang.org/x/term v0.17.0 // indirect + google.golang.org/api v0.44.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/grpc v1.56.3 // indirect + google.golang.org/protobuf v1.32.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + k8s.io/apimachinery v0.20.0 // indirect + k8s.io/client-go v0.20.0 // indirect + k8s.io/klog/v2 v2.80.0 // indirect + k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect + lukechampine.com/blake3 v1.2.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.0.2 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect ) + +replace github.com/grpc-ecosystem/grpc-gateway/v2 => github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1 diff --git a/go.sum b/go.sum index ef2b3b25d..d122561d8 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,11 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -13,6 +16,12 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -21,6 +30,7 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -30,34 +40,57 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +contrib.go.opencensus.io/exporter/jaeger v0.2.1 h1:yGBYzYMewVL0yO9qqJv3Z5+IRhPdU7e9o/2oKpX4YvI= +contrib.go.opencensus.io/exporter/jaeger v0.2.1/go.mod h1:Y8IsLgdxqh1QxYxPC5IgXVmBaeLUeQFfBeBi9PbeZd0= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 h1:Ma67P/GGprNwsslzEH6+Kb8nybI8jpDTm4Wmzu2ReK8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/go.mod h1:c+Lifp3EDEamAkPVzMooRNOK6CZjNSdEnf1A7jsI9u4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 h1:gggzg0SUMs6SQbEw+3LoSsYf9YMjkupeAnHMX8O9mmY= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgxoBDMqMO/Nvy7bZ9a0nbU3I1DtFQK3YvB4= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= -github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= -github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= -github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= -github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= +github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -65,7 +98,23 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= +github.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= +github.com/aristanetworks/goarista v0.0.0-20200805130819-fd197cf57d96 h1:XJH0YfVFKbq782tlNThzN/Ud5qm/cx6LXOA/P6RkTxc= +github.com/aristanetworks/goarista v0.0.0-20200805130819-fd197cf57d96/go.mod h1:QZe5Yh80Hp1b6JxQdpfSEEe8X7hTyTEZSosSrFf/oJE= +github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= github.com/aws/aws-sdk-go-v2/config v1.18.45 h1:Aka9bI7n8ysuwPeFdm77nfbyHCAKQ3z9ghB3S/38zes= @@ -92,162 +141,274 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 h1:0BkLfgeDjfZnZ+MhB3ONb01u9pwF github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8= github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/bazelbuild/rules_go v0.23.2 h1:Wxu7JjqnF78cKZbsBsARLSXx/jlGaSLCnUV3mTlyHvM= +github.com/bazelbuild/rules_go v0.23.2/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= -github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= -github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.11.0 h1:RMyy2mBBShArUAhfVRZJ2xyBO58KCBCtZFShw3umo6k= +github.com/bits-and-blooms/bitset v1.11.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= +github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/bufbuild/buf v0.37.0/go.mod h1:lQ1m2HkIaGOFba6w/aC3KYBHhKEOESP3gaAEpS3dAFM= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= -github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= +github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= +github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.79.0 h1:ErwCYDjFCYppDJlDJ/5WhsSmzegAUe2+K9qgFyQDg3M= github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= -github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= -github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= -github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= +github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= -github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= -github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= +github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U= +github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= -github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/deepmap/oapi-codegen v1.6.0 h1:w/d1ntwh91XI0b/8ja7+u5SvA4IFfM0UNNLmiDR1gg0= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/deckarep/golang-set/v2 v2.5.0 h1:hn6cEZtQ0h3J8kFrHR/NrzyOoTnjgW1+FmNJzQ7y/sA= +github.com/deckarep/golang-set/v2 v2.5.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= +github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +github.com/dgraph-io/ristretto v0.0.4-0.20210318174700-74754f61e018 h1:cNcG4c2n5xanQzp2hMyxDxPYVQmZ91y4WN6fJFlndLo= +github.com/dgraph-io/ristretto v0.0.4-0.20210318174700-74754f61e018/go.mod h1:MIonLggsKgZLUSt414ExgwNtlOL5MuEoAJP514mwGe8= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 h1:qwcF+vdFrvPSEUDSX5RVoRccG8a5DhOdWdQ4zN62zzo= github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= +github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9 h1:9VDpsWq096+oGMDTT/SgBD/VgZYf4pTF+KTPmZ+OaKM= +github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgxrzK5E1fW7RQGeDwE8F/ZZnUYc= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= -github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= +github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI= +github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= -github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= -github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ= +github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -255,6 +416,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -270,14 +432,16 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= -github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -288,19 +452,25 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -308,35 +478,91 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= +github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/herumi/bls-eth-go-binary v0.0.0-20210130185500-57372fb27371/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= +github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e h1:wCMygKUQhmcQAjlk2Gquzq6dLmyMv2kF+llRspoRgrk= +github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= @@ -344,111 +570,200 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= -github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= -github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= -github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= +github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsDSy7TDxedi9gyBkMvAirat/oRcL0lFdJBf6tdM= +github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= +github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= +github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= +github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jhump/protoreflect v1.8.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= -github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= -github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= -github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= -github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= +github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg= +github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= +github.com/karalabe/usb v0.0.3-0.20230711191512-61db3e06439c h1:AqsttAyEyIEsNz5WLRwuRwjiT5CMDUfLk6cFJDVPebs= +github.com/karalabe/usb v0.0.3-0.20230711191512-61db3e06439c/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= -github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= +github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= +github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA= +github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= +github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= +github.com/libp2p/go-libp2p v0.33.1 h1:tvJl9b9M6nSLBtZSXSguq+/lRhRj2oLRkyhBmQNMFLA= +github.com/libp2p/go-libp2p v0.33.1/go.mod h1:zOUTMjG4I7TXwMndNyOBn/CNtVBLlvBlnxfi+8xzx+E= +github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= +github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= +github.com/libp2p/go-libp2p-mplex v0.9.0 h1:R58pDRAmuBXkYugbSSXR9wrTX3+1pFM1xP2bLuodIq8= +github.com/libp2p/go-libp2p-mplex v0.9.0/go.mod h1:ro1i4kuwiFT+uMPbIDIFkcLs1KRbNp0QwnUXM+P64Og= +github.com/libp2p/go-libp2p-pubsub v0.10.0 h1:wS0S5FlISavMaAbxyQn3dxMOe2eegMfswM471RuHJwA= +github.com/libp2p/go-libp2p-pubsub v0.10.0/go.mod h1:1OxbaT/pFRO5h+Dpze8hdHQ63R0ke55XTs6b6NwLLkw= +github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= +github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= +github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= +github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= +github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= +github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= +github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= +github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= +github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= +github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= +github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= +github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/manifoldco/promptui v0.7.0 h1:3l11YT8tm9MnwGFQ4kETwkzpAwY2Jt9lCrumCUW4+z4= +github.com/manifoldco/promptui v0.7.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= -github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= -github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= @@ -457,167 +772,454 @@ github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iP github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.12.2 h1:9G9sTY/wCYajKa9lyfWPmpZAwe6oV+Wb1zcmMS1HG24= +github.com/multiformats/go-multiaddr v0.12.2/go.mod h1:GKyaTYjZRdcUhyOetrxTk9z0cW+jA/YrnqTOvKgi44M= +github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= +github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= +github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= +github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= +github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= +github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= -github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= +github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= +github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= +github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/panjf2000/ants/v2 v2.4.5 h1:kcGvjXB7ea0MrzzszpnlVFthhYKoFxLi75nRbsq01HY= +github.com/panjf2000/ants/v2 v2.4.5/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/peterh/liner v1.2.0 h1:w/UPXyl5GfahFxcTOz2j9wCIHNI+pUPr2laqpojKNCg= +github.com/peterh/liner v1.2.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y= -github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= +github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/prom2json v1.3.0 h1:BlqrtbT9lLH3ZsOVhXPsHzFrApCTKRifB7gjJuypu6Y= +github.com/prometheus/prom2json v1.3.0/go.mod h1:rMN7m0ApCowcoDlypBHlkNbp5eJQf/+1isKykIP5ZnM= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 h1:cZC+usqsYgHtlBaGulVnZ1hfKAi8iWtujBnRLQE698c= github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/prysmaticlabs/fastssz v0.0.0-20221107182844-78142813af44 h1:c3p3UzV4vFA7xaCDphnDWOjpxcadrQ26l5b+ypsvyxo= +github.com/prysmaticlabs/fastssz v0.0.0-20221107182844-78142813af44/go.mod h1:MA5zShstUwCQaE9faGHgCGvEWUbG87p4SAXINhmCkvg= +github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4tdWQK9ZpYygoV7+vS6QkDvQVySboMVEIxBJmXw= +github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4= +github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= +github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs= +github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1 h1:xcu59yYL6AWWTl6jtejBfE0y8uF35fArCBeZjRlvJss= +github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1/go.mod h1:IOyTYjcIO0rkmnGBfJTL0NJ11exy/Tc2QEuv7hCXp24= +github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c h1:9PHRCuO/VN0s9k+RmLykho7AjDxblNYI5bYKed16NPU= +github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c/go.mod h1:ZRws458tYHS/Zs936OQ6oCrL+Ict5O4Xpwve1UQ6C9M= +github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294 h1:q9wE0ZZRdTUAAeyFP/w0SwBEnCqlVy2+on6X2/e+eAU= +github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294/go.mod h1:ZVEbRdnMkGhp/pu35zq4SXxtvUwWK0J1MATtekZpH2Y= +github.com/prysmaticlabs/prysm/v5 v5.0.3 h1:hUi0gu6v7aXmMQkl2GbrLoWcMhDNIbkVxRwrZchKbxU= +github.com/prysmaticlabs/prysm/v5 v5.0.3/go.mod h1:v5Oz4A4cWljfxUmW7SDk/VBzoYnei+lzwJogvSqUZVs= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM= +github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= +github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY= +github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc= +github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= +github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= -github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/schollz/progressbar/v3 v3.3.4 h1:nMinx+JaEm/zJz4cEyClQeAw5rsYSB5th3xv+5lV6Vg= +github.com/schollz/progressbar/v3 v3.3.4/go.mod h1:Rp5lZwpgtYmlvmGo1FyDwXMqagyRBQYSDwzlP9QDu84= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= +github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.1-0.20201006035406-b97b5ead31f7/go.mod h1:yk5b0mALVusDL5fMM6Rd1wgnoO5jUPhwsQ6LQAJTidQ= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= +github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e h1:cR8/SYRgyQCt5cNCMniB/ZScMkhI9nk8U5C7SbISXjo= +github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e/go.mod h1:Tu4lItkATkonrYuvtVjG0/rhy15qrNGNTjPdaphtZ/8= +github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo= +github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/tinylru v1.1.0 h1:XY6IUfzVTU9rpwdhKUF6nQdChgCdGjkMfLzbWyiau6I= +github.com/tidwall/tinylru v1.1.0/go.mod h1:3+bX+TJ2baOLMWTnlyNWHh4QMnFyARg2TLTQ6OFbzw8= +github.com/tidwall/wal v1.1.7 h1:emc1TRjIVsdKKSnpwGBAcsAGg0767SvUk8+ygx7Bb+4= +github.com/tidwall/wal v1.1.7/go.mod h1:r6lR1j27W9EPalgHiB7zLJDYu3mzW5BQP5KrzBpYY/E= +github.com/tjfoc/gmsm v1.3.0/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= +github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= +github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= +github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= +github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/trailofbits/go-mutexasserts v0.0.0-20230328101604-8cdbc5f3d279 h1:+LynomhWB+14Plp/bOONEAZCtvCZk4leRbTvNzNVkL0= +github.com/trailofbits/go-mutexasserts v0.0.0-20230328101604-8cdbc5f3d279/go.mod h1:GA3+Mq3kt3tYAfM0WZCu7ofy+GW9PuGysHfhr+6JX7s= +github.com/twitchtv/twirp v7.1.0+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= -github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U= +github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI= +github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/wealdtech/go-bytesutil v1.1.1 h1:ocEg3Ke2GkZ4vQw5lp46rmO+pfqCCTgq35gqOy8JKVc= +github.com/wealdtech/go-bytesutil v1.1.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s= +github.com/wealdtech/go-eth2-types/v2 v2.5.2 h1:tiA6T88M6XQIbrV5Zz53l1G5HtRERcxQfmET225V4Ls= +github.com/wealdtech/go-eth2-types/v2 v2.5.2/go.mod h1:8lkNUbgklSQ4LZ2oMSuxSdR7WwJW3L9ge1dcoCVyzws= +github.com/wealdtech/go-eth2-util v1.6.3 h1:2INPeOR35x5LdFFpSzyw954WzTD+DFyHe3yKlJnG5As= +github.com/wealdtech/go-eth2-util v1.6.3/go.mod h1:0hFMj/qtio288oZFHmAbCnPQ9OB3c4WFzs5NVPKTY4k= +github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3 h1:SxrDVSr+oXuT1x8kZt4uWqNCvv5xXEGV9zd7cuSrZS8= +github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3/go.mod h1:qiIimacW5NhVRy8o+YxWo9YrecXqDAKKbL0+sOa0SJ4= +github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2 h1:264/meVYWt1wFw6Mtn+xwkZkXjID42gNra4rycoiDXI= +github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2/go.mod h1:k6kmiKWSWBTd4OxFifTEkPaBLhZspnO2KFD5XJY9nqg= +github.com/willf/bitset v1.1.3 h1:ekJIKh6+YbUIVt9DfNbkR5d6aFcFTLDRyJNAACURBg8= +github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME= go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= +go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk= +go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -628,10 +1230,12 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -642,6 +1246,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -650,18 +1255,26 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -670,6 +1283,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -678,6 +1292,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -688,18 +1303,36 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -712,25 +1345,33 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -738,86 +1379,118 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -825,12 +1498,14 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= @@ -839,20 +1514,33 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= -golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -869,18 +1557,33 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0 h1:URs6qR1lAxDsqWITsQXI4ZkGiYJ5dHtRNiCpfs2OeKA= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -892,11 +1595,13 @@ google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200218151345-dad8c97a84f5/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= @@ -905,11 +1610,33 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210426193834-eac7f76ac494/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -918,6 +1645,17 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0-dev.0.20201218190559-666aea1fb34c/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -928,36 +1666,56 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.25.1-0.20201208041424-160c7477e0e8/go.mod h1:hFxJC2f0epmp1elRCiEGJTKAWbwxZ2nvqZdHl3FQXCY= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/d4l3k/messagediff.v1 v1.2.1 h1:70AthpjunwzUiarMHyED52mj9UwtAnE89l1Gmrt3EU0= +gopkg.in/d4l3k/messagediff.v1 v1.2.1/go.mod h1:EUzikiKadqXWcD1AzJLagx0j/BeeWGtn++04Xniyg44= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -965,8 +1723,32 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.20.0 h1:WwrYoZNM1W1aQEbyl8HNG+oWGzLpZQBlcerS9BQw9yI= +k8s.io/api v0.20.0/go.mod h1:HyLC5l5eoS/ygQYl1BXBgFzWNlkHiAuyNAbevIn+FKg= +k8s.io/apimachinery v0.20.0 h1:jjzbTJRXk0unNS71L7h3lxGDH/2HPxMPaQY+MjECKL8= +k8s.io/apimachinery v0.20.0/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/client-go v0.20.0 h1:Xlax8PKbZsjX4gFvNtt4F5MoJ1V5prDvCuoq9B7iax0= +k8s.io/client-go v0.20.0/go.mod h1:4KWh/g+Ocd8KkCwKF8vUNnmqgv+EVnQDK4MBF4oB5tY= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.80.0 h1:lyJt0TWMPaGoODa8B8bUuxgHS3W/m/bNr2cca3brA/g= +k8s.io/klog/v2 v2.80.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= +lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index c2490ac70..f5bce466a 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -556,6 +556,12 @@ func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) even func (b testBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { panic("implement me") } +func (b testBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription { + panic("implement me") +} +func (b testBackend) SubscribeNewVoteEvent(ch chan<- core.NewVoteEvent) event.Subscription { + panic("implement me") +} func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { panic("implement me") } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 50f338f5c..f026640bf 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -97,6 +97,8 @@ type Backend interface { SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription BloomStatus() (uint64, uint64) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) + SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription + SubscribeNewVoteEvent(chan<- core.NewVoteEvent) event.Subscription } func GetAPIs(apiBackend Backend) []rpc.API { diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index ab7c2f70e..1d8c5e7bb 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -338,6 +338,12 @@ func (b *backendMock) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) eve return nil } func (b *backendMock) SendTx(ctx context.Context, signedTx *types.Transaction) error { return nil } +func (b *backendMock) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription { + return nil +} +func (b *backendMock) SubscribeNewVoteEvent(ch chan<- core.NewVoteEvent) event.Subscription { + return nil +} func (b *backendMock) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { return nil, [32]byte{}, 0, 0, nil } diff --git a/internal/flags/categories.go b/internal/flags/categories.go index 3ff076792..f152d8fb4 100644 --- a/internal/flags/categories.go +++ b/internal/flags/categories.go @@ -37,6 +37,8 @@ const ( MiscCategory = "MISC" TestingCategory = "TESTING" DeprecatedCategory = "ALIASED (deprecated)" + // for finality + FastFinalityCategory = "FAST FINALITY" ) func init() { diff --git a/miner/miner.go b/miner/miner.go index 613c217e8..229a826a6 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -53,6 +53,9 @@ type Config struct { Recommit time.Duration // The time interval for miner to re-create mining work. NewPayloadTimeout time.Duration // The maximum time allowance for creating a new payload + + VoteEnable bool // Whether to vote when mining + DisableVoteAttestation bool // Whether to skip assembling vote attestation } // DefaultConfig contains default settings for miner. diff --git a/miner/worker.go b/miner/worker.go index 15e7f4006..5033523d3 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -462,7 +462,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { case <-timer.C: // If sealing is running resubmit a new work cycle periodically to pull in // higher priced transactions. Disable this overhead for pending blocks. - if w.isRunning() && ((w.chainConfig.Clique == nil || w.chainConfig.Clique.Period > 0) || w.chainConfig.Oasys == nil || w.chainConfig.Oasys.Period > 0) { + if w.isRunning() && ((w.chainConfig.Clique != nil && w.chainConfig.Clique.Period > 0) || (w.chainConfig.Oasys != nil && w.chainConfig.Oasys.Period > 0)) { // Short circuit if no new transaction arrives. if w.newTxs.Load() == 0 { timer.Reset(recommit) @@ -1073,6 +1073,7 @@ func (w *worker) commitWork(interrupt *atomic.Int32, timestamp int64) { coinbase: coinbase, }) if err != nil { + log.Error("Failed to prepare work", "in", "commitWork", "err", err) return } // Deploy oasys built-in contracts @@ -1107,7 +1108,9 @@ func (w *worker) commitWork(interrupt *atomic.Int32, timestamp int64) { return } // Submit the generated block for consensus sealing. - w.commit(work.copy(), w.fullTaskHook, true, start) + if err = w.commit(work.copy(), w.fullTaskHook, true, start); err != nil { + log.Warn("Failed to commit work", "in", "commitWork", "err", err) + } // Swap out the old work with the new one, terminating any leftover // prefetcher processes in the mean time and starting a new one. diff --git a/node/config.go b/node/config.go index 949db887e..44787ae96 100644 --- a/node/config.go +++ b/node/config.go @@ -198,6 +198,23 @@ type Config struct { // AllowUnprotectedTxs allows non EIP-155 protected transactions to be send over RPC. AllowUnprotectedTxs bool `toml:",omitempty"` + // EnableMaliciousVoteMonitor is a flag that whether to enable the malicious vote checker + EnableMaliciousVoteMonitor bool `toml:",omitempty"` + + // BLSPasswordFile is the file that contains BLS wallet password. + BLSPasswordFile string `toml:",omitempty"` + + // BLSWalletDir is the file system folder of BLS wallet. The directory can + // be specified as a relative path, in which case it is resolved relative to the + // current directory. + BLSWalletDir string `toml:",omitempty"` + + // VoteJournalDir is the directory to store votes in the fast finality feature. + VoteJournalDir string `toml:",omitempty"` + + // VoteKeyName is name of the BLS public key used for voting + VoteKeyName string `toml:",omitempty"` + // BatchRequestLimit is the maximum number of requests in a batch. BatchRequestLimit int `toml:",omitempty"` diff --git a/p2p/rlpx/rlpx.go b/p2p/rlpx/rlpx.go index 8bd6f64b9..7427c01b9 100644 --- a/p2p/rlpx/rlpx.go +++ b/p2p/rlpx/rlpx.go @@ -664,7 +664,7 @@ func exportPubkey(pub *ecies.PublicKey) []byte { if pub == nil { panic("nil pubkey") } - return elliptic.Marshal(pub.Curve, pub.X, pub.Y)[1:] + return elliptic.Marshal(pub.Curve, pub.X, pub.Y)[1:] //nolint:all //TODO } func xor(one, other []byte) (xor []byte) { diff --git a/params/config.go b/params/config.go index 6dd72bc04..b6828e531 100644 --- a/params/config.go +++ b/params/config.go @@ -480,6 +480,9 @@ func (c *ChainConfig) Description() string { if c.ShanghaiTime != nil { banner += fmt.Sprintf(" - Shanghai: @%-10v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", *c.ShanghaiTime) } + if c.OasysFastFinalityEnabledBlock() != nil { + banner += fmt.Sprintf(" - Oasys Fast Finality Enabled: #%-8v (https://github.com/oasysgames/oasys-validator/releases/tag/v1.6.0)\n", c.OasysFastFinalityEnabledBlock()) + } if c.CancunTime != nil { banner += fmt.Sprintf(" - Cancun: @%-10v\n", *c.CancunTime) } @@ -616,6 +619,26 @@ func (c *ChainConfig) OasysShortenedBlockTimeStartEpoch() *big.Int { return big.NewInt(SHORT_BLOCK_TIME_FORK_EPOCH_OTHERS) } +// OasysFastFinalityEnabledBlock returns the hard fork of Oasys. +// TODO: Set correct block number for mainnet and testnet. +func (c *ChainConfig) OasysFastFinalityEnabledBlock() *big.Int { + if c.Oasys == nil { + return nil + } + if c.ChainID.Cmp(OasysMainnetChainConfig.ChainID) == 0 { + return big.NewInt(9999999) + } + if c.ChainID.Cmp(OasysTestnetChainConfig.ChainID) == 0 { + return big.NewInt(4958700) // Thu Oct 31 2024 18:00:00 GMT+0900 + } + return big.NewInt(2) +} + +// IsFastFinalityEnabled returns whether num is either equal to the first fast finality fork block or greater. +func (c *ChainConfig) IsFastFinalityEnabled(num *big.Int) bool { + return isBlockForked(c.OasysFastFinalityEnabledBlock(), num) +} + // IsTerminalPoWBlock returns whether the given block is the last block of PoW stage. func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool { if c.TerminalTotalDifficulty == nil { diff --git a/params/oasys.go b/params/oasys.go index 0090ead48..097f226cf 100644 --- a/params/oasys.go +++ b/params/oasys.go @@ -1,6 +1,7 @@ package params import ( + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -10,9 +11,9 @@ const ( SHORT_BLOCK_TIME_SECONDS = 6 SHORT_BLOCK_TIME_EPOCH_PERIOD = 14400 // 6 sec * 14400 block = 1 days - SHORT_BLOCK_TIME_FORK_EPOCH_MAINNET = 999 // TODO - SHORT_BLOCK_TIME_FORK_EPOCH_TESTNET = 699 - SHORT_BLOCK_TIME_FORK_EPOCH_OTHERS = 10 // for local chain + SHORT_BLOCK_TIME_FORK_EPOCH_MAINNET = 711 // Block #4089600 + SHORT_BLOCK_TIME_FORK_EPOCH_TESTNET = 699 // Block #4020480 + SHORT_BLOCK_TIME_FORK_EPOCH_OTHERS = 10 // for local chain ) // EnvironmentValue is a representation of `Environment.EnvironmentValue`. @@ -73,6 +74,40 @@ func (p *EnvironmentValue) Copy() *EnvironmentValue { } } +// Checks if the values of all fields are equal to `expect`. +func (p *EnvironmentValue) Equal(expect *EnvironmentValue) error { + ne := func(a, b *big.Int) bool { return a.Cmp(b) != 0 } + + if ne(p.StartBlock, expect.StartBlock) { + return fmt.Errorf("mismatching start block, expected: %v, real: %v", expect.StartBlock, p.StartBlock) + } + if ne(p.StartEpoch, expect.StartEpoch) { + return fmt.Errorf("mismatching start epoch, expected: %v, real: %v", expect.StartEpoch, p.StartEpoch) + } + if ne(p.BlockPeriod, expect.BlockPeriod) { + return fmt.Errorf("mismatching block period, expected: %v, real: %v", expect.BlockPeriod, p.BlockPeriod) + } + if ne(p.EpochPeriod, expect.EpochPeriod) { + return fmt.Errorf("mismatching epoch period, expected: %v, real: %v", expect.EpochPeriod, p.EpochPeriod) + } + if ne(p.RewardRate, expect.RewardRate) { + return fmt.Errorf("mismatching reward rate, expected: %v, real: %v", expect.RewardRate, p.RewardRate) + } + if ne(p.CommissionRate, expect.CommissionRate) { + return fmt.Errorf("mismatching commission rate, expected: %v, real: %v", expect.CommissionRate, p.CommissionRate) + } + if ne(p.ValidatorThreshold, expect.ValidatorThreshold) { + return fmt.Errorf("mismatching validator threshold, expected: %v, real: %v", expect.ValidatorThreshold, p.ValidatorThreshold) + } + if ne(p.JailThreshold, expect.JailThreshold) { + return fmt.Errorf("mismatching jail threshold, expected: %v, real: %v", expect.JailThreshold, p.JailThreshold) + } + if ne(p.JailPeriod, expect.JailPeriod) { + return fmt.Errorf("mismatching jail period, expected: %v, real: %v", expect.JailPeriod, p.JailPeriod) + } + return nil +} + // Returns the environment value in Genesis. func InitialEnvironmentValue(cfg *OasysConfig) *EnvironmentValue { return &EnvironmentValue{ diff --git a/params/oasys_test.go b/params/oasys_test.go index 776169d67..02f47c945 100644 --- a/params/oasys_test.go +++ b/params/oasys_test.go @@ -79,60 +79,11 @@ func TestEnvironmentValue(t *testing.T) { t.Errorf("GetFirstBlock(%d): want=11520 got=%d", number, got) } } -} -func TestNewEnvironmentValue(t *testing.T) { - compare := func(got, want *EnvironmentValue) { - if got.StartBlock.Cmp(want.StartBlock) != 0 { - t.Errorf("StartBlock: want=%d got=%d", want.StartBlock, got.StartBlock) - } - if got.StartEpoch.Cmp(want.StartEpoch) != 0 { - t.Errorf("StartEpoch: want=%d got=%d", want.StartEpoch, got.StartEpoch) - } - if got.BlockPeriod.Cmp(want.BlockPeriod) != 0 { - t.Errorf("BlockPeriod: want=%d got=%d", want.BlockPeriod, got.BlockPeriod) - } - if got.EpochPeriod.Cmp(want.EpochPeriod) != 0 { - t.Errorf("EpochPeriod: want=%d got=%d", want.EpochPeriod, got.EpochPeriod) - } - if got.RewardRate.Cmp(want.RewardRate) != 0 { - t.Errorf("RewardRate: want=%d got=%d", want.RewardRate, got.RewardRate) - } - if got.CommissionRate.Cmp(want.CommissionRate) != 0 { - t.Errorf("CommissionRate: want=%d got=%d", want.CommissionRate, got.CommissionRate) - } - if got.ValidatorThreshold.Cmp(want.ValidatorThreshold) != 0 { - t.Errorf("ValidatorThreshold: want=%d got=%d", want.ValidatorThreshold, got.ValidatorThreshold) - } - if got.JailThreshold.Cmp(want.JailThreshold) != 0 { - t.Errorf("JailThreshold: want=%d got=%d", want.JailThreshold, got.JailThreshold) - } - if got.JailPeriod.Cmp(want.JailPeriod) != 0 { - t.Errorf("JailPeriod: want=%d got=%d", want.JailPeriod, got.JailPeriod) - } + // test `Equal` method + wantErr := "mismatching start block, expected: 0, real: 11520" + gotErr := newVal.Equal(env).Error() + if gotErr != wantErr { + t.Errorf("Equal(env): want=`%s` got=`%s`", wantErr, gotErr) } - - compare(InitialEnvironmentValue(OasysMainnetChainConfig), &EnvironmentValue{ - StartBlock: common.Big0, - StartEpoch: common.Big1, - BlockPeriod: big.NewInt(15), - EpochPeriod: big.NewInt(5760), - RewardRate: big.NewInt(10), - CommissionRate: big.NewInt(10), - ValidatorThreshold: new(big.Int).Mul(big.NewInt(Ether), big.NewInt(10_000_000)), - JailThreshold: big.NewInt(500), - JailPeriod: big.NewInt(2), - }) - - compare(ShortenedBlockTimeEnvironmentValue(OasysMainnetChainConfig), &EnvironmentValue{ - StartBlock: big.NewInt(5748480), - StartEpoch: big.NewInt(999), - BlockPeriod: big.NewInt(6), - EpochPeriod: big.NewInt(14400), - RewardRate: big.NewInt(10), - CommissionRate: big.NewInt(10), - ValidatorThreshold: new(big.Int).Mul(big.NewInt(Ether), big.NewInt(10_000_000)), - JailThreshold: big.NewInt(500), - JailPeriod: big.NewInt(2), - }) } diff --git a/params/version.go b/params/version.go index 77657364a..f02b4be18 100644 --- a/params/version.go +++ b/params/version.go @@ -22,7 +22,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release - VersionMinor = 5 // Minor version component of the current release + VersionMinor = 6 // Minor version component of the current release VersionPatch = 0 // Patch version component of the current release VersionMeta = "testnet0" // Version metadata to append to the version string ) diff --git a/rlp/unsafe.go b/rlp/unsafe.go index 2152ba35f..7218be45a 100644 --- a/rlp/unsafe.go +++ b/rlp/unsafe.go @@ -27,7 +27,7 @@ import ( // byteArrayBytes returns a slice of the byte array v. func byteArrayBytes(v reflect.Value, length int) []byte { var s []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s)) + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s)) //nolint:all //TODO hdr.Data = v.UnsafeAddr() hdr.Cap = length hdr.Len = length diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go index f8806076b..b7167552d 100644 --- a/signer/core/signed_data.go +++ b/signer/core/signed_data.go @@ -258,7 +258,7 @@ func oasysHeaderHashAndRlp(header *types.Header) (hash, rlp []byte, err error) { return } rlp = oasys.OasysRLP(header) - hash = oasys.SealHash(header).Bytes() + hash = types.SealHash(header).Bytes() return hash, rlp, err }