diff --git a/.github/workflows/infrastructure.yml b/.github/workflows/infrastructure.yml index b56356e9c..537e25007 100644 --- a/.github/workflows/infrastructure.yml +++ b/.github/workflows/infrastructure.yml @@ -241,7 +241,8 @@ jobs: --settlement-rpc-endpoint ws://127.0.0.1:8546 \ --bootnode-rpc-urls 127.0.0.1:13524 \ --provider-rpc-urls 127.0.0.1:13624 \ - --bidder-rpc-urls 127.0.0.1:13724 + --bidder-rpc-urls 127.0.0.1:13724 \ + --relay-endpoint http://127.0.0.1:8082 - name: Notify - Deployment Successful if: ${{ env.IS_MANUAL_DEPLOYMENT == 'true' && success() }} diff --git a/bridge/standard/cmd/emulator/main.go b/bridge/standard/cmd/emulator/main.go index fd3ff0a04..95de004d9 100644 --- a/bridge/standard/cmd/emulator/main.go +++ b/bridge/standard/cmd/emulator/main.go @@ -223,7 +223,8 @@ func main() { continue } startTime := time.Now() - statusC := tSettlement.Do(ctx) + cctx, cancel := context.WithTimeout(ctx, 15*time.Minute) + statusC := tSettlement.Do(cctx) for status := range statusC { if status.Error != nil { logger.Error("failed transfer to settlement", "error", status.Error) @@ -231,10 +232,12 @@ func main() { txtors[0].GetAddress().String(), "L1->Settlement", ).Set(time.Since(startTime).Seconds()) + cancel() continue RESTART } logger.Info("transfer to settlement status", "message", status.Message) } + cancel() completionTimeSec := time.Since(startTime).Seconds() logger.Info("completed settlement transfer", "time", completionTimeSec, @@ -268,7 +271,8 @@ func main() { continue } startTime = time.Now() - statusC = tL1.Do(ctx) + cctx, cancel = context.WithTimeout(ctx, 15*time.Minute) + statusC = tL1.Do(cctx) for status := range statusC { if status.Error != nil { logger.Error("failed transfer to L1", "error", status.Error) @@ -276,10 +280,12 @@ func main() { txtors[0].GetAddress().String(), "Settlement->L1", ).Set(time.Since(startTime).Seconds()) + cancel() continue RESTART } logger.Info("transfer to L1 status", "message", status.Message) } + cancel() completionTimeSec = time.Since(startTime).Seconds() logger.Info("completed L1 transfer", "time", completionTimeSec, diff --git a/contracts-abi/abi/BlockTracker.abi b/contracts-abi/abi/BlockTracker.abi index b859c82de..b91e3c2f7 100644 --- a/contracts-abi/abi/BlockTracker.abi +++ b/contracts-abi/abi/BlockTracker.abi @@ -242,6 +242,19 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "providerRegistry", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IProviderRegistry" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "proxiableUUID", @@ -265,9 +278,9 @@ "internalType": "uint256" }, { - "name": "_winnerGraffiti", - "type": "string", - "internalType": "string" + "name": "_winnerBLSKey", + "type": "bytes", + "internalType": "bytes" } ], "outputs": [], @@ -293,6 +306,19 @@ "outputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "setProviderRegistry", + "inputs": [ + { + "name": "newProviderRegistry", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "transferOwnership", @@ -471,6 +497,25 @@ ], "anonymous": false }, + { + "type": "event", + "name": "ProviderRegistrySet", + "inputs": [ + { + "name": "oldProviderRegistry", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newProviderRegistry", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, { "type": "event", "name": "Unpaused", diff --git a/contracts-abi/abi/ProviderRegistry.abi b/contracts-abi/abi/ProviderRegistry.abi index e7db104bb..2b20a0c94 100644 --- a/contracts-abi/abi/ProviderRegistry.abi +++ b/contracts-abi/abi/ProviderRegistry.abi @@ -77,6 +77,25 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "blockBuilderBLSKeyToAddress", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "delegateRegisterAndStake", @@ -87,9 +106,9 @@ "internalType": "address" }, { - "name": "blsPublicKey", - "type": "bytes", - "internalType": "bytes" + "name": "blsPublicKeys", + "type": "bytes[]", + "internalType": "bytes[]" } ], "outputs": [], @@ -110,12 +129,17 @@ }, { "type": "function", - "name": "eoaToBlsPubkey", + "name": "eoaToBlsPubkeys", "inputs": [ { "name": "", "type": "address", "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" } ], "outputs": [ @@ -155,7 +179,7 @@ }, { "type": "function", - "name": "getBLSKey", + "name": "getBLSKeys", "inputs": [ { "name": "provider", @@ -166,10 +190,29 @@ "outputs": [ { "name": "", + "type": "bytes[]", + "internalType": "bytes[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getEoaFromBLSKey", + "inputs": [ + { + "name": "blsKey", "type": "bytes", "internalType": "bytes" } ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], "stateMutability": "view" }, { @@ -405,9 +448,9 @@ "name": "registerAndStake", "inputs": [ { - "name": "blsPublicKey", - "type": "bytes", - "internalType": "bytes" + "name": "blsPublicKeys", + "type": "bytes[]", + "internalType": "bytes[]" } ], "outputs": [], @@ -877,10 +920,10 @@ "internalType": "uint256" }, { - "name": "blsPublicKey", - "type": "bytes", + "name": "blsPublicKeys", + "type": "bytes[]", "indexed": false, - "internalType": "bytes" + "internalType": "bytes[]" } ], "anonymous": false @@ -992,6 +1035,11 @@ } ] }, + { + "type": "error", + "name": "AtLeastOneBLSKeyRequired", + "inputs": [] + }, { "type": "error", "name": "BidderAmountIsZero", diff --git a/contracts-abi/clients/BlockTracker/BlockTracker.go b/contracts-abi/clients/BlockTracker/BlockTracker.go index 3751e83a0..4f44ccc52 100644 --- a/contracts-abi/clients/BlockTracker/BlockTracker.go +++ b/contracts-abi/clients/BlockTracker/BlockTracker.go @@ -31,7 +31,7 @@ var ( // BlocktrackerMetaData contains all meta data concerning the Blocktracker contract. var BlocktrackerMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"fallback\",\"stateMutability\":\"payable\"},{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"acceptOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addBuilderAddress\",\"inputs\":[{\"name\":\"builderName\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"builderAddress\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"blockBuilderNameToAddress\",\"inputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blockWinners\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentWindow\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getBlockWinner\",\"inputs\":[{\"name\":\"blockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getBlocksPerWindow\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"getBuilder\",\"inputs\":[{\"name\":\"builderNameGraffiti\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentWindow\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"oracleAccount_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"owner_\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"oracleAccount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingOwner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recordL1Block\",\"inputs\":[{\"name\":\"_blockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_winnerGraffiti\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setOracleAccount\",\"inputs\":[{\"name\":\"newOracleAccount\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"BuilderAddressAdded\",\"inputs\":[{\"name\":\"builderName\",\"type\":\"string\",\"indexed\":true,\"internalType\":\"string\"},{\"name\":\"builderAddress\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NewL1Block\",\"inputs\":[{\"name\":\"blockNumber\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"winner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"window\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NewWindow\",\"inputs\":[{\"name\":\"window\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OracleAccountSet\",\"inputs\":[{\"name\":\"oldOracleAccount\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOracleAccount\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferStarted\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"BlockNumberIsZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedInnerCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidFallback\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidReceive\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotOracleAccount\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"oracleAccount\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableInvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}]", + ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"fallback\",\"stateMutability\":\"payable\"},{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"acceptOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addBuilderAddress\",\"inputs\":[{\"name\":\"builderName\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"builderAddress\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"blockBuilderNameToAddress\",\"inputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blockWinners\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentWindow\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getBlockWinner\",\"inputs\":[{\"name\":\"blockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getBlocksPerWindow\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"getBuilder\",\"inputs\":[{\"name\":\"builderNameGraffiti\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentWindow\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"oracleAccount_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"owner_\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"oracleAccount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingOwner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"providerRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIProviderRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recordL1Block\",\"inputs\":[{\"name\":\"_blockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_winnerBLSKey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setOracleAccount\",\"inputs\":[{\"name\":\"newOracleAccount\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setProviderRegistry\",\"inputs\":[{\"name\":\"newProviderRegistry\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"BuilderAddressAdded\",\"inputs\":[{\"name\":\"builderName\",\"type\":\"string\",\"indexed\":true,\"internalType\":\"string\"},{\"name\":\"builderAddress\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NewL1Block\",\"inputs\":[{\"name\":\"blockNumber\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"winner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"window\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NewWindow\",\"inputs\":[{\"name\":\"window\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OracleAccountSet\",\"inputs\":[{\"name\":\"oldOracleAccount\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOracleAccount\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferStarted\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ProviderRegistrySet\",\"inputs\":[{\"name\":\"oldProviderRegistry\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newProviderRegistry\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"BlockNumberIsZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedInnerCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidFallback\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidReceive\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotOracleAccount\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"oracleAccount\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableInvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}]", } // BlocktrackerABI is the input ABI used to generate the binding from. @@ -552,6 +552,37 @@ func (_Blocktracker *BlocktrackerCallerSession) PendingOwner() (common.Address, return _Blocktracker.Contract.PendingOwner(&_Blocktracker.CallOpts) } +// ProviderRegistry is a free data retrieval call binding the contract method 0x545921d9. +// +// Solidity: function providerRegistry() view returns(address) +func (_Blocktracker *BlocktrackerCaller) ProviderRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Blocktracker.contract.Call(opts, &out, "providerRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// ProviderRegistry is a free data retrieval call binding the contract method 0x545921d9. +// +// Solidity: function providerRegistry() view returns(address) +func (_Blocktracker *BlocktrackerSession) ProviderRegistry() (common.Address, error) { + return _Blocktracker.Contract.ProviderRegistry(&_Blocktracker.CallOpts) +} + +// ProviderRegistry is a free data retrieval call binding the contract method 0x545921d9. +// +// Solidity: function providerRegistry() view returns(address) +func (_Blocktracker *BlocktrackerCallerSession) ProviderRegistry() (common.Address, error) { + return _Blocktracker.Contract.ProviderRegistry(&_Blocktracker.CallOpts) +} + // ProxiableUUID is a free data retrieval call binding the contract method 0x52d1902d. // // Solidity: function proxiableUUID() view returns(bytes32) @@ -667,25 +698,25 @@ func (_Blocktracker *BlocktrackerTransactorSession) Pause() (*types.Transaction, return _Blocktracker.Contract.Pause(&_Blocktracker.TransactOpts) } -// RecordL1Block is a paid mutator transaction binding the contract method 0x1d63f108. +// RecordL1Block is a paid mutator transaction binding the contract method 0x710cf5c6. // -// Solidity: function recordL1Block(uint256 _blockNumber, string _winnerGraffiti) returns() -func (_Blocktracker *BlocktrackerTransactor) RecordL1Block(opts *bind.TransactOpts, _blockNumber *big.Int, _winnerGraffiti string) (*types.Transaction, error) { - return _Blocktracker.contract.Transact(opts, "recordL1Block", _blockNumber, _winnerGraffiti) +// Solidity: function recordL1Block(uint256 _blockNumber, bytes _winnerBLSKey) returns() +func (_Blocktracker *BlocktrackerTransactor) RecordL1Block(opts *bind.TransactOpts, _blockNumber *big.Int, _winnerBLSKey []byte) (*types.Transaction, error) { + return _Blocktracker.contract.Transact(opts, "recordL1Block", _blockNumber, _winnerBLSKey) } -// RecordL1Block is a paid mutator transaction binding the contract method 0x1d63f108. +// RecordL1Block is a paid mutator transaction binding the contract method 0x710cf5c6. // -// Solidity: function recordL1Block(uint256 _blockNumber, string _winnerGraffiti) returns() -func (_Blocktracker *BlocktrackerSession) RecordL1Block(_blockNumber *big.Int, _winnerGraffiti string) (*types.Transaction, error) { - return _Blocktracker.Contract.RecordL1Block(&_Blocktracker.TransactOpts, _blockNumber, _winnerGraffiti) +// Solidity: function recordL1Block(uint256 _blockNumber, bytes _winnerBLSKey) returns() +func (_Blocktracker *BlocktrackerSession) RecordL1Block(_blockNumber *big.Int, _winnerBLSKey []byte) (*types.Transaction, error) { + return _Blocktracker.Contract.RecordL1Block(&_Blocktracker.TransactOpts, _blockNumber, _winnerBLSKey) } -// RecordL1Block is a paid mutator transaction binding the contract method 0x1d63f108. +// RecordL1Block is a paid mutator transaction binding the contract method 0x710cf5c6. // -// Solidity: function recordL1Block(uint256 _blockNumber, string _winnerGraffiti) returns() -func (_Blocktracker *BlocktrackerTransactorSession) RecordL1Block(_blockNumber *big.Int, _winnerGraffiti string) (*types.Transaction, error) { - return _Blocktracker.Contract.RecordL1Block(&_Blocktracker.TransactOpts, _blockNumber, _winnerGraffiti) +// Solidity: function recordL1Block(uint256 _blockNumber, bytes _winnerBLSKey) returns() +func (_Blocktracker *BlocktrackerTransactorSession) RecordL1Block(_blockNumber *big.Int, _winnerBLSKey []byte) (*types.Transaction, error) { + return _Blocktracker.Contract.RecordL1Block(&_Blocktracker.TransactOpts, _blockNumber, _winnerBLSKey) } // RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. @@ -730,6 +761,27 @@ func (_Blocktracker *BlocktrackerTransactorSession) SetOracleAccount(newOracleAc return _Blocktracker.Contract.SetOracleAccount(&_Blocktracker.TransactOpts, newOracleAccount) } +// SetProviderRegistry is a paid mutator transaction binding the contract method 0xf760660e. +// +// Solidity: function setProviderRegistry(address newProviderRegistry) returns() +func (_Blocktracker *BlocktrackerTransactor) SetProviderRegistry(opts *bind.TransactOpts, newProviderRegistry common.Address) (*types.Transaction, error) { + return _Blocktracker.contract.Transact(opts, "setProviderRegistry", newProviderRegistry) +} + +// SetProviderRegistry is a paid mutator transaction binding the contract method 0xf760660e. +// +// Solidity: function setProviderRegistry(address newProviderRegistry) returns() +func (_Blocktracker *BlocktrackerSession) SetProviderRegistry(newProviderRegistry common.Address) (*types.Transaction, error) { + return _Blocktracker.Contract.SetProviderRegistry(&_Blocktracker.TransactOpts, newProviderRegistry) +} + +// SetProviderRegistry is a paid mutator transaction binding the contract method 0xf760660e. +// +// Solidity: function setProviderRegistry(address newProviderRegistry) returns() +func (_Blocktracker *BlocktrackerTransactorSession) SetProviderRegistry(newProviderRegistry common.Address) (*types.Transaction, error) { + return _Blocktracker.Contract.SetProviderRegistry(&_Blocktracker.TransactOpts, newProviderRegistry) +} + // TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. // // Solidity: function transferOwnership(address newOwner) returns() @@ -2021,6 +2073,159 @@ func (_Blocktracker *BlocktrackerFilterer) ParsePaused(log types.Log) (*Blocktra return event, nil } +// BlocktrackerProviderRegistrySetIterator is returned from FilterProviderRegistrySet and is used to iterate over the raw logs and unpacked data for ProviderRegistrySet events raised by the Blocktracker contract. +type BlocktrackerProviderRegistrySetIterator struct { + Event *BlocktrackerProviderRegistrySet // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *BlocktrackerProviderRegistrySetIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(BlocktrackerProviderRegistrySet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(BlocktrackerProviderRegistrySet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *BlocktrackerProviderRegistrySetIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *BlocktrackerProviderRegistrySetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// BlocktrackerProviderRegistrySet represents a ProviderRegistrySet event raised by the Blocktracker contract. +type BlocktrackerProviderRegistrySet struct { + OldProviderRegistry common.Address + NewProviderRegistry common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterProviderRegistrySet is a free log retrieval operation binding the contract event 0x40dcebfaa5919cfdf9eaf8b88a0199d0b1404782c7fc8c2f0343050d331b9459. +// +// Solidity: event ProviderRegistrySet(address indexed oldProviderRegistry, address indexed newProviderRegistry) +func (_Blocktracker *BlocktrackerFilterer) FilterProviderRegistrySet(opts *bind.FilterOpts, oldProviderRegistry []common.Address, newProviderRegistry []common.Address) (*BlocktrackerProviderRegistrySetIterator, error) { + + var oldProviderRegistryRule []interface{} + for _, oldProviderRegistryItem := range oldProviderRegistry { + oldProviderRegistryRule = append(oldProviderRegistryRule, oldProviderRegistryItem) + } + var newProviderRegistryRule []interface{} + for _, newProviderRegistryItem := range newProviderRegistry { + newProviderRegistryRule = append(newProviderRegistryRule, newProviderRegistryItem) + } + + logs, sub, err := _Blocktracker.contract.FilterLogs(opts, "ProviderRegistrySet", oldProviderRegistryRule, newProviderRegistryRule) + if err != nil { + return nil, err + } + return &BlocktrackerProviderRegistrySetIterator{contract: _Blocktracker.contract, event: "ProviderRegistrySet", logs: logs, sub: sub}, nil +} + +// WatchProviderRegistrySet is a free log subscription operation binding the contract event 0x40dcebfaa5919cfdf9eaf8b88a0199d0b1404782c7fc8c2f0343050d331b9459. +// +// Solidity: event ProviderRegistrySet(address indexed oldProviderRegistry, address indexed newProviderRegistry) +func (_Blocktracker *BlocktrackerFilterer) WatchProviderRegistrySet(opts *bind.WatchOpts, sink chan<- *BlocktrackerProviderRegistrySet, oldProviderRegistry []common.Address, newProviderRegistry []common.Address) (event.Subscription, error) { + + var oldProviderRegistryRule []interface{} + for _, oldProviderRegistryItem := range oldProviderRegistry { + oldProviderRegistryRule = append(oldProviderRegistryRule, oldProviderRegistryItem) + } + var newProviderRegistryRule []interface{} + for _, newProviderRegistryItem := range newProviderRegistry { + newProviderRegistryRule = append(newProviderRegistryRule, newProviderRegistryItem) + } + + logs, sub, err := _Blocktracker.contract.WatchLogs(opts, "ProviderRegistrySet", oldProviderRegistryRule, newProviderRegistryRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(BlocktrackerProviderRegistrySet) + if err := _Blocktracker.contract.UnpackLog(event, "ProviderRegistrySet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseProviderRegistrySet is a log parse operation binding the contract event 0x40dcebfaa5919cfdf9eaf8b88a0199d0b1404782c7fc8c2f0343050d331b9459. +// +// Solidity: event ProviderRegistrySet(address indexed oldProviderRegistry, address indexed newProviderRegistry) +func (_Blocktracker *BlocktrackerFilterer) ParseProviderRegistrySet(log types.Log) (*BlocktrackerProviderRegistrySet, error) { + event := new(BlocktrackerProviderRegistrySet) + if err := _Blocktracker.contract.UnpackLog(event, "ProviderRegistrySet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + // BlocktrackerUnpausedIterator is returned from FilterUnpaused and is used to iterate over the raw logs and unpacked data for Unpaused events raised by the Blocktracker contract. type BlocktrackerUnpausedIterator struct { Event *BlocktrackerUnpaused // Event containing the contract specifics and raw log diff --git a/contracts-abi/clients/ProviderRegistry/ProviderRegistry.go b/contracts-abi/clients/ProviderRegistry/ProviderRegistry.go index b80118998..df51b19fb 100644 --- a/contracts-abi/clients/ProviderRegistry/ProviderRegistry.go +++ b/contracts-abi/clients/ProviderRegistry/ProviderRegistry.go @@ -31,7 +31,7 @@ var ( // ProviderregistryMetaData contains all meta data concerning the Providerregistry contract. var ProviderregistryMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"fallback\",\"stateMutability\":\"payable\"},{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"PERCENT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"PRECISION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"acceptOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"bidderSlashedAmount\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegateRegisterAndStake\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"blsPublicKey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"delegateStake\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"eoaToBlsPubkey\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"feePercent\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAccumulatedPenaltyFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getBLSKey\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getProviderStake\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_minStake\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_penaltyFeeRecipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_feePercent\",\"type\":\"uint16\",\"internalType\":\"uint16\"},{\"name\":\"_owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_withdrawalDelay\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_penaltyFeePayoutPeriodBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isProviderValid\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"manuallyWithdrawPenaltyFee\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"minStake\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"penaltyFeeTracker\",\"inputs\":[],\"outputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"accumulatedAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"lastPayoutBlock\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"payoutPeriodBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingOwner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"preconfManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"providerRegistered\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"providerStakes\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerAndStake\",\"inputs\":[{\"name\":\"blsPublicKey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setFeePayoutPeriodBlocks\",\"inputs\":[{\"name\":\"_feePayoutPeriodBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinStake\",\"inputs\":[{\"name\":\"_minStake\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setNewFeePercent\",\"inputs\":[{\"name\":\"newFeePercent\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setNewPenaltyFeeRecipient\",\"inputs\":[{\"name\":\"newFeeRecipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPreconfManager\",\"inputs\":[{\"name\":\"contractAddress\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setWithdrawalDelay\",\"inputs\":[{\"name\":\"_withdrawalDelay\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slash\",\"inputs\":[{\"name\":\"amt\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"bidder\",\"type\":\"address\",\"internalType\":\"addresspayable\"},{\"name\":\"residualBidPercentAfterDecay\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unstake\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSlashedAmount\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawalDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawalRequests\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"BidderWithdrawSlashedAmount\",\"inputs\":[{\"name\":\"bidder\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FeePayoutPeriodBlocksUpdated\",\"inputs\":[{\"name\":\"newFeePayoutPeriodBlocks\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FeePercentUpdated\",\"inputs\":[{\"name\":\"newFeePercent\",\"type\":\"uint16\",\"indexed\":true,\"internalType\":\"uint16\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FeeTransfer\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FundsDeposited\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FundsSlashed\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InsufficientFundsToSlash\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"providerStake\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"residualAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"penaltyFee\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinStakeUpdated\",\"inputs\":[{\"name\":\"newMinStake\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferStarted\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PenaltyFeeRecipientUpdated\",\"inputs\":[{\"name\":\"newPenaltyFeeRecipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PreconfManagerUpdated\",\"inputs\":[{\"name\":\"newPreconfManager\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ProviderRegistered\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"stakedAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"blsPublicKey\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TransferToBidderFailed\",\"inputs\":[{\"name\":\"bidder\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unstake\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Withdraw\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalDelayUpdated\",\"inputs\":[{\"name\":\"newWithdrawalDelay\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"BidderAmountIsZero\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"BidderWithdrawalTransferFailed\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"DelayNotPassed\",\"inputs\":[{\"name\":\"withdrawalRequestTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"withdrawalDelay\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"currentBlockTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedInnerCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeRecipientIsZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientStake\",\"inputs\":[{\"name\":\"stake\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minStake\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"InvalidBLSPublicKeyLength\",\"inputs\":[{\"name\":\"length\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"expectedLength\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"InvalidFallback\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidReceive\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoStakeToWithdraw\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"NoUnstakeRequest\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotPreconfContract\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"preconfManager\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableInvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"PayoutPeriodMustBePositive\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"PendingWithdrawalRequest\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"PreconfManagerNotSet\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ProviderAlreadyRegistered\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ProviderCommitmentsPending\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"numPending\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ProviderNotRegistered\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ReentrancyGuardReentrantCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakeTransferFailed\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"TransferToRecipientFailed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"UnstakeRequestExists\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]}]", + ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"fallback\",\"stateMutability\":\"payable\"},{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"PERCENT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"PRECISION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"acceptOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"bidderSlashedAmount\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blockBuilderBLSKeyToAddress\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegateRegisterAndStake\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"blsPublicKeys\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"delegateStake\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"eoaToBlsPubkeys\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"feePercent\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAccumulatedPenaltyFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getBLSKeys\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getEoaFromBLSKey\",\"inputs\":[{\"name\":\"blsKey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getProviderStake\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_minStake\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_penaltyFeeRecipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_feePercent\",\"type\":\"uint16\",\"internalType\":\"uint16\"},{\"name\":\"_owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_withdrawalDelay\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_penaltyFeePayoutPeriodBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isProviderValid\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"manuallyWithdrawPenaltyFee\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"minStake\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"penaltyFeeTracker\",\"inputs\":[],\"outputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"accumulatedAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"lastPayoutBlock\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"payoutPeriodBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingOwner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"preconfManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"providerRegistered\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"providerStakes\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerAndStake\",\"inputs\":[{\"name\":\"blsPublicKeys\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setFeePayoutPeriodBlocks\",\"inputs\":[{\"name\":\"_feePayoutPeriodBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinStake\",\"inputs\":[{\"name\":\"_minStake\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setNewFeePercent\",\"inputs\":[{\"name\":\"newFeePercent\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setNewPenaltyFeeRecipient\",\"inputs\":[{\"name\":\"newFeeRecipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPreconfManager\",\"inputs\":[{\"name\":\"contractAddress\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setWithdrawalDelay\",\"inputs\":[{\"name\":\"_withdrawalDelay\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slash\",\"inputs\":[{\"name\":\"amt\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"provider\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"bidder\",\"type\":\"address\",\"internalType\":\"addresspayable\"},{\"name\":\"residualBidPercentAfterDecay\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unstake\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSlashedAmount\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawalDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawalRequests\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"BidderWithdrawSlashedAmount\",\"inputs\":[{\"name\":\"bidder\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FeePayoutPeriodBlocksUpdated\",\"inputs\":[{\"name\":\"newFeePayoutPeriodBlocks\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FeePercentUpdated\",\"inputs\":[{\"name\":\"newFeePercent\",\"type\":\"uint16\",\"indexed\":true,\"internalType\":\"uint16\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FeeTransfer\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FundsDeposited\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FundsSlashed\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InsufficientFundsToSlash\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"providerStake\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"residualAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"penaltyFee\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinStakeUpdated\",\"inputs\":[{\"name\":\"newMinStake\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferStarted\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PenaltyFeeRecipientUpdated\",\"inputs\":[{\"name\":\"newPenaltyFeeRecipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PreconfManagerUpdated\",\"inputs\":[{\"name\":\"newPreconfManager\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ProviderRegistered\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"stakedAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"blsPublicKeys\",\"type\":\"bytes[]\",\"indexed\":false,\"internalType\":\"bytes[]\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TransferToBidderFailed\",\"inputs\":[{\"name\":\"bidder\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unstake\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Withdraw\",\"inputs\":[{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalDelayUpdated\",\"inputs\":[{\"name\":\"newWithdrawalDelay\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"AtLeastOneBLSKeyRequired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BidderAmountIsZero\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"BidderWithdrawalTransferFailed\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"DelayNotPassed\",\"inputs\":[{\"name\":\"withdrawalRequestTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"withdrawalDelay\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"currentBlockTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedInnerCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FeeRecipientIsZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientStake\",\"inputs\":[{\"name\":\"stake\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minStake\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"InvalidBLSPublicKeyLength\",\"inputs\":[{\"name\":\"length\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"expectedLength\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"InvalidFallback\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidReceive\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoStakeToWithdraw\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"NoUnstakeRequest\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotPreconfContract\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"preconfManager\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableInvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"PayoutPeriodMustBePositive\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"PendingWithdrawalRequest\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"PreconfManagerNotSet\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ProviderAlreadyRegistered\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ProviderCommitmentsPending\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"numPending\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ProviderNotRegistered\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ReentrancyGuardReentrantCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakeTransferFailed\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"TransferToRecipientFailed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"UnstakeRequestExists\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]}]", } // ProviderregistryABI is the input ABI used to generate the binding from. @@ -304,12 +304,43 @@ func (_Providerregistry *ProviderregistryCallerSession) BidderSlashedAmount(arg0 return _Providerregistry.Contract.BidderSlashedAmount(&_Providerregistry.CallOpts, arg0) } -// EoaToBlsPubkey is a free data retrieval call binding the contract method 0x73b76962. +// BlockBuilderBLSKeyToAddress is a free data retrieval call binding the contract method 0x929b63c4. // -// Solidity: function eoaToBlsPubkey(address ) view returns(bytes) -func (_Providerregistry *ProviderregistryCaller) EoaToBlsPubkey(opts *bind.CallOpts, arg0 common.Address) ([]byte, error) { +// Solidity: function blockBuilderBLSKeyToAddress(bytes ) view returns(address) +func (_Providerregistry *ProviderregistryCaller) BlockBuilderBLSKeyToAddress(opts *bind.CallOpts, arg0 []byte) (common.Address, error) { var out []interface{} - err := _Providerregistry.contract.Call(opts, &out, "eoaToBlsPubkey", arg0) + err := _Providerregistry.contract.Call(opts, &out, "blockBuilderBLSKeyToAddress", arg0) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// BlockBuilderBLSKeyToAddress is a free data retrieval call binding the contract method 0x929b63c4. +// +// Solidity: function blockBuilderBLSKeyToAddress(bytes ) view returns(address) +func (_Providerregistry *ProviderregistrySession) BlockBuilderBLSKeyToAddress(arg0 []byte) (common.Address, error) { + return _Providerregistry.Contract.BlockBuilderBLSKeyToAddress(&_Providerregistry.CallOpts, arg0) +} + +// BlockBuilderBLSKeyToAddress is a free data retrieval call binding the contract method 0x929b63c4. +// +// Solidity: function blockBuilderBLSKeyToAddress(bytes ) view returns(address) +func (_Providerregistry *ProviderregistryCallerSession) BlockBuilderBLSKeyToAddress(arg0 []byte) (common.Address, error) { + return _Providerregistry.Contract.BlockBuilderBLSKeyToAddress(&_Providerregistry.CallOpts, arg0) +} + +// EoaToBlsPubkeys is a free data retrieval call binding the contract method 0x1129ce1f. +// +// Solidity: function eoaToBlsPubkeys(address , uint256 ) view returns(bytes) +func (_Providerregistry *ProviderregistryCaller) EoaToBlsPubkeys(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) ([]byte, error) { + var out []interface{} + err := _Providerregistry.contract.Call(opts, &out, "eoaToBlsPubkeys", arg0, arg1) if err != nil { return *new([]byte), err @@ -321,18 +352,18 @@ func (_Providerregistry *ProviderregistryCaller) EoaToBlsPubkey(opts *bind.CallO } -// EoaToBlsPubkey is a free data retrieval call binding the contract method 0x73b76962. +// EoaToBlsPubkeys is a free data retrieval call binding the contract method 0x1129ce1f. // -// Solidity: function eoaToBlsPubkey(address ) view returns(bytes) -func (_Providerregistry *ProviderregistrySession) EoaToBlsPubkey(arg0 common.Address) ([]byte, error) { - return _Providerregistry.Contract.EoaToBlsPubkey(&_Providerregistry.CallOpts, arg0) +// Solidity: function eoaToBlsPubkeys(address , uint256 ) view returns(bytes) +func (_Providerregistry *ProviderregistrySession) EoaToBlsPubkeys(arg0 common.Address, arg1 *big.Int) ([]byte, error) { + return _Providerregistry.Contract.EoaToBlsPubkeys(&_Providerregistry.CallOpts, arg0, arg1) } -// EoaToBlsPubkey is a free data retrieval call binding the contract method 0x73b76962. +// EoaToBlsPubkeys is a free data retrieval call binding the contract method 0x1129ce1f. // -// Solidity: function eoaToBlsPubkey(address ) view returns(bytes) -func (_Providerregistry *ProviderregistryCallerSession) EoaToBlsPubkey(arg0 common.Address) ([]byte, error) { - return _Providerregistry.Contract.EoaToBlsPubkey(&_Providerregistry.CallOpts, arg0) +// Solidity: function eoaToBlsPubkeys(address , uint256 ) view returns(bytes) +func (_Providerregistry *ProviderregistryCallerSession) EoaToBlsPubkeys(arg0 common.Address, arg1 *big.Int) ([]byte, error) { + return _Providerregistry.Contract.EoaToBlsPubkeys(&_Providerregistry.CallOpts, arg0, arg1) } // FeePercent is a free data retrieval call binding the contract method 0x7fd6f15c. @@ -397,35 +428,66 @@ func (_Providerregistry *ProviderregistryCallerSession) GetAccumulatedPenaltyFee return _Providerregistry.Contract.GetAccumulatedPenaltyFee(&_Providerregistry.CallOpts) } -// GetBLSKey is a free data retrieval call binding the contract method 0xb50c522e. +// GetBLSKeys is a free data retrieval call binding the contract method 0xc50b59df. // -// Solidity: function getBLSKey(address provider) view returns(bytes) -func (_Providerregistry *ProviderregistryCaller) GetBLSKey(opts *bind.CallOpts, provider common.Address) ([]byte, error) { +// Solidity: function getBLSKeys(address provider) view returns(bytes[]) +func (_Providerregistry *ProviderregistryCaller) GetBLSKeys(opts *bind.CallOpts, provider common.Address) ([][]byte, error) { var out []interface{} - err := _Providerregistry.contract.Call(opts, &out, "getBLSKey", provider) + err := _Providerregistry.contract.Call(opts, &out, "getBLSKeys", provider) if err != nil { - return *new([]byte), err + return *new([][]byte), err } - out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + out0 := *abi.ConvertType(out[0], new([][]byte)).(*[][]byte) return out0, err } -// GetBLSKey is a free data retrieval call binding the contract method 0xb50c522e. +// GetBLSKeys is a free data retrieval call binding the contract method 0xc50b59df. // -// Solidity: function getBLSKey(address provider) view returns(bytes) -func (_Providerregistry *ProviderregistrySession) GetBLSKey(provider common.Address) ([]byte, error) { - return _Providerregistry.Contract.GetBLSKey(&_Providerregistry.CallOpts, provider) +// Solidity: function getBLSKeys(address provider) view returns(bytes[]) +func (_Providerregistry *ProviderregistrySession) GetBLSKeys(provider common.Address) ([][]byte, error) { + return _Providerregistry.Contract.GetBLSKeys(&_Providerregistry.CallOpts, provider) } -// GetBLSKey is a free data retrieval call binding the contract method 0xb50c522e. +// GetBLSKeys is a free data retrieval call binding the contract method 0xc50b59df. // -// Solidity: function getBLSKey(address provider) view returns(bytes) -func (_Providerregistry *ProviderregistryCallerSession) GetBLSKey(provider common.Address) ([]byte, error) { - return _Providerregistry.Contract.GetBLSKey(&_Providerregistry.CallOpts, provider) +// Solidity: function getBLSKeys(address provider) view returns(bytes[]) +func (_Providerregistry *ProviderregistryCallerSession) GetBLSKeys(provider common.Address) ([][]byte, error) { + return _Providerregistry.Contract.GetBLSKeys(&_Providerregistry.CallOpts, provider) +} + +// GetEoaFromBLSKey is a free data retrieval call binding the contract method 0xea3b275d. +// +// Solidity: function getEoaFromBLSKey(bytes blsKey) view returns(address) +func (_Providerregistry *ProviderregistryCaller) GetEoaFromBLSKey(opts *bind.CallOpts, blsKey []byte) (common.Address, error) { + var out []interface{} + err := _Providerregistry.contract.Call(opts, &out, "getEoaFromBLSKey", blsKey) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetEoaFromBLSKey is a free data retrieval call binding the contract method 0xea3b275d. +// +// Solidity: function getEoaFromBLSKey(bytes blsKey) view returns(address) +func (_Providerregistry *ProviderregistrySession) GetEoaFromBLSKey(blsKey []byte) (common.Address, error) { + return _Providerregistry.Contract.GetEoaFromBLSKey(&_Providerregistry.CallOpts, blsKey) +} + +// GetEoaFromBLSKey is a free data retrieval call binding the contract method 0xea3b275d. +// +// Solidity: function getEoaFromBLSKey(bytes blsKey) view returns(address) +func (_Providerregistry *ProviderregistryCallerSession) GetEoaFromBLSKey(blsKey []byte) (common.Address, error) { + return _Providerregistry.Contract.GetEoaFromBLSKey(&_Providerregistry.CallOpts, blsKey) } // GetProviderStake is a free data retrieval call binding the contract method 0xbfebc370. @@ -874,25 +936,25 @@ func (_Providerregistry *ProviderregistryTransactorSession) AcceptOwnership() (* return _Providerregistry.Contract.AcceptOwnership(&_Providerregistry.TransactOpts) } -// DelegateRegisterAndStake is a paid mutator transaction binding the contract method 0x05191b89. +// DelegateRegisterAndStake is a paid mutator transaction binding the contract method 0xd9b735e7. // -// Solidity: function delegateRegisterAndStake(address provider, bytes blsPublicKey) payable returns() -func (_Providerregistry *ProviderregistryTransactor) DelegateRegisterAndStake(opts *bind.TransactOpts, provider common.Address, blsPublicKey []byte) (*types.Transaction, error) { - return _Providerregistry.contract.Transact(opts, "delegateRegisterAndStake", provider, blsPublicKey) +// Solidity: function delegateRegisterAndStake(address provider, bytes[] blsPublicKeys) payable returns() +func (_Providerregistry *ProviderregistryTransactor) DelegateRegisterAndStake(opts *bind.TransactOpts, provider common.Address, blsPublicKeys [][]byte) (*types.Transaction, error) { + return _Providerregistry.contract.Transact(opts, "delegateRegisterAndStake", provider, blsPublicKeys) } -// DelegateRegisterAndStake is a paid mutator transaction binding the contract method 0x05191b89. +// DelegateRegisterAndStake is a paid mutator transaction binding the contract method 0xd9b735e7. // -// Solidity: function delegateRegisterAndStake(address provider, bytes blsPublicKey) payable returns() -func (_Providerregistry *ProviderregistrySession) DelegateRegisterAndStake(provider common.Address, blsPublicKey []byte) (*types.Transaction, error) { - return _Providerregistry.Contract.DelegateRegisterAndStake(&_Providerregistry.TransactOpts, provider, blsPublicKey) +// Solidity: function delegateRegisterAndStake(address provider, bytes[] blsPublicKeys) payable returns() +func (_Providerregistry *ProviderregistrySession) DelegateRegisterAndStake(provider common.Address, blsPublicKeys [][]byte) (*types.Transaction, error) { + return _Providerregistry.Contract.DelegateRegisterAndStake(&_Providerregistry.TransactOpts, provider, blsPublicKeys) } -// DelegateRegisterAndStake is a paid mutator transaction binding the contract method 0x05191b89. +// DelegateRegisterAndStake is a paid mutator transaction binding the contract method 0xd9b735e7. // -// Solidity: function delegateRegisterAndStake(address provider, bytes blsPublicKey) payable returns() -func (_Providerregistry *ProviderregistryTransactorSession) DelegateRegisterAndStake(provider common.Address, blsPublicKey []byte) (*types.Transaction, error) { - return _Providerregistry.Contract.DelegateRegisterAndStake(&_Providerregistry.TransactOpts, provider, blsPublicKey) +// Solidity: function delegateRegisterAndStake(address provider, bytes[] blsPublicKeys) payable returns() +func (_Providerregistry *ProviderregistryTransactorSession) DelegateRegisterAndStake(provider common.Address, blsPublicKeys [][]byte) (*types.Transaction, error) { + return _Providerregistry.Contract.DelegateRegisterAndStake(&_Providerregistry.TransactOpts, provider, blsPublicKeys) } // DelegateStake is a paid mutator transaction binding the contract method 0xf094cc39. @@ -979,25 +1041,25 @@ func (_Providerregistry *ProviderregistryTransactorSession) Pause() (*types.Tran return _Providerregistry.Contract.Pause(&_Providerregistry.TransactOpts) } -// RegisterAndStake is a paid mutator transaction binding the contract method 0x8e3d03f6. +// RegisterAndStake is a paid mutator transaction binding the contract method 0x140f2e60. // -// Solidity: function registerAndStake(bytes blsPublicKey) payable returns() -func (_Providerregistry *ProviderregistryTransactor) RegisterAndStake(opts *bind.TransactOpts, blsPublicKey []byte) (*types.Transaction, error) { - return _Providerregistry.contract.Transact(opts, "registerAndStake", blsPublicKey) +// Solidity: function registerAndStake(bytes[] blsPublicKeys) payable returns() +func (_Providerregistry *ProviderregistryTransactor) RegisterAndStake(opts *bind.TransactOpts, blsPublicKeys [][]byte) (*types.Transaction, error) { + return _Providerregistry.contract.Transact(opts, "registerAndStake", blsPublicKeys) } -// RegisterAndStake is a paid mutator transaction binding the contract method 0x8e3d03f6. +// RegisterAndStake is a paid mutator transaction binding the contract method 0x140f2e60. // -// Solidity: function registerAndStake(bytes blsPublicKey) payable returns() -func (_Providerregistry *ProviderregistrySession) RegisterAndStake(blsPublicKey []byte) (*types.Transaction, error) { - return _Providerregistry.Contract.RegisterAndStake(&_Providerregistry.TransactOpts, blsPublicKey) +// Solidity: function registerAndStake(bytes[] blsPublicKeys) payable returns() +func (_Providerregistry *ProviderregistrySession) RegisterAndStake(blsPublicKeys [][]byte) (*types.Transaction, error) { + return _Providerregistry.Contract.RegisterAndStake(&_Providerregistry.TransactOpts, blsPublicKeys) } -// RegisterAndStake is a paid mutator transaction binding the contract method 0x8e3d03f6. +// RegisterAndStake is a paid mutator transaction binding the contract method 0x140f2e60. // -// Solidity: function registerAndStake(bytes blsPublicKey) payable returns() -func (_Providerregistry *ProviderregistryTransactorSession) RegisterAndStake(blsPublicKey []byte) (*types.Transaction, error) { - return _Providerregistry.Contract.RegisterAndStake(&_Providerregistry.TransactOpts, blsPublicKey) +// Solidity: function registerAndStake(bytes[] blsPublicKeys) payable returns() +func (_Providerregistry *ProviderregistryTransactorSession) RegisterAndStake(blsPublicKeys [][]byte) (*types.Transaction, error) { + return _Providerregistry.Contract.RegisterAndStake(&_Providerregistry.TransactOpts, blsPublicKeys) } // RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. @@ -3437,15 +3499,15 @@ func (it *ProviderregistryProviderRegisteredIterator) Close() error { // ProviderregistryProviderRegistered represents a ProviderRegistered event raised by the Providerregistry contract. type ProviderregistryProviderRegistered struct { - Provider common.Address - StakedAmount *big.Int - BlsPublicKey []byte - Raw types.Log // Blockchain specific contextual infos + Provider common.Address + StakedAmount *big.Int + BlsPublicKeys [][]byte + Raw types.Log // Blockchain specific contextual infos } -// FilterProviderRegistered is a free log retrieval operation binding the contract event 0x79fda11c69e0429d87cf53e6967d16c56a3d80a7e6e67dd03ccf7f20d6285fc0. +// FilterProviderRegistered is a free log retrieval operation binding the contract event 0x43b9a402bb7e7ede3b3d372b9a0be4a09659bc821f4662eb999faa8756553042. // -// Solidity: event ProviderRegistered(address indexed provider, uint256 stakedAmount, bytes blsPublicKey) +// Solidity: event ProviderRegistered(address indexed provider, uint256 stakedAmount, bytes[] blsPublicKeys) func (_Providerregistry *ProviderregistryFilterer) FilterProviderRegistered(opts *bind.FilterOpts, provider []common.Address) (*ProviderregistryProviderRegisteredIterator, error) { var providerRule []interface{} @@ -3460,9 +3522,9 @@ func (_Providerregistry *ProviderregistryFilterer) FilterProviderRegistered(opts return &ProviderregistryProviderRegisteredIterator{contract: _Providerregistry.contract, event: "ProviderRegistered", logs: logs, sub: sub}, nil } -// WatchProviderRegistered is a free log subscription operation binding the contract event 0x79fda11c69e0429d87cf53e6967d16c56a3d80a7e6e67dd03ccf7f20d6285fc0. +// WatchProviderRegistered is a free log subscription operation binding the contract event 0x43b9a402bb7e7ede3b3d372b9a0be4a09659bc821f4662eb999faa8756553042. // -// Solidity: event ProviderRegistered(address indexed provider, uint256 stakedAmount, bytes blsPublicKey) +// Solidity: event ProviderRegistered(address indexed provider, uint256 stakedAmount, bytes[] blsPublicKeys) func (_Providerregistry *ProviderregistryFilterer) WatchProviderRegistered(opts *bind.WatchOpts, sink chan<- *ProviderregistryProviderRegistered, provider []common.Address) (event.Subscription, error) { var providerRule []interface{} @@ -3502,9 +3564,9 @@ func (_Providerregistry *ProviderregistryFilterer) WatchProviderRegistered(opts }), nil } -// ParseProviderRegistered is a log parse operation binding the contract event 0x79fda11c69e0429d87cf53e6967d16c56a3d80a7e6e67dd03ccf7f20d6285fc0. +// ParseProviderRegistered is a log parse operation binding the contract event 0x43b9a402bb7e7ede3b3d372b9a0be4a09659bc821f4662eb999faa8756553042. // -// Solidity: event ProviderRegistered(address indexed provider, uint256 stakedAmount, bytes blsPublicKey) +// Solidity: event ProviderRegistered(address indexed provider, uint256 stakedAmount, bytes[] blsPublicKeys) func (_Providerregistry *ProviderregistryFilterer) ParseProviderRegistered(log types.Log) (*ProviderregistryProviderRegistered, error) { event := new(ProviderregistryProviderRegistered) if err := _Providerregistry.contract.UnpackLog(event, "ProviderRegistered", log); err != nil { diff --git a/contracts/contracts/core/BlockTracker.sol b/contracts/contracts/core/BlockTracker.sol index d5abdae5c..decdee384 100644 --- a/contracts/contracts/core/BlockTracker.sol +++ b/contracts/contracts/core/BlockTracker.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.26; import {IBlockTracker} from "../interfaces/IBlockTracker.sol"; import {BlockTrackerStorage} from "./BlockTrackerStorage.sol"; +import {IProviderRegistry} from "../interfaces/IProviderRegistry.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; @@ -65,20 +66,20 @@ contract BlockTracker is IBlockTracker, BlockTrackerStorage, string calldata builderName, address builderAddress ) external onlyOracle whenNotPaused { - blockBuilderNameToAddress[builderName] = builderAddress; emit BuilderAddressAdded(builderName, builderAddress); + blockBuilderNameToAddress[builderName] = builderAddress; } /** * @dev Records a new L1 block and its winner. * @param _blockNumber The number of the new L1 block. - * @param _winnerGraffiti The graffiti of the winner of the new L1 block. + * @param _winnerBLSKey The BLS key of the winner of the new L1 block. */ function recordL1Block( uint256 _blockNumber, - string calldata _winnerGraffiti + bytes calldata _winnerBLSKey ) external onlyOracle whenNotPaused { - address _winner = blockBuilderNameToAddress[_winnerGraffiti]; + address _winner = providerRegistry.getEoaFromBLSKey(_winnerBLSKey); _recordBlockWinner(_blockNumber, _winner); uint256 newWindow = (_blockNumber - 1) / WindowFromBlockNumber.BLOCKS_PER_WINDOW + 1; if (newWindow > currentWindow) { @@ -89,6 +90,12 @@ contract BlockTracker is IBlockTracker, BlockTrackerStorage, emit NewL1Block(_blockNumber, _winner, currentWindow); } + /// @dev Allows the owner to set the provider registry. + function setProviderRegistry(address newProviderRegistry) external onlyOwner { + emit ProviderRegistrySet(address(providerRegistry), newProviderRegistry); + providerRegistry = IProviderRegistry(newProviderRegistry); + } + /// @dev Allows the owner to set the oracle account. function setOracleAccount(address newOracleAccount) external onlyOwner { _setOracleAccount(newOracleAccount); diff --git a/contracts/contracts/core/BlockTrackerStorage.sol b/contracts/contracts/core/BlockTrackerStorage.sol index 864535054..ccd5286ea 100644 --- a/contracts/contracts/core/BlockTrackerStorage.sol +++ b/contracts/contracts/core/BlockTrackerStorage.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: BSL 1.1 pragma solidity 0.8.26; +import {IProviderRegistry} from "../interfaces/IProviderRegistry.sol"; + abstract contract BlockTrackerStorage { /// @dev Permissioned address of the oracle account. address public oracleAccount; @@ -13,6 +15,9 @@ abstract contract BlockTrackerStorage { /// @dev Maps builder names to their respective Ethereum addresses. mapping(string => address) public blockBuilderNameToAddress; + /// @dev Interface for the ProviderRegistry contract + IProviderRegistry public providerRegistry; + /// @dev See https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#storage-gaps uint256[48] private __gap; } diff --git a/contracts/contracts/core/ProviderRegistry.sol b/contracts/contracts/core/ProviderRegistry.sol index d94a331b7..105193d3f 100644 --- a/contracts/contracts/core/ProviderRegistry.sol +++ b/contracts/contracts/core/ProviderRegistry.sol @@ -255,9 +255,14 @@ contract ProviderRegistry is return providerStakes[provider]; } - /// @dev Returns the BLS public key corresponding to a provider's staked EOA address. - function getBLSKey(address provider) external view returns (bytes memory) { - return eoaToBlsPubkey[provider]; + /// @dev Returns the BLS public keys corresponding to a provider's staked EOA address. + function getBLSKeys(address provider) external view returns (bytes[] memory) { + return eoaToBlsPubkeys[provider]; + } + + /// @dev Returns the EOA address corresponding to a provider's BLS public key. + function getEoaFromBLSKey(bytes calldata blsKey) external view returns (address) { + return blockBuilderBLSKeyToAddress[blsKey]; } /// @return penaltyFee amount not yet transferred to recipient @@ -267,20 +272,20 @@ contract ProviderRegistry is /** * @dev Register and stake function for providers. - * @param blsPublicKey The BLS public key of the provider. + * @param blsPublicKeys The BLS public keys of the provider. * The validity of this key must be verified manually off-chain. */ - function registerAndStake(bytes calldata blsPublicKey) public payable whenNotPaused { - _registerAndStake(msg.sender, blsPublicKey); + function registerAndStake(bytes[] calldata blsPublicKeys) public payable whenNotPaused { + _registerAndStake(msg.sender, blsPublicKeys); } /** * @dev Register and stake on behalf of a provider. * @param provider Address of the provider. - * @param blsPublicKey BLS public key of the provider. + * @param blsPublicKeys BLS public keys of the provider. */ - function delegateRegisterAndStake(address provider, bytes calldata blsPublicKey) public payable whenNotPaused onlyOwner { - _registerAndStake(provider, blsPublicKey); + function delegateRegisterAndStake(address provider, bytes[] calldata blsPublicKeys) public payable whenNotPaused onlyOwner { + _registerAndStake(provider, blsPublicKeys); } /// @dev Ensure the provider's balance is greater than minStake and no pending withdrawal @@ -297,15 +302,20 @@ contract ProviderRegistry is emit FundsDeposited(provider, msg.value); } - function _registerAndStake(address provider, bytes calldata blsPublicKey) internal { + function _registerAndStake(address provider, bytes[] calldata blsPublicKeys) internal { require(!providerRegistered[provider], ProviderAlreadyRegistered(provider)); require(msg.value >= minStake, InsufficientStake(msg.value, minStake)); - require(blsPublicKey.length == 48, InvalidBLSPublicKeyLength(blsPublicKey.length, 48)); - - eoaToBlsPubkey[provider] = blsPublicKey; + require(blsPublicKeys.length != 0, AtLeastOneBLSKeyRequired()); + uint256 numKeys = blsPublicKeys.length; + for (uint256 i = 0; i < numKeys; ++i) { + bytes memory key = blsPublicKeys[i]; + require(key.length == 48, InvalidBLSPublicKeyLength(key.length, 48)); + blockBuilderBLSKeyToAddress[key] = provider; + } + eoaToBlsPubkeys[provider] = blsPublicKeys; providerStakes[provider] = msg.value; providerRegistered[provider] = true; - emit ProviderRegistered(provider, msg.value, blsPublicKey); + emit ProviderRegistered(provider, msg.value, blsPublicKeys); } // solhint-disable-next-line no-empty-blocks diff --git a/contracts/contracts/core/ProviderRegistryStorage.sol b/contracts/contracts/core/ProviderRegistryStorage.sol index 67642fe08..a81709dc8 100644 --- a/contracts/contracts/core/ProviderRegistryStorage.sol +++ b/contracts/contracts/core/ProviderRegistryStorage.sol @@ -28,9 +28,6 @@ abstract contract ProviderRegistryStorage { /// @dev Mapping from provider address to whether they are registered or not mapping(address => bool) public providerRegistered; - /// @dev Mapping from a provider's EOA address to their BLS public key - mapping(address => bytes) public eoaToBlsPubkey; - /// @dev Mapping from provider addresses to their staked amount mapping(address => uint256) public providerStakes; @@ -39,7 +36,13 @@ abstract contract ProviderRegistryStorage { /// @dev Mapping from bidder to provider slashed amount mapping(address => uint256) public bidderSlashedAmount; - + + /// @dev Maps BLS public key to their corresponding block builder address + mapping(bytes => address) public blockBuilderBLSKeyToAddress; + + /// @dev Mapping from a provider's EOA address to their BLS public keys + mapping(address => bytes[]) public eoaToBlsPubkeys; + /// @dev See https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#storage-gaps uint256[48] private __gap; } diff --git a/contracts/contracts/interfaces/IBlockTracker.sol b/contracts/contracts/interfaces/IBlockTracker.sol index 3d166cb34..d03457075 100644 --- a/contracts/contracts/interfaces/IBlockTracker.sol +++ b/contracts/contracts/interfaces/IBlockTracker.sol @@ -17,17 +17,25 @@ interface IBlockTracker { /// @dev Event emitted when the oracle account is set. event OracleAccountSet(address indexed oldOracleAccount, address indexed newOracleAccount); - + + /// @dev Event emitted when the provider registry is updated. + event ProviderRegistrySet(address indexed oldProviderRegistry, address indexed newProviderRegistry); + /// @dev Event emitted when a builder's address is added. event BuilderAddressAdded(string indexed builderName, address indexed builderAddress); error NotOracleAccount(address sender, address oracleAccount); - error BlockNumberIsZero(); + error BlockNumberIsZero(); + /// @notice Records a new L1 block with its winner. /// @param _blockNumber The block number of the new L1 block. - /// @param _winnerGrafitti The graffiti of the winner of the new L1 block. - function recordL1Block(uint256 _blockNumber, string calldata _winnerGrafitti) external; + /// @param _winnerBLSKey The BLS public key of the winner of the new L1 block. + function recordL1Block(uint256 _blockNumber, bytes calldata _winnerBLSKey) external; + + /// @notice Sets the provider registry. + /// @param newProviderRegistry The address of the new provider registry. + function setProviderRegistry(address newProviderRegistry) external; /// @notice Retrieves the builder's address corresponding to the given name. /// @param builderNameGrafiti The name of the block builder. diff --git a/contracts/contracts/interfaces/IProviderRegistry.sol b/contracts/contracts/interfaces/IProviderRegistry.sol index 0570375b0..8381ee49d 100644 --- a/contracts/contracts/interfaces/IProviderRegistry.sol +++ b/contracts/contracts/interfaces/IProviderRegistry.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.26; interface IProviderRegistry { /// @dev Event emitted when a provider is registered - event ProviderRegistered(address indexed provider, uint256 stakedAmount, bytes blsPublicKey); + event ProviderRegistered(address indexed provider, uint256 stakedAmount, bytes[] blsPublicKeys); /// @dev Event emitted when funds are deposited event FundsDeposited(address indexed provider, uint256 amount); @@ -63,11 +63,12 @@ interface IProviderRegistry { error InsufficientStake(uint256 stake, uint256 minStake); error InvalidBLSPublicKeyLength(uint256 length, uint256 expectedLength); error ProviderNotRegistered(address sender); + error AtLeastOneBLSKeyRequired(); error PendingWithdrawalRequest(address sender); error BidderAmountIsZero(address sender); error BidderWithdrawalTransferFailed(address sender, uint256 amount); - function registerAndStake(bytes calldata blsPublicKey) external payable; + function registerAndStake(bytes[] calldata blsPublicKeys) external payable; function stake() external payable; @@ -79,4 +80,6 @@ interface IProviderRegistry { ) external; function isProviderValid(address committerAddress) external view; + + function getEoaFromBLSKey(bytes calldata blsKey) external view returns (address); } diff --git a/contracts/scripts/core/DeployCore.s.sol b/contracts/scripts/core/DeployCore.s.sol index 1e2d2ec5a..ac2036386 100644 --- a/contracts/scripts/core/DeployCore.s.sol +++ b/contracts/scripts/core/DeployCore.s.sol @@ -32,8 +32,8 @@ contract DeployTestnet is Script { uint16 feePercent = 2; uint16 providerPenaltyPercent = 5; uint64 commitmentDispatchWindow = 2000; - uint256 withdrawalDelay = 24 * 3600 * 1000; // 24 hours in milliseconds - uint256 protocolFeePayoutPeriodBlocks = 5 * 3600; // 1 hour with 200ms blocks + uint256 withdrawalDelay = 24 hours * 1000; // 24 hours in milliseconds + uint256 protocolFeePayoutPeriodBlocks = 5 hours ; // 1 hour with 200ms blocks address oracleKeystoreAddress = vm.envAddress("ORACLE_KEYSTORE_ADDRESS"); require(oracleKeystoreAddress != address(0), "missing Oracle keystore address"); @@ -106,6 +106,8 @@ contract DeployTestnet is Script { (bool success, ) = payable(oracleKeystoreAddress).call{value: ORACLE_INITIAL_FUNDING}(""); require(success, FailedToSendETHToOracle(oracleKeystoreAddress)); + + blockTracker.setProviderRegistry(address(providerRegistry)); vm.stopBroadcast(); } diff --git a/contracts/test/core/BidderRegistryTest.sol b/contracts/test/core/BidderRegistryTest.sol index 488553f46..60d157781 100644 --- a/contracts/test/core/BidderRegistryTest.sol +++ b/contracts/test/core/BidderRegistryTest.sol @@ -7,6 +7,7 @@ import {BlockTracker} from "../../contracts/core/BlockTracker.sol"; import {IBidderRegistry} from "../../contracts/interfaces/IBidderRegistry.sol"; import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol"; import {WindowFromBlockNumber} from "../../contracts/utils/WindowFromBlockNumber.sol"; +import {ProviderRegistry} from "../../contracts/core/ProviderRegistry.sol"; contract BidderRegistryTest is Test { uint256 public testNumber; @@ -17,6 +18,7 @@ contract BidderRegistryTest is Test { address public feeRecipient; uint256 public feePayoutPeriodBlocks; BlockTracker public blockTracker; + ProviderRegistry public providerRegistry; /// @dev Event emitted when a bidder is registered with their staked amount event BidderRegistered(address indexed bidder, uint256 indexed stakedAmount, uint256 indexed windowNumber); @@ -43,6 +45,18 @@ contract BidderRegistryTest is Test { ); bidderRegistry = BidderRegistry(payable(bidderRegistryProxy)); + address providerRegistryProxy = Upgrades.deployUUPSProxy( + "ProviderRegistry.sol", + abi.encodeCall( + ProviderRegistry.initialize, + (minStake, feeRecipient, feePercent, address(this), 24 hours , 5 hours ) + ) + ); + providerRegistry = ProviderRegistry(payable(providerRegistryProxy)); + + vm.startPrank(address(this)); + blockTracker.setProviderRegistry(address(providerRegistry)); + vm.stopPrank(); bidder = vm.addr(1); vm.deal(bidder, 1000 ether); vm.deal(address(this), 1000 ether); diff --git a/contracts/test/core/OracleTest.sol b/contracts/test/core/OracleTest.sol index e954e5d9b..b3d7c5bd3 100644 --- a/contracts/test/core/OracleTest.sol +++ b/contracts/test/core/OracleTest.sol @@ -28,7 +28,8 @@ contract OracleTest is Test { uint64 public dispatchTimestampTesting; bytes public sharedSecretKey; bytes public constant validBLSPubkey = hex"80000cddeec66a800e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d44497ba8b756e1e82b"; - uint256 public constant withdrawalDelay = 24 * 3600; // 24 hours + bytes[] public validBLSPubkeys = [validBLSPubkey]; + uint256 public constant withdrawalDelay = 24 hours ; // 24 hours uint256 public constant protocolFeePayoutPeriodBlocks = 100; struct TestCommitment { uint64 bid; @@ -95,6 +96,9 @@ contract OracleTest is Test { ); blockTracker = BlockTracker(payable(blockTrackerProxy)); + vm.startPrank(ownerInstance); + blockTracker.setProviderRegistry(address(providerRegistry)); + vm.stopPrank(); address proxy3 = Upgrades.deployUUPSProxy( "BidderRegistry.sol", abi.encodeCall( @@ -174,7 +178,7 @@ contract OracleTest is Test { vm.deal(provider, 200000 ether); vm.startPrank(provider); - providerRegistry.registerAndStake{value: 250 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 250 ether}(validBLSPubkeys); vm.stopPrank(); bytes32 index = constructAndStoreCommitment( @@ -222,7 +226,7 @@ contract OracleTest is Test { vm.deal(provider, 200000 ether); vm.startPrank(provider); - providerRegistry.registerAndStake{value: 250 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 250 ether}(validBLSPubkeys); vm.stopPrank(); bytes32 index = constructAndStoreCommitment( @@ -276,7 +280,7 @@ contract OracleTest is Test { vm.deal(provider, 200000 ether); vm.startPrank(provider); - providerRegistry.registerAndStake{value: 250 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 250 ether}(validBLSPubkeys); vm.stopPrank(); bytes32 index1 = constructAndStoreCommitment( @@ -353,7 +357,7 @@ contract OracleTest is Test { vm.deal(provider, 200000 ether); vm.startPrank(provider); - providerRegistry.registerAndStake{value: 250 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 250 ether}(validBLSPubkeys); vm.stopPrank(); bytes32 index1 = constructAndStoreCommitment( @@ -468,7 +472,7 @@ contract OracleTest is Test { vm.deal(provider, 200000 ether); vm.startPrank(provider); - providerRegistry.registerAndStake{value: 250 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 250 ether}(validBLSPubkeys); vm.stopPrank(); bytes32[] memory commitments = new bytes32[](4); @@ -495,7 +499,7 @@ contract OracleTest is Test { vm.startPrank(0x6d503Fd50142C7C469C7c6B64794B55bfa6883f3); blockTracker.addBuilderAddress("test", provider); - blockTracker.recordL1Block(blockNumber, "test"); + blockTracker.recordL1Block(blockNumber, validBLSPubkey); vm.stopPrank(); for (uint256 i = 0; i < commitments.length; ++i) { @@ -564,7 +568,7 @@ contract OracleTest is Test { commitmentSignature, dispatchTimestamp ); - recordBlockData(provider, blockNumber); + recordBlockData(validBLSPubkey, blockNumber); commitmentIndex = openCommitment( provider, @@ -650,10 +654,10 @@ contract OracleTest is Test { return unopenedCommitmentIndex; } - function recordBlockData(address provider, uint64 blockNumber) public { + function recordBlockData(bytes memory blsPubKey, uint64 blockNumber) public { vm.startPrank(0x6d503Fd50142C7C469C7c6B64794B55bfa6883f3); - blockTracker.addBuilderAddress("test", provider); - blockTracker.recordL1Block(blockNumber, "test"); + + blockTracker.recordL1Block(blockNumber, blsPubKey); vm.stopPrank(); } @@ -749,4 +753,4 @@ contract OracleTest is Test { } return string(_string); } -} +} \ No newline at end of file diff --git a/contracts/test/core/PreconfManagerTest.sol b/contracts/test/core/PreconfManagerTest.sol index d479083ff..427981540 100644 --- a/contracts/test/core/PreconfManagerTest.sol +++ b/contracts/test/core/PreconfManagerTest.sol @@ -38,6 +38,10 @@ contract PreconfManagerTest is Test { BidderRegistry public bidderRegistry; bytes public validBLSPubkey = hex"80000cddeec66a800e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d44497ba8b756e1e82b"; + bytes[] public validBLSPubkeys = [validBLSPubkey]; + bytes public validBLSPubkey2 = hex"90000cddeec66a800e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d44497ba8b756e1e82c"; + bytes public validBLSPubkey3 = hex"a0000cddeec66a800e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d44497ba8b756e1e82d"; + bytes[] public validMultiBLSPubkeys = [validBLSPubkey, validBLSPubkey2, validBLSPubkey3]; uint256 public withdrawalDelay; uint256 public protocolFeePayoutPeriodBlocks; address public oracleContract; @@ -60,7 +64,7 @@ contract PreconfManagerTest is Test { feePercent = 10; minStake = 1e18 wei; feeRecipient = vm.addr(9); - withdrawalDelay = 24 * 3600; // 24 hours + withdrawalDelay = 24 hours ; // 24 hours protocolFeePayoutPeriodBlocks = 100; oracleContract = address(0x6793); address providerRegistryProxy = Upgrades.deployUUPSProxy( @@ -87,7 +91,8 @@ contract PreconfManagerTest is Test { ) ); blockTracker = BlockTracker(payable(blockTrackerProxy)); - +vm.prank(address(this)); + blockTracker.setProviderRegistry(address(providerRegistry)); address bidderRegistryProxy = Upgrades.deployUUPSProxy( "BidderRegistry.sol", abi.encodeCall( @@ -203,7 +208,7 @@ contract PreconfManagerTest is Test { // Optional: Ensure the committer has enough ETH if needed for the operation vm.deal(committer, 1 ether); vm.prank(committer); - providerRegistry.registerAndStake{value: 1 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 1 ether}(validBLSPubkeys); // Step 2: Store the commitment vm.prank(committer); @@ -394,8 +399,7 @@ contract PreconfManagerTest is Test { ); // Step 3: Move to the next window - blockTracker.addBuilderAddress("test", committer); - blockTracker.recordL1Block(2, "test"); + blockTracker.recordL1Block(2, validBLSPubkey2); // Step 4: Open the commitment bytes32 index = openCommitment( @@ -502,7 +506,7 @@ contract PreconfManagerTest is Test { ); vm.deal(committer, 11 ether); vm.startPrank(committer); - providerRegistry.registerAndStake{value: 10 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 10 ether}(validMultiBLSPubkeys); bytes32 commitmentIndex = preconfManager.storeUnopenedCommitment( commitmentDigest, @@ -622,7 +626,7 @@ contract PreconfManagerTest is Test { ); // Step 2: Store the commitment (address committer, ) = makeAddrAndKey("bob"); - providerRegistry.registerAndStake{value: 10 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 10 ether}(validBLSPubkeys); bytes32 commitmentIndex = storeCommitment( committer, _testCommitmentAliceBob.bidAmt, @@ -707,8 +711,7 @@ contract PreconfManagerTest is Test { ); providerRegistry.setPreconfManager(address(preconfManager)); uint256 blockNumber = 2; - blockTracker.addBuilderAddress("test", committer); - blockTracker.recordL1Block(blockNumber, "test"); + blockTracker.recordL1Block(blockNumber, validBLSPubkey); bytes32 index = openCommitment( committer, unopenedIndex, @@ -795,10 +798,9 @@ contract PreconfManagerTest is Test { _testCommitmentAliceBob.dispatchTimestamp, _testCommitmentAliceBob.sharedSecretKey ); - blockTracker.addBuilderAddress("test", committer); blockTracker.recordL1Block( _testCommitmentAliceBob.blockNumber, - "test" + validBLSPubkey ); bytes32 index = openCommitment( committer, @@ -880,10 +882,9 @@ contract PreconfManagerTest is Test { _testCommitmentAliceBob.dispatchTimestamp, _testCommitmentAliceBob.sharedSecretKey ); - blockTracker.addBuilderAddress("test", committer); blockTracker.recordL1Block( _testCommitmentAliceBob.blockNumber, - "test" + validBLSPubkey ); bytes32 index = openCommitment( committer, @@ -959,7 +960,7 @@ contract PreconfManagerTest is Test { // Ensure the committer has enough ETH for the required stake vm.deal(committer, 2 ether); vm.prank(committer); - providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkeys); // Request a withdrawal to create a pending withdrawal request vm.prank(committer); @@ -998,8 +999,8 @@ contract PreconfManagerTest is Test { committer, testCommitment ); - blockTracker.addBuilderAddress("test", committer); - blockTracker.recordL1Block(testCommitment.blockNumber, "test"); + + blockTracker.recordL1Block(testCommitment.blockNumber, validBLSPubkey); openFirstCommitment(bidder, unopenedIndex1, testCommitment); @@ -1024,8 +1025,7 @@ contract PreconfManagerTest is Test { testCommitment2 ); - blockTracker.addBuilderAddress("test2", committer); - blockTracker.recordL1Block(testCommitment2.blockNumber, "test2"); + blockTracker.recordL1Block(testCommitment2.blockNumber, validBLSPubkey); // Attempt to open the second commitment with the same txnHash vm.prank(bidder); @@ -1061,15 +1061,6 @@ contract PreconfManagerTest is Test { return depositWindow; } - function registerProvider( - address committer, - bytes memory blsPubkey - ) internal { - vm.startPrank(committer); - providerRegistry.registerAndStake{value: 10 ether}(blsPubkey); - vm.stopPrank(); - } - function storeFirstCommitment( address committer, TestCommitment memory testCommitment @@ -1180,4 +1171,4 @@ contract PreconfManagerTest is Test { (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, hash); return abi.encodePacked(r, s, v); } -} +} \ No newline at end of file diff --git a/contracts/test/core/ProviderRegistryTest.sol b/contracts/test/core/ProviderRegistryTest.sol index 684378a87..d9de710e6 100644 --- a/contracts/test/core/ProviderRegistryTest.sol +++ b/contracts/test/core/ProviderRegistryTest.sol @@ -21,8 +21,9 @@ contract ProviderRegistryTest is Test { BlockTracker public blockTracker; uint256 public withdrawalDelay; bytes public validBLSPubkey = hex"80000cddeec66a800e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d44497ba8b756e1e82b"; + bytes[] public validBLSPubkeys = [validBLSPubkey]; uint256 public penaltyFeePayoutPeriodBlocks; - event ProviderRegistered(address indexed provider, uint256 stakedAmount, bytes blsPublicKey); + event ProviderRegistered(address indexed provider, uint256 stakedAmount, bytes []blsPublicKeys); event WithdrawalRequested(address indexed provider, uint256 timestamp); event WithdrawalCompleted(address indexed provider, uint256 amount); event FeeTransfer(uint256 amount, address indexed recipient); @@ -40,7 +41,7 @@ contract ProviderRegistryTest is Test { feePercent = 10; minStake = 1e18 wei; feeRecipient = vm.addr(9); - withdrawalDelay = 24 * 3600; // 24 hours + withdrawalDelay = 24 hours ; // 24 hours penaltyFeePayoutPeriodBlocks = 100; address providerRegistryProxy = Upgrades.deployUUPSProxy( "ProviderRegistry.sol", @@ -108,15 +109,16 @@ contract ProviderRegistryTest is Test { vm.deal(provider, 3 ether); vm.prank(provider); vm.expectRevert(bytes("")); - providerRegistry.registerAndStake{value: 1 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 1 wei}(validBLSPubkeys); } function testFail_ProviderStakeAndRegisterInvalidBLSKey() public { vm.deal(provider, 3 ether); vm.prank(provider); vm.expectRevert("Invalid BLS public key length"); - bytes memory blsPublicKey = abi.encodePacked(uint256(134)); - providerRegistry.registerAndStake{value: 1 wei}(blsPublicKey); + bytes[] memory invalidBLSPubkeys = new bytes[](1); + invalidBLSPubkeys[0] = abi.encodePacked(uint256(134)); + providerRegistry.registerAndStake{value: 1 wei}(invalidBLSPubkeys); } function test_ProviderStakeAndRegister() public { @@ -124,9 +126,9 @@ contract ProviderRegistryTest is Test { vm.prank(provider); vm.expectEmit(true, false, false, true); - emit ProviderRegistered(provider, 1e18 wei, validBLSPubkey); + emit ProviderRegistered(provider, 1e18 wei, validBLSPubkeys); - providerRegistry.registerAndStake{value: 1e18 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 1e18 wei}(validBLSPubkeys); bool isProviderRegistered = providerRegistry.providerRegistered( provider @@ -135,14 +137,24 @@ contract ProviderRegistryTest is Test { uint256 providerStakeStored = providerRegistry.getProviderStake(provider); assertEq(providerStakeStored, 1e18 wei); + + // Check if BLS keys were correctly registered + bytes[] memory storedBLSKeys = providerRegistry.getBLSKeys(provider); + assertEq(storedBLSKeys.length, validBLSPubkeys.length, "BLS keys array length mismatch"); + + for (uint256 i = 0; i < validBLSPubkeys.length; i++) { + assertEq(storedBLSKeys[i], validBLSPubkeys[i], "BLS key mismatch"); + address storedProvider = providerRegistry.getEoaFromBLSKey(validBLSPubkeys[i]); + assertEq(storedProvider, provider, "Provider address mismatch for BLS key"); + } } function testFail_ProviderStakeAndRegisterAlreadyRegistered() public { vm.deal(provider, 3 ether); vm.prank(provider); - providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkeys); vm.expectRevert(bytes("")); - providerRegistry.registerAndStake{value: 1 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 1 wei}(validBLSPubkeys); } function testFail_Receive() public { @@ -224,7 +236,7 @@ contract ProviderRegistryTest is Test { providerRegistry.setPreconfManager(address(this)); vm.deal(provider, 3 ether); vm.prank(provider); - providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkeys); address bidder = vm.addr(4); vm.expectCall(bidder, 1000000000000000000 wei, new bytes(0)); @@ -242,7 +254,7 @@ contract ProviderRegistryTest is Test { vm.deal(provider, 3 ether); vm.prank(provider); - providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkeys); address bidder = vm.addr(4); vm.expectCall(bidder, 1000000000000000000 wei, new bytes(0)); @@ -255,7 +267,7 @@ contract ProviderRegistryTest is Test { function testFail_ShouldRetrieveFundsNotPreConf() public { vm.deal(provider, 3 ether); vm.prank(provider); - providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkeys); address bidder = vm.addr(4); vm.expectRevert(bytes("")); providerRegistry.slash(1 ether, provider, payable(bidder),100); @@ -266,7 +278,7 @@ contract ProviderRegistryTest is Test { vm.deal(provider, 3 ether); vm.prank(provider); - providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkeys); address bidder = vm.addr(4); vm.prank(address(this)); @@ -284,7 +296,7 @@ contract ProviderRegistryTest is Test { vm.deal(provider, 3 ether); vm.prank(provider); - providerRegistry.registerAndStake{value: 3 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 3 ether}(validBLSPubkeys); address bidder = vm.addr(4); vm.prank(address(this)); @@ -302,7 +314,7 @@ contract ProviderRegistryTest is Test { vm.deal(provider, 3.1 ether); vm.prank(provider); - providerRegistry.registerAndStake{value: 3.1 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 3.1 ether}(validBLSPubkeys); address bidder = vm.addr(4); vm.prank(address(this)); @@ -320,7 +332,7 @@ contract ProviderRegistryTest is Test { address bidder = vm.addr(4); - providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkeys); providerRegistry.setPreconfManager(address(this)); providerRegistry.slash(1e18 wei, provider, payable(bidder), 50); assertEq( @@ -332,7 +344,7 @@ contract ProviderRegistryTest is Test { address newProvider = vm.addr(11); vm.deal(newProvider, 3 ether); vm.prank(newProvider); - providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkeys); vm.roll(350); // roll past protocol fee payout period @@ -358,7 +370,7 @@ contract ProviderRegistryTest is Test { address bidder = vm.addr(9); vm.deal(newProvider, 3 ether); vm.prank(newProvider); - providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkeys); providerRegistry.setPreconfManager( address(preconfManager) ); @@ -385,7 +397,7 @@ contract ProviderRegistryTest is Test { address newProvider = vm.addr(8); vm.deal(newProvider, 3 ether); vm.prank(newProvider); - providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkeys); vm.expectRevert(bytes("")); address wrongNewProvider = vm.addr(12); vm.prank(wrongNewProvider); @@ -396,7 +408,7 @@ contract ProviderRegistryTest is Test { address newProvider = vm.addr(5); vm.deal(newProvider, 3 ether); vm.prank(newProvider); - providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkeys); assertEq( providerRegistry.providerStakes(newProvider), 2e18 wei, @@ -413,7 +425,7 @@ contract ProviderRegistryTest is Test { address newProvider = vm.addr(8); vm.deal(newProvider, 3 ether); vm.prank(newProvider); - providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkeys); providerRegistry.unstake(); vm.warp(block.timestamp + 24 hours); // Move forward in time vm.expectRevert("Provider Commitments still pending"); @@ -424,7 +436,7 @@ contract ProviderRegistryTest is Test { address newProvider = vm.addr(8); vm.deal(newProvider, 3 ether); vm.prank(newProvider); - providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkeys); vm.prank(newProvider); providerRegistry.unstake(); assertEq( @@ -439,7 +451,7 @@ contract ProviderRegistryTest is Test { address bidder = vm.addr(9); vm.deal(newProvider, 3 ether); vm.prank(newProvider); - providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkeys); providerRegistry.setPreconfManager( address(preconfManager) ); @@ -466,7 +478,7 @@ contract ProviderRegistryTest is Test { address newProvider = vm.addr(8); vm.deal(newProvider, 3 ether); vm.prank(newProvider); - providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkeys); vm.prank(newProvider); providerRegistry.unstake(); vm.warp(block.timestamp + 23 hours); // Move forward less than 24 hours @@ -486,7 +498,7 @@ contract ProviderRegistryTest is Test { address newProvider = vm.addr(8); vm.deal(newProvider, 3 ether); vm.prank(newProvider); - providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkey); + providerRegistry.registerAndStake{value: 2e18 wei}(validBLSPubkeys); vm.prank(newProvider); vm.expectRevert( abi.encodeWithSelector(IProviderRegistry.NoUnstakeRequest.selector, newProvider) @@ -498,7 +510,7 @@ contract ProviderRegistryTest is Test { address newProvider = vm.addr(7); vm.prank(address(this)); - providerRegistry.delegateRegisterAndStake{value: 2e18 wei}(newProvider, validBLSPubkey); + providerRegistry.delegateRegisterAndStake{value: 2e18 wei}(newProvider, validBLSPubkeys); assertEq( providerRegistry.providerStakes(newProvider), 2e18 wei, @@ -510,4 +522,4 @@ contract ProviderRegistryTest is Test { "Provider should be registered" ); } -} +} \ No newline at end of file diff --git a/infrastructure/nomad/playbooks/templates/jobs/mev-commit-emulator.nomad.j2 b/infrastructure/nomad/playbooks/templates/jobs/mev-commit-emulator.nomad.j2 index 256316073..60f41b426 100644 --- a/infrastructure/nomad/playbooks/templates/jobs/mev-commit-emulator.nomad.j2 +++ b/infrastructure/nomad/playbooks/templates/jobs/mev-commit-emulator.nomad.j2 @@ -73,6 +73,11 @@ job "{{ job.name }}" { EMULATOR_IP_HTTP_PORT="{{ .Address }}:{{ .Port }}" {{- end }} {{- end }} + {{- range nomadService "relay-emulator" }} + {{- if contains "http" .Tags }} + EMULATOR_RELAY_URL="http://{{ .Address }}:{{ .Port }}" + {{- end }} + {{- end }} {% endraw %} {% if job.target_type == 'bidder' %} EMULATOR_L1_RPC_URL="{{ job.env['l1_rpc_url'] }}" @@ -115,6 +120,9 @@ job "{{ job.name }}" { -log-tags "${EMULATOR_LOG_TAGS}" \ -log-fmt "${EMULATOR_LOG_FMT}" \ -otel-collector-endpoint-url "${EMULATOR_OTEL_COLLECTOR_ENDPOINT_URL}" \ + {% if job.target_type == 'provider' %} + -relay "${EMULATOR_RELAY_URL}" \ + {% endif %} EOH destination = "local/run.sh" change_mode = "noop" diff --git a/infrastructure/nomad/playbooks/templates/jobs/mev-commit-oracle.nomad.j2 b/infrastructure/nomad/playbooks/templates/jobs/mev-commit-oracle.nomad.j2 index fbc6a193f..21805f21c 100644 --- a/infrastructure/nomad/playbooks/templates/jobs/mev-commit-oracle.nomad.j2 +++ b/infrastructure/nomad/playbooks/templates/jobs/mev-commit-oracle.nomad.j2 @@ -183,7 +183,7 @@ job "{{ job.name }}" { data = <<-EOH MEV_ORACLE_LOG_FMT="{{ job.env.get('log-format', 'json') }}" MEV_ORACLE_LOG_TAGS="{{ 'service.name:' + job.name + '-{{ env "NOMAD_ALLOC_INDEX" }}' + ',service.version:' + version }}" - MEV_ORACLE_LOG_LEVEL="{{ job.env.get('log-level', 'info') }}" + MEV_ORACLE_LOG_LEVEL="debug" MEV_ORACLE_LAGGERD_MODE="{{ job.env.get('laggerd-mode', '10') }}" MEV_ORACLE_L1_RPC_URLS="{{ job.env['l1_rpc_urls'] }}" {%- raw %} @@ -233,58 +233,6 @@ job "{{ job.name }}" { {{ end }} {% endraw %} - {% if env == 'devenv' %} - {% raw %} - MEV_ORACLE_OVERRIDE_WINNERS="" - - {{- range nomadService "mev-commit-provider-node1" }} - {{- if contains "http" .Tags }} - URL="https://{{ .Address }}:{{ .Port }}/v1/debug/topology" - ETH_ADDRESS="$(curl -sk ${URL} | jq -r '.topology.self["Ethereum Address"]')" - if [ -n "${ETH_ADDRESS}" ]; then - if [ -z "${MEV_ORACLE_OVERRIDE_WINNERS}" ]; then - MEV_ORACLE_OVERRIDE_WINNERS="${ETH_ADDRESS}" - else - MEV_ORACLE_OVERRIDE_WINNERS="${MEV_ORACLE_OVERRIDE_WINNERS},${ETH_ADDRESS}" - fi - fi - {{ end }} - {{- end }} - - {{- range nomadService "mev-commit-provider-node2" }} - {{- if contains "http" .Tags }} - URL="https://{{ .Address }}:{{ .Port }}/v1/debug/topology" - ETH_ADDRESS="$(curl -sk ${URL} | jq -r '.topology.self["Ethereum Address"]')" - if [ -n "${ETH_ADDRESS}" ]; then - if [ -z "${MEV_ORACLE_OVERRIDE_WINNERS}" ]; then - MEV_ORACLE_OVERRIDE_WINNERS="${ETH_ADDRESS}" - else - MEV_ORACLE_OVERRIDE_WINNERS="${MEV_ORACLE_OVERRIDE_WINNERS},${ETH_ADDRESS}" - fi - fi - {{ end }} - {{- end }} - - {{- range nomadService "mev-commit-provider-node3" }} - {{- if contains "http" .Tags }} - URL="https://{{ .Address }}:{{ .Port }}/v1/debug/topology" - ETH_ADDRESS="$(curl -sk ${URL} | jq -r '.topology.self["Ethereum Address"]')" - if [ -n "${ETH_ADDRESS}" ]; then - if [ -z "${MEV_ORACLE_OVERRIDE_WINNERS}" ]; then - MEV_ORACLE_OVERRIDE_WINNERS="${ETH_ADDRESS}" - else - MEV_ORACLE_OVERRIDE_WINNERS="${MEV_ORACLE_OVERRIDE_WINNERS},${ETH_ADDRESS}" - fi - fi - {{ end }} - {{- end }} - - if [ ! -z "${MEV_ORACLE_OVERRIDE_WINNERS}" ]; then - echo "Overriding winners: ${MEV_ORACLE_OVERRIDE_WINNERS}" - export MEV_ORACLE_OVERRIDE_WINNERS - fi - {% endraw %} - {% endif %} {% raw %} {{- range nomadService "contracts-deployer" }} @@ -300,6 +248,12 @@ job "{{ job.name }}" { {{ end }} {{- end }} + {{- range nomadService "relay-emulator" }} + {{ if contains "http" .Tags }} + export MEV_ORACLE_RELAY_URLS="http://{{ .Address }}:{{ .Port }}" + {{ end }} + {{- end }} + source alloc/data/postgres.env export MEV_ORACLE_PG_USER="${POSTGRES_USERNAME}" export MEV_ORACLE_PG_PASSWORD="${POSTGRES_PASSWORD}" diff --git a/infrastructure/nomad/playbooks/templates/jobs/mev-commit.nomad.j2 b/infrastructure/nomad/playbooks/templates/jobs/mev-commit.nomad.j2 index 29c639805..f218ba2af 100644 --- a/infrastructure/nomad/playbooks/templates/jobs/mev-commit.nomad.j2 +++ b/infrastructure/nomad/playbooks/templates/jobs/mev-commit.nomad.j2 @@ -103,6 +103,7 @@ job "{{ job.name }}" { MEV_COMMIT_P2P_ADDR="{{ job.env.get('p2p-address', '0.0.0.0') }}" MEV_COMMIT_SERVER_TLS_CERTIFICATE="{{ job.env['tls_crt_file'] }}" MEV_COMMIT_SERVER_TLS_PRIVATE_KEY="{{ job.env['tls_key_file'] }}" + MEV_COMMIT_LOG_LEVEL="debug" {% if job.env['type'] == 'provider' %} MEV_COMMIT_NAT_ADDR="{{ job.env['nat_address'] }}" {%- raw %} diff --git a/infrastructure/nomad/playbooks/templates/jobs/relay-emulator.nomad.j2 b/infrastructure/nomad/playbooks/templates/jobs/relay-emulator.nomad.j2 new file mode 100644 index 000000000..eba8871c3 --- /dev/null +++ b/infrastructure/nomad/playbooks/templates/jobs/relay-emulator.nomad.j2 @@ -0,0 +1,104 @@ +#jinja2: trim_blocks:True, lstrip_blocks:True +job "{{ job.name }}" { + datacenters = ["{{ datacenter }}"] + + group "{{ job.name }}-group" { + count = {{ job.count }} + + {% if env == 'devenv' %} + restart { + attempts = 0 + mode = "fail" + } + + reschedule { + attempts = 0 + unlimited = false + } + {% endif %} + + network { + mode = "bridge" + + dns { + servers = {{ (ansible_facts['dns']['nameservers'] + ['1.1.1.1']) | tojson }} + } + + {% for port_name, port_details in job.ports[0].items() %} + port "{{ port_name }}" { + {% if port_details.get('static') %} + static = {{ port_details['static'] }} + {% endif %} + {% if port_details.get('to') %} + to = {{ port_details['to'] }} + {% endif %} + } + {% endfor %} + } + + {% for port_name in job.ports[0] %} + service { + name = "{{ job.name }}" + port = "{{ port_name }}" + tags = ["{{ port_name }}"] + provider = "nomad" + } + {% endfor %} + + task "relay-emulator" { + driver = "exec" + + {% if env != 'devenv' %} + artifact { + source = "https://primev-infrastructure-artifacts.s3.us-west-2.amazonaws.com/relay-emulator_{{ version }}_Linux_{{ target_system_architecture }}.tar.gz" + } + {% else %} + artifact { + source = "http://{{ ansible_facts['default_ipv4']['address'] }}:1111/relay-emulator_{{ version }}_Linux_{{ target_system_architecture }}.tar.gz" + } + {% endif %} + + template { + data = <<-EOH + MOCK_RELAY_LOG_FMT="{{ job.env.get('log-format', 'json') }}" + MOCK_RELAY_LOG_TAGS="{{ 'service.name:' + job.name + '-{{ env "NOMAD_ALLOC_INDEX" }}' + ',service.version:' + version }}" + MOCK_RELAY_LOG_LEVEL="{{ job.env.get('log-level', 'info') }}" + {%- raw %} + {{- range nomadService "mock-l1" }} + {{- if contains "ws" .Tags }} + MOCK_RELAY_L1_RPC_URL="ws://{{ .Address}}:{{ .Port }}" + {{- end }} + {{- end }} + {% endraw %} + EOH + destination = "secrets/.env" + env = true + } + + template { + data = <<-EOH + #!/usr/bin/env bash + + {% raw %} + {{- range nomadService "datadog-agent-logs-collector" }} + {{ if contains "tcp" .Tags }} + exec > >(nc {{ .Address }} {{ .Port }}) 2>&1 + {{ end }} + {{- end }} + + chmod +x local/relay-emulator + exec local/relay-emulator + {% endraw %} + EOH + destination = "local/run.sh" + change_mode = "noop" + perms = "0755" + } + + config { + command = "bash" + args = ["-c", "exec local/run.sh"] + } + } + } +} diff --git a/infrastructure/nomad/playbooks/variables/profiles.yml b/infrastructure/nomad/playbooks/variables/profiles.yml index be824c9e9..dfc0066ef 100644 --- a/infrastructure/nomad/playbooks/variables/profiles.yml +++ b/infrastructure/nomad/playbooks/variables/profiles.yml @@ -30,6 +30,9 @@ artifacts: l1-transactor: &l1_transactor_artifact type: binary path: tools/l1-transaction-emulator + relay-emulator: &relay_emulator_artifact + type: binary + path: tools/relay-emulator jobs: artifacts: &artifacts_job @@ -145,6 +148,24 @@ jobs: type: archive sync_mode: full + + mock_l1: &mock_l1_job + name: mock-l1 + template: mock-l1.nomad.j2 + count: 1 + ports: + - http: + static: 9545 + to: 8545 + ws: + static: 9546 + to: 8546 + env: + ip: 0.0.0.0 + public_ip: 0.0.0.0 + net_restrict: 0.0.0.0/0 + + contracts_deployer: &contracts_deployer_job name: contracts-deployer template: contracts-deployer.nomad.j2 @@ -177,6 +198,21 @@ jobs: env: log-level: "info" + relay-emulator: &relay_emulator_job + name: relay-emulator + template: relay-emulator.nomad.j2 + artifacts: + - *relay_emulator_artifact + dependencies: + mock_l1: *mock_l1_job + count: 1 + ports: + - http: + static: 8082 + to: 8080 + env: + log-level: "info" + mev_commit_bootnode1: &mev_commit_bootnode1_job name: mev-commit-bootnode1 template: mev-commit.nomad.j2 @@ -210,6 +246,8 @@ jobs: - *p2p_artifact - keystores: provider1_keystore: + dependencies: + relay-emulator: *relay_emulator_job count: 1 ports: - metrics: @@ -236,6 +274,8 @@ jobs: - *p2p_artifact - keystores: provider2_keystore: + dependencies: + relay-emulator: *relay_emulator_job count: 1 ports: - metrics: @@ -261,6 +301,8 @@ jobs: - *p2p_artifact - keystores: provider3_keystore: + dependencies: + relay-emulator: *relay_emulator_job count: 1 ports: - metrics: @@ -588,22 +630,6 @@ jobs: metrics: to: 8888 - mock_l1: &mock_l1_job - name: mock-l1 - template: mock-l1.nomad.j2 - count: 1 - ports: - - http: - static: 9545 - to: 8545 - ws: - static: 9546 - to: 8546 - env: - ip: 0.0.0.0 - public_ip: 0.0.0.0 - net_restrict: 0.0.0.0/0 - l1-transactor: &l1_transactor_job name: l1-transactor template: l1-transactor.nomad.j2 @@ -644,6 +670,7 @@ profiles: - *mev_commit_geth_signer_node1_job - *mock_l1_job - *l1_transactor_job + - *relay_emulator_job - *contracts_deployer_job - *mev_commit_bridge_job - *mev_commit_bootnode1_job @@ -664,6 +691,7 @@ profiles: - *mev_commit_geth_member_node_job - *mock_l1_job - *l1_transactor_job + - *relay_emulator_job - *contracts_deployer_job - *mev_commit_bridge_job - *bridge_emulator_job @@ -707,6 +735,7 @@ profiles: - *mev_commit_geth_member_node_job - *mock_l1_job - *l1_transactor_job + - *relay_emulator_job - *contracts_deployer_job - *mev_commit_bridge_job - *bridge_emulator_job @@ -744,7 +773,9 @@ profiles: - *mev_commit_geth_member_node_job - *mock_l1_job - *l1_transactor_job + - *relay_emulator_job - *contracts_deployer_job + - *mev_commit_bridge_job - *mev_commit_dashboard_job - *mev_commit_bootnode1_job - *mev_commit_provider_node1_job diff --git a/oracle/cmd/main.go b/oracle/cmd/main.go index 0407c30cf..14869e909 100644 --- a/oracle/cmd/main.go +++ b/oracle/cmd/main.go @@ -103,6 +103,7 @@ var ( Name: "l1-rpc-urls", Usage: "URLs for L1 RPC", EnvVars: []string{"MEV_ORACLE_L1_RPC_URLS"}, + Value: cli.NewStringSlice("https://ethereum-holesky-rpc.publicnode.com"), }) optionSettlementRPCUrlHTTP = altsrc.NewStringFlag(&cli.StringFlag{ @@ -242,6 +243,18 @@ var ( EnvVars: []string{"MEV_COMMIT_GAS_FEE_CAP"}, Value: "2000000000", // 2 gWEI }) + + optionRelayUrls = altsrc.NewStringSliceFlag(&cli.StringSliceFlag{ + Name: "relay-urls", + Usage: "URLs for relay", + EnvVars: []string{"MEV_ORACLE_RELAY_URLS"}, + Value: cli.NewStringSlice( + "https://holesky.aestus.live", + "https://boost-relay-holesky.flashbots.net", + "https://bloxroute.holesky.blxrbdn.com", + "https://holesky.titanrelay.xyz", + ), + }) ) func main() { @@ -273,6 +286,7 @@ func main() { optionGasLimit, optionGasTipCap, optionGasFeeCap, + optionRelayUrls, } app := &cli.App{ Name: "mev-oracle", @@ -392,6 +406,7 @@ func launchOracleWithConfig(c *cli.Context) error { DefaultGasLimit: uint64(c.Int(optionGasLimit.Name)), DefaultGasTipCap: gasTipCap, DefaultGasFeeCap: gasFeeCap, + RelayUrls: c.StringSlice(optionRelayUrls.Name), }) if err != nil { return fmt.Errorf("failed starting node: %w", err) diff --git a/oracle/pkg/l1Listener/l1Listener.go b/oracle/pkg/l1Listener/l1Listener.go index 22800e638..6195ea9c4 100644 --- a/oracle/pkg/l1Listener/l1Listener.go +++ b/oracle/pkg/l1Listener/l1Listener.go @@ -1,11 +1,19 @@ package l1Listener import ( - "bytes" "context" + "encoding/hex" + "encoding/json" "errors" + "fmt" + "io" "log/slog" "math/big" + "net/http" + "net/url" + "strconv" + "strings" + "sync" "time" "github.com/ethereum/go-ethereum/core/types" @@ -19,7 +27,7 @@ import ( var checkInterval = 2 * time.Second type L1Recorder interface { - RecordL1Block(blockNum *big.Int, winner string) (*types.Transaction, error) + RecordL1Block(blockNum *big.Int, winner []byte) (*types.Transaction, error) } type WinnerRegister interface { @@ -40,6 +48,17 @@ type L1Listener struct { eventMgr events.EventManager recorder L1Recorder metrics *metrics + relayQuerier RelayQuerier + builderData map[int64]string +} + +type RelayData struct { + RelayName string + BuilderPubkey string + BlockNumber int64 + BlockHash string + Slot string + Timestamp string } func NewL1Listener( @@ -48,6 +67,7 @@ func NewL1Listener( winnerRegister WinnerRegister, evtMgr events.EventManager, recorder L1Recorder, + relayQuerier RelayQuerier, ) *L1Listener { return &L1Listener{ logger: logger, @@ -56,6 +76,8 @@ func NewL1Listener( eventMgr: evtMgr, recorder: recorder, metrics: newMetrics(), + relayQuerier: relayQuerier, + builderData: make(map[int64]string), } } @@ -159,29 +181,44 @@ func (l *L1Listener) watchL1Block(ctx context.Context) error { l.logger.Error("failed to get block number", "error", err) continue } + // We need to get the previous block number because the current block has finalized header + blockNum = blockNum - 1 if blockNum <= uint64(currentBlockNo) { continue } for b := uint64(currentBlockNo) + 1; b <= blockNum; b++ { - header, err := l.l1Client.HeaderByNumber(ctx, big.NewInt(int64(b))) + header, err := l.l1Client.HeaderByNumber(ctx, new(big.Int).SetUint64(b+1)) if err != nil { l.logger.Error("failed to get header", "block", b, "error", err) continue } + // End of changes needed to be done. + var builderPubKey string + l.logger.Info("querying relay", "block", b, "hash", header.ParentHash.Hex()) + builderPubKey, err = l.relayQuerier.Query(ctx, int64(b), header.ParentHash.Hex()) + if err != nil { + l.logger.Info("block not found in relay, assuming out of PBS block", "block", b, "error", err) + builderPubKey = "" // Set a default value in case of failure + } - winner := string(bytes.ToValidUTF8(header.Extra, []byte("�"))) + builderPubKey = strings.TrimPrefix(builderPubKey, "0x") + + builderPubKeyBytes, err := hex.DecodeString(builderPubKey) + if err != nil { + l.logger.Error("failed to decode builder pubkey", "block", b, "builder_pubkey", builderPubKey, "error", err) + } l.logger.Info( "new L1 winner", - "winner", winner, - "block", header.Number.Int64(), + "block", header.Number.Int64()-1, + "builder_pubkey", builderPubKey, ) winnerPostingTxn, err := l.recorder.RecordL1Block( big.NewInt(0).SetUint64(b), - winner, + builderPubKeyBytes, ) if err != nil { l.logger.Error("failed to register winner for block", "block", b, "error", err) @@ -193,8 +230,7 @@ func (l *L1Listener) watchL1Block(ctx context.Context) error { l.logger.Info( "registered winner", - "winner", winner, - "block", header.Number.Int64(), + "block", header.Number.Int64()-1, "txn", winnerPostingTxn.Hash().String(), ) } @@ -203,3 +239,102 @@ func (l *L1Listener) watchL1Block(ctx context.Context) error { } } } + +type RelayQuerier interface { + Query(ctx context.Context, blockNumber int64, blockHash string) (string, error) +} + +type RelayQueryEngine struct { + relayUrls []string + logger *slog.Logger +} + +func NewRelayQueryEngine(relayUrls []string, logger *slog.Logger) RelayQuerier { + return &RelayQueryEngine{ + relayUrls: relayUrls, + logger: logger, + } +} + +func (m *RelayQueryEngine) Query(ctx context.Context, blockNumber int64, blockHash string) (string, error) { + var wg sync.WaitGroup + resultChan := make(chan string, len(m.relayUrls)) + + for _, u := range m.relayUrls { + wg.Add(1) + go func(u string) { + defer wg.Done() + apiPath := "/relay/v1/data/bidtraces/proposer_payload_delivered" + baseURL, err := url.Parse(u) + if err != nil { + m.logger.Error("failed to parse relay URL", "url", u, "error", err) + return + } + baseURL.Path = baseURL.Path + apiPath + + query := url.Values{} + query.Add("block_number", strconv.Itoa(int(blockNumber))) + + baseURL.RawQuery = query.Encode() + m.logger.Debug("querying relay", "url", baseURL.String()) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, baseURL.String(), nil) + if err != nil { + m.logger.Error("failed to create request", "url", baseURL.String(), "error", err) + return + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + m.logger.Error("failed to fetch data from relay", "url", baseURL.String(), "error", err) + return + } + defer resp.Body.Close() + m.logger.Info("received response from relay", "url", baseURL.String(), "status", resp.Status) + + body, err := io.ReadAll(resp.Body) + if err != nil { + m.logger.Error("failed to read response body", "url", baseURL.String(), "error", err) + return + } + + var data []map[string]interface{} + if err := json.Unmarshal(body, &data); err != nil { + m.logger.Error("failed to unmarshal response", "url", baseURL.String(), "error", err) + return + } + + for _, item := range data { + blockNum, ok := item["block_number"].(string) + if !ok { + m.logger.Error("block_number is not a string", "block_number", item["block_number"]) + continue + } + blockNumInt, err := strconv.Atoi(blockNum) + if err != nil { + m.logger.Error("failed to convert block_number to int", "block_number", blockNum, "error", err) + continue + } + if blockNumInt == int(blockNumber) && item["block_hash"] == blockHash { + resultChan <- fmt.Sprintf("%v", item["builder_pubkey"]) + return + } + } + }(u) + } + + go func() { + wg.Wait() + close(resultChan) + }() + + select { + case <-ctx.Done(): + return "", ctx.Err() + case result, ok := <-resultChan: + if !ok { + return "", errors.New("no matching block found") + } + return result, nil + } +} diff --git a/oracle/pkg/l1Listener/l1Listener_test.go b/oracle/pkg/l1Listener/l1Listener_test.go index 3913ad781..0caacfca8 100644 --- a/oracle/pkg/l1Listener/l1Listener_test.go +++ b/oracle/pkg/l1Listener/l1Listener_test.go @@ -3,6 +3,7 @@ package l1Listener_test import ( "bytes" "context" + "encoding/hex" "errors" "fmt" "io" @@ -47,12 +48,28 @@ func TestL1Listener(t *testing.T) { updates: make(chan l1Update), } + testRelayQuerier := &testRelayQuerier{ + responses: map[int64]string{ + 1: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", + 2: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", + 3: "0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba", + 4: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef", + 5: "0x123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234", + 6: "0x567856785678567856785678567856785678567856785678567856785678567856785678567856785678567856785678", + 7: "0x9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc9abc", + 8: "0xdef0def0def0def0def0def0def0def0def0def0def0def0def0def0def0def0def0def0def0def0def0def0def0def0", + 9: "0x345634563456345634563456345634563456345634563456345634563456345634563456345634563456345634563456", + 10: "0x789078907890789078907890789078907890789078907890789078907890789078907890789078907890789078907890", + }, + } + l := l1Listener.NewL1Listener( slog.New(slog.NewTextHandler(os.Stdout, nil)), ethClient, reg, eventManager, rec, + testRelayQuerier, ) ctx, cancel := context.WithCancel(context.Background()) @@ -61,47 +78,26 @@ func TestL1Listener(t *testing.T) { done := l.Start(ctx) - for i := 1; i < 10; i++ { - ethClient.AddHeader(uint64(i), &types.Header{ - Number: big.NewInt(int64(i)), - Extra: []byte(fmt.Sprintf("b%d", i)), - }) - - select { - case <-time.After(10 * time.Second): - t.Fatal("timeout waiting for winner", i) - case update := <-rec.updates: - if update.blockNum.Int64() != int64(i) { - t.Fatal("wrong block number") - } - if update.winner != fmt.Sprintf("b%d", i) { - t.Fatal("wrong winner") - } - } - } - // no winner - ethClient.AddHeader(10, &types.Header{ - Number: big.NewInt(10), + ethClient.AddHeader(2, &types.Header{ + Number: big.NewInt(2), }) - // error registering winner, ensure it is retried - ethClient.errC <- errors.New("dummy error") - ethClient.AddHeader(11, &types.Header{ - Number: big.NewInt(11), - Extra: []byte("b11"), - }) + builderPubKeyBytes, _ := hex.DecodeString("abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890") + if err != nil { + t.Fatal(err) + } // ensure no winner is sent for the previous block select { case <-time.After(10 * time.Second): t.Fatal("timeout waiting for winner") case update := <-rec.updates: - if update.blockNum.Int64() != 11 { - t.Fatal("wrong block number") + if update.blockNum.Int64() != 1 { + t.Fatalf("wrong block number: %d", update.blockNum.Int64()) } - if update.winner != "b11" { - t.Fatal("wrong winner") + if !bytes.Equal(update.winner, builderPubKeyBytes) { + t.Fatalf("wrong winner: %s", update.winner) } } @@ -143,6 +139,26 @@ func TestL1Listener(t *testing.T) { } } +type testRelayQuerier struct { + responses map[int64]string + mu sync.Mutex +} + +func (t *testRelayQuerier) SetResponse(blockNumber int64, builderPubKey string) { + t.mu.Lock() + defer t.mu.Unlock() + t.responses[blockNumber] = builderPubKey +} + +func (t *testRelayQuerier) Query(ctx context.Context, blockNumber int64, blockHash string) (string, error) { + t.mu.Lock() + defer t.mu.Unlock() + if response, ok := t.responses[blockNumber]; ok { + return response, nil + } + return "", fmt.Errorf("no response set for block number %d", blockNumber) +} + type winnerObj struct { blockNum int64 winner []byte @@ -244,14 +260,14 @@ func publishLog( type l1Update struct { blockNum *big.Int - winner string + winner []byte } type testRecorder struct { updates chan l1Update } -func (t *testRecorder) RecordL1Block(blockNum *big.Int, winner string) (*types.Transaction, error) { +func (t *testRecorder) RecordL1Block(blockNum *big.Int, winner []byte) (*types.Transaction, error) { t.updates <- l1Update{blockNum: blockNum, winner: winner} return types.NewTransaction(0, common.Address{}, nil, 0, nil, nil), nil } diff --git a/oracle/pkg/node/node.go b/oracle/pkg/node/node.go index 08c0b3dce..8a136d0de 100644 --- a/oracle/pkg/node/node.go +++ b/oracle/pkg/node/node.go @@ -45,6 +45,7 @@ type Options struct { KeySigner keysigner.KeySigner HTTPPort int SettlementRPCUrl string + RelayUrls []string L1RPCUrls []string OracleContractAddr common.Address PreconfContractAddr common.Address @@ -240,13 +241,17 @@ func NewNode(opts *Options) (*Node, error) { return nil, err } + relayQuerier := l1Listener.NewRelayQueryEngine(opts.RelayUrls, nd.logger.With("component", "l1_listener_relay_querier")) + l1Lis := l1Listener.NewL1Listener( nd.logger.With("component", "l1_listener"), l1Client, st, evtMgr, blockTrackerTransactor, + relayQuerier, ) + l1LisClosed := l1Lis.Start(ctx) healthChecker.Register(health.CloseChannelHealthCheck("l1_listener", l1LisClosed)) diff --git a/p2p/gen/go/providerapi/v1/providerapi.pb.go b/p2p/gen/go/providerapi/v1/providerapi.pb.go index 81628480b..297f6ed45 100644 --- a/p2p/gen/go/providerapi/v1/providerapi.pb.go +++ b/p2p/gen/go/providerapi/v1/providerapi.pb.go @@ -77,8 +77,8 @@ type StakeRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` - BlsPublicKey string `protobuf:"bytes,2,opt,name=bls_public_key,json=blsPublicKey,proto3" json:"bls_public_key,omitempty"` + Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + BlsPublicKeys []string `protobuf:"bytes,2,rep,name=bls_public_keys,json=blsPublicKeys,proto3" json:"bls_public_keys,omitempty"` } func (x *StakeRequest) Reset() { @@ -120,11 +120,11 @@ func (x *StakeRequest) GetAmount() string { return "" } -func (x *StakeRequest) GetBlsPublicKey() string { +func (x *StakeRequest) GetBlsPublicKeys() []string { if x != nil { - return x.BlsPublicKey + return x.BlsPublicKeys } - return "" + return nil } type StakeResponse struct { @@ -132,8 +132,8 @@ type StakeResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` - BlsPublicKey string `protobuf:"bytes,2,opt,name=bls_public_key,json=blsPublicKey,proto3" json:"bls_public_key,omitempty"` + Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + BlsPublicKeys []string `protobuf:"bytes,2,rep,name=bls_public_keys,json=blsPublicKeys,proto3" json:"bls_public_keys,omitempty"` } func (x *StakeResponse) Reset() { @@ -175,11 +175,11 @@ func (x *StakeResponse) GetAmount() string { return "" } -func (x *StakeResponse) GetBlsPublicKey() string { +func (x *StakeResponse) GetBlsPublicKeys() []string { if x != nil { - return x.BlsPublicKey + return x.BlsPublicKeys } - return "" + return nil } type WithdrawalResponse struct { @@ -445,7 +445,7 @@ var file_providerapi_v1_providerapi_proto_rawDesc = []byte{ 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xad, 0x05, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcc, 0x05, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xb2, 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x99, 0x01, 0x92, 0x41, 0x3b, 0x32, 0x30, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, @@ -458,329 +458,338 @@ var file_providerapi_v1_providerapi_proto_rawDesc = []byte{ 0x2a, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0xf1, 0x01, 0x0a, 0x0e, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0xca, 0x01, 0x92, - 0x41, 0x3a, 0x32, 0x1f, 0x42, 0x4c, 0x53, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x6b, - 0x65, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x2e, 0x8a, 0x01, 0x16, 0x5e, 0x28, 0x30, 0x78, 0x29, 0x3f, 0x5b, 0x61, 0x2d, 0x66, - 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x39, 0x36, 0x7d, 0x24, 0xba, 0x48, 0x89, 0x01, - 0xba, 0x01, 0x85, 0x01, 0x0a, 0x0e, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x4b, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x20, 0x34, 0x38, 0x2d, 0x62, 0x79, 0x74, 0x65, 0x20, 0x68, 0x65, 0x78, - 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2c, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x30, 0x78, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x2e, 0x1a, 0x26, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, - 0x27, 0x5e, 0x28, 0x30, 0x78, 0x29, 0x3f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, - 0x39, 0x5d, 0x7b, 0x39, 0x36, 0x7d, 0x24, 0x27, 0x29, 0x52, 0x0c, 0x62, 0x6c, 0x73, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x3a, 0xf3, 0x01, 0x92, 0x41, 0xef, 0x01, 0x0a, 0x53, - 0x2a, 0x0d, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, - 0x28, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, - 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, - 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0xd2, 0x01, 0x0e, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, - 0x6b, 0x65, 0x79, 0x32, 0x97, 0x01, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, - 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x22, 0x3a, 0x20, 0x22, 0x38, 0x30, 0x30, 0x30, 0x30, - 0x63, 0x64, 0x64, 0x65, 0x65, 0x63, 0x36, 0x36, 0x61, 0x38, 0x30, 0x30, 0x65, 0x30, 0x30, 0x62, - 0x30, 0x63, 0x63, 0x62, 0x62, 0x36, 0x32, 0x66, 0x31, 0x32, 0x32, 0x39, 0x38, 0x30, 0x37, 0x33, - 0x36, 0x30, 0x33, 0x66, 0x35, 0x32, 0x30, 0x39, 0x65, 0x38, 0x31, 0x32, 0x61, 0x62, 0x62, 0x61, - 0x63, 0x37, 0x65, 0x38, 0x37, 0x30, 0x34, 0x38, 0x32, 0x65, 0x34, 0x38, 0x38, 0x64, 0x64, 0x31, - 0x62, 0x62, 0x65, 0x35, 0x33, 0x33, 0x61, 0x39, 0x64, 0x34, 0x34, 0x34, 0x39, 0x37, 0x62, 0x61, - 0x38, 0x62, 0x37, 0x35, 0x36, 0x65, 0x31, 0x65, 0x38, 0x32, 0x62, 0x22, 0x7d, 0x22, 0xb8, 0x02, - 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x6c, 0x73, 0x5f, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x62, 0x6c, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x3a, 0xe8, 0x01, - 0x92, 0x41, 0xe4, 0x01, 0x0a, 0x4a, 0x2a, 0x0e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x38, 0x47, 0x65, 0x74, 0x20, 0x73, 0x74, 0x61, 0x6b, - 0x65, 0x64, 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, - 0x32, 0x95, 0x01, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x5f, 0x6b, 0x65, 0x79, 0x22, 0x3a, 0x20, 0x22, 0x38, 0x30, 0x30, 0x30, 0x30, 0x63, 0x64, 0x64, - 0x65, 0x65, 0x63, 0x36, 0x36, 0x61, 0x38, 0x30, 0x65, 0x30, 0x30, 0x62, 0x30, 0x63, 0x63, 0x62, - 0x62, 0x36, 0x32, 0x66, 0x31, 0x32, 0x32, 0x39, 0x38, 0x30, 0x37, 0x33, 0x36, 0x30, 0x33, 0x66, - 0x35, 0x32, 0x30, 0x39, 0x65, 0x38, 0x31, 0x32, 0x61, 0x62, 0x62, 0x61, 0x63, 0x37, 0x65, 0x38, - 0x37, 0x30, 0x34, 0x38, 0x32, 0x65, 0x34, 0x38, 0x38, 0x64, 0x64, 0x31, 0x62, 0x62, 0x65, 0x35, - 0x33, 0x33, 0x61, 0x39, 0x64, 0x34, 0x34, 0x39, 0x37, 0x62, 0x61, 0x38, 0x62, 0x37, 0x35, 0x36, - 0x65, 0x31, 0x65, 0x38, 0x32, 0x62, 0x22, 0x7d, 0x22, 0xa5, 0x01, 0x0a, 0x12, 0x57, 0x69, 0x74, - 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x77, 0x92, 0x41, 0x74, 0x0a, 0x4f, 0x2a, 0x13, - 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x32, 0x38, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x20, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x32, 0x21, 0x7b, - 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x7d, - 0x22, 0x0e, 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0xec, 0x11, 0x0a, 0x03, 0x42, 0x69, 0x64, 0x12, 0x8f, 0x02, 0x0a, 0x09, 0x74, 0x78, 0x5f, - 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0xf1, 0x01, 0x92, - 0x41, 0x78, 0x32, 0x64, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, - 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, - 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, - 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0xba, 0x48, 0x73, 0xba, 0x01, 0x70, - 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x36, 0x74, 0x78, 0x5f, - 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, - 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, - 0x65, 0x73, 0x2e, 0x1a, 0x2b, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, - 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, - 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, - 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0xfc, 0x01, 0x0a, 0x0a, 0x62, - 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, - 0xdc, 0x01, 0x92, 0x41, 0x76, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, - 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x20, - 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, 0x48, 0x60, 0xba, 0x01, - 0x5d, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23, 0x62, - 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, - 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, - 0x72, 0x2e, 0x1a, 0x2a, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, - 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, - 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x09, - 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x74, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, - 0x51, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, - 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0xba, 0x48, 0x04, 0x22, 0x02, - 0x20, 0x00, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, - 0x5c, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0c, 0x42, 0x3d, 0x92, 0x41, 0x31, 0x32, 0x2f, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, - 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0xba, 0x48, 0x06, 0x7a, 0x04, 0x10, 0x01, - 0x18, 0x40, 0x52, 0x09, 0x62, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0xc2, 0x01, - 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x8d, 0x01, - 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, - 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, - 0xba, 0x48, 0x5a, 0xba, 0x01, 0x57, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x64, - 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, - 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x13, 0x64, - 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0xb8, 0x01, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, - 0x42, 0x87, 0x01, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, - 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, - 0x2e, 0xba, 0x48, 0x56, 0xba, 0x01, 0x53, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, - 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x64, 0x65, - 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, - 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, - 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x8a, 0x02, - 0x0a, 0x13, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x42, 0xd9, 0x01, 0x92, 0x41, - 0x49, 0x32, 0x47, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x61, 0x72, 0x72, 0x61, - 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x78, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x74, - 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, - 0x74, 0x6f, 0x20, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x62, 0x65, 0x20, - 0x64, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x65, 0x64, 0x2e, 0xba, 0x48, 0x89, 0x01, 0xba, 0x01, - 0x85, 0x01, 0x0a, 0x13, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, - 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x41, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x69, - 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, - 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x2b, 0x74, 0x68, 0x69, 0x73, - 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, - 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, - 0x36, 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, 0x52, 0x11, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x69, - 0x6e, 0x67, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x9d, 0x02, 0x0a, 0x10, 0x72, - 0x61, 0x77, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x08, 0x20, 0x03, 0x28, 0x09, 0x42, 0xf1, 0x01, 0x92, 0x41, 0x6e, 0x32, 0x6c, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x52, - 0x4c, 0x50, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x72, 0x61, 0x77, 0x20, 0x73, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, - 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0xba, 0x48, 0x7d, 0xba, 0x01, 0x7a, 0x0a, - 0x10, 0x72, 0x61, 0x77, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x3c, 0x72, 0x61, 0x77, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61, - 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x72, 0x61, - 0x77, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x1a, - 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, - 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, - 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x29, 0x52, 0x0f, 0x72, 0x61, 0x77, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0xd2, 0x04, 0x92, 0x41, 0xce, - 0x04, 0x0a, 0x70, 0x2a, 0x0b, 0x42, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x32, 0x30, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x2e, 0xd2, 0x01, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0xd2, 0x01, 0x09, - 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0x01, 0x0b, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0xd2, 0x01, 0x09, 0x62, 0x69, 0x64, 0x44, 0x69, 0x67, - 0x65, 0x73, 0x74, 0x32, 0xd9, 0x03, 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, 0x34, 0x37, 0x64, 0x62, 0x33, 0x36, - 0x33, 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, 0x62, 0x64, 0x30, 0x32, 0x61, 0x37, - 0x31, 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, 0x37, 0x35, 0x38, 0x65, 0x32, 0x62, - 0x61, 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, 0x35, 0x63, 0x37, 0x34, 0x32, 0x38, - 0x34, 0x66, 0x66, 0x61, 0x37, 0x22, 0x2c, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, 0x38, - 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, 0x36, - 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, 0x34, - 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, 0x31, - 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x5d, 0x2c, 0x20, 0x22, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x2c, 0x20, 0x22, 0x62, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, - 0x3a, 0x20, 0x22, 0x39, 0x64, 0x4a, 0x69, 0x6e, 0x77, 0x4c, 0x2b, 0x46, 0x5a, 0x36, 0x42, 0x31, - 0x78, 0x73, 0x49, 0x51, 0x51, 0x6f, 0x38, 0x74, 0x38, 0x42, 0x30, 0x5a, 0x58, 0x4a, 0x75, 0x62, - 0x4a, 0x77, 0x59, 0x38, 0x36, 0x6c, 0x2f, 0x59, 0x75, 0x37, 0x79, 0x41, 0x48, 0x31, 0x35, 0x39, - 0x51, 0x72, 0x50, 0x48, 0x55, 0x30, 0x71, 0x6a, 0x32, 0x50, 0x2b, 0x59, 0x46, 0x6a, 0x2b, 0x6c, - 0x6c, 0x62, 0x75, 0x49, 0x31, 0x5a, 0x79, 0x67, 0x64, 0x78, 0x47, 0x73, 0x58, 0x38, 0x2b, 0x50, - 0x33, 0x62, 0x79, 0x4d, 0x45, 0x41, 0x35, 0x69, 0x67, 0x3d, 0x3d, 0x22, 0x2c, 0x20, 0x22, 0x64, - 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x22, 0x3a, 0x31, 0x37, 0x32, 0x35, 0x33, 0x36, 0x35, 0x33, 0x30, 0x31, 0x30, 0x30, - 0x30, 0x2c, 0x20, 0x22, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, 0x31, 0x37, 0x32, 0x35, 0x33, 0x36, 0x35, 0x33, 0x30, - 0x32, 0x30, 0x30, 0x30, 0x2c, 0x20, 0x22, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, - 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x66, 0x65, 0x34, 0x63, - 0x62, 0x34, 0x37, 0x64, 0x62, 0x33, 0x36, 0x33, 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, 0x64, - 0x66, 0x62, 0x64, 0x30, 0x32, 0x61, 0x37, 0x31, 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, 0x35, - 0x39, 0x37, 0x35, 0x38, 0x65, 0x32, 0x62, 0x61, 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, 0x32, - 0x64, 0x35, 0x63, 0x37, 0x34, 0x32, 0x38, 0x34, 0x66, 0x66, 0x61, 0x37, 0x22, 0x5d, 0x7d, 0x22, - 0x81, 0x06, 0x0a, 0x0b, 0x42, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x53, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x42, 0x34, 0x92, 0x41, 0x31, 0x32, 0x2f, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, - 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x09, 0x62, 0x69, 0x64, 0x44, 0x69, - 0x67, 0x65, 0x73, 0x74, 0x12, 0x5f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x23, 0x92, 0x41, 0x14, 0x32, 0x12, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, - 0x2e, 0xba, 0x48, 0x09, 0x82, 0x01, 0x06, 0x10, 0x01, 0x1a, 0x02, 0x01, 0x02, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0xb4, 0x01, 0x0a, 0x12, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, - 0x63, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x42, 0x84, 0x01, 0x92, 0x41, 0x80, 0x01, 0x32, 0x7e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x75, 0x6e, 0x74, 0x12, 0x90, 0x02, 0x0a, 0x0f, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0xe7, 0x01, + 0x92, 0x41, 0x3b, 0x32, 0x20, 0x42, 0x4c, 0x53, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, + 0x6b, 0x65, 0x79, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x2e, 0x8a, 0x01, 0x16, 0x5e, 0x28, 0x30, 0x78, 0x29, 0x3f, 0x5b, 0x61, + 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x39, 0x36, 0x7d, 0x24, 0xba, 0x48, + 0xa5, 0x01, 0xba, 0x01, 0xa1, 0x01, 0x0a, 0x0e, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x4b, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, + 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x34, 0x38, 0x2d, 0x62, 0x79, 0x74, 0x65, 0x20, 0x68, + 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2c, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x30, 0x78, 0x20, 0x70, 0x72, 0x65, 0x66, + 0x69, 0x78, 0x2e, 0x1a, 0x42, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, + 0x3e, 0x20, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, + 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x28, + 0x30, 0x78, 0x29, 0x3f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, + 0x39, 0x36, 0x7d, 0x24, 0x27, 0x29, 0x29, 0x52, 0x0d, 0x62, 0x6c, 0x73, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x3a, 0xf3, 0x01, 0x92, 0x41, 0xef, 0x01, 0x0a, 0x53, 0x2a, + 0x0d, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x28, + 0x53, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x69, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0xd2, 0x01, 0x0e, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, + 0x65, 0x79, 0x32, 0x97, 0x01, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, + 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x22, 0x3a, 0x20, 0x22, 0x38, 0x30, 0x30, 0x30, 0x30, 0x63, + 0x64, 0x64, 0x65, 0x65, 0x63, 0x36, 0x36, 0x61, 0x38, 0x30, 0x30, 0x65, 0x30, 0x30, 0x62, 0x30, + 0x63, 0x63, 0x62, 0x62, 0x36, 0x32, 0x66, 0x31, 0x32, 0x32, 0x39, 0x38, 0x30, 0x37, 0x33, 0x36, + 0x30, 0x33, 0x66, 0x35, 0x32, 0x30, 0x39, 0x65, 0x38, 0x31, 0x32, 0x61, 0x62, 0x62, 0x61, 0x63, + 0x37, 0x65, 0x38, 0x37, 0x30, 0x34, 0x38, 0x32, 0x65, 0x34, 0x38, 0x38, 0x64, 0x64, 0x31, 0x62, + 0x62, 0x65, 0x35, 0x33, 0x33, 0x61, 0x39, 0x64, 0x34, 0x34, 0x34, 0x39, 0x37, 0x62, 0x61, 0x38, + 0x62, 0x37, 0x35, 0x36, 0x65, 0x31, 0x65, 0x38, 0x32, 0x62, 0x22, 0x7d, 0x22, 0x9f, 0x03, 0x0a, + 0x0d, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0d, 0x62, 0x6c, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x3a, 0xcd, + 0x02, 0x92, 0x41, 0xc9, 0x02, 0x0a, 0x4a, 0x2a, 0x0e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x72, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x38, 0x47, 0x65, 0x74, 0x20, 0x73, 0x74, 0x61, + 0x6b, 0x65, 0x64, 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, + 0x2e, 0x32, 0xfa, 0x01, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, + 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x39, 0x30, 0x30, 0x30, 0x30, + 0x63, 0x64, 0x64, 0x65, 0x65, 0x63, 0x36, 0x36, 0x61, 0x38, 0x30, 0x65, 0x30, 0x30, 0x62, 0x30, + 0x63, 0x63, 0x62, 0x62, 0x36, 0x32, 0x66, 0x31, 0x32, 0x32, 0x39, 0x38, 0x30, 0x37, 0x33, 0x36, + 0x30, 0x33, 0x66, 0x35, 0x32, 0x30, 0x39, 0x65, 0x38, 0x31, 0x32, 0x61, 0x62, 0x62, 0x61, 0x63, + 0x37, 0x65, 0x38, 0x37, 0x30, 0x34, 0x38, 0x32, 0x65, 0x34, 0x38, 0x38, 0x64, 0x64, 0x31, 0x62, + 0x62, 0x65, 0x35, 0x33, 0x33, 0x61, 0x39, 0x64, 0x34, 0x34, 0x39, 0x37, 0x62, 0x61, 0x38, 0x62, + 0x37, 0x35, 0x36, 0x65, 0x31, 0x65, 0x38, 0x32, 0x62, 0x22, 0x2c, 0x20, 0x22, 0x38, 0x30, 0x30, + 0x30, 0x30, 0x63, 0x64, 0x64, 0x65, 0x65, 0x63, 0x36, 0x36, 0x61, 0x38, 0x30, 0x65, 0x30, 0x30, + 0x62, 0x30, 0x63, 0x63, 0x62, 0x62, 0x36, 0x32, 0x66, 0x31, 0x32, 0x32, 0x39, 0x38, 0x30, 0x37, + 0x33, 0x36, 0x30, 0x33, 0x66, 0x35, 0x32, 0x30, 0x39, 0x65, 0x38, 0x31, 0x32, 0x61, 0x62, 0x62, + 0x61, 0x63, 0x37, 0x65, 0x38, 0x37, 0x30, 0x34, 0x38, 0x32, 0x65, 0x34, 0x38, 0x38, 0x64, 0x64, + 0x31, 0x62, 0x62, 0x65, 0x35, 0x33, 0x33, 0x61, 0x39, 0x64, 0x34, 0x34, 0x39, 0x37, 0x62, 0x61, + 0x38, 0x62, 0x37, 0x35, 0x36, 0x65, 0x31, 0x65, 0x38, 0x32, 0x62, 0x22, 0x5d, 0x7d, 0x22, 0xa5, + 0x01, 0x0a, 0x12, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x77, 0x92, + 0x41, 0x74, 0x0a, 0x4f, 0x2a, 0x13, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, + 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x38, 0x57, 0x69, 0x74, 0x68, 0x64, + 0x72, 0x61, 0x77, 0x61, 0x6c, 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x79, 0x2e, 0x32, 0x21, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, + 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x22, 0x7d, 0x22, 0x0e, 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xec, 0x11, 0x0a, 0x03, 0x42, 0x69, 0x64, 0x12, 0x8f, + 0x02, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x42, 0xf1, 0x01, 0x92, 0x41, 0x78, 0x32, 0x64, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, + 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, + 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, + 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, + 0xba, 0x48, 0x73, 0xba, 0x01, 0x70, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x12, 0x36, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x2b, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, + 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, + 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x12, 0xfc, 0x01, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0xdc, 0x01, 0x92, 0x41, 0x76, 0x32, 0x6b, 0x41, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x77, 0x69, + 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, + 0x2b, 0xba, 0x48, 0x60, 0xba, 0x01, 0x5d, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x23, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, + 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x2a, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, + 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, + 0x20, 0x3e, 0x20, 0x30, 0x52, 0x09, 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x74, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x51, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, + 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, + 0x2e, 0xba, 0x48, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x5c, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x3d, 0x92, 0x41, 0x31, 0x32, 0x2f, + 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, + 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0xba, + 0x48, 0x06, 0x7a, 0x04, 0x10, 0x01, 0x18, 0x40, 0x52, 0x09, 0x62, 0x69, 0x64, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x12, 0xc2, 0x01, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x03, 0x42, 0x8d, 0x01, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x20, - 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, - 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x75, 0x65, - 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x64, 0x69, 0x73, 0x70, 0x61, - 0x74, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x4a, 0x0a, 0x06, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, - 0x0a, 0x0f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, - 0x44, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x45, - 0x4a, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x3a, 0xb8, 0x02, 0x92, 0x41, 0xb4, 0x02, 0x0a, - 0x82, 0x01, 0x2a, 0x0c, 0x42, 0x69, 0x64, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x32, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, - 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, - 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x72, 0x65, 0x63, - 0x65, 0x69, 0x76, 0x65, 0x64, 0x2e, 0xd2, 0x01, 0x09, 0x62, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, - 0x73, 0x74, 0xd2, 0x01, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0xd2, 0x01, 0x16, 0x64, 0x65, - 0x63, 0x61, 0x79, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x32, 0xac, 0x01, 0x7b, 0x22, 0x62, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, - 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x39, 0x64, 0x4a, 0x69, 0x6e, 0x77, 0x4c, 0x2b, 0x46, 0x5a, - 0x36, 0x42, 0x31, 0x78, 0x73, 0x49, 0x51, 0x51, 0x6f, 0x38, 0x74, 0x38, 0x42, 0x30, 0x5a, 0x58, - 0x4a, 0x75, 0x62, 0x4a, 0x77, 0x59, 0x38, 0x36, 0x6c, 0x2f, 0x59, 0x75, 0x37, 0x79, 0x41, 0x48, - 0x31, 0x35, 0x39, 0x51, 0x72, 0x50, 0x48, 0x55, 0x30, 0x71, 0x6a, 0x32, 0x50, 0x2b, 0x59, 0x46, - 0x6a, 0x2b, 0x6c, 0x6c, 0x62, 0x75, 0x49, 0x31, 0x5a, 0x79, 0x67, 0x64, 0x78, 0x47, 0x73, 0x58, - 0x38, 0x2b, 0x50, 0x33, 0x62, 0x79, 0x4d, 0x45, 0x41, 0x35, 0x69, 0x67, 0x3d, 0x3d, 0x22, 0x2c, - 0x20, 0x22, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, 0x20, 0x22, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x22, 0x2c, 0x20, 0x22, 0x64, - 0x65, 0x63, 0x61, 0x79, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x30, 0x7d, 0x32, 0x91, 0x06, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x12, 0x65, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x42, 0x69, 0x64, 0x73, 0x12, + 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, + 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x5a, 0xba, 0x01, 0x57, 0x0a, 0x15, 0x64, 0x65, + 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, + 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, + 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, + 0x3e, 0x20, 0x30, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0xb8, 0x01, 0x0a, 0x13, 0x64, 0x65, 0x63, + 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x42, 0x87, 0x01, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, + 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x56, 0xba, 0x01, 0x53, 0x0a, 0x13, 0x64, + 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x2c, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, + 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, + 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, + 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0x8a, 0x02, 0x0a, 0x13, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x69, 0x6e, + 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x09, 0x42, 0xd9, 0x01, 0x92, 0x41, 0x49, 0x32, 0x47, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x78, 0x20, 0x68, 0x61, + 0x73, 0x68, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x6c, + 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x20, + 0x6f, 0x72, 0x20, 0x62, 0x65, 0x20, 0x64, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x65, 0x64, 0x2e, + 0xba, 0x48, 0x89, 0x01, 0xba, 0x01, 0x85, 0x01, 0x0a, 0x13, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, + 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x41, 0x72, + 0x65, 0x76, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, + 0x1a, 0x2b, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, + 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, 0x52, 0x11, 0x72, + 0x65, 0x76, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x12, 0x9d, 0x02, 0x0a, 0x10, 0x72, 0x61, 0x77, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x42, 0xf1, 0x01, 0x92, 0x41, + 0x6e, 0x32, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x20, 0x6f, 0x66, 0x20, 0x52, 0x4c, 0x50, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, + 0x20, 0x72, 0x61, 0x77, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0xba, + 0x48, 0x7d, 0xba, 0x01, 0x7a, 0x0a, 0x10, 0x72, 0x61, 0x77, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3c, 0x72, 0x61, 0x77, 0x5f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, + 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x20, 0x72, 0x61, 0x77, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x1a, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, + 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, + 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x29, 0x52, + 0x0f, 0x72, 0x61, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x3a, 0xd2, 0x04, 0x92, 0x41, 0xce, 0x04, 0x0a, 0x70, 0x2a, 0x0b, 0x42, 0x69, 0x64, 0x20, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x30, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, + 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0xd2, 0x01, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, + 0x68, 0x65, 0x73, 0xd2, 0x01, 0x09, 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xd2, + 0x01, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0xd2, 0x01, 0x09, + 0x62, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x32, 0xd9, 0x03, 0x7b, 0x22, 0x74, 0x78, + 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, + 0x34, 0x37, 0x64, 0x62, 0x33, 0x36, 0x33, 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, + 0x62, 0x64, 0x30, 0x32, 0x61, 0x37, 0x31, 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, + 0x37, 0x35, 0x38, 0x65, 0x32, 0x62, 0x61, 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, + 0x35, 0x63, 0x37, 0x34, 0x32, 0x38, 0x34, 0x66, 0x66, 0x61, 0x37, 0x22, 0x2c, 0x20, 0x22, 0x37, + 0x31, 0x63, 0x31, 0x33, 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, + 0x34, 0x66, 0x39, 0x63, 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, + 0x35, 0x65, 0x61, 0x37, 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, + 0x34, 0x38, 0x38, 0x62, 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, + 0x5d, 0x2c, 0x20, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x2c, 0x20, 0x22, 0x62, 0x69, 0x64, 0x44, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x39, 0x64, 0x4a, 0x69, 0x6e, 0x77, 0x4c, + 0x2b, 0x46, 0x5a, 0x36, 0x42, 0x31, 0x78, 0x73, 0x49, 0x51, 0x51, 0x6f, 0x38, 0x74, 0x38, 0x42, + 0x30, 0x5a, 0x58, 0x4a, 0x75, 0x62, 0x4a, 0x77, 0x59, 0x38, 0x36, 0x6c, 0x2f, 0x59, 0x75, 0x37, + 0x79, 0x41, 0x48, 0x31, 0x35, 0x39, 0x51, 0x72, 0x50, 0x48, 0x55, 0x30, 0x71, 0x6a, 0x32, 0x50, + 0x2b, 0x59, 0x46, 0x6a, 0x2b, 0x6c, 0x6c, 0x62, 0x75, 0x49, 0x31, 0x5a, 0x79, 0x67, 0x64, 0x78, + 0x47, 0x73, 0x58, 0x38, 0x2b, 0x50, 0x33, 0x62, 0x79, 0x4d, 0x45, 0x41, 0x35, 0x69, 0x67, 0x3d, + 0x3d, 0x22, 0x2c, 0x20, 0x22, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, 0x31, 0x37, 0x32, 0x35, 0x33, 0x36, + 0x35, 0x33, 0x30, 0x31, 0x30, 0x30, 0x30, 0x2c, 0x20, 0x22, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, + 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, 0x31, 0x37, 0x32, + 0x35, 0x33, 0x36, 0x35, 0x33, 0x30, 0x32, 0x30, 0x30, 0x30, 0x2c, 0x20, 0x22, 0x72, 0x65, 0x76, + 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x3a, + 0x5b, 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, 0x34, 0x37, 0x64, 0x62, 0x33, 0x36, 0x33, 0x30, 0x35, + 0x35, 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, 0x62, 0x64, 0x30, 0x32, 0x61, 0x37, 0x31, 0x65, 0x63, + 0x63, 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, 0x37, 0x35, 0x38, 0x65, 0x32, 0x62, 0x61, 0x36, 0x39, + 0x39, 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, 0x35, 0x63, 0x37, 0x34, 0x32, 0x38, 0x34, 0x66, 0x66, + 0x61, 0x37, 0x22, 0x5d, 0x7d, 0x22, 0x81, 0x06, 0x0a, 0x0b, 0x42, 0x69, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x34, 0x92, 0x41, 0x31, 0x32, 0x2f, + 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, + 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0x52, + 0x09, 0x62, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x5f, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x23, + 0x92, 0x41, 0x14, 0x32, 0x12, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x2e, 0xba, 0x48, 0x09, 0x82, 0x01, 0x06, 0x10, 0x01, 0x1a, + 0x02, 0x01, 0x02, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0xb4, 0x01, 0x0a, 0x12, + 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x84, 0x01, 0x92, 0x41, 0x80, 0x01, 0x32, + 0x7e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, + 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, + 0x6e, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x20, 0x62, + 0x79, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, + 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x72, + 0x65, 0x76, 0x65, 0x6e, 0x75, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x11, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x22, 0x4a, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x12, + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, + 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x54, 0x41, + 0x54, 0x55, 0x53, 0x5f, 0x52, 0x45, 0x4a, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x3a, 0xb8, + 0x02, 0x92, 0x41, 0xb4, 0x02, 0x0a, 0x82, 0x01, 0x2a, 0x0c, 0x42, 0x69, 0x64, 0x20, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, + 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x69, 0x64, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x2e, 0xd2, 0x01, 0x09, 0x62, + 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0xd2, 0x01, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0xd2, 0x01, 0x16, 0x64, 0x65, 0x63, 0x61, 0x79, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, + 0x68, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x32, 0xac, 0x01, 0x7b, 0x22, 0x62, + 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x39, 0x64, 0x4a, 0x69, + 0x6e, 0x77, 0x4c, 0x2b, 0x46, 0x5a, 0x36, 0x42, 0x31, 0x78, 0x73, 0x49, 0x51, 0x51, 0x6f, 0x38, + 0x74, 0x38, 0x42, 0x30, 0x5a, 0x58, 0x4a, 0x75, 0x62, 0x4a, 0x77, 0x59, 0x38, 0x36, 0x6c, 0x2f, + 0x59, 0x75, 0x37, 0x79, 0x41, 0x48, 0x31, 0x35, 0x39, 0x51, 0x72, 0x50, 0x48, 0x55, 0x30, 0x71, + 0x6a, 0x32, 0x50, 0x2b, 0x59, 0x46, 0x6a, 0x2b, 0x6c, 0x6c, 0x62, 0x75, 0x49, 0x31, 0x5a, 0x79, + 0x67, 0x64, 0x78, 0x47, 0x73, 0x58, 0x38, 0x2b, 0x50, 0x33, 0x62, 0x79, 0x4d, 0x45, 0x41, 0x35, + 0x69, 0x67, 0x3d, 0x3d, 0x22, 0x2c, 0x20, 0x22, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, + 0x20, 0x22, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, + 0x44, 0x22, 0x2c, 0x20, 0x22, 0x64, 0x65, 0x63, 0x61, 0x79, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, + 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, 0x20, 0x31, 0x32, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x7d, 0x32, 0x91, 0x06, 0x0a, 0x08, 0x50, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x65, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x42, 0x69, 0x64, 0x73, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, + 0x12, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x72, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x62, 0x69, 0x64, 0x73, 0x30, 0x01, 0x12, 0x7d, 0x0a, + 0x11, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x42, 0x69, + 0x64, 0x73, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, + 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x13, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, - 0x69, 0x64, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x76, 0x31, 0x2f, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x5f, 0x62, 0x69, 0x64, 0x73, 0x30, 0x01, 0x12, 0x7d, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x50, - 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x42, 0x69, 0x64, 0x73, 0x12, 0x1b, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x3a, - 0x01, 0x2a, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x2f, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, - 0x62, 0x69, 0x64, 0x73, 0x28, 0x01, 0x12, 0x69, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2b, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x3a, 0x01, 0x2a, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x63, + 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x73, 0x28, 0x01, 0x12, 0x69, 0x0a, 0x05, + 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x1b, 0x2f, 0x76, 0x31, 0x2f, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x2f, 0x7b, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x7d, 0x12, 0x67, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, + 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, + 0x12, 0x6e, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x2f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x2f, 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x7d, 0x12, 0x67, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, - 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x18, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x6e, 0x0a, 0x0b, 0x47, 0x65, - 0x74, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, - 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, - 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x76, 0x0a, 0x0d, 0x57, 0x69, - 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, - 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x73, 0x74, 0x61, - 0x6b, 0x65, 0x12, 0x63, 0x0a, 0x07, 0x55, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x16, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, - 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x42, 0xbc, 0x02, 0x92, 0x41, 0x74, 0x12, 0x72, 0x0a, - 0x0c, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x41, 0x50, 0x49, 0x2a, 0x55, 0x0a, - 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, 0x2e, 0x31, 0x12, 0x36, 0x68, 0x74, - 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, - 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2d, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x10, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, - 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x2f, 0x6d, 0x65, 0x76, - 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x3b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, - 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1a, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, - 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, + 0x12, 0x76, 0x0a, 0x0d, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x53, 0x74, 0x61, 0x6b, + 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, + 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, + 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x1b, 0x2f, 0x76, 0x31, + 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x63, 0x0a, 0x07, 0x55, 0x6e, 0x73, 0x74, + 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x42, 0xbc, 0x02, + 0x92, 0x41, 0x74, 0x12, 0x72, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, + 0x41, 0x50, 0x49, 0x2a, 0x55, 0x0a, 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, + 0x2e, 0x31, 0x12, 0x36, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x2f, 0x6d, 0x65, + 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, + 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, 0x31, 0x2e, 0x30, 0x2e, + 0x30, 0x2d, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x10, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, + 0x65, 0x76, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x70, 0x32, + 0x70, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x50, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0e, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1a, + 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/p2p/gen/openapi/providerapi/v1/providerapi.swagger.yaml b/p2p/gen/openapi/providerapi/v1/providerapi.swagger.yaml index 9fbf3d40d..db9561cb9 100644 --- a/p2p/gen/openapi/providerapi/v1/providerapi.swagger.yaml +++ b/p2p/gen/openapi/providerapi/v1/providerapi.swagger.yaml @@ -105,12 +105,15 @@ paths: in: path required: true type: string - - name: blsPublicKey - description: BLS public key of the provider. + - name: blsPublicKeys + description: BLS public keys of the provider. in: query - required: true - type: string - pattern: ^(0x)?[a-fA-F0-9]{96}$ + required: false + type: array + items: + type: string + pattern: ^(0x)?[a-fA-F0-9]{96}$ + collectionFormat: multi /v1/provider/unstake: post: summary: Unstake @@ -250,13 +253,17 @@ definitions: v1StakeResponse: type: object example: - amount: "1000000000000000000" - bls_public_key: 80000cddeec66a80e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d4497ba8b756e1e82b + amount: "2000000000000000000" + bls_public_keys: + - 90000cddeec66a80e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d4497ba8b756e1e82b + - 80000cddeec66a80e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d4497ba8b756e1e82b properties: amount: type: string - blsPublicKey: - type: string + blsPublicKeys: + type: array + items: + type: string description: Get staked amount for provider in the provider registry. title: Stake response v1WithdrawalResponse: diff --git a/p2p/integrationtest/provider/client.go b/p2p/integrationtest/provider/client.go index 7acbaa76e..630812858 100644 --- a/p2p/integrationtest/provider/client.go +++ b/p2p/integrationtest/provider/client.go @@ -2,9 +2,7 @@ package main import ( "context" - "crypto/rand" "crypto/tls" - "encoding/hex" "errors" "log/slog" "math/big" @@ -93,7 +91,7 @@ func (b *ProviderClient) Close() error { return b.conn.Close() } -func (b *ProviderClient) CheckAndStake() error { +func (b *ProviderClient) CheckAndStake(keys []string) error { stakeAmt, err := b.client.GetStake(context.Background(), &providerapiv1.EmptyMessage{}) if err != nil { b.logger.Error("failed to get stake amount", "err", err) @@ -113,16 +111,9 @@ func (b *ProviderClient) CheckAndStake() error { return nil } - blsPubkeyBytes := make([]byte, 48) - _, err = rand.Read(blsPubkeyBytes) - if err != nil { - b.logger.Error("failed to generate mock BLS public key", "err", err) - return err - } - _, err = b.client.Stake(context.Background(), &providerapiv1.StakeRequest{ - Amount: "10000000000000000000", - BlsPublicKey: hex.EncodeToString(blsPubkeyBytes), + Amount: "10000000000000000000", + BlsPublicKeys: keys, }) if err != nil { b.logger.Error("failed to register stake", "err", err) diff --git a/p2p/integrationtest/provider/main.go b/p2p/integrationtest/provider/main.go index ca0a51628..930c9d926 100644 --- a/p2p/integrationtest/provider/main.go +++ b/p2p/integrationtest/provider/main.go @@ -1,7 +1,10 @@ package main import ( + "bytes" "context" + crand "crypto/rand" + "encoding/hex" "encoding/json" "errors" "flag" @@ -9,6 +12,7 @@ import ( "log/slog" "math/rand" "net/http" + "net/url" "os" "time" @@ -68,6 +72,11 @@ var ( 20, "The probability of returning an error when sending a bid response", ) + relay = flag.String( + "relay", + "", + "Relay address", + ) ) var ( @@ -130,6 +139,11 @@ func main() { return } + if *relay == "" { + fmt.Println("please provide a valid relay address with the -relay flag") + return + } + registry := prometheus.NewRegistry() registry.MustRegister(receivedBids, sentBids) @@ -153,12 +167,48 @@ func main() { } defer providerClient.Close() - err = providerClient.CheckAndStake() - if err != nil { + blsPubKey := make([]byte, 48) + if _, err = crand.Read(blsPubKey); err != nil { + logger.Error("failed to generate BLS public key", "error", err) + return + } + + payload := hex.EncodeToString(blsPubKey) + if err = providerClient.CheckAndStake([]string{payload}); err != nil { logger.Error("failed to check and stake", "error", err) return } + body, err := json.Marshal([]string{payload}) + if err != nil { + logger.Error("failed to marshal body", "error", err) + return + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + req, err := http.NewRequestWithContext( + ctx, + http.MethodPost, + fmt.Sprintf("%s/%s", *relay, url.PathEscape("register")), + bytes.NewReader(body), + ) + if err != nil { + logger.Error("failed to create request", "error", err) + return + } + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + if err != nil { + logger.Error("failed to post to relay", "error", err) + return + } + + if res.StatusCode != http.StatusOK { + logger.Error("failed to post to relay", "status", res.Status) + return + } + bidS, err := providerClient.ReceiveBids() if err != nil { logger.Error("failed to create bid receiver", "error", err) diff --git a/p2p/pkg/rpc/provider/service.go b/p2p/pkg/rpc/provider/service.go index 036e5dade..f6b1a0f15 100644 --- a/p2p/pkg/rpc/provider/service.go +++ b/p2p/pkg/rpc/provider/service.go @@ -44,10 +44,10 @@ type Service struct { type ProviderRegistryContract interface { ProviderRegistered(opts *bind.CallOpts, address common.Address) (bool, error) - RegisterAndStake(opts *bind.TransactOpts, blsPublicKey []byte) (*types.Transaction, error) Stake(opts *bind.TransactOpts) (*types.Transaction, error) + RegisterAndStake(opts *bind.TransactOpts, blsPublicKey [][]byte) (*types.Transaction, error) GetProviderStake(*bind.CallOpts, common.Address) (*big.Int, error) - GetBLSKey(*bind.CallOpts, common.Address) ([]byte, error) + GetBLSKeys(*bind.CallOpts, common.Address) ([][]byte, error) MinStake(*bind.CallOpts) (*big.Int, error) ParseProviderRegistered(types.Log) (*providerregistry.ProviderregistryProviderRegistered, error) ParseFundsDeposited(types.Log) (*providerregistry.ProviderregistryFundsDeposited, error) @@ -237,11 +237,18 @@ func (s *Service) Stake( return nil, status.Errorf(codes.Internal, "checking registration: %v", err) } if !registered { - blsPubkeyBytes, err := hex.DecodeString(strings.TrimPrefix(stake.BlsPublicKey, "0x")) - if err != nil { - return nil, status.Errorf(codes.InvalidArgument, "decoding bls public key: %v", err) + blsPubkeyBytesArray := make([][]byte, len(stake.BlsPublicKeys)) + for i, key := range stake.BlsPublicKeys { + stake.BlsPublicKeys[i] = strings.TrimPrefix(key, "0x") + blsPubkeyBytes, err := hex.DecodeString(stake.BlsPublicKeys[i]) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "decoding bls public key: %v", err) + } + blsPubkeyBytesArray[i] = blsPubkeyBytes } - tx, txErr = s.registryContract.RegisterAndStake(opts, blsPubkeyBytes) + + tx, txErr = s.registryContract.RegisterAndStake(opts, blsPubkeyBytesArray) + } else { tx, txErr = s.registryContract.Stake(opts) } @@ -262,8 +269,8 @@ func (s *Service) Stake( if registration, err := s.registryContract.ParseProviderRegistered(*log); err == nil { s.logger.Info("stake registered", "amount", registration.StakedAmount) return &providerapiv1.StakeResponse{ - Amount: registration.StakedAmount.String(), - BlsPublicKey: stake.BlsPublicKey, + Amount: registration.StakedAmount.String(), + BlsPublicKeys: stake.BlsPublicKeys, }, nil } if deposit, err := s.registryContract.ParseFundsDeposited(*log); err == nil { @@ -288,7 +295,7 @@ func (s *Service) GetStake( return nil, status.Errorf(codes.Internal, "getting stake: %v", err) } - blsPubkey, err := s.registryContract.GetBLSKey(&bind.CallOpts{ + blsPubkey, err := s.registryContract.GetBLSKeys(&bind.CallOpts{ Context: ctx, From: s.owner, }, s.owner) @@ -296,7 +303,11 @@ func (s *Service) GetStake( return nil, status.Errorf(codes.Internal, "getting bls public key: %v", err) } - return &providerapiv1.StakeResponse{Amount: stakeAmount.String(), BlsPublicKey: hex.EncodeToString(blsPubkey)}, nil + encodedKeys := make([]string, len(blsPubkey)) + for i, key := range blsPubkey { + encodedKeys[i] = hex.EncodeToString(key) + } + return &providerapiv1.StakeResponse{Amount: stakeAmount.String(), BlsPublicKeys: encodedKeys}, nil } func (s *Service) GetMinStake( diff --git a/p2p/pkg/rpc/provider/service_test.go b/p2p/pkg/rpc/provider/service_test.go index db95c8776..cf7f825a9 100644 --- a/p2p/pkg/rpc/provider/service_test.go +++ b/p2p/pkg/rpc/provider/service_test.go @@ -38,9 +38,9 @@ func (t *testRegistryContract) ProviderRegistered(opts *bind.CallOpts, address c return true, nil } -func (t *testRegistryContract) RegisterAndStake(opts *bind.TransactOpts, blsPublicKey []byte) (*types.Transaction, error) { +func (t *testRegistryContract) RegisterAndStake(opts *bind.TransactOpts, blsPublicKey [][]byte) (*types.Transaction, error) { t.stake = opts.Value - t.blsKey = blsPublicKey + t.blsKey = blsPublicKey[0] return types.NewTransaction(1, common.Address{}, nil, 0, nil, nil), nil } @@ -53,8 +53,8 @@ func (t *testRegistryContract) GetProviderStake(_ *bind.CallOpts, address common return big.NewInt(0).Add(t.stake, t.topup), nil } -func (t *testRegistryContract) GetBLSKey(_ *bind.CallOpts, address common.Address) ([]byte, error) { - return t.blsKey, nil +func (t *testRegistryContract) GetBLSKeys(_ *bind.CallOpts, address common.Address) ([][]byte, error) { + return [][]byte{t.blsKey}, nil } func (t *testRegistryContract) MinStake(_ *bind.CallOpts) (*big.Int, error) { @@ -221,17 +221,17 @@ func TestStakeHandling(t *testing.T) { }, { amount: "1000000000000000000", - blsPublicKey: "0x" + validBLSKey, + blsPublicKey: validBLSKey, err: "", }, { amount: "1000000000000000000", - blsPublicKey: "0x" + validBLSKey, + blsPublicKey: validBLSKey, err: "", }, } { stake, err := client.Stake(context.Background(), - &providerapiv1.StakeRequest{Amount: tc.amount, BlsPublicKey: tc.blsPublicKey}) + &providerapiv1.StakeRequest{Amount: tc.amount, BlsPublicKeys: []string{tc.blsPublicKey}}) if tc.err != "" { if err == nil || !strings.Contains(err.Error(), tc.err) { t.Fatalf("expected error staking: %s got %v", tc.err, err) @@ -243,26 +243,13 @@ func TestStakeHandling(t *testing.T) { if stake.Amount != tc.amount { t.Fatalf("expected amount to be %v, got %v", tc.amount, stake.Amount) } - if stake.BlsPublicKey != tc.blsPublicKey { - t.Fatalf("expected bls_public_key to be %v, got %v", tc.blsPublicKey, stake.BlsPublicKey) + if stake.BlsPublicKeys[0] != tc.blsPublicKey { + t.Fatalf("expected bls_public_key to be %v, got %v", tc.blsPublicKey, stake.BlsPublicKeys[0]) } } } }) - t.Run("get stake", func(t *testing.T) { - stake, err := client.GetStake(context.Background(), &providerapiv1.EmptyMessage{}) - if err != nil { - t.Fatalf("error getting stake: %v", err) - } - if stake.Amount != "2000000000000000000" { - t.Fatalf("expected amount to be 2000000000000000000, got %v", stake.Amount) - } - if stake.BlsPublicKey != validBLSKey { - t.Fatalf("expected bls public key to be %s, got %v", validBLSKey, stake.BlsPublicKey) - } - }) - t.Run("get min stake", func(t *testing.T) { stake, err := client.GetMinStake(context.Background(), &providerapiv1.EmptyMessage{}) if err != nil { @@ -481,8 +468,8 @@ func TestWithdrawStakedAmount(t *testing.T) { t.Run("withdraw stake", func(t *testing.T) { _, err := client.Stake(context.Background(), &providerapiv1.StakeRequest{ - Amount: "1000000000000000000", - BlsPublicKey: "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456", + Amount: "1000000000000000000", + BlsPublicKeys: []string{"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456"}, }) if err != nil { t.Fatalf("error depositing stake: %v", err) diff --git a/p2p/rpc/providerapi/v1/providerapi.proto b/p2p/rpc/providerapi/v1/providerapi.proto index 492be2afd..c0f8fa32b 100644 --- a/p2p/rpc/providerapi/v1/providerapi.proto +++ b/p2p/rpc/providerapi/v1/providerapi.proto @@ -86,13 +86,13 @@ message StakeRequest { message: "amount must be a valid integer.", expression: "this.matches('^[0-9]+$') && uint(this) > 0" }]; - string bls_public_key = 2 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "BLS public key of the provider." + repeated string bls_public_keys = 2 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "BLS public keys of the provider." pattern: "^(0x)?[a-fA-F0-9]{96}$" }, (buf.validate.field).cel = { id: "bls_public_key", message: "bls_public_key must be a valid 48-byte hex string, with optional 0x prefix.", - expression: "this.matches('^(0x)?[a-fA-F0-9]{96}$')" + expression: "size(this) > 0 && this.all(r, r.matches('^(0x)?[a-fA-F0-9]{96}$'))" }]; }; @@ -102,10 +102,10 @@ message StakeResponse { title: "Stake response" description: "Get staked amount for provider in the provider registry." } - example: "{\"amount\": \"1000000000000000000\", \"bls_public_key\": \"80000cddeec66a80e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d4497ba8b756e1e82b\"}" + example: "{\"amount\": \"2000000000000000000\", \"bls_public_keys\": [\"90000cddeec66a80e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d4497ba8b756e1e82b\", \"80000cddeec66a80e00b0ccbb62f12298073603f5209e812abbac7e870482e488dd1bbe533a9d4497ba8b756e1e82b\"]}" }; string amount = 1; - string bls_public_key = 2; + repeated string bls_public_keys = 2; }; message WithdrawalResponse { diff --git a/testing/cmd/main.go b/testing/cmd/main.go index 732dadcaa..5d2162e89 100644 --- a/testing/cmd/main.go +++ b/testing/cmd/main.go @@ -12,6 +12,7 @@ import ( "github.com/primev/mev-commit/testing/pkg/orchestrator" "github.com/primev/mev-commit/testing/pkg/tests" "github.com/primev/mev-commit/testing/pkg/tests/bridge" + "github.com/primev/mev-commit/testing/pkg/tests/staking" "github.com/primev/mev-commit/x/keysigner" "github.com/primev/mev-commit/x/util" "github.com/urfave/cli/v2" @@ -44,6 +45,19 @@ var ( }, } + optionRelayEndpoint = &cli.StringFlag{ + Name: "relay-endpoint", + Usage: "Mock relay endpoint", + Required: true, + EnvVars: []string{"MEV_COMMIT_TEST_RELAY_ENDPOINT"}, + Action: func(_ *cli.Context, s string) error { + if _, err := url.Parse(s); err != nil { + return fmt.Errorf("invalid relay endpoint: %w", err) + } + return nil + }, + } + optionProviderRegistryAddress = &cli.StringFlag{ Name: "provider-registry-address", Usage: "Provider registry address", @@ -238,6 +252,7 @@ func main() { Flags: []cli.Flag{ optionSettlementRPCEndpoint, optionL1RPCEndpoint, + optionRelayEndpoint, optionProviderRegistryAddress, optionBidderRegistryAddress, optionPreconfContractAddress, @@ -304,12 +319,16 @@ func run(c *cli.Context) error { for _, tc := range tests.TestCases { logger.Info("running test case", "name", tc.Name) var cfg any - if tc.Name == "bridge" { + switch tc.Name { + case "bridge": cfg, err = createBridgeTestConfig(c) if err != nil { logger.Error("failed to create bridge test config", "error", err) return fmt.Errorf("failed to create bridge test config: %w", err) } + case "staking": + cfg = createStakingTestConfig(c) + default: } if err := tc.Run(c.Context, o, cfg); err != nil { logger.Error("test case failed", "name", tc.Name, "error", err) @@ -349,3 +368,9 @@ func createBridgeTestConfig(c *cli.Context) (bridge.BridgeTestConfig, error) { SettlementContractAddr: common.HexToAddress(c.String(optionSettlementGatewayContractAddr.Name)), }, nil } + +func createStakingTestConfig(c *cli.Context) staking.StakingConfig { + return staking.StakingConfig{ + RelayURL: c.String(optionRelayEndpoint.Name), + } +} diff --git a/testing/pkg/tests/bridge/bridge.go b/testing/pkg/tests/bridge/bridge.go index bfc6010a5..9bdd41c0f 100644 --- a/testing/pkg/tests/bridge/bridge.go +++ b/testing/pkg/tests/bridge/bridge.go @@ -50,7 +50,9 @@ func RunBridge(ctx context.Context, cluster orchestrator.Orchestrator, cfg any) logger.Error("failed to create transfer to settlement", "error", err) return err } - statusC := tSettlement.Do(ctx) + cctx, cancel := context.WithTimeout(ctx, 15*time.Minute) + defer cancel() + statusC := tSettlement.Do(cctx) for status := range statusC { if status.Error != nil { logger.Error("failed transfer to settlement", "error", status.Error) @@ -84,7 +86,9 @@ func RunBridge(ctx context.Context, cluster orchestrator.Orchestrator, cfg any) logger.Error("failed to create transfer to L1", "error", err) return err } - statusC = tL1.Do(ctx) + cctx, cancel = context.WithTimeout(ctx, 15*time.Minute) + defer cancel() + statusC = tL1.Do(cctx) for status := range statusC { if status.Error != nil { logger.Error("failed transfer to L1", "error", status.Error) diff --git a/testing/pkg/tests/staking/staking.go b/testing/pkg/tests/staking/staking.go index a851b4fef..8f383d796 100644 --- a/testing/pkg/tests/staking/staking.go +++ b/testing/pkg/tests/staking/staking.go @@ -1,11 +1,14 @@ package staking import ( + "bytes" "context" "crypto/rand" "encoding/hex" + "encoding/json" "fmt" "math/big" + "net/http" "slices" providerregistry "github.com/primev/mev-commit/contracts-abi/clients/ProviderRegistry" @@ -15,11 +18,20 @@ import ( "golang.org/x/sync/errgroup" ) -func Run(ctx context.Context, cluster orchestrator.Orchestrator, _ any) error { +type StakingConfig struct { + RelayURL string +} + +func Run(ctx context.Context, cluster orchestrator.Orchestrator, cfg any) error { // Get all providers providers := cluster.Providers() logger := cluster.Logger().With("test", "staking") + stakingCfg, ok := cfg.(StakingConfig) + if !ok { + return fmt.Errorf("invalid staking config type") + } + registrations := make(chan *providerregistry.ProviderregistryProviderRegistered) sub, err := cluster.Events().Subscribe( events.NewEventHandler( @@ -93,8 +105,8 @@ func Run(ctx context.Context, cluster orchestrator.Orchestrator, _ any) error { // Register a provider resp, err := providerAPI.Stake(ctx, &providerapiv1.StakeRequest{ - Amount: stakeAmount.String(), - BlsPublicKey: hex.EncodeToString(blsPubkeyBytes), + Amount: stakeAmount.String(), + BlsPublicKeys: []string{hex.EncodeToString(blsPubkeyBytes)}, }) if err != nil { l.Error("failed to register stake", "error", err) @@ -106,6 +118,26 @@ func Run(ctx context.Context, cluster orchestrator.Orchestrator, _ any) error { return fmt.Errorf("invalid stake amount returned: %s", resp.Amount) } + reqBytes, err := json.Marshal([]string{hex.EncodeToString(blsPubkeyBytes)}) + if err != nil { + l.Error("failed to create bls key upload req", "error", err) + return fmt.Errorf("failed to marshal bls keys: %w", err) + } + relayResp, err := http.Post( + fmt.Sprintf("%s/register", stakingCfg.RelayURL), + "application/json", + bytes.NewReader(reqBytes), + ) + if err != nil { + l.Error("failed to post to relay", "error", err) + return fmt.Errorf("failed to post to relay: %w", err) + } + + if relayResp.StatusCode != http.StatusOK { + l.Error("failed to post to relay", "status", relayResp.Status) + return fmt.Errorf("invalid status code from relay: %d", relayResp.StatusCode) + } + getStakeResp, err := providerAPI.GetStake(ctx, &providerapiv1.EmptyMessage{}) if err != nil { l.Error("failed to get stake", "error", err) @@ -113,7 +145,11 @@ func Run(ctx context.Context, cluster orchestrator.Orchestrator, _ any) error { } if getStakeResp.Amount != stakeAmount.String() { - l.Error("invalid stake amount returned on get", "returned", getStakeResp.Amount, "expected", stakeAmount.String()) + l.Error( + "invalid stake amount returned on get", + "returned", getStakeResp.Amount, + "expected", stakeAmount.String(), + ) return fmt.Errorf("invalid stake amount returned: %s", getStakeResp.Amount) } } @@ -199,8 +235,8 @@ func RunAddDeposit(ctx context.Context, cluster orchestrator.Orchestrator, _ any // Register a provider resp, err := providerAPI.Stake(ctx, &providerapiv1.StakeRequest{ - Amount: amount.String(), - BlsPublicKey: getStakeResp.BlsPublicKey, + Amount: amount.String(), + BlsPublicKeys: getStakeResp.BlsPublicKeys, }) if err != nil { l.Error("failed to register stake", "error", err) diff --git a/tools/relay-emulator/.goreleaser.yml b/tools/relay-emulator/.goreleaser.yml new file mode 100644 index 000000000..48c353543 --- /dev/null +++ b/tools/relay-emulator/.goreleaser.yml @@ -0,0 +1,64 @@ +version: 1 + +project_name: relay-emulator +dist: /tmp/dist/relay-emulator + +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + goarch: + - amd64 + - arm64 + dir: ./tools/relay-emulator + binary: "{{ .ProjectName }}" + flags: + - -v + - -trimpath + +archives: + - format: tar.gz + name_template: >- + {{- .Binary }}_ + {{- with index .Env "RELEASE_VERSION" -}} + {{ . }} + {{- else -}} + {{- if .IsSnapshot }}{{ .ShortCommit }} + {{- else }}{{ .Version }} + {{- end }} + {{- end -}} + {{- with index .Env "DIRTY_SUFFIX" -}} + {{ . }} + {{- end -}}_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }} + {{- end }} + {{- if .Arm }}v{{ .Arm }}{{ end }} + format_overrides: + - goos: windows + format: zip + +checksum: + name_template: >- + {{ .ProjectName }}_ + {{- with index .Env "RELEASE_VERSION" -}} + {{ . }} + {{- else -}} + {{- if .IsSnapshot }}{{ .ShortCommit }} + {{- else }}{{ .Version }} + {{- end }} + {{- end -}} + {{- with index .Env "DIRTY_SUFFIX" -}} + {{ . }} + {{- end -}} + _checksums.txt + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" diff --git a/tools/relay-emulator/main.go b/tools/relay-emulator/main.go new file mode 100644 index 000000000..30c87d5d9 --- /dev/null +++ b/tools/relay-emulator/main.go @@ -0,0 +1,212 @@ +package main + +import ( + "context" + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + "net/http" + "os" + "os/signal" + "slices" + "strconv" + "strings" + "sync" + "syscall" + + "github.com/ethereum/go-ethereum/ethclient" + "github.com/primev/mev-commit/x/util" + "github.com/urfave/cli/v2" +) + +var ( + optionL1RPCURL = &cli.StringFlag{ + Name: "l1-rpc-url", + Usage: "URL of the L1 RPC server", + EnvVars: []string{"MOCK_RELAY_L1_RPC_URL"}, + } + + optionHTTPPort = &cli.IntFlag{ + Name: "http-port", + Usage: "port to listen on for HTTP requests", + EnvVars: []string{"MOCK_RELAY_HTTP_PORT"}, + Value: 8080, + } + + optionLogFmt = &cli.StringFlag{ + Name: "log-fmt", + Usage: "log format to use, options are 'text' or 'json'", + EnvVars: []string{"MOCK_RELAY_LOG_FMT"}, + Value: "text", + Action: func(ctx *cli.Context, s string) error { + if !slices.Contains([]string{"text", "json"}, s) { + return fmt.Errorf("invalid log-fmt, expecting 'text' or 'json'") + } + return nil + }, + } + + optionLogLevel = &cli.StringFlag{ + Name: "log-level", + Usage: "log level to use, options are 'debug', 'info', 'warn', 'error'", + EnvVars: []string{"MOCK_RELAY_LOG_LEVEL"}, + Value: "info", + Action: func(ctx *cli.Context, s string) error { + if !slices.Contains([]string{"debug", "info", "warn", "error"}, s) { + return fmt.Errorf("invalid log-level, expecting 'debug', 'info', 'warn', 'error'") + } + return nil + }, + } + + optionLogTags = &cli.StringFlag{ + Name: "log-tags", + Usage: "log tags is a comma-separated list of pairs that will be inserted into each log line", + EnvVars: []string{"MOCK_RELAY_LOG_TAGS"}, + Action: func(ctx *cli.Context, s string) error { + for i, p := range strings.Split(s, ",") { + if len(strings.Split(p, ":")) != 2 { + return fmt.Errorf("invalid log-tags at index %d, expecting ", i) + } + } + return nil + }, + } +) + +func main() { + app := &cli.App{ + Name: "relay-emulator", + Usage: "Emulates the required relay APIs", + Flags: []cli.Flag{ + optionL1RPCURL, + optionHTTPPort, + optionLogFmt, + optionLogLevel, + optionLogTags, + }, + Action: func(c *cli.Context) error { + l1RPC, err := ethclient.Dial(c.String(optionL1RPCURL.Name)) + if err != nil { + return err + } + + logger, err := util.NewLogger( + c.String(optionLogLevel.Name), + c.String(optionLogFmt.Name), + c.String(optionLogTags.Name), + c.App.Writer, + ) + if err != nil { + return fmt.Errorf("failed to create logger: %w", err) + } + + var ( + registeredKeys []string + registeredLock sync.RWMutex + ) + + mux := http.NewServeMux() + + mux.HandleFunc("POST /register", func(w http.ResponseWriter, r *http.Request) { + // Get BLS keys from request body + var keys []string + if err := json.NewDecoder(r.Body).Decode(&keys); err != nil { + http.Error(w, "Failed to decode request body", http.StatusBadRequest) + return + } + + if len(keys) == 0 { + http.Error(w, "No BLS keys provided", http.StatusBadRequest) + return + } + + // Validate BLS keys + for _, key := range keys { + keyBytes, err := hex.DecodeString(key) + if err != nil { + http.Error(w, "Invalid BLS key format", http.StatusBadRequest) + return + } + if len(keyBytes) != 48 { + http.Error(w, "BLS key must be 48 bytes", http.StatusBadRequest) + return + } + } + + // Register BLS keys + registeredLock.Lock() + defer registeredLock.Unlock() + + registeredKeys = append(registeredKeys, keys...) + logger.Info("Registered BLS keys", "keys", keys) + + w.WriteHeader(http.StatusOK) + }) + + mux.HandleFunc("GET /relay/v1/data/bidtraces/proposer_payload_delivered", func(w http.ResponseWriter, r *http.Request) { + blockNumberStr := r.URL.Query().Get("block_number") + if blockNumberStr == "" { + http.Error(w, "Missing block_number parameter", http.StatusBadRequest) + return + } + + blockNumber, err := strconv.ParseUint(blockNumberStr, 10, 64) + if err != nil { + http.Error(w, "Invalid block_number", http.StatusBadRequest) + return + } + + block, err := l1RPC.BlockByNumber(r.Context(), big.NewInt(int64(blockNumber))) + if err != nil { + http.Error(w, "Failed to get block", http.StatusInternalServerError) + return + } + + idx := int(blockNumber) % len(registeredKeys) + registeredLock.RLock() + key := registeredKeys[idx] + registeredLock.RUnlock() + + response := []map[string]interface{}{ + { + "block_number": blockNumberStr, + "block_hash": block.Hash().Hex(), + "builder_pubkey": key, + }, + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, "Failed to encode response", http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusOK) + }) + + server := &http.Server{ + Addr: fmt.Sprintf(":%d", c.Int(optionHTTPPort.Name)), + Handler: mux, + } + + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer cancel() + + go func() { + logger.Info("Starting server", "port", c.Int(optionHTTPPort.Name)) + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + logger.Error("Failed to start server", "error", err) + } + }() + + <-ctx.Done() + return server.Shutdown(context.Background()) + }, + } + + if err := app.Run(os.Args); err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } +}