From ef5d78922e08d8b815814df419d03e0561c1e974 Mon Sep 17 00:00:00 2001 From: Victor Elias Date: Wed, 27 Mar 2024 15:57:51 -0300 Subject: [PATCH 01/39] eth,eth/watcher: Create Chainlink price feed watcher (#2972) * eth/watchers: Create PriceFeed watcher Makefile: Use mockgen binary from tool dependencies eth/contracts: Add chainlink interfaces source Makefile: Generate Chainlink contracts ABI tools: Add abigen tool to repo eth/contracts: Generate chainlink bindings Makefile: Fix abigen bindings generation Revert everything abigen Turns out there's already bindings exported from the Chainlink lib. go.mod: Add chainlink library eth/watchers: Add pricefeed watcher eth/watchers: Clean-up event watching code eth/watchers: Improve price tracking Revert "go.mod: Add chainlink library" This reverts commit ac415bd8fb210088874e7fdea8d37ac4dad81dab. Revert "Revert everything abigen" This reverts commit b7c40b1e936c885aad973f28d87d42b0d85cb0e4. eth/contracts: Gen bindings for proxy iface eth/watchers: Use local bindings for contracts eth/watchers: Simplify event subs logic eth/watchers: Simplify&optimize truncated ticker eth/watchers: Update decimals on fetch eth/watchers: Improve handling of decimals eth/watchers: Fix price rat creation eth/watchers: Make sure we use UTC on truncated timer eth/contracts/chainlink: Generate only V3 contract bindings eth/watchers: Watch PriceFeed only with polling eth/watchers: Add a retry logic on price update eth/watchers: Use clog instead of fmt.Printf * eth: Create separate pricefeed client unit This will make the code more testable. * eth: Add tests for pricefeed client * eth/watchers: Add tests to the truncated ticker Gosh that was much harder than I thought * eth/watchers: Add tests for pricefeedwatcher * eth: Add comments to the new components * go fmt * eth: Address minor review comments * eth,eth/watchers: Improve pricefeed watcher interface * eth/watchers: Remove truncated ticker tests --- Makefile | 18 +- .../chainlink/AggregatorV3Interface.abi | 1 + .../chainlink/AggregatorV3Interface.go | 394 ++++++++++++++++++ .../chainlink/AggregatorV3Interface.sol | 36 ++ eth/pricefeed.go | 78 ++++ eth/pricefeed_test.go | 51 +++ eth/watchers/pricefeedwatcher.go | 182 ++++++++ eth/watchers/pricefeedwatcher_test.go | 216 ++++++++++ go.mod | 36 +- go.sum | 225 +++++++++- tools.go | 9 + 11 files changed, 1240 insertions(+), 6 deletions(-) create mode 100644 eth/contracts/chainlink/AggregatorV3Interface.abi create mode 100644 eth/contracts/chainlink/AggregatorV3Interface.go create mode 100644 eth/contracts/chainlink/AggregatorV3Interface.sol create mode 100644 eth/pricefeed.go create mode 100644 eth/pricefeed_test.go create mode 100644 eth/watchers/pricefeedwatcher.go create mode 100644 eth/watchers/pricefeedwatcher_test.go create mode 100644 tools.go diff --git a/Makefile b/Makefile index db8026968a..d57d7ffc96 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,10 @@ SHELL=/bin/bash GO_BUILD_DIR?="./" -all: net/lp_rpc.pb.go net/redeemer.pb.go net/redeemer_mock.pb.go core/test_segment.go livepeer livepeer_cli livepeer_router livepeer_bench +MOCKGEN=go run github.com/golang/mock/mockgen +ABIGEN=go run github.com/ethereum/go-ethereum/cmd/abigen + +all: net/lp_rpc.pb.go net/redeemer.pb.go net/redeemer_mock.pb.go core/test_segment.go eth/contracts/chainlink/AggregatorV3Interface.go livepeer livepeer_cli livepeer_router livepeer_bench net/lp_rpc.pb.go: net/lp_rpc.proto protoc -I=. --go_out=. --go-grpc_out=. $^ @@ -10,12 +13,21 @@ net/redeemer.pb.go: net/redeemer.proto protoc -I=. --go_out=. --go-grpc_out=. $^ net/redeemer_mock.pb.go net/redeemer_grpc_mock.pb.go: net/redeemer.pb.go net/redeemer_grpc.pb.go - @mockgen -source net/redeemer.pb.go -destination net/redeemer_mock.pb.go -package net - @mockgen -source net/redeemer_grpc.pb.go -destination net/redeemer_grpc_mock.pb.go -package net + @$(MOCKGEN) -source net/redeemer.pb.go -destination net/redeemer_mock.pb.go -package net + @$(MOCKGEN) -source net/redeemer_grpc.pb.go -destination net/redeemer_grpc_mock.pb.go -package net core/test_segment.go: core/test_segment.sh core/test_segment.go +eth/contracts/chainlink/AggregatorV3Interface.go: + solc --version | grep 0.7.6+commit.7338295f + @set -ex; \ + for sol_file in eth/contracts/chainlink/*.sol; do \ + contract_name=$$(basename "$$sol_file" .sol); \ + solc --abi --optimize --overwrite -o $$(dirname "$$sol_file") $$sol_file; \ + $(ABIGEN) --abi=$${sol_file%.sol}.abi --pkg=chainlink --type=$$contract_name --out=$${sol_file%.sol}.go; \ + done + version=$(shell cat VERSION) ldflags := -X github.com/livepeer/go-livepeer/core.LivepeerVersion=$(shell ./print_version.sh) diff --git a/eth/contracts/chainlink/AggregatorV3Interface.abi b/eth/contracts/chainlink/AggregatorV3Interface.abi new file mode 100644 index 0000000000..106c4a7bcb --- /dev/null +++ b/eth/contracts/chainlink/AggregatorV3Interface.abi @@ -0,0 +1 @@ +[{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"_roundId","type":"uint80"}],"name":"getRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] diff --git a/eth/contracts/chainlink/AggregatorV3Interface.go b/eth/contracts/chainlink/AggregatorV3Interface.go new file mode 100644 index 0000000000..2b0c1c9587 --- /dev/null +++ b/eth/contracts/chainlink/AggregatorV3Interface.go @@ -0,0 +1,394 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package chainlink + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// AggregatorV3InterfaceMetaData contains all meta data concerning the AggregatorV3Interface contract. +var AggregatorV3InterfaceMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"description\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint80\",\"name\":\"_roundId\",\"type\":\"uint80\"}],\"name\":\"getRoundData\",\"outputs\":[{\"internalType\":\"uint80\",\"name\":\"roundId\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"answer\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"startedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint80\",\"name\":\"answeredInRound\",\"type\":\"uint80\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestRoundData\",\"outputs\":[{\"internalType\":\"uint80\",\"name\":\"roundId\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"answer\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"startedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint80\",\"name\":\"answeredInRound\",\"type\":\"uint80\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +} + +// AggregatorV3InterfaceABI is the input ABI used to generate the binding from. +// Deprecated: Use AggregatorV3InterfaceMetaData.ABI instead. +var AggregatorV3InterfaceABI = AggregatorV3InterfaceMetaData.ABI + +// AggregatorV3Interface is an auto generated Go binding around an Ethereum contract. +type AggregatorV3Interface struct { + AggregatorV3InterfaceCaller // Read-only binding to the contract + AggregatorV3InterfaceTransactor // Write-only binding to the contract + AggregatorV3InterfaceFilterer // Log filterer for contract events +} + +// AggregatorV3InterfaceCaller is an auto generated read-only Go binding around an Ethereum contract. +type AggregatorV3InterfaceCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AggregatorV3InterfaceTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AggregatorV3InterfaceTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AggregatorV3InterfaceFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AggregatorV3InterfaceFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AggregatorV3InterfaceSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AggregatorV3InterfaceSession struct { + Contract *AggregatorV3Interface // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AggregatorV3InterfaceCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AggregatorV3InterfaceCallerSession struct { + Contract *AggregatorV3InterfaceCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AggregatorV3InterfaceTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AggregatorV3InterfaceTransactorSession struct { + Contract *AggregatorV3InterfaceTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AggregatorV3InterfaceRaw is an auto generated low-level Go binding around an Ethereum contract. +type AggregatorV3InterfaceRaw struct { + Contract *AggregatorV3Interface // Generic contract binding to access the raw methods on +} + +// AggregatorV3InterfaceCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AggregatorV3InterfaceCallerRaw struct { + Contract *AggregatorV3InterfaceCaller // Generic read-only contract binding to access the raw methods on +} + +// AggregatorV3InterfaceTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AggregatorV3InterfaceTransactorRaw struct { + Contract *AggregatorV3InterfaceTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAggregatorV3Interface creates a new instance of AggregatorV3Interface, bound to a specific deployed contract. +func NewAggregatorV3Interface(address common.Address, backend bind.ContractBackend) (*AggregatorV3Interface, error) { + contract, err := bindAggregatorV3Interface(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AggregatorV3Interface{AggregatorV3InterfaceCaller: AggregatorV3InterfaceCaller{contract: contract}, AggregatorV3InterfaceTransactor: AggregatorV3InterfaceTransactor{contract: contract}, AggregatorV3InterfaceFilterer: AggregatorV3InterfaceFilterer{contract: contract}}, nil +} + +// NewAggregatorV3InterfaceCaller creates a new read-only instance of AggregatorV3Interface, bound to a specific deployed contract. +func NewAggregatorV3InterfaceCaller(address common.Address, caller bind.ContractCaller) (*AggregatorV3InterfaceCaller, error) { + contract, err := bindAggregatorV3Interface(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AggregatorV3InterfaceCaller{contract: contract}, nil +} + +// NewAggregatorV3InterfaceTransactor creates a new write-only instance of AggregatorV3Interface, bound to a specific deployed contract. +func NewAggregatorV3InterfaceTransactor(address common.Address, transactor bind.ContractTransactor) (*AggregatorV3InterfaceTransactor, error) { + contract, err := bindAggregatorV3Interface(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AggregatorV3InterfaceTransactor{contract: contract}, nil +} + +// NewAggregatorV3InterfaceFilterer creates a new log filterer instance of AggregatorV3Interface, bound to a specific deployed contract. +func NewAggregatorV3InterfaceFilterer(address common.Address, filterer bind.ContractFilterer) (*AggregatorV3InterfaceFilterer, error) { + contract, err := bindAggregatorV3Interface(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AggregatorV3InterfaceFilterer{contract: contract}, nil +} + +// bindAggregatorV3Interface binds a generic wrapper to an already deployed contract. +func bindAggregatorV3Interface(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AggregatorV3InterfaceMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AggregatorV3Interface *AggregatorV3InterfaceRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AggregatorV3Interface.Contract.AggregatorV3InterfaceCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AggregatorV3Interface *AggregatorV3InterfaceRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AggregatorV3Interface.Contract.AggregatorV3InterfaceTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AggregatorV3Interface *AggregatorV3InterfaceRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AggregatorV3Interface.Contract.AggregatorV3InterfaceTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AggregatorV3Interface *AggregatorV3InterfaceCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AggregatorV3Interface.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AggregatorV3Interface *AggregatorV3InterfaceTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AggregatorV3Interface.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AggregatorV3Interface *AggregatorV3InterfaceTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AggregatorV3Interface.Contract.contract.Transact(opts, method, params...) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_AggregatorV3Interface *AggregatorV3InterfaceCaller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _AggregatorV3Interface.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_AggregatorV3Interface *AggregatorV3InterfaceSession) Decimals() (uint8, error) { + return _AggregatorV3Interface.Contract.Decimals(&_AggregatorV3Interface.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_AggregatorV3Interface *AggregatorV3InterfaceCallerSession) Decimals() (uint8, error) { + return _AggregatorV3Interface.Contract.Decimals(&_AggregatorV3Interface.CallOpts) +} + +// Description is a free data retrieval call binding the contract method 0x7284e416. +// +// Solidity: function description() view returns(string) +func (_AggregatorV3Interface *AggregatorV3InterfaceCaller) Description(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _AggregatorV3Interface.contract.Call(opts, &out, "description") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Description is a free data retrieval call binding the contract method 0x7284e416. +// +// Solidity: function description() view returns(string) +func (_AggregatorV3Interface *AggregatorV3InterfaceSession) Description() (string, error) { + return _AggregatorV3Interface.Contract.Description(&_AggregatorV3Interface.CallOpts) +} + +// Description is a free data retrieval call binding the contract method 0x7284e416. +// +// Solidity: function description() view returns(string) +func (_AggregatorV3Interface *AggregatorV3InterfaceCallerSession) Description() (string, error) { + return _AggregatorV3Interface.Contract.Description(&_AggregatorV3Interface.CallOpts) +} + +// GetRoundData is a free data retrieval call binding the contract method 0x9a6fc8f5. +// +// Solidity: function getRoundData(uint80 _roundId) view returns(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) +func (_AggregatorV3Interface *AggregatorV3InterfaceCaller) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (struct { + RoundId *big.Int + Answer *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int +}, error) { + var out []interface{} + err := _AggregatorV3Interface.contract.Call(opts, &out, "getRoundData", _roundId) + + outstruct := new(struct { + RoundId *big.Int + Answer *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.RoundId = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Answer = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + outstruct.StartedAt = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.UpdatedAt = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.AnsweredInRound = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +// GetRoundData is a free data retrieval call binding the contract method 0x9a6fc8f5. +// +// Solidity: function getRoundData(uint80 _roundId) view returns(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) +func (_AggregatorV3Interface *AggregatorV3InterfaceSession) GetRoundData(_roundId *big.Int) (struct { + RoundId *big.Int + Answer *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int +}, error) { + return _AggregatorV3Interface.Contract.GetRoundData(&_AggregatorV3Interface.CallOpts, _roundId) +} + +// GetRoundData is a free data retrieval call binding the contract method 0x9a6fc8f5. +// +// Solidity: function getRoundData(uint80 _roundId) view returns(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) +func (_AggregatorV3Interface *AggregatorV3InterfaceCallerSession) GetRoundData(_roundId *big.Int) (struct { + RoundId *big.Int + Answer *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int +}, error) { + return _AggregatorV3Interface.Contract.GetRoundData(&_AggregatorV3Interface.CallOpts, _roundId) +} + +// LatestRoundData is a free data retrieval call binding the contract method 0xfeaf968c. +// +// Solidity: function latestRoundData() view returns(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) +func (_AggregatorV3Interface *AggregatorV3InterfaceCaller) LatestRoundData(opts *bind.CallOpts) (struct { + RoundId *big.Int + Answer *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int +}, error) { + var out []interface{} + err := _AggregatorV3Interface.contract.Call(opts, &out, "latestRoundData") + + outstruct := new(struct { + RoundId *big.Int + Answer *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.RoundId = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Answer = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + outstruct.StartedAt = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.UpdatedAt = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.AnsweredInRound = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +// LatestRoundData is a free data retrieval call binding the contract method 0xfeaf968c. +// +// Solidity: function latestRoundData() view returns(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) +func (_AggregatorV3Interface *AggregatorV3InterfaceSession) LatestRoundData() (struct { + RoundId *big.Int + Answer *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int +}, error) { + return _AggregatorV3Interface.Contract.LatestRoundData(&_AggregatorV3Interface.CallOpts) +} + +// LatestRoundData is a free data retrieval call binding the contract method 0xfeaf968c. +// +// Solidity: function latestRoundData() view returns(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) +func (_AggregatorV3Interface *AggregatorV3InterfaceCallerSession) LatestRoundData() (struct { + RoundId *big.Int + Answer *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int +}, error) { + return _AggregatorV3Interface.Contract.LatestRoundData(&_AggregatorV3Interface.CallOpts) +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(uint256) +func (_AggregatorV3Interface *AggregatorV3InterfaceCaller) Version(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AggregatorV3Interface.contract.Call(opts, &out, "version") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(uint256) +func (_AggregatorV3Interface *AggregatorV3InterfaceSession) Version() (*big.Int, error) { + return _AggregatorV3Interface.Contract.Version(&_AggregatorV3Interface.CallOpts) +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(uint256) +func (_AggregatorV3Interface *AggregatorV3InterfaceCallerSession) Version() (*big.Int, error) { + return _AggregatorV3Interface.Contract.Version(&_AggregatorV3Interface.CallOpts) +} diff --git a/eth/contracts/chainlink/AggregatorV3Interface.sol b/eth/contracts/chainlink/AggregatorV3Interface.sol new file mode 100644 index 0000000000..1bedfce214 --- /dev/null +++ b/eth/contracts/chainlink/AggregatorV3Interface.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +// https://github.com/smartcontractkit/chainlink/blob/v2.9.1/contracts/src/v0.7/interfaces/AggregatorV3Interface.sol +pragma solidity ^0.7.0; + +interface AggregatorV3Interface { + function decimals() external view returns (uint8); + + function description() external view returns (string memory); + + function version() external view returns (uint256); + + // getRoundData and latestRoundData should both raise "No data present" + // if they do not have data to report, instead of returning unset values + // which could be misinterpreted as actual reported values. + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); + + function latestRoundData() + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ); +} diff --git a/eth/pricefeed.go b/eth/pricefeed.go new file mode 100644 index 0000000000..a9f51d0122 --- /dev/null +++ b/eth/pricefeed.go @@ -0,0 +1,78 @@ +package eth + +import ( + "errors" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/livepeer/go-livepeer/eth/contracts/chainlink" +) + +type PriceData struct { + RoundID int64 + Price *big.Rat + UpdatedAt time.Time +} + +// PriceFeedEthClient is an interface for fetching price data from a Chainlink +// PriceFeed contract. +type PriceFeedEthClient interface { + Description() (string, error) + FetchPriceData() (PriceData, error) +} + +func NewPriceFeedEthClient(ethClient *ethclient.Client, priceFeedAddr string) (PriceFeedEthClient, error) { + addr := common.HexToAddress(priceFeedAddr) + priceFeed, err := chainlink.NewAggregatorV3Interface(addr, ethClient) + if err != nil { + return nil, fmt.Errorf("failed to create aggregator proxy: %w", err) + } + + return &priceFeedClient{ + client: ethClient, + priceFeed: priceFeed, + }, nil +} + +type priceFeedClient struct { + client *ethclient.Client + priceFeed *chainlink.AggregatorV3Interface +} + +func (c *priceFeedClient) Description() (string, error) { + return c.priceFeed.Description(&bind.CallOpts{}) +} + +func (c *priceFeedClient) FetchPriceData() (PriceData, error) { + data, err := c.priceFeed.LatestRoundData(&bind.CallOpts{}) + if err != nil { + return PriceData{}, errors.New("failed to get latest round data: " + err.Error()) + } + + decimals, err := c.priceFeed.Decimals(&bind.CallOpts{}) + if err != nil { + return PriceData{}, errors.New("failed to get decimals: " + err.Error()) + } + + return computePriceData(data.RoundId, data.UpdatedAt, data.Answer, decimals), nil +} + +// computePriceData transforms the raw data from the PriceFeed into the higher +// level PriceData struct, more easily usable by the rest of the system. +func computePriceData(roundID, updatedAt, answer *big.Int, decimals uint8) PriceData { + // Compute a big.int which is 10^decimals. + divisor := new(big.Int).Exp( + big.NewInt(10), + big.NewInt(int64(decimals)), + nil) + + return PriceData{ + RoundID: roundID.Int64(), + Price: new(big.Rat).SetFrac(answer, divisor), + UpdatedAt: time.Unix(updatedAt.Int64(), 0), + } +} diff --git a/eth/pricefeed_test.go b/eth/pricefeed_test.go new file mode 100644 index 0000000000..981a158e75 --- /dev/null +++ b/eth/pricefeed_test.go @@ -0,0 +1,51 @@ +package eth + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestComputePriceData(t *testing.T) { + assert := assert.New(t) + + t.Run("valid data", func(t *testing.T) { + roundID := big.NewInt(1) + updatedAt := big.NewInt(1626192000) + answer := big.NewInt(420666000) + decimals := uint8(6) + + data := computePriceData(roundID, updatedAt, answer, decimals) + + assert.EqualValues(int64(1), data.RoundID, "Round ID didn't match") + assert.Equal("210333/500", data.Price.RatString(), "The Price Rat didn't match") + assert.Equal("2021-07-13 16:00:00 +0000 UTC", data.UpdatedAt.UTC().String(), "The updated at time did not match") + }) + + t.Run("zero answer", func(t *testing.T) { + roundID := big.NewInt(2) + updatedAt := big.NewInt(1626192000) + answer := big.NewInt(0) + decimals := uint8(18) + + data := computePriceData(roundID, updatedAt, answer, decimals) + + assert.EqualValues(int64(2), data.RoundID, "Round ID didn't match") + assert.Equal("0", data.Price.RatString(), "The Price Rat didn't match") + assert.Equal("2021-07-13 16:00:00 +0000 UTC", data.UpdatedAt.UTC().String(), "The updated at time did not match") + }) + + t.Run("zero decimals", func(t *testing.T) { + roundID := big.NewInt(3) + updatedAt := big.NewInt(1626192000) + answer := big.NewInt(13) + decimals := uint8(0) + + data := computePriceData(roundID, updatedAt, answer, decimals) + + assert.EqualValues(int64(3), data.RoundID, "Round ID didn't match") + assert.Equal("13", data.Price.RatString(), "The Price Rat didn't match") + assert.Equal("2021-07-13 16:00:00 +0000 UTC", data.UpdatedAt.UTC().String(), "The updated at time did not match") + }) +} diff --git a/eth/watchers/pricefeedwatcher.go b/eth/watchers/pricefeedwatcher.go new file mode 100644 index 0000000000..ec7a81f2f3 --- /dev/null +++ b/eth/watchers/pricefeedwatcher.go @@ -0,0 +1,182 @@ +package watchers + +import ( + "context" + "fmt" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/event" + "github.com/livepeer/go-livepeer/clog" + "github.com/livepeer/go-livepeer/eth" +) + +const ( + priceUpdateMaxRetries = 5 + priceUpdateBaseRetryDelay = 30 * time.Second + priceUpdatePeriod = 1 * time.Hour +) + +// PriceFeedWatcher monitors a Chainlink PriceFeed for updated pricing info. It +// allows fetching the current price as well as listening for updates on the +// PriceUpdated channel. +type PriceFeedWatcher struct { + baseRetryDelay time.Duration + + priceFeed eth.PriceFeedEthClient + currencyBase, currencyQuote string + + mu sync.RWMutex + current eth.PriceData + priceEventFeed event.Feed +} + +// NewPriceFeedWatcher creates a new PriceFeedWatcher instance. It will already +// fetch the current price and start a goroutine to watch for updates. +func NewPriceFeedWatcher(ethClient *ethclient.Client, priceFeedAddr string) (*PriceFeedWatcher, error) { + priceFeed, err := eth.NewPriceFeedEthClient(ethClient, priceFeedAddr) + if err != nil { + return nil, fmt.Errorf("failed to create price feed client: %w", err) + } + + description, err := priceFeed.Description() + if err != nil { + return nil, fmt.Errorf("failed to get description: %w", err) + } + + currencyFrom, currencyTo, err := parseCurrencies(description) + if err != nil { + return nil, err + } + + w := &PriceFeedWatcher{ + baseRetryDelay: priceUpdateBaseRetryDelay, + priceFeed: priceFeed, + currencyBase: currencyFrom, + currencyQuote: currencyTo, + } + + err = w.updatePrice() + if err != nil { + return nil, fmt.Errorf("failed to update price: %w", err) + } + + return w, nil +} + +// Currencies returns the base and quote currencies of the price feed. +// i.e. base = CurrentPrice() * quote +func (w *PriceFeedWatcher) Currencies() (base string, quote string) { + return w.currencyBase, w.currencyQuote +} + +// Current returns the latest fetched price data. +func (w *PriceFeedWatcher) Current() eth.PriceData { + w.mu.RLock() + defer w.mu.RUnlock() + return w.current +} + +// Subscribe allows one to subscribe to price updates emitted by the Watcher. +// To unsubscribe, simply call `Unsubscribe` on the returned subscription. +// The sink channel should have ample buffer space to avoid blocking other +// subscribers. Slow subscribers are not dropped. +func (w *PriceFeedWatcher) Subscribe(sub chan<- eth.PriceData) event.Subscription { + return w.priceEventFeed.Subscribe(sub) +} + +func (w *PriceFeedWatcher) updatePrice() error { + newPrice, err := w.priceFeed.FetchPriceData() + if err != nil { + return fmt.Errorf("failed to fetch price data: %w", err) + } + + if newPrice.UpdatedAt.After(w.current.UpdatedAt) { + w.mu.Lock() + w.current = newPrice + w.mu.Unlock() + w.priceEventFeed.Send(newPrice) + } + + return nil +} + +// Watch starts the watch process. It will periodically poll the price feed for +// price updates until the given context is canceled. Typically, you want to +// call Watch inside a goroutine. +func (w *PriceFeedWatcher) Watch(ctx context.Context) { + ticker := newTruncatedTicker(ctx, priceUpdatePeriod) + w.watchTicker(ctx, ticker) +} + +func (w *PriceFeedWatcher) watchTicker(ctx context.Context, ticker <-chan time.Time) { + for { + select { + case <-ctx.Done(): + return + case <-ticker: + attempt, retryDelay := 1, w.baseRetryDelay + for { + err := w.updatePrice() + if err == nil { + break + } else if attempt >= priceUpdateMaxRetries { + clog.Errorf(ctx, "Failed to fetch updated price from PriceFeed attempts=%d err=%q", attempt, err) + break + } + + clog.Warningf(ctx, "Failed to fetch updated price from PriceFeed, retrying after retryDelay=%d attempt=%d err=%q", retryDelay, attempt, err) + select { + case <-ctx.Done(): + return + case <-time.After(retryDelay): + } + attempt, retryDelay = attempt+1, retryDelay*2 + } + } + } +} + +// parseCurrencies parses the base and quote currencies from a price feed based +// on Chainlink PriceFeed description pattern "FROM / TO". +func parseCurrencies(description string) (currencyBase string, currencyQuote string, err error) { + currencies := strings.Split(description, "/") + if len(currencies) != 2 { + return "", "", fmt.Errorf("aggregator description must be in the format 'FROM / TO' but got: %s", description) + } + + currencyBase = strings.TrimSpace(currencies[0]) + currencyQuote = strings.TrimSpace(currencies[1]) + return +} + +// newTruncatedTicker creates a ticker that ticks at the next time that is a +// multiple of d, starting from the current time. This is a best-effort approach +// to ensure that nodes update their prices around the same time to avoid too +// big price discrepancies. +func newTruncatedTicker(ctx context.Context, d time.Duration) <-chan time.Time { + ch := make(chan time.Time, 1) + go func() { + defer close(ch) + + nextTick := time.Now().UTC().Truncate(d) + for { + nextTick = nextTick.Add(d) + untilNextTick := nextTick.Sub(time.Now().UTC()) + if untilNextTick <= 0 { + continue + } + + select { + case <-ctx.Done(): + return + case t := <-time.After(untilNextTick): + ch <- t + } + } + }() + + return ch +} diff --git a/eth/watchers/pricefeedwatcher_test.go b/eth/watchers/pricefeedwatcher_test.go new file mode 100644 index 0000000000..20e09578e1 --- /dev/null +++ b/eth/watchers/pricefeedwatcher_test.go @@ -0,0 +1,216 @@ +package watchers + +import ( + "context" + "errors" + "math/big" + "testing" + "time" + + "github.com/livepeer/go-livepeer/eth" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +type mockPriceFeedEthClient struct { + mock.Mock +} + +func (m *mockPriceFeedEthClient) FetchPriceData() (eth.PriceData, error) { + args := m.Called() + return args.Get(0).(eth.PriceData), args.Error(1) +} + +func (m *mockPriceFeedEthClient) Description() (string, error) { + args := m.Called() + return args.String(0), args.Error(1) +} + +func TestPriceFeedWatcher_UpdatePrice(t *testing.T) { + priceFeedMock := new(mockPriceFeedEthClient) + defer priceFeedMock.AssertExpectations(t) + + priceData := eth.PriceData{ + RoundID: 10, + Price: big.NewRat(3, 2), + UpdatedAt: time.Now(), + } + priceFeedMock.On("FetchPriceData").Return(priceData, nil).Once() + + w := &PriceFeedWatcher{ + priceFeed: priceFeedMock, + currencyBase: "ETH", + currencyQuote: "USD", + } + + priceUpdated := make(chan eth.PriceData, 1) + sub := w.Subscribe(priceUpdated) + defer sub.Unsubscribe() + + require.NoError(t, w.updatePrice()) + require.Equal(t, priceData, w.current) + + select { + case updatedPrice := <-priceUpdated: + require.Equal(t, priceData, updatedPrice) + case <-time.After(2 * time.Second): + t.Error("Updated price hasn't been received on channel") + } +} + +func TestPriceFeedWatcher_Watch(t *testing.T) { + require := require.New(t) + priceFeedMock := new(mockPriceFeedEthClient) + defer priceFeedMock.AssertExpectations(t) + + w := &PriceFeedWatcher{ + priceFeed: priceFeedMock, + currencyBase: "ETH", + currencyQuote: "USD", + } + + priceUpdated := make(chan eth.PriceData, 1) + sub := w.Subscribe(priceUpdated) + defer sub.Unsubscribe() + + priceData := eth.PriceData{ + RoundID: 10, + Price: big.NewRat(9, 2), + UpdatedAt: time.Now(), + } + checkPriceUpdated := func() { + select { + case updatedPrice := <-priceUpdated: + require.Equal(priceData, updatedPrice) + require.Equal(priceData, w.current) + case <-time.After(1 * time.Second): + require.Fail("Updated price hasn't been received on channel in a timely manner") + } + priceFeedMock.AssertExpectations(t) + } + checkNoPriceUpdate := func() { + select { + case <-priceUpdated: + require.Fail("Unexpected price update given it hasn't changed") + case <-time.After(1 * time.Second): + // all good + } + priceFeedMock.AssertExpectations(t) + } + + // Start the watch loop + fakeTicker := make(chan time.Time, 10) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go func() { + w.watchTicker(ctx, fakeTicker) + }() + + // First time should trigger an update + priceFeedMock.On("FetchPriceData").Return(priceData, nil).Once() + fakeTicker <- time.Now() + checkPriceUpdated() + + // Trigger a dummy update given price hasn't changed + priceFeedMock.On("FetchPriceData").Return(priceData, nil).Once() + fakeTicker <- time.Now() + checkNoPriceUpdate() + + // still shouldn't update given UpdatedAt stayed the same + priceData.Price = big.NewRat(1, 1) + priceFeedMock.On("FetchPriceData").Return(priceData, nil).Once() + fakeTicker <- time.Now() + checkNoPriceUpdate() + + // bump the UpdatedAt time to trigger an update + priceData.UpdatedAt = priceData.UpdatedAt.Add(1 * time.Minute) + priceFeedMock.On("FetchPriceData").Return(priceData, nil).Once() + fakeTicker <- time.Now() + checkPriceUpdated() + + priceData.UpdatedAt = priceData.UpdatedAt.Add(1 * time.Hour) + priceData.Price = big.NewRat(3, 2) + priceFeedMock.On("FetchPriceData").Return(priceData, nil).Once() + fakeTicker <- time.Now() + checkPriceUpdated() +} + +func TestPriceFeedWatcher_WatchErrorRetries(t *testing.T) { + priceFeedMock := new(mockPriceFeedEthClient) + defer priceFeedMock.AssertExpectations(t) + + // First 4 calls should fail then succeed on the 5th + for i := 0; i < 4; i++ { + priceFeedMock.On("FetchPriceData").Return(eth.PriceData{}, errors.New("error")).Once() + } + priceData := eth.PriceData{ + RoundID: 10, + Price: big.NewRat(3, 2), + UpdatedAt: time.Now(), + } + priceFeedMock.On("FetchPriceData").Return(priceData, nil) + + w := &PriceFeedWatcher{ + baseRetryDelay: 5 * time.Millisecond, + priceFeed: priceFeedMock, + currencyBase: "ETH", + currencyQuote: "USD", + } + + priceUpdated := make(chan eth.PriceData, 1) + sub := w.Subscribe(priceUpdated) + defer sub.Unsubscribe() + + // Start watch loop + fakeTicker := make(chan time.Time, 10) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go func() { + w.watchTicker(ctx, fakeTicker) + }() + + fakeTicker <- time.Now() + select { + case updatedPrice := <-priceUpdated: + require.Equal(t, priceData, updatedPrice) + case <-time.After(2 * time.Second): + t.Error("Updated price hasn't been received on channel") + } +} + +func TestParseCurrencies(t *testing.T) { + t.Run("Valid currencies", func(t *testing.T) { + description := "ETH / USD" + currencyBase, currencyQuote, err := parseCurrencies(description) + + require.NoError(t, err) + require.Equal(t, "ETH", currencyBase) + require.Equal(t, "USD", currencyQuote) + }) + + t.Run("Missing separator", func(t *testing.T) { + description := "ETHUSD" + _, _, err := parseCurrencies(description) + + require.Error(t, err) + require.Contains(t, err.Error(), "aggregator description must be in the format 'FROM / TO'") + }) + + t.Run("Extra spaces", func(t *testing.T) { + description := " ETH / USD " + currencyBase, currencyQuote, err := parseCurrencies(description) + + require.NoError(t, err) + require.Equal(t, "ETH", currencyBase) + require.Equal(t, "USD", currencyQuote) + }) + + t.Run("Lowercase currency", func(t *testing.T) { + description := "eth / usd" + currencyBase, currencyQuote, err := parseCurrencies(description) + + require.NoError(t, err) + require.Equal(t, "eth", currencyBase) + require.Equal(t, "usd", currencyQuote) + }) +} diff --git a/go.mod b/go.mod index ed9e2f3715..675f75b480 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( go.uber.org/goleak v1.3.0 golang.org/x/net v0.17.0 google.golang.org/grpc v1.57.1 + google.golang.org/protobuf v1.30.0 pgregory.net/rapid v1.1.0 ) @@ -39,9 +40,11 @@ require ( cloud.google.com/go/storage v1.28.1 // indirect dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/DataDog/zstd v1.4.5 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.1 // indirect github.com/StackExchange/wmi v1.2.1 // indirect + github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/aws/aws-sdk-go v1.44.64 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.7.0 // indirect @@ -49,6 +52,12 @@ require ( github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/cp v1.1.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cockroachdb/errors v1.8.1 // indirect + github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect + github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect + github.com/cockroachdb/redact v1.0.8 // indirect + github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/containerd/containerd v1.7.7 // indirect @@ -59,6 +68,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/deepmap/oapi-codegen v1.6.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v24.0.6+incompatible // indirect @@ -67,6 +77,7 @@ require ( github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 // indirect github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/fatih/color v1.13.0 // indirect + github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect github.com/ghodss/yaml v1.0.0 // indirect @@ -75,7 +86,9 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-stack/stack v1.8.1 // indirect + github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/go-cmp v0.5.9 // indirect @@ -84,10 +97,21 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect github.com/googleapis/gax-go/v2 v2.7.1 // indirect github.com/gorilla/websocket v1.4.2 // indirect + github.com/graph-gophers/graphql-go v1.3.0 // indirect + github.com/hashicorp/go-bexpr v0.1.10 // indirect + github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 // indirect + github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.2.3 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/karalabe/usb v0.0.2 // indirect github.com/klauspost/compress v1.16.3 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect @@ -96,6 +120,8 @@ require ( github.com/mattn/go-runewidth v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect @@ -104,6 +130,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/opencontainers/runc v1.1.5 // indirect + github.com/opentracing/opentracing-go v1.1.0 // indirect github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -115,6 +142,8 @@ require ( github.com/rabbitmq/amqp091-go v1.8.0 // indirect github.com/rabbitmq/rabbitmq-stream-go-client v1.1.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/rs/cors v1.7.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/shirou/gopsutil/v3 v3.23.9 // indirect @@ -123,8 +152,12 @@ require ( github.com/status-im/keycard-go v0.2.0 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/supranational/blst v0.3.11 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/urfave/cli/v2 v2.25.7 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect @@ -133,6 +166,7 @@ require ( golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect + golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.13.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.114.0 // indirect @@ -140,7 +174,7 @@ require ( google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect - google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v1.0.0 // indirect diff --git a/go.sum b/go.sum index 5f01dac8e5..02fdd1f23e 100644 --- a/go.sum +++ b/go.sum @@ -47,27 +47,41 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA= github.com/Microsoft/hcsshim v0.11.1/go.mod h1:nFJmaO4Zr5Y7eADdFOpYswDDlNVbvcIJJNJLECr5JQg= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go v1.44.64 h1:DuDZSBDkFBWW5H8q6i80RJDkBaaa/53KA6Jreqwjlqw= github.com/aws/aws-sdk-go v1.44.64/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -98,12 +112,22 @@ github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMn github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= +github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= +github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= @@ -113,9 +137,13 @@ github.com/containerd/containerd v1.7.7 h1:QOC2K4A42RQpcrZyptP6z9EJZnlHfHJUfZrAA github.com/containerd/containerd v1.7.7/go.mod h1:3c4XZv6VeT9qgf9GMTxNTMFxGJrGpI2vz1yk4ye+YY8= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -123,6 +151,7 @@ github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBS github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -133,6 +162,11 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/deepmap/oapi-codegen v1.6.0 h1:w/d1ntwh91XI0b/8ja7+u5SvA4IFfM0UNNLmiDR1gg0= +github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= @@ -150,25 +184,42 @@ github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 h1:qwcF+vdFrvPSEUDSX5R github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-ethereum v1.13.5 h1:U6TCRciCqZRe4FPXmy1sMGxTfuk8P7u2UoinF3VbaFk= github.com/ethereum/go-ethereum v1.13.5/go.mod h1:yMTu38GSuyxaYzQMViqNmQ1s3cE84abZexQmTgenWk0= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -184,21 +235,33 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -234,8 +297,11 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -252,6 +318,7 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -277,19 +344,45 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= +github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= +github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jaypipes/ghw v0.10.0 h1:UHu9UX08Py315iPojADFPOkmjTsNzHj4g4adsNKKteY= github.com/jaypipes/ghw v0.10.0/go.mod h1:jeJGbkRB2lL3/gxYzNYzEDETV1ZJ56OKr+CSeSEym+g= github.com/jaypipes/pcidb v1.0.0 h1:vtZIfkiCUE42oYbJS0TAq9XSfSmcsgo9IdxSm9qzYU8= @@ -306,14 +399,28 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= +github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -321,11 +428,15 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/livepeer/go-tools v0.0.0-20220805063103-76df6beb6506 h1:qKon23c1RQPvL5Oya/hkImbaXNMkt6VdYtnh5jcIhoY= github.com/livepeer/go-tools v0.0.0-20220805063103-76df6beb6506/go.mod h1:aLVS1DT0ur9kpr0IlNI4DNcm9vVjRRUjDnwuEUm0BdQ= @@ -333,19 +444,27 @@ github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded h1:ZQlvR5RB4nfT+cO github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded/go.mod h1:xkDdm+akniYxVT9KW1Y2Y7Hso6aW+rZObz3nrA9yTHw= github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18 h1:4oH3NqV0NvcdS44Ld3zK2tO8IUiNozIggm74yobQeZg= github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18/go.mod h1:Jpf4jHK+fbWioBHRDRM1WadNT1qmY27g2YicTdO0Rtc= -github.com/livepeer/lpms v0.0.0-20231002131146-663c62246a3c h1:qxmMX/j6Yp0xFR17nhGktbHwEVqIjLK5lh2TiiENzY8= -github.com/livepeer/lpms v0.0.0-20231002131146-663c62246a3c/go.mod h1:Hr/JhxxPDipOVd4ZrGYWrdJfpVF8/SEI0nNr2ctAlkM= github.com/livepeer/lpms v0.0.0-20240115103113-98566e26c007 h1:0xr1TeIanBDdzI3sE2Zgf2yEV3s+6cPo3lJeyOHKmtM= github.com/livepeer/lpms v0.0.0-20240115103113-98566e26c007/go.mod h1:Hr/JhxxPDipOVd4ZrGYWrdJfpVF8/SEI0nNr2ctAlkM= github.com/livepeer/m3u8 v0.11.1 h1:VkUJzfNTyjy9mqsgp5JPvouwna8wGZMvd/gAfT5FinU= github.com/livepeer/m3u8 v0.11.1/go.mod h1:IUqAtwWPAG2CblfQa4SVzTQoDcEMPyfNOaBSxqHMS04= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -357,13 +476,20 @@ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4 github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI= github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= +github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= @@ -381,12 +507,25 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -396,14 +535,20 @@ github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/ github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -453,11 +598,17 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= @@ -473,6 +624,14 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -483,6 +642,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -495,6 +655,7 @@ github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbe github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/testcontainers/testcontainers-go v0.26.0 h1:uqcYdoOHBy1ca7gKODfBd9uTHVK3a7UL848z09MVZ0c= github.com/testcontainers/testcontainers-go v0.26.0/go.mod h1:ICriE9bLX5CLxL9OFQ2N+2N+f+803LNJ1utJb1+Inx0= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= @@ -502,13 +663,32 @@ github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0h github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8= github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -529,11 +709,15 @@ go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= @@ -575,10 +759,13 @@ golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -587,6 +774,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -597,13 +785,16 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -638,8 +829,11 @@ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -648,11 +842,16 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -668,10 +867,13 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -695,11 +897,13 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -707,6 +911,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= @@ -715,13 +920,20 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -794,6 +1006,7 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -829,6 +1042,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1: google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -868,7 +1082,14 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/tools.go b/tools.go new file mode 100644 index 0000000000..6bc191ddd2 --- /dev/null +++ b/tools.go @@ -0,0 +1,9 @@ +//go:build tools +// +build tools + +package tools + +import ( + _ "github.com/ethereum/go-ethereum/cmd/abigen" + _ "github.com/golang/mock/mockgen" +) From 706ec33286344613ec37c4f0ac4d4f3d17657049 Mon Sep 17 00:00:00 2001 From: Victor Elias Date: Wed, 27 Mar 2024 20:58:52 -0300 Subject: [PATCH 02/39] cmd/livepeer: Use price feed watcher for dynamic pricePerPixel (#2981) * eth/watchers: Create PriceFeed watcher Makefile: Use mockgen binary from tool dependencies eth/contracts: Add chainlink interfaces source Makefile: Generate Chainlink contracts ABI tools: Add abigen tool to repo eth/contracts: Generate chainlink bindings Makefile: Fix abigen bindings generation Revert everything abigen Turns out there's already bindings exported from the Chainlink lib. go.mod: Add chainlink library eth/watchers: Add pricefeed watcher eth/watchers: Clean-up event watching code eth/watchers: Improve price tracking Revert "go.mod: Add chainlink library" This reverts commit ac415bd8fb210088874e7fdea8d37ac4dad81dab. Revert "Revert everything abigen" This reverts commit b7c40b1e936c885aad973f28d87d42b0d85cb0e4. eth/contracts: Gen bindings for proxy iface eth/watchers: Use local bindings for contracts eth/watchers: Simplify event subs logic eth/watchers: Simplify&optimize truncated ticker eth/watchers: Update decimals on fetch eth/watchers: Improve handling of decimals eth/watchers: Fix price rat creation eth/watchers: Make sure we use UTC on truncated timer eth/contracts/chainlink: Generate only V3 contract bindings eth/watchers: Watch PriceFeed only with polling eth/watchers: Add a retry logic on price update eth/watchers: Use clog instead of fmt.Printf * eth: Create separate pricefeed client unit This will make the code more testable. * eth: Add tests for pricefeed client * eth/watchers: Add tests to the truncated ticker Gosh that was much harder than I thought * eth/watchers: Add tests for pricefeedwatcher * eth: Add comments to the new components * go fmt * cmd: make pricePerUnit flags strings * cmd: Allow price per unit to be speficied with a currency Currently ignoring the currency value. * cmd: Add logic to start price update loop * cmd: Add flag for specifying price feed address * cmd: Add a lil test to priceDataToWei * TODO: Reminder for something I noticed is missing * cmd/starter: Support currencies for custom broadcaster prices * eth: Address minor review comments * eth,eth/watchers: Improve pricefeed watcher interface * eth/watchers: Fix pricefeed watcher after merge * cmd,core,server: Support dynamic updates to price in USD * eth/watchers: Remove truncated ticker tests * eth/watchers: Finalize pricefeedwatcher docs/tests * cmd: Address review comment * core: Create tests for autoconvertedprice * cmd,core: Move wei default to AutoConvertedPrice * Address review comments * cmd: Fix the e2e flow for setting/updating configs * CHANGELOG * cmd: Make sure pricePerPixel can be specified with e notation Parse it directlty as a big.Rat from a raw string, like I was doing for pricePerUnit in some places. * Fix tests Turns out tests were not running on my branch due to base branch * go fmt * core: Fix typo in comment * cmd,server: Use 3 decimal points when logging PPP Found out that's officially supported precision on the discovery logic, so let's reflect that here. --- CHANGELOG_PENDING.md | 2 + cmd/livepeer/livepeer.go | 11 +- cmd/livepeer/starter/starter.go | 163 ++++++++++++---- cmd/livepeer/starter/starter_test.go | 92 ++++++++- cmd/livepeer_cli/wizard_broadcast.go | 22 ++- cmd/livepeer_cli/wizard_stats.go | 30 +-- cmd/livepeer_cli/wizard_transcoder.go | 49 ++--- core/autoconvertedprice.go | 139 ++++++++++++++ core/autoconvertedprice_test.go | 258 ++++++++++++++++++++++++++ core/livepeernode.go | 22 ++- core/livepeernode_test.go | 12 +- core/orch_test.go | 44 ++--- discovery/discovery_test.go | 8 +- eth/watchers/pricefeedwatcher.go | 146 ++++++++++----- eth/watchers/pricefeedwatcher_test.go | 83 ++++++--- server/broadcast.go | 15 +- server/handlers.go | 103 +++++----- server/handlers_test.go | 29 +-- server/rpc_test.go | 8 +- server/segment_rpc_test.go | 2 +- test/e2e/e2e.go | 2 +- 21 files changed, 976 insertions(+), 264 deletions(-) create mode 100644 core/autoconvertedprice.go create mode 100644 core/autoconvertedprice_test.go diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 3ca5044811..df9d710ef8 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -8,6 +8,8 @@ #### General +- [#2981](https://github.com/livepeer/go-livepeer/pull/2981) Add support for prices in custom currencies like USD (@victorges) + #### Broadcaster #### Orchestrator diff --git a/cmd/livepeer/livepeer.go b/cmd/livepeer/livepeer.go index b9ed7a907d..d875a079f8 100755 --- a/cmd/livepeer/livepeer.go +++ b/cmd/livepeer/livepeer.go @@ -133,7 +133,7 @@ func parseLivepeerConfig() starter.LivepeerConfig { cfg.SelectPriceExpFactor = flag.Float64("selectPriceExpFactor", *cfg.SelectPriceExpFactor, "Expresses how significant a small change of price is for the selection algorithm; default 100") cfg.OrchPerfStatsURL = flag.String("orchPerfStatsUrl", *cfg.OrchPerfStatsURL, "URL of Orchestrator Performance Stream Tester") cfg.Region = flag.String("region", *cfg.Region, "Region in which a broadcaster is deployed; used to select the region while using the orchestrator's performance stats") - cfg.MaxPricePerUnit = flag.Int("maxPricePerUnit", *cfg.MaxPricePerUnit, "The maximum transcoding price (in wei) per 'pixelsPerUnit' a broadcaster is willing to accept. If not set explicitly, broadcaster is willing to accept ANY price") + cfg.MaxPricePerUnit = flag.String("maxPricePerUnit", *cfg.MaxPricePerUnit, "The maximum transcoding price per 'pixelsPerUnit' a broadcaster is willing to accept. If not set explicitly, broadcaster is willing to accept ANY price. Can be specified in wei or a custom currency in the format (e.g. 0.50USD). When using a custom currency, a corresponding price feed must be configured with -priceFeedAddr") cfg.MinPerfScore = flag.Float64("minPerfScore", *cfg.MinPerfScore, "The minimum orchestrator's performance score a broadcaster is willing to accept") // Transcoding: @@ -171,11 +171,12 @@ func parseLivepeerConfig() starter.LivepeerConfig { // Broadcaster deposit multiplier to determine max acceptable ticket faceValue cfg.DepositMultiplier = flag.Int("depositMultiplier", *cfg.DepositMultiplier, "The deposit multiplier used to determine max acceptable faceValue for PM tickets") // Orchestrator base pricing info - cfg.PricePerUnit = flag.Int("pricePerUnit", 0, "The price per 'pixelsPerUnit' amount pixels") - // Unit of pixels for both O's basePriceInfo and B's MaxBroadcastPrice - cfg.PixelsPerUnit = flag.Int("pixelsPerUnit", *cfg.PixelsPerUnit, "Amount of pixels per unit. Set to '> 1' to have smaller price granularity than 1 wei / pixel") + cfg.PricePerUnit = flag.String("pricePerUnit", "0", "The price per 'pixelsPerUnit' amount pixels. Can be specified in wei or a custom currency in the format (e.g. 0.50USD). When using a custom currency, a corresponding price feed must be configured with -priceFeedAddr") + // Unit of pixels for both O's pricePerUnit and B's maxPricePerUnit + cfg.PixelsPerUnit = flag.String("pixelsPerUnit", *cfg.PixelsPerUnit, "Amount of pixels per unit. Set to '> 1' to have smaller price granularity than 1 wei / pixel") + cfg.PriceFeedAddr = flag.String("priceFeedAddr", *cfg.PriceFeedAddr, "ETH address of the Chainlink price feed contract. Used for custom currencies conversion on -pricePerUnit or -maxPricePerUnit") cfg.AutoAdjustPrice = flag.Bool("autoAdjustPrice", *cfg.AutoAdjustPrice, "Enable/disable automatic price adjustments based on the overhead for redeeming tickets") - cfg.PricePerBroadcaster = flag.String("pricePerBroadcaster", *cfg.PricePerBroadcaster, `json list of price per broadcaster or path to json config file. Example: {"broadcasters":[{"ethaddress":"address1","priceperunit":1000,"pixelsperunit":1},{"ethaddress":"address2","priceperunit":1200,"pixelsperunit":1}]}`) + cfg.PricePerBroadcaster = flag.String("pricePerBroadcaster", *cfg.PricePerBroadcaster, `json list of price per broadcaster or path to json config file. Example: {"broadcasters":[{"ethaddress":"address1","priceperunit":0.5,"currency":"USD","pixelsperunit":1000000000000},{"ethaddress":"address2","priceperunit":0.3,"currency":"USD","pixelsperunit":1000000000000}]}`) // Interval to poll for blocks cfg.BlockPollingInterval = flag.Int("blockPollingInterval", *cfg.BlockPollingInterval, "Interval in seconds at which different blockchain event services poll for blocks") // Redemption service diff --git a/cmd/livepeer/starter/starter.go b/cmd/livepeer/starter/starter.go index 8c5da0bf2a..2896d95431 100755 --- a/cmd/livepeer/starter/starter.go +++ b/cmd/livepeer/starter/starter.go @@ -15,6 +15,7 @@ import ( "os" "os/user" "path/filepath" + "regexp" "strconv" "strings" "time" @@ -32,6 +33,7 @@ import ( "github.com/livepeer/go-livepeer/eth" "github.com/livepeer/go-livepeer/eth/blockwatch" "github.com/livepeer/go-livepeer/eth/watchers" + "github.com/livepeer/go-livepeer/monitor" lpmon "github.com/livepeer/go-livepeer/monitor" "github.com/livepeer/go-livepeer/pm" "github.com/livepeer/go-livepeer/server" @@ -95,7 +97,7 @@ type LivepeerConfig struct { SelectPriceExpFactor *float64 OrchPerfStatsURL *string Region *string - MaxPricePerUnit *int + MaxPricePerUnit *string MinPerfScore *float64 MaxSessions *string CurrentManifest *bool @@ -118,8 +120,9 @@ type LivepeerConfig struct { MaxTicketEV *string MaxTotalEV *string DepositMultiplier *int - PricePerUnit *int - PixelsPerUnit *int + PricePerUnit *string + PixelsPerUnit *string + PriceFeedAddr *string AutoAdjustPrice *bool PricePerBroadcaster *string BlockPollingInterval *int @@ -192,8 +195,9 @@ func DefaultLivepeerConfig() LivepeerConfig { defaultMaxTicketEV := "3000000000000" defaultMaxTotalEV := "20000000000000" defaultDepositMultiplier := 1 - defaultMaxPricePerUnit := 0 - defaultPixelsPerUnit := 1 + defaultMaxPricePerUnit := "0" + defaultPixelsPerUnit := "1" + defaultPriceFeedAddr := "0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612" // ETH / USD price feed address on Arbitrum Mainnet defaultAutoAdjustPrice := true defaultPricePerBroadcaster := "" defaultBlockPollingInterval := 5 @@ -278,6 +282,7 @@ func DefaultLivepeerConfig() LivepeerConfig { DepositMultiplier: &defaultDepositMultiplier, MaxPricePerUnit: &defaultMaxPricePerUnit, PixelsPerUnit: &defaultPixelsPerUnit, + PriceFeedAddr: &defaultPriceFeedAddr, AutoAdjustPrice: &defaultAutoAdjustPrice, PricePerBroadcaster: &defaultPricePerBroadcaster, BlockPollingInterval: &defaultBlockPollingInterval, @@ -712,6 +717,13 @@ func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { go serviceRegistryWatcher.Watch() defer serviceRegistryWatcher.Stop() + core.PriceFeedWatcher, err = watchers.NewPriceFeedWatcher(backend, *cfg.PriceFeedAddr) + // The price feed watch loop is started on demand on first subscribe. + if err != nil { + glog.Errorf("Failed to set up price feed watcher: %v", err) + return + } + n.Balances = core.NewAddressBalances(cleanupInterval) defer n.Balances.StopCleanup() @@ -733,27 +745,44 @@ func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { if *cfg.Orchestrator { // Set price per pixel base info - if *cfg.PixelsPerUnit <= 0 { + pixelsPerUnit, ok := new(big.Rat).SetString(*cfg.PixelsPerUnit) + if !ok || !pixelsPerUnit.IsInt() { + panic(fmt.Errorf("-pixelsPerUnit must be a valid integer, provided %v", *cfg.PixelsPerUnit)) + } + if pixelsPerUnit.Sign() <= 0 { // Can't divide by 0 - panic(fmt.Errorf("-pixelsPerUnit must be > 0, provided %d", *cfg.PixelsPerUnit)) + panic(fmt.Errorf("-pixelsPerUnit must be > 0, provided %v", *cfg.PixelsPerUnit)) } if cfg.PricePerUnit == nil { // Prevent orchestrators from unknowingly providing free transcoding panic(fmt.Errorf("-pricePerUnit must be set")) } - if *cfg.PricePerUnit < 0 { - panic(fmt.Errorf("-pricePerUnit must be >= 0, provided %d", *cfg.PricePerUnit)) + pricePerUnit, currency, err := parsePricePerUnit(*cfg.PricePerUnit) + if err != nil { + panic(fmt.Errorf("-pricePerUnit must be a valid integer with an optional currency, provided %v", *cfg.PricePerUnit)) + } else if pricePerUnit.Sign() < 0 { + panic(fmt.Errorf("-pricePerUnit must be >= 0, provided %s", pricePerUnit)) + } + pricePerPixel := new(big.Rat).Quo(pricePerUnit, pixelsPerUnit) + autoPrice, err := core.NewAutoConvertedPrice(currency, pricePerPixel, func(price *big.Rat) { + glog.Infof("Price: %v wei per pixel\n ", price.FloatString(3)) + }) + if err != nil { + panic(fmt.Errorf("Error converting price: %v", err)) } - n.SetBasePrice("default", big.NewRat(int64(*cfg.PricePerUnit), int64(*cfg.PixelsPerUnit))) - glog.Infof("Price: %d wei for %d pixels\n ", *cfg.PricePerUnit, *cfg.PixelsPerUnit) - - if *cfg.PricePerBroadcaster != "" { - ppb := getBroadcasterPrices(*cfg.PricePerBroadcaster) - for _, p := range ppb { - price := big.NewRat(p.PricePerUnit, p.PixelsPerUnit) - n.SetBasePrice(p.EthAddress, price) - glog.Infof("Price: %v set for broadcaster %v", price.RatString(), p.EthAddress) + n.SetBasePrice("default", autoPrice) + + broadcasterPrices := getBroadcasterPrices(*cfg.PricePerBroadcaster) + for _, p := range broadcasterPrices { + p := p + pricePerPixel := new(big.Rat).Quo(p.PricePerUnit, p.PixelsPerUnit) + autoPrice, err := core.NewAutoConvertedPrice(p.Currency, pricePerPixel, func(price *big.Rat) { + glog.Infof("Price: %v wei per pixel for broadcaster %v", price.FloatString(3), p.EthAddress) + }) + if err != nil { + panic(fmt.Errorf("Error converting price for broadcaster %s: %v", p.EthAddress, err)) } + n.SetBasePrice(p.EthAddress, autoPrice) } n.AutoSessionLimit = *cfg.MaxSessions == "auto" @@ -850,12 +879,30 @@ func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { n.Sender = pm.NewSender(n.Eth, timeWatcher, senderWatcher, maxEV, maxTotalEV, *cfg.DepositMultiplier) - if *cfg.PixelsPerUnit <= 0 { + pixelsPerUnit, ok := new(big.Rat).SetString(*cfg.PixelsPerUnit) + if !ok || !pixelsPerUnit.IsInt() { + panic(fmt.Errorf("-pixelsPerUnit must be a valid integer, provided %v", *cfg.PixelsPerUnit)) + } + if pixelsPerUnit.Sign() <= 0 { // Can't divide by 0 - panic(fmt.Errorf("The amount of pixels per unit must be greater than 0, provided %d instead\n", *cfg.PixelsPerUnit)) + panic(fmt.Errorf("-pixelsPerUnit must be > 0, provided %v", *cfg.PixelsPerUnit)) + } + maxPricePerUnit, currency, err := parsePricePerUnit(*cfg.MaxPricePerUnit) + if err != nil { + panic(fmt.Errorf("The maximum price per unit must be a valid integer with an optional currency, provided %v instead\n", *cfg.MaxPricePerUnit)) } - if *cfg.MaxPricePerUnit > 0 { - server.BroadcastCfg.SetMaxPrice(big.NewRat(int64(*cfg.MaxPricePerUnit), int64(*cfg.PixelsPerUnit))) + if maxPricePerUnit.Sign() > 0 { + pricePerPixel := new(big.Rat).Quo(maxPricePerUnit, pixelsPerUnit) + autoPrice, err := core.NewAutoConvertedPrice(currency, pricePerPixel, func(price *big.Rat) { + if monitor.Enabled { + monitor.MaxTranscodingPrice(price) + } + glog.Infof("Maximum transcoding price: %v wei per pixel\n ", price.FloatString(3)) + }) + if err != nil { + panic(fmt.Errorf("Error converting price: %v", err)) + } + server.BroadcastCfg.SetMaxPrice(autoPrice) } else { glog.Infof("Maximum transcoding price per pixel is not greater than 0: %v, broadcaster is currently set to accept ANY price.\n", *cfg.MaxPricePerUnit) glog.Infoln("To update the broadcaster's maximum acceptable transcoding price per pixel, use the CLI or restart the broadcaster with the appropriate 'maxPricePerUnit' and 'pixelsPerUnit' values") @@ -1420,29 +1467,59 @@ func checkOrStoreChainID(dbh *common.DB, chainID *big.Int) error { return nil } -// Format of broadcasterPrices json -// {"broadcasters":[{"ethaddress":"address1","priceperunit":1000,"pixelsperunit":1}, {"ethaddress":"address2","priceperunit":2000,"pixelsperunit":3}]} -type BroadcasterPrices struct { - Prices []BroadcasterPrice `json:"broadcasters"` -} - type BroadcasterPrice struct { - EthAddress string `json:"ethaddress"` - PricePerUnit int64 `json:"priceperunit"` - PixelsPerUnit int64 `json:"pixelsperunit"` + EthAddress string + PricePerUnit *big.Rat + Currency string + PixelsPerUnit *big.Rat } func getBroadcasterPrices(broadcasterPrices string) []BroadcasterPrice { - var pricesSet BroadcasterPrices - prices, _ := common.ReadFromFile(broadcasterPrices) + if broadcasterPrices == "" { + return nil + } + + // Format of broadcasterPrices json + // {"broadcasters":[{"ethaddress":"address1","priceperunit":0.5,"currency":"USD","pixelsperunit":1}, {"ethaddress":"address2","priceperunit":0.3,"currency":"USD","pixelsperunit":3}]} + var pricesSet struct { + Broadcasters []struct { + EthAddress string `json:"ethaddress"` + // The fields below are specified as a number in the JSON, but we don't want to lose precision so we store the raw characters here and parse as a big.Rat. + // This also allows support for exponential notation for numbers, which is helpful for pricePerUnit which could be a value like 1e12. + PixelsPerUnit json.RawMessage `json:"pixelsperunit"` + PricePerUnit json.RawMessage `json:"priceperunit"` + Currency string `json:"currency"` + } `json:"broadcasters"` + } + pricesFileContent, _ := common.ReadFromFile(broadcasterPrices) - err := json.Unmarshal([]byte(prices), &pricesSet) + err := json.Unmarshal([]byte(pricesFileContent), &pricesSet) if err != nil { glog.Errorf("broadcaster prices could not be parsed: %s", err) return nil } - return pricesSet.Prices + prices := make([]BroadcasterPrice, len(pricesSet.Broadcasters)) + for i, p := range pricesSet.Broadcasters { + pixelsPerUnit, ok := new(big.Rat).SetString(string(p.PixelsPerUnit)) + if !ok { + glog.Errorf("Pixels per unit could not be parsed for broadcaster %v. must be a valid number, provided %s", p.EthAddress, p.PixelsPerUnit) + continue + } + pricePerUnit, ok := new(big.Rat).SetString(string(p.PricePerUnit)) + if !ok { + glog.Errorf("Price per unit could not be parsed for broadcaster %v. must be a valid number, provided %s", p.EthAddress, p.PricePerUnit) + continue + } + prices[i] = BroadcasterPrice{ + EthAddress: p.EthAddress, + Currency: p.Currency, + PricePerUnit: pricePerUnit, + PixelsPerUnit: pixelsPerUnit, + } + } + + return prices } func createSelectionAlgorithm(cfg LivepeerConfig) (common.SelectionAlgorithm, error) { @@ -1494,6 +1571,22 @@ func parseEthKeystorePath(ethKeystorePath string) (keystorePath, error) { return keystore, nil } +func parsePricePerUnit(pricePerUnitStr string) (*big.Rat, string, error) { + pricePerUnitRex := regexp.MustCompile(`^(\d+(\.\d+)?)([A-z][A-z0-9]*)?$`) + match := pricePerUnitRex.FindStringSubmatch(pricePerUnitStr) + if match == nil { + return nil, "", fmt.Errorf("price must be in the format of , provided %v", pricePerUnitStr) + } + price, currency := match[1], match[3] + + pricePerUnit, ok := new(big.Rat).SetString(price) + if !ok { + return nil, "", fmt.Errorf("price must be a valid number, provided %v", match[1]) + } + + return pricePerUnit, currency, nil +} + func refreshOrchPerfScoreLoop(ctx context.Context, region string, orchPerfScoreURL string, score *common.PerfScore) { for { refreshOrchPerfScore(region, orchPerfScoreURL, score) diff --git a/cmd/livepeer/starter/starter_test.go b/cmd/livepeer/starter/starter_test.go index 18a08633a2..45d3620b8e 100644 --- a/cmd/livepeer/starter/starter_test.go +++ b/cmd/livepeer/starter/starter_test.go @@ -96,8 +96,8 @@ func TestParseGetBroadcasterPrices(t *testing.T) { assert.NotNil(prices) assert.Equal(2, len(prices)) - price1 := big.NewRat(prices[0].PricePerUnit, prices[0].PixelsPerUnit) - price2 := big.NewRat(prices[1].PricePerUnit, prices[1].PixelsPerUnit) + price1 := new(big.Rat).Quo(prices[0].PricePerUnit, prices[0].PixelsPerUnit) + price2 := new(big.Rat).Quo(prices[1].PricePerUnit, prices[1].PixelsPerUnit) assert.Equal(big.NewRat(1000, 1), price1) assert.Equal(big.NewRat(2000, 3), price2) } @@ -295,3 +295,91 @@ func TestUpdatePerfScore(t *testing.T) { } require.Equal(t, expScores, scores.Scores) } + +func TestParsePricePerUnit(t *testing.T) { + tests := []struct { + name string + pricePerUnitStr string + expectedPrice *big.Rat + expectedCurrency string + expectError bool + }{ + { + name: "Valid input with integer price", + pricePerUnitStr: "100USD", + expectedPrice: big.NewRat(100, 1), + expectedCurrency: "USD", + expectError: false, + }, + { + name: "Valid input with fractional price", + pricePerUnitStr: "0.13USD", + expectedPrice: big.NewRat(13, 100), + expectedCurrency: "USD", + expectError: false, + }, + { + name: "Valid input with decimal price", + pricePerUnitStr: "99.99EUR", + expectedPrice: big.NewRat(9999, 100), + expectedCurrency: "EUR", + expectError: false, + }, + { + name: "Lower case currency", + pricePerUnitStr: "99.99eur", + expectedPrice: big.NewRat(9999, 100), + expectedCurrency: "eur", + expectError: false, + }, + { + name: "Currency with numbers", + pricePerUnitStr: "420DOG3", + expectedPrice: big.NewRat(420, 1), + expectedCurrency: "DOG3", + expectError: false, + }, + { + name: "No specified currency, empty currency", + pricePerUnitStr: "100", + expectedPrice: big.NewRat(100, 1), + expectedCurrency: "", + expectError: false, + }, + { + name: "Explicit wei currency", + pricePerUnitStr: "100wei", + expectedPrice: big.NewRat(100, 1), + expectedCurrency: "wei", + expectError: false, + }, + { + name: "Invalid number", + pricePerUnitStr: "abcUSD", + expectedPrice: nil, + expectedCurrency: "", + expectError: true, + }, + { + name: "Negative price", + pricePerUnitStr: "-100USD", + expectedPrice: nil, + expectedCurrency: "", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + price, currency, err := parsePricePerUnit(tt.pricePerUnitStr) + + if tt.expectError { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.True(t, tt.expectedPrice.Cmp(price) == 0) + assert.Equal(t, tt.expectedCurrency, currency) + } + }) + } +} diff --git a/cmd/livepeer_cli/wizard_broadcast.go b/cmd/livepeer_cli/wizard_broadcast.go index b7967b0dd6..8f2c59e917 100644 --- a/cmd/livepeer_cli/wizard_broadcast.go +++ b/cmd/livepeer_cli/wizard_broadcast.go @@ -57,10 +57,14 @@ func (w *wizard) setBroadcastConfig() { fmt.Printf("eg. 1 wei / 10 pixels = 0,1 wei per pixel \n") fmt.Printf("\n") fmt.Printf("Enter amount of pixels that make up a single unit (default: 1 pixel) - ") - pixelsPerUnit := w.readDefaultInt(1) + // Read numbers as strings not to lose precision and support big numbers + pixelsPerUnit := w.readDefaultString("1") fmt.Printf("\n") - fmt.Printf("Enter the maximum price to pay for %d pixels in Wei (required) - ", pixelsPerUnit) - maxPricePerUnit := w.readDefaultInt(0) + fmt.Printf("Enter the currency for the price per unit (default: Wei) - ") + currency := w.readDefaultString("Wei") + fmt.Printf("\n") + fmt.Printf("Enter the maximum price to pay for %s pixels in %s (default: 0) - ", pixelsPerUnit, currency) + maxPricePerUnit := w.readDefaultString("0") opts := w.allTranscodingOptions() if opts == nil { @@ -77,12 +81,18 @@ func (w *wizard) setBroadcastConfig() { } val := url.Values{ - "pixelsPerUnit": {fmt.Sprintf("%v", strconv.Itoa(pixelsPerUnit))}, - "maxPricePerUnit": {fmt.Sprintf("%v", strconv.Itoa(maxPricePerUnit))}, + "pixelsPerUnit": {fmt.Sprintf("%v", pixelsPerUnit)}, + "currency": {fmt.Sprintf("%v", currency)}, + "maxPricePerUnit": {fmt.Sprintf("%v", maxPricePerUnit)}, "transcodingOptions": {fmt.Sprintf("%v", transOpts)}, } - httpPostWithParams(fmt.Sprintf("http://%v:%v/setBroadcastConfig", w.host, w.httpPort), val) + result, ok := httpPostWithParams(fmt.Sprintf("http://%v:%v/setBroadcastConfig", w.host, w.httpPort), val) + if !ok { + fmt.Printf("Error applying configuration: %s\n", result) + } else { + fmt.Printf("Configuration applied successfully\n") + } } func (w *wizard) idListToVideoProfileList(idList string, opts map[int]string) (string, error) { diff --git a/cmd/livepeer_cli/wizard_stats.go b/cmd/livepeer_cli/wizard_stats.go index 8a251fc9a4..bea3b07908 100644 --- a/cmd/livepeer_cli/wizard_stats.go +++ b/cmd/livepeer_cli/wizard_stats.go @@ -171,14 +171,10 @@ func (w *wizard) broadcastStats() { } price, transcodingOptions := w.getBroadcastConfig() - priceString := "n/a" - if price != nil { - priceString = fmt.Sprintf("%v wei / %v pixels", price.Num().Int64(), price.Denom().Int64()) - } table := tablewriter.NewWriter(os.Stdout) data := [][]string{ - {"Max Price Per Pixel", priceString}, + {"Max Price Per Pixel", formatPricePerPixel(price)}, {"Broadcast Transcoding Options", transcodingOptions}, {"Deposit", eth.FormatUnits(sender.Deposit, "ETH")}, {"Reserve", eth.FormatUnits(sender.Reserve.FundsRemaining, "ETH")}, @@ -227,7 +223,7 @@ func (w *wizard) orchestratorStats() { {"Reward Cut (%)", eth.FormatPerc(t.RewardCut)}, {"Fee Cut (%)", eth.FormatPerc(flipPerc(t.FeeShare))}, {"Last Reward Round", t.LastRewardRound.String()}, - {"Base price per pixel", fmt.Sprintf("%v wei / %v pixels", priceInfo.Num(), priceInfo.Denom())}, + {"Base price per pixel", formatPricePerPixel(priceInfo)}, {"Base price for broadcasters", b_prices}, } @@ -488,7 +484,9 @@ func (w *wizard) getBroadcasterPrices() (string, error) { return "", err } - var status map[string]interface{} + var status struct { + BroadcasterPrices map[string]*big.Rat `json:"BroadcasterPrices"` + } err = json.Unmarshal(result, &status) if err != nil { return "", err @@ -496,13 +494,21 @@ func (w *wizard) getBroadcasterPrices() (string, error) { prices := new(bytes.Buffer) - if broadcasterPrices, ok := status["BroadcasterPrices"]; ok { - for b, p := range broadcasterPrices.(map[string]interface{}) { - if b != "default" { - fmt.Fprintf(prices, "%s: %s per pixel\n", b, p) - } + for b, p := range status.BroadcasterPrices { + if b != "default" { + fmt.Fprintf(prices, "%s: %s\n", b, formatPricePerPixel(p)) } } return prices.String(), nil } + +func formatPricePerPixel(price *big.Rat) string { + if price == nil { + return "n/a" + } + if price.IsInt() { + return fmt.Sprintf("%v wei/pixel", price.RatString()) + } + return fmt.Sprintf("%v wei/pixel (%v/%v)", price.FloatString(3), price.Num(), price.Denom()) +} diff --git a/cmd/livepeer_cli/wizard_transcoder.go b/cmd/livepeer_cli/wizard_transcoder.go index b25644a744..2416aadbd0 100644 --- a/cmd/livepeer_cli/wizard_transcoder.go +++ b/cmd/livepeer_cli/wizard_transcoder.go @@ -43,13 +43,7 @@ func myHostPort() string { return "https://" + ip + ":" + defaultRPCPort } -func (w *wizard) promptOrchestratorConfig() (float64, float64, int, int, string) { - var ( - blockRewardCut float64 - feeCut float64 - addr string - ) - +func (w *wizard) promptOrchestratorConfig() (blockRewardCut, feeCut float64, pricePerUnit, currency, pixelsPerUnit, serviceURI string) { orch, _, err := w.getOrchestratorInfo() if err != nil || orch == nil { fmt.Println("unable to get current reward cut and fee cut") @@ -68,17 +62,23 @@ func (w *wizard) promptOrchestratorConfig() (float64, float64, int, int, string) fmt.Println("eg. 1 wei / 10 pixels = 0,1 wei per pixel") fmt.Println() fmt.Printf("Enter amount of pixels that make up a single unit (default: 1 pixel) ") - pixelsPerUnit := w.readDefaultInt(1) - fmt.Printf("Enter the price for %d pixels in Wei (required) ", pixelsPerUnit) - pricePerUnit := w.readDefaultInt(0) + // Read numbers as strings not to lose precision and support big numbers + pixelsPerUnit = w.readDefaultString("1") + fmt.Println() + fmt.Printf("Enter the currency for the price per unit (default: Wei) ") + currency = w.readDefaultString("Wei") + fmt.Println() + fmt.Printf("Enter the price for %s pixels in %s (default: 0) ", pixelsPerUnit, currency) + pricePerUnit = w.readDefaultString("0") + var addr string if orch.ServiceURI == "" { addr = myHostPort() } else { addr = orch.ServiceURI } fmt.Printf("Enter the public host:port of node (default: %v)", addr) - serviceURI := w.readStringAndValidate(func(in string) (string, error) { + serviceURI = w.readStringAndValidate(func(in string) (string, error) { if "" == in { in = addr } @@ -92,7 +92,7 @@ func (w *wizard) promptOrchestratorConfig() (float64, float64, int, int, string) return in, nil }) - return blockRewardCut, 100 - feeCut, pricePerUnit, pixelsPerUnit, serviceURI + return blockRewardCut, 100 - feeCut, pricePerUnit, currency, pixelsPerUnit, serviceURI } func (w *wizard) activateOrchestrator() { @@ -196,13 +196,14 @@ func (w *wizard) setOrchestratorConfig() { } func (w *wizard) getOrchestratorConfigFormValues() url.Values { - blockRewardCut, feeShare, pricePerUnit, pixelsPerUnit, serviceURI := w.promptOrchestratorConfig() + blockRewardCut, feeShare, pricePerUnit, currency, pixelsPerUnit, serviceURI := w.promptOrchestratorConfig() return url.Values{ "blockRewardCut": {fmt.Sprintf("%v", blockRewardCut)}, "feeShare": {fmt.Sprintf("%v", feeShare)}, - "pricePerUnit": {fmt.Sprintf("%v", strconv.Itoa(pricePerUnit))}, - "pixelsPerUnit": {fmt.Sprintf("%v", strconv.Itoa(pixelsPerUnit))}, + "pricePerUnit": {fmt.Sprintf("%v", pricePerUnit)}, + "currency": {fmt.Sprintf("%v", currency)}, + "pixelsPerUnit": {fmt.Sprintf("%v", pixelsPerUnit)}, "serviceURI": {fmt.Sprintf("%v", serviceURI)}, } } @@ -319,18 +320,22 @@ func (w *wizard) setPriceForBroadcaster() { return in, nil }) - fmt.Println("Enter price per unit:") - price := w.readDefaultInt(0) - fmt.Println("Enter pixels per unit:") - pixels := w.readDefaultInt(1) + fmt.Println("Enter pixels per unit (default: 1 pixel)") + // Read numbers as strings not to lose precision and support big numbers + pixels := w.readDefaultString("1") + fmt.Println("Enter currency for the price per unit (default: Wei)") + currency := w.readDefaultString("Wei") + fmt.Println("Enter price per unit (default: 0)") + price := w.readDefaultString("0") data := url.Values{ - "pricePerUnit": {fmt.Sprintf("%v", strconv.Itoa(price))}, - "pixelsPerUnit": {fmt.Sprintf("%v", strconv.Itoa(pixels))}, + "pricePerUnit": {fmt.Sprintf("%v", price)}, + "currency": {fmt.Sprintf("%v", currency)}, + "pixelsPerUnit": {fmt.Sprintf("%v", pixels)}, "broadcasterEthAddr": {fmt.Sprintf("%v", ethaddr)}, } result, ok := httpPostWithParams(fmt.Sprintf("http://%v:%v/setPriceForBroadcaster", w.host, w.httpPort), data) if ok { - fmt.Printf("Price for broadcaster %v set to %v gwei per %v pixels", ethaddr, price, pixels) + fmt.Printf("Price for broadcaster %v set to %v %v per %v pixels", ethaddr, price, currency, pixels) return } else { fmt.Printf("Error setting price for broadcaster: %v", result) diff --git a/core/autoconvertedprice.go b/core/autoconvertedprice.go new file mode 100644 index 0000000000..b248937db1 --- /dev/null +++ b/core/autoconvertedprice.go @@ -0,0 +1,139 @@ +package core + +import ( + "context" + "fmt" + "math/big" + "strings" + "sync" + + "github.com/livepeer/go-livepeer/eth" + "github.com/livepeer/go-livepeer/eth/watchers" +) + +// PriceFeedWatcher is a global instance of a PriceFeedWatcher. It must be +// initialized before creating an AutoConvertedPrice instance. +var PriceFeedWatcher watchers.PriceFeedWatcher + +// Number of wei in 1 ETH +var weiPerETH = big.NewRat(1e18, 1) + +// AutoConvertedPrice represents a price that is automatically converted to wei +// based on the current price of ETH in a given currency. It uses the static +// PriceFeedWatcher that must be configured before creating an instance. +type AutoConvertedPrice struct { + cancelSubscription func() + onUpdate func(*big.Rat) + basePrice *big.Rat + + mu sync.RWMutex + current *big.Rat +} + +// NewFixedPrice creates a new AutoConvertedPrice with a fixed price in wei. +func NewFixedPrice(price *big.Rat) *AutoConvertedPrice { + return &AutoConvertedPrice{current: price} +} + +// NewAutoConvertedPrice creates a new AutoConvertedPrice instance with the given +// currency and base price. The onUpdate function is optional and gets called +// whenever the price is updated (also with the initial price). The Stop function +// must be called to free resources when the price is no longer needed. +func NewAutoConvertedPrice(currency string, basePrice *big.Rat, onUpdate func(*big.Rat)) (*AutoConvertedPrice, error) { + if onUpdate == nil { + onUpdate = func(*big.Rat) {} + } + + // Default currency (wei/eth) doesn't need the conversion loop + if lcurr := strings.ToLower(currency); lcurr == "" || lcurr == "wei" || lcurr == "eth" { + price := basePrice + if lcurr == "eth" { + price = new(big.Rat).Mul(basePrice, weiPerETH) + } + onUpdate(price) + return NewFixedPrice(price), nil + } + + if PriceFeedWatcher == nil { + return nil, fmt.Errorf("PriceFeedWatcher is not initialized") + } + + base, quote, err := PriceFeedWatcher.Currencies() + if err != nil { + return nil, fmt.Errorf("error getting price feed currencies: %v", err) + } + base, quote, currency = strings.ToUpper(base), strings.ToUpper(quote), strings.ToUpper(currency) + if base != "ETH" && quote != "ETH" { + return nil, fmt.Errorf("price feed does not have ETH as a currency (%v/%v)", base, quote) + } + if base != currency && quote != currency { + return nil, fmt.Errorf("price feed does not have %v as a currency (%v/%v)", currency, base, quote) + } + + currencyPrice, err := PriceFeedWatcher.Current() + if err != nil { + return nil, fmt.Errorf("error getting current price data: %v", err) + } + + ctx, cancel := context.WithCancel(context.Background()) + price := &AutoConvertedPrice{ + cancelSubscription: cancel, + onUpdate: onUpdate, + basePrice: basePrice, + current: new(big.Rat).Mul(basePrice, currencyToWeiMultiplier(currencyPrice, base)), + } + // Trigger the initial update with the current price + onUpdate(price.current) + + price.startAutoConvertLoop(ctx, base) + + return price, nil +} + +// Value returns the current price in wei. +func (a *AutoConvertedPrice) Value() *big.Rat { + a.mu.RLock() + defer a.mu.RUnlock() + return a.current +} + +// Stop unsubscribes from the price feed and frees resources from the +// auto-conversion loop. +func (a *AutoConvertedPrice) Stop() { + a.mu.Lock() + defer a.mu.Unlock() + if a.cancelSubscription != nil { + a.cancelSubscription() + a.cancelSubscription = nil + } +} + +func (a *AutoConvertedPrice) startAutoConvertLoop(ctx context.Context, baseCurrency string) { + priceUpdated := make(chan eth.PriceData, 1) + PriceFeedWatcher.Subscribe(ctx, priceUpdated) + go func() { + for { + select { + case <-ctx.Done(): + return + case currencyPrice := <-priceUpdated: + a.mu.Lock() + a.current = new(big.Rat).Mul(a.basePrice, currencyToWeiMultiplier(currencyPrice, baseCurrency)) + a.mu.Unlock() + + a.onUpdate(a.current) + } + } + }() +} + +// currencyToWeiMultiplier calculates the multiplier to convert the value +// specified in the custom currency to wei. +func currencyToWeiMultiplier(data eth.PriceData, baseCurrency string) *big.Rat { + ethMultipler := data.Price + if baseCurrency == "ETH" { + // Invert the multiplier if the quote is in the form ETH / X + ethMultipler = new(big.Rat).Inv(ethMultipler) + } + return new(big.Rat).Mul(ethMultipler, weiPerETH) +} diff --git a/core/autoconvertedprice_test.go b/core/autoconvertedprice_test.go new file mode 100644 index 0000000000..54db6cfde0 --- /dev/null +++ b/core/autoconvertedprice_test.go @@ -0,0 +1,258 @@ +package core + +import ( + "context" + "math/big" + "testing" + "time" + + "github.com/livepeer/go-livepeer/eth" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestNewAutoConvertedPrice(t *testing.T) { + t.Run("PriceFeedWatcher not initialized", func(t *testing.T) { + _, err := NewAutoConvertedPrice("USD", big.NewRat(1, 1), nil) + require.Error(t, err) + }) + + watcherMock := NewPriceFeedWatcherMock(t) + PriceFeedWatcher = watcherMock + watcherMock.On("Currencies").Return("ETH", "USD", nil) + + t.Run("Fixed price for wei", func(t *testing.T) { + price, err := NewAutoConvertedPrice("wei", big.NewRat(1, 1), nil) + require.NoError(t, err) + require.Equal(t, big.NewRat(1, 1), price.Value()) + require.Nil(t, price.cancelSubscription) + }) + + t.Run("Auto-converted price for ETH", func(t *testing.T) { + price, err := NewAutoConvertedPrice("ETH", big.NewRat(2, 1), nil) + require.NoError(t, err) + require.Equal(t, big.NewRat(2e18, 1), price.Value()) // 2 ETH in wei + require.Nil(t, price.cancelSubscription) + }) + + t.Run("Auto-converted price for USD", func(t *testing.T) { + watcherMock.On("Current").Return(eth.PriceData{Price: big.NewRat(100, 1)}, nil) + watcherMock.On("Subscribe", mock.Anything, mock.Anything).Once() + price, err := NewAutoConvertedPrice("USD", big.NewRat(2, 1), nil) + require.NoError(t, err) + require.Equal(t, big.NewRat(2e16, 1), price.Value()) // 2 USD * 1/100 ETH/USD + require.NotNil(t, price.cancelSubscription) + price.Stop() + }) + + t.Run("Currency not supported by feed", func(t *testing.T) { + _, err := NewAutoConvertedPrice("GBP", big.NewRat(1, 1), nil) + require.Error(t, err) + }) + + t.Run("Currency ETH not supported by feed", func(t *testing.T) { + // set up a new mock to change the currencies returned + watcherMock := NewPriceFeedWatcherMock(t) + PriceFeedWatcher = watcherMock + watcherMock.On("Currencies").Return("wei", "USD", nil) + + _, err := NewAutoConvertedPrice("USD", big.NewRat(1, 1), nil) + require.Error(t, err) + }) + + t.Run("Auto-converted price for inverted quote", func(t *testing.T) { + // set up a new mock to change the currencies returned + watcherMock := NewPriceFeedWatcherMock(t) + PriceFeedWatcher = watcherMock + watcherMock.On("Currencies").Return("USD", "ETH", nil) + watcherMock.On("Current").Return(eth.PriceData{Price: big.NewRat(1, 420)}, nil) + watcherMock.On("Subscribe", mock.Anything, mock.Anything).Once() + price, err := NewAutoConvertedPrice("USD", big.NewRat(66, 1), nil) + require.NoError(t, err) + require.Equal(t, big.NewRat(11e17, 7), price.Value()) // 66 USD * 1/420 ETH/USD + require.NotNil(t, price.cancelSubscription) + price.Stop() + }) +} + +func TestAutoConvertedPrice_Update(t *testing.T) { + require := require.New(t) + watcherMock := NewPriceFeedWatcherMock(t) + PriceFeedWatcher = watcherMock + + watcherMock.On("Currencies").Return("ETH", "USD", nil) + watcherMock.On("Current").Return(eth.PriceData{Price: big.NewRat(3000, 1)}, nil) + + priceUpdatedChan := make(chan *big.Rat, 1) + onUpdate := func(price *big.Rat) { + priceUpdatedChan <- price + } + + var sink chan<- eth.PriceData + watcherMock.On("Subscribe", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + sink = args.Get(1).(chan<- eth.PriceData) + }).Once() + + price, err := NewAutoConvertedPrice("USD", big.NewRat(50, 1), onUpdate) + require.NoError(err) + require.NotNil(t, price.cancelSubscription) + defer price.Stop() + watcherMock.AssertExpectations(t) + + require.Equal(big.NewRat(5e16, 3), price.Value()) // 50 USD * 1/3000 ETH/USD + require.Equal(big.NewRat(5e16, 3), <-priceUpdatedChan) // initial update must be sent + + // Simulate a price update + sink <- eth.PriceData{Price: big.NewRat(6000, 1)} + + select { + case updatedPrice := <-priceUpdatedChan: + require.Equal(big.NewRat(5e16, 6), updatedPrice) // 50 USD * 1/6000 USD/ETH + require.Equal(big.NewRat(5e16, 6), price.Value()) // must also udpate current value + case <-time.After(time.Second): + t.Fatal("Expected price update not received") + } +} + +func TestAutoConvertedPrice_Stop(t *testing.T) { + require := require.New(t) + watcherMock := NewPriceFeedWatcherMock(t) + PriceFeedWatcher = watcherMock + + watcherMock.On("Currencies").Return("ETH", "USD", nil) + watcherMock.On("Current").Return(eth.PriceData{Price: big.NewRat(100, 1)}, nil) + + var subsCtx context.Context + watcherMock.On("Subscribe", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + subsCtx = args.Get(0).(context.Context) + }).Once() + + price, err := NewAutoConvertedPrice("USD", big.NewRat(50, 1), nil) + require.NoError(err) + require.NotNil(t, price.cancelSubscription) + + price.Stop() + require.Nil(price.cancelSubscription) + require.Error(subsCtx.Err()) +} + +func TestCurrencyToWeiMultiplier(t *testing.T) { + tests := []struct { + name string + data eth.PriceData + baseCurrency string + expectedWei *big.Rat + }{ + { + name: "Base currency is ETH", + data: eth.PriceData{Price: big.NewRat(500, 1)}, // 500 USD per ETH + baseCurrency: "ETH", + expectedWei: big.NewRat(1e18, 500), // (1 / 500 USD/ETH) * 1e18 wei/ETH + }, + { + name: "Base currency is not ETH", + data: eth.PriceData{Price: big.NewRat(1, 2000)}, // 1/2000 ETH per USD + baseCurrency: "USD", + expectedWei: big.NewRat(5e14, 1), // (1 * 1/2000 ETH/USD) * 1e18 wei/ETH + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := currencyToWeiMultiplier(tt.data, tt.baseCurrency) + assert.Equal(t, 0, tt.expectedWei.Cmp(result)) + }) + } +} + +// Auto-generated code from here down. +// +// Code generated by mockery v2.42.1. DO NOT EDIT. + +// PriceFeedWatcherMock is an autogenerated mock type for the PriceFeedWatcher type +type PriceFeedWatcherMock struct { + mock.Mock +} + +// Currencies provides a mock function with given fields: +func (_m *PriceFeedWatcherMock) Currencies() (string, string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Currencies") + } + + var r0 string + var r1 string + var r2 error + if rf, ok := ret.Get(0).(func() (string, string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() string); ok { + r1 = rf() + } else { + r1 = ret.Get(1).(string) + } + + if rf, ok := ret.Get(2).(func() error); ok { + r2 = rf() + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Current provides a mock function with given fields: +func (_m *PriceFeedWatcherMock) Current() (eth.PriceData, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Current") + } + + var r0 eth.PriceData + var r1 error + if rf, ok := ret.Get(0).(func() (eth.PriceData, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() eth.PriceData); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(eth.PriceData) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Subscribe provides a mock function with given fields: ctx, sink +func (_m *PriceFeedWatcherMock) Subscribe(ctx context.Context, sink chan<- eth.PriceData) { + _m.Called(ctx, sink) +} + +// NewPriceFeedWatcherMock creates a new instance of PriceFeedWatcherMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewPriceFeedWatcherMock(t interface { + mock.TestingT + Cleanup(func()) +}) *PriceFeedWatcherMock { + mock := &PriceFeedWatcherMock{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/livepeernode.go b/core/livepeernode.go index 57b1055e39..f4741aae93 100644 --- a/core/livepeernode.go +++ b/core/livepeernode.go @@ -93,7 +93,7 @@ type LivepeerNode struct { StorageConfigs map[string]*transcodeConfig storageMutex *sync.RWMutex // Transcoder private fields - priceInfo map[string]*big.Rat + priceInfo map[string]*AutoConvertedPrice serviceURI url.URL segmentMutex *sync.RWMutex } @@ -109,7 +109,7 @@ func NewLivepeerNode(e eth.LivepeerEthClient, wd string, dbh *common.DB) (*Livep SegmentChans: make(map[ManifestID]SegmentChan), segmentMutex: &sync.RWMutex{}, Capabilities: &Capabilities{capacities: map[Capability]int{}}, - priceInfo: make(map[string]*big.Rat), + priceInfo: make(map[string]*AutoConvertedPrice), StorageConfigs: make(map[string]*transcodeConfig), storageMutex: &sync.RWMutex{}, }, nil @@ -128,12 +128,16 @@ func (n *LivepeerNode) SetServiceURI(newUrl *url.URL) { } // SetBasePrice sets the base price for an orchestrator on the node -func (n *LivepeerNode) SetBasePrice(b_eth_addr string, price *big.Rat) { +func (n *LivepeerNode) SetBasePrice(b_eth_addr string, price *AutoConvertedPrice) { addr := strings.ToLower(b_eth_addr) n.mu.Lock() defer n.mu.Unlock() + prevPrice := n.priceInfo[addr] n.priceInfo[addr] = price + if prevPrice != nil { + prevPrice.Stop() + } } // GetBasePrice gets the base price for an orchestrator @@ -142,14 +146,22 @@ func (n *LivepeerNode) GetBasePrice(b_eth_addr string) *big.Rat { n.mu.RLock() defer n.mu.RUnlock() - return n.priceInfo[addr] + price := n.priceInfo[addr] + if price == nil { + return nil + } + return price.Value() } func (n *LivepeerNode) GetBasePrices() map[string]*big.Rat { n.mu.RLock() defer n.mu.RUnlock() - return n.priceInfo + prices := make(map[string]*big.Rat) + for addr, price := range n.priceInfo { + prices[addr] = price.Value() + } + return prices } // SetMaxFaceValue sets the faceValue upper limit for tickets received diff --git a/core/livepeernode_test.go b/core/livepeernode_test.go index 259992f892..230f8dd421 100644 --- a/core/livepeernode_test.go +++ b/core/livepeernode_test.go @@ -162,8 +162,8 @@ func TestSetAndGetBasePrice(t *testing.T) { price := big.NewRat(1, 1) - n.SetBasePrice("default", price) - assert.Zero(n.priceInfo["default"].Cmp(price)) + n.SetBasePrice("default", NewFixedPrice(price)) + assert.Zero(n.priceInfo["default"].Value().Cmp(price)) assert.Zero(n.GetBasePrice("default").Cmp(price)) assert.Zero(n.GetBasePrices()["default"].Cmp(price)) @@ -172,10 +172,10 @@ func TestSetAndGetBasePrice(t *testing.T) { price1 := big.NewRat(2, 1) price2 := big.NewRat(3, 1) - n.SetBasePrice(addr1, price1) - n.SetBasePrice(addr2, price2) - assert.Zero(n.priceInfo[addr1].Cmp(price1)) - assert.Zero(n.priceInfo[addr2].Cmp(price2)) + n.SetBasePrice(addr1, NewFixedPrice(price1)) + n.SetBasePrice(addr2, NewFixedPrice(price2)) + assert.Zero(n.priceInfo[addr1].Value().Cmp(price1)) + assert.Zero(n.priceInfo[addr2].Value().Cmp(price2)) assert.Zero(n.GetBasePrices()[addr1].Cmp(price1)) assert.Zero(n.GetBasePrices()[addr2].Cmp(price2)) } diff --git a/core/orch_test.go b/core/orch_test.go index 981661433d..dcc8a6c2d9 100644 --- a/core/orch_test.go +++ b/core/orch_test.go @@ -704,7 +704,7 @@ func TestProcessPayment_GivenRecipientError_ReturnsNil(t *testing.T) { } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) recipient.On("TxCostMultiplier", mock.Anything).Return(big.NewRat(1, 1), nil) recipient.On("ReceiveTicket", mock.Anything, mock.Anything, mock.Anything).Return("", false, nil) @@ -785,7 +785,7 @@ func TestProcessPayment_ActiveOrchestrator(t *testing.T) { } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) // orchestrator inactive -> error err := orch.ProcessPayment(context.Background(), defaultPayment(t), ManifestID("some manifest")) @@ -856,7 +856,7 @@ func TestProcessPayment_GivenLosingTicket_DoesNotRedeem(t *testing.T) { } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) recipient.On("TxCostMultiplier", mock.Anything).Return(big.NewRat(1, 1), nil) recipient.On("ReceiveTicket", mock.Anything, mock.Anything, mock.Anything).Return("some sessionID", false, nil) @@ -888,7 +888,7 @@ func TestProcessPayment_GivenWinningTicket_RedeemError(t *testing.T) { } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) manifestID := ManifestID("some manifest") sessionID := "some sessionID" @@ -928,7 +928,7 @@ func TestProcessPayment_GivenWinningTicket_Redeems(t *testing.T) { } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) manifestID := ManifestID("some manifest") sessionID := "some sessionID" @@ -968,7 +968,7 @@ func TestProcessPayment_GivenMultipleWinningTickets_RedeemsAll(t *testing.T) { } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) manifestID := ManifestID("some manifest") sessionID := "some sessionID" @@ -1038,7 +1038,7 @@ func TestProcessPayment_GivenConcurrentWinningTickets_RedeemsAll(t *testing.T) { } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) manifestIDs := make([]string, 5) @@ -1097,7 +1097,7 @@ func TestProcessPayment_GivenReceiveTicketError_ReturnsError(t *testing.T) { } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) manifestID := ManifestID("some manifest") @@ -1165,7 +1165,7 @@ func TestProcessPayment_PaymentError_DoesNotIncreaseCreditBalance(t *testing.T) } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) manifestID := ManifestID("some manifest") paymentError := errors.New("ReceiveTicket error") @@ -1227,7 +1227,7 @@ func TestSufficientBalance_IsSufficient_ReturnsTrue(t *testing.T) { } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) manifestID := ManifestID("some manifest") @@ -1265,7 +1265,7 @@ func TestSufficientBalance_IsNotSufficient_ReturnsFalse(t *testing.T) { } orch := NewOrchestrator(n, rm) orch.address = addr - orch.node.SetBasePrice("default", big.NewRat(0, 1)) + orch.node.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) manifestID := ManifestID("some manifest") @@ -1307,7 +1307,7 @@ func TestSufficientBalance_OffChainMode_ReturnsTrue(t *testing.T) { func TestTicketParams(t *testing.T) { n, _ := NewLivepeerNode(nil, "", nil) - n.priceInfo["default"] = big.NewRat(1, 1) + n.priceInfo["default"] = NewFixedPrice(big.NewRat(1, 1)) priceInfo := &net.PriceInfo{PricePerUnit: 1, PixelsPerUnit: 1} recipient := new(pm.MockRecipient) n.Recipient = recipient @@ -1388,7 +1388,7 @@ func TestPriceInfo(t *testing.T) { expPricePerPixel := big.NewRat(101, 100) n, _ := NewLivepeerNode(nil, "", nil) - n.SetBasePrice("default", basePrice) + n.SetBasePrice("default", NewFixedPrice(basePrice)) recipient := new(pm.MockRecipient) n.Recipient = recipient @@ -1406,7 +1406,7 @@ func TestPriceInfo(t *testing.T) { // basePrice = 10/1, txMultiplier = 100/1 => expPricePerPixel = 1010/100 basePrice = big.NewRat(10, 1) - n.SetBasePrice("default", basePrice) + n.SetBasePrice("default", NewFixedPrice(basePrice)) orch = NewOrchestrator(n, nil) expPricePerPixel = big.NewRat(1010, 100) @@ -1421,7 +1421,7 @@ func TestPriceInfo(t *testing.T) { // basePrice = 1/10, txMultiplier = 100 => expPricePerPixel = 101/1000 basePrice = big.NewRat(1, 10) - n.SetBasePrice("default", basePrice) + n.SetBasePrice("default", NewFixedPrice(basePrice)) orch = NewOrchestrator(n, nil) expPricePerPixel = big.NewRat(101, 1000) @@ -1435,7 +1435,7 @@ func TestPriceInfo(t *testing.T) { assert.Equal(priceInfo.PixelsPerUnit, expPrice.Denom().Int64()) // basePrice = 25/10 , txMultiplier = 100 => expPricePerPixel = 2525/1000 basePrice = big.NewRat(25, 10) - n.SetBasePrice("default", basePrice) + n.SetBasePrice("default", NewFixedPrice(basePrice)) orch = NewOrchestrator(n, nil) expPricePerPixel = big.NewRat(2525, 1000) @@ -1451,7 +1451,7 @@ func TestPriceInfo(t *testing.T) { // basePrice = 10/1 , txMultiplier = 100/10 => expPricePerPixel = 11 basePrice = big.NewRat(10, 1) txMultiplier = big.NewRat(100, 10) - n.SetBasePrice("default", basePrice) + n.SetBasePrice("default", NewFixedPrice(basePrice)) recipient = new(pm.MockRecipient) n.Recipient = recipient recipient.On("TxCostMultiplier", mock.Anything).Return(txMultiplier, nil) @@ -1470,7 +1470,7 @@ func TestPriceInfo(t *testing.T) { // basePrice = 10/1 , txMultiplier = 1/10 => expPricePerPixel = 110 basePrice = big.NewRat(10, 1) txMultiplier = big.NewRat(1, 10) - n.SetBasePrice("default", basePrice) + n.SetBasePrice("default", NewFixedPrice(basePrice)) recipient = new(pm.MockRecipient) n.Recipient = recipient recipient.On("TxCostMultiplier", mock.Anything).Return(txMultiplier, nil) @@ -1489,7 +1489,7 @@ func TestPriceInfo(t *testing.T) { // basePrice = 10, txMultiplier = 1 => expPricePerPixel = 20 basePrice = big.NewRat(10, 1) txMultiplier = big.NewRat(1, 1) - n.SetBasePrice("default", basePrice) + n.SetBasePrice("default", NewFixedPrice(basePrice)) recipient = new(pm.MockRecipient) n.Recipient = recipient recipient.On("TxCostMultiplier", mock.Anything).Return(txMultiplier, nil) @@ -1506,7 +1506,7 @@ func TestPriceInfo(t *testing.T) { assert.Equal(priceInfo.PixelsPerUnit, expPrice.Denom().Int64()) // basePrice = 0 => expPricePerPixel = 0 - n.SetBasePrice("default", big.NewRat(0, 1)) + n.SetBasePrice("default", NewFixedPrice(big.NewRat(0, 1))) orch = NewOrchestrator(n, nil) priceInfo, err = orch.PriceInfo(ethcommon.Address{}, "") @@ -1516,7 +1516,7 @@ func TestPriceInfo(t *testing.T) { // test no overflows basePrice = big.NewRat(25000, 1) - n.SetBasePrice("default", basePrice) + n.SetBasePrice("default", NewFixedPrice(basePrice)) faceValue, _ := new(big.Int).SetString("22245599237119512", 10) txCost := new(big.Int).Mul(big.NewInt(100000), big.NewInt(7500000000)) txMultiplier = new(big.Rat).SetFrac(faceValue, txCost) // 926899968213313/31250000000000 @@ -1572,7 +1572,7 @@ func TestPriceInfo_TxMultiplierError_ReturnsError(t *testing.T) { expError := errors.New("TxMultiplier Error") n, _ := NewLivepeerNode(nil, "", nil) - n.SetBasePrice("default", big.NewRat(1, 1)) + n.SetBasePrice("default", NewFixedPrice(big.NewRat(1, 1))) recipient := new(pm.MockRecipient) n.Recipient = recipient recipient.On("TxCostMultiplier", mock.Anything).Return(nil, expError) diff --git a/discovery/discovery_test.go b/discovery/discovery_test.go index c52ce7ce61..c7e2b1d3ac 100644 --- a/discovery/discovery_test.go +++ b/discovery/discovery_test.go @@ -608,11 +608,11 @@ func TestNewOrchestratorPoolWithPred_TestPredicate(t *testing.T) { assert.True(t, pool.pred(oInfo)) // Set server.BroadcastCfg.maxPrice higher than PriceInfo , should return true - server.BroadcastCfg.SetMaxPrice(big.NewRat(10, 1)) + server.BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(10, 1))) assert.True(t, pool.pred(oInfo)) // Set MaxBroadcastPrice lower than PriceInfo, should return false - server.BroadcastCfg.SetMaxPrice(big.NewRat(1, 1)) + server.BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(1, 1))) assert.False(t, pool.pred(oInfo)) // PixelsPerUnit is 0 , return false @@ -629,7 +629,7 @@ func TestCachedPool_AllOrchestratorsTooExpensive_ReturnsEmptyList(t *testing.T) expTranscoder := "transcoderFromTest" expPricePerPixel, _ := common.PriceToFixed(big.NewRat(999, 1)) - server.BroadcastCfg.SetMaxPrice(big.NewRat(1, 1)) + server.BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(1, 1))) gmp := runtime.GOMAXPROCS(50) defer runtime.GOMAXPROCS(gmp) var mu sync.Mutex @@ -823,7 +823,7 @@ func TestCachedPool_N_OrchestratorsGoodPricing_ReturnsNOrchestrators(t *testing. }, } - server.BroadcastCfg.SetMaxPrice(big.NewRat(10, 1)) + server.BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(10, 1))) gmp := runtime.GOMAXPROCS(50) defer runtime.GOMAXPROCS(gmp) var mu sync.Mutex diff --git a/eth/watchers/pricefeedwatcher.go b/eth/watchers/pricefeedwatcher.go index ec7a81f2f3..1bab9dc130 100644 --- a/eth/watchers/pricefeedwatcher.go +++ b/eth/watchers/pricefeedwatcher.go @@ -19,78 +19,93 @@ const ( priceUpdatePeriod = 1 * time.Hour ) +type PriceFeedWatcher interface { + Currencies() (base string, quote string, err error) + Current() (eth.PriceData, error) + Subscribe(ctx context.Context, sink chan<- eth.PriceData) +} + // PriceFeedWatcher monitors a Chainlink PriceFeed for updated pricing info. It // allows fetching the current price as well as listening for updates on the // PriceUpdated channel. -type PriceFeedWatcher struct { +type priceFeedWatcher struct { baseRetryDelay time.Duration - priceFeed eth.PriceFeedEthClient - currencyBase, currencyQuote string + priceFeed eth.PriceFeedEthClient + + mu sync.RWMutex + current eth.PriceData + cancelWatch func() - mu sync.RWMutex - current eth.PriceData priceEventFeed event.Feed + subscriptions event.SubscriptionScope } // NewPriceFeedWatcher creates a new PriceFeedWatcher instance. It will already // fetch the current price and start a goroutine to watch for updates. -func NewPriceFeedWatcher(ethClient *ethclient.Client, priceFeedAddr string) (*PriceFeedWatcher, error) { +func NewPriceFeedWatcher(ethClient *ethclient.Client, priceFeedAddr string) (PriceFeedWatcher, error) { priceFeed, err := eth.NewPriceFeedEthClient(ethClient, priceFeedAddr) if err != nil { return nil, fmt.Errorf("failed to create price feed client: %w", err) } - - description, err := priceFeed.Description() - if err != nil { - return nil, fmt.Errorf("failed to get description: %w", err) - } - - currencyFrom, currencyTo, err := parseCurrencies(description) - if err != nil { - return nil, err - } - - w := &PriceFeedWatcher{ + w := &priceFeedWatcher{ baseRetryDelay: priceUpdateBaseRetryDelay, priceFeed: priceFeed, - currencyBase: currencyFrom, - currencyQuote: currencyTo, - } - - err = w.updatePrice() - if err != nil { - return nil, fmt.Errorf("failed to update price: %w", err) } - return w, nil } // Currencies returns the base and quote currencies of the price feed. // i.e. base = CurrentPrice() * quote -func (w *PriceFeedWatcher) Currencies() (base string, quote string) { - return w.currencyBase, w.currencyQuote +func (w *priceFeedWatcher) Currencies() (base string, quote string, err error) { + description, err := w.priceFeed.Description() + if err != nil { + return "", "", fmt.Errorf("failed to get description: %w", err) + } + + base, quote, err = parseCurrencies(description) + if err != nil { + return "", "", err + } + return } -// Current returns the latest fetched price data. -func (w *PriceFeedWatcher) Current() eth.PriceData { +// Current returns the latest fetched price data, or fetches it in case it has +// not been fetched yet. +func (w *priceFeedWatcher) Current() (eth.PriceData, error) { w.mu.RLock() - defer w.mu.RUnlock() - return w.current + current := w.current + w.mu.RUnlock() + if current.UpdatedAt.IsZero() { + return w.updatePrice() + } + return current, nil } // Subscribe allows one to subscribe to price updates emitted by the Watcher. -// To unsubscribe, simply call `Unsubscribe` on the returned subscription. // The sink channel should have ample buffer space to avoid blocking other -// subscribers. Slow subscribers are not dropped. -func (w *PriceFeedWatcher) Subscribe(sub chan<- eth.PriceData) event.Subscription { - return w.priceEventFeed.Subscribe(sub) +// subscribers. Slow subscribers are not dropped. The subscription is kept alive +// until the passed Context is cancelled. +// +// The watch loop is run automatically while there are active subscriptions. It +// will be started when the first subscription is made and is automatically +// stopped when the last subscription is closed. +func (w *priceFeedWatcher) Subscribe(ctx context.Context, sink chan<- eth.PriceData) { + w.mu.Lock() + defer w.mu.Unlock() + w.ensureWatchLocked() + + sub := w.subscriptions.Track(w.priceEventFeed.Subscribe(sink)) + go w.handleUnsubscribe(ctx, sub) } -func (w *PriceFeedWatcher) updatePrice() error { +// updatePrice fetches the latest price data from the price feed and updates the +// current price if it is newer. If the price is updated, it will also send the +// updated price to the price event feed. +func (w *priceFeedWatcher) updatePrice() (eth.PriceData, error) { newPrice, err := w.priceFeed.FetchPriceData() if err != nil { - return fmt.Errorf("failed to fetch price data: %w", err) + return eth.PriceData{}, fmt.Errorf("failed to fetch price data: %w", err) } if newPrice.UpdatedAt.After(w.current.UpdatedAt) { @@ -100,26 +115,62 @@ func (w *PriceFeedWatcher) updatePrice() error { w.priceEventFeed.Send(newPrice) } - return nil + return newPrice, nil } -// Watch starts the watch process. It will periodically poll the price feed for -// price updates until the given context is canceled. Typically, you want to -// call Watch inside a goroutine. -func (w *PriceFeedWatcher) Watch(ctx context.Context) { +// ensureWatchLocked makes sure that the watch process is running. It assumes it +// is already running in a locked context (w.mu). The watch process itself will +// run in background and periodically poll the price feed for updates until the +// `w.cancelWatch` function is called. +func (w *priceFeedWatcher) ensureWatchLocked() { + if w.cancelWatch != nil { + // already running + return + } + ctx, cancel := context.WithCancel(context.Background()) + w.cancelWatch = cancel + ticker := newTruncatedTicker(ctx, priceUpdatePeriod) - w.watchTicker(ctx, ticker) + go w.watchTicker(ctx, ticker) +} + +// handleUnsubscribe waits for the provided Context to be done and then closes +// the given subscription. It then stops the watch process if there are no more +// active subscriptions. +func (w *priceFeedWatcher) handleUnsubscribe(ctx context.Context, sub event.Subscription) { +loop: + for { + select { + case <-ctx.Done(): + break loop + case <-sub.Err(): + clog.Errorf(ctx, "PriceFeedWatcher subscription error: %v", sub.Err()) + } + } + w.mu.Lock() + defer w.mu.Unlock() + + sub.Unsubscribe() + if w.subscriptions.Count() == 0 && w.cancelWatch != nil { + w.cancelWatch() + w.cancelWatch = nil + } } -func (w *PriceFeedWatcher) watchTicker(ctx context.Context, ticker <-chan time.Time) { +// watchTicker is the main loop that periodically fetches the latest price data +// from the price feed. It's lifecycle is handled through the ensureWatch and +// handleUnsubscribe functions. +func (w *priceFeedWatcher) watchTicker(ctx context.Context, ticker <-chan time.Time) { + clog.V(6).Infof(ctx, "Starting PriceFeed watch loop") for { select { case <-ctx.Done(): + clog.V(6).Infof(ctx, "Stopping PriceFeed watch loop") return case <-ticker: attempt, retryDelay := 1, w.baseRetryDelay for { - err := w.updatePrice() + _, err := w.updatePrice() if err == nil { break } else if attempt >= priceUpdateMaxRetries { @@ -159,7 +210,8 @@ func parseCurrencies(description string) (currencyBase string, currencyQuote str func newTruncatedTicker(ctx context.Context, d time.Duration) <-chan time.Time { ch := make(chan time.Time, 1) go func() { - defer close(ch) + // Do not close the channel, to prevent a concurrent goroutine reading from + // the channel from seeing an erroneous "tick" after its closed. nextTick := time.Now().UTC().Truncate(d) for { diff --git a/eth/watchers/pricefeedwatcher_test.go b/eth/watchers/pricefeedwatcher_test.go index 20e09578e1..27eb5d24d0 100644 --- a/eth/watchers/pricefeedwatcher_test.go +++ b/eth/watchers/pricefeedwatcher_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "math/big" + "reflect" "testing" "time" @@ -37,18 +38,16 @@ func TestPriceFeedWatcher_UpdatePrice(t *testing.T) { } priceFeedMock.On("FetchPriceData").Return(priceData, nil).Once() - w := &PriceFeedWatcher{ - priceFeed: priceFeedMock, - currencyBase: "ETH", - currencyQuote: "USD", - } + w := &priceFeedWatcher{priceFeed: priceFeedMock} + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() priceUpdated := make(chan eth.PriceData, 1) - sub := w.Subscribe(priceUpdated) - defer sub.Unsubscribe() + w.Subscribe(ctx, priceUpdated) - require.NoError(t, w.updatePrice()) - require.Equal(t, priceData, w.current) + newPrice, err := w.updatePrice() + require.NoError(t, err) + require.Equal(t, priceData, newPrice) select { case updatedPrice := <-priceUpdated: @@ -58,20 +57,59 @@ func TestPriceFeedWatcher_UpdatePrice(t *testing.T) { } } -func TestPriceFeedWatcher_Watch(t *testing.T) { +func TestPriceFeedWatcher_Subscribe(t *testing.T) { require := require.New(t) priceFeedMock := new(mockPriceFeedEthClient) defer priceFeedMock.AssertExpectations(t) - w := &PriceFeedWatcher{ - priceFeed: priceFeedMock, - currencyBase: "ETH", - currencyQuote: "USD", + w := &priceFeedWatcher{priceFeed: priceFeedMock} + + // Start a bunch of subscriptions and make sure only 1 watch loop gets started + observedCancelWatch := []context.CancelFunc{} + cancelSub := []context.CancelFunc{} + for i := 0; i < 5; i++ { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + w.Subscribe(ctx, make(chan eth.PriceData, 1)) + + observedCancelWatch = append(observedCancelWatch, w.cancelWatch) + cancelSub = append(cancelSub, cancel) + } + + require.NotNil(w.cancelWatch) + for i := range observedCancelWatch { + require.Equal(reflect.ValueOf(w.cancelWatch).Pointer(), reflect.ValueOf(observedCancelWatch[i]).Pointer()) } + // Stop all but the last subscription and ensure watch loop stays running + for i := 0; i < 4; i++ { + cancelSub[i]() + require.NotNil(w.cancelWatch) + } + + // Now stop the last subscription and ensure watch loop gets stopped + cancelSub[4]() + time.Sleep(1 * time.Second) + require.Nil(w.cancelWatch) + + // Finally, just make sure it can be started again after having been stopped + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + w.Subscribe(ctx, make(chan eth.PriceData, 1)) + require.NotNil(w.cancelWatch) +} + +func TestPriceFeedWatcher_Watch(t *testing.T) { + require := require.New(t) + priceFeedMock := new(mockPriceFeedEthClient) + defer priceFeedMock.AssertExpectations(t) + + w := &priceFeedWatcher{priceFeed: priceFeedMock} + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() priceUpdated := make(chan eth.PriceData, 1) - sub := w.Subscribe(priceUpdated) - defer sub.Unsubscribe() + w.Subscribe(ctx, priceUpdated) priceData := eth.PriceData{ RoundID: 10, @@ -100,8 +138,6 @@ func TestPriceFeedWatcher_Watch(t *testing.T) { // Start the watch loop fakeTicker := make(chan time.Time, 10) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() go func() { w.watchTicker(ctx, fakeTicker) }() @@ -150,21 +186,18 @@ func TestPriceFeedWatcher_WatchErrorRetries(t *testing.T) { } priceFeedMock.On("FetchPriceData").Return(priceData, nil) - w := &PriceFeedWatcher{ + w := &priceFeedWatcher{ baseRetryDelay: 5 * time.Millisecond, priceFeed: priceFeedMock, - currencyBase: "ETH", - currencyQuote: "USD", } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() priceUpdated := make(chan eth.PriceData, 1) - sub := w.Subscribe(priceUpdated) - defer sub.Unsubscribe() + w.Subscribe(ctx, priceUpdated) // Start watch loop fakeTicker := make(chan time.Time, 10) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() go func() { w.watchTicker(ctx, fakeTicker) }() diff --git a/server/broadcast.go b/server/broadcast.go index 5658f0cda6..2edcd4f58d 100755 --- a/server/broadcast.go +++ b/server/broadcast.go @@ -56,7 +56,7 @@ var submitMultiSession = func(ctx context.Context, sess *BroadcastSession, seg * var maxTranscodeAttempts = errors.New("hit max transcode attempts") type BroadcastConfig struct { - maxPrice *big.Rat + maxPrice *core.AutoConvertedPrice mu sync.RWMutex } @@ -68,16 +68,19 @@ type SegFlightMetadata struct { func (cfg *BroadcastConfig) MaxPrice() *big.Rat { cfg.mu.RLock() defer cfg.mu.RUnlock() - return cfg.maxPrice + if cfg.maxPrice == nil { + return nil + } + return cfg.maxPrice.Value() } -func (cfg *BroadcastConfig) SetMaxPrice(price *big.Rat) { +func (cfg *BroadcastConfig) SetMaxPrice(price *core.AutoConvertedPrice) { cfg.mu.Lock() defer cfg.mu.Unlock() + prevPrice := cfg.maxPrice cfg.maxPrice = price - - if monitor.Enabled { - monitor.MaxTranscodingPrice(price) + if prevPrice != nil { + prevPrice.Stop() } } diff --git a/server/handlers.go b/server/handlers.go index 7461065fc1..7514de56ff 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -20,6 +20,7 @@ import ( "github.com/livepeer/go-livepeer/core" "github.com/livepeer/go-livepeer/eth" "github.com/livepeer/go-livepeer/eth/types" + "github.com/livepeer/go-livepeer/monitor" "github.com/livepeer/go-livepeer/pm" "github.com/livepeer/lpms/ffmpeg" "github.com/pkg/errors" @@ -125,6 +126,7 @@ func setBroadcastConfigHandler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { pricePerUnit := r.FormValue("maxPricePerUnit") pixelsPerUnit := r.FormValue("pixelsPerUnit") + currency := r.FormValue("currency") transcodingOptions := r.FormValue("transcodingOptions") if (pricePerUnit == "" || pixelsPerUnit == "") && transcodingOptions == "" { @@ -134,28 +136,38 @@ func setBroadcastConfigHandler() http.Handler { // set max price if pricePerUnit != "" && pixelsPerUnit != "" { - pr, err := strconv.ParseInt(pricePerUnit, 10, 64) - if err != nil { - respond400(w, errors.Wrapf(err, "Error converting string to int64").Error()) + pr, ok := new(big.Rat).SetString(pricePerUnit) + if !ok { + respond400(w, fmt.Sprintf("Error parsing pricePerUnit value: %s", pricePerUnit)) return } - px, err := strconv.ParseInt(pixelsPerUnit, 10, 64) - if err != nil { - respond400(w, errors.Wrapf(err, "Error converting string to int64").Error()) + px, ok := new(big.Rat).SetString(pixelsPerUnit) + if !ok { + respond400(w, fmt.Sprintf("Error parsing pixelsPerUnit value: %s", pixelsPerUnit)) return } - if px <= 0 { - respond400(w, fmt.Sprintf("pixels per unit must be greater than 0, provided %d", px)) + if px.Sign() <= 0 { + respond400(w, fmt.Sprintf("pixels per unit must be greater than 0, provided %v", pixelsPerUnit)) return } - - var price *big.Rat - if pr > 0 { - price = big.NewRat(pr, px) + pricePerPixel := new(big.Rat).Quo(pr, px) + + var autoPrice *core.AutoConvertedPrice + if pricePerPixel.Sign() > 0 { + var err error + autoPrice, err = core.NewAutoConvertedPrice(currency, pricePerPixel, func(price *big.Rat) { + if monitor.Enabled { + monitor.MaxTranscodingPrice(price) + } + glog.Infof("Maximum transcoding price: %v wei per pixel\n", price.FloatString(3)) + }) + if err != nil { + respond400(w, errors.Wrap(err, "error converting price").Error()) + return + } } - BroadcastCfg.SetMaxPrice(price) - glog.Infof("Maximum transcoding price: %d per %q pixels\n", pr, px) + BroadcastCfg.SetMaxPrice(autoPrice) } // set broadcast profiles @@ -291,7 +303,8 @@ func (s *LivepeerServer) activateOrchestratorHandler(client eth.LivepeerEthClien return } - if err := s.setOrchestratorPriceInfo("default", r.FormValue("pricePerUnit"), r.FormValue("pixelsPerUnit")); err != nil { + pricePerUnit, pixelsPerUnit, currency := r.FormValue("pricePerUnit"), r.FormValue("pixelsPerUnit"), r.FormValue("currency") + if err := s.setOrchestratorPriceInfo("default", pricePerUnit, pixelsPerUnit, currency); err != nil { respond400(w, err.Error()) return } @@ -385,8 +398,9 @@ func (s *LivepeerServer) setOrchestratorConfigHandler(client eth.LivepeerEthClie return mustHaveClient(client, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { pixels := r.FormValue("pixelsPerUnit") price := r.FormValue("pricePerUnit") + currency := r.FormValue("currency") if pixels != "" && price != "" { - if err := s.setOrchestratorPriceInfo("default", price, pixels); err != nil { + if err := s.setOrchestratorPriceInfo("default", price, pixels, currency); err != nil { respond400(w, err.Error()) return } @@ -458,53 +472,43 @@ func (s *LivepeerServer) setOrchestratorConfigHandler(client eth.LivepeerEthClie })) } -func (s *LivepeerServer) setOrchestratorPriceInfo(broadcasterEthAddr, pricePerUnitStr, pixelsPerUnitStr string) error { - ok, err := regexp.MatchString("^[0-9]+$", pricePerUnitStr) +func (s *LivepeerServer) setOrchestratorPriceInfo(broadcasterEthAddr, pricePerUnitStr, pixelsPerUnitStr, currency string) error { + ok, err := regexp.MatchString("^0x[0-9a-fA-F]{40}|default$", broadcasterEthAddr) if err != nil { return err } if !ok { - return fmt.Errorf("pricePerUnit is not a valid integer, provided %v", pricePerUnitStr) + return fmt.Errorf("broadcasterEthAddr is not a valid eth address, provided %v", broadcasterEthAddr) } - ok, err = regexp.MatchString("^[0-9]+$", pixelsPerUnitStr) - if err != nil { - return err - } + pricePerUnit, ok := new(big.Rat).SetString(pricePerUnitStr) if !ok { - return fmt.Errorf("pixelsPerUnit is not a valid integer, provided %v", pixelsPerUnitStr) + return fmt.Errorf("error parsing pricePerUnit value: %s", pricePerUnitStr) } - - ok, err = regexp.MatchString("^0x[0-9a-fA-F]{40}|default$", broadcasterEthAddr) - if err != nil { - return err - } - if !ok { - return fmt.Errorf("broadcasterEthAddr is not a valid eth address, provided %v", broadcasterEthAddr) + if pricePerUnit.Sign() < 0 { + return fmt.Errorf("price unit must be greater than or equal to 0, provided %s", pricePerUnitStr) } - pricePerUnit, err := strconv.ParseInt(pricePerUnitStr, 10, 64) - if err != nil { - return fmt.Errorf("error converting pricePerUnit string to int64: %v", err) + pixelsPerUnit, ok := new(big.Rat).SetString(pixelsPerUnitStr) + if !ok { + return fmt.Errorf("error parsing pixelsPerUnit value: %v", pixelsPerUnitStr) } - if pricePerUnit < 0 { - return fmt.Errorf("price unit must be greater than or equal to 0, provided %d", pricePerUnit) + if pixelsPerUnit.Sign() <= 0 { + return fmt.Errorf("pixels per unit must be greater than 0, provided %s", pixelsPerUnitStr) } - pixelsPerUnit, err := strconv.ParseInt(pixelsPerUnitStr, 10, 64) + pricePerPixel := new(big.Rat).Quo(pricePerUnit, pixelsPerUnit) + autoPrice, err := core.NewAutoConvertedPrice(currency, pricePerPixel, func(price *big.Rat) { + if broadcasterEthAddr == "default" { + glog.Infof("Price: %v wei per pixel\n ", price.FloatString(3)) + } else { + glog.Infof("Price: %v wei per pixel for broadcaster %v", price.FloatString(3), broadcasterEthAddr) + } + }) if err != nil { - return fmt.Errorf("error converting pixelsPerUnit string to int64: %v", err) - } - if pixelsPerUnit <= 0 { - return fmt.Errorf("pixels per unit must be greater than 0, provided %d", pixelsPerUnit) - } - - s.LivepeerNode.SetBasePrice(broadcasterEthAddr, big.NewRat(pricePerUnit, pixelsPerUnit)) - if broadcasterEthAddr == "default" { - glog.Infof("Price per pixel set to %d wei for %d pixels\n", pricePerUnit, pixelsPerUnit) - } else { - glog.Infof("Price per pixel set to %d wei for %d pixels for broadcaster %s\n", pricePerUnit, pixelsPerUnit, broadcasterEthAddr) + return fmt.Errorf("error converting price: %v", err) } + s.LivepeerNode.SetBasePrice(broadcasterEthAddr, autoPrice) return nil } @@ -564,9 +568,10 @@ func (s *LivepeerServer) setPriceForBroadcaster() http.Handler { if s.LivepeerNode.NodeType == core.OrchestratorNode { pricePerUnitStr := r.FormValue("pricePerUnit") pixelsPerUnitStr := r.FormValue("pixelsPerUnit") + currency := r.FormValue("currency") broadcasterEthAddr := r.FormValue("broadcasterEthAddr") - err := s.setOrchestratorPriceInfo(broadcasterEthAddr, pricePerUnitStr, pixelsPerUnitStr) + err := s.setOrchestratorPriceInfo(broadcasterEthAddr, pricePerUnitStr, pixelsPerUnitStr, currency) if err == nil { respondOk(w, []byte(fmt.Sprintf("Price per pixel set to %s wei for %s pixels for broadcaster %s\n", pricePerUnitStr, pixelsPerUnitStr, broadcasterEthAddr))) } else { diff --git a/server/handlers_test.go b/server/handlers_test.go index aa01fe88cc..f7852e3d46 100644 --- a/server/handlers_test.go +++ b/server/handlers_test.go @@ -116,7 +116,7 @@ func TestOrchestratorInfoHandler_Success(t *testing.T) { s := &LivepeerServer{LivepeerNode: n} price := big.NewRat(1, 2) - s.LivepeerNode.SetBasePrice("default", price) + s.LivepeerNode.SetBasePrice("default", core.NewFixedPrice(price)) trans := &types.Transcoder{ ServiceURI: "127.0.0.1:8935", @@ -196,7 +196,7 @@ func TestSetBroadcastConfigHandler_ConvertPricePerUnitError(t *testing.T) { }) assert.Equal(http.StatusBadRequest, status) - assert.Contains(body, "Error converting string to int64") + assert.Contains(body, "Error parsing pricePerUnit value") } func TestSetBroadcastConfigHandler_ConvertPixelsPerUnitError(t *testing.T) { @@ -209,7 +209,7 @@ func TestSetBroadcastConfigHandler_ConvertPixelsPerUnitError(t *testing.T) { }) assert.Equal(http.StatusBadRequest, status) - assert.Contains(body, "Error converting string to int64") + assert.Contains(body, "Error parsing pixelsPerUnit value") } func TestSetBroadcastConfigHandler_NegativePixelPerUnitError(t *testing.T) { @@ -259,7 +259,7 @@ func TestSetBroadcastConfigHandler_Success(t *testing.T) { func TestGetBroadcastConfigHandler(t *testing.T) { assert := assert.New(t) - BroadcastCfg.maxPrice = big.NewRat(1, 2) + BroadcastCfg.maxPrice = core.NewFixedPrice(big.NewRat(1, 2)) BroadcastJobVideoProfiles = []ffmpeg.VideoProfile{ ffmpeg.VideoProfileLookup["P240p25fps16x9"], } @@ -501,26 +501,31 @@ func TestSetOrchestratorPriceInfo(t *testing.T) { s := stubServer() // pricePerUnit is not an integer - err := s.setOrchestratorPriceInfo("default", "nil", "1") + err := s.setOrchestratorPriceInfo("default", "nil", "1", "") assert.Error(t, err) - assert.True(t, strings.Contains(err.Error(), "pricePerUnit is not a valid integer")) + assert.Contains(t, err.Error(), "error parsing pricePerUnit value") // pixelsPerUnit is not an integer - err = s.setOrchestratorPriceInfo("default", "1", "nil") + err = s.setOrchestratorPriceInfo("default", "1", "nil", "") assert.Error(t, err) - assert.True(t, strings.Contains(err.Error(), "pixelsPerUnit is not a valid integer")) + assert.Contains(t, err.Error(), "error parsing pixelsPerUnit value") - err = s.setOrchestratorPriceInfo("default", "1", "1") + // price feed watcher is not initialized and one attempts a custom currency + err = s.setOrchestratorPriceInfo("default", "1e12", "0.7", "USD") + assert.Error(t, err) + assert.Contains(t, err.Error(), "PriceFeedWatcher is not initialized") + + err = s.setOrchestratorPriceInfo("default", "1", "1", "") assert.Nil(t, err) assert.Zero(t, s.LivepeerNode.GetBasePrice("default").Cmp(big.NewRat(1, 1))) - err = s.setOrchestratorPriceInfo("default", "-5", "1") + err = s.setOrchestratorPriceInfo("default", "-5", "1", "") assert.EqualErrorf(t, err, err.Error(), "price unit must be greater than or equal to 0, provided %d\n", -5) // pixels per unit <= 0 - err = s.setOrchestratorPriceInfo("default", "1", "0") + err = s.setOrchestratorPriceInfo("default", "1", "0", "") assert.EqualErrorf(t, err, err.Error(), "pixels per unit must be greater than 0, provided %d\n", 0) - err = s.setOrchestratorPriceInfo("default", "1", "-5") + err = s.setOrchestratorPriceInfo("default", "1", "-5", "") assert.EqualErrorf(t, err, err.Error(), "pixels per unit must be greater than 0, provided %d\n", -5) } diff --git a/server/rpc_test.go b/server/rpc_test.go index 712568c20d..ab35bb0875 100644 --- a/server/rpc_test.go +++ b/server/rpc_test.go @@ -550,7 +550,7 @@ func TestGenPayment(t *testing.T) { s.Sender = sender // Test invalid price - BroadcastCfg.SetMaxPrice(big.NewRat(1, 5)) + BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(1, 5))) payment, err = genPayment(context.TODO(), s, 1) assert.Equal("", payment) assert.Errorf(err, err.Error(), "Orchestrator price higher than the set maximum price of %v wei per %v pixels", int64(1), int64(5)) @@ -687,12 +687,12 @@ func TestValidatePrice(t *testing.T) { defer BroadcastCfg.SetMaxPrice(nil) // B MaxPrice > O Price - BroadcastCfg.SetMaxPrice(big.NewRat(5, 1)) + BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(5, 1))) err = validatePrice(s) assert.Nil(err) // B MaxPrice == O Price - BroadcastCfg.SetMaxPrice(big.NewRat(1, 3)) + BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(1, 3))) err = validatePrice(s) assert.Nil(err) @@ -713,7 +713,7 @@ func TestValidatePrice(t *testing.T) { // B MaxPrice < O Price s.InitialPrice = nil - BroadcastCfg.SetMaxPrice(big.NewRat(1, 5)) + BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(1, 5))) err = validatePrice(s) assert.EqualError(err, fmt.Sprintf("Orchestrator price higher than the set maximum price of %v wei per %v pixels", int64(1), int64(5))) diff --git a/server/segment_rpc_test.go b/server/segment_rpc_test.go index 6feb1a5ba8..f8786202cd 100644 --- a/server/segment_rpc_test.go +++ b/server/segment_rpc_test.go @@ -1679,7 +1679,7 @@ func TestSubmitSegment_GenPaymentError_ValidatePriceError(t *testing.T) { OrchestratorInfo: oinfo, } - BroadcastCfg.SetMaxPrice(big.NewRat(1, 5)) + BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(1, 5))) defer BroadcastCfg.SetMaxPrice(nil) _, err := SubmitSegment(context.TODO(), s, &stream.HLSSegment{}, nil, 0, false, true) diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 59a77b5c88..efc723d602 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -122,7 +122,7 @@ func lpCfg() starter.LivepeerConfig { ethPassword := "" network := "devnet" blockPollingInterval := 1 - pricePerUnit := 1 + pricePerUnit := "1" initializeRound := true cfg := starter.DefaultLivepeerConfig() From 2572d97ec8be0d11ed6aef9d072971d4b6b96c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Fri, 29 Mar 2024 17:35:23 +0100 Subject: [PATCH 03/39] Release 0.7.3 (#2988) * release v0.7.3 * release v0.7.3 --- CHANGELOG.md | 32 +++++++++++++++++++++++++++++++- CHANGELOG_PENDING.md | 2 -- VERSION | 2 +- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bebd6eff2..3c86a0649c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,35 @@ # Changelog +## v0.7.3 + +### Breaking Changes 🚨🚨 + +### Features βš’ + +#### General + +- [#2978](https://github.com/livepeer/go-livepeer/pull/2978) Update CUDA version from 11.x to 12.x (@leszko) +- [#2973](https://github.com/livepeer/go-livepeer/pull/2973) Update ffmpeg version (@thomshutt) +- [#2981](https://github.com/livepeer/go-livepeer/pull/2981) Add support for prices in custom currencies like USD (@victorges) + +#### Broadcaster + +#### Orchestrator + +#### Transcoder + +### Bug Fixes 🐞 + +#### CLI + +#### General + +#### Broadcaster + +#### Orchestrator + +#### Transcoder + ## v0.7.2 ### Breaking Changes 🚨🚨 @@ -562,7 +592,7 @@ Additional highlights of this release: - Support for EIP-1559 (otherwise known as type 2) Ethereum transactions which results in more predictable transaction confirmation times, reduces the chance of stuck pending transactions and avoids overpaying in gas fees. If you are interested in additional details on the implications of EIP-1559 transactions refer to this [resource](https://hackmd.io/@timbeiko/1559-resources). - An improvement in ticket parameter generation for orchestrators to prevent short lived gas price spikes on the Ethereum network from disrupting streams. - The node will automatically detect if the GPU enters an unrecoverable state and crash. The reason for crashing upon detecting an unrecoverable GPU state is that no transcoding will -be possible in this scenario until the node is restarted. We recommend node operators to setup a process for monitoring if their node is still up and starting the node if it has crashed. For reference, a bash script similar to [this one](https://gist.github.com/jailuthra/03c3d65d0bbff457cae8f9a14b4c04b7) can be used to automate restarts of the node in the event of a crash. + be possible in this scenario until the node is restarted. We recommend node operators to setup a process for monitoring if their node is still up and starting the node if it has crashed. For reference, a bash script similar to [this one](https://gist.github.com/jailuthra/03c3d65d0bbff457cae8f9a14b4c04b7) can be used to automate restarts of the node in the event of a crash. Thanks to everyone that submitted bug reports and assisted in testing! diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index df9d710ef8..3ca5044811 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -8,8 +8,6 @@ #### General -- [#2981](https://github.com/livepeer/go-livepeer/pull/2981) Add support for prices in custom currencies like USD (@victorges) - #### Broadcaster #### Orchestrator diff --git a/VERSION b/VERSION index d5cc44d1d3..b09a54cb9b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.2 \ No newline at end of file +0.7.3 \ No newline at end of file From 8c243abfc2ed877aef121e9c208857c0d1ad5c18 Mon Sep 17 00:00:00 2001 From: Thom Shutt Date: Tue, 2 Apr 2024 11:11:26 +0100 Subject: [PATCH 04/39] Revert "Bump ffmpeg version and nv-codec-headers" (#2989) * Revert "Bump ffmpeg version and nv-codec-headers (#2973)" This reverts commit cad6713174fc351850ae5a2f82b0f6ab306fc133. * Revert "Update CUDA build version from 11.7.1 to 12.0.0 (#2978)" This reverts commit 6c09a9f00682d7ed404257bba9f485dc0c4041ad. * Reapply "Update CUDA build version from 11.7.1 to 12.0.0 (#2978)" This reverts commit ebbf2102b8f6420a02439554fbe4992ab1113749. * Force ffmpeg reinstall * Revert "Force ffmpeg reinstall" This reverts commit 5adb9a598b14b3d12f038201d7d8374fac5e2f8c. --------- Co-authored-by: Victor Elias --- install_ffmpeg.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/install_ffmpeg.sh b/install_ffmpeg.sh index 03b4e0b301..af66bd0b88 100755 --- a/install_ffmpeg.sh +++ b/install_ffmpeg.sh @@ -116,7 +116,7 @@ if [[ "$GOOS" != "darwin" ]]; then if [[ ! -e "$ROOT/nv-codec-headers" ]]; then git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git "$ROOT/nv-codec-headers" cd $ROOT/nv-codec-headers - git checkout n12.1.14.0 + git checkout n9.1.23.1 make -e PREFIX="$ROOT/compiled" make install -e PREFIX="$ROOT/compiled" fi @@ -203,8 +203,9 @@ else fi if [[ ! -e "$ROOT/ffmpeg/libavcodec/libavcodec.a" ]]; then - git clone https://github.com/livepeer/FFmpeg-6.1.1.git "$ROOT/ffmpeg" || echo "FFmpeg dir already exists" + git clone https://github.com/livepeer/FFmpeg.git "$ROOT/ffmpeg" || echo "FFmpeg dir already exists" cd "$ROOT/ffmpeg" + git checkout 2e18d069668c143f3c251067abd25389e411d022 ./configure ${TARGET_OS:-} $DISABLE_FFMPEG_COMPONENTS --fatal-warnings \ --enable-libx264 --enable-gpl \ --enable-protocol=rtmp,file,pipe \ From f55d6058e0c57a77b63963422db277954bd6ec04 Mon Sep 17 00:00:00 2001 From: Thom Shutt Date: Tue, 2 Apr 2024 12:01:26 +0100 Subject: [PATCH 05/39] Bump LPMS (#2992) --- go.mod | 6 +++--- go.sum | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 675f75b480..fd1a55b99f 100644 --- a/go.mod +++ b/go.mod @@ -8,12 +8,12 @@ require ( github.com/ethereum/go-ethereum v1.13.5 github.com/golang/glog v1.1.1 github.com/golang/mock v1.6.0 - github.com/golang/protobuf v1.5.3 + github.com/golang/protobuf v1.5.4 github.com/jaypipes/ghw v0.10.0 github.com/jaypipes/pcidb v1.0.0 github.com/livepeer/go-tools v0.0.0-20220805063103-76df6beb6506 github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18 - github.com/livepeer/lpms v0.0.0-20240115103113-98566e26c007 + github.com/livepeer/lpms v0.0.0-20240402101153-ced71c476bd0 github.com/livepeer/m3u8 v0.11.1 github.com/mattn/go-sqlite3 v1.14.18 github.com/olekukonko/tablewriter v0.0.5 @@ -28,7 +28,7 @@ require ( go.uber.org/goleak v1.3.0 golang.org/x/net v0.17.0 google.golang.org/grpc v1.57.1 - google.golang.org/protobuf v1.30.0 + google.golang.org/protobuf v1.33.0 pgregory.net/rapid v1.1.0 ) diff --git a/go.sum b/go.sum index 02fdd1f23e..984557a611 100644 --- a/go.sum +++ b/go.sum @@ -297,6 +297,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -446,6 +448,8 @@ github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18 h1:4oH3Nq github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18/go.mod h1:Jpf4jHK+fbWioBHRDRM1WadNT1qmY27g2YicTdO0Rtc= github.com/livepeer/lpms v0.0.0-20240115103113-98566e26c007 h1:0xr1TeIanBDdzI3sE2Zgf2yEV3s+6cPo3lJeyOHKmtM= github.com/livepeer/lpms v0.0.0-20240115103113-98566e26c007/go.mod h1:Hr/JhxxPDipOVd4ZrGYWrdJfpVF8/SEI0nNr2ctAlkM= +github.com/livepeer/lpms v0.0.0-20240402101153-ced71c476bd0 h1:Ch+HRjVJHpNo3kySGJgyDqb+l0KPWehyqZfA1wOafgY= +github.com/livepeer/lpms v0.0.0-20240402101153-ced71c476bd0/go.mod h1:z5ROP1l5OzAKSoqVRLc34MjUdueil6wHSecQYV7llIw= github.com/livepeer/m3u8 v0.11.1 h1:VkUJzfNTyjy9mqsgp5JPvouwna8wGZMvd/gAfT5FinU= github.com/livepeer/m3u8 v0.11.1/go.mod h1:IUqAtwWPAG2CblfQa4SVzTQoDcEMPyfNOaBSxqHMS04= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -1075,6 +1079,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 85bea861061b8931f60e3b30e9af1d9300ef040f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Tue, 2 Apr 2024 16:11:01 +0200 Subject: [PATCH 06/39] release v0.7.4 (#2993) --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ VERSION | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c86a0649c..ea7f99c11a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## v0.7.4 + +### Breaking Changes 🚨🚨 + +### Features βš’ + +#### General + +- [#2989](https://github.com/livepeer/go-livepeer/pull/2989) Revert "Update ffmpeg version" (@thomshutt) + +#### Broadcaster + +#### Orchestrator + +#### Transcoder + +### Bug Fixes 🐞 + +#### CLI + +#### General + +#### Broadcaster + +#### Orchestrator + +#### Transcoder + ## v0.7.3 ### Breaking Changes 🚨🚨 diff --git a/VERSION b/VERSION index b09a54cb9b..ef090a6c47 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.3 \ No newline at end of file +0.7.4 \ No newline at end of file From 07fed97ca250dfe61ba87043bae9ac5672364fed Mon Sep 17 00:00:00 2001 From: Victor Elias Date: Wed, 3 Apr 2024 08:44:49 -0300 Subject: [PATCH 07/39] server: Skip redundant maxPrice check in ongoing session (#2994) * server: Remove maxPrice check mid-session * server: Fix tests * server: Fix erroneous usage of assert.EqualErrorf When I was writing the tests for validatePrice I found out we were using that function wrong in a couple places and never checking any error. We were sending err.Error() to check the error from err. * server: Fix error checks after fixing assertion * CHANGELOG --- CHANGELOG_PENDING.md | 2 ++ server/handlers_test.go | 6 +++--- server/rpc_test.go | 28 +++++----------------------- server/segment_rpc.go | 4 ---- server/segment_rpc_test.go | 9 +++++---- 5 files changed, 15 insertions(+), 34 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 3ca5044811..cb662d0568 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -22,6 +22,8 @@ #### Broadcaster +- [#2994](https://github.com/livepeer/go-livepeer/pull/2994) server: Skip redundant maxPrice check in ongoing session (@victorges) + #### Orchestrator #### Transcoder diff --git a/server/handlers_test.go b/server/handlers_test.go index f7852e3d46..d191d0a75e 100644 --- a/server/handlers_test.go +++ b/server/handlers_test.go @@ -520,13 +520,13 @@ func TestSetOrchestratorPriceInfo(t *testing.T) { assert.Zero(t, s.LivepeerNode.GetBasePrice("default").Cmp(big.NewRat(1, 1))) err = s.setOrchestratorPriceInfo("default", "-5", "1", "") - assert.EqualErrorf(t, err, err.Error(), "price unit must be greater than or equal to 0, provided %d\n", -5) + assert.EqualError(t, err, fmt.Sprintf("price unit must be greater than or equal to 0, provided %d", -5)) // pixels per unit <= 0 err = s.setOrchestratorPriceInfo("default", "1", "0", "") - assert.EqualErrorf(t, err, err.Error(), "pixels per unit must be greater than 0, provided %d\n", 0) + assert.EqualError(t, err, fmt.Sprintf("pixels per unit must be greater than 0, provided %d", 0)) err = s.setOrchestratorPriceInfo("default", "1", "-5", "") - assert.EqualErrorf(t, err, err.Error(), "pixels per unit must be greater than 0, provided %d\n", -5) + assert.EqualError(t, err, fmt.Sprintf("pixels per unit must be greater than 0, provided %d", -5)) } func TestSetPriceForBroadcasterHandler(t *testing.T) { diff --git a/server/rpc_test.go b/server/rpc_test.go index ab35bb0875..93c776f456 100644 --- a/server/rpc_test.go +++ b/server/rpc_test.go @@ -549,13 +549,13 @@ func TestGenPayment(t *testing.T) { sender := &pm.MockSender{} s.Sender = sender - // Test invalid price - BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(1, 5))) + // Test changing O price + s.InitialPrice = &net.PriceInfo{PricePerUnit: 1, PixelsPerUnit: 5} payment, err = genPayment(context.TODO(), s, 1) assert.Equal("", payment) - assert.Errorf(err, err.Error(), "Orchestrator price higher than the set maximum price of %v wei per %v pixels", int64(1), int64(5)) + assert.Errorf(err, "Orchestrator price has changed, Orchestrator price: %v, Orchestrator initial price: %v", "1/3", "1/5") - BroadcastCfg.SetMaxPrice(nil) + s.InitialPrice = nil // Test CreateTicketBatch error sender.On("CreateTicketBatch", mock.Anything, mock.Anything).Return(nil, errors.New("CreateTicketBatch error")).Once() @@ -680,22 +680,10 @@ func TestValidatePrice(t *testing.T) { PMSessionID: "foo", } - // B's MaxPrice is nil + // O's Initial Price is nil err := validatePrice(s) assert.Nil(err) - defer BroadcastCfg.SetMaxPrice(nil) - - // B MaxPrice > O Price - BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(5, 1))) - err = validatePrice(s) - assert.Nil(err) - - // B MaxPrice == O Price - BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(1, 3))) - err = validatePrice(s) - assert.Nil(err) - // O Initial Price == O Price s.InitialPrice = oinfo.PriceInfo err = validatePrice(s) @@ -711,12 +699,6 @@ func TestValidatePrice(t *testing.T) { err = validatePrice(s) assert.ErrorContains(err, "price has changed") - // B MaxPrice < O Price - s.InitialPrice = nil - BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(1, 5))) - err = validatePrice(s) - assert.EqualError(err, fmt.Sprintf("Orchestrator price higher than the set maximum price of %v wei per %v pixels", int64(1), int64(5))) - // O.PriceInfo is nil s.OrchestratorInfo.PriceInfo = nil err = validatePrice(s) diff --git a/server/segment_rpc.go b/server/segment_rpc.go index 7f81999f7b..3472222e27 100644 --- a/server/segment_rpc.go +++ b/server/segment_rpc.go @@ -826,10 +826,6 @@ func validatePrice(sess *BroadcastSession) error { return errors.New("missing orchestrator price") } - maxPrice := BroadcastCfg.MaxPrice() - if maxPrice != nil && oPrice.Cmp(maxPrice) == 1 { - return fmt.Errorf("Orchestrator price higher than the set maximum price of %v wei per %v pixels", maxPrice.Num().Int64(), maxPrice.Denom().Int64()) - } iPrice, err := common.RatPriceInfo(sess.InitialPrice) if err == nil && iPrice != nil && oPrice.Cmp(iPrice) == 1 { return fmt.Errorf("Orchestrator price has changed, Orchestrator price: %v, Orchestrator initial price: %v", oPrice, iPrice) diff --git a/server/segment_rpc_test.go b/server/segment_rpc_test.go index f8786202cd..01c37f903c 100644 --- a/server/segment_rpc_test.go +++ b/server/segment_rpc_test.go @@ -1677,14 +1677,15 @@ func TestSubmitSegment_GenPaymentError_ValidatePriceError(t *testing.T) { Sender: sender, Balance: balance, OrchestratorInfo: oinfo, + InitialPrice: &net.PriceInfo{ + PricePerUnit: 1, + PixelsPerUnit: 5, + }, } - BroadcastCfg.SetMaxPrice(core.NewFixedPrice(big.NewRat(1, 5))) - defer BroadcastCfg.SetMaxPrice(nil) - _, err := SubmitSegment(context.TODO(), s, &stream.HLSSegment{}, nil, 0, false, true) - assert.EqualErrorf(t, err, err.Error(), "Orchestrator price higher than the set maximum price of %v wei per %v pixels", int64(1), int64(5)) + assert.EqualError(t, err, fmt.Sprintf("Orchestrator price has changed, Orchestrator price: %v, Orchestrator initial price: %v", "1/3", "1/5")) balance.AssertCalled(t, "Credit", existingCredit) } From 119f346c3835cfa5f77e23344b102462a52b78be Mon Sep 17 00:00:00 2001 From: Victor Elias Date: Wed, 3 Apr 2024 08:49:47 -0300 Subject: [PATCH 08/39] server: Allow Os price to increase up to 2x mid-session (#2995) * server: Allow dynamic (and sometimes >max) prices for Os * CHANGELOG --- CHANGELOG_PENDING.md | 2 ++ server/rpc_test.go | 15 ++++++++++----- server/segment_rpc.go | 18 +++++++++++++++--- server/segment_rpc_test.go | 4 ++-- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index cb662d0568..f5e99d64c6 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -10,6 +10,8 @@ #### Broadcaster +- [#2995](https://github.com/livepeer/go-livepeer/pull/2995) server: Allow Os price to increase up to 2x mid-session (@victorges) + #### Orchestrator #### Transcoder diff --git a/server/rpc_test.go b/server/rpc_test.go index 93c776f456..c0832a0c46 100644 --- a/server/rpc_test.go +++ b/server/rpc_test.go @@ -550,10 +550,10 @@ func TestGenPayment(t *testing.T) { s.Sender = sender // Test changing O price - s.InitialPrice = &net.PriceInfo{PricePerUnit: 1, PixelsPerUnit: 5} + s.InitialPrice = &net.PriceInfo{PricePerUnit: 1, PixelsPerUnit: 7} payment, err = genPayment(context.TODO(), s, 1) assert.Equal("", payment) - assert.Errorf(err, "Orchestrator price has changed, Orchestrator price: %v, Orchestrator initial price: %v", "1/3", "1/5") + assert.Errorf(err, "Orchestrator price has more than doubled, Orchestrator price: %v, Orchestrator initial price: %v", "1/3", "1/7") s.InitialPrice = nil @@ -694,10 +694,15 @@ func TestValidatePrice(t *testing.T) { err = validatePrice(s) assert.Nil(err) - // O Initial Price lower than O Price - s.InitialPrice = &net.PriceInfo{PricePerUnit: 1, PixelsPerUnit: 10} + // O Price higher but up to 2x Initial Price + s.InitialPrice = &net.PriceInfo{PricePerUnit: 1, PixelsPerUnit: 6} err = validatePrice(s) - assert.ErrorContains(err, "price has changed") + assert.Nil(err) + + // O Price higher than 2x Initial Price + s.InitialPrice = &net.PriceInfo{PricePerUnit: 1000, PixelsPerUnit: 6001} + err = validatePrice(s) + assert.ErrorContains(err, "price has more than doubled") // O.PriceInfo is nil s.OrchestratorInfo.PriceInfo = nil diff --git a/server/segment_rpc.go b/server/segment_rpc.go index 3472222e27..b7a948b5f0 100644 --- a/server/segment_rpc.go +++ b/server/segment_rpc.go @@ -36,6 +36,9 @@ const segmentHeader = "Livepeer-Segment" const pixelEstimateMultiplier = 1.02 +// Maximum price change allowed in orchestrator pricing before the session is swapped. +var priceIncreaseThreshold = big.NewRat(2, 1) + var errSegEncoding = errors.New("ErrorSegEncoding") var errSegSig = errors.New("ErrSegSig") var errFormat = errors.New("unrecognized profile output format") @@ -826,9 +829,18 @@ func validatePrice(sess *BroadcastSession) error { return errors.New("missing orchestrator price") } - iPrice, err := common.RatPriceInfo(sess.InitialPrice) - if err == nil && iPrice != nil && oPrice.Cmp(iPrice) == 1 { - return fmt.Errorf("Orchestrator price has changed, Orchestrator price: %v, Orchestrator initial price: %v", oPrice, iPrice) + initPrice, err := common.RatPriceInfo(sess.InitialPrice) + if err != nil { + glog.Warningf("Error parsing session initial price (%d / %d): %v", + sess.InitialPrice.PricePerUnit, sess.InitialPrice.PixelsPerUnit, err) + } + if initPrice != nil { + // Prices are dynamic if configured with a custom currency, so we need to allow some change during the session. + // TODO: Make sure prices stay the same during a session so we can make this logic more strict, disallowing any price changes. + maxIncreasedPrice := new(big.Rat).Mul(initPrice, priceIncreaseThreshold) + if oPrice.Cmp(maxIncreasedPrice) > 0 { + return fmt.Errorf("Orchestrator price has more than doubled, Orchestrator price: %v, Orchestrator initial price: %v", oPrice.RatString(), initPrice.RatString()) + } } return nil diff --git a/server/segment_rpc_test.go b/server/segment_rpc_test.go index 01c37f903c..282e3187dc 100644 --- a/server/segment_rpc_test.go +++ b/server/segment_rpc_test.go @@ -1679,13 +1679,13 @@ func TestSubmitSegment_GenPaymentError_ValidatePriceError(t *testing.T) { OrchestratorInfo: oinfo, InitialPrice: &net.PriceInfo{ PricePerUnit: 1, - PixelsPerUnit: 5, + PixelsPerUnit: 7, }, } _, err := SubmitSegment(context.TODO(), s, &stream.HLSSegment{}, nil, 0, false, true) - assert.EqualError(t, err, fmt.Sprintf("Orchestrator price has changed, Orchestrator price: %v, Orchestrator initial price: %v", "1/3", "1/5")) + assert.EqualError(t, err, fmt.Sprintf("Orchestrator price has more than doubled, Orchestrator price: %v, Orchestrator initial price: %v", "1/3", "1/7")) balance.AssertCalled(t, "Credit", existingCredit) } From eb25467f56d8288aadffe9592a299e37c43aa1e9 Mon Sep 17 00:00:00 2001 From: Victor Elias Date: Fri, 5 Apr 2024 15:57:33 -0300 Subject: [PATCH 09/39] server,discovery: Allow B to use any O in case none match maxPrice (#2999) * discovery: Ignore maxPrice on db_discovery queries Still kept the feature on the db as it had all the tests already implemented and could still be useful in the future. I can remove it if preferred though. * server: Get prices as big rats for selection While this may not seem useful now since we just convert them to floats on the probability calculation, it will be useful later when comparing prices to max price. * server: Add maxPrice filter logic on selection algorithm * CHANGELOG * server: Break filter in 2 functions --- CHANGELOG_PENDING.md | 1 + common/types.go | 9 ++- discovery/db_discovery.go | 14 +--- discovery/discovery_test.go | 26 ++++--- server/selection.go | 9 ++- server/selection_algorithm.go | 48 +++++++++--- server/selection_algorithm_test.go | 121 +++++++++++++++++++++++++++-- server/selection_test.go | 8 +- 8 files changed, 190 insertions(+), 46 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index f5e99d64c6..1015174350 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -11,6 +11,7 @@ #### Broadcaster - [#2995](https://github.com/livepeer/go-livepeer/pull/2995) server: Allow Os price to increase up to 2x mid-session (@victorges) +- [#2999](https://github.com/livepeer/go-livepeer/pull/2999) server,discovery: Allow B to use any O in case none match maxPrice (@victorges) #### Orchestrator diff --git a/common/types.go b/common/types.go index 0dc4e7445b..4535e24e36 100644 --- a/common/types.go +++ b/common/types.go @@ -3,12 +3,13 @@ package common import ( "context" "encoding/json" - ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/livepeer/go-livepeer/net" - "github.com/livepeer/m3u8" "math/big" "net/url" "sync" + + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/livepeer/go-livepeer/net" + "github.com/livepeer/m3u8" ) type RemoteTranscoderInfo struct { @@ -104,7 +105,7 @@ type OrchestratorPool interface { } type SelectionAlgorithm interface { - Select(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, prices map[ethcommon.Address]float64, perfScores map[ethcommon.Address]float64) ethcommon.Address + Select(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) ethcommon.Address } type PerfScore struct { diff --git a/discovery/db_discovery.go b/discovery/db_discovery.go index f75a9cdb01..7747be9b72 100644 --- a/discovery/db_discovery.go +++ b/discovery/db_discovery.go @@ -16,7 +16,6 @@ import ( lpTypes "github.com/livepeer/go-livepeer/eth/types" "github.com/livepeer/go-livepeer/net" "github.com/livepeer/go-livepeer/pm" - "github.com/livepeer/go-livepeer/server" "github.com/golang/glog" ) @@ -71,7 +70,6 @@ func NewDBOrchestratorPoolCache(ctx context.Context, node *core.LivepeerNode, rm func (dbo *DBOrchestratorPoolCache) getURLs() ([]*url.URL, error) { orchs, err := dbo.store.SelectOrchs( &common.DBOrchFilter{ - MaxPrice: server.BroadcastCfg.MaxPrice(), CurrentRound: dbo.rm.LastInitializedRound(), UpdatedLastDay: true, }, @@ -120,8 +118,7 @@ func (dbo *DBOrchestratorPoolCache) GetOrchestrators(ctx context.Context, numOrc return false } - // check if O's price is below B's max price - maxPrice := server.BroadcastCfg.MaxPrice() + // check if O has a valid price price, err := common.RatPriceInfo(info.PriceInfo) if err != nil { clog.V(common.DEBUG).Infof(ctx, "invalid price info orch=%v err=%q", info.GetTranscoder(), err) @@ -131,12 +128,8 @@ func (dbo *DBOrchestratorPoolCache) GetOrchestrators(ctx context.Context, numOrc clog.V(common.DEBUG).Infof(ctx, "no price info received for orch=%v", info.GetTranscoder()) return false } - if maxPrice != nil && price.Cmp(maxPrice) > 0 { - clog.V(common.DEBUG).Infof(ctx, "orchestrator's price is too high orch=%v price=%v wei/pixel maxPrice=%v wei/pixel", - info.GetTranscoder(), - price.FloatString(3), - maxPrice.FloatString(3), - ) + if price.Sign() < 0 { + clog.V(common.DEBUG).Infof(ctx, "invalid price received for orch=%v price=%v", info.GetTranscoder(), price.RatString()) return false } return true @@ -154,7 +147,6 @@ func (dbo *DBOrchestratorPoolCache) GetOrchestrators(ctx context.Context, numOrc func (dbo *DBOrchestratorPoolCache) Size() int { count, _ := dbo.store.OrchCount( &common.DBOrchFilter{ - MaxPrice: server.BroadcastCfg.MaxPrice(), CurrentRound: dbo.rm.LastInitializedRound(), UpdatedLastDay: true, }, diff --git a/discovery/discovery_test.go b/discovery/discovery_test.go index c7e2b1d3ac..33e20e5b79 100644 --- a/discovery/discovery_test.go +++ b/discovery/discovery_test.go @@ -620,7 +620,7 @@ func TestNewOrchestratorPoolWithPred_TestPredicate(t *testing.T) { assert.False(t, pool.pred(oInfo)) } -func TestCachedPool_AllOrchestratorsTooExpensive_ReturnsEmptyList(t *testing.T) { +func TestCachedPool_AllOrchestratorsTooExpensive_ReturnsAllOrchestrators(t *testing.T) { // Test setup expPriceInfo := &net.PriceInfo{ PricePerUnit: 999, @@ -698,14 +698,15 @@ func TestCachedPool_AllOrchestratorsTooExpensive_ReturnsEmptyList(t *testing.T) } // check size - assert.Equal(0, pool.Size()) + assert.Equal(50, pool.Size()) urls := pool.GetInfos() - assert.Len(urls, 0) + assert.Len(urls, 50) + infos, err := pool.GetOrchestrators(context.TODO(), len(addresses), newStubSuspender(), newStubCapabilities(), common.ScoreAtLeast(0)) assert.Nil(err, "Should not be error") - assert.Len(infos, 0) + assert.Len(infos, 50) } func TestCachedPool_GetOrchestrators_MaxBroadcastPriceNotSet(t *testing.T) { @@ -899,22 +900,27 @@ func TestCachedPool_N_OrchestratorsGoodPricing_ReturnsNOrchestrators(t *testing. assert.Contains(testOrchs[25:], toOrchTest(o.EthereumAddr, o.ServiceURI, o.PricePerPixel)) } - // check size - assert.Equal(25, pool.Size()) + // check pool returns all Os, not filtering by max price + assert.Equal(50, pool.Size()) infos := pool.GetInfos() - assert.Len(infos, 25) + assert.Len(infos, 50) for _, info := range infos { - assert.Contains(addresses[25:], info.URL.String()) + assert.Contains(addresses, info.URL.String()) } oinfos, err := pool.GetOrchestrators(context.TODO(), len(orchestrators), newStubSuspender(), newStubCapabilities(), common.ScoreAtLeast(0)) assert.Nil(err, "Should not be error") - assert.Len(oinfos, 25) + assert.Len(oinfos, 50) + + seenAddrs := make(map[string]bool) for _, info := range oinfos { - assert.Equal(info.RemoteInfo.Transcoder, "goodPriceTranscoder") + addr := info.LocalInfo.URL.String() + assert.Contains(addresses, addr) + seenAddrs[addr] = true } + assert.Len(seenAddrs, 50) } func TestCachedPool_GetOrchestrators_TicketParamsValidation(t *testing.T) { diff --git a/server/selection.go b/server/selection.go index c7187c79e1..e9b9103247 100644 --- a/server/selection.go +++ b/server/selection.go @@ -3,6 +3,8 @@ package server import ( "container/heap" "context" + "math/big" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/livepeer/go-livepeer/clog" "github.com/livepeer/go-livepeer/common" @@ -167,7 +169,7 @@ func (s *MinLSSelector) selectUnknownSession(ctx context.Context) *BroadcastSess } var addrs []ethcommon.Address - prices := map[ethcommon.Address]float64{} + prices := map[ethcommon.Address]*big.Rat{} addrCount := make(map[ethcommon.Address]int) for _, sess := range s.unknownSessions { if sess.OrchestratorInfo.GetTicketParams() == nil { @@ -180,9 +182,10 @@ func (s *MinLSSelector) selectUnknownSession(ctx context.Context) *BroadcastSess addrCount[addr]++ pi := sess.OrchestratorInfo.PriceInfo if pi != nil && pi.PixelsPerUnit != 0 { - prices[addr] = float64(pi.PricePerUnit) / float64(pi.PixelsPerUnit) + prices[addr] = big.NewRat(pi.PricePerUnit, pi.PixelsPerUnit) } } + maxPrice := BroadcastCfg.MaxPrice() stakes, err := s.stakeRdr.Stakes(addrs) if err != nil { @@ -199,7 +202,7 @@ func (s *MinLSSelector) selectUnknownSession(ctx context.Context) *BroadcastSess s.perfScore.Mu.Unlock() } - selected := s.selectionAlgorithm.Select(addrs, stakes, prices, perfScores) + selected := s.selectionAlgorithm.Select(addrs, stakes, maxPrice, prices, perfScores) for i, sess := range s.unknownSessions { if sess.OrchestratorInfo.GetTicketParams() == nil { diff --git a/server/selection_algorithm.go b/server/selection_algorithm.go index 72bc2a663b..54aebb0e65 100644 --- a/server/selection_algorithm.go +++ b/server/selection_algorithm.go @@ -1,11 +1,13 @@ package server import ( - ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/golang/glog" "math" + "math/big" "math/rand" "time" + + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/golang/glog" ) var random = rand.New(rand.NewSource(time.Now().UnixNano())) @@ -20,14 +22,19 @@ type ProbabilitySelectionAlgorithm struct { PriceExpFactor float64 } -func (sa ProbabilitySelectionAlgorithm) Select(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, prices map[ethcommon.Address]float64, perfScores map[ethcommon.Address]float64) ethcommon.Address { - filtered := sa.filter(addrs, perfScores) +func (sa ProbabilitySelectionAlgorithm) Select(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) ethcommon.Address { + filtered := sa.filter(addrs, maxPrice, prices, perfScores) probabilities := sa.calculateProbabilities(filtered, stakes, prices) return selectBy(probabilities) } -func (sa ProbabilitySelectionAlgorithm) filter(addrs []ethcommon.Address, scores map[ethcommon.Address]float64) []ethcommon.Address { - if sa.MinPerfScore <= 0 || scores == nil || len(scores) == 0 { +func (sa ProbabilitySelectionAlgorithm) filter(addrs []ethcommon.Address, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) []ethcommon.Address { + filteredByPerfScore := sa.filterByPerfScore(addrs, perfScores) + return sa.filterByMaxPrice(filteredByPerfScore, maxPrice, prices) +} + +func (sa ProbabilitySelectionAlgorithm) filterByPerfScore(addrs []ethcommon.Address, scores map[ethcommon.Address]float64) []ethcommon.Address { + if sa.MinPerfScore <= 0 || len(scores) == 0 { // Performance Score filter not defined, return all Orchestrators return addrs } @@ -40,7 +47,7 @@ func (sa ProbabilitySelectionAlgorithm) filter(addrs []ethcommon.Address, scores } if len(res) == 0 { - // If no orchestrators pass the filter, then returns all Orchestrators + // If no orchestrators pass the perf filter, return all Orchestrators. // That may mean some issues with the PerfScore service. glog.Warning("No Orchestrators passed min performance score filter, not using the filter") return addrs @@ -48,10 +55,33 @@ func (sa ProbabilitySelectionAlgorithm) filter(addrs []ethcommon.Address, scores return res } -func (sa ProbabilitySelectionAlgorithm) calculateProbabilities(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, prices map[ethcommon.Address]float64) map[ethcommon.Address]float64 { +func (sa ProbabilitySelectionAlgorithm) filterByMaxPrice(addrs []ethcommon.Address, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat) []ethcommon.Address { + if maxPrice == nil || len(prices) == 0 { + // Max price filter not defined, return all Orchestrators + return addrs + } + + var res []ethcommon.Address + for _, addr := range addrs { + price := prices[addr] + if price != nil && price.Cmp(maxPrice) <= 0 { + res = append(res, addr) + } + } + + if len(res) == 0 { + // If no orchestrators pass the filter, return all Orchestrators + // It means that no orchestrators are below the max price + glog.Warning("No Orchestrators passed max price filter, not using the filter") + return addrs + } + return res +} + +func (sa ProbabilitySelectionAlgorithm) calculateProbabilities(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, prices map[ethcommon.Address]*big.Rat) map[ethcommon.Address]float64 { pricesNorm := map[ethcommon.Address]float64{} for _, addr := range addrs { - p := prices[addr] + p, _ := prices[addr].Float64() pricesNorm[addr] = math.Exp(-1 * p / sa.PriceExpFactor) } diff --git a/server/selection_algorithm_test.go b/server/selection_algorithm_test.go index 96ef58f0a4..85e677a6ba 100644 --- a/server/selection_algorithm_test.go +++ b/server/selection_algorithm_test.go @@ -1,9 +1,11 @@ package server import ( + "math/big" + "testing" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - "testing" ) const testPriceExpFactor = 100 @@ -12,6 +14,8 @@ func TestFilter(t *testing.T) { tests := []struct { name string orchMinPerfScore float64 + maxPrice float64 + prices map[string]float64 orchPerfScores map[string]float64 orchestrators []string want []string @@ -85,21 +89,126 @@ func TestFilter(t *testing.T) { "0x0000000000000000000000000000000000000004", }, }, + { + name: "All prices below max price", + orchMinPerfScore: 0.7, + maxPrice: 2000, + prices: map[string]float64{ + "0x0000000000000000000000000000000000000001": 500, + "0x0000000000000000000000000000000000000002": 1500, + "0x0000000000000000000000000000000000000003": 1000, + }, + orchPerfScores: map[string]float64{ + "0x0000000000000000000000000000000000000001": 0.6, + "0x0000000000000000000000000000000000000002": 0.8, + "0x0000000000000000000000000000000000000003": 0.9, + }, + orchestrators: []string{ + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000003", + }, + want: []string{ + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000003", + }, + }, + { + name: "All prices above max price", + orchMinPerfScore: 0.7, + maxPrice: 100, + prices: map[string]float64{ + "0x0000000000000000000000000000000000000001": 500, + "0x0000000000000000000000000000000000000002": 1500, + "0x0000000000000000000000000000000000000003": 1000, + }, + orchPerfScores: map[string]float64{ + "0x0000000000000000000000000000000000000001": 0.6, + "0x0000000000000000000000000000000000000002": 0.8, + "0x0000000000000000000000000000000000000003": 0.9, + }, + orchestrators: []string{ + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000003", + }, + want: []string{ + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000003", + }, + }, + { + name: "Mix of prices relative to max price", + orchMinPerfScore: 0.7, + maxPrice: 750, + prices: map[string]float64{ + "0x0000000000000000000000000000000000000001": 500, + "0x0000000000000000000000000000000000000002": 1500, + "0x0000000000000000000000000000000000000003": 700, + }, + orchPerfScores: map[string]float64{ + "0x0000000000000000000000000000000000000001": 0.8, + "0x0000000000000000000000000000000000000002": 0.6, + "0x0000000000000000000000000000000000000003": 0.9, + }, + orchestrators: []string{ + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000003", + }, + want: []string{ + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000003", + }, + }, + { + name: "Exact match with max price", + orchMinPerfScore: 0.7, + maxPrice: 1000, + prices: map[string]float64{ + "0x0000000000000000000000000000000000000001": 500, + "0x0000000000000000000000000000000000000002": 1000, // exactly max + "0x0000000000000000000000000000000000000003": 1500, + }, + orchPerfScores: map[string]float64{ + "0x0000000000000000000000000000000000000001": 0.8, + "0x0000000000000000000000000000000000000002": 0.9, + "0x0000000000000000000000000000000000000003": 0.6, + }, + orchestrators: []string{ + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000003", + }, + want: []string{ + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000002", + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var addrs []ethcommon.Address + var maxPrice *big.Rat + prices := map[ethcommon.Address]*big.Rat{} perfScores := map[ethcommon.Address]float64{} for _, o := range tt.orchestrators { - perfScores[ethcommon.HexToAddress(o)] = tt.orchPerfScores[o] - addrs = append(addrs, ethcommon.HexToAddress(o)) + addr := ethcommon.HexToAddress(o) + addrs = append(addrs, addr) + perfScores[addr] = tt.orchPerfScores[o] + if price, ok := tt.prices[o]; ok { + prices[addr] = new(big.Rat).SetFloat64(price) + } + } + if tt.maxPrice > 0 { + maxPrice = new(big.Rat).SetFloat64(tt.maxPrice) } sa := &ProbabilitySelectionAlgorithm{ MinPerfScore: tt.orchMinPerfScore, } - res := sa.filter(addrs, perfScores) + res := sa.filter(addrs, maxPrice, prices, perfScores) var exp []ethcommon.Address for _, o := range tt.want { @@ -160,13 +269,13 @@ func TestCalculateProbabilities(t *testing.T) { t.Run(tt.name, func(t *testing.T) { var orchs []ethcommon.Address stakes := map[ethcommon.Address]int64{} - prices := map[ethcommon.Address]float64{} + prices := map[ethcommon.Address]*big.Rat{} expProbs := map[ethcommon.Address]float64{} for i, addrStr := range tt.addrs { addr := ethcommon.HexToAddress(addrStr) orchs = append(orchs, addr) stakes[addr] = tt.stakes[i] - prices[addr] = tt.prices[i] + prices[addr] = new(big.Rat).SetFloat64(tt.prices[i]) expProbs[addr] = tt.want[i] } diff --git a/server/selection_test.go b/server/selection_test.go index 716c780d06..b7d6958ab3 100644 --- a/server/selection_test.go +++ b/server/selection_test.go @@ -4,10 +4,12 @@ import ( "container/heap" "context" "errors" + "math/big" + "testing" + "github.com/livepeer/go-livepeer/core" "github.com/livepeer/go-livepeer/net" "github.com/stretchr/testify/require" - "testing" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/livepeer/go-livepeer/common" @@ -89,7 +91,7 @@ func (r *stubStakeReader) SetStakes(stakes map[ethcommon.Address]int64) { type stubSelectionAlgorithm struct{} -func (sa stubSelectionAlgorithm) Select(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, prices map[ethcommon.Address]float64, perfScores map[ethcommon.Address]float64) ethcommon.Address { +func (sa stubSelectionAlgorithm) Select(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) ethcommon.Address { if len(addrs) == 0 { return ethcommon.Address{} } @@ -98,7 +100,7 @@ func (sa stubSelectionAlgorithm) Select(addrs []ethcommon.Address, stakes map[et // select lowest price lowest := prices[addr] for _, a := range addrs { - if prices[a] < lowest { + if prices[a].Cmp(lowest) < 0 { addr = a lowest = prices[a] } From 52186d7c1d7dd8508b9eec9e840f88f3762257b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Wed, 10 Apr 2024 14:46:07 +0200 Subject: [PATCH 10/39] Fix transcoding price metrics (#3001) --- monitor/census.go | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/monitor/census.go b/monitor/census.go index 3381a92d7f..8c80459bc7 100644 --- a/monitor/census.go +++ b/monitor/census.go @@ -1551,14 +1551,12 @@ func Reserve(sender string, reserve *big.Int) { } func MaxTranscodingPrice(maxPrice *big.Rat) { - floatWei, ok := maxPrice.Float64() - if ok { - if err := stats.RecordWithTags(census.ctx, - []tag.Mutator{tag.Insert(census.kSender, "max")}, - census.mTranscodingPrice.M(floatWei)); err != nil { + floatWei, _ := maxPrice.Float64() + if err := stats.RecordWithTags(census.ctx, + []tag.Mutator{tag.Insert(census.kSender, "max")}, + census.mTranscodingPrice.M(floatWei)); err != nil { - glog.Errorf("Error recording metrics err=%q", err) - } + glog.Errorf("Error recording metrics err=%q", err) } } @@ -1672,15 +1670,13 @@ func MaxGasPrice(maxGasPrice *big.Int) { // TranscodingPrice records the last transcoding price func TranscodingPrice(sender string, price *big.Rat) { - floatWei, ok := price.Float64() - if ok { - stats.Record(census.ctx, census.mTranscodingPrice.M(floatWei)) - if err := stats.RecordWithTags(census.ctx, - []tag.Mutator{tag.Insert(census.kSender, sender)}, - census.mTranscodingPrice.M(floatWei)); err != nil { + floatWei, _ := price.Float64() + stats.Record(census.ctx, census.mTranscodingPrice.M(floatWei)) + if err := stats.RecordWithTags(census.ctx, + []tag.Mutator{tag.Insert(census.kSender, sender)}, + census.mTranscodingPrice.M(floatWei)); err != nil { - glog.Errorf("Error recording metrics err=%q", err) - } + glog.Errorf("Error recording metrics err=%q", err) } } From 44c95d093d7cd61fcbd53628d7c44d83b156a593 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sat, 13 Apr 2024 10:47:55 +0200 Subject: [PATCH 11/39] ci(ai): add AI issue templates This commit introduces two new AI-specific issue templates, aiming to streamline the routing of AI subnet-related issues and feature requests to the appropriate team. --- .github/ISSUE_TEMPLATE/ai_bug_report.yml | 76 +++++++++++++++++++ .github/ISSUE_TEMPLATE/ai_feature_request.yml | 45 +++++++++++ .github/ISSUE_TEMPLATE/config.yml | 8 ++ 3 files changed, 129 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/ai_bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/ai_feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/ai_bug_report.yml b/.github/ISSUE_TEMPLATE/ai_bug_report.yml new file mode 100644 index 0000000000..b992554a2e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ai_bug_report.yml @@ -0,0 +1,76 @@ +name: AI Bug report +description: Create a report to help us improve. +labels: + - "bug" + - "ai" +body: + - type: markdown + attributes: + value: | + ## Bug report + Please fill out the following information to help us understand your issue. + + > [!IMPORTANT] + > This repository is only related to the core bugs with the AI branch of the go-livepeer software (i.e. `ai-video`). It does not cover bugs related to running AI pipelines and AI models used on the AI subnet. For these issues, please refer to the [AI-worker repository](https://github.com/livepeer/ai-worker/issues/new/choose) + - type: textarea + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. + validations: + required: true + - type: textarea + attributes: + label: Reproduction steps + description: "How do you trigger this bug? Please walk us through it step by step." + value: | + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error + - type: textarea + attributes: + label: Expected behaviour + description: A clear and concise description of what you expected to happen. + - type: dropdown + id: severity + attributes: + label: Severity + description: "How severe is this bug?" + options: + - Minor + - Major + - Critical + - type: textarea + attributes: + label: Screenshots / Live demo link + description: If applicable, add screenshots to help explain your problem. + placeholder: Paste the image link as markdown image + - type: dropdown + id: os + attributes: + label: OS + description: "What operating system are you using?" + options: + - Windows + - Mac + - Linux + - type: dropdown + id: running_on + attributes: + label: Running on + description: "Where are you running the application?" + options: + - Local + - Docker + - type: input + attributes: + label: AI go-livepeer version + description: "What version of the AI-worker are you using?" + - type: input + attributes: + label: AI go-livepeer commit hash + description: "Could you please provide the commit hash of the `ai-video` branch that you are currently using?" + - type: textarea + attributes: + label: Additional context + description: Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/ai_feature_request.yml b/.github/ISSUE_TEMPLATE/ai_feature_request.yml new file mode 100644 index 0000000000..22ddfa71f4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ai_feature_request.yml @@ -0,0 +1,45 @@ +name: AI Feature request +description: Suggest an idea for this project. +labels: + - "enhancement" + - "ai" +body: + - type: markdown + attributes: + value: | + ## Feature Request + Please fill out the following information to help us understand your request. + + > [!IMPORTANT] + > This repository is only related to feature requests related to the the AI branch of the go-livepeer software (i.e. `ai-video`). It does not cover feature requests related to the addition of new AI pipelines and AI models used on the AI subnet. For these issues, please refer to the [AI-worker repository](https://github.com/livepeer/ai-worker/issues/new/choose). + - type: textarea + attributes: + label: Is your feature request related to a problem? Please describe. + description: + A clear and concise description of what the problem is. Ex. I'm always + frustrated when [...] + validations: + required: true + - type: textarea + attributes: + label: Describe the solution you'd like + description: A clear and concise description of what you want to happen. + - type: textarea + attributes: + label: Describe alternatives you've considered + description: + A clear and concise description of any alternative solutions or features + you've considered. + - type: textarea + attributes: + label: Use Case + description: "Please describe why you want this feature to be added. This will help us prioritize your request." + - type: textarea + attributes: + label: Expected Outcome + description: "What do you expect to happen once this feature is implemented?" + - type: textarea + attributes: + label: Additional context + description: + Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..4ee3f97db0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: Go-livepeer Question + url: https://github.com/livepeer/go-livepeer/discussions + about: Please ask and answer questions related to the go-livepeer software here. + - name: Livepeer Question + url: https://discord.gg/livepeer + about: "Have a general Livepeer question? Join us in the Livepeer Discord server. We're here to help!" From c822b132d790e89fc6601a3052990cea3faeb85b Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sat, 13 Apr 2024 11:13:08 +0200 Subject: [PATCH 12/39] ci(ai): add AI pull request labeler This commit adds a pull request labeler action that automatically attaches the `ai` label when a pull request is created to the `ai-video` branch. --- .github/workflows/issue-labeler.yml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/issue-labeler.yml b/.github/workflows/issue-labeler.yml index b647014f3c..92a7186661 100644 --- a/.github/workflows/issue-labeler.yml +++ b/.github/workflows/issue-labeler.yml @@ -1,11 +1,13 @@ -name: Label issues +name: Label issues and pull requests on: issues: - types: - - reopened - - opened + types: [opened, reopened] + pull_request: + types: [opened, reopened] + jobs: label_issues: + if: ${{ github.event_name == 'issues' }} runs-on: ubuntu-latest permissions: issues: write @@ -16,3 +18,12 @@ jobs: add-labels: "status: triage" repo-token: ${{ secrets.GITHUB_TOKEN }} ignore-if-assigned: false + + label_pull_requests: + if: ${{ github.event_name == 'pull_request' }} + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/labeler@v5 From 8d378fd3b36d53a6a1acdc4ba694ef42d360bcc7 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Mon, 15 Apr 2024 14:28:45 +0200 Subject: [PATCH 13/39] ci: change issue template order and add PR labeler config (#3006) * ci: change issue template order This commit ensures that the main branch issue templates are put above the AI related issue templates. * ci(ai): add PR labeler config file This commmit adds a https://github.com/actions/labeler configuration file so that all PRs on the `ai-video` branch will be correctly labeled with the `ai` label. --- .github/ISSUE_TEMPLATE/{bug_report.md => 01-bug_report.md} | 0 .../{feature_request.md => 02-feature_request.md} | 0 .github/ISSUE_TEMPLATE/{spec.md => 03-spec.md} | 0 .../{ai_bug_report.yml => bug_report_ai_video.yml} | 0 .../{ai_feature_request.yml => feature_request_ai.yml} | 0 .github/labeler.yml | 2 ++ 6 files changed, 2 insertions(+) rename .github/ISSUE_TEMPLATE/{bug_report.md => 01-bug_report.md} (100%) rename .github/ISSUE_TEMPLATE/{feature_request.md => 02-feature_request.md} (100%) rename .github/ISSUE_TEMPLATE/{spec.md => 03-spec.md} (100%) rename .github/ISSUE_TEMPLATE/{ai_bug_report.yml => bug_report_ai_video.yml} (100%) rename .github/ISSUE_TEMPLATE/{ai_feature_request.yml => feature_request_ai.yml} (100%) create mode 100644 .github/labeler.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/01-bug_report.md similarity index 100% rename from .github/ISSUE_TEMPLATE/bug_report.md rename to .github/ISSUE_TEMPLATE/01-bug_report.md diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/02-feature_request.md similarity index 100% rename from .github/ISSUE_TEMPLATE/feature_request.md rename to .github/ISSUE_TEMPLATE/02-feature_request.md diff --git a/.github/ISSUE_TEMPLATE/spec.md b/.github/ISSUE_TEMPLATE/03-spec.md similarity index 100% rename from .github/ISSUE_TEMPLATE/spec.md rename to .github/ISSUE_TEMPLATE/03-spec.md diff --git a/.github/ISSUE_TEMPLATE/ai_bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report_ai_video.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/ai_bug_report.yml rename to .github/ISSUE_TEMPLATE/bug_report_ai_video.yml diff --git a/.github/ISSUE_TEMPLATE/ai_feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request_ai.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/ai_feature_request.yml rename to .github/ISSUE_TEMPLATE/feature_request_ai.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000..4e219d6f45 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,2 @@ +ai: + - base-branch: "ai-video" From bc726a81358e625399f13a68039b2c7e02efb495 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 16 Apr 2024 08:01:45 +0200 Subject: [PATCH 14/39] ci(ai): fix incorrect labels (#3012) * ci(ai): fix incorrect labels This commit fixed the labels that were specified in the Issue Templates to the one found in the repository. * ci: rename labeler and remove trailing whitespace --- .github/ISSUE_TEMPLATE/bug_report_ai_video.yml | 4 ++-- .github/ISSUE_TEMPLATE/feature_request_ai.yml | 4 ++-- .github/labeler.yml | 2 +- .github/workflows/{issue-labeler.yml => labeler.yml} | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) rename .github/workflows/{issue-labeler.yml => labeler.yml} (95%) diff --git a/.github/ISSUE_TEMPLATE/bug_report_ai_video.yml b/.github/ISSUE_TEMPLATE/bug_report_ai_video.yml index b992554a2e..b8a7c25dd0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_ai_video.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_ai_video.yml @@ -1,8 +1,8 @@ name: AI Bug report description: Create a report to help us improve. labels: - - "bug" - - "ai" + - "type: bug" + - "AI" body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_request_ai.yml b/.github/ISSUE_TEMPLATE/feature_request_ai.yml index 22ddfa71f4..0c708f1100 100644 --- a/.github/ISSUE_TEMPLATE/feature_request_ai.yml +++ b/.github/ISSUE_TEMPLATE/feature_request_ai.yml @@ -1,8 +1,8 @@ name: AI Feature request description: Suggest an idea for this project. labels: - - "enhancement" - - "ai" + - "type: feature" + - "AI" body: - type: markdown attributes: diff --git a/.github/labeler.yml b/.github/labeler.yml index 4e219d6f45..2e2c7b2861 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,2 +1,2 @@ -ai: +AI: - base-branch: "ai-video" diff --git a/.github/workflows/issue-labeler.yml b/.github/workflows/labeler.yml similarity index 95% rename from .github/workflows/issue-labeler.yml rename to .github/workflows/labeler.yml index 92a7186661..0c45d7086b 100644 --- a/.github/workflows/issue-labeler.yml +++ b/.github/workflows/labeler.yml @@ -18,7 +18,7 @@ jobs: add-labels: "status: triage" repo-token: ${{ secrets.GITHUB_TOKEN }} ignore-if-assigned: false - + label_pull_requests: if: ${{ github.event_name == 'pull_request' }} runs-on: ubuntu-latest @@ -26,4 +26,4 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/labeler@v5 + - uses: actions/labeler@v5 From 930533388e62d21b339cccd8d6f4348dc14c5e75 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Fri, 19 Apr 2024 08:59:20 +0200 Subject: [PATCH 15/39] ci(ai): fix pull request config warning (#3018) (#3019) * ci(ai): fix pull request config warning (#3018) This commit gets rid of the Pull request labeler configuration file warning. * ci(ai): auto assign AI issues This commit auto assigns the AI issues to the right member of the AI team. * ci(ai): cleanup labeler actions This commit cleans up the labeler actions and ensure they run on the right triggers. --- .github/ISSUE_TEMPLATE/bug_report_ai_video.yml | 2 ++ .github/ISSUE_TEMPLATE/feature_request_ai.yml | 2 ++ .../workflows/{labeler.yml => issue-labeler.yml} | 13 +------------ .github/workflows/pr-labeler.yml | 14 ++++++++++++++ 4 files changed, 19 insertions(+), 12 deletions(-) rename .github/workflows/{labeler.yml => issue-labeler.yml} (57%) create mode 100644 .github/workflows/pr-labeler.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report_ai_video.yml b/.github/ISSUE_TEMPLATE/bug_report_ai_video.yml index b8a7c25dd0..bd8565982e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_ai_video.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_ai_video.yml @@ -3,6 +3,8 @@ description: Create a report to help us improve. labels: - "type: bug" - "AI" +assignees: + - rickstaa body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_request_ai.yml b/.github/ISSUE_TEMPLATE/feature_request_ai.yml index 0c708f1100..648117fa78 100644 --- a/.github/ISSUE_TEMPLATE/feature_request_ai.yml +++ b/.github/ISSUE_TEMPLATE/feature_request_ai.yml @@ -3,6 +3,8 @@ description: Suggest an idea for this project. labels: - "type: feature" - "AI" +assignees: + - rickstaa body: - type: markdown attributes: diff --git a/.github/workflows/labeler.yml b/.github/workflows/issue-labeler.yml similarity index 57% rename from .github/workflows/labeler.yml rename to .github/workflows/issue-labeler.yml index 0c45d7086b..390535f95c 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/issue-labeler.yml @@ -1,9 +1,7 @@ -name: Label issues and pull requests +name: Label issues on: issues: types: [opened, reopened] - pull_request: - types: [opened, reopened] jobs: label_issues: @@ -18,12 +16,3 @@ jobs: add-labels: "status: triage" repo-token: ${{ secrets.GITHUB_TOKEN }} ignore-if-assigned: false - - label_pull_requests: - if: ${{ github.event_name == 'pull_request' }} - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - steps: - - uses: actions/labeler@v5 diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml new file mode 100644 index 0000000000..26bade1dfc --- /dev/null +++ b/.github/workflows/pr-labeler.yml @@ -0,0 +1,14 @@ +name: Label PRs +on: + pull_request_target: + types: [opened, reopened] + +jobs: + label_pull_requests: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: actions/labeler@v5 From e9cbadbee54abe1e29393065a9c048b11ba9a215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Wed, 24 Apr 2024 14:49:05 +0200 Subject: [PATCH 16/39] Initialize round by any B/O who has the initializeRound flag set to true (#3029) --- cmd/livepeer/livepeer.go | 1 + cmd/livepeer/starter/starter.go | 205 ++++++++++++++++---------------- eth/roundinitializer.go | 95 ++++----------- eth/roundinitializer_test.go | 112 +---------------- 4 files changed, 131 insertions(+), 282 deletions(-) diff --git a/cmd/livepeer/livepeer.go b/cmd/livepeer/livepeer.go index d875a079f8..030d897957 100755 --- a/cmd/livepeer/livepeer.go +++ b/cmd/livepeer/livepeer.go @@ -162,6 +162,7 @@ func parseLivepeerConfig() starter.LivepeerConfig { cfg.MaxGasPrice = flag.Int("maxGasPrice", *cfg.MaxGasPrice, "Maximum gas price (priority fee + base fee) for ETH transactions in wei, 40 Gwei = 40000000000") cfg.EthController = flag.String("ethController", *cfg.EthController, "Protocol smart contract address") cfg.InitializeRound = flag.Bool("initializeRound", *cfg.InitializeRound, "Set to true if running as a transcoder and the node should automatically initialize new rounds") + cfg.InitializeRoundMaxDelay = flag.Duration("initializeRoundMaxDelay", *cfg.InitializeRoundMaxDelay, "Maximum delay to wait before initializing a round") cfg.TicketEV = flag.String("ticketEV", *cfg.TicketEV, "The expected value for PM tickets") cfg.MaxFaceValue = flag.String("maxFaceValue", *cfg.MaxFaceValue, "set max ticket face value in WEI") // Broadcaster max acceptable ticket EV diff --git a/cmd/livepeer/starter/starter.go b/cmd/livepeer/starter/starter.go index 2896d95431..f9296abfa6 100755 --- a/cmd/livepeer/starter/starter.go +++ b/cmd/livepeer/starter/starter.go @@ -74,76 +74,77 @@ const ( ) type LivepeerConfig struct { - Network *string - RtmpAddr *string - CliAddr *string - HttpAddr *string - ServiceAddr *string - OrchAddr *string - VerifierURL *string - EthController *string - VerifierPath *string - LocalVerify *bool - HttpIngest *bool - Orchestrator *bool - Transcoder *bool - Broadcaster *bool - OrchSecret *string - TranscodingOptions *string - MaxAttempts *int - SelectRandWeight *float64 - SelectStakeWeight *float64 - SelectPriceWeight *float64 - SelectPriceExpFactor *float64 - OrchPerfStatsURL *string - Region *string - MaxPricePerUnit *string - MinPerfScore *float64 - MaxSessions *string - CurrentManifest *bool - Nvidia *string - Netint *string - TestTranscoder *bool - EthAcctAddr *string - EthPassword *string - EthKeystorePath *string - EthOrchAddr *string - EthUrl *string - TxTimeout *time.Duration - MaxTxReplacements *int - GasLimit *int - MinGasPrice *int64 - MaxGasPrice *int - InitializeRound *bool - TicketEV *string - MaxFaceValue *string - MaxTicketEV *string - MaxTotalEV *string - DepositMultiplier *int - PricePerUnit *string - PixelsPerUnit *string - PriceFeedAddr *string - AutoAdjustPrice *bool - PricePerBroadcaster *string - BlockPollingInterval *int - Redeemer *bool - RedeemerAddr *string - Reward *bool - Monitor *bool - MetricsPerStream *bool - MetricsExposeClientIP *bool - MetadataQueueUri *string - MetadataAmqpExchange *string - MetadataPublishTimeout *time.Duration - Datadir *string - Objectstore *string - Recordstore *string - FVfailGsBucket *string - FVfailGsKey *string - AuthWebhookURL *string - OrchWebhookURL *string - OrchBlacklist *string - TestOrchAvail *bool + Network *string + RtmpAddr *string + CliAddr *string + HttpAddr *string + ServiceAddr *string + OrchAddr *string + VerifierURL *string + EthController *string + VerifierPath *string + LocalVerify *bool + HttpIngest *bool + Orchestrator *bool + Transcoder *bool + Broadcaster *bool + OrchSecret *string + TranscodingOptions *string + MaxAttempts *int + SelectRandWeight *float64 + SelectStakeWeight *float64 + SelectPriceWeight *float64 + SelectPriceExpFactor *float64 + OrchPerfStatsURL *string + Region *string + MaxPricePerUnit *string + MinPerfScore *float64 + MaxSessions *string + CurrentManifest *bool + Nvidia *string + Netint *string + TestTranscoder *bool + EthAcctAddr *string + EthPassword *string + EthKeystorePath *string + EthOrchAddr *string + EthUrl *string + TxTimeout *time.Duration + MaxTxReplacements *int + GasLimit *int + MinGasPrice *int64 + MaxGasPrice *int + InitializeRound *bool + InitializeRoundMaxDelay *time.Duration + TicketEV *string + MaxFaceValue *string + MaxTicketEV *string + MaxTotalEV *string + DepositMultiplier *int + PricePerUnit *string + PixelsPerUnit *string + PriceFeedAddr *string + AutoAdjustPrice *bool + PricePerBroadcaster *string + BlockPollingInterval *int + Redeemer *bool + RedeemerAddr *string + Reward *bool + Monitor *bool + MetricsPerStream *bool + MetricsExposeClientIP *bool + MetadataQueueUri *string + MetadataAmqpExchange *string + MetadataPublishTimeout *time.Duration + Datadir *string + Objectstore *string + Recordstore *string + FVfailGsBucket *string + FVfailGsKey *string + AuthWebhookURL *string + OrchWebhookURL *string + OrchBlacklist *string + TestOrchAvail *bool } // DefaultLivepeerConfig creates LivepeerConfig exactly the same as when no flags are passed to the livepeer process. @@ -190,6 +191,7 @@ func DefaultLivepeerConfig() LivepeerConfig { defaultMaxGasPrice := 0 defaultEthController := "" defaultInitializeRound := false + defaultInitializeRoundMaxDelay := 30 * time.Second defaultTicketEV := "8000000000" defaultMaxFaceValue := "0" defaultMaxTicketEV := "3000000000000" @@ -264,36 +266,37 @@ func DefaultLivepeerConfig() LivepeerConfig { TestTranscoder: &defaultTestTranscoder, // Onchain: - EthAcctAddr: &defaultEthAcctAddr, - EthPassword: &defaultEthPassword, - EthKeystorePath: &defaultEthKeystorePath, - EthOrchAddr: &defaultEthOrchAddr, - EthUrl: &defaultEthUrl, - TxTimeout: &defaultTxTimeout, - MaxTxReplacements: &defaultMaxTxReplacements, - GasLimit: &defaultGasLimit, - MaxGasPrice: &defaultMaxGasPrice, - EthController: &defaultEthController, - InitializeRound: &defaultInitializeRound, - TicketEV: &defaultTicketEV, - MaxFaceValue: &defaultMaxFaceValue, - MaxTicketEV: &defaultMaxTicketEV, - MaxTotalEV: &defaultMaxTotalEV, - DepositMultiplier: &defaultDepositMultiplier, - MaxPricePerUnit: &defaultMaxPricePerUnit, - PixelsPerUnit: &defaultPixelsPerUnit, - PriceFeedAddr: &defaultPriceFeedAddr, - AutoAdjustPrice: &defaultAutoAdjustPrice, - PricePerBroadcaster: &defaultPricePerBroadcaster, - BlockPollingInterval: &defaultBlockPollingInterval, - Redeemer: &defaultRedeemer, - RedeemerAddr: &defaultRedeemerAddr, - Monitor: &defaultMonitor, - MetricsPerStream: &defaultMetricsPerStream, - MetricsExposeClientIP: &defaultMetricsExposeClientIP, - MetadataQueueUri: &defaultMetadataQueueUri, - MetadataAmqpExchange: &defaultMetadataAmqpExchange, - MetadataPublishTimeout: &defaultMetadataPublishTimeout, + EthAcctAddr: &defaultEthAcctAddr, + EthPassword: &defaultEthPassword, + EthKeystorePath: &defaultEthKeystorePath, + EthOrchAddr: &defaultEthOrchAddr, + EthUrl: &defaultEthUrl, + TxTimeout: &defaultTxTimeout, + MaxTxReplacements: &defaultMaxTxReplacements, + GasLimit: &defaultGasLimit, + MaxGasPrice: &defaultMaxGasPrice, + EthController: &defaultEthController, + InitializeRound: &defaultInitializeRound, + InitializeRoundMaxDelay: &defaultInitializeRoundMaxDelay, + TicketEV: &defaultTicketEV, + MaxFaceValue: &defaultMaxFaceValue, + MaxTicketEV: &defaultMaxTicketEV, + MaxTotalEV: &defaultMaxTotalEV, + DepositMultiplier: &defaultDepositMultiplier, + MaxPricePerUnit: &defaultMaxPricePerUnit, + PixelsPerUnit: &defaultPixelsPerUnit, + PriceFeedAddr: &defaultPriceFeedAddr, + AutoAdjustPrice: &defaultAutoAdjustPrice, + PricePerBroadcaster: &defaultPricePerBroadcaster, + BlockPollingInterval: &defaultBlockPollingInterval, + Redeemer: &defaultRedeemer, + RedeemerAddr: &defaultRedeemerAddr, + Monitor: &defaultMonitor, + MetricsPerStream: &defaultMetricsPerStream, + MetricsExposeClientIP: &defaultMetricsExposeClientIP, + MetadataQueueUri: &defaultMetadataQueueUri, + MetadataAmqpExchange: &defaultMetadataAmqpExchange, + MetadataPublishTimeout: &defaultMetadataPublishTimeout, // Ingest: HttpIngest: &defaultHttpIngest, @@ -975,7 +978,7 @@ func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { if *cfg.InitializeRound { // Start round initializer // The node will only initialize rounds if it in the upcoming active set for the round - initializer := eth.NewRoundInitializer(n.Eth, timeWatcher) + initializer := eth.NewRoundInitializer(n.Eth, timeWatcher, *cfg.InitializeRoundMaxDelay) go func() { if err := initializer.Start(); err != nil { serviceErr <- err diff --git a/eth/roundinitializer.go b/eth/roundinitializer.go index d3f2cbeeee..a7aaff6667 100644 --- a/eth/roundinitializer.go +++ b/eth/roundinitializer.go @@ -2,10 +2,11 @@ package eth import ( "math/big" + "math/rand" "sync" + "time" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" "github.com/golang/glog" ) @@ -29,20 +30,22 @@ type timeWatcher interface { // This selection process is purely a client side implementation that attempts to minimize on-chain transaction collisions, but // collisions are still possible if initialization transactions are submitted by parties that are not using this selection process type RoundInitializer struct { - client LivepeerEthClient - tw timeWatcher - quit chan struct{} + maxDelay time.Duration + client LivepeerEthClient + tw timeWatcher + quit chan struct{} nextRoundStartL1Block *big.Int mu sync.Mutex } // NewRoundInitializer creates a RoundInitializer instance -func NewRoundInitializer(client LivepeerEthClient, tw timeWatcher) *RoundInitializer { +func NewRoundInitializer(client LivepeerEthClient, tw timeWatcher, maxDelay time.Duration) *RoundInitializer { return &RoundInitializer{ - client: client, - tw: tw, - quit: make(chan struct{}), + maxDelay: maxDelay, + client: client, + tw: tw, + quit: make(chan struct{}), } } @@ -104,23 +107,23 @@ func (r *RoundInitializer) tryInitialize() error { r.mu.Lock() defer r.mu.Unlock() - currentL1Blk := r.tw.LastSeenL1Block() - lastInitializedL1BlkHash := r.tw.LastInitializedL1BlockHash() - - epochSeed := r.currentEpochSeed(currentL1Blk, r.nextRoundStartL1Block, lastInitializedL1BlkHash) - - ok, err := r.shouldInitialize(epochSeed) - if err != nil { - return err + if r.tw.LastSeenL1Block().Cmp(r.nextRoundStartL1Block) < 0 { + // Round already initialized + return nil } - // Noop if the caller should not initialize the round - if !ok { - return nil + if r.maxDelay > 0 { + randDelay := time.Duration(rand.Int63n(int64(r.maxDelay))) + glog.Infof("Waiting %v before attempting to initialize round", randDelay) + time.Sleep(randDelay) + + if r.tw.LastSeenL1Block().Cmp(r.nextRoundStartL1Block) < 0 { + glog.Infof("Round is already initialized, not initializing") + return nil + } } currentRound := new(big.Int).Add(r.tw.LastInitializedRound(), big.NewInt(1)) - glog.Infof("New round - preparing to initialize round to join active set, current round is %d", currentRound) tx, err := r.client.InitializeRound() @@ -136,55 +139,3 @@ func (r *RoundInitializer) tryInitialize() error { return nil } - -func (r *RoundInitializer) shouldInitialize(epochSeed *big.Int) (bool, error) { - transcoders, err := r.client.TranscoderPool() - if err != nil { - return false, err - } - - numActive := big.NewInt(int64(len(transcoders))) - - // Should not initialize if the upcoming active set is empty - if numActive.Cmp(big.NewInt(0)) == 0 { - return false, nil - } - - // Find the caller's rank in the upcoming active set - rank := int64(-1) - maxRank := numActive.Int64() - caller := r.client.Account().Address - for i := int64(0); i < maxRank; i++ { - if transcoders[i].Address == caller { - rank = i - break - } - } - - // Should not initialize if the caller is not in the upcoming active set - if rank == -1 { - return false, nil - } - - // Use the seed to select a position within the active set - selection := new(big.Int).Mod(epochSeed, numActive) - // Should not initialize if the selection does not match the caller's rank in the active set - if selection.Int64() != int64(rank) { - return false, nil - } - - // If the selection matches the caller's rank the caller should initialize the round - return true, nil -} - -// Returns the seed used to select a round initializer in the current epoch for the current round -// This seed is not meant to be unpredictable. The only requirement for the seed is that it is calculated the same way for each -// party running the round initializer -func (r *RoundInitializer) currentEpochSeed(currentL1Block, roundStartL1Block *big.Int, lastInitializedL1BlkHash [32]byte) *big.Int { - epochNum := new(big.Int).Sub(currentL1Block, roundStartL1Block) - epochNum.Div(epochNum, epochL1Blocks) - - // The seed for the current epoch is calculated as: - // keccak256(lastInitializedL1BlkHash | epochNum) - return crypto.Keccak256Hash(append(lastInitializedL1BlkHash[:], epochNum.Bytes()...)).Big() -} diff --git a/eth/roundinitializer_test.go b/eth/roundinitializer_test.go index 25e60205a0..a96cb3b2f2 100644 --- a/eth/roundinitializer_test.go +++ b/eth/roundinitializer_test.go @@ -16,84 +16,6 @@ import ( "github.com/stretchr/testify/mock" ) -func TestRoundInitializer_CurrentEpochSeed(t *testing.T) { - initializer := NewRoundInitializer(nil, nil) - - assert := assert.New(t) - - // Test epochNum = 0 - blkHash := [32]byte{123} - - epochSeed := initializer.currentEpochSeed(big.NewInt(5), big.NewInt(5), blkHash) - // epochNum = (5 - 5) / 5 = 0 - // epochSeed = keccak256(blkHash | 0) = 53205358842179480591542570540016728811976439286094436690881169143335261643310 - expEpochSeed, _ := new(big.Int).SetString("53205358842179480591542570540016728811976439286094436690881169143335261643310", 10) - assert.Equal(expEpochSeed, epochSeed) - - // Test epochNum > 0 - epochSeed = initializer.currentEpochSeed(big.NewInt(20), big.NewInt(5), blkHash) - // epochNum = (20 - 5) / 5 = 3 - // epochSeed = keccak256(blkHash | 3) = 42541119854153860846042329644941941146216657514071318786342840580076059276721 - expEpochSeed.SetString("42541119854153860846042329644941941146216657514071318786342840580076059276721", 10) - assert.Equal(expEpochSeed, epochSeed) - - // Test epochNum > 0 with some # of blocks into the epoch - epochSeed = initializer.currentEpochSeed(big.NewInt(20), big.NewInt(4), blkHash) - // epochNum = (20 - 4) / 5 = 3.2 -> 3 - assert.Equal(expEpochSeed, epochSeed) -} - -func TestRoundInitializer_ShouldInitialize(t *testing.T) { - client := &MockClient{} - tw := &stubTimeWatcher{} - initializer := NewRoundInitializer(client, tw) - - assert := assert.New(t) - - // Test error getting transcoders - expErr := errors.New("TranscoderPool error") - client.On("TranscoderPool").Return(nil, expErr).Once() - - ok, err := initializer.shouldInitialize(nil) - assert.EqualError(err, expErr.Error()) - assert.False(ok) - - // Test active set is empty because no registered transcoders - client.On("TranscoderPool").Return([]*lpTypes.Transcoder{}, nil).Once() - ok, err = initializer.shouldInitialize(nil) - assert.Nil(err) - assert.False(ok) - - // Test that caller is not in active set because it is not registered - caller := ethcommon.BytesToAddress([]byte("foo")) - client.On("Account").Return(accounts.Account{Address: caller}) - - registered := []*lpTypes.Transcoder{ - {Address: ethcommon.BytesToAddress([]byte("jar"))}, - {Address: ethcommon.BytesToAddress([]byte("bar"))}, - } - client.On("TranscoderPool").Return(registered, nil).Once() - - ok, err = initializer.shouldInitialize(nil) - assert.Nil(err) - assert.False(ok) - - // Test not selected - registered = append(registered, &lpTypes.Transcoder{Address: caller}) - client.On("TranscoderPool").Return(registered, nil) - - seed := big.NewInt(3) - ok, err = initializer.shouldInitialize(seed) - assert.Nil(err) - assert.False(ok) - - // Test caller selected - seed = big.NewInt(5) - ok, err = initializer.shouldInitialize(seed) - assert.Nil(err) - assert.True(ok) -} - func TestRoundInitializer_TryInitialize(t *testing.T) { client := &MockClient{} tw := &stubTimeWatcher{ @@ -101,45 +23,17 @@ func TestRoundInitializer_TryInitialize(t *testing.T) { lastInitializedRound: big.NewInt(100), lastInitializedBlockHash: [32]byte{123}, } - initializer := NewRoundInitializer(client, tw) + initializer := NewRoundInitializer(client, tw, 0) initializer.nextRoundStartL1Block = big.NewInt(5) assert := assert.New(t) - // Test error checking should initialize - expErr := errors.New("shouldInitialize error") - client.On("TranscoderPool").Return(nil, expErr).Once() - - err := initializer.tryInitialize() - assert.EqualError(err, expErr.Error()) - - // Test should not initialize - caller := ethcommon.BytesToAddress([]byte("foo")) - client.On("Account").Return(accounts.Account{Address: caller}) - - registered := []*lpTypes.Transcoder{ - {Address: ethcommon.BytesToAddress([]byte("jar"))}, - } - client.On("TranscoderPool").Return(registered, nil).Once() - - err = initializer.tryInitialize() - assert.Nil(err) - - // Test error when submitting initialization tx - registered = []*lpTypes.Transcoder{{Address: caller}} - client.On("TranscoderPool").Return(registered, nil) - expErr = errors.New("InitializeRound error") - client.On("InitializeRound").Return(nil, expErr).Once() - - err = initializer.tryInitialize() - assert.EqualError(err, expErr.Error()) - // Test error checking initialization tx tx := &types.Transaction{} client.On("InitializeRound").Return(tx, nil) - expErr = errors.New("CheckTx error") + expErr := errors.New("CheckTx error") client.On("CheckTx", mock.Anything).Return(expErr).Once() - err = initializer.tryInitialize() + err := initializer.tryInitialize() assert.EqualError(err, expErr.Error()) // Test success From b1b2c030ad39638ca3f1dead504ec2f1cdc516de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Wed, 8 May 2024 16:32:17 +0200 Subject: [PATCH 17/39] Fix CI Darwin Build (#3049) * Fix CI * Fix CI --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index cb2d590e43..6e93599485 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -157,7 +157,7 @@ jobs: target: - GOOS: darwin GOARCH: amd64 - runner: macos-latest + runner: macos-14-large - GOOS: darwin GOARCH: arm64 From 6e49ae205367d9d0729c962a8492aa097e45b200 Mon Sep 17 00:00:00 2001 From: kevincatty <168698033+kevincatty@users.noreply.github.com> Date: Thu, 9 May 2024 22:14:42 +0800 Subject: [PATCH 18/39] chore: fix function names (#3040) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: kevincatty Co-authored-by: RafaΕ‚ Leszko --- cmd/livepeer_cli/wizard.go | 2 +- core/orchestrator.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/livepeer_cli/wizard.go b/cmd/livepeer_cli/wizard.go index 01801e4fd6..27ba130174 100644 --- a/cmd/livepeer_cli/wizard.go +++ b/cmd/livepeer_cli/wizard.go @@ -76,7 +76,7 @@ func (w *wizard) readStringAndValidate(validate func(in string) (string, error)) } } -// readStringYesOrNot reads a single line from stdin, trims spaces and +// readStringYesOrNo reads a single line from stdin, trims spaces and // checks that the string is either y or n func (w *wizard) readStringYesOrNo() string { return w.readStringAndValidate(func(in string) (string, error) { diff --git a/core/orchestrator.go b/core/orchestrator.go index f5eeb121c4..d7314a4581 100644 --- a/core/orchestrator.go +++ b/core/orchestrator.go @@ -1033,7 +1033,7 @@ func (node *RemoteTranscoderManager) EndTranscodingSession(sessionId string) { panic("shouldn't be called on RemoteTranscoderManager") } -// completeStreamSessions end a stream session for a remote transcoder and decrements its load +// completeStreamSession end a stream session for a remote transcoder and decrements its load // caller should hold the mutex lock func (rtm *RemoteTranscoderManager) completeStreamSession(sessionId string) { t, ok := rtm.streamSessions[sessionId] From 133ca8bd0141275b9717328bf6369a576190fa01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Mon, 13 May 2024 18:28:09 +0200 Subject: [PATCH 19/39] Create option to filter Os by min livepeer version used (#3050) --- cmd/livepeer/livepeer.go | 1 + cmd/livepeer/starter/starter.go | 10 +- core/capabilities.go | 58 +- core/capabilities_test.go | 103 ++ core/livepeernode.go | 2 +- core/orch_test.go | 19 +- core/orchestrator.go | 4 +- go.mod | 1 + go.sum | 2 + net/lp_rpc.pb.go | 2934 ++++++++++++------------------- net/lp_rpc.proto | 6 +- net/lp_rpc_grpc.pb.go | 2 +- net/redeemer.pb.go | 1 - server/broadcast.go | 3 + server/mediaserver.go | 1 + 15 files changed, 1280 insertions(+), 1867 deletions(-) diff --git a/cmd/livepeer/livepeer.go b/cmd/livepeer/livepeer.go index 030d897957..b25472f7fa 100755 --- a/cmd/livepeer/livepeer.go +++ b/cmd/livepeer/livepeer.go @@ -127,6 +127,7 @@ func parseLivepeerConfig() starter.LivepeerConfig { cfg.OrchAddr = flag.String("orchAddr", *cfg.OrchAddr, "Comma-separated list of orchestrators to connect to") cfg.OrchWebhookURL = flag.String("orchWebhookUrl", *cfg.OrchWebhookURL, "Orchestrator discovery callback URL") cfg.OrchBlacklist = flag.String("orchBlocklist", "", "Comma-separated list of blocklisted orchestrators") + cfg.OrchMinLivepeerVersion = flag.String("orchMinLivepeerVersion", *cfg.OrchMinLivepeerVersion, "Minimal go-livepeer version orchestrator should have to be selected") cfg.SelectRandWeight = flag.Float64("selectRandFreq", *cfg.SelectRandWeight, "Weight of the random factor in the orchestrator selection algorithm") cfg.SelectStakeWeight = flag.Float64("selectStakeWeight", *cfg.SelectStakeWeight, "Weight of the stake factor in the orchestrator selection algorithm") cfg.SelectPriceWeight = flag.Float64("selectPriceWeight", *cfg.SelectPriceWeight, "Weight of the price factor in the orchestrator selection algorithm") diff --git a/cmd/livepeer/starter/starter.go b/cmd/livepeer/starter/starter.go index f9296abfa6..84ff08c330 100755 --- a/cmd/livepeer/starter/starter.go +++ b/cmd/livepeer/starter/starter.go @@ -144,6 +144,7 @@ type LivepeerConfig struct { AuthWebhookURL *string OrchWebhookURL *string OrchBlacklist *string + OrchMinLivepeerVersion *string TestOrchAvail *bool } @@ -230,6 +231,7 @@ func DefaultLivepeerConfig() LivepeerConfig { // API defaultAuthWebhookURL := "" defaultOrchWebhookURL := "" + defaultMinLivepeerVersion := "" // Flags defaultTestOrchAvail := true @@ -314,8 +316,9 @@ func DefaultLivepeerConfig() LivepeerConfig { FVfailGsKey: &defaultFVfailGsKey, // API - AuthWebhookURL: &defaultAuthWebhookURL, - OrchWebhookURL: &defaultOrchWebhookURL, + AuthWebhookURL: &defaultAuthWebhookURL, + OrchWebhookURL: &defaultOrchWebhookURL, + OrchMinLivepeerVersion: &defaultMinLivepeerVersion, // Flags TestOrchAvail: &defaultTestOrchAvail, @@ -1169,6 +1172,9 @@ func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { } n.Capabilities = core.NewCapabilities(transcoderCaps, core.MandatoryOCapabilities()) + if cfg.OrchMinLivepeerVersion != nil { + n.Capabilities.SetMinVersionConstraint(*cfg.OrchMinLivepeerVersion) + } if drivers.NodeStorage == nil { // base URI will be empty for broadcasters; that's OK diff --git a/core/capabilities.go b/core/capabilities.go index 9d54c41e16..7bd4f00f5f 100644 --- a/core/capabilities.go +++ b/core/capabilities.go @@ -3,9 +3,10 @@ package core import ( "errors" "fmt" - "sync" + "github.com/Masterminds/semver/v3" + "github.com/golang/glog" "github.com/livepeer/go-livepeer/net" "github.com/livepeer/go-tools/drivers" "github.com/livepeer/lpms/ffmpeg" @@ -13,10 +14,13 @@ import ( type Capability int type CapabilityString []uint64 -type Constraints struct{} +type Constraints struct { + minVersion string +} type Capabilities struct { bitstring CapabilityString mandatories CapabilityString + version string constraints Constraints capacities map[Capability]int mutex sync.Mutex @@ -316,6 +320,34 @@ func JobCapabilities(params *StreamParameters, segPar *SegmentParameters) (*Capa return &Capabilities{bitstring: NewCapabilityString(capList)}, nil } +func (bcast *Capabilities) LivepeerVersionCompatibleWith(orch *net.Capabilities) bool { + if bcast == nil || orch == nil || bcast.constraints.minVersion == "" { + // should not happen, but just in case, return true by default + return true + } + if orch.Version == "" || orch.Version == "undefined" { + // Orchestrator/Transcoder version is not set, so it's incompatible + return false + } + + minVer, err := semver.NewVersion(bcast.constraints.minVersion) + if err != nil { + glog.Warningf("error while parsing minVersion: %v", err) + return true + } + ver, err := semver.NewVersion(orch.Version) + if err != nil { + glog.Warningf("error while parsing version: %v", err) + return false + } + + // Ignore prerelease versions as in go-livepeer we actually define post-release suffixes + minVerNoSuffix, _ := minVer.SetPrerelease("") + verNoSuffix, _ := ver.SetPrerelease("") + + return !verNoSuffix.LessThan(&minVerNoSuffix) +} + func (bcast *Capabilities) CompatibleWith(orch *net.Capabilities) bool { // Ensure bcast and orch are compatible with one another. @@ -325,6 +357,9 @@ func (bcast *Capabilities) CompatibleWith(orch *net.Capabilities) bool { // cf. common.CapabilityComparator return false } + if !bcast.LivepeerVersionCompatibleWith(orch) { + return false + } // For now, check this: // ( orch.mandatories AND bcast.bitstring ) == orch.mandatories && @@ -346,7 +381,7 @@ func (c *Capabilities) ToNetCapabilities() *net.Capabilities { } c.mutex.Lock() defer c.mutex.Unlock() - netCaps := &net.Capabilities{Bitstring: c.bitstring, Mandatories: c.mandatories, Capacities: make(map[uint32]uint32)} + netCaps := &net.Capabilities{Bitstring: c.bitstring, Mandatories: c.mandatories, Version: c.version, Capacities: make(map[uint32]uint32), Constraints: &net.Capabilities_Constraints{MinVersion: c.constraints.minVersion}} for capability, capacity := range c.capacities { netCaps.Capacities[uint32(capability)] = uint32(capacity) } @@ -361,6 +396,8 @@ func CapabilitiesFromNetCapabilities(caps *net.Capabilities) *Capabilities { bitstring: caps.Bitstring, mandatories: caps.Mandatories, capacities: make(map[Capability]int), + version: caps.Version, + constraints: Constraints{minVersion: caps.Constraints.GetMinVersion()}, } if caps.Capacities == nil || len(caps.Capacities) == 0 { // build capacities map if not present (struct received from previous versions) @@ -381,7 +418,7 @@ func CapabilitiesFromNetCapabilities(caps *net.Capabilities) *Capabilities { } func NewCapabilities(caps []Capability, m []Capability) *Capabilities { - c := &Capabilities{capacities: make(map[Capability]int)} + c := &Capabilities{capacities: make(map[Capability]int), version: LivepeerVersion} if len(caps) > 0 { c.bitstring = NewCapabilityString(caps) // initialize capacities to 1 by default, mandatory capabilities doesn't have capacities @@ -567,3 +604,16 @@ func (bcast *Capabilities) LegacyOnly() bool { } return bcast.bitstring.CompatibleWith(legacyCapabilityString) } + +func (bcast *Capabilities) SetMinVersionConstraint(minVersionConstraint string) { + if bcast != nil { + bcast.constraints.minVersion = minVersionConstraint + } +} + +func (bcast *Capabilities) MinVersionConstraint() string { + if bcast != nil { + return bcast.constraints.minVersion + } + return "" +} diff --git a/core/capabilities_test.go b/core/capabilities_test.go index c9c1ee319f..b165a3d9ca 100644 --- a/core/capabilities_test.go +++ b/core/capabilities_test.go @@ -331,6 +331,20 @@ func TestCapability_CompatibleWithNetCap(t *testing.T) { orch = NewCapabilities(nil, nil) bcast = NewCapabilities(nil, []Capability{1}) assert.True(bcast.CompatibleWith(orch.ToNetCapabilities())) + + // broadcaster is not compatible with orchestrator - old O's version + orch = NewCapabilities(nil, nil) + bcast = NewCapabilities(nil, nil) + bcast.constraints.minVersion = "0.4.1" + orch.version = "0.4.0" + assert.False(bcast.CompatibleWith(orch.ToNetCapabilities())) + + // broadcaster is not compatible with orchestrator - the same version + orch = NewCapabilities(nil, nil) + bcast = NewCapabilities(nil, nil) + bcast.constraints.minVersion = "0.4.1" + orch.version = "0.4.1" + assert.True(bcast.CompatibleWith(orch.ToNetCapabilities())) } func TestCapability_RoundTrip_Net(t *testing.T) { @@ -474,3 +488,92 @@ func TestCapabilities_LegacyCheck(t *testing.T) { assert.Len(legacyCapabilities, legacyLen) // sanity check no modifications } + +func TestLiveeerVersionCompatibleWith(t *testing.T) { + tests := []struct { + name string + broadcasterMinVersion string + transcoderVersion string + expected bool + }{ + { + name: "broadcaster required version is the same as the transcoder version", + broadcasterMinVersion: "0.4.1", + transcoderVersion: "0.4.1", + expected: true, + }, + { + name: "broadcaster required version is less than the transcoder version", + broadcasterMinVersion: "0.4.0", + transcoderVersion: "0.4.1", + expected: true, + }, + { + name: "broadcaster required version is more than the transcoder version", + broadcasterMinVersion: "0.4.2", + transcoderVersion: "0.4.1", + expected: false, + }, + { + name: "broadcaster required version is the same as the transcoder dirty version", + broadcasterMinVersion: "0.4.1", + transcoderVersion: "0.4.1-b3278dce-dirty", + expected: true, + }, + { + name: "broadcaster required version is before the transcoder dirty version", + broadcasterMinVersion: "0.4.0", + transcoderVersion: "0.4.1-b3278dce-dirty", + expected: true, + }, + { + name: "broadcaster required version is after the transcoder dirty version", + broadcasterMinVersion: "0.4.2", + transcoderVersion: "0.4.1-b3278dce-dirty", + expected: false, + }, + { + name: "broadcaster required version is empty", + broadcasterMinVersion: "", + transcoderVersion: "0.4.1", + expected: true, + }, + { + name: "both versions are undefined", + broadcasterMinVersion: "", + transcoderVersion: "", + expected: true, + }, + { + name: "transcoder version is empty", + broadcasterMinVersion: "0.4.0", + transcoderVersion: "", + expected: false, + }, + { + name: "transcoder version is undefined", + broadcasterMinVersion: "0.4.0", + transcoderVersion: "undefined", + expected: false, + }, + { + name: "unparsable broadcaster's min version", + broadcasterMinVersion: "nonparsablesemversion", + transcoderVersion: "0.4.1", + expected: true, + }, + { + name: "unparsable transcoder's version", + broadcasterMinVersion: "0.4.1", + transcoderVersion: "nonparsablesemversion", + expected: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bCapabilities := &Capabilities{constraints: Constraints{minVersion: tt.broadcasterMinVersion}} + tCapabilities := &Capabilities{version: tt.transcoderVersion} + assert.Equal(t, tt.expected, bCapabilities.LivepeerVersionCompatibleWith(tCapabilities.ToNetCapabilities())) + }) + } +} diff --git a/core/livepeernode.go b/core/livepeernode.go index f4741aae93..19839a185b 100644 --- a/core/livepeernode.go +++ b/core/livepeernode.go @@ -108,7 +108,7 @@ func NewLivepeerNode(e eth.LivepeerEthClient, wd string, dbh *common.DB) (*Livep AutoAdjustPrice: true, SegmentChans: make(map[ManifestID]SegmentChan), segmentMutex: &sync.RWMutex{}, - Capabilities: &Capabilities{capacities: map[Capability]int{}}, + Capabilities: &Capabilities{capacities: map[Capability]int{}, version: LivepeerVersion}, priceInfo: make(map[string]*AutoConvertedPrice), StorageConfigs: make(map[string]*transcodeConfig), storageMutex: &sync.RWMutex{}, diff --git a/core/orch_test.go b/core/orch_test.go index dcc8a6c2d9..72aa9cb8bb 100644 --- a/core/orch_test.go +++ b/core/orch_test.go @@ -245,7 +245,10 @@ func TestSelectTranscoder(t *testing.T) { strm := &StubTranscoderServer{manager: m, WithholdResults: false} strm2 := &StubTranscoderServer{manager: m} + LivepeerVersion = "0.4.1" capabilities := NewCapabilities(DefaultCapabilities(), []Capability{}) + LivepeerVersion = "undefined" + richCapabilities := NewCapabilities(append(DefaultCapabilities(), Capability_HEVC_Encode), []Capability{}) allCapabilities := NewCapabilities(append(DefaultCapabilities(), OptionalCapabilities()...), []Capability{}) @@ -259,7 +262,7 @@ func TestSelectTranscoder(t *testing.T) { go func() { m.Manage(strm, 1, capabilities.ToNetCapabilities()) }() time.Sleep(1 * time.Millisecond) // allow time for first stream to register go func() { m.Manage(strm2, 1, richCapabilities.ToNetCapabilities()); wg.Done() }() - time.Sleep(1 * time.Millisecond) // allow time for second stream to register + time.Sleep(1 * time.Millisecond) // allow time for second stream to register e for third stream to register assert.NotNil(m.liveTranscoders[strm]) assert.NotNil(m.liveTranscoders[strm2]) @@ -341,6 +344,20 @@ func TestSelectTranscoder(t *testing.T) { assert.Equal(1, t1.load) m.completeStreamSession(testSessionId) assert.Equal(0, t1.load) + + // assert one transcoder with the correct Livepeer version is selected + minVersionCapabilities := NewCapabilities(DefaultCapabilities(), []Capability{}) + minVersionCapabilities.SetMinVersionConstraint("0.4.0") + currentTranscoder, err = m.selectTranscoder(testSessionId, minVersionCapabilities) + assert.Nil(err) + m.completeStreamSession(testSessionId) + + // assert no transcoders available for min version higher than any transcoder + minVersionHighCapabilities := NewCapabilities(DefaultCapabilities(), []Capability{}) + minVersionHighCapabilities.SetMinVersionConstraint("0.4.2") + currentTranscoder, err = m.selectTranscoder(testSessionId, minVersionHighCapabilities) + assert.NotNil(err) + m.completeStreamSession(testSessionId) } func TestCompleteStreamSession(t *testing.T) { diff --git a/core/orchestrator.go b/core/orchestrator.go index d7314a4581..50d6ea9757 100644 --- a/core/orchestrator.go +++ b/core/orchestrator.go @@ -981,7 +981,9 @@ func (rtm *RemoteTranscoderManager) selectTranscoder(sessionId string, caps *Cap findCompatibleTranscoder := func(rtm *RemoteTranscoderManager) int { for i := len(rtm.remoteTranscoders) - 1; i >= 0; i-- { // no capabilities = default capabilities, all transcoders must support them - if caps == nil || caps.bitstring.CompatibleWith(rtm.remoteTranscoders[i].capabilities.bitstring) { + if caps == nil || + (caps.bitstring.CompatibleWith(rtm.remoteTranscoders[i].capabilities.bitstring) && + caps.LivepeerVersionCompatibleWith(rtm.remoteTranscoders[i].capabilities.ToNetCapabilities())) { return i } } diff --git a/go.mod b/go.mod index fd1a55b99f..e4837beb3b 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/DataDog/zstd v1.4.5 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.1 // indirect github.com/StackExchange/wmi v1.2.1 // indirect diff --git a/go.sum b/go.sum index 984557a611..cad66eecff 100644 --- a/go.sum +++ b/go.sum @@ -60,6 +60,8 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA= diff --git a/net/lp_rpc.pb.go b/net/lp_rpc.pb.go index 5e6ac70297..d5102d77c5 100644 --- a/net/lp_rpc.pb.go +++ b/net/lp_rpc.pb.go @@ -1,24 +1,24 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.1 -// protoc v4.25.2 // source: net/lp_rpc.proto package net import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" ) -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package type OSInfo_StorageType int32 @@ -28,45 +28,24 @@ const ( OSInfo_GOOGLE OSInfo_StorageType = 2 ) -// Enum value maps for OSInfo_StorageType. -var ( - OSInfo_StorageType_name = map[int32]string{ - 0: "DIRECT", - 1: "S3", - 2: "GOOGLE", - } - OSInfo_StorageType_value = map[string]int32{ - "DIRECT": 0, - "S3": 1, - "GOOGLE": 2, - } -) - -func (x OSInfo_StorageType) Enum() *OSInfo_StorageType { - p := new(OSInfo_StorageType) - *p = x - return p +var OSInfo_StorageType_name = map[int32]string{ + 0: "DIRECT", + 1: "S3", + 2: "GOOGLE", } -func (x OSInfo_StorageType) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +var OSInfo_StorageType_value = map[string]int32{ + "DIRECT": 0, + "S3": 1, + "GOOGLE": 2, } -func (OSInfo_StorageType) Descriptor() protoreflect.EnumDescriptor { - return file_net_lp_rpc_proto_enumTypes[0].Descriptor() -} - -func (OSInfo_StorageType) Type() protoreflect.EnumType { - return &file_net_lp_rpc_proto_enumTypes[0] -} - -func (x OSInfo_StorageType) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) +func (x OSInfo_StorageType) String() string { + return proto.EnumName(OSInfo_StorageType_name, int32(x)) } -// Deprecated: Use OSInfo_StorageType.Descriptor instead. func (OSInfo_StorageType) EnumDescriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{4, 0} + return fileDescriptor_034e29c79f9ba827, []int{4, 0} } // Desired output format @@ -77,43 +56,22 @@ const ( VideoProfile_MP4 VideoProfile_Format = 1 ) -// Enum value maps for VideoProfile_Format. -var ( - VideoProfile_Format_name = map[int32]string{ - 0: "MPEGTS", - 1: "MP4", - } - VideoProfile_Format_value = map[string]int32{ - "MPEGTS": 0, - "MP4": 1, - } -) - -func (x VideoProfile_Format) Enum() *VideoProfile_Format { - p := new(VideoProfile_Format) - *p = x - return p -} - -func (x VideoProfile_Format) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (VideoProfile_Format) Descriptor() protoreflect.EnumDescriptor { - return file_net_lp_rpc_proto_enumTypes[1].Descriptor() +var VideoProfile_Format_name = map[int32]string{ + 0: "MPEGTS", + 1: "MP4", } -func (VideoProfile_Format) Type() protoreflect.EnumType { - return &file_net_lp_rpc_proto_enumTypes[1] +var VideoProfile_Format_value = map[string]int32{ + "MPEGTS": 0, + "MP4": 1, } -func (x VideoProfile_Format) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) +func (x VideoProfile_Format) String() string { + return proto.EnumName(VideoProfile_Format_name, int32(x)) } -// Deprecated: Use VideoProfile_Format.Descriptor instead. func (VideoProfile_Format) EnumDescriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{12, 0} + return fileDescriptor_034e29c79f9ba827, []int{12, 0} } type VideoProfile_Profile int32 @@ -126,49 +84,28 @@ const ( VideoProfile_H264_CONSTRAINED_HIGH VideoProfile_Profile = 4 ) -// Enum value maps for VideoProfile_Profile. -var ( - VideoProfile_Profile_name = map[int32]string{ - 0: "ENCODER_DEFAULT", - 1: "H264_BASELINE", - 2: "H264_MAIN", - 3: "H264_HIGH", - 4: "H264_CONSTRAINED_HIGH", - } - VideoProfile_Profile_value = map[string]int32{ - "ENCODER_DEFAULT": 0, - "H264_BASELINE": 1, - "H264_MAIN": 2, - "H264_HIGH": 3, - "H264_CONSTRAINED_HIGH": 4, - } -) - -func (x VideoProfile_Profile) Enum() *VideoProfile_Profile { - p := new(VideoProfile_Profile) - *p = x - return p -} - -func (x VideoProfile_Profile) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +var VideoProfile_Profile_name = map[int32]string{ + 0: "ENCODER_DEFAULT", + 1: "H264_BASELINE", + 2: "H264_MAIN", + 3: "H264_HIGH", + 4: "H264_CONSTRAINED_HIGH", } -func (VideoProfile_Profile) Descriptor() protoreflect.EnumDescriptor { - return file_net_lp_rpc_proto_enumTypes[2].Descriptor() +var VideoProfile_Profile_value = map[string]int32{ + "ENCODER_DEFAULT": 0, + "H264_BASELINE": 1, + "H264_MAIN": 2, + "H264_HIGH": 3, + "H264_CONSTRAINED_HIGH": 4, } -func (VideoProfile_Profile) Type() protoreflect.EnumType { - return &file_net_lp_rpc_proto_enumTypes[2] -} - -func (x VideoProfile_Profile) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) +func (x VideoProfile_Profile) String() string { + return proto.EnumName(VideoProfile_Profile_name, int32(x)) } -// Deprecated: Use VideoProfile_Profile.Descriptor instead. func (VideoProfile_Profile) EnumDescriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{12, 1} + return fileDescriptor_034e29c79f9ba827, []int{12, 1} } type VideoProfile_VideoCodec int32 @@ -180,47 +117,26 @@ const ( VideoProfile_VP9 VideoProfile_VideoCodec = 3 ) -// Enum value maps for VideoProfile_VideoCodec. -var ( - VideoProfile_VideoCodec_name = map[int32]string{ - 0: "H264", - 1: "H265", - 2: "VP8", - 3: "VP9", - } - VideoProfile_VideoCodec_value = map[string]int32{ - "H264": 0, - "H265": 1, - "VP8": 2, - "VP9": 3, - } -) - -func (x VideoProfile_VideoCodec) Enum() *VideoProfile_VideoCodec { - p := new(VideoProfile_VideoCodec) - *p = x - return p +var VideoProfile_VideoCodec_name = map[int32]string{ + 0: "H264", + 1: "H265", + 2: "VP8", + 3: "VP9", } -func (x VideoProfile_VideoCodec) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (VideoProfile_VideoCodec) Descriptor() protoreflect.EnumDescriptor { - return file_net_lp_rpc_proto_enumTypes[3].Descriptor() +var VideoProfile_VideoCodec_value = map[string]int32{ + "H264": 0, + "H265": 1, + "VP8": 2, + "VP9": 3, } -func (VideoProfile_VideoCodec) Type() protoreflect.EnumType { - return &file_net_lp_rpc_proto_enumTypes[3] -} - -func (x VideoProfile_VideoCodec) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) +func (x VideoProfile_VideoCodec) String() string { + return proto.EnumName(VideoProfile_VideoCodec_name, int32(x)) } -// Deprecated: Use VideoProfile_VideoCodec.Descriptor instead. func (VideoProfile_VideoCodec) EnumDescriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{12, 2} + return fileDescriptor_034e29c79f9ba827, []int{12, 2} } type VideoProfile_ChromaSubsampling int32 @@ -231,237 +147,185 @@ const ( VideoProfile_CHROMA_444 VideoProfile_ChromaSubsampling = 2 ) -// Enum value maps for VideoProfile_ChromaSubsampling. -var ( - VideoProfile_ChromaSubsampling_name = map[int32]string{ - 0: "CHROMA_420", - 1: "CHROMA_422", - 2: "CHROMA_444", - } - VideoProfile_ChromaSubsampling_value = map[string]int32{ - "CHROMA_420": 0, - "CHROMA_422": 1, - "CHROMA_444": 2, - } -) - -func (x VideoProfile_ChromaSubsampling) Enum() *VideoProfile_ChromaSubsampling { - p := new(VideoProfile_ChromaSubsampling) - *p = x - return p -} - -func (x VideoProfile_ChromaSubsampling) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (VideoProfile_ChromaSubsampling) Descriptor() protoreflect.EnumDescriptor { - return file_net_lp_rpc_proto_enumTypes[4].Descriptor() +var VideoProfile_ChromaSubsampling_name = map[int32]string{ + 0: "CHROMA_420", + 1: "CHROMA_422", + 2: "CHROMA_444", } -func (VideoProfile_ChromaSubsampling) Type() protoreflect.EnumType { - return &file_net_lp_rpc_proto_enumTypes[4] +var VideoProfile_ChromaSubsampling_value = map[string]int32{ + "CHROMA_420": 0, + "CHROMA_422": 1, + "CHROMA_444": 2, } -func (x VideoProfile_ChromaSubsampling) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) +func (x VideoProfile_ChromaSubsampling) String() string { + return proto.EnumName(VideoProfile_ChromaSubsampling_name, int32(x)) } -// Deprecated: Use VideoProfile_ChromaSubsampling.Descriptor instead. func (VideoProfile_ChromaSubsampling) EnumDescriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{12, 3} + return fileDescriptor_034e29c79f9ba827, []int{12, 3} } type PingPong struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Implementation defined - Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *PingPong) Reset() { - *x = PingPong{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *PingPong) Reset() { *m = PingPong{} } +func (m *PingPong) String() string { return proto.CompactTextString(m) } +func (*PingPong) ProtoMessage() {} +func (*PingPong) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{0} } -func (x *PingPong) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *PingPong) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PingPong.Unmarshal(m, b) } - -func (*PingPong) ProtoMessage() {} - -func (x *PingPong) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *PingPong) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PingPong.Marshal(b, m, deterministic) } - -// Deprecated: Use PingPong.ProtoReflect.Descriptor instead. -func (*PingPong) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{0} +func (m *PingPong) XXX_Merge(src proto.Message) { + xxx_messageInfo_PingPong.Merge(m, src) +} +func (m *PingPong) XXX_Size() int { + return xxx_messageInfo_PingPong.Size(m) } +func (m *PingPong) XXX_DiscardUnknown() { + xxx_messageInfo_PingPong.DiscardUnknown(m) +} + +var xxx_messageInfo_PingPong proto.InternalMessageInfo -func (x *PingPong) GetValue() []byte { - if x != nil { - return x.Value +func (m *PingPong) GetValue() []byte { + if m != nil { + return m.Value } return nil } // sent by Broadcaster to Orchestrator to terminate the transcoding session and free resources (used for verification sessions) type EndTranscodingSessionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Data for transcoding authentication - AuthToken *AuthToken `protobuf:"bytes,1,opt,name=auth_token,json=authToken,proto3" json:"auth_token,omitempty"` + AuthToken *AuthToken `protobuf:"bytes,1,opt,name=auth_token,json=authToken,proto3" json:"auth_token,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *EndTranscodingSessionRequest) Reset() { - *x = EndTranscodingSessionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *EndTranscodingSessionRequest) Reset() { *m = EndTranscodingSessionRequest{} } +func (m *EndTranscodingSessionRequest) String() string { return proto.CompactTextString(m) } +func (*EndTranscodingSessionRequest) ProtoMessage() {} +func (*EndTranscodingSessionRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{1} } -func (x *EndTranscodingSessionRequest) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *EndTranscodingSessionRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EndTranscodingSessionRequest.Unmarshal(m, b) } - -func (*EndTranscodingSessionRequest) ProtoMessage() {} - -func (x *EndTranscodingSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *EndTranscodingSessionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EndTranscodingSessionRequest.Marshal(b, m, deterministic) } - -// Deprecated: Use EndTranscodingSessionRequest.ProtoReflect.Descriptor instead. -func (*EndTranscodingSessionRequest) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{1} +func (m *EndTranscodingSessionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EndTranscodingSessionRequest.Merge(m, src) +} +func (m *EndTranscodingSessionRequest) XXX_Size() int { + return xxx_messageInfo_EndTranscodingSessionRequest.Size(m) } +func (m *EndTranscodingSessionRequest) XXX_DiscardUnknown() { + xxx_messageInfo_EndTranscodingSessionRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_EndTranscodingSessionRequest proto.InternalMessageInfo -func (x *EndTranscodingSessionRequest) GetAuthToken() *AuthToken { - if x != nil { - return x.AuthToken +func (m *EndTranscodingSessionRequest) GetAuthToken() *AuthToken { + if m != nil { + return m.AuthToken } return nil } type EndTranscodingSessionResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *EndTranscodingSessionResponse) Reset() { - *x = EndTranscodingSessionResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *EndTranscodingSessionResponse) Reset() { *m = EndTranscodingSessionResponse{} } +func (m *EndTranscodingSessionResponse) String() string { return proto.CompactTextString(m) } +func (*EndTranscodingSessionResponse) ProtoMessage() {} +func (*EndTranscodingSessionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{2} } -func (x *EndTranscodingSessionResponse) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *EndTranscodingSessionResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EndTranscodingSessionResponse.Unmarshal(m, b) } - -func (*EndTranscodingSessionResponse) ProtoMessage() {} - -func (x *EndTranscodingSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *EndTranscodingSessionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EndTranscodingSessionResponse.Marshal(b, m, deterministic) } - -// Deprecated: Use EndTranscodingSessionResponse.ProtoReflect.Descriptor instead. -func (*EndTranscodingSessionResponse) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{2} +func (m *EndTranscodingSessionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_EndTranscodingSessionResponse.Merge(m, src) +} +func (m *EndTranscodingSessionResponse) XXX_Size() int { + return xxx_messageInfo_EndTranscodingSessionResponse.Size(m) +} +func (m *EndTranscodingSessionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_EndTranscodingSessionResponse.DiscardUnknown(m) } +var xxx_messageInfo_EndTranscodingSessionResponse proto.InternalMessageInfo + // This request is sent by the broadcaster in `GetTranscoder` to request // information on which transcoder to use. type OrchestratorRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Ethereum address of the broadcaster Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // Broadcaster's signature over its address - Sig []byte `protobuf:"bytes,2,opt,name=sig,proto3" json:"sig,omitempty"` + Sig []byte `protobuf:"bytes,2,opt,name=sig,proto3" json:"sig,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *OrchestratorRequest) Reset() { - *x = OrchestratorRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *OrchestratorRequest) Reset() { *m = OrchestratorRequest{} } +func (m *OrchestratorRequest) String() string { return proto.CompactTextString(m) } +func (*OrchestratorRequest) ProtoMessage() {} +func (*OrchestratorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{3} } -func (x *OrchestratorRequest) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *OrchestratorRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OrchestratorRequest.Unmarshal(m, b) } - -func (*OrchestratorRequest) ProtoMessage() {} - -func (x *OrchestratorRequest) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *OrchestratorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OrchestratorRequest.Marshal(b, m, deterministic) } - -// Deprecated: Use OrchestratorRequest.ProtoReflect.Descriptor instead. -func (*OrchestratorRequest) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{3} +func (m *OrchestratorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrchestratorRequest.Merge(m, src) +} +func (m *OrchestratorRequest) XXX_Size() int { + return xxx_messageInfo_OrchestratorRequest.Size(m) +} +func (m *OrchestratorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_OrchestratorRequest.DiscardUnknown(m) } -func (x *OrchestratorRequest) GetAddress() []byte { - if x != nil { - return x.Address +var xxx_messageInfo_OrchestratorRequest proto.InternalMessageInfo + +func (m *OrchestratorRequest) GetAddress() []byte { + if m != nil { + return m.Address } return nil } -func (x *OrchestratorRequest) GetSig() []byte { - if x != nil { - return x.Sig +func (m *OrchestratorRequest) GetSig() []byte { + if m != nil { + return m.Sig } return nil } @@ -469,66 +333,54 @@ func (x *OrchestratorRequest) GetSig() []byte { // OSInfo needed to negotiate storages that will be used. // It carries info needed to write to the storage. type OSInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Storage type: direct, s3, ipfs. - StorageType OSInfo_StorageType `protobuf:"varint,1,opt,name=storageType,proto3,enum=net.OSInfo_StorageType" json:"storageType,omitempty"` - S3Info *S3OSInfo `protobuf:"bytes,16,opt,name=s3info,proto3" json:"s3info,omitempty"` + StorageType OSInfo_StorageType `protobuf:"varint,1,opt,name=storageType,proto3,enum=net.OSInfo_StorageType" json:"storageType,omitempty"` + S3Info *S3OSInfo `protobuf:"bytes,16,opt,name=s3info,proto3" json:"s3info,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *OSInfo) Reset() { - *x = OSInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *OSInfo) Reset() { *m = OSInfo{} } +func (m *OSInfo) String() string { return proto.CompactTextString(m) } +func (*OSInfo) ProtoMessage() {} +func (*OSInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{4} } -func (x *OSInfo) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *OSInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OSInfo.Unmarshal(m, b) } - -func (*OSInfo) ProtoMessage() {} - -func (x *OSInfo) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *OSInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OSInfo.Marshal(b, m, deterministic) } - -// Deprecated: Use OSInfo.ProtoReflect.Descriptor instead. -func (*OSInfo) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{4} +func (m *OSInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_OSInfo.Merge(m, src) +} +func (m *OSInfo) XXX_Size() int { + return xxx_messageInfo_OSInfo.Size(m) } +func (m *OSInfo) XXX_DiscardUnknown() { + xxx_messageInfo_OSInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_OSInfo proto.InternalMessageInfo -func (x *OSInfo) GetStorageType() OSInfo_StorageType { - if x != nil { - return x.StorageType +func (m *OSInfo) GetStorageType() OSInfo_StorageType { + if m != nil { + return m.StorageType } return OSInfo_DIRECT } -func (x *OSInfo) GetS3Info() *S3OSInfo { - if x != nil { - return x.S3Info +func (m *OSInfo) GetS3Info() *S3OSInfo { + if m != nil { + return m.S3Info } return nil } type S3OSInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Host to use to connect to S3 Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"` // Key (prefix) to use when uploading the object. @@ -540,215 +392,247 @@ type S3OSInfo struct { // Needed for POST policy. Credential string `protobuf:"bytes,5,opt,name=credential,proto3" json:"credential,omitempty"` // Needed for POST policy. - XAmzDate string `protobuf:"bytes,6,opt,name=xAmzDate,proto3" json:"xAmzDate,omitempty"` + XAmzDate string `protobuf:"bytes,6,opt,name=xAmzDate,proto3" json:"xAmzDate,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *S3OSInfo) Reset() { - *x = S3OSInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *S3OSInfo) Reset() { *m = S3OSInfo{} } +func (m *S3OSInfo) String() string { return proto.CompactTextString(m) } +func (*S3OSInfo) ProtoMessage() {} +func (*S3OSInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{5} } -func (x *S3OSInfo) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *S3OSInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_S3OSInfo.Unmarshal(m, b) } - -func (*S3OSInfo) ProtoMessage() {} - -func (x *S3OSInfo) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *S3OSInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_S3OSInfo.Marshal(b, m, deterministic) } - -// Deprecated: Use S3OSInfo.ProtoReflect.Descriptor instead. -func (*S3OSInfo) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{5} +func (m *S3OSInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_S3OSInfo.Merge(m, src) +} +func (m *S3OSInfo) XXX_Size() int { + return xxx_messageInfo_S3OSInfo.Size(m) } +func (m *S3OSInfo) XXX_DiscardUnknown() { + xxx_messageInfo_S3OSInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_S3OSInfo proto.InternalMessageInfo -func (x *S3OSInfo) GetHost() string { - if x != nil { - return x.Host +func (m *S3OSInfo) GetHost() string { + if m != nil { + return m.Host } return "" } -func (x *S3OSInfo) GetKey() string { - if x != nil { - return x.Key +func (m *S3OSInfo) GetKey() string { + if m != nil { + return m.Key } return "" } -func (x *S3OSInfo) GetPolicy() string { - if x != nil { - return x.Policy +func (m *S3OSInfo) GetPolicy() string { + if m != nil { + return m.Policy } return "" } -func (x *S3OSInfo) GetSignature() string { - if x != nil { - return x.Signature +func (m *S3OSInfo) GetSignature() string { + if m != nil { + return m.Signature } return "" } -func (x *S3OSInfo) GetCredential() string { - if x != nil { - return x.Credential +func (m *S3OSInfo) GetCredential() string { + if m != nil { + return m.Credential } return "" } -func (x *S3OSInfo) GetXAmzDate() string { - if x != nil { - return x.XAmzDate +func (m *S3OSInfo) GetXAmzDate() string { + if m != nil { + return m.XAmzDate } return "" } // PriceInfo conveys pricing info for transcoding services type PriceInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // price in wei PricePerUnit int64 `protobuf:"varint,1,opt,name=pricePerUnit,proto3" json:"pricePerUnit,omitempty"` // Pixels covered in the price // Set price to 1 wei and pixelsPerUnit > 1 to have a smaller price granularity per pixel than 1 wei - PixelsPerUnit int64 `protobuf:"varint,2,opt,name=pixelsPerUnit,proto3" json:"pixelsPerUnit,omitempty"` + PixelsPerUnit int64 `protobuf:"varint,2,opt,name=pixelsPerUnit,proto3" json:"pixelsPerUnit,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *PriceInfo) Reset() { - *x = PriceInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *PriceInfo) Reset() { *m = PriceInfo{} } +func (m *PriceInfo) String() string { return proto.CompactTextString(m) } +func (*PriceInfo) ProtoMessage() {} +func (*PriceInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{6} } -func (x *PriceInfo) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *PriceInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PriceInfo.Unmarshal(m, b) } - -func (*PriceInfo) ProtoMessage() {} - -func (x *PriceInfo) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *PriceInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PriceInfo.Marshal(b, m, deterministic) } - -// Deprecated: Use PriceInfo.ProtoReflect.Descriptor instead. -func (*PriceInfo) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{6} +func (m *PriceInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_PriceInfo.Merge(m, src) +} +func (m *PriceInfo) XXX_Size() int { + return xxx_messageInfo_PriceInfo.Size(m) +} +func (m *PriceInfo) XXX_DiscardUnknown() { + xxx_messageInfo_PriceInfo.DiscardUnknown(m) } -func (x *PriceInfo) GetPricePerUnit() int64 { - if x != nil { - return x.PricePerUnit +var xxx_messageInfo_PriceInfo proto.InternalMessageInfo + +func (m *PriceInfo) GetPricePerUnit() int64 { + if m != nil { + return m.PricePerUnit } return 0 } -func (x *PriceInfo) GetPixelsPerUnit() int64 { - if x != nil { - return x.PixelsPerUnit +func (m *PriceInfo) GetPixelsPerUnit() int64 { + if m != nil { + return m.PixelsPerUnit } return 0 } type Capabilities struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Bit string of supported features - one bit per feature Bitstring []uint64 `protobuf:"varint,1,rep,packed,name=bitstring,proto3" json:"bitstring,omitempty"` // Bit string of features that are required to be supported Mandatories []uint64 `protobuf:"varint,2,rep,packed,name=mandatories,proto3" json:"mandatories,omitempty"` // Capacity corresponding to each capability - Capacities map[uint32]uint32 `protobuf:"bytes,3,rep,name=capacities,proto3" json:"capacities,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + Capacities map[uint32]uint32 `protobuf:"bytes,3,rep,name=capacities,proto3" json:"capacities,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` + Constraints *Capabilities_Constraints `protobuf:"bytes,5,opt,name=constraints,proto3" json:"constraints,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *Capabilities) Reset() { - *x = Capabilities{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *Capabilities) Reset() { *m = Capabilities{} } +func (m *Capabilities) String() string { return proto.CompactTextString(m) } +func (*Capabilities) ProtoMessage() {} +func (*Capabilities) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{7} } -func (x *Capabilities) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *Capabilities) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Capabilities.Unmarshal(m, b) +} +func (m *Capabilities) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Capabilities.Marshal(b, m, deterministic) +} +func (m *Capabilities) XXX_Merge(src proto.Message) { + xxx_messageInfo_Capabilities.Merge(m, src) +} +func (m *Capabilities) XXX_Size() int { + return xxx_messageInfo_Capabilities.Size(m) +} +func (m *Capabilities) XXX_DiscardUnknown() { + xxx_messageInfo_Capabilities.DiscardUnknown(m) } -func (*Capabilities) ProtoMessage() {} +var xxx_messageInfo_Capabilities proto.InternalMessageInfo -func (x *Capabilities) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms +func (m *Capabilities) GetBitstring() []uint64 { + if m != nil { + return m.Bitstring } - return mi.MessageOf(x) + return nil } -// Deprecated: Use Capabilities.ProtoReflect.Descriptor instead. -func (*Capabilities) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{7} +func (m *Capabilities) GetMandatories() []uint64 { + if m != nil { + return m.Mandatories + } + return nil } -func (x *Capabilities) GetBitstring() []uint64 { - if x != nil { - return x.Bitstring +func (m *Capabilities) GetCapacities() map[uint32]uint32 { + if m != nil { + return m.Capacities } return nil } -func (x *Capabilities) GetMandatories() []uint64 { - if x != nil { - return x.Mandatories +func (m *Capabilities) GetVersion() string { + if m != nil { + return m.Version } - return nil + return "" } -func (x *Capabilities) GetCapacities() map[uint32]uint32 { - if x != nil { - return x.Capacities +func (m *Capabilities) GetConstraints() *Capabilities_Constraints { + if m != nil { + return m.Constraints } return nil } +// Non-binary capability constraints, such as supported ranges. +type Capabilities_Constraints struct { + MinVersion string `protobuf:"bytes,1,opt,name=minVersion,proto3" json:"minVersion,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Capabilities_Constraints) Reset() { *m = Capabilities_Constraints{} } +func (m *Capabilities_Constraints) String() string { return proto.CompactTextString(m) } +func (*Capabilities_Constraints) ProtoMessage() {} +func (*Capabilities_Constraints) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{7, 1} +} + +func (m *Capabilities_Constraints) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Capabilities_Constraints.Unmarshal(m, b) +} +func (m *Capabilities_Constraints) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Capabilities_Constraints.Marshal(b, m, deterministic) +} +func (m *Capabilities_Constraints) XXX_Merge(src proto.Message) { + xxx_messageInfo_Capabilities_Constraints.Merge(m, src) +} +func (m *Capabilities_Constraints) XXX_Size() int { + return xxx_messageInfo_Capabilities_Constraints.Size(m) +} +func (m *Capabilities_Constraints) XXX_DiscardUnknown() { + xxx_messageInfo_Capabilities_Constraints.DiscardUnknown(m) +} + +var xxx_messageInfo_Capabilities_Constraints proto.InternalMessageInfo + +func (m *Capabilities_Constraints) GetMinVersion() string { + if m != nil { + return m.MinVersion + } + return "" +} + // The orchestrator sends this in response to `GetOrchestrator`, containing // miscellaneous data related to the job. type OrchestratorInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // URI of the transcoder to use for submitting segments. Transcoder string `protobuf:"bytes,1,opt,name=transcoder,proto3" json:"transcoder,omitempty"` // Parameters for probabilistic micropayment tickets @@ -762,164 +646,148 @@ type OrchestratorInfo struct { // Data for transcoding authentication AuthToken *AuthToken `protobuf:"bytes,6,opt,name=auth_token,json=authToken,proto3" json:"auth_token,omitempty"` // Orchestrator returns info about own input object storage, if it wants it to be used. - Storage []*OSInfo `protobuf:"bytes,32,rep,name=storage,proto3" json:"storage,omitempty"` + Storage []*OSInfo `protobuf:"bytes,32,rep,name=storage,proto3" json:"storage,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *OrchestratorInfo) Reset() { - *x = OrchestratorInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *OrchestratorInfo) Reset() { *m = OrchestratorInfo{} } +func (m *OrchestratorInfo) String() string { return proto.CompactTextString(m) } +func (*OrchestratorInfo) ProtoMessage() {} +func (*OrchestratorInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{8} } -func (x *OrchestratorInfo) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *OrchestratorInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OrchestratorInfo.Unmarshal(m, b) } - -func (*OrchestratorInfo) ProtoMessage() {} - -func (x *OrchestratorInfo) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *OrchestratorInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OrchestratorInfo.Marshal(b, m, deterministic) } - -// Deprecated: Use OrchestratorInfo.ProtoReflect.Descriptor instead. -func (*OrchestratorInfo) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{8} +func (m *OrchestratorInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrchestratorInfo.Merge(m, src) } +func (m *OrchestratorInfo) XXX_Size() int { + return xxx_messageInfo_OrchestratorInfo.Size(m) +} +func (m *OrchestratorInfo) XXX_DiscardUnknown() { + xxx_messageInfo_OrchestratorInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_OrchestratorInfo proto.InternalMessageInfo -func (x *OrchestratorInfo) GetTranscoder() string { - if x != nil { - return x.Transcoder +func (m *OrchestratorInfo) GetTranscoder() string { + if m != nil { + return m.Transcoder } return "" } -func (x *OrchestratorInfo) GetTicketParams() *TicketParams { - if x != nil { - return x.TicketParams +func (m *OrchestratorInfo) GetTicketParams() *TicketParams { + if m != nil { + return m.TicketParams } return nil } -func (x *OrchestratorInfo) GetPriceInfo() *PriceInfo { - if x != nil { - return x.PriceInfo +func (m *OrchestratorInfo) GetPriceInfo() *PriceInfo { + if m != nil { + return m.PriceInfo } return nil } -func (x *OrchestratorInfo) GetAddress() []byte { - if x != nil { - return x.Address +func (m *OrchestratorInfo) GetAddress() []byte { + if m != nil { + return m.Address } return nil } -func (x *OrchestratorInfo) GetCapabilities() *Capabilities { - if x != nil { - return x.Capabilities +func (m *OrchestratorInfo) GetCapabilities() *Capabilities { + if m != nil { + return m.Capabilities } return nil } -func (x *OrchestratorInfo) GetAuthToken() *AuthToken { - if x != nil { - return x.AuthToken +func (m *OrchestratorInfo) GetAuthToken() *AuthToken { + if m != nil { + return m.AuthToken } return nil } -func (x *OrchestratorInfo) GetStorage() []*OSInfo { - if x != nil { - return x.Storage +func (m *OrchestratorInfo) GetStorage() []*OSInfo { + if m != nil { + return m.Storage } return nil } // Data for transcoding authentication that is included in the OrchestratorInfo message during discovery type AuthToken struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Record used to authenticate for a transcode session // Opaque to the receiver Token []byte `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` // ID of the transcode session that the token is authenticating for SessionId string `protobuf:"bytes,2,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` // Timestamp when the token expires - Expiration int64 `protobuf:"varint,3,opt,name=expiration,proto3" json:"expiration,omitempty"` + Expiration int64 `protobuf:"varint,3,opt,name=expiration,proto3" json:"expiration,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *AuthToken) Reset() { - *x = AuthToken{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *AuthToken) Reset() { *m = AuthToken{} } +func (m *AuthToken) String() string { return proto.CompactTextString(m) } +func (*AuthToken) ProtoMessage() {} +func (*AuthToken) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{9} } -func (x *AuthToken) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *AuthToken) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AuthToken.Unmarshal(m, b) } - -func (*AuthToken) ProtoMessage() {} - -func (x *AuthToken) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *AuthToken) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AuthToken.Marshal(b, m, deterministic) } - -// Deprecated: Use AuthToken.ProtoReflect.Descriptor instead. -func (*AuthToken) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{9} +func (m *AuthToken) XXX_Merge(src proto.Message) { + xxx_messageInfo_AuthToken.Merge(m, src) +} +func (m *AuthToken) XXX_Size() int { + return xxx_messageInfo_AuthToken.Size(m) } +func (m *AuthToken) XXX_DiscardUnknown() { + xxx_messageInfo_AuthToken.DiscardUnknown(m) +} + +var xxx_messageInfo_AuthToken proto.InternalMessageInfo -func (x *AuthToken) GetToken() []byte { - if x != nil { - return x.Token +func (m *AuthToken) GetToken() []byte { + if m != nil { + return m.Token } return nil } -func (x *AuthToken) GetSessionId() string { - if x != nil { - return x.SessionId +func (m *AuthToken) GetSessionId() string { + if m != nil { + return m.SessionId } return "" } -func (x *AuthToken) GetExpiration() int64 { - if x != nil { - return x.Expiration +func (m *AuthToken) GetExpiration() int64 { + if m != nil { + return m.Expiration } return 0 } // Data included by the broadcaster when submitting a segment for transcoding. type SegData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Manifest ID this segment belongs to ManifestId []byte `protobuf:"bytes,1,opt,name=manifestId,proto3" json:"manifestId,omitempty"` // Sequence number of the segment to be transcoded @@ -953,210 +821,194 @@ type SegData struct { // Transcoding parameters specific to this segment SegmentParameters *SegParameters `protobuf:"bytes,37,opt,name=segment_parameters,json=segmentParameters,proto3" json:"segment_parameters,omitempty"` // Force HW Session Reinit - ForceSessionReinit bool `protobuf:"varint,38,opt,name=ForceSessionReinit,proto3" json:"ForceSessionReinit,omitempty"` + ForceSessionReinit bool `protobuf:"varint,38,opt,name=ForceSessionReinit,proto3" json:"ForceSessionReinit,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *SegData) Reset() { - *x = SegData{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *SegData) Reset() { *m = SegData{} } +func (m *SegData) String() string { return proto.CompactTextString(m) } +func (*SegData) ProtoMessage() {} +func (*SegData) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{10} } -func (x *SegData) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *SegData) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SegData.Unmarshal(m, b) } - -func (*SegData) ProtoMessage() {} - -func (x *SegData) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *SegData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SegData.Marshal(b, m, deterministic) } - -// Deprecated: Use SegData.ProtoReflect.Descriptor instead. -func (*SegData) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{10} +func (m *SegData) XXX_Merge(src proto.Message) { + xxx_messageInfo_SegData.Merge(m, src) +} +func (m *SegData) XXX_Size() int { + return xxx_messageInfo_SegData.Size(m) } +func (m *SegData) XXX_DiscardUnknown() { + xxx_messageInfo_SegData.DiscardUnknown(m) +} + +var xxx_messageInfo_SegData proto.InternalMessageInfo -func (x *SegData) GetManifestId() []byte { - if x != nil { - return x.ManifestId +func (m *SegData) GetManifestId() []byte { + if m != nil { + return m.ManifestId } return nil } -func (x *SegData) GetSeq() int64 { - if x != nil { - return x.Seq +func (m *SegData) GetSeq() int64 { + if m != nil { + return m.Seq } return 0 } -func (x *SegData) GetHash() []byte { - if x != nil { - return x.Hash +func (m *SegData) GetHash() []byte { + if m != nil { + return m.Hash } return nil } -func (x *SegData) GetProfiles() []byte { - if x != nil { - return x.Profiles +func (m *SegData) GetProfiles() []byte { + if m != nil { + return m.Profiles } return nil } -func (x *SegData) GetSig() []byte { - if x != nil { - return x.Sig +func (m *SegData) GetSig() []byte { + if m != nil { + return m.Sig } return nil } -func (x *SegData) GetDuration() int32 { - if x != nil { - return x.Duration +func (m *SegData) GetDuration() int32 { + if m != nil { + return m.Duration } return 0 } -func (x *SegData) GetCapabilities() *Capabilities { - if x != nil { - return x.Capabilities +func (m *SegData) GetCapabilities() *Capabilities { + if m != nil { + return m.Capabilities } return nil } -func (x *SegData) GetAuthToken() *AuthToken { - if x != nil { - return x.AuthToken +func (m *SegData) GetAuthToken() *AuthToken { + if m != nil { + return m.AuthToken } return nil } -func (x *SegData) GetCalcPerceptualHash() bool { - if x != nil { - return x.CalcPerceptualHash +func (m *SegData) GetCalcPerceptualHash() bool { + if m != nil { + return m.CalcPerceptualHash } return false } -func (x *SegData) GetStorage() []*OSInfo { - if x != nil { - return x.Storage +func (m *SegData) GetStorage() []*OSInfo { + if m != nil { + return m.Storage } return nil } -func (x *SegData) GetFullProfiles() []*VideoProfile { - if x != nil { - return x.FullProfiles +func (m *SegData) GetFullProfiles() []*VideoProfile { + if m != nil { + return m.FullProfiles } return nil } -func (x *SegData) GetFullProfiles2() []*VideoProfile { - if x != nil { - return x.FullProfiles2 +func (m *SegData) GetFullProfiles2() []*VideoProfile { + if m != nil { + return m.FullProfiles2 } return nil } -func (x *SegData) GetFullProfiles3() []*VideoProfile { - if x != nil { - return x.FullProfiles3 +func (m *SegData) GetFullProfiles3() []*VideoProfile { + if m != nil { + return m.FullProfiles3 } return nil } -func (x *SegData) GetSegmentParameters() *SegParameters { - if x != nil { - return x.SegmentParameters +func (m *SegData) GetSegmentParameters() *SegParameters { + if m != nil { + return m.SegmentParameters } return nil } -func (x *SegData) GetForceSessionReinit() bool { - if x != nil { - return x.ForceSessionReinit +func (m *SegData) GetForceSessionReinit() bool { + if m != nil { + return m.ForceSessionReinit } return false } type SegParameters struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Start timestamp from which to start encoding // Milliseconds, from start of the file From uint64 `protobuf:"varint,1,opt,name=from,proto3" json:"from,omitempty"` // Skip all frames after that timestamp // Milliseconds, from start of the file - To uint64 `protobuf:"varint,2,opt,name=to,proto3" json:"to,omitempty"` + To uint64 `protobuf:"varint,2,opt,name=to,proto3" json:"to,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *SegParameters) Reset() { - *x = SegParameters{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *SegParameters) Reset() { *m = SegParameters{} } +func (m *SegParameters) String() string { return proto.CompactTextString(m) } +func (*SegParameters) ProtoMessage() {} +func (*SegParameters) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{11} } -func (x *SegParameters) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *SegParameters) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SegParameters.Unmarshal(m, b) } - -func (*SegParameters) ProtoMessage() {} - -func (x *SegParameters) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *SegParameters) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SegParameters.Marshal(b, m, deterministic) } - -// Deprecated: Use SegParameters.ProtoReflect.Descriptor instead. -func (*SegParameters) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{11} +func (m *SegParameters) XXX_Merge(src proto.Message) { + xxx_messageInfo_SegParameters.Merge(m, src) +} +func (m *SegParameters) XXX_Size() int { + return xxx_messageInfo_SegParameters.Size(m) +} +func (m *SegParameters) XXX_DiscardUnknown() { + xxx_messageInfo_SegParameters.DiscardUnknown(m) } -func (x *SegParameters) GetFrom() uint64 { - if x != nil { - return x.From +var xxx_messageInfo_SegParameters proto.InternalMessageInfo + +func (m *SegParameters) GetFrom() uint64 { + if m != nil { + return m.From } return 0 } -func (x *SegParameters) GetTo() uint64 { - if x != nil { - return x.To +func (m *SegParameters) GetTo() uint64 { + if m != nil { + return m.To } return 0 } type VideoProfile struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Name of VideoProfile Name string `protobuf:"bytes,16,opt,name=name,proto3" json:"name,omitempty"` // Width of VideoProfile @@ -1175,318 +1027,306 @@ type VideoProfile struct { // GOP interval Gop int32 `protobuf:"varint,24,opt,name=gop,proto3" json:"gop,omitempty"` // Encoder (video codec) - Encoder VideoProfile_VideoCodec `protobuf:"varint,25,opt,name=encoder,proto3,enum=net.VideoProfile_VideoCodec" json:"encoder,omitempty"` - ColorDepth int32 `protobuf:"varint,26,opt,name=colorDepth,proto3" json:"colorDepth,omitempty"` - ChromaFormat VideoProfile_ChromaSubsampling `protobuf:"varint,27,opt,name=chromaFormat,proto3,enum=net.VideoProfile_ChromaSubsampling" json:"chromaFormat,omitempty"` - Quality uint32 `protobuf:"varint,28,opt,name=quality,proto3" json:"quality,omitempty"` + Encoder VideoProfile_VideoCodec `protobuf:"varint,25,opt,name=encoder,proto3,enum=net.VideoProfile_VideoCodec" json:"encoder,omitempty"` + ColorDepth int32 `protobuf:"varint,26,opt,name=colorDepth,proto3" json:"colorDepth,omitempty"` + ChromaFormat VideoProfile_ChromaSubsampling `protobuf:"varint,27,opt,name=chromaFormat,proto3,enum=net.VideoProfile_ChromaSubsampling" json:"chromaFormat,omitempty"` + Quality uint32 `protobuf:"varint,28,opt,name=quality,proto3" json:"quality,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *VideoProfile) Reset() { *m = VideoProfile{} } +func (m *VideoProfile) String() string { return proto.CompactTextString(m) } +func (*VideoProfile) ProtoMessage() {} +func (*VideoProfile) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{12} } -func (x *VideoProfile) Reset() { - *x = VideoProfile{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *VideoProfile) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_VideoProfile.Unmarshal(m, b) } - -func (x *VideoProfile) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *VideoProfile) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_VideoProfile.Marshal(b, m, deterministic) } - -func (*VideoProfile) ProtoMessage() {} - -func (x *VideoProfile) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *VideoProfile) XXX_Merge(src proto.Message) { + xxx_messageInfo_VideoProfile.Merge(m, src) } - -// Deprecated: Use VideoProfile.ProtoReflect.Descriptor instead. -func (*VideoProfile) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{12} +func (m *VideoProfile) XXX_Size() int { + return xxx_messageInfo_VideoProfile.Size(m) +} +func (m *VideoProfile) XXX_DiscardUnknown() { + xxx_messageInfo_VideoProfile.DiscardUnknown(m) } -func (x *VideoProfile) GetName() string { - if x != nil { - return x.Name +var xxx_messageInfo_VideoProfile proto.InternalMessageInfo + +func (m *VideoProfile) GetName() string { + if m != nil { + return m.Name } return "" } -func (x *VideoProfile) GetWidth() int32 { - if x != nil { - return x.Width +func (m *VideoProfile) GetWidth() int32 { + if m != nil { + return m.Width } return 0 } -func (x *VideoProfile) GetHeight() int32 { - if x != nil { - return x.Height +func (m *VideoProfile) GetHeight() int32 { + if m != nil { + return m.Height } return 0 } -func (x *VideoProfile) GetBitrate() int32 { - if x != nil { - return x.Bitrate +func (m *VideoProfile) GetBitrate() int32 { + if m != nil { + return m.Bitrate } return 0 } -func (x *VideoProfile) GetFps() uint32 { - if x != nil { - return x.Fps +func (m *VideoProfile) GetFps() uint32 { + if m != nil { + return m.Fps } return 0 } -func (x *VideoProfile) GetFormat() VideoProfile_Format { - if x != nil { - return x.Format +func (m *VideoProfile) GetFormat() VideoProfile_Format { + if m != nil { + return m.Format } return VideoProfile_MPEGTS } -func (x *VideoProfile) GetFpsDen() uint32 { - if x != nil { - return x.FpsDen +func (m *VideoProfile) GetFpsDen() uint32 { + if m != nil { + return m.FpsDen } return 0 } -func (x *VideoProfile) GetProfile() VideoProfile_Profile { - if x != nil { - return x.Profile +func (m *VideoProfile) GetProfile() VideoProfile_Profile { + if m != nil { + return m.Profile } return VideoProfile_ENCODER_DEFAULT } -func (x *VideoProfile) GetGop() int32 { - if x != nil { - return x.Gop +func (m *VideoProfile) GetGop() int32 { + if m != nil { + return m.Gop } return 0 } -func (x *VideoProfile) GetEncoder() VideoProfile_VideoCodec { - if x != nil { - return x.Encoder +func (m *VideoProfile) GetEncoder() VideoProfile_VideoCodec { + if m != nil { + return m.Encoder } return VideoProfile_H264 } -func (x *VideoProfile) GetColorDepth() int32 { - if x != nil { - return x.ColorDepth +func (m *VideoProfile) GetColorDepth() int32 { + if m != nil { + return m.ColorDepth } return 0 } -func (x *VideoProfile) GetChromaFormat() VideoProfile_ChromaSubsampling { - if x != nil { - return x.ChromaFormat +func (m *VideoProfile) GetChromaFormat() VideoProfile_ChromaSubsampling { + if m != nil { + return m.ChromaFormat } return VideoProfile_CHROMA_420 } -func (x *VideoProfile) GetQuality() uint32 { - if x != nil { - return x.Quality +func (m *VideoProfile) GetQuality() uint32 { + if m != nil { + return m.Quality } return 0 } // Individual transcoded segment data. type TranscodedSegmentData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // URL where the transcoded data can be downloaded from. Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` // Amount of pixels processed (output pixels) Pixels int64 `protobuf:"varint,2,opt,name=pixels,proto3" json:"pixels,omitempty"` // URL where the perceptual hash data can be downloaded from (can be empty) - PerceptualHashUrl string `protobuf:"bytes,3,opt,name=perceptual_hash_url,json=perceptualHashUrl,proto3" json:"perceptual_hash_url,omitempty"` + PerceptualHashUrl string `protobuf:"bytes,3,opt,name=perceptual_hash_url,json=perceptualHashUrl,proto3" json:"perceptual_hash_url,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *TranscodedSegmentData) Reset() { - *x = TranscodedSegmentData{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *TranscodedSegmentData) Reset() { *m = TranscodedSegmentData{} } +func (m *TranscodedSegmentData) String() string { return proto.CompactTextString(m) } +func (*TranscodedSegmentData) ProtoMessage() {} +func (*TranscodedSegmentData) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{13} } -func (x *TranscodedSegmentData) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *TranscodedSegmentData) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TranscodedSegmentData.Unmarshal(m, b) } - -func (*TranscodedSegmentData) ProtoMessage() {} - -func (x *TranscodedSegmentData) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *TranscodedSegmentData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TranscodedSegmentData.Marshal(b, m, deterministic) } - -// Deprecated: Use TranscodedSegmentData.ProtoReflect.Descriptor instead. -func (*TranscodedSegmentData) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{13} +func (m *TranscodedSegmentData) XXX_Merge(src proto.Message) { + xxx_messageInfo_TranscodedSegmentData.Merge(m, src) +} +func (m *TranscodedSegmentData) XXX_Size() int { + return xxx_messageInfo_TranscodedSegmentData.Size(m) +} +func (m *TranscodedSegmentData) XXX_DiscardUnknown() { + xxx_messageInfo_TranscodedSegmentData.DiscardUnknown(m) } -func (x *TranscodedSegmentData) GetUrl() string { - if x != nil { - return x.Url +var xxx_messageInfo_TranscodedSegmentData proto.InternalMessageInfo + +func (m *TranscodedSegmentData) GetUrl() string { + if m != nil { + return m.Url } return "" } -func (x *TranscodedSegmentData) GetPixels() int64 { - if x != nil { - return x.Pixels +func (m *TranscodedSegmentData) GetPixels() int64 { + if m != nil { + return m.Pixels } return 0 } -func (x *TranscodedSegmentData) GetPerceptualHashUrl() string { - if x != nil { - return x.PerceptualHashUrl +func (m *TranscodedSegmentData) GetPerceptualHashUrl() string { + if m != nil { + return m.PerceptualHashUrl } return "" } // A set of transcoded segments following the profiles specified in the job. type TranscodeData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Transcoded data, in the order specified in the job options Segments []*TranscodedSegmentData `protobuf:"bytes,1,rep,name=segments,proto3" json:"segments,omitempty"` // Signature of the hash of the concatenated hashes - Sig []byte `protobuf:"bytes,2,opt,name=sig,proto3" json:"sig,omitempty"` + Sig []byte `protobuf:"bytes,2,opt,name=sig,proto3" json:"sig,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *TranscodeData) Reset() { - *x = TranscodeData{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *TranscodeData) Reset() { *m = TranscodeData{} } +func (m *TranscodeData) String() string { return proto.CompactTextString(m) } +func (*TranscodeData) ProtoMessage() {} +func (*TranscodeData) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{14} } -func (x *TranscodeData) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *TranscodeData) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TranscodeData.Unmarshal(m, b) } - -func (*TranscodeData) ProtoMessage() {} - -func (x *TranscodeData) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *TranscodeData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TranscodeData.Marshal(b, m, deterministic) } - -// Deprecated: Use TranscodeData.ProtoReflect.Descriptor instead. -func (*TranscodeData) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{14} +func (m *TranscodeData) XXX_Merge(src proto.Message) { + xxx_messageInfo_TranscodeData.Merge(m, src) +} +func (m *TranscodeData) XXX_Size() int { + return xxx_messageInfo_TranscodeData.Size(m) +} +func (m *TranscodeData) XXX_DiscardUnknown() { + xxx_messageInfo_TranscodeData.DiscardUnknown(m) } -func (x *TranscodeData) GetSegments() []*TranscodedSegmentData { - if x != nil { - return x.Segments +var xxx_messageInfo_TranscodeData proto.InternalMessageInfo + +func (m *TranscodeData) GetSegments() []*TranscodedSegmentData { + if m != nil { + return m.Segments } return nil } -func (x *TranscodeData) GetSig() []byte { - if x != nil { - return x.Sig +func (m *TranscodeData) GetSig() []byte { + if m != nil { + return m.Sig } return nil } // Response that a transcoder sends after transcoding a segment. type TranscodeResult struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Sequence number of the transcoded results. Seq int64 `protobuf:"varint,1,opt,name=seq,proto3" json:"seq,omitempty"` // Result of transcoding can be an error, or successful with more info // - // Types that are assignable to Result: + // Types that are valid to be assigned to Result: // // *TranscodeResult_Error // *TranscodeResult_Data Result isTranscodeResult_Result `protobuf_oneof:"result"` // Used to notify a broadcaster of updated orchestrator information - Info *OrchestratorInfo `protobuf:"bytes,16,opt,name=info,proto3" json:"info,omitempty"` + Info *OrchestratorInfo `protobuf:"bytes,16,opt,name=info,proto3" json:"info,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *TranscodeResult) Reset() { - *x = TranscodeResult{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *TranscodeResult) Reset() { *m = TranscodeResult{} } +func (m *TranscodeResult) String() string { return proto.CompactTextString(m) } +func (*TranscodeResult) ProtoMessage() {} +func (*TranscodeResult) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{15} } -func (x *TranscodeResult) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *TranscodeResult) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TranscodeResult.Unmarshal(m, b) +} +func (m *TranscodeResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TranscodeResult.Marshal(b, m, deterministic) +} +func (m *TranscodeResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_TranscodeResult.Merge(m, src) +} +func (m *TranscodeResult) XXX_Size() int { + return xxx_messageInfo_TranscodeResult.Size(m) +} +func (m *TranscodeResult) XXX_DiscardUnknown() { + xxx_messageInfo_TranscodeResult.DiscardUnknown(m) } -func (*TranscodeResult) ProtoMessage() {} +var xxx_messageInfo_TranscodeResult proto.InternalMessageInfo -func (x *TranscodeResult) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms +func (m *TranscodeResult) GetSeq() int64 { + if m != nil { + return m.Seq } - return mi.MessageOf(x) + return 0 } -// Deprecated: Use TranscodeResult.ProtoReflect.Descriptor instead. -func (*TranscodeResult) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{15} +type isTranscodeResult_Result interface { + isTranscodeResult_Result() } -func (x *TranscodeResult) GetSeq() int64 { - if x != nil { - return x.Seq - } - return 0 +type TranscodeResult_Error struct { + Error string `protobuf:"bytes,2,opt,name=error,proto3,oneof"` } +type TranscodeResult_Data struct { + Data *TranscodeData `protobuf:"bytes,3,opt,name=data,proto3,oneof"` +} + +func (*TranscodeResult_Error) isTranscodeResult_Result() {} + +func (*TranscodeResult_Data) isTranscodeResult_Result() {} + func (m *TranscodeResult) GetResult() isTranscodeResult_Result { if m != nil { return m.Result @@ -1494,116 +1334,96 @@ func (m *TranscodeResult) GetResult() isTranscodeResult_Result { return nil } -func (x *TranscodeResult) GetError() string { - if x, ok := x.GetResult().(*TranscodeResult_Error); ok { +func (m *TranscodeResult) GetError() string { + if x, ok := m.GetResult().(*TranscodeResult_Error); ok { return x.Error } return "" } -func (x *TranscodeResult) GetData() *TranscodeData { - if x, ok := x.GetResult().(*TranscodeResult_Data); ok { +func (m *TranscodeResult) GetData() *TranscodeData { + if x, ok := m.GetResult().(*TranscodeResult_Data); ok { return x.Data } return nil } -func (x *TranscodeResult) GetInfo() *OrchestratorInfo { - if x != nil { - return x.Info +func (m *TranscodeResult) GetInfo() *OrchestratorInfo { + if m != nil { + return m.Info } return nil } -type isTranscodeResult_Result interface { - isTranscodeResult_Result() -} - -type TranscodeResult_Error struct { - Error string `protobuf:"bytes,2,opt,name=error,proto3,oneof"` -} - -type TranscodeResult_Data struct { - Data *TranscodeData `protobuf:"bytes,3,opt,name=data,proto3,oneof"` +// XXX_OneofWrappers is for the internal use of the proto package. +func (*TranscodeResult) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*TranscodeResult_Error)(nil), + (*TranscodeResult_Data)(nil), + } } -func (*TranscodeResult_Error) isTranscodeResult_Result() {} - -func (*TranscodeResult_Data) isTranscodeResult_Result() {} - // Sent by the transcoder to register itself to the orchestrator. type RegisterRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Shared secret for auth Secret string `protobuf:"bytes,1,opt,name=secret,proto3" json:"secret,omitempty"` // Transcoder capacity Capacity int64 `protobuf:"varint,2,opt,name=capacity,proto3" json:"capacity,omitempty"` // Transcoder capabilities - Capabilities *Capabilities `protobuf:"bytes,3,opt,name=capabilities,proto3" json:"capabilities,omitempty"` + Capabilities *Capabilities `protobuf:"bytes,3,opt,name=capabilities,proto3" json:"capabilities,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *RegisterRequest) Reset() { - *x = RegisterRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *RegisterRequest) Reset() { *m = RegisterRequest{} } +func (m *RegisterRequest) String() string { return proto.CompactTextString(m) } +func (*RegisterRequest) ProtoMessage() {} +func (*RegisterRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{16} } -func (x *RegisterRequest) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *RegisterRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RegisterRequest.Unmarshal(m, b) } - -func (*RegisterRequest) ProtoMessage() {} - -func (x *RegisterRequest) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *RegisterRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RegisterRequest.Marshal(b, m, deterministic) } - -// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead. -func (*RegisterRequest) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{16} +func (m *RegisterRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RegisterRequest.Merge(m, src) +} +func (m *RegisterRequest) XXX_Size() int { + return xxx_messageInfo_RegisterRequest.Size(m) +} +func (m *RegisterRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RegisterRequest.DiscardUnknown(m) } -func (x *RegisterRequest) GetSecret() string { - if x != nil { - return x.Secret +var xxx_messageInfo_RegisterRequest proto.InternalMessageInfo + +func (m *RegisterRequest) GetSecret() string { + if m != nil { + return m.Secret } return "" } -func (x *RegisterRequest) GetCapacity() int64 { - if x != nil { - return x.Capacity +func (m *RegisterRequest) GetCapacity() int64 { + if m != nil { + return m.Capacity } return 0 } -func (x *RegisterRequest) GetCapabilities() *Capabilities { - if x != nil { - return x.Capabilities +func (m *RegisterRequest) GetCapabilities() *Capabilities { + if m != nil { + return m.Capabilities } return nil } // Sent by the orchestrator to the transcoder type NotifySegment struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // URL of the segment to transcode. Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` // Configuration for the transcoding job @@ -1612,75 +1432,67 @@ type NotifySegment struct { TaskId int64 `protobuf:"varint,16,opt,name=taskId,proto3" json:"taskId,omitempty"` // Deprecated by fullProfiles. Set of presets to transcode into. // Should be set to an invalid value to induce failures - Profiles []byte `protobuf:"bytes,17,opt,name=profiles,proto3" json:"profiles,omitempty"` + Profiles []byte `protobuf:"bytes,17,opt,name=profiles,proto3" json:"profiles,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *NotifySegment) Reset() { - *x = NotifySegment{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *NotifySegment) Reset() { *m = NotifySegment{} } +func (m *NotifySegment) String() string { return proto.CompactTextString(m) } +func (*NotifySegment) ProtoMessage() {} +func (*NotifySegment) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{17} } -func (x *NotifySegment) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *NotifySegment) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NotifySegment.Unmarshal(m, b) } - -func (*NotifySegment) ProtoMessage() {} - -func (x *NotifySegment) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *NotifySegment) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NotifySegment.Marshal(b, m, deterministic) } - -// Deprecated: Use NotifySegment.ProtoReflect.Descriptor instead. -func (*NotifySegment) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{17} +func (m *NotifySegment) XXX_Merge(src proto.Message) { + xxx_messageInfo_NotifySegment.Merge(m, src) +} +func (m *NotifySegment) XXX_Size() int { + return xxx_messageInfo_NotifySegment.Size(m) +} +func (m *NotifySegment) XXX_DiscardUnknown() { + xxx_messageInfo_NotifySegment.DiscardUnknown(m) } -func (x *NotifySegment) GetUrl() string { - if x != nil { - return x.Url +var xxx_messageInfo_NotifySegment proto.InternalMessageInfo + +func (m *NotifySegment) GetUrl() string { + if m != nil { + return m.Url } return "" } -func (x *NotifySegment) GetSegData() *SegData { - if x != nil { - return x.SegData +func (m *NotifySegment) GetSegData() *SegData { + if m != nil { + return m.SegData } return nil } -func (x *NotifySegment) GetTaskId() int64 { - if x != nil { - return x.TaskId +func (m *NotifySegment) GetTaskId() int64 { + if m != nil { + return m.TaskId } return 0 } -func (x *NotifySegment) GetProfiles() []byte { - if x != nil { - return x.Profiles +func (m *NotifySegment) GetProfiles() []byte { + if m != nil { + return m.Profiles } return nil } // Required parameters for probabilistic micropayment tickets type TicketParams struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // ETH address of the recipient Recipient []byte `protobuf:"bytes,1,opt,name=recipient,proto3" json:"recipient,omitempty"` // Pay out (in Wei) to the recipient if the ticket wins @@ -1696,203 +1508,183 @@ type TicketParams struct { // Block number at which the current set of advertised TicketParams is no longer valid ExpirationBlock []byte `protobuf:"bytes,6,opt,name=expiration_block,json=expirationBlock,proto3" json:"expiration_block,omitempty"` // Expected ticket expiration params - ExpirationParams *TicketExpirationParams `protobuf:"bytes,7,opt,name=expiration_params,json=expirationParams,proto3" json:"expiration_params,omitempty"` + ExpirationParams *TicketExpirationParams `protobuf:"bytes,7,opt,name=expiration_params,json=expirationParams,proto3" json:"expiration_params,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *TicketParams) Reset() { - *x = TicketParams{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *TicketParams) Reset() { *m = TicketParams{} } +func (m *TicketParams) String() string { return proto.CompactTextString(m) } +func (*TicketParams) ProtoMessage() {} +func (*TicketParams) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{18} } -func (x *TicketParams) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *TicketParams) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TicketParams.Unmarshal(m, b) } - -func (*TicketParams) ProtoMessage() {} - -func (x *TicketParams) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *TicketParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TicketParams.Marshal(b, m, deterministic) } - -// Deprecated: Use TicketParams.ProtoReflect.Descriptor instead. -func (*TicketParams) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{18} +func (m *TicketParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_TicketParams.Merge(m, src) +} +func (m *TicketParams) XXX_Size() int { + return xxx_messageInfo_TicketParams.Size(m) } +func (m *TicketParams) XXX_DiscardUnknown() { + xxx_messageInfo_TicketParams.DiscardUnknown(m) +} + +var xxx_messageInfo_TicketParams proto.InternalMessageInfo -func (x *TicketParams) GetRecipient() []byte { - if x != nil { - return x.Recipient +func (m *TicketParams) GetRecipient() []byte { + if m != nil { + return m.Recipient } return nil } -func (x *TicketParams) GetFaceValue() []byte { - if x != nil { - return x.FaceValue +func (m *TicketParams) GetFaceValue() []byte { + if m != nil { + return m.FaceValue } return nil } -func (x *TicketParams) GetWinProb() []byte { - if x != nil { - return x.WinProb +func (m *TicketParams) GetWinProb() []byte { + if m != nil { + return m.WinProb } return nil } -func (x *TicketParams) GetRecipientRandHash() []byte { - if x != nil { - return x.RecipientRandHash +func (m *TicketParams) GetRecipientRandHash() []byte { + if m != nil { + return m.RecipientRandHash } return nil } -func (x *TicketParams) GetSeed() []byte { - if x != nil { - return x.Seed +func (m *TicketParams) GetSeed() []byte { + if m != nil { + return m.Seed } return nil } -func (x *TicketParams) GetExpirationBlock() []byte { - if x != nil { - return x.ExpirationBlock +func (m *TicketParams) GetExpirationBlock() []byte { + if m != nil { + return m.ExpirationBlock } return nil } -func (x *TicketParams) GetExpirationParams() *TicketExpirationParams { - if x != nil { - return x.ExpirationParams +func (m *TicketParams) GetExpirationParams() *TicketExpirationParams { + if m != nil { + return m.ExpirationParams } return nil } // Sender Params (nonces and signatures) type TicketSenderParams struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Monotonically increasing counter that makes the ticket // unique relative to a particular hash commitment to a recipient's random number SenderNonce uint32 `protobuf:"varint,1,opt,name=sender_nonce,json=senderNonce,proto3" json:"sender_nonce,omitempty"` // Sender signature over the ticket - Sig []byte `protobuf:"bytes,2,opt,name=sig,proto3" json:"sig,omitempty"` + Sig []byte `protobuf:"bytes,2,opt,name=sig,proto3" json:"sig,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *TicketSenderParams) Reset() { - *x = TicketSenderParams{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *TicketSenderParams) Reset() { *m = TicketSenderParams{} } +func (m *TicketSenderParams) String() string { return proto.CompactTextString(m) } +func (*TicketSenderParams) ProtoMessage() {} +func (*TicketSenderParams) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{19} } -func (x *TicketSenderParams) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *TicketSenderParams) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TicketSenderParams.Unmarshal(m, b) } - -func (*TicketSenderParams) ProtoMessage() {} - -func (x *TicketSenderParams) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *TicketSenderParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TicketSenderParams.Marshal(b, m, deterministic) } - -// Deprecated: Use TicketSenderParams.ProtoReflect.Descriptor instead. -func (*TicketSenderParams) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{19} +func (m *TicketSenderParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_TicketSenderParams.Merge(m, src) +} +func (m *TicketSenderParams) XXX_Size() int { + return xxx_messageInfo_TicketSenderParams.Size(m) } +func (m *TicketSenderParams) XXX_DiscardUnknown() { + xxx_messageInfo_TicketSenderParams.DiscardUnknown(m) +} + +var xxx_messageInfo_TicketSenderParams proto.InternalMessageInfo -func (x *TicketSenderParams) GetSenderNonce() uint32 { - if x != nil { - return x.SenderNonce +func (m *TicketSenderParams) GetSenderNonce() uint32 { + if m != nil { + return m.SenderNonce } return 0 } -func (x *TicketSenderParams) GetSig() []byte { - if x != nil { - return x.Sig +func (m *TicketSenderParams) GetSig() []byte { + if m != nil { + return m.Sig } return nil } // Ticket params for expiration related validation type TicketExpirationParams struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Round during which tickets are created CreationRound int64 `protobuf:"varint,1,opt,name=creation_round,json=creationRound,proto3" json:"creation_round,omitempty"` // Block hash associated with creation_round - CreationRoundBlockHash []byte `protobuf:"bytes,2,opt,name=creation_round_block_hash,json=creationRoundBlockHash,proto3" json:"creation_round_block_hash,omitempty"` + CreationRoundBlockHash []byte `protobuf:"bytes,2,opt,name=creation_round_block_hash,json=creationRoundBlockHash,proto3" json:"creation_round_block_hash,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *TicketExpirationParams) Reset() { - *x = TicketExpirationParams{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *TicketExpirationParams) Reset() { *m = TicketExpirationParams{} } +func (m *TicketExpirationParams) String() string { return proto.CompactTextString(m) } +func (*TicketExpirationParams) ProtoMessage() {} +func (*TicketExpirationParams) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{20} } -func (x *TicketExpirationParams) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *TicketExpirationParams) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TicketExpirationParams.Unmarshal(m, b) } - -func (*TicketExpirationParams) ProtoMessage() {} - -func (x *TicketExpirationParams) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *TicketExpirationParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TicketExpirationParams.Marshal(b, m, deterministic) } - -// Deprecated: Use TicketExpirationParams.ProtoReflect.Descriptor instead. -func (*TicketExpirationParams) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{20} +func (m *TicketExpirationParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_TicketExpirationParams.Merge(m, src) +} +func (m *TicketExpirationParams) XXX_Size() int { + return xxx_messageInfo_TicketExpirationParams.Size(m) +} +func (m *TicketExpirationParams) XXX_DiscardUnknown() { + xxx_messageInfo_TicketExpirationParams.DiscardUnknown(m) } -func (x *TicketExpirationParams) GetCreationRound() int64 { - if x != nil { - return x.CreationRound +var xxx_messageInfo_TicketExpirationParams proto.InternalMessageInfo + +func (m *TicketExpirationParams) GetCreationRound() int64 { + if m != nil { + return m.CreationRound } return 0 } -func (x *TicketExpirationParams) GetCreationRoundBlockHash() []byte { - if x != nil { - return x.CreationRoundBlockHash +func (m *TicketExpirationParams) GetCreationRoundBlockHash() []byte { + if m != nil { + return m.CreationRoundBlockHash } return nil } @@ -1901,10 +1693,6 @@ func (x *TicketExpirationParams) GetCreationRoundBlockHash() []byte { // A payment can constitute of multiple tickets // A broadcaster might need to send multiple tickets to top up his credit with an Orchestrator type Payment struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - // Probabilistic micropayment ticket parameters // These remain the same even when sending multiple tickets TicketParams *TicketParams `protobuf:"bytes,1,opt,name=ticket_params,json=ticketParams,proto3" json:"ticket_params,omitempty"` @@ -1914,792 +1702,228 @@ type Payment struct { ExpirationParams *TicketExpirationParams `protobuf:"bytes,3,opt,name=expiration_params,json=expirationParams,proto3" json:"expiration_params,omitempty"` TicketSenderParams []*TicketSenderParams `protobuf:"bytes,4,rep,name=ticket_sender_params,json=ticketSenderParams,proto3" json:"ticket_sender_params,omitempty"` // O's last known price - ExpectedPrice *PriceInfo `protobuf:"bytes,5,opt,name=expected_price,json=expectedPrice,proto3" json:"expected_price,omitempty"` + ExpectedPrice *PriceInfo `protobuf:"bytes,5,opt,name=expected_price,json=expectedPrice,proto3" json:"expected_price,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (x *Payment) Reset() { - *x = Payment{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (m *Payment) Reset() { *m = Payment{} } +func (m *Payment) String() string { return proto.CompactTextString(m) } +func (*Payment) ProtoMessage() {} +func (*Payment) Descriptor() ([]byte, []int) { + return fileDescriptor_034e29c79f9ba827, []int{21} } -func (x *Payment) String() string { - return protoimpl.X.MessageStringOf(x) +func (m *Payment) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Payment.Unmarshal(m, b) } - -func (*Payment) ProtoMessage() {} - -func (x *Payment) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) +func (m *Payment) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Payment.Marshal(b, m, deterministic) } - -// Deprecated: Use Payment.ProtoReflect.Descriptor instead. -func (*Payment) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{21} +func (m *Payment) XXX_Merge(src proto.Message) { + xxx_messageInfo_Payment.Merge(m, src) } - -func (x *Payment) GetTicketParams() *TicketParams { - if x != nil { - return x.TicketParams - } - return nil +func (m *Payment) XXX_Size() int { + return xxx_messageInfo_Payment.Size(m) } - -func (x *Payment) GetSender() []byte { - if x != nil { - return x.Sender - } - return nil +func (m *Payment) XXX_DiscardUnknown() { + xxx_messageInfo_Payment.DiscardUnknown(m) } -func (x *Payment) GetExpirationParams() *TicketExpirationParams { - if x != nil { - return x.ExpirationParams +var xxx_messageInfo_Payment proto.InternalMessageInfo + +func (m *Payment) GetTicketParams() *TicketParams { + if m != nil { + return m.TicketParams } return nil } -func (x *Payment) GetTicketSenderParams() []*TicketSenderParams { - if x != nil { - return x.TicketSenderParams +func (m *Payment) GetSender() []byte { + if m != nil { + return m.Sender } return nil } -func (x *Payment) GetExpectedPrice() *PriceInfo { - if x != nil { - return x.ExpectedPrice +func (m *Payment) GetExpirationParams() *TicketExpirationParams { + if m != nil { + return m.ExpirationParams } return nil } -// Non-binary capability constraints, such as supported ranges. -type Capabilities_Constraints struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *Capabilities_Constraints) Reset() { - *x = Capabilities_Constraints{} - if protoimpl.UnsafeEnabled { - mi := &file_net_lp_rpc_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) +func (m *Payment) GetTicketSenderParams() []*TicketSenderParams { + if m != nil { + return m.TicketSenderParams } + return nil } -func (x *Capabilities_Constraints) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Capabilities_Constraints) ProtoMessage() {} - -func (x *Capabilities_Constraints) ProtoReflect() protoreflect.Message { - mi := &file_net_lp_rpc_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms +func (m *Payment) GetExpectedPrice() *PriceInfo { + if m != nil { + return m.ExpectedPrice } - return mi.MessageOf(x) + return nil } -// Deprecated: Use Capabilities_Constraints.ProtoReflect.Descriptor instead. -func (*Capabilities_Constraints) Descriptor() ([]byte, []int) { - return file_net_lp_rpc_proto_rawDescGZIP(), []int{7, 1} -} - -var File_net_lp_rpc_proto protoreflect.FileDescriptor - -var file_net_lp_rpc_proto_rawDesc = []byte{ - 0x0a, 0x10, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x70, 0x5f, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x03, 0x6e, 0x65, 0x74, 0x22, 0x20, 0x0a, 0x08, 0x50, 0x69, 0x6e, 0x67, 0x50, - 0x6f, 0x6e, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4d, 0x0a, 0x1c, 0x45, 0x6e, 0x64, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x0a, 0x61, 0x75, 0x74, - 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, - 0x6e, 0x65, 0x74, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x09, 0x61, - 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x1f, 0x0a, 0x1d, 0x45, 0x6e, 0x64, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x13, 0x4f, 0x72, 0x63, - 0x68, 0x65, 0x73, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, - 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x22, 0x99, 0x01, 0x0a, - 0x06, 0x4f, 0x53, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x39, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x6e, - 0x65, 0x74, 0x2e, 0x4f, 0x53, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x25, 0x0a, 0x06, 0x73, 0x33, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x10, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x33, 0x4f, 0x53, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x06, 0x73, 0x33, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x2d, 0x0a, 0x0b, 0x53, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x49, 0x52, 0x45, - 0x43, 0x54, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x53, 0x33, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, - 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x10, 0x02, 0x22, 0xa2, 0x01, 0x0a, 0x08, 0x53, 0x33, 0x4f, - 0x53, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x78, 0x41, 0x6d, 0x7a, 0x44, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x78, 0x41, 0x6d, 0x7a, 0x44, 0x61, 0x74, 0x65, 0x22, 0x55, 0x0a, - 0x09, 0x50, 0x72, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, - 0x69, 0x63, 0x65, 0x50, 0x65, 0x72, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0c, 0x70, 0x72, 0x69, 0x63, 0x65, 0x50, 0x65, 0x72, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x24, - 0x0a, 0x0d, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x50, 0x65, 0x72, 0x55, 0x6e, 0x69, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x50, 0x65, 0x72, - 0x55, 0x6e, 0x69, 0x74, 0x22, 0xdf, 0x01, 0x0a, 0x0c, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, - 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x69, 0x74, 0x73, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x62, 0x69, 0x74, 0x73, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x6e, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x69, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x6e, 0x64, 0x61, 0x74, - 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, - 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6e, 0x65, 0x74, 0x2e, - 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x2e, 0x43, 0x61, 0x70, - 0x61, 0x63, 0x69, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x63, 0x61, - 0x70, 0x61, 0x63, 0x69, 0x74, 0x69, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x43, 0x61, 0x70, 0x61, - 0x63, 0x69, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x0d, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x73, 0x74, - 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73, 0x22, 0xc0, 0x02, 0x0a, 0x10, 0x4f, 0x72, 0x63, 0x68, 0x65, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x0d, 0x74, - 0x69, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x0c, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x73, 0x12, 0x2d, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, - 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, - 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x70, 0x72, 0x69, 0x63, 0x65, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x35, 0x0a, 0x0c, - 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, - 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x69, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x41, 0x75, - 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x12, 0x25, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x20, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4f, 0x53, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x22, 0x60, 0x0a, 0x09, 0x41, 0x75, 0x74, - 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, - 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xf4, 0x04, 0x0a, 0x07, - 0x53, 0x65, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x6e, 0x69, 0x66, - 0x65, 0x73, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x61, 0x6e, - 0x69, 0x66, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x65, 0x71, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x73, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, - 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1a, 0x0a, - 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x64, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x6e, 0x65, 0x74, 0x2e, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, - 0x52, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x2d, - 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x30, 0x0a, - 0x14, 0x63, 0x61, 0x6c, 0x63, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x75, 0x61, 0x6c, - 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x63, 0x61, 0x6c, - 0x63, 0x50, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x75, 0x61, 0x6c, 0x48, 0x61, 0x73, 0x68, 0x12, - 0x25, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x20, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x0b, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4f, 0x53, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x0c, 0x66, 0x75, 0x6c, 0x6c, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x21, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6e, - 0x65, 0x74, 0x2e, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, - 0x0c, 0x66, 0x75, 0x6c, 0x6c, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x37, 0x0a, - 0x0d, 0x66, 0x75, 0x6c, 0x6c, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x32, 0x18, 0x22, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x56, 0x69, 0x64, 0x65, 0x6f, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x0d, 0x66, 0x75, 0x6c, 0x6c, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x32, 0x12, 0x37, 0x0a, 0x0d, 0x66, 0x75, 0x6c, 0x6c, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x33, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x6e, 0x65, 0x74, 0x2e, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x52, 0x0d, 0x66, 0x75, 0x6c, 0x6c, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x33, 0x12, - 0x41, 0x0a, 0x12, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x25, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6e, 0x65, - 0x74, 0x2e, 0x53, 0x65, 0x67, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, - 0x11, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x69, 0x6e, 0x69, 0x74, 0x18, 0x26, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, - 0x46, 0x6f, 0x72, 0x63, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x69, 0x6e, - 0x69, 0x74, 0x22, 0x33, 0x0a, 0x0d, 0x53, 0x65, 0x67, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x02, 0x74, 0x6f, 0x22, 0xcc, 0x05, 0x0a, 0x0c, 0x56, 0x69, 0x64, 0x65, - 0x6f, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, 0x64, - 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x12, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x69, - 0x74, 0x72, 0x61, 0x74, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x69, 0x74, - 0x72, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x70, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x03, 0x66, 0x70, 0x73, 0x12, 0x30, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, - 0x18, 0x15, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x56, 0x69, 0x64, - 0x65, 0x6f, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, - 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x70, 0x73, 0x44, - 0x65, 0x6e, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x66, 0x70, 0x73, 0x44, 0x65, 0x6e, - 0x12, 0x33, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x19, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x07, 0x70, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x6f, 0x70, 0x18, 0x18, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x03, 0x67, 0x6f, 0x70, 0x12, 0x36, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, - 0x65, 0x72, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x56, - 0x69, 0x64, 0x65, 0x6f, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x56, 0x69, 0x64, 0x65, - 0x6f, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, - 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x44, 0x65, 0x70, 0x74, 0x68, 0x18, 0x1a, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x44, 0x65, 0x70, 0x74, 0x68, 0x12, - 0x47, 0x0a, 0x0c, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, - 0x1b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x56, 0x69, 0x64, 0x65, - 0x6f, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x43, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x53, - 0x75, 0x62, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x63, 0x68, 0x72, 0x6f, - 0x6d, 0x61, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x71, 0x75, 0x61, 0x6c, - 0x69, 0x74, 0x79, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x71, 0x75, 0x61, 0x6c, 0x69, - 0x74, 0x79, 0x22, 0x1d, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x0a, 0x0a, 0x06, - 0x4d, 0x50, 0x45, 0x47, 0x54, 0x53, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x50, 0x34, 0x10, - 0x01, 0x22, 0x6a, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x13, 0x0a, 0x0f, - 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x45, 0x52, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, - 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x48, 0x32, 0x36, 0x34, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x4c, 0x49, - 0x4e, 0x45, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x32, 0x36, 0x34, 0x5f, 0x4d, 0x41, 0x49, - 0x4e, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x32, 0x36, 0x34, 0x5f, 0x48, 0x49, 0x47, 0x48, - 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x48, 0x32, 0x36, 0x34, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x54, - 0x52, 0x41, 0x49, 0x4e, 0x45, 0x44, 0x5f, 0x48, 0x49, 0x47, 0x48, 0x10, 0x04, 0x22, 0x32, 0x0a, - 0x0a, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x12, 0x08, 0x0a, 0x04, 0x48, - 0x32, 0x36, 0x34, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x32, 0x36, 0x35, 0x10, 0x01, 0x12, - 0x07, 0x0a, 0x03, 0x56, 0x50, 0x38, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x56, 0x50, 0x39, 0x10, - 0x03, 0x22, 0x43, 0x0a, 0x11, 0x43, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x53, 0x75, 0x62, 0x73, 0x61, - 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x48, 0x52, 0x4f, 0x4d, 0x41, - 0x5f, 0x34, 0x32, 0x30, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x48, 0x52, 0x4f, 0x4d, 0x41, - 0x5f, 0x34, 0x32, 0x32, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x48, 0x52, 0x4f, 0x4d, 0x41, - 0x5f, 0x34, 0x34, 0x34, 0x10, 0x02, 0x22, 0x71, 0x0a, 0x15, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, - 0x6f, 0x64, 0x65, 0x64, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, - 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, - 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x06, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x65, 0x72, - 0x63, 0x65, 0x70, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x75, 0x72, 0x6c, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x75, - 0x61, 0x6c, 0x48, 0x61, 0x73, 0x68, 0x55, 0x72, 0x6c, 0x22, 0x59, 0x0a, 0x0d, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x36, 0x0a, 0x08, 0x73, 0x65, - 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6e, - 0x65, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x53, 0x65, 0x67, - 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x03, 0x73, 0x69, 0x67, 0x22, 0x9a, 0x01, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, - 0x64, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x65, 0x71, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x73, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x12, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x65, - 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x29, 0x0a, 0x04, - 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6e, 0x65, 0x74, - 0x2e, 0x4f, 0x72, 0x63, 0x68, 0x65, 0x73, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x22, 0x7c, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, - 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, - 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x35, 0x0a, 0x0c, 0x63, 0x61, 0x70, 0x61, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, - 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, - 0x73, 0x52, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, - 0x89, 0x01, 0x0a, 0x0d, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, - 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x75, 0x72, 0x6c, 0x12, 0x26, 0x0a, 0x07, 0x73, 0x65, 0x67, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x65, 0x67, 0x44, 0x61, - 0x74, 0x61, 0x52, 0x07, 0x73, 0x65, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x74, - 0x61, 0x73, 0x6b, 0x49, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, - 0x6b, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, - 0x11, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4a, - 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x21, 0x10, 0x22, 0x22, 0x9f, 0x02, 0x0a, 0x0c, - 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1c, 0x0a, 0x09, - 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x61, - 0x63, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, - 0x66, 0x61, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x77, 0x69, 0x6e, - 0x5f, 0x70, 0x72, 0x6f, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x77, 0x69, 0x6e, - 0x50, 0x72, 0x6f, 0x62, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, - 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x11, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x61, 0x6e, 0x64, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x04, 0x73, 0x65, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x70, 0x69, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x12, 0x48, 0x0a, 0x11, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x45, 0x78, 0x70, 0x69, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x10, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x49, 0x0a, - 0x12, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x6e, 0x6f, - 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x73, 0x65, 0x6e, 0x64, 0x65, - 0x72, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x22, 0x7a, 0x0a, 0x16, 0x54, 0x69, 0x63, 0x6b, - 0x65, 0x74, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, - 0x6d, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, - 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x16, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x48, 0x61, 0x73, 0x68, 0x22, 0xa5, 0x02, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x12, 0x36, 0x0a, 0x0d, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x54, 0x69, - 0x63, 0x6b, 0x65, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x0c, 0x74, 0x69, 0x63, 0x6b, - 0x65, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, - 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, - 0x12, 0x48, 0x0a, 0x11, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6e, 0x65, - 0x74, 0x2e, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x10, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x49, 0x0a, 0x14, 0x74, 0x69, - 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x54, - 0x69, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x52, 0x12, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x35, 0x0a, 0x0e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, - 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x65, - 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x72, 0x69, 0x63, 0x65, 0x32, 0xd8, 0x01, 0x0a, - 0x0c, 0x4f, 0x72, 0x63, 0x68, 0x65, 0x73, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x42, 0x0a, - 0x0f, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x63, 0x68, 0x65, 0x73, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x72, - 0x12, 0x18, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4f, 0x72, 0x63, 0x68, 0x65, 0x73, 0x74, 0x72, 0x61, - 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x6e, 0x65, 0x74, - 0x2e, 0x4f, 0x72, 0x63, 0x68, 0x65, 0x73, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x5e, 0x0a, 0x15, 0x45, 0x6e, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, - 0x69, 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x2e, 0x6e, 0x65, 0x74, - 0x2e, 0x45, 0x6e, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, - 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, - 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x24, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x0d, 0x2e, 0x6e, 0x65, 0x74, 0x2e, - 0x50, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6e, 0x67, 0x1a, 0x0d, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, - 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6e, 0x67, 0x32, 0x4e, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x40, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x14, 0x2e, 0x6e, 0x65, - 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x12, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x65, - 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x2f, 0x6e, 0x65, 0x74, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_net_lp_rpc_proto_rawDescOnce sync.Once - file_net_lp_rpc_proto_rawDescData = file_net_lp_rpc_proto_rawDesc -) - -func file_net_lp_rpc_proto_rawDescGZIP() []byte { - file_net_lp_rpc_proto_rawDescOnce.Do(func() { - file_net_lp_rpc_proto_rawDescData = protoimpl.X.CompressGZIP(file_net_lp_rpc_proto_rawDescData) - }) - return file_net_lp_rpc_proto_rawDescData -} - -var file_net_lp_rpc_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_net_lp_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 24) -var file_net_lp_rpc_proto_goTypes = []interface{}{ - (OSInfo_StorageType)(0), // 0: net.OSInfo.StorageType - (VideoProfile_Format)(0), // 1: net.VideoProfile.Format - (VideoProfile_Profile)(0), // 2: net.VideoProfile.Profile - (VideoProfile_VideoCodec)(0), // 3: net.VideoProfile.VideoCodec - (VideoProfile_ChromaSubsampling)(0), // 4: net.VideoProfile.ChromaSubsampling - (*PingPong)(nil), // 5: net.PingPong - (*EndTranscodingSessionRequest)(nil), // 6: net.EndTranscodingSessionRequest - (*EndTranscodingSessionResponse)(nil), // 7: net.EndTranscodingSessionResponse - (*OrchestratorRequest)(nil), // 8: net.OrchestratorRequest - (*OSInfo)(nil), // 9: net.OSInfo - (*S3OSInfo)(nil), // 10: net.S3OSInfo - (*PriceInfo)(nil), // 11: net.PriceInfo - (*Capabilities)(nil), // 12: net.Capabilities - (*OrchestratorInfo)(nil), // 13: net.OrchestratorInfo - (*AuthToken)(nil), // 14: net.AuthToken - (*SegData)(nil), // 15: net.SegData - (*SegParameters)(nil), // 16: net.SegParameters - (*VideoProfile)(nil), // 17: net.VideoProfile - (*TranscodedSegmentData)(nil), // 18: net.TranscodedSegmentData - (*TranscodeData)(nil), // 19: net.TranscodeData - (*TranscodeResult)(nil), // 20: net.TranscodeResult - (*RegisterRequest)(nil), // 21: net.RegisterRequest - (*NotifySegment)(nil), // 22: net.NotifySegment - (*TicketParams)(nil), // 23: net.TicketParams - (*TicketSenderParams)(nil), // 24: net.TicketSenderParams - (*TicketExpirationParams)(nil), // 25: net.TicketExpirationParams - (*Payment)(nil), // 26: net.Payment - nil, // 27: net.Capabilities.CapacitiesEntry - (*Capabilities_Constraints)(nil), // 28: net.Capabilities.Constraints -} -var file_net_lp_rpc_proto_depIdxs = []int32{ - 14, // 0: net.EndTranscodingSessionRequest.auth_token:type_name -> net.AuthToken - 0, // 1: net.OSInfo.storageType:type_name -> net.OSInfo.StorageType - 10, // 2: net.OSInfo.s3info:type_name -> net.S3OSInfo - 27, // 3: net.Capabilities.capacities:type_name -> net.Capabilities.CapacitiesEntry - 23, // 4: net.OrchestratorInfo.ticket_params:type_name -> net.TicketParams - 11, // 5: net.OrchestratorInfo.price_info:type_name -> net.PriceInfo - 12, // 6: net.OrchestratorInfo.capabilities:type_name -> net.Capabilities - 14, // 7: net.OrchestratorInfo.auth_token:type_name -> net.AuthToken - 9, // 8: net.OrchestratorInfo.storage:type_name -> net.OSInfo - 12, // 9: net.SegData.capabilities:type_name -> net.Capabilities - 14, // 10: net.SegData.auth_token:type_name -> net.AuthToken - 9, // 11: net.SegData.storage:type_name -> net.OSInfo - 17, // 12: net.SegData.fullProfiles:type_name -> net.VideoProfile - 17, // 13: net.SegData.fullProfiles2:type_name -> net.VideoProfile - 17, // 14: net.SegData.fullProfiles3:type_name -> net.VideoProfile - 16, // 15: net.SegData.segment_parameters:type_name -> net.SegParameters - 1, // 16: net.VideoProfile.format:type_name -> net.VideoProfile.Format - 2, // 17: net.VideoProfile.profile:type_name -> net.VideoProfile.Profile - 3, // 18: net.VideoProfile.encoder:type_name -> net.VideoProfile.VideoCodec - 4, // 19: net.VideoProfile.chromaFormat:type_name -> net.VideoProfile.ChromaSubsampling - 18, // 20: net.TranscodeData.segments:type_name -> net.TranscodedSegmentData - 19, // 21: net.TranscodeResult.data:type_name -> net.TranscodeData - 13, // 22: net.TranscodeResult.info:type_name -> net.OrchestratorInfo - 12, // 23: net.RegisterRequest.capabilities:type_name -> net.Capabilities - 15, // 24: net.NotifySegment.segData:type_name -> net.SegData - 25, // 25: net.TicketParams.expiration_params:type_name -> net.TicketExpirationParams - 23, // 26: net.Payment.ticket_params:type_name -> net.TicketParams - 25, // 27: net.Payment.expiration_params:type_name -> net.TicketExpirationParams - 24, // 28: net.Payment.ticket_sender_params:type_name -> net.TicketSenderParams - 11, // 29: net.Payment.expected_price:type_name -> net.PriceInfo - 8, // 30: net.Orchestrator.GetOrchestrator:input_type -> net.OrchestratorRequest - 6, // 31: net.Orchestrator.EndTranscodingSession:input_type -> net.EndTranscodingSessionRequest - 5, // 32: net.Orchestrator.Ping:input_type -> net.PingPong - 21, // 33: net.Transcoder.RegisterTranscoder:input_type -> net.RegisterRequest - 13, // 34: net.Orchestrator.GetOrchestrator:output_type -> net.OrchestratorInfo - 7, // 35: net.Orchestrator.EndTranscodingSession:output_type -> net.EndTranscodingSessionResponse - 5, // 36: net.Orchestrator.Ping:output_type -> net.PingPong - 22, // 37: net.Transcoder.RegisterTranscoder:output_type -> net.NotifySegment - 34, // [34:38] is the sub-list for method output_type - 30, // [30:34] is the sub-list for method input_type - 30, // [30:30] is the sub-list for extension type_name - 30, // [30:30] is the sub-list for extension extendee - 0, // [0:30] is the sub-list for field type_name -} - -func init() { file_net_lp_rpc_proto_init() } -func file_net_lp_rpc_proto_init() { - if File_net_lp_rpc_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_net_lp_rpc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingPong); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EndTranscodingSessionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EndTranscodingSessionResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OrchestratorRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OSInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*S3OSInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PriceInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Capabilities); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OrchestratorInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AuthToken); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SegData); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SegParameters); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VideoProfile); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TranscodedSegmentData); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TranscodeData); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TranscodeResult); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifySegment); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TicketParams); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TicketSenderParams); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TicketExpirationParams); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Payment); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_net_lp_rpc_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Capabilities_Constraints); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_net_lp_rpc_proto_msgTypes[15].OneofWrappers = []interface{}{ - (*TranscodeResult_Error)(nil), - (*TranscodeResult_Data)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_net_lp_rpc_proto_rawDesc, - NumEnums: 5, - NumMessages: 24, - NumExtensions: 0, - NumServices: 2, - }, - GoTypes: file_net_lp_rpc_proto_goTypes, - DependencyIndexes: file_net_lp_rpc_proto_depIdxs, - EnumInfos: file_net_lp_rpc_proto_enumTypes, - MessageInfos: file_net_lp_rpc_proto_msgTypes, - }.Build() - File_net_lp_rpc_proto = out.File - file_net_lp_rpc_proto_rawDesc = nil - file_net_lp_rpc_proto_goTypes = nil - file_net_lp_rpc_proto_depIdxs = nil +func init() { + proto.RegisterEnum("net.OSInfo_StorageType", OSInfo_StorageType_name, OSInfo_StorageType_value) + proto.RegisterEnum("net.VideoProfile_Format", VideoProfile_Format_name, VideoProfile_Format_value) + proto.RegisterEnum("net.VideoProfile_Profile", VideoProfile_Profile_name, VideoProfile_Profile_value) + proto.RegisterEnum("net.VideoProfile_VideoCodec", VideoProfile_VideoCodec_name, VideoProfile_VideoCodec_value) + proto.RegisterEnum("net.VideoProfile_ChromaSubsampling", VideoProfile_ChromaSubsampling_name, VideoProfile_ChromaSubsampling_value) + proto.RegisterType((*PingPong)(nil), "net.PingPong") + proto.RegisterType((*EndTranscodingSessionRequest)(nil), "net.EndTranscodingSessionRequest") + proto.RegisterType((*EndTranscodingSessionResponse)(nil), "net.EndTranscodingSessionResponse") + proto.RegisterType((*OrchestratorRequest)(nil), "net.OrchestratorRequest") + proto.RegisterType((*OSInfo)(nil), "net.OSInfo") + proto.RegisterType((*S3OSInfo)(nil), "net.S3OSInfo") + proto.RegisterType((*PriceInfo)(nil), "net.PriceInfo") + proto.RegisterType((*Capabilities)(nil), "net.Capabilities") + proto.RegisterMapType((map[uint32]uint32)(nil), "net.Capabilities.CapacitiesEntry") + proto.RegisterType((*Capabilities_Constraints)(nil), "net.Capabilities.Constraints") + proto.RegisterType((*OrchestratorInfo)(nil), "net.OrchestratorInfo") + proto.RegisterType((*AuthToken)(nil), "net.AuthToken") + proto.RegisterType((*SegData)(nil), "net.SegData") + proto.RegisterType((*SegParameters)(nil), "net.SegParameters") + proto.RegisterType((*VideoProfile)(nil), "net.VideoProfile") + proto.RegisterType((*TranscodedSegmentData)(nil), "net.TranscodedSegmentData") + proto.RegisterType((*TranscodeData)(nil), "net.TranscodeData") + proto.RegisterType((*TranscodeResult)(nil), "net.TranscodeResult") + proto.RegisterType((*RegisterRequest)(nil), "net.RegisterRequest") + proto.RegisterType((*NotifySegment)(nil), "net.NotifySegment") + proto.RegisterType((*TicketParams)(nil), "net.TicketParams") + proto.RegisterType((*TicketSenderParams)(nil), "net.TicketSenderParams") + proto.RegisterType((*TicketExpirationParams)(nil), "net.TicketExpirationParams") + proto.RegisterType((*Payment)(nil), "net.Payment") +} + +func init() { + proto.RegisterFile("net/lp_rpc.proto", fileDescriptor_034e29c79f9ba827) +} + +var fileDescriptor_034e29c79f9ba827 = []byte{ + // 1911 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x58, 0xef, 0x6e, 0x1b, 0xc7, + 0x11, 0x17, 0xff, 0x88, 0x7f, 0x86, 0xa4, 0x74, 0x5c, 0x4b, 0xca, 0x49, 0xb1, 0x53, 0xf9, 0x12, + 0x07, 0xca, 0x07, 0x2b, 0x06, 0x25, 0xbb, 0x71, 0x81, 0xa2, 0xa5, 0x24, 0x5a, 0x62, 0x60, 0x49, + 0xc4, 0x52, 0x36, 0xd0, 0x7e, 0x28, 0x7b, 0xba, 0x5b, 0x92, 0x57, 0x91, 0x7b, 0xe7, 0xbd, 0x65, + 0x6c, 0x05, 0x7d, 0x81, 0x3e, 0x42, 0xfb, 0xa5, 0x40, 0x81, 0xbe, 0x47, 0x1f, 0xa0, 0x0f, 0x50, + 0xf4, 0x39, 0xfa, 0x00, 0xc5, 0xce, 0xee, 0x1d, 0x8f, 0xa2, 0x92, 0x18, 0xf9, 0xb6, 0xf3, 0x9b, + 0xd9, 0xd9, 0xd9, 0x99, 0x9d, 0x3f, 0x77, 0x60, 0x71, 0x26, 0xbf, 0x9e, 0x44, 0x03, 0x11, 0x79, + 0xfb, 0x91, 0x08, 0x65, 0x48, 0x0a, 0x9c, 0x49, 0x67, 0x17, 0x2a, 0xbd, 0x80, 0x8f, 0x7a, 0x21, + 0x1f, 0x91, 0x0d, 0x58, 0xfd, 0xce, 0x9d, 0xcc, 0x98, 0x9d, 0xdb, 0xcd, 0xed, 0xd5, 0xa9, 0x26, + 0x9c, 0x73, 0x78, 0xd8, 0xe1, 0xfe, 0x95, 0x70, 0x79, 0xec, 0x85, 0x7e, 0xc0, 0x47, 0x7d, 0x16, + 0xc7, 0x41, 0xc8, 0x29, 0x7b, 0x37, 0x63, 0xb1, 0x24, 0x4f, 0x01, 0xdc, 0x99, 0x1c, 0x0f, 0x64, + 0x78, 0xc3, 0x38, 0x6e, 0xad, 0xb5, 0xd6, 0xf6, 0x39, 0x93, 0xfb, 0xed, 0x99, 0x1c, 0x5f, 0x29, + 0x94, 0x56, 0xdd, 0x64, 0xe9, 0xfc, 0x02, 0x1e, 0xfd, 0x80, 0xba, 0x38, 0x0a, 0x79, 0xcc, 0x9c, + 0x36, 0x3c, 0xb8, 0x14, 0xde, 0x98, 0xc5, 0x52, 0xb8, 0x32, 0x14, 0xc9, 0x31, 0x36, 0x94, 0x5d, + 0xdf, 0x17, 0x2c, 0x8e, 0x8d, 0x79, 0x09, 0x49, 0x2c, 0x28, 0xc4, 0xc1, 0xc8, 0xce, 0x23, 0xaa, + 0x96, 0xce, 0x5f, 0x73, 0x50, 0xba, 0xec, 0x77, 0xf9, 0x30, 0x24, 0x2f, 0xa1, 0x16, 0xcb, 0x50, + 0xb8, 0x23, 0x76, 0x75, 0x1b, 0xe9, 0x9b, 0xad, 0xb5, 0x3e, 0x41, 0xf3, 0xb4, 0xc4, 0x7e, 0x7f, + 0xce, 0xa6, 0x59, 0x59, 0xf2, 0x04, 0x4a, 0xf1, 0x41, 0xc0, 0x87, 0xa1, 0x6d, 0xe1, 0xa5, 0x1a, + 0xb8, 0xab, 0x7f, 0xa0, 0xf7, 0x51, 0xc3, 0x74, 0x9e, 0x42, 0x2d, 0xa3, 0x82, 0x00, 0x94, 0x4e, + 0xba, 0xb4, 0x73, 0x7c, 0x65, 0xad, 0x90, 0x12, 0xe4, 0xfb, 0x07, 0x56, 0x4e, 0x61, 0xa7, 0x97, + 0x97, 0xa7, 0xaf, 0x3b, 0x56, 0xde, 0xf9, 0x47, 0x0e, 0x2a, 0x89, 0x0e, 0x42, 0xa0, 0x38, 0x0e, + 0x63, 0x89, 0x66, 0x55, 0x29, 0xae, 0xd5, 0x75, 0x6e, 0xd8, 0x2d, 0x5e, 0xa7, 0x4a, 0xd5, 0x92, + 0x6c, 0x41, 0x29, 0x0a, 0x27, 0x81, 0x77, 0x6b, 0x17, 0x10, 0x34, 0x14, 0x79, 0x08, 0xd5, 0x38, + 0x18, 0x71, 0x57, 0xce, 0x04, 0xb3, 0x8b, 0xc8, 0x9a, 0x03, 0xe4, 0x33, 0x00, 0x4f, 0x30, 0x9f, + 0x71, 0x19, 0xb8, 0x13, 0x7b, 0x15, 0xd9, 0x19, 0x84, 0xec, 0x40, 0xe5, 0x43, 0x7b, 0xfa, 0xfd, + 0x89, 0x2b, 0x99, 0x5d, 0x42, 0x6e, 0x4a, 0x3b, 0x6f, 0xa0, 0xda, 0x13, 0x81, 0xc7, 0xd0, 0x48, + 0x07, 0xea, 0x91, 0x22, 0x7a, 0x4c, 0xbc, 0xe1, 0x81, 0x36, 0xb6, 0x40, 0x17, 0x30, 0xf2, 0x05, + 0x34, 0xa2, 0xe0, 0x03, 0x9b, 0xc4, 0x89, 0x50, 0x1e, 0x85, 0x16, 0x41, 0xe7, 0xbf, 0x79, 0xa8, + 0x1f, 0xbb, 0x91, 0x7b, 0x1d, 0x4c, 0x02, 0x19, 0xb0, 0x58, 0xdd, 0xe0, 0x3a, 0x90, 0xb1, 0x14, + 0x01, 0x1f, 0xd9, 0xb9, 0xdd, 0xc2, 0x5e, 0x91, 0xce, 0x01, 0xb2, 0x0b, 0xb5, 0xa9, 0xcb, 0x7d, + 0xf5, 0x0a, 0x02, 0x16, 0xdb, 0x79, 0xe4, 0x67, 0x21, 0xd2, 0x06, 0xf0, 0xdc, 0xc8, 0xf5, 0x50, + 0x9b, 0x5d, 0xd8, 0x2d, 0xec, 0xd5, 0x5a, 0x8f, 0x31, 0x4c, 0xd9, 0x63, 0x90, 0xd0, 0x32, 0x1d, + 0x2e, 0xc5, 0x2d, 0xcd, 0x6c, 0x52, 0xef, 0xea, 0x3b, 0x26, 0xd4, 0x0b, 0x34, 0x2e, 0x4c, 0x48, + 0xf2, 0x1b, 0xa8, 0x79, 0x21, 0x57, 0xcf, 0x30, 0xe0, 0x32, 0x46, 0x0f, 0xd6, 0x5a, 0x8f, 0xee, + 0xd1, 0x3e, 0x17, 0xa2, 0xd9, 0x1d, 0x3b, 0xbf, 0x86, 0xf5, 0x3b, 0x27, 0x27, 0xc1, 0x55, 0x2e, + 0x6c, 0xe8, 0xe0, 0xa6, 0x49, 0x97, 0x47, 0x4c, 0x13, 0xbf, 0xca, 0x7f, 0x93, 0xdb, 0x79, 0x0a, + 0xb5, 0x8c, 0x6a, 0x15, 0xcf, 0x69, 0xc0, 0xdf, 0x1a, 0x5b, 0xf5, 0x8b, 0xc9, 0x20, 0xce, 0xbf, + 0xf2, 0x60, 0x65, 0x13, 0x07, 0x63, 0xf7, 0x19, 0x80, 0x34, 0xa9, 0xc6, 0x44, 0xb2, 0x69, 0x8e, + 0x90, 0x17, 0xd0, 0x90, 0x81, 0x77, 0xc3, 0xe4, 0x20, 0x72, 0x85, 0x3b, 0x8d, 0xd1, 0x8a, 0x5a, + 0xab, 0x89, 0xb7, 0xbc, 0x42, 0x4e, 0x0f, 0x19, 0xb4, 0x2e, 0x33, 0x94, 0x4a, 0x7a, 0x8c, 0xff, + 0x00, 0xf3, 0xa3, 0x90, 0x49, 0xfa, 0xf4, 0xdd, 0xd0, 0x6a, 0x94, 0x3e, 0xa1, 0x4c, 0xf2, 0x16, + 0x17, 0x93, 0xf7, 0x39, 0xd4, 0xbd, 0x8c, 0x33, 0x8d, 0x97, 0x9b, 0x4b, 0x5e, 0xa6, 0x0b, 0x62, + 0x77, 0x8a, 0x4e, 0xe9, 0x27, 0x8a, 0x0e, 0x79, 0x02, 0x65, 0x93, 0xd9, 0xf6, 0x2e, 0x3e, 0x92, + 0x5a, 0xa6, 0x02, 0xd0, 0x84, 0xe7, 0xfc, 0x11, 0xaa, 0xe9, 0x76, 0x15, 0x98, 0x79, 0x49, 0xab, + 0x53, 0x4d, 0x90, 0x47, 0x00, 0xb1, 0x2e, 0x58, 0x83, 0xc0, 0x37, 0x49, 0x5a, 0x35, 0x48, 0xd7, + 0x57, 0xfe, 0x66, 0x1f, 0xa2, 0x40, 0xb8, 0x52, 0x05, 0xa9, 0x80, 0x49, 0x90, 0x41, 0x9c, 0xff, + 0x15, 0xa1, 0xdc, 0x67, 0xa3, 0x13, 0x57, 0xba, 0x18, 0x50, 0x97, 0x07, 0x43, 0x16, 0xcb, 0xae, + 0x6f, 0x4e, 0xc9, 0x20, 0x58, 0xd7, 0xd8, 0x3b, 0x93, 0x49, 0x6a, 0x89, 0xe5, 0xc2, 0x8d, 0xc7, + 0xa8, 0xb7, 0x4e, 0x71, 0xad, 0xd2, 0x38, 0x12, 0xe1, 0x30, 0x98, 0xb0, 0xc4, 0xb7, 0x29, 0x9d, + 0x54, 0xc6, 0xd5, 0xb4, 0x32, 0x2a, 0x69, 0x7f, 0x66, 0xac, 0x53, 0x5e, 0x5b, 0xa5, 0x29, 0xbd, + 0x14, 0x8a, 0xf2, 0xcf, 0x09, 0x45, 0xe5, 0xa7, 0x42, 0xf1, 0x0c, 0x36, 0x3c, 0x77, 0xe2, 0x0d, + 0x22, 0x26, 0x3c, 0x16, 0xc9, 0x99, 0x3b, 0x19, 0xe0, 0x9d, 0x60, 0x37, 0xb7, 0x57, 0xa1, 0x44, + 0xf1, 0x7a, 0x29, 0xeb, 0x4c, 0xdd, 0xf0, 0xe3, 0x82, 0xa7, 0xcc, 0x1f, 0xce, 0x26, 0x93, 0x5e, + 0xe2, 0x8c, 0xc7, 0x28, 0xab, 0xcd, 0x7f, 0x1b, 0xf8, 0x2c, 0x34, 0x1c, 0xba, 0x20, 0x46, 0x7e, + 0x09, 0x8d, 0x2c, 0xdd, 0xb2, 0x9d, 0x1f, 0xda, 0xb7, 0x28, 0x77, 0x77, 0xe3, 0x81, 0xfd, 0xf9, + 0x47, 0x6d, 0x3c, 0x20, 0x6d, 0x20, 0x31, 0x1b, 0x4d, 0x19, 0x37, 0x49, 0xc7, 0x24, 0x13, 0xb1, + 0xfd, 0x04, 0x1d, 0x47, 0x74, 0x8f, 0x61, 0xa3, 0x5e, 0xca, 0xa1, 0x4d, 0x23, 0x3d, 0x87, 0xc8, + 0x3e, 0x90, 0x57, 0xa1, 0xf0, 0x58, 0xda, 0x3b, 0x03, 0x55, 0x73, 0xbf, 0xd4, 0x2e, 0x5c, 0xe6, + 0x38, 0x07, 0xd0, 0x58, 0xd0, 0xa9, 0x5e, 0xd2, 0x50, 0x84, 0x53, 0x7c, 0x75, 0x45, 0x8a, 0x6b, + 0xb2, 0x06, 0x79, 0x19, 0xe2, 0x73, 0x2b, 0xd2, 0xbc, 0x0c, 0x9d, 0x7f, 0xaf, 0x42, 0x3d, 0x7b, + 0x0f, 0xb5, 0x89, 0xbb, 0x53, 0x86, 0xed, 0xb0, 0x4a, 0x71, 0xad, 0xb2, 0xe4, 0x7d, 0xe0, 0xcb, + 0xb1, 0xdd, 0xc4, 0xd7, 0xa4, 0x09, 0xd5, 0xb1, 0xc6, 0x2c, 0x18, 0x8d, 0xa5, 0x4d, 0x10, 0x36, + 0x94, 0xaa, 0x03, 0xd7, 0x81, 0x2a, 0x4f, 0xcc, 0x7e, 0x80, 0x8c, 0x84, 0x54, 0x4f, 0x75, 0x18, + 0xc5, 0xf6, 0x86, 0x2e, 0x8c, 0xc3, 0x28, 0x26, 0xcf, 0xa0, 0x34, 0x0c, 0xc5, 0xd4, 0x95, 0xf6, + 0x26, 0x36, 0x6d, 0x7b, 0xc9, 0xb1, 0xfb, 0xaf, 0x90, 0x4f, 0x8d, 0x9c, 0x3a, 0x75, 0x18, 0xc5, + 0x27, 0x8c, 0xdb, 0x5b, 0xa8, 0xc6, 0x50, 0xe4, 0x00, 0xca, 0x26, 0x25, 0xec, 0x4f, 0x50, 0xd5, + 0xf6, 0xb2, 0xaa, 0x24, 0x56, 0x89, 0xa4, 0x32, 0x68, 0x14, 0x46, 0xb6, 0x8d, 0x66, 0xaa, 0x25, + 0x79, 0x01, 0x65, 0xc6, 0x75, 0x21, 0xdd, 0x46, 0x35, 0x0f, 0x97, 0xd5, 0x20, 0x71, 0x1c, 0xfa, + 0xcc, 0xa3, 0x89, 0x30, 0x36, 0xe2, 0x70, 0x12, 0x8a, 0x13, 0x16, 0xc9, 0xb1, 0xbd, 0x83, 0x0a, + 0x33, 0x08, 0x39, 0x85, 0xba, 0x37, 0x16, 0xe1, 0xd4, 0xd5, 0xd7, 0xb1, 0x3f, 0x45, 0xe5, 0x9f, + 0x2f, 0x2b, 0x3f, 0x46, 0xa9, 0xfe, 0xec, 0x3a, 0x76, 0xa7, 0xd1, 0x24, 0xe0, 0x23, 0xba, 0xb0, + 0x51, 0x79, 0xf7, 0xdd, 0xcc, 0x9d, 0x04, 0xf2, 0xd6, 0x7e, 0x88, 0x0e, 0x48, 0x48, 0xe7, 0x11, + 0x94, 0x8c, 0x0c, 0x40, 0xe9, 0xbc, 0xd7, 0x39, 0xbd, 0xea, 0x5b, 0x2b, 0xa4, 0x0c, 0x85, 0xf3, + 0xde, 0xa1, 0x95, 0x73, 0xfe, 0x04, 0xe5, 0x24, 0xc6, 0x0f, 0x60, 0xbd, 0x73, 0x71, 0x7c, 0x79, + 0xd2, 0xa1, 0x83, 0x93, 0xce, 0xab, 0xf6, 0x9b, 0xd7, 0x6a, 0x8e, 0x69, 0x42, 0xe3, 0xac, 0xf5, + 0xe2, 0x70, 0x70, 0xd4, 0xee, 0x77, 0x5e, 0x77, 0x2f, 0x3a, 0x56, 0x8e, 0x34, 0xa0, 0x8a, 0xd0, + 0x79, 0xbb, 0x7b, 0x61, 0xe5, 0x53, 0xf2, 0xac, 0x7b, 0x7a, 0x66, 0x15, 0xc8, 0x36, 0x6c, 0x22, + 0x79, 0x7c, 0x79, 0xd1, 0xbf, 0xa2, 0xed, 0xee, 0x45, 0xe7, 0x44, 0xb3, 0x8a, 0x4e, 0x0b, 0x60, + 0xee, 0x24, 0x52, 0x81, 0xa2, 0x12, 0xb4, 0x56, 0xcc, 0xea, 0xb9, 0x95, 0x53, 0x66, 0xbd, 0xed, + 0x7d, 0x63, 0xe5, 0xf5, 0xe2, 0xa5, 0x55, 0x70, 0x8e, 0xa1, 0xb9, 0x74, 0x77, 0xb2, 0x06, 0x70, + 0x7c, 0x46, 0x2f, 0xcf, 0xdb, 0x83, 0xc3, 0xd6, 0x33, 0x6b, 0x65, 0x81, 0x6e, 0x59, 0xb9, 0x2c, + 0x7d, 0x78, 0x68, 0xe5, 0x9d, 0x77, 0xb0, 0x99, 0x4c, 0x9d, 0xcc, 0xef, 0xeb, 0x94, 0xc2, 0x3a, + 0x6c, 0x41, 0x61, 0x26, 0x26, 0xa6, 0x39, 0xaa, 0x25, 0x0e, 0x5c, 0x38, 0xb8, 0x98, 0xe2, 0x6b, + 0x28, 0xb2, 0x0f, 0x0f, 0xee, 0x94, 0xad, 0x81, 0xda, 0xa9, 0xa7, 0xb2, 0x66, 0xb4, 0x50, 0xb6, + 0xde, 0x88, 0x89, 0xf3, 0x3b, 0x68, 0xa4, 0x47, 0xe2, 0x51, 0x2f, 0xa0, 0x62, 0x92, 0x39, 0xc6, + 0x71, 0xa7, 0xd6, 0xda, 0xd1, 0x9d, 0xf6, 0x3e, 0xc3, 0x68, 0x2a, 0x7b, 0xcf, 0x88, 0xfb, 0xb7, + 0x1c, 0xac, 0xa7, 0xbb, 0x28, 0x8b, 0x67, 0x13, 0x99, 0x34, 0x8c, 0xdc, 0xbc, 0x61, 0x6c, 0xc1, + 0x2a, 0x13, 0x22, 0x14, 0xba, 0x51, 0x9d, 0xad, 0x50, 0x4d, 0x92, 0x3d, 0x28, 0xfa, 0xae, 0x74, + 0x4d, 0xe3, 0x26, 0x8b, 0x36, 0xa8, 0xb3, 0xcf, 0x56, 0x28, 0x4a, 0x90, 0xaf, 0xa0, 0x98, 0x19, + 0x81, 0x37, 0x75, 0xe5, 0xbd, 0x33, 0x65, 0x50, 0x14, 0x39, 0xaa, 0x40, 0x49, 0xa0, 0x21, 0xce, + 0x9f, 0x61, 0x9d, 0xb2, 0x51, 0x10, 0x4b, 0x96, 0x8e, 0xef, 0x5b, 0x50, 0x8a, 0x99, 0x27, 0x58, + 0x32, 0xeb, 0x1a, 0x4a, 0x35, 0x24, 0x33, 0x8c, 0xdd, 0x1a, 0x67, 0xa7, 0xf4, 0x52, 0x43, 0x2a, + 0x7c, 0x54, 0x43, 0x72, 0xfe, 0x92, 0x83, 0xc6, 0x45, 0x28, 0x83, 0xe1, 0xad, 0x71, 0xe6, 0x3d, + 0x11, 0xfe, 0x12, 0xca, 0xb1, 0x6e, 0xc3, 0x46, 0x6b, 0x3d, 0x29, 0xbc, 0xe8, 0xf9, 0x84, 0xa9, + 0xcc, 0x96, 0x6e, 0x7c, 0xd3, 0xf5, 0xd1, 0x01, 0x05, 0x6a, 0xa8, 0x85, 0xae, 0xdb, 0x5c, 0xec, + 0xba, 0xdf, 0x16, 0x2b, 0x79, 0xab, 0xf0, 0x6d, 0xb1, 0xf2, 0xd8, 0x72, 0x9c, 0xbf, 0xe7, 0xa1, + 0x9e, 0x1d, 0xa3, 0xd4, 0xc4, 0x2b, 0x98, 0x17, 0x44, 0x01, 0xe3, 0xd2, 0xf4, 0xfc, 0x39, 0xa0, + 0xa6, 0x8b, 0xa1, 0xeb, 0xb1, 0xc1, 0x7c, 0x22, 0xac, 0xd3, 0xaa, 0x42, 0xde, 0x2a, 0x80, 0x6c, + 0x43, 0xe5, 0x7d, 0xc0, 0x07, 0x91, 0x08, 0xaf, 0xcd, 0x0c, 0x50, 0x7e, 0x1f, 0xf0, 0x9e, 0x08, + 0xaf, 0xd5, 0xd3, 0x4c, 0xd5, 0x0c, 0x84, 0xcb, 0x7d, 0xdd, 0x55, 0xf5, 0x44, 0xd0, 0x4c, 0x59, + 0xd4, 0xe5, 0x3e, 0x36, 0x55, 0x02, 0xc5, 0x98, 0x31, 0xdf, 0xcc, 0x06, 0xb8, 0x26, 0x5f, 0x81, + 0x35, 0x1f, 0x55, 0x06, 0xd7, 0x93, 0xd0, 0xbb, 0xc1, 0x21, 0xa1, 0x4e, 0xd7, 0xe7, 0xf8, 0x91, + 0x82, 0xc9, 0x19, 0x34, 0x33, 0xa2, 0x66, 0x76, 0xd4, 0x03, 0xc3, 0xa7, 0x99, 0xd9, 0xb1, 0x93, + 0xca, 0x98, 0x29, 0x32, 0x73, 0x80, 0x46, 0x9c, 0x2e, 0x10, 0x2d, 0xdb, 0x67, 0xdc, 0x67, 0xc2, + 0xb8, 0xe9, 0x31, 0xd4, 0x63, 0xa4, 0x07, 0x3c, 0xe4, 0x1e, 0x33, 0x03, 0x73, 0x4d, 0x63, 0x17, + 0x0a, 0xba, 0x27, 0x27, 0xbe, 0x87, 0xad, 0xfb, 0x8f, 0x25, 0x4f, 0x60, 0xcd, 0x13, 0x4c, 0x1b, + 0x2b, 0xc2, 0x19, 0xf7, 0x4d, 0x92, 0x34, 0x12, 0x94, 0x2a, 0x90, 0xbc, 0x84, 0xed, 0x45, 0x31, + 0xed, 0x04, 0xed, 0x4a, 0x7d, 0xd0, 0xd6, 0xc2, 0x0e, 0x74, 0x86, 0xf2, 0xa7, 0xf3, 0xcf, 0x3c, + 0x94, 0x7b, 0xee, 0x2d, 0x3e, 0xb7, 0xa5, 0xa1, 0x3a, 0xf7, 0x71, 0x43, 0x35, 0xe6, 0x88, 0xba, + 0xa0, 0x39, 0xcb, 0x50, 0xf7, 0x3b, 0xbb, 0xf0, 0x33, 0x9c, 0x4d, 0xba, 0xb0, 0x61, 0x2c, 0x33, + 0xde, 0x35, 0xca, 0x8a, 0x58, 0x8b, 0x3e, 0xc9, 0x28, 0xcb, 0x46, 0x83, 0x12, 0xb9, 0x1c, 0xa1, + 0xe7, 0xb0, 0xc6, 0x3e, 0x44, 0xcc, 0x93, 0xcc, 0x1f, 0xe0, 0xa0, 0x6f, 0x46, 0xf7, 0xbb, 0x5f, + 0x01, 0x8d, 0x44, 0x0a, 0xa1, 0xd6, 0x7f, 0x72, 0x50, 0xcf, 0xd6, 0x0f, 0x72, 0x04, 0xeb, 0xa7, + 0x4c, 0x2e, 0x40, 0xf6, 0x52, 0x95, 0x31, 0x55, 0x64, 0xe7, 0xfe, 0xfa, 0x43, 0xfe, 0x00, 0x9b, + 0xf7, 0xfe, 0x53, 0x20, 0xfa, 0x5b, 0xf0, 0xc7, 0x7e, 0x5f, 0xec, 0x38, 0x3f, 0x26, 0xa2, 0x7f, + 0x49, 0x90, 0x2f, 0xa0, 0xd8, 0x53, 0x2d, 0x47, 0xff, 0x01, 0x48, 0xfe, 0x97, 0xec, 0x2c, 0x92, + 0xad, 0x0b, 0x80, 0xab, 0xf9, 0x97, 0xd5, 0x6f, 0x81, 0x24, 0x35, 0x30, 0x83, 0x6e, 0xe0, 0x96, + 0x3b, 0xc5, 0x71, 0x47, 0x17, 0xe0, 0x85, 0x9a, 0xf5, 0x2c, 0x77, 0x54, 0xfe, 0xfd, 0xea, 0xfe, + 0xd7, 0x9c, 0xc9, 0xeb, 0x12, 0xfe, 0xaf, 0x39, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8c, + 0x55, 0x8b, 0x9a, 0xc3, 0x11, 0x00, 0x00, } diff --git a/net/lp_rpc.proto b/net/lp_rpc.proto index c7854f5980..e53a594fcf 100644 --- a/net/lp_rpc.proto +++ b/net/lp_rpc.proto @@ -105,9 +105,13 @@ message Capabilities { // Capacity corresponding to each capability map capacities = 3; + string version = 4; + + Constraints constraints = 5; + // Non-binary capability constraints, such as supported ranges. message Constraints { - // Empty for now + string minVersion = 1; } } diff --git a/net/lp_rpc_grpc.pb.go b/net/lp_rpc_grpc.pb.go index 3743d79756..64a0935463 100644 --- a/net/lp_rpc_grpc.pb.go +++ b/net/lp_rpc_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 -// - protoc v4.25.2 +// - protoc v3.21.4 // source: net/lp_rpc.proto package net diff --git a/net/redeemer.pb.go b/net/redeemer.pb.go index 132a70cf49..87d1869b4d 100644 --- a/net/redeemer.pb.go +++ b/net/redeemer.pb.go @@ -319,7 +319,6 @@ func file_net_redeemer_proto_init() { if File_net_redeemer_proto != nil { return } - file_net_lp_rpc_proto_init() if !protoimpl.UnsafeEnabled { file_net_redeemer_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Ticket); i { diff --git a/server/broadcast.go b/server/broadcast.go index 2edcd4f58d..150d66ea86 100755 --- a/server/broadcast.go +++ b/server/broadcast.go @@ -448,6 +448,9 @@ func (bsm *BroadcastSessionsManager) shouldSkipVerification(sessions []*Broadcas } func NewSessionManager(ctx context.Context, node *core.LivepeerNode, params *core.StreamParameters, sel BroadcastSessionsSelectorFactory) *BroadcastSessionsManager { + if node.Capabilities != nil { + params.Capabilities.SetMinVersionConstraint(node.Capabilities.MinVersionConstraint()) + } var trustedPoolSize, untrustedPoolSize float64 if node.OrchestratorPool != nil { trustedPoolSize = float64(node.OrchestratorPool.SizeWith(common.ScoreAtLeast(common.Score_Trusted))) diff --git a/server/mediaserver.go b/server/mediaserver.go index c123c578a9..7f57e6b823 100644 --- a/server/mediaserver.go +++ b/server/mediaserver.go @@ -433,6 +433,7 @@ func gotRTMPStreamHandler(s *LivepeerServer) func(url *url.URL, rtmpStrm stream. func endRTMPStreamHandler(s *LivepeerServer) func(url *url.URL, rtmpStrm stream.RTMPVideoStream) error { return func(url *url.URL, rtmpStrm stream.RTMPVideoStream) error { params := streamParams(rtmpStrm.AppData()) + params.Capabilities.SetMinVersionConstraint(s.LivepeerNode.Capabilities.MinVersionConstraint()) if params == nil { return errMismatchedParams } From 5f8bc5549879880a03c9e48f731e786b58a2b67c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Mon, 13 May 2024 18:57:12 +0200 Subject: [PATCH 20/39] Update LPMS with the mobile transcoding fix (#3003) --- core/core_test.go | 4 ++-- core/transcoder_test.go | 4 ++-- go.mod | 2 +- go.sum | 2 ++ 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/core_test.go b/core/core_test.go index 671c56c916..5346e2a3d3 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -78,10 +78,10 @@ func TestTranscode(t *testing.T) { } // Check transcode result - if Over1Pct(len(tr.TranscodeData.Segments[0].Data), 218268) { // 144p + if Over1Pct(len(tr.TranscodeData.Segments[0].Data), 273352) { // 144p t.Error("Unexpected transcode result ", len(tr.TranscodeData.Segments[0].Data)) } - if Over1Pct(len(tr.TranscodeData.Segments[1].Data), 302868) { // 240p + if Over1Pct(len(tr.TranscodeData.Segments[1].Data), 378068) { // 240p t.Error("Unexpected transcode result ", len(tr.TranscodeData.Segments[1].Data)) } diff --git a/core/transcoder_test.go b/core/transcoder_test.go index 8b8061ffc8..25e19c5818 100644 --- a/core/transcoder_test.go +++ b/core/transcoder_test.go @@ -32,10 +32,10 @@ func TestLocalTranscoder(t *testing.T) { if len(res.Segments) != len(videoProfiles) { t.Error("Mismatched results") } - if Over1Pct(len(res.Segments[0].Data), 522264) { + if Over1Pct(len(res.Segments[0].Data), 585620) { t.Errorf("Wrong data %v", len(res.Segments[0].Data)) } - if Over1Pct(len(res.Segments[1].Data), 715528) { + if Over1Pct(len(res.Segments[1].Data), 813100) { t.Errorf("Wrong data %v", len(res.Segments[1].Data)) } } diff --git a/go.mod b/go.mod index e4837beb3b..42eef47297 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/jaypipes/pcidb v1.0.0 github.com/livepeer/go-tools v0.0.0-20220805063103-76df6beb6506 github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18 - github.com/livepeer/lpms v0.0.0-20240402101153-ced71c476bd0 + github.com/livepeer/lpms v0.0.0-20240513161533-11a5584d691d github.com/livepeer/m3u8 v0.11.1 github.com/mattn/go-sqlite3 v1.14.18 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index cad66eecff..6a79bae3e1 100644 --- a/go.sum +++ b/go.sum @@ -452,6 +452,8 @@ github.com/livepeer/lpms v0.0.0-20240115103113-98566e26c007 h1:0xr1TeIanBDdzI3sE github.com/livepeer/lpms v0.0.0-20240115103113-98566e26c007/go.mod h1:Hr/JhxxPDipOVd4ZrGYWrdJfpVF8/SEI0nNr2ctAlkM= github.com/livepeer/lpms v0.0.0-20240402101153-ced71c476bd0 h1:Ch+HRjVJHpNo3kySGJgyDqb+l0KPWehyqZfA1wOafgY= github.com/livepeer/lpms v0.0.0-20240402101153-ced71c476bd0/go.mod h1:z5ROP1l5OzAKSoqVRLc34MjUdueil6wHSecQYV7llIw= +github.com/livepeer/lpms v0.0.0-20240513161533-11a5584d691d h1:RehRsei/f2mv1RCWD1e3FWRkPl/+eKlHq6syU9c4WJE= +github.com/livepeer/lpms v0.0.0-20240513161533-11a5584d691d/go.mod h1:z5ROP1l5OzAKSoqVRLc34MjUdueil6wHSecQYV7llIw= github.com/livepeer/m3u8 v0.11.1 h1:VkUJzfNTyjy9mqsgp5JPvouwna8wGZMvd/gAfT5FinU= github.com/livepeer/m3u8 v0.11.1/go.mod h1:IUqAtwWPAG2CblfQa4SVzTQoDcEMPyfNOaBSxqHMS04= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= From 7599f7fe79174d8541305fe79aeb5d0bac078afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Tue, 14 May 2024 17:17:17 +0200 Subject: [PATCH 21/39] Release 0.7.5 (#3051) --- CHANGELOG.md | 41 ++++++++++++++++++++++++++++++++++++++++- CHANGELOG_PENDING.md | 5 ----- VERSION | 2 +- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea7f99c11a..49545e9b2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,44 @@ # Changelog +## v0.7.5 + +### Breaking Changes 🚨🚨 + +### Features βš’ + +#### General + +- [#3050](https://github.com/livepeer/go-livepeer/pull/3050) Create option to filter Os by min livepeer version used (@leszko) +- [#3029](https://github.com/livepeer/go-livepeer/pull/3029) Initialize round by any B/O who has the initializeRound flag set to true (@leszko) +- [#3040](https://github.com/livepeer/go-livepeer/pull/3040) Fix function names (@kevincatty) + +#### Broadcaster + +- [#2995](https://github.com/livepeer/go-livepeer/pull/2995) server: Allow Os price to increase up to 2x mid-session (@victorges) +- [#2999](https://github.com/livepeer/go-livepeer/pull/2999) server,discovery: Allow B to use any O in case none match maxPrice (@victorges) + +#### Orchestrator + +#### Transcoder + +### Bug Fixes 🐞 + +#### CLI + +#### General + +#### Broadcaster + +- [#2994](https://github.com/livepeer/go-livepeer/pull/2994) server: Skip redundant maxPrice check in ongoing session (@victorges) + +#### Orchestrator + +- [#3001](https://github.com/livepeer/go-livepeer/pull/3001) Fix transcoding price metrics (@leszko) + +#### Transcoder + +- [#3003](https://github.com/livepeer/go-livepeer/pull/3003) Fix issue in the transcoding layer for WebRTC input (@j0sh) + ## v0.7.4 ### Breaking Changes 🚨🚨 @@ -946,4 +985,4 @@ Thanks everyone that submitted bug reports and assisted in testing! - [#1775](https://github.com/livepeer/go-livepeer/pull/1775) Fix transcoder load balancer race condition around session cleanup (@jailuthra) - [#1784](https://github.com/livepeer/go-livepeer/pull/1784) Use auth token sessionID to index into sessions map in transcoder load balancer (@jailuthra) -[Full list of changes](https://github.com/livepeer/go-livepeer/compare/v0.5.14...v0.5.15) \ No newline at end of file +[Full list of changes](https://github.com/livepeer/go-livepeer/compare/v0.5.14...v0.5.15) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 1015174350..3ca5044811 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -10,9 +10,6 @@ #### Broadcaster -- [#2995](https://github.com/livepeer/go-livepeer/pull/2995) server: Allow Os price to increase up to 2x mid-session (@victorges) -- [#2999](https://github.com/livepeer/go-livepeer/pull/2999) server,discovery: Allow B to use any O in case none match maxPrice (@victorges) - #### Orchestrator #### Transcoder @@ -25,8 +22,6 @@ #### Broadcaster -- [#2994](https://github.com/livepeer/go-livepeer/pull/2994) server: Skip redundant maxPrice check in ongoing session (@victorges) - #### Orchestrator #### Transcoder diff --git a/VERSION b/VERSION index ef090a6c47..da2ac9c7e6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.4 \ No newline at end of file +0.7.5 \ No newline at end of file From 19f1cf62293a76d050567e4d7edc018c274901a9 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Thu, 16 May 2024 18:46:20 +0200 Subject: [PATCH 22/39] refactor: add -gateway and deprecate -broadcaster (#3053) * refactor: add -gateway and deprecate -broadcaster This commit adds the `gateway` flag and deprecates the `broadcaster` flag per core team decision (details: https://discord.com/channels/423160867534929930/1051963444598943784/1210356864643109004). * chore: update pending changelog --------- Co-authored-by: John | Elite Encoder --- CHANGELOG_PENDING.md | 2 ++ cmd/livepeer/livepeer.go | 3 ++- cmd/livepeer/starter/starter.go | 8 +++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 3ca5044811..fa297c5552 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -2,6 +2,8 @@ ## vX.X +- [#3053](https://github.com/livepeer/go-livepeer/pull/3053) cli: add `-gateway` flag and deprecate `-broadcaster` flag. + ### Breaking Changes 🚨🚨 ### Features βš’ diff --git a/cmd/livepeer/livepeer.go b/cmd/livepeer/livepeer.go index b25472f7fa..0568b70836 100755 --- a/cmd/livepeer/livepeer.go +++ b/cmd/livepeer/livepeer.go @@ -140,7 +140,8 @@ func parseLivepeerConfig() starter.LivepeerConfig { // Transcoding: cfg.Orchestrator = flag.Bool("orchestrator", *cfg.Orchestrator, "Set to true to be an orchestrator") cfg.Transcoder = flag.Bool("transcoder", *cfg.Transcoder, "Set to true to be a transcoder") - cfg.Broadcaster = flag.Bool("broadcaster", *cfg.Broadcaster, "Set to true to be a broadcaster") + cfg.Gateway = flag.Bool("gateway", *cfg.Broadcaster, "Set to true to be a gateway") + cfg.Broadcaster = flag.Bool("broadcaster", *cfg.Broadcaster, "Set to true to be a broadcaster (**Deprecated**, use -gateway)") cfg.OrchSecret = flag.String("orchSecret", *cfg.OrchSecret, "Shared secret with the orchestrator as a standalone transcoder or path to file") cfg.TranscodingOptions = flag.String("transcodingOptions", *cfg.TranscodingOptions, "Transcoding options for broadcast job, or path to json config") cfg.MaxAttempts = flag.Int("maxAttempts", *cfg.MaxAttempts, "Maximum transcode attempts") diff --git a/cmd/livepeer/starter/starter.go b/cmd/livepeer/starter/starter.go index 84ff08c330..3ed6edfaa0 100755 --- a/cmd/livepeer/starter/starter.go +++ b/cmd/livepeer/starter/starter.go @@ -87,6 +87,7 @@ type LivepeerConfig struct { HttpIngest *bool Orchestrator *bool Transcoder *bool + Gateway *bool Broadcaster *bool OrchSecret *string TranscodingOptions *string @@ -164,6 +165,7 @@ func DefaultLivepeerConfig() LivepeerConfig { defaultOrchestrator := false defaultTranscoder := false defaultBroadcaster := false + defaultGateway := false defaultOrchSecret := "" defaultTranscodingOptions := "P240p30fps16x9,P360p30fps16x9" defaultMaxAttempts := 3 @@ -250,6 +252,7 @@ func DefaultLivepeerConfig() LivepeerConfig { // Transcoding: Orchestrator: &defaultOrchestrator, Transcoder: &defaultTranscoder, + Gateway: &defaultGateway, Broadcaster: &defaultBroadcaster, OrchSecret: &defaultOrchSecret, TranscodingOptions: &defaultTranscodingOptions, @@ -501,6 +504,9 @@ func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { n.NodeType = core.TranscoderNode } else if *cfg.Broadcaster { n.NodeType = core.BroadcasterNode + glog.Warning("-broadcaster flag is deprecated and will be removed in a future release. Please use -gateway instead") + } else if *cfg.Gateway { + n.NodeType = core.BroadcasterNode } else if (cfg.Reward == nil || !*cfg.Reward) && !*cfg.InitializeRound { exit("No services enabled; must be at least one of -broadcaster, -transcoder, -orchestrator, -redeemer, -reward or -initializeRound") } @@ -1273,7 +1279,7 @@ func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { case core.OrchestratorNode: glog.Infof("***Livepeer Running in Orchestrator Mode***") case core.BroadcasterNode: - glog.Infof("***Livepeer Running in Broadcaster Mode***") + glog.Infof("***Livepeer Running in Gateway Mode***") glog.Infof("Video Ingest Endpoint - rtmp://%v", *cfg.RtmpAddr) case core.TranscoderNode: glog.Infof("**Liveepeer Running in Transcoder Mode***") From 304e47f12e805aa25a51968b7ddf00a87ed54172 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Thu, 16 May 2024 20:06:18 +0200 Subject: [PATCH 23/39] refactor(census): rename Broadcaster metrics to Gateway (#3055) * refactor(census): rename Broadcaster metrics to Gateway This commit renames the metrics related to Broadcaster to Gateway, following a team decision. More details can be found in the discussion here: [Team Discussion Link](.com/channels/423160867534929930/1051963444598943784/1210356864643109004). * chore: update pending changelog --- CHANGELOG_PENDING.md | 3 ++- monitor/census.go | 25 ++++++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index fa297c5552..bd4caf70d2 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -2,7 +2,8 @@ ## vX.X -- [#3053](https://github.com/livepeer/go-livepeer/pull/3053) cli: add `-gateway` flag and deprecate `-broadcaster` flag. +- [#3055](https://github.com/livepeer/go-livepeer/pull/3055) census: Rename broadcaster metrics to gateway metrics +- [#3053](https://github.com/livepeer/go-livepeer/pull/3053) cli: add `-gateway` flag and deprecate `-broadcaster` flag. ### Breaking Changes 🚨🚨 diff --git a/monitor/census.go b/monitor/census.go index 8c80459bc7..f6ee869231 100644 --- a/monitor/census.go +++ b/monitor/census.go @@ -306,8 +306,8 @@ func InitCensus(nodeType NodeType, version string) { census.mTicketValueSent = stats.Float64("ticket_value_sent", "TicketValueSent", "gwei") census.mTicketsSent = stats.Int64("tickets_sent", "TicketsSent", "tot") census.mPaymentCreateError = stats.Int64("payment_create_errors", "PaymentCreateError", "tot") - census.mDeposit = stats.Float64("broadcaster_deposit", "Current remaining deposit for the broadcaster node", "gwei") - census.mReserve = stats.Float64("broadcaster_reserve", "Current remaining reserve for the broadcaster node", "gwei") + census.mDeposit = stats.Float64("gateway_deposit", "Current remaining deposit for the gateway node", "gwei") + census.mReserve = stats.Float64("gateway_reserve", "Current remaining reserve for the gateway node", "gwei") // Metrics for receiving payments census.mTicketValueRecv = stats.Float64("ticket_value_recv", "TicketValueRecv", "gwei") @@ -690,17 +690,32 @@ func InitCensus(nodeType NodeType, version string) { TagKeys: baseTagsWithManifestID, Aggregation: view.Sum(), }, + { + Name: "gateway_deposit", + Measure: census.mDeposit, + Description: "Current remaining deposit for the gateway node", + TagKeys: baseTagsWithEthAddr, + Aggregation: view.LastValue(), + }, + { + Name: "gateway_reserve", + Measure: census.mReserve, + Description: "Current remaining reserve for the gateway node", + TagKeys: baseTagsWithEthAddr, + Aggregation: view.LastValue(), + }, + // TODO: Keep the old names for backwards compatibility, remove in the future { Name: "broadcaster_deposit", Measure: census.mDeposit, - Description: "Current remaining deposit for the broadcaster node", + Description: "Current remaining deposit for the gateway node", TagKeys: baseTagsWithEthAddr, Aggregation: view.LastValue(), }, { Name: "broadcaster_reserve", Measure: census.mReserve, - Description: "Current remaining reserve for the broadcaster node", + Description: "Current remaining reserve for the gateway node", TagKeys: baseTagsWithEthAddr, Aggregation: view.LastValue(), }, @@ -1533,7 +1548,7 @@ func PaymentCreateError(ctx context.Context) { } } -// Deposit records the current deposit for the broadcaster +// Deposit records the current deposit for the gateway func Deposit(sender string, deposit *big.Int) { if err := stats.RecordWithTags(census.ctx, []tag.Mutator{tag.Insert(census.kSender, sender)}, census.mDeposit.M(wei2gwei(deposit))); err != nil { From b739f354ce42d20d51c0778156999932dd8c2ae8 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sun, 19 May 2024 23:12:03 +0200 Subject: [PATCH 24/39] refactor: add -pricePerGateway and deprecate -pricePerBroadcaster (#3056) * refactor: add -pricePerGateway and deprecate -pricePerBroadcaster This commit adds the `pricePerGateway` flag and deprecates the `pricePerBroadcaster` flag per core team decision (details: https://discord.com/channels/423160867534929930/1051963444598943784/1210356864643109004). * chore: update pending changelog * refactor: remove redundant deprecation comment This commit removes the `PricePerBroadcaster` deprecation comment since this is already clear from the glog warning below. * fix: correct the `pricePerBroadcaster` flag check This commit ensures that the deprecation condition for the `pricePerBroadcaster` flag properly handles the default empty string value. * fix: ensure 'pricePerGateway' is used This commit ensures that the `pricePerGateway` is correctly used instead of the `pricePerBroadcaster` when it is set. * refactor: deprecate 'pricePerGateway' broadcasters property in favor of 'gateways' This commit updates the configuration to replace the `broadcasters` property specified under the `pricePerGateway` flag with `gateways`. Additionally, it ensures that a warning is issued when the deprecated property is still used. * test: fix TestParseGetBroadcasterPrices test This commit ensures that the TestParseGetBroadcasterPrices function uses the new getGatewayPrices function. * test: rename TestParseGetBroadcasterPrices to reflect Gateway naming This commit updates the `TestParseGetBroadcasterPrices` function to `TestParseGetGatewayPrices` to align with the new node naming convention. --- CHANGELOG_PENDING.md | 1 + cmd/livepeer/livepeer.go | 1 + cmd/livepeer/starter/starter.go | 50 +++++++++++++++++++--------- cmd/livepeer/starter/starter_test.go | 25 +++++++++----- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index bd4caf70d2..cd86a5c596 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -4,6 +4,7 @@ - [#3055](https://github.com/livepeer/go-livepeer/pull/3055) census: Rename broadcaster metrics to gateway metrics - [#3053](https://github.com/livepeer/go-livepeer/pull/3053) cli: add `-gateway` flag and deprecate `-broadcaster` flag. +- [#3056](https://github.com/livepeer/go-livepeer/pull/3056) cli: add `-pricePerGateway` flag and deprecate `-pricePerBroadcaster` flag. ### Breaking Changes 🚨🚨 diff --git a/cmd/livepeer/livepeer.go b/cmd/livepeer/livepeer.go index 0568b70836..0bf119b7bb 100755 --- a/cmd/livepeer/livepeer.go +++ b/cmd/livepeer/livepeer.go @@ -179,6 +179,7 @@ func parseLivepeerConfig() starter.LivepeerConfig { cfg.PixelsPerUnit = flag.String("pixelsPerUnit", *cfg.PixelsPerUnit, "Amount of pixels per unit. Set to '> 1' to have smaller price granularity than 1 wei / pixel") cfg.PriceFeedAddr = flag.String("priceFeedAddr", *cfg.PriceFeedAddr, "ETH address of the Chainlink price feed contract. Used for custom currencies conversion on -pricePerUnit or -maxPricePerUnit") cfg.AutoAdjustPrice = flag.Bool("autoAdjustPrice", *cfg.AutoAdjustPrice, "Enable/disable automatic price adjustments based on the overhead for redeeming tickets") + cfg.PricePerGateway = flag.String("pricePerGateway", *cfg.PricePerGateway, `json list of price per gateway or path to json config file. Example: {"broadcasters":[{"ethaddress":"address1","priceperunit":0.5,"currency":"USD","pixelsperunit":1000000000000},{"ethaddress":"address2","priceperunit":0.3,"currency":"USD","pixelsperunit":1000000000000}]}`) cfg.PricePerBroadcaster = flag.String("pricePerBroadcaster", *cfg.PricePerBroadcaster, `json list of price per broadcaster or path to json config file. Example: {"broadcasters":[{"ethaddress":"address1","priceperunit":0.5,"currency":"USD","pixelsperunit":1000000000000},{"ethaddress":"address2","priceperunit":0.3,"currency":"USD","pixelsperunit":1000000000000}]}`) // Interval to poll for blocks cfg.BlockPollingInterval = flag.Int("blockPollingInterval", *cfg.BlockPollingInterval, "Interval in seconds at which different blockchain event services poll for blocks") diff --git a/cmd/livepeer/starter/starter.go b/cmd/livepeer/starter/starter.go index 3ed6edfaa0..1053506bda 100755 --- a/cmd/livepeer/starter/starter.go +++ b/cmd/livepeer/starter/starter.go @@ -126,6 +126,7 @@ type LivepeerConfig struct { PixelsPerUnit *string PriceFeedAddr *string AutoAdjustPrice *bool + PricePerGateway *string PricePerBroadcaster *string BlockPollingInterval *int Redeemer *bool @@ -204,6 +205,7 @@ func DefaultLivepeerConfig() LivepeerConfig { defaultPixelsPerUnit := "1" defaultPriceFeedAddr := "0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612" // ETH / USD price feed address on Arbitrum Mainnet defaultAutoAdjustPrice := true + defaultPricePerGateway := "" defaultPricePerBroadcaster := "" defaultBlockPollingInterval := 5 defaultRedeemer := false @@ -292,6 +294,7 @@ func DefaultLivepeerConfig() LivepeerConfig { PixelsPerUnit: &defaultPixelsPerUnit, PriceFeedAddr: &defaultPriceFeedAddr, AutoAdjustPrice: &defaultAutoAdjustPrice, + PricePerGateway: &defaultPricePerGateway, PricePerBroadcaster: &defaultPricePerBroadcaster, BlockPollingInterval: &defaultBlockPollingInterval, Redeemer: &defaultRedeemer, @@ -784,7 +787,11 @@ func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { } n.SetBasePrice("default", autoPrice) - broadcasterPrices := getBroadcasterPrices(*cfg.PricePerBroadcaster) + if *cfg.PricePerBroadcaster != "" { + glog.Warning("-PricePerBroadcaster flag is deprecated and will be removed in a future release. Please use -PricePerGateway instead") + cfg.PricePerGateway = cfg.PricePerBroadcaster + } + broadcasterPrices := getGatewayPrices(*cfg.PricePerGateway) for _, p := range broadcasterPrices { p := p pricePerPixel := new(big.Rat).Quo(p.PricePerUnit, p.PixelsPerUnit) @@ -1482,51 +1489,64 @@ func checkOrStoreChainID(dbh *common.DB, chainID *big.Int) error { return nil } -type BroadcasterPrice struct { +type GatewayPrice struct { EthAddress string PricePerUnit *big.Rat Currency string PixelsPerUnit *big.Rat } -func getBroadcasterPrices(broadcasterPrices string) []BroadcasterPrice { - if broadcasterPrices == "" { +func getGatewayPrices(gatewayPrices string) []GatewayPrice { + if gatewayPrices == "" { return nil } // Format of broadcasterPrices json - // {"broadcasters":[{"ethaddress":"address1","priceperunit":0.5,"currency":"USD","pixelsperunit":1}, {"ethaddress":"address2","priceperunit":0.3,"currency":"USD","pixelsperunit":3}]} + // {"gateways":[{"ethaddress":"address1","priceperunit":0.5,"currency":"USD","pixelsperunit":1}, {"ethaddress":"address2","priceperunit":0.3,"currency":"USD","pixelsperunit":3}]} var pricesSet struct { + Gateways []struct { + EthAddress string `json:"ethaddress"` + PixelsPerUnit json.RawMessage `json:"pixelsperunit"` + PricePerUnit json.RawMessage `json:"priceperunit"` + Currency string `json:"currency"` + } `json:"gateways"` + // TODO: Keep the old name for backwards compatibility, remove in the future Broadcasters []struct { - EthAddress string `json:"ethaddress"` - // The fields below are specified as a number in the JSON, but we don't want to lose precision so we store the raw characters here and parse as a big.Rat. - // This also allows support for exponential notation for numbers, which is helpful for pricePerUnit which could be a value like 1e12. + EthAddress string `json:"ethaddress"` PixelsPerUnit json.RawMessage `json:"pixelsperunit"` PricePerUnit json.RawMessage `json:"priceperunit"` Currency string `json:"currency"` } `json:"broadcasters"` } - pricesFileContent, _ := common.ReadFromFile(broadcasterPrices) + pricesFileContent, _ := common.ReadFromFile(gatewayPrices) err := json.Unmarshal([]byte(pricesFileContent), &pricesSet) if err != nil { - glog.Errorf("broadcaster prices could not be parsed: %s", err) + glog.Errorf("gateway prices could not be parsed: %s", err) return nil } - prices := make([]BroadcasterPrice, len(pricesSet.Broadcasters)) - for i, p := range pricesSet.Broadcasters { + // Check if broadcasters field is used and display a warning + if len(pricesSet.Broadcasters) > 0 { + glog.Warning("The 'broadcaster' property in the 'pricePerGateway' config is deprecated and will be removed in a future release. Please use 'gateways' instead.") + } + + // Combine broadcasters and gateways into a single slice + allGateways := append(pricesSet.Broadcasters, pricesSet.Gateways...) + + prices := make([]GatewayPrice, len(allGateways)) + for i, p := range allGateways { pixelsPerUnit, ok := new(big.Rat).SetString(string(p.PixelsPerUnit)) if !ok { - glog.Errorf("Pixels per unit could not be parsed for broadcaster %v. must be a valid number, provided %s", p.EthAddress, p.PixelsPerUnit) + glog.Errorf("Pixels per unit could not be parsed for gateway %v. must be a valid number, provided %s", p.EthAddress, p.PixelsPerUnit) continue } pricePerUnit, ok := new(big.Rat).SetString(string(p.PricePerUnit)) if !ok { - glog.Errorf("Price per unit could not be parsed for broadcaster %v. must be a valid number, provided %s", p.EthAddress, p.PricePerUnit) + glog.Errorf("Price per unit could not be parsed for gateway %v. must be a valid number, provided %s", p.EthAddress, p.PricePerUnit) continue } - prices[i] = BroadcasterPrice{ + prices[i] = GatewayPrice{ EthAddress: p.EthAddress, Currency: p.Currency, PricePerUnit: pricePerUnit, diff --git a/cmd/livepeer/starter/starter_test.go b/cmd/livepeer/starter/starter_test.go index 45d3620b8e..60df927897 100644 --- a/cmd/livepeer/starter/starter_test.go +++ b/cmd/livepeer/starter/starter_test.go @@ -2,6 +2,7 @@ package starter import ( "errors" + "fmt" "math/big" "os" "path/filepath" @@ -87,19 +88,25 @@ func TestIsLocalURL(t *testing.T) { assert.False(isLocal) } -func TestParseGetBroadcasterPrices(t *testing.T) { +func TestParseGetGatewayPrices(t *testing.T) { assert := assert.New(t) - j := `{"broadcasters":[{"ethaddress":"0x0000000000000000000000000000000000000000","priceperunit":1000,"pixelsperunit":1}, {"ethaddress":"0x1000000000000000000000000000000000000000","priceperunit":2000,"pixelsperunit":3}]}` + // TODO: Keep checking old field for backwards compatibility, remove in future + jsonTemplate := `{"%s":[{"ethaddress":"0x0000000000000000000000000000000000000000","priceperunit":1000,"pixelsperunit":1}, {"ethaddress":"0x1000000000000000000000000000000000000000","priceperunit":2000,"pixelsperunit":3}]}` + testCases := []string{"gateways", "broadcasters"} - prices := getBroadcasterPrices(j) - assert.NotNil(prices) - assert.Equal(2, len(prices)) + for _, tc := range testCases { + jsonStr := fmt.Sprintf(jsonTemplate, tc) - price1 := new(big.Rat).Quo(prices[0].PricePerUnit, prices[0].PixelsPerUnit) - price2 := new(big.Rat).Quo(prices[1].PricePerUnit, prices[1].PixelsPerUnit) - assert.Equal(big.NewRat(1000, 1), price1) - assert.Equal(big.NewRat(2000, 3), price2) + prices := getGatewayPrices(jsonStr) + assert.NotNil(prices) + assert.Equal(2, len(prices)) + + price1 := new(big.Rat).Quo(prices[0].PricePerUnit, prices[0].PixelsPerUnit) + price2 := new(big.Rat).Quo(prices[1].PricePerUnit, prices[1].PixelsPerUnit) + assert.Equal(big.NewRat(1000, 1), price1) + assert.Equal(big.NewRat(2000, 3), price2) + } } // Address provided to keystore file From 6cfaf1e619da499b9509c268b01a9d2dbb11516b Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 21 May 2024 09:01:33 +0200 Subject: [PATCH 25/39] ci: protect Docker 'stable' tag (#3062) This commit introduces a safeguard to ensure that the Docker image tagged as 'stable' is only pushed when a new tag is created on the stable branch. This prevents unintended updates to the stable Docker image, ensuring consistency and reliability for users relying on the stable tag. --- .github/workflows/docker.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 6661c9dc03..05b64262f1 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -81,7 +81,7 @@ jobs: type=semver,pattern={{major}}.{{minor}},prefix=v type=raw,value=latest,enable={{is_default_branch}} type=raw,value=${{ github.event.pull_request.head.ref }} - type=raw,value=stable,enable=${{ startsWith(github.event.ref, 'refs/tags/v') }} + type=raw,value=stable,enable=${{ startsWith(github.event.ref, 'refs/tags/v') && is_default_branch }} - name: Build and push livepeer docker image uses: docker/build-push-action@v5 From fbb393e3fdc899eb6d2232afa6952a52904eba75 Mon Sep 17 00:00:00 2001 From: Thom Shutt Date: Tue, 28 May 2024 11:21:47 +0100 Subject: [PATCH 26/39] Return appropriate errors when auth fails, not just 5xx (#3065) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Return appropriate errors when auth fails, not just 5xx * Fix unit tests for new signature * Fix remaining tests * Fix another test * Refactor Forbidden to error type * Refactor Forbidden to error type --------- Co-authored-by: RafaΕ‚ Leszko --- go.mod | 4 +- go.sum | 12 +--- server/mediaserver.go | 61 +++++++++++-------- server/mediaserver_test.go | 118 ++++++++++++++++++++++++++----------- server/push_test.go | 2 +- 5 files changed, 126 insertions(+), 71 deletions(-) diff --git a/go.mod b/go.mod index 42eef47297..54396951d9 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( contrib.go.opencensus.io/exporter/prometheus v0.4.2 + github.com/Masterminds/semver/v3 v3.2.1 github.com/cenkalti/backoff v2.2.1+incompatible github.com/ethereum/go-ethereum v1.13.5 github.com/golang/glog v1.1.1 @@ -13,7 +14,7 @@ require ( github.com/jaypipes/pcidb v1.0.0 github.com/livepeer/go-tools v0.0.0-20220805063103-76df6beb6506 github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18 - github.com/livepeer/lpms v0.0.0-20240513161533-11a5584d691d + github.com/livepeer/lpms v0.0.0-20240528070257-343a3ddb3748 github.com/livepeer/m3u8 v0.11.1 github.com/mattn/go-sqlite3 v1.14.18 github.com/olekukonko/tablewriter v0.0.5 @@ -41,7 +42,6 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/DataDog/zstd v1.4.5 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.1 // indirect github.com/StackExchange/wmi v1.2.1 // indirect diff --git a/go.sum b/go.sum index 6a79bae3e1..866e8b20bc 100644 --- a/go.sum +++ b/go.sum @@ -297,8 +297,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -448,12 +446,8 @@ github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded h1:ZQlvR5RB4nfT+cO github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded/go.mod h1:xkDdm+akniYxVT9KW1Y2Y7Hso6aW+rZObz3nrA9yTHw= github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18 h1:4oH3NqV0NvcdS44Ld3zK2tO8IUiNozIggm74yobQeZg= github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18/go.mod h1:Jpf4jHK+fbWioBHRDRM1WadNT1qmY27g2YicTdO0Rtc= -github.com/livepeer/lpms v0.0.0-20240115103113-98566e26c007 h1:0xr1TeIanBDdzI3sE2Zgf2yEV3s+6cPo3lJeyOHKmtM= -github.com/livepeer/lpms v0.0.0-20240115103113-98566e26c007/go.mod h1:Hr/JhxxPDipOVd4ZrGYWrdJfpVF8/SEI0nNr2ctAlkM= -github.com/livepeer/lpms v0.0.0-20240402101153-ced71c476bd0 h1:Ch+HRjVJHpNo3kySGJgyDqb+l0KPWehyqZfA1wOafgY= -github.com/livepeer/lpms v0.0.0-20240402101153-ced71c476bd0/go.mod h1:z5ROP1l5OzAKSoqVRLc34MjUdueil6wHSecQYV7llIw= -github.com/livepeer/lpms v0.0.0-20240513161533-11a5584d691d h1:RehRsei/f2mv1RCWD1e3FWRkPl/+eKlHq6syU9c4WJE= -github.com/livepeer/lpms v0.0.0-20240513161533-11a5584d691d/go.mod h1:z5ROP1l5OzAKSoqVRLc34MjUdueil6wHSecQYV7llIw= +github.com/livepeer/lpms v0.0.0-20240528070257-343a3ddb3748 h1:sucdljv+Wjo24WbuHYNFFzjRFsKlSj/s9bn7qdCkG/Y= +github.com/livepeer/lpms v0.0.0-20240528070257-343a3ddb3748/go.mod h1:z5ROP1l5OzAKSoqVRLc34MjUdueil6wHSecQYV7llIw= github.com/livepeer/m3u8 v0.11.1 h1:VkUJzfNTyjy9mqsgp5JPvouwna8wGZMvd/gAfT5FinU= github.com/livepeer/m3u8 v0.11.1/go.mod h1:IUqAtwWPAG2CblfQa4SVzTQoDcEMPyfNOaBSxqHMS04= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -1081,8 +1075,6 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/server/mediaserver.go b/server/mediaserver.go index 7f57e6b823..168686525c 100644 --- a/server/mediaserver.go +++ b/server/mediaserver.go @@ -44,12 +44,15 @@ import ( "github.com/patrickmn/go-cache" ) -var errAlreadyExists = errors.New("StreamAlreadyExists") -var errStorage = errors.New("ErrStorage") -var errDiscovery = errors.New("ErrDiscovery") -var errNoOrchs = errors.New("ErrNoOrchs") -var errUnknownStream = errors.New("ErrUnknownStream") -var errMismatchedParams = errors.New("Mismatched type for stream params") +var ( + errAlreadyExists = errors.New("StreamAlreadyExists") + errStorage = errors.New("ErrStorage") + errDiscovery = errors.New("ErrDiscovery") + errNoOrchs = errors.New("ErrNoOrchs") + errUnknownStream = errors.New("ErrUnknownStream") + errMismatchedParams = errors.New("Mismatched type for stream params") + errForbidden = errors.New("authentication denied") +) const HLSWaitInterval = time.Second const HLSBufferCap = uint(43200) //12 hrs assuming 1s segment @@ -233,8 +236,8 @@ func (s *LivepeerServer) StartMediaServer(ctx context.Context, httpAddr string) } // RTMP Publish Handlers -func createRTMPStreamIDHandler(_ctx context.Context, s *LivepeerServer, webhookResponseOverride *authWebhookResponse) func(url *url.URL) (strmID stream.AppData) { - return func(url *url.URL) (strmID stream.AppData) { +func createRTMPStreamIDHandler(_ctx context.Context, s *LivepeerServer, webhookResponseOverride *authWebhookResponse) func(url *url.URL) (strmID stream.AppData, e error) { + return func(url *url.URL) (strmID stream.AppData, e error) { //Check HTTP header for ManifestID //If ManifestID is passed in HTTP header, use that one //Else check webhook for ManifestID @@ -256,8 +259,8 @@ func createRTMPStreamIDHandler(_ctx context.Context, s *LivepeerServer, webhookR // do not replace captured _ctx variable ctx := clog.AddNonce(_ctx, nonce) if resp, err = authenticateStream(AuthWebhookURL, url.String()); err != nil { - clog.Errorf(ctx, "Authentication denied for streamID url=%s err=%q", url.String(), err) - return nil + clog.Errorf(ctx, fmt.Sprintf("Forbidden: Authentication denied for streamID url=%s err=%q", url.String(), err)) + return nil, errForbidden } // If we've received auth in header AND callback URL forms then for now, we reject cases where they're @@ -265,7 +268,7 @@ func createRTMPStreamIDHandler(_ctx context.Context, s *LivepeerServer, webhookR if resp != nil && webhookResponseOverride != nil { if !resp.areProfilesEqual(*webhookResponseOverride) { clog.Errorf(ctx, "Received auth header with profiles that don't match those in callback URL response") - return nil + return nil, fmt.Errorf("Received auth header with profiles that don't match those in callback URL response") } } @@ -287,8 +290,9 @@ func createRTMPStreamIDHandler(_ctx context.Context, s *LivepeerServer, webhookR parsedProfiles, err := ffmpeg.ParseProfilesFromJsonProfileArray(resp.Profiles) if err != nil { - clog.Errorf(ctx, "Failed to parse JSON video profile for streamID url=%s err=%q", url.String(), err) - return nil + errMsg := fmt.Sprintf("Failed to parse JSON video profile for streamID url=%s err=%q", url.String(), err) + clog.Errorf(ctx, errMsg) + return nil, fmt.Errorf(errMsg) } profiles = append(profiles, parsedProfiles...) @@ -301,16 +305,18 @@ func createRTMPStreamIDHandler(_ctx context.Context, s *LivepeerServer, webhookR if resp.ObjectStore != "" { os, err = drivers.ParseOSURL(resp.ObjectStore, false) if err != nil { - clog.Errorf(ctx, "Failed to parse object store url for streamID url=%s err=%q", url.String(), err) - return nil + errMsg := fmt.Sprintf("Failed to parse object store url for streamID url=%s err=%q", url.String(), err) + clog.Errorf(ctx, errMsg) + return nil, fmt.Errorf(errMsg) } } // set Recording OS if it was provided if resp.RecordObjectStore != "" { ros, err = drivers.ParseOSURL(resp.RecordObjectStore, true) if err != nil { - clog.Errorf(ctx, "Failed to parse recording object store url for streamID url=%s err=%q", url.String(), err) - return nil + errMsg := fmt.Sprintf("Failed to parse recording object store url for streamID url=%s err=%q", url.String(), err) + clog.Errorf(ctx, errMsg) + return nil, fmt.Errorf(errMsg) } } @@ -346,8 +352,10 @@ func createRTMPStreamIDHandler(_ctx context.Context, s *LivepeerServer, webhookR s.connectionLock.RLock() defer s.connectionLock.RUnlock() if core.MaxSessions > 0 && len(s.rtmpConnections) >= core.MaxSessions { - clog.Errorf(ctx, "Too many connections for streamID url=%s err=%q", url.String(), err) - return nil + errMsg := fmt.Sprintf("Too many connections for streamID url=%s err=%q", url.String(), err) + clog.Errorf(ctx, errMsg) + return nil, fmt.Errorf(errMsg) + } return &core.StreamParameters{ ManifestID: mid, @@ -360,7 +368,7 @@ func createRTMPStreamIDHandler(_ctx context.Context, s *LivepeerServer, webhookR RecordOS: ross, VerificationFreq: VerificationFreq, Nonce: nonce, - } + }, nil } } @@ -820,10 +828,15 @@ func (s *LivepeerServer) HandlePush(w http.ResponseWriter, r *http.Request) { // Check for presence and register if a fresh cxn if !exists { - appData := (createRTMPStreamIDHandler(ctx, s, authHeaderConfig))(r.URL) - if appData == nil { - errorOut(http.StatusInternalServerError, "Could not create stream ID: url=%s", r.URL) - return + appData, err := (createRTMPStreamIDHandler(ctx, s, authHeaderConfig))(r.URL) + if err != nil { + if errors.Is(err, errForbidden) { + errorOut(http.StatusForbidden, "Could not create stream ID: url=%s", r.URL) + return + } else { + errorOut(http.StatusInternalServerError, "Could not create stream ID: url=%s", r.URL) + return + } } params := streamParams(appData) if authHeaderConfig != nil { diff --git a/server/mediaserver_test.go b/server/mediaserver_test.go index 79b4f611fb..595c4e29ab 100644 --- a/server/mediaserver_test.go +++ b/server/mediaserver_test.go @@ -438,7 +438,9 @@ func TestCreateRTMPStreamHandlerCap(t *testing.T) { oldMaxSessions := core.MaxSessions core.MaxSessions = 1 // happy case - sid := createSid(u).(*core.StreamParameters) + id, err := createSid(u) + require.NoError(t, err) + sid := id.(*core.StreamParameters) mid := sid.ManifestID if mid != "id1" { t.Error("Stream should be allowd", sid) @@ -448,7 +450,8 @@ func TestCreateRTMPStreamHandlerCap(t *testing.T) { } s.rtmpConnections[core.ManifestID("id1")] = nil // capped case - params := createSid(u) + params, err := createSid(u) + require.Error(t, err) if params != nil { t.Error("Stream should be denied because of capacity cap") } @@ -460,7 +463,7 @@ type authWebhookReq struct { } func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { - assert := assert.New(t) + assert := require.New(t) s, cancel := setupServerWithCancel() defer serverCleanup(s) defer cancel() @@ -469,7 +472,8 @@ func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { AuthWebhookURL = mustParseUrl(t, "http://localhost:8938/notexisting") u := mustParseUrl(t, "http://hot/something/id1") - sid := createSid(u) + sid, err := createSid(u) + assert.Error(err) assert.Nil(sid, "Webhook auth failed") ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -486,7 +490,8 @@ func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { })) defer ts.Close() AuthWebhookURL = mustParseUrl(t, ts.URL) - sid = createSid(u) + sid, err = createSid(u) + assert.NoError(err) assert.NotNil(sid, "On empty response with 200 code should pass") // local helper to reduce boilerplate @@ -503,19 +508,23 @@ func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { // empty manifestID ts2 := makeServer(`{"manifestID":""}`) defer ts2.Close() - sid = createSid(u) + sid, err = createSid(u) + assert.Error(err) assert.Nil(sid, "Should not pass if returned manifest id is empty") // invalid json ts3 := makeServer(`{manifestID:"XX"}`) defer ts3.Close() - sid = createSid(u) + sid, err = createSid(u) + assert.Error(err) assert.Nil(sid, "Should not pass if returned json is invalid") // set manifestID ts4 := makeServer(`{"manifestID":"xy"}`) defer ts4.Close() - params := createSid(u).(*core.StreamParameters) + p, err := createSid(u) + assert.NoError(err) + params := p.(*core.StreamParameters) mid := params.ManifestID assert.Equal(core.ManifestID("xy"), mid, "Should set manifest id to one provided by webhook") @@ -526,7 +535,9 @@ func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { // set manifestID + streamKey ts5 := makeServer(`{"manifestID":"xyz", "streamKey":"zyx"}`) defer ts5.Close() - params = createSid(u).(*core.StreamParameters) + id, err := createSid(u) + require.NoError(t, err) + params = id.(*core.StreamParameters) mid = params.ManifestID assert.Equal(core.ManifestID("xyz"), mid, "Should set manifest to one provided by webhook") assert.Equal("xyz/zyx", params.StreamID(), "Should set streamkey to one provided by webhook") @@ -535,7 +546,9 @@ func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { // set presets (with some invalid) ts6 := makeServer(`{"manifestID":"a", "presets":["P240p30fps16x9", "unknown", "P720p30fps16x9"]}`) defer ts6.Close() - params = createSid(u).(*core.StreamParameters) + strmID, err := createSid(u) + require.NoError(t, err) + params = strmID.(*core.StreamParameters) assert.Len(params.Profiles, 2) assert.Equal(params.Profiles, []ffmpeg.VideoProfile{ffmpeg.P240p30fps16x9, ffmpeg.P720p30fps16x9}, "Did not have matching presets") @@ -547,7 +560,9 @@ func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { {"name": "passthru_fps", "bitrate": 890, "width": 789, "height": 654, "profile": "H264ConstrainedHigh", "gop":"123"}, {"name": "gop0", "bitrate": 800, "width": 400, "height": 220, "profile": "H264ConstrainedHigh", "gop":"0.0"}]}`) defer ts7.Close() - params = createSid(u).(*core.StreamParameters) + data, err := createSid(u) + require.NoError(t, err) + params = data.(*core.StreamParameters) assert.Len(params.Profiles, 4) expectedProfiles := []ffmpeg.VideoProfile{ @@ -597,7 +612,9 @@ func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { {"name": "prof1", "bitrate": 432, "fps": 560, "width": 123, "height": 456}, {"name": "prof2", "bitrate": 765, "fps": 876, "width": 456, "height": "hello"}]}`) defer ts8.Close() - params, ok := createSid(u).(*core.StreamParameters) + appData, err := createSid(u) + require.Error(t, err) + params, ok := appData.(*core.StreamParameters) assert.False(ok) assert.Nil(params) @@ -609,7 +626,9 @@ func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { {"name": "gop0", "bitrate": 800, "width": 400, "height": 220, "profile": "H264ConstrainedHigh", "gop":"0.0"}]}`) defer ts9.Close() - params = createSid(u).(*core.StreamParameters) + i, err := createSid(u) + require.NoError(t, err) + params = i.(*core.StreamParameters) jointProfiles := append([]ffmpeg.VideoProfile{ffmpeg.P240p30fps16x9, ffmpeg.P720p30fps16x9}, expectedProfiles...) assert.Len(params.Profiles, 6) @@ -618,7 +637,9 @@ func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { // all invalid presets in webhook should lead to empty set ts10 := makeServer(`{"manifestID":"a", "presets":["very", "unknown"]}`) defer ts10.Close() - params = createSid(u).(*core.StreamParameters) + id2, err := createSid(u) + require.NoError(t, err) + params = id2.(*core.StreamParameters) assert.Len(params.Profiles, 0, "Unexpected value in presets") // invalid gops @@ -636,25 +657,31 @@ func TestCreateRTMPStreamHandlerWebhook(t *testing.T) { // intra only gop ts14 := makeServer(`{"manifestID":"a", "profiles": [ {"gop": "intra" }]}`) defer ts14.Close() - params = createSid(u).(*core.StreamParameters) + id3, err := createSid(u) + require.NoError(t, err) + params = id3.(*core.StreamParameters) assert.Len(params.Profiles, 1) assert.Equal(ffmpeg.GOPIntraOnly, params.Profiles[0].GOP) // do not create stream if ObjectStore URL is invalid ts15 := makeServer(`{"manifestID":"a2", "objectStore": "invalid://object.store", "recordObjectStore": ""}`) defer ts15.Close() - sid = createSid(u) + sid, err = createSid(u) + require.Error(t, err) assert.Nil(sid) // do not create stream if RecordObjectStore URL is invalid ts16 := makeServer(`{"manifestID":"a2", "objectStore": "", "recordObjectStore": "invalid://object.store"}`) defer ts16.Close() - sid = createSid(u) + sid, err = createSid(u) + require.Error(t, err) assert.Nil(sid) ts17 := makeServer(`{"manifestID":"a3", "objectStore": "s3+http://us:pass@object.store/path", "recordObjectStore": "s3+http://us:pass@record.store"}`) defer ts17.Close() - params = createSid(u).(*core.StreamParameters) + id4, err := createSid(u) + require.NoError(t, err) + params = id4.(*core.StreamParameters) assert.Equal(core.ManifestID("a3"), params.ManifestID) assert.NotNil(params.OS) assert.True(params.OS.IsExternal()) @@ -689,30 +716,41 @@ func TestCreateRTMPStreamHandler(t *testing.T) { u := mustParseUrl(t, "rtmp://localhost/"+expectedSid.String()) // with key rand.Seed(123) - sid := createSid(u) + sid, err := createSid(u) + require.NoError(t, err) sap := sid.(*core.StreamParameters) assert.Equal(t, uint64(0x4a68998bed5c40f1), sap.Nonce) - if sid := createSid(u); sid.StreamID() != expectedSid.String() { + sid, err = createSid(u) + require.NoError(t, err) + if sid.StreamID() != expectedSid.String() { t.Error("Unexpected streamid", sid.StreamID()) } u = mustParseUrl(t, "rtmp://localhost/stream/"+expectedSid.String()) // with stream - if sid := createSid(u); sid.StreamID() != expectedSid.String() { + sid, err = createSid(u) + require.NoError(t, err) + if sid.StreamID() != expectedSid.String() { t.Error("Unexpected streamid") } expectedMid := "mnopq" key := common.RandomIDGenerator(StreamKeyBytes) u = mustParseUrl(t, "rtmp://localhost/"+string(expectedMid)) // without key - if sid := createSid(u); sid.StreamID() != string(expectedMid)+"/"+key { + sid, err = createSid(u) + require.NoError(t, err) + if sid.StreamID() != string(expectedMid)+"/"+key { t.Error("Unexpected streamid", sid.StreamID()) } u = mustParseUrl(t, "rtmp://localhost/stream/"+string(expectedMid)) // with stream, without key - if sid := createSid(u); sid.StreamID() != string(expectedMid)+"/"+key { + sid, err = createSid(u) + require.NoError(t, err) + if sid.StreamID() != string(expectedMid)+"/"+key { t.Error("Unexpected streamid", sid.StreamID()) } // Test normal case u = mustParseUrl(t, "rtmp://localhost") - st := stream.NewBasicRTMPVideoStream(createSid(u)) + id, err := createSid(u) + require.NoError(t, err) + st := stream.NewBasicRTMPVideoStream(id) if st.GetStreamID() == "" { t.Error("Empty streamid") } @@ -721,14 +759,18 @@ func TestCreateRTMPStreamHandler(t *testing.T) { t.Error("Handler failed ", err) } // Test collisions via stream reuse - if sid := createSid(u); sid == nil { + sid, err = createSid(u) + require.NoError(t, err) + if sid == nil { t.Error("Did not expect a failure due to naming collision") } // Ensure the stream ID is reusable after the stream ends if err := endHandler(u, st); err != nil { t.Error("Could not clean up stream") } - if sid := createSid(u); sid.StreamID() != st.GetStreamID() { + sid, err = createSid(u) + require.NoError(t, err) + if sid.StreamID() != st.GetStreamID() { t.Error("Mismatched streamid during stream reuse", sid.StreamID(), st.GetStreamID()) } @@ -739,7 +781,9 @@ func TestCreateRTMPStreamHandler(t *testing.T) { // This isn't a great test because if the query param ever changes, // this test will still pass u := mustParseUrl(t, "rtmp://localhost/"+inp) - if sid := createSid(u); sid.StreamID() != st.GetStreamID() { + sid, err = createSid(u) + require.NoError(t, err) + if sid.StreamID() != st.GetStreamID() { t.Errorf("Unexpected StreamID for '%v' ; expected '%v' for input '%v'", sid, st.GetStreamID(), inp) } } @@ -804,7 +848,8 @@ func TestCreateRTMPStreamHandlerWithAuthHeader(t *testing.T) { expectedSid := core.MakeStreamIDFromString("override-manifest-id", "abcdef") u := mustParseUrl(t, "rtmp://localhost/"+expectedSid.String()) // with key - sid := createSid(u) + sid, err := createSid(u) + require.NoError(t, err) require.NotNil(t, sid) require.Equal(t, expectedSid.String(), sid.StreamID()) @@ -874,7 +919,8 @@ func TestCreateRTMPStreamHandlerWithAuthHeader_DifferentProfilesToCallbackURL(t expectedSid := core.MakeStreamIDFromString("override-manifest-id", "abcdef") u := mustParseUrl(t, "rtmp://localhost/"+expectedSid.String()) // with key - sid := createSid(u) + sid, err := createSid(u) + require.Error(t, err) require.Nil(t, sid) } @@ -887,7 +933,8 @@ func TestEndRTMPStreamHandler(t *testing.T) { handler := gotRTMPStreamHandler(s) endHandler := endRTMPStreamHandler(s) u := mustParseUrl(t, "rtmp://localhost") - sid := createSid(u) + sid, err := createSid(u) + require.NoError(t, err) st := stream.NewBasicRTMPVideoStream(sid) // Nonexistent stream @@ -998,7 +1045,9 @@ func TestMultiStream(t *testing.T) { createSid := createRTMPStreamIDHandler(context.TODO(), s, nil) handleStream := func(i int) { - st := stream.NewBasicRTMPVideoStream(createSid(u)) + id, err := createSid(u) + require.NoError(t, err) + st := stream.NewBasicRTMPVideoStream(id) if err := handler(u, st); err != nil { t.Error("Could not handle stream ", i, err) } @@ -1229,7 +1278,8 @@ func TestBroadcastSessionManagerWithStreamStartStop(t *testing.T) { // create BasicRTMPVideoStream and extract ManifestID u := mustParseUrl(t, "rtmp://localhost") - sid := createSid(u) + sid, err := createSid(u) + assert.NoError(err) st := stream.NewBasicRTMPVideoStream(sid) mid := streamParams(st.AppData()).ManifestID @@ -1238,8 +1288,8 @@ func TestBroadcastSessionManagerWithStreamStartStop(t *testing.T) { assert.Equal(exists, false) // assert stream starts successfully - err := handler(u, st) - assert.Nil(err) + err = handler(u, st) + assert.NoError(err) // assert sessManager is running and has right number of sessions cxn, exists := s.rtmpConnections[mid] diff --git a/server/push_test.go b/server/push_test.go index b5d0817e0c..bb17ac8a11 100644 --- a/server/push_test.go +++ b/server/push_test.go @@ -1037,7 +1037,7 @@ func TestPush_ForAuthWebhookFailure(t *testing.T) { body, err := ioutil.ReadAll(resp.Body) require.Nil(t, err) - assert.Equal(http.StatusInternalServerError, resp.StatusCode) + assert.Equal(http.StatusForbidden, resp.StatusCode) assert.Contains(strings.TrimSpace(string(body)), "Could not create stream ID") } From 29732e7f879b22070b67879c14c1d815aa863e8c Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Wed, 29 May 2024 16:58:11 +0200 Subject: [PATCH 27/39] ci: fix syntax error in Docker action tags (#3068) * ci: fix syntax error in Docker action tags This commit addresses a syntax error in the Docker image tag creation step. * ci(docker): ensure stable tag is created on master branch This commit ensures that the stable tag is created on the master branch. --- .github/workflows/docker.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 05b64262f1..44dd48fa14 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -81,7 +81,7 @@ jobs: type=semver,pattern={{major}}.{{minor}},prefix=v type=raw,value=latest,enable={{is_default_branch}} type=raw,value=${{ github.event.pull_request.head.ref }} - type=raw,value=stable,enable=${{ startsWith(github.event.ref, 'refs/tags/v') && is_default_branch }} + type=raw,value=stable,enable=${{ startsWith(github.event.ref, 'refs/tags/v') && github.event.base_ref == 'refs/heads/master' }} - name: Build and push livepeer docker image uses: docker/build-push-action@v5 From e8f079e3af2464e582f93c7786b5aa0ac88944ab Mon Sep 17 00:00:00 2001 From: linghuying <1599935829@qq.com> Date: Sat, 1 Jun 2024 20:09:19 +0800 Subject: [PATCH 28/39] chore: fix some comments (#3070) Signed-off-by: linghuying <1599935829@qq.com> --- cmd/devtool/devtool.go | 2 +- pm/recipient.go | 2 +- pm/sender.go | 2 +- pm/stub.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/devtool/devtool.go b/cmd/devtool/devtool.go index e106e30444..ffd696427e 100644 --- a/cmd/devtool/devtool.go +++ b/cmd/devtool/devtool.go @@ -61,7 +61,7 @@ func main() { if !goodToGo { fmt.Println(` Usage: go run cmd/devtool/devtool.go setup broadcaster|transcoder [nodeIndex] - It will create initilize eth account (on private testnet) to be used for broadcaster or transcoder + It will create initialize eth account (on private testnet) to be used for broadcaster or transcoder and will create shell script (run_broadcaster_ETHACC.sh or run_transcoder_ETHACC.sh) to run it. Node index indicates how much to offset node's port. Orchestrator node's index by default is 1. For example: diff --git a/pm/recipient.go b/pm/recipient.go index 1c2333a5bb..4c20281756 100644 --- a/pm/recipient.go +++ b/pm/recipient.go @@ -43,7 +43,7 @@ type Recipient interface { RedeemWinningTicket(ticket *Ticket, sig []byte, seed *big.Int) error // TicketParams returns the recipient's currently accepted ticket parameters - // for a provided sender ETH adddress + // for a provided sender ETH address TicketParams(sender ethcommon.Address, price *big.Rat) (*TicketParams, error) // TxCostMultiplier returns the tx cost multiplier for an address diff --git a/pm/sender.go b/pm/sender.go index db178bfc5b..6f6acf0fd4 100644 --- a/pm/sender.go +++ b/pm/sender.go @@ -113,7 +113,7 @@ func (s *sender) CreateTicketBatch(sessionID string, size int) (*TicketBatch, er ticketParams := &session.ticketParams expirationParams := ticketParams.ExpirationParams - // Ensure backwards compatbility + // Ensure backwards compatibility // If no expirationParams are included by O // B sets the values based upon its last seen round if expirationParams == nil || expirationParams.CreationRound == 0 || expirationParams.CreationRoundBlockHash == (ethcommon.Hash{}) { diff --git a/pm/stub.go b/pm/stub.go index 856bb9416f..a3e0f7f224 100644 --- a/pm/stub.go +++ b/pm/stub.go @@ -466,7 +466,7 @@ func (m *MockRecipient) RedeemWinningTicket(ticket *Ticket, sig []byte, seed *bi } // TicketParams returns the recipient's currently accepted ticket parameters -// for a provided sender ETH adddress +// for a provided sender ETH address func (m *MockRecipient) TicketParams(sender ethcommon.Address, price *big.Rat) (*TicketParams, error) { args := m.Called(sender, price) From 65f501ac541d1b5c0aea9e7258ba75accad538a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Tue, 11 Jun 2024 13:33:25 +0200 Subject: [PATCH 29/39] Add logging to selection_algorithm.go (#3076) * Add logging to selection_algorithm.go * Add even more logging --- server/selection_algorithm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/selection_algorithm.go b/server/selection_algorithm.go index 54aebb0e65..9264922046 100644 --- a/server/selection_algorithm.go +++ b/server/selection_algorithm.go @@ -49,7 +49,7 @@ func (sa ProbabilitySelectionAlgorithm) filterByPerfScore(addrs []ethcommon.Addr if len(res) == 0 { // If no orchestrators pass the perf filter, return all Orchestrators. // That may mean some issues with the PerfScore service. - glog.Warning("No Orchestrators passed min performance score filter, not using the filter") + glog.Warning("No Orchestrators passed min performance score filter, not using the filter, numAddrs=%d, minPerfScore=%v, scores=%v, addrs=%v", len(addrs), sa.MinPerfScore, scores, addrs) return addrs } return res @@ -72,7 +72,7 @@ func (sa ProbabilitySelectionAlgorithm) filterByMaxPrice(addrs []ethcommon.Addre if len(res) == 0 { // If no orchestrators pass the filter, return all Orchestrators // It means that no orchestrators are below the max price - glog.Warning("No Orchestrators passed max price filter, not using the filter") + glog.Warning("No Orchestrators passed max price filter, not using the filter, numAddrs=%d, maxPrice=%v, prices=%v, addrs=%v", len(addrs), maxPrice, prices, addrs) return addrs } return res From df4c1062f247ef6563ef1f1aea6d6710bf5b5146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Thu, 13 Jun 2024 09:38:49 +0200 Subject: [PATCH 30/39] Fix typo in logs (#3079) --- server/selection_algorithm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/selection_algorithm.go b/server/selection_algorithm.go index 9264922046..e5d868c61f 100644 --- a/server/selection_algorithm.go +++ b/server/selection_algorithm.go @@ -49,7 +49,7 @@ func (sa ProbabilitySelectionAlgorithm) filterByPerfScore(addrs []ethcommon.Addr if len(res) == 0 { // If no orchestrators pass the perf filter, return all Orchestrators. // That may mean some issues with the PerfScore service. - glog.Warning("No Orchestrators passed min performance score filter, not using the filter, numAddrs=%d, minPerfScore=%v, scores=%v, addrs=%v", len(addrs), sa.MinPerfScore, scores, addrs) + glog.Warningf("No Orchestrators passed min performance score filter, not using the filter, numAddrs=%d, minPerfScore=%v, scores=%v, addrs=%v", len(addrs), sa.MinPerfScore, scores, addrs) return addrs } return res @@ -72,7 +72,7 @@ func (sa ProbabilitySelectionAlgorithm) filterByMaxPrice(addrs []ethcommon.Addre if len(res) == 0 { // If no orchestrators pass the filter, return all Orchestrators // It means that no orchestrators are below the max price - glog.Warning("No Orchestrators passed max price filter, not using the filter, numAddrs=%d, maxPrice=%v, prices=%v, addrs=%v", len(addrs), maxPrice, prices, addrs) + glog.Warningf("No Orchestrators passed max price filter, not using the filter, numAddrs=%d, maxPrice=%v, prices=%v, addrs=%v", len(addrs), maxPrice, prices, addrs) return addrs } return res From b62c60c11bcbe8486af40e29452c4e45b2bc2bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Fri, 14 Jun 2024 16:04:29 +0200 Subject: [PATCH 31/39] Add ctx to logging for selection algorithm (#3080) * Add ctx to logging for selection algorithm * Reorg imports * Fix unit tests --- common/types.go | 2 +- server/selection.go | 2 +- server/selection_algorithm.go | 21 +++++++++++---------- server/selection_algorithm_test.go | 3 ++- server/selection_test.go | 2 +- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/common/types.go b/common/types.go index 4535e24e36..8dc0845a77 100644 --- a/common/types.go +++ b/common/types.go @@ -105,7 +105,7 @@ type OrchestratorPool interface { } type SelectionAlgorithm interface { - Select(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) ethcommon.Address + Select(ctx context.Context, addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) ethcommon.Address } type PerfScore struct { diff --git a/server/selection.go b/server/selection.go index e9b9103247..c827034db6 100644 --- a/server/selection.go +++ b/server/selection.go @@ -202,7 +202,7 @@ func (s *MinLSSelector) selectUnknownSession(ctx context.Context) *BroadcastSess s.perfScore.Mu.Unlock() } - selected := s.selectionAlgorithm.Select(addrs, stakes, maxPrice, prices, perfScores) + selected := s.selectionAlgorithm.Select(ctx, addrs, stakes, maxPrice, prices, perfScores) for i, sess := range s.unknownSessions { if sess.OrchestratorInfo.GetTicketParams() == nil { diff --git a/server/selection_algorithm.go b/server/selection_algorithm.go index e5d868c61f..050b459283 100644 --- a/server/selection_algorithm.go +++ b/server/selection_algorithm.go @@ -1,13 +1,14 @@ package server import ( + "context" "math" "math/big" "math/rand" "time" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/golang/glog" + "github.com/livepeer/go-livepeer/clog" ) var random = rand.New(rand.NewSource(time.Now().UnixNano())) @@ -22,18 +23,18 @@ type ProbabilitySelectionAlgorithm struct { PriceExpFactor float64 } -func (sa ProbabilitySelectionAlgorithm) Select(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) ethcommon.Address { - filtered := sa.filter(addrs, maxPrice, prices, perfScores) +func (sa ProbabilitySelectionAlgorithm) Select(ctx context.Context, addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) ethcommon.Address { + filtered := sa.filter(ctx, addrs, maxPrice, prices, perfScores) probabilities := sa.calculateProbabilities(filtered, stakes, prices) return selectBy(probabilities) } -func (sa ProbabilitySelectionAlgorithm) filter(addrs []ethcommon.Address, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) []ethcommon.Address { - filteredByPerfScore := sa.filterByPerfScore(addrs, perfScores) - return sa.filterByMaxPrice(filteredByPerfScore, maxPrice, prices) +func (sa ProbabilitySelectionAlgorithm) filter(ctx context.Context, addrs []ethcommon.Address, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) []ethcommon.Address { + filteredByPerfScore := sa.filterByPerfScore(ctx, addrs, perfScores) + return sa.filterByMaxPrice(ctx, filteredByPerfScore, maxPrice, prices) } -func (sa ProbabilitySelectionAlgorithm) filterByPerfScore(addrs []ethcommon.Address, scores map[ethcommon.Address]float64) []ethcommon.Address { +func (sa ProbabilitySelectionAlgorithm) filterByPerfScore(ctx context.Context, addrs []ethcommon.Address, scores map[ethcommon.Address]float64) []ethcommon.Address { if sa.MinPerfScore <= 0 || len(scores) == 0 { // Performance Score filter not defined, return all Orchestrators return addrs @@ -49,13 +50,13 @@ func (sa ProbabilitySelectionAlgorithm) filterByPerfScore(addrs []ethcommon.Addr if len(res) == 0 { // If no orchestrators pass the perf filter, return all Orchestrators. // That may mean some issues with the PerfScore service. - glog.Warningf("No Orchestrators passed min performance score filter, not using the filter, numAddrs=%d, minPerfScore=%v, scores=%v, addrs=%v", len(addrs), sa.MinPerfScore, scores, addrs) + clog.Warningf(ctx, "No Orchestrators passed min performance score filter, not using the filter, numAddrs=%d, minPerfScore=%v, scores=%v, addrs=%v", len(addrs), sa.MinPerfScore, scores, addrs) return addrs } return res } -func (sa ProbabilitySelectionAlgorithm) filterByMaxPrice(addrs []ethcommon.Address, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat) []ethcommon.Address { +func (sa ProbabilitySelectionAlgorithm) filterByMaxPrice(ctx context.Context, addrs []ethcommon.Address, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat) []ethcommon.Address { if maxPrice == nil || len(prices) == 0 { // Max price filter not defined, return all Orchestrators return addrs @@ -72,7 +73,7 @@ func (sa ProbabilitySelectionAlgorithm) filterByMaxPrice(addrs []ethcommon.Addre if len(res) == 0 { // If no orchestrators pass the filter, return all Orchestrators // It means that no orchestrators are below the max price - glog.Warningf("No Orchestrators passed max price filter, not using the filter, numAddrs=%d, maxPrice=%v, prices=%v, addrs=%v", len(addrs), maxPrice, prices, addrs) + clog.Warningf(ctx, "No Orchestrators passed max price filter, not using the filter, numAddrs=%d, maxPrice=%v, prices=%v, addrs=%v", len(addrs), maxPrice, prices, addrs) return addrs } return res diff --git a/server/selection_algorithm_test.go b/server/selection_algorithm_test.go index 85e677a6ba..ffae12de39 100644 --- a/server/selection_algorithm_test.go +++ b/server/selection_algorithm_test.go @@ -1,6 +1,7 @@ package server import ( + "context" "math/big" "testing" @@ -208,7 +209,7 @@ func TestFilter(t *testing.T) { MinPerfScore: tt.orchMinPerfScore, } - res := sa.filter(addrs, maxPrice, prices, perfScores) + res := sa.filter(context.Background(), addrs, maxPrice, prices, perfScores) var exp []ethcommon.Address for _, o := range tt.want { diff --git a/server/selection_test.go b/server/selection_test.go index b7d6958ab3..aa936ddb04 100644 --- a/server/selection_test.go +++ b/server/selection_test.go @@ -91,7 +91,7 @@ func (r *stubStakeReader) SetStakes(stakes map[ethcommon.Address]int64) { type stubSelectionAlgorithm struct{} -func (sa stubSelectionAlgorithm) Select(addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) ethcommon.Address { +func (sa stubSelectionAlgorithm) Select(ctx context.Context, addrs []ethcommon.Address, stakes map[ethcommon.Address]int64, maxPrice *big.Rat, prices map[ethcommon.Address]*big.Rat, perfScores map[ethcommon.Address]float64) ethcommon.Address { if len(addrs) == 0 { return ethcommon.Address{} } From 0dd670f0098c456d93d8d8addc9d83f09939c842 Mon Sep 17 00:00:00 2001 From: tongjicoder Date: Mon, 17 Jun 2024 05:57:25 +0900 Subject: [PATCH 32/39] chore: make function comment match function name (#3081) Signed-off-by: tongjicoder --- server/rpc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/rpc.go b/server/rpc.go index 4f278d06f6..097c61e709 100644 --- a/server/rpc.go +++ b/server/rpc.go @@ -268,7 +268,7 @@ func GetOrchestratorInfo(ctx context.Context, bcast common.Broadcaster, orchestr return r, nil } -// EndSession - the broadcaster calls EndTranscodingSession to tear down sessions used for verification only once +// EndTranscodingSession - the broadcaster calls EndTranscodingSession to tear down sessions used for verification only once func EndTranscodingSession(ctx context.Context, sess *BroadcastSession) error { uri, err := url.Parse(sess.Transcoder()) if err != nil { From 20e81fbba28f8e042827c71162cf7274882295cd Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Tue, 18 Jun 2024 12:41:30 +0200 Subject: [PATCH 33/39] refactor: rename internal references from Broadcaster to Gateway (#3060) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: rename internal references from Broadcaster to Gateway This commit updates internal references from 'Broadcaster' to 'Gateway' in accordance with the core team’s decision. For more details, refer to the discussion: [Discord Link](https://discord.com/channels/423160867534929930/1051963444598943784/1210356864643109004). * chore: update pending changelog --- CHANGELOG_PENDING.md | 1 + cmd/livepeer/livepeer.go | 2 +- cmd/livepeer/starter/starter.go | 10 +++++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index cd86a5c596..28d9c39c4f 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -5,6 +5,7 @@ - [#3055](https://github.com/livepeer/go-livepeer/pull/3055) census: Rename broadcaster metrics to gateway metrics - [#3053](https://github.com/livepeer/go-livepeer/pull/3053) cli: add `-gateway` flag and deprecate `-broadcaster` flag. - [#3056](https://github.com/livepeer/go-livepeer/pull/3056) cli: add `-pricePerGateway` flag and deprecate `-pricePerBroadcaster` flag. +- [#3060](https://github.com/livepeer/go-livepeer/pull/3060) refactor: rename internal references from Broadcaster to Gateway ### Breaking Changes 🚨🚨 diff --git a/cmd/livepeer/livepeer.go b/cmd/livepeer/livepeer.go index 0bf119b7bb..70922549c5 100755 --- a/cmd/livepeer/livepeer.go +++ b/cmd/livepeer/livepeer.go @@ -179,7 +179,7 @@ func parseLivepeerConfig() starter.LivepeerConfig { cfg.PixelsPerUnit = flag.String("pixelsPerUnit", *cfg.PixelsPerUnit, "Amount of pixels per unit. Set to '> 1' to have smaller price granularity than 1 wei / pixel") cfg.PriceFeedAddr = flag.String("priceFeedAddr", *cfg.PriceFeedAddr, "ETH address of the Chainlink price feed contract. Used for custom currencies conversion on -pricePerUnit or -maxPricePerUnit") cfg.AutoAdjustPrice = flag.Bool("autoAdjustPrice", *cfg.AutoAdjustPrice, "Enable/disable automatic price adjustments based on the overhead for redeeming tickets") - cfg.PricePerGateway = flag.String("pricePerGateway", *cfg.PricePerGateway, `json list of price per gateway or path to json config file. Example: {"broadcasters":[{"ethaddress":"address1","priceperunit":0.5,"currency":"USD","pixelsperunit":1000000000000},{"ethaddress":"address2","priceperunit":0.3,"currency":"USD","pixelsperunit":1000000000000}]}`) + cfg.PricePerGateway = flag.String("pricePerGateway", *cfg.PricePerGateway, `json list of price per gateway or path to json config file. Example: {"gateways":[{"ethaddress":"address1","priceperunit":0.5,"currency":"USD","pixelsperunit":1000000000000},{"ethaddress":"address2","priceperunit":0.3,"currency":"USD","pixelsperunit":1000000000000}]}`) cfg.PricePerBroadcaster = flag.String("pricePerBroadcaster", *cfg.PricePerBroadcaster, `json list of price per broadcaster or path to json config file. Example: {"broadcasters":[{"ethaddress":"address1","priceperunit":0.5,"currency":"USD","pixelsperunit":1000000000000},{"ethaddress":"address2","priceperunit":0.3,"currency":"USD","pixelsperunit":1000000000000}]}`) // Interval to poll for blocks cfg.BlockPollingInterval = flag.Int("blockPollingInterval", *cfg.BlockPollingInterval, "Interval in seconds at which different blockchain event services poll for blocks") diff --git a/cmd/livepeer/starter/starter.go b/cmd/livepeer/starter/starter.go index 1053506bda..384d89edf0 100755 --- a/cmd/livepeer/starter/starter.go +++ b/cmd/livepeer/starter/starter.go @@ -791,15 +791,15 @@ func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { glog.Warning("-PricePerBroadcaster flag is deprecated and will be removed in a future release. Please use -PricePerGateway instead") cfg.PricePerGateway = cfg.PricePerBroadcaster } - broadcasterPrices := getGatewayPrices(*cfg.PricePerGateway) - for _, p := range broadcasterPrices { + gatewayPrices := getGatewayPrices(*cfg.PricePerGateway) + for _, p := range gatewayPrices { p := p pricePerPixel := new(big.Rat).Quo(p.PricePerUnit, p.PixelsPerUnit) autoPrice, err := core.NewAutoConvertedPrice(p.Currency, pricePerPixel, func(price *big.Rat) { - glog.Infof("Price: %v wei per pixel for broadcaster %v", price.FloatString(3), p.EthAddress) + glog.Infof("Price: %v wei per pixel for gateway %v", price.FloatString(3), p.EthAddress) }) if err != nil { - panic(fmt.Errorf("Error converting price for broadcaster %s: %v", p.EthAddress, err)) + panic(fmt.Errorf("Error converting price for gateway %s: %v", p.EthAddress, err)) } n.SetBasePrice(p.EthAddress, autoPrice) } @@ -1501,7 +1501,7 @@ func getGatewayPrices(gatewayPrices string) []GatewayPrice { return nil } - // Format of broadcasterPrices json + // Format of gatewayPrices json // {"gateways":[{"ethaddress":"address1","priceperunit":0.5,"currency":"USD","pixelsperunit":1}, {"ethaddress":"address2","priceperunit":0.3,"currency":"USD","pixelsperunit":3}]} var pricesSet struct { Gateways []struct { From 3dcdf3d57d49951276a4132466506256d9a24e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Fri, 21 Jun 2024 08:52:30 +0200 Subject: [PATCH 34/39] Add logging to the session refresh (#3083) --- server/broadcast.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/broadcast.go b/server/broadcast.go index 150d66ea86..bcd0a54658 100755 --- a/server/broadcast.go +++ b/server/broadcast.go @@ -288,7 +288,9 @@ func (sp *SessionPool) selectSessions(ctx context.Context, sessionsNum int) []*B checkSessions := func(m *SessionPool) bool { numSess := m.sel.Size() - if numSess < int(math.Min(maxRefreshSessionsThreshold, math.Ceil(float64(m.numOrchs)/2.0))) { + refreshThreshold := int(math.Min(maxRefreshSessionsThreshold, math.Ceil(float64(m.numOrchs)/2.0))) + clog.Infof(ctx, "Checking if the session refresh is needed, numSess=%v, refreshThreshold=%v", numSess, refreshThreshold) + if numSess < refreshThreshold { go m.refreshSessions(ctx) } return (numSess > 0 || len(sp.lastSess) > 0) From e6a712b130382616c899e8424bdb903393441a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Leszko?= Date: Mon, 15 Jul 2024 09:19:45 +0200 Subject: [PATCH 35/39] Add `/healthz` endpoint (#3095) --- server/handlers.go | 6 ++++++ server/mediaserver.go | 3 +++ 2 files changed, 9 insertions(+) diff --git a/server/handlers.go b/server/handlers.go index 7514de56ff..22116079e6 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -29,6 +29,12 @@ import ( const MainnetChainId = 1 const RinkebyChainId = 4 +func (s *LivepeerServer) healthzHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + respondOk(w, nil) + }) +} + // Status func (s *LivepeerServer) statusHandler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/server/mediaserver.go b/server/mediaserver.go index 168686525c..e24bf1edbe 100644 --- a/server/mediaserver.go +++ b/server/mediaserver.go @@ -199,6 +199,9 @@ func (s *LivepeerServer) StartMediaServer(ctx context.Context, httpAddr string) // Store ctx to later use as cancel signal for watchdog goroutine s.context = ctx + // health endpoint + s.HTTPMux.Handle("/healthz", s.healthzHandler()) + //LPMS handlers for handling RTMP video s.LPMS.HandleRTMPPublish(createRTMPStreamIDHandler(ctx, s, nil), gotRTMPStreamHandler(s), endRTMPStreamHandler(s)) s.LPMS.HandleRTMPPlay(getRTMPStreamHandler(s)) From 16246943ccb5ee50b07501c36d7a23391918bd8e Mon Sep 17 00:00:00 2001 From: Josh Allmann Date: Wed, 24 Jul 2024 05:55:52 -0700 Subject: [PATCH 36/39] Update LPMS to ffmpeg 7 (#3096) * install_ffmpeg: point to LPMS * Update to use ffmpeg7 LPMS --- go.mod | 2 +- go.sum | 4 +- install_ffmpeg.sh | 232 +--------------------------------------------- 3 files changed, 5 insertions(+), 233 deletions(-) diff --git a/go.mod b/go.mod index 54396951d9..9347403796 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jaypipes/pcidb v1.0.0 github.com/livepeer/go-tools v0.0.0-20220805063103-76df6beb6506 github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18 - github.com/livepeer/lpms v0.0.0-20240528070257-343a3ddb3748 + github.com/livepeer/lpms v0.0.0-20240711034524-d9c78b62effd github.com/livepeer/m3u8 v0.11.1 github.com/mattn/go-sqlite3 v1.14.18 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index 866e8b20bc..92db740f3b 100644 --- a/go.sum +++ b/go.sum @@ -446,8 +446,8 @@ github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded h1:ZQlvR5RB4nfT+cO github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded/go.mod h1:xkDdm+akniYxVT9KW1Y2Y7Hso6aW+rZObz3nrA9yTHw= github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18 h1:4oH3NqV0NvcdS44Ld3zK2tO8IUiNozIggm74yobQeZg= github.com/livepeer/livepeer-data v0.7.5-0.20231004073737-06f1f383fb18/go.mod h1:Jpf4jHK+fbWioBHRDRM1WadNT1qmY27g2YicTdO0Rtc= -github.com/livepeer/lpms v0.0.0-20240528070257-343a3ddb3748 h1:sucdljv+Wjo24WbuHYNFFzjRFsKlSj/s9bn7qdCkG/Y= -github.com/livepeer/lpms v0.0.0-20240528070257-343a3ddb3748/go.mod h1:z5ROP1l5OzAKSoqVRLc34MjUdueil6wHSecQYV7llIw= +github.com/livepeer/lpms v0.0.0-20240711034524-d9c78b62effd h1:IdSZM8gUW7N4pHln8PyUFmvch6oK01QXyknYpycGA80= +github.com/livepeer/lpms v0.0.0-20240711034524-d9c78b62effd/go.mod h1:z5ROP1l5OzAKSoqVRLc34MjUdueil6wHSecQYV7llIw= github.com/livepeer/m3u8 v0.11.1 h1:VkUJzfNTyjy9mqsgp5JPvouwna8wGZMvd/gAfT5FinU= github.com/livepeer/m3u8 v0.11.1/go.mod h1:IUqAtwWPAG2CblfQa4SVzTQoDcEMPyfNOaBSxqHMS04= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= diff --git a/install_ffmpeg.sh b/install_ffmpeg.sh index af66bd0b88..fdc111f8b0 100755 --- a/install_ffmpeg.sh +++ b/install_ffmpeg.sh @@ -1,231 +1,3 @@ #!/usr/bin/env bash - -set -exuo pipefail - -ROOT="${1:-$HOME}" -NPROC=${NPROC:-$(nproc)} -EXTRA_CFLAGS="" -EXTRA_LDFLAGS="" -EXTRA_X264_FLAGS="" -EXTRA_FFMPEG_FLAGS="" -BUILD_TAGS="${BUILD_TAGS:-}" - -# Build platform flags -BUILDOS=$(uname -s | tr '[:upper:]' '[:lower:]') -BUILDARCH=$(uname -m | tr '[:upper:]' '[:lower:]') -if [[ $BUILDARCH == "aarch64" ]]; then - BUILDARCH=arm64 -fi -if [[ $BUILDARCH == "x86_64" ]]; then - BUILDARCH=amd64 -fi - -# Override these for cross-compilation -export GOOS="${GOOS:-$BUILDOS}" -export GOARCH="${GOARCH:-$BUILDARCH}" - -echo "BUILDOS: $BUILDOS" -echo "BUILDARCH: $BUILDARCH" -echo "GOOS: $GOOS" -echo "GOARCH: $GOARCH" - -function check_sysroot() { - if ! stat $SYSROOT > /dev/null; then - echo "cross-compilation sysroot not found at $SYSROOT, try setting SYSROOT to the correct path" - exit 1 - fi -} - -if [[ "$BUILDARCH" == "amd64" && "$BUILDOS" == "linux" && "$GOARCH" == "arm64" && "$GOOS" == "linux" ]]; then - echo "cross-compiling linux-amd64 --> linux-arm64" - export CC="clang-14" - export STRIP="llvm-strip-14" - export AR="llvm-ar-14" - export RANLIB="llvm-ranlib-14" - EXTRA_CFLAGS="--target=aarch64-linux-gnu -I/usr/local/cuda_arm64/include $EXTRA_CFLAGS" - EXTRA_LDFLAGS="-fuse-ld=lld --target=aarch64-linux-gnu -L/usr/local/cuda_arm64/lib64 $EXTRA_LDFLAGS" - EXTRA_FFMPEG_FLAGS="$EXTRA_FFMPEG_FLAGS --arch=aarch64 --enable-cross-compile --cc=clang --strip=llvm-strip-14" - HOST_OS="--host=aarch64-linux-gnu" -fi - -if [[ "$BUILDARCH" == "arm64" && "$BUILDOS" == "darwin" && "$GOARCH" == "arm64" && "$GOOS" == "linux" ]]; then - SYSROOT="${SYSROOT:-"/tmp/sysroot-aarch64-linux-gnu"}" - check_sysroot - echo "cross-compiling darwin-arm64 --> linux-arm64" - LLVM_PATH="${LLVM_PATH:-/opt/homebrew/opt/llvm/bin}" - if [[ ! -f "$LLVM_PATH/ld.lld" ]]; then - echo "llvm linker not found at '$LLVM_PATH/ld.lld'. try 'brew install llvm' or set LLVM_PATH to your LLVM bin directory" - exit 1 - fi - export CC="$LLVM_PATH/clang --sysroot=$SYSROOT" - export AR="/opt/homebrew/opt/llvm/bin/llvm-ar" - export RANLIB="/opt/homebrew/opt/llvm/bin/llvm-ranlib" - EXTRA_CFLAGS="--target=aarch64-linux-gnu $EXTRA_CFLAGS" - EXTRA_LDFLAGS="--target=aarch64-linux-gnu -fuse-ld=$LLVM_PATH/ld.lld $EXTRA_LDFLAGS" - EXTRA_FFMPEG_FLAGS="$EXTRA_FFMPEG_FLAGS --arch=aarch64 --enable-cross-compile --cc=$LLVM_PATH/clang --sysroot=$SYSROOT --ar=$AR --ranlib=$RANLIB --target-os=linux" - EXTRA_X264_FLAGS="$EXTRA_X264_FLAGS --sysroot=$SYSROOT --ar=$AR --ranlib=$RANLIB" - HOST_OS="--host=aarch64-linux-gnu" -fi - -if [[ "$BUILDOS" == "linux" && "$GOARCH" == "amd64" && "$GOOS" == "windows" ]]; then - echo "cross-compiling linux-$BUILDARCH --> windows-amd64" - SYSROOT="${SYSROOT:-"/usr/x86_64-w64-mingw32"}" - check_sysroot - EXTRA_CFLAGS="-L$SYSROOT/lib -I$SYSROOT/include $EXTRA_CFLAGS" - EXTRA_LDFLAGS="-L$SYSROOT/lib $EXTRA_LDFLAGS" - EXTRA_FFMPEG_FLAGS="$EXTRA_FFMPEG_FLAGS --arch=x86_64 --enable-cross-compile --cross-prefix=x86_64-w64-mingw32- --target-os=mingw64 --sysroot=$SYSROOT" - EXTRA_X264_FLAGS="$EXTRA_X264_FLAGS --cross-prefix=x86_64-w64-mingw32- --sysroot=$SYSROOT" - HOST_OS="--host=mingw64" - # Workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=967969 - export PKG_CONFIG_LIBDIR="/usr/local/x86_64-w64-mingw32/lib/pkgconfig" - EXTRA_FFMPEG_FLAGS="$EXTRA_FFMPEG_FLAGS --pkg-config=$(which pkg-config)" -fi - -if [[ "$BUILDARCH" == "amd64" && "$BUILDOS" == "darwin" && "$GOARCH" == "arm64" && "$GOOS" == "darwin" ]]; then - echo "cross-compiling darwin-amd64 --> darwin-arm64" - EXTRA_CFLAGS="$EXTRA_CFLAGS --target=arm64-apple-macos11" - EXTRA_LDFLAGS="$EXTRA_LDFLAGS --target=arm64-apple-macos11" - HOST_OS="--host=aarch64-darwin" - EXTRA_FFMPEG_FLAGS="$EXTRA_FFMPEG_FLAGS --arch=aarch64 --enable-cross-compile" -fi - -# Windows (MSYS2) needs a few tweaks -if [[ "$BUILDOS" == *"MSYS"* ]]; then - ROOT="/build" - export PATH="$PATH:/usr/bin:/mingw64/bin" - export C_INCLUDE_PATH="${C_INCLUDE_PATH:-}:/mingw64/lib" - - export PATH="$ROOT/compiled/bin":$PATH - export PKG_CONFIG_PATH=/mingw64/lib/pkgconfig - - export TARGET_OS="--target-os=mingw64" - export HOST_OS="--host=x86_64-w64-mingw32" - export BUILD_OS="--build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --target=x86_64-w64-mingw32" - - # Needed for mbedtls - export WINDOWS_BUILD=1 -fi - -export PATH="$ROOT/compiled/bin:${PATH}" -export PKG_CONFIG_PATH="${PKG_CONFIG_PATH:-}:$ROOT/compiled/lib/pkgconfig" - -mkdir -p "$ROOT/" - -# NVENC only works on Windows/Linux -if [[ "$GOOS" != "darwin" ]]; then - if [[ ! -e "$ROOT/nv-codec-headers" ]]; then - git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git "$ROOT/nv-codec-headers" - cd $ROOT/nv-codec-headers - git checkout n9.1.23.1 - make -e PREFIX="$ROOT/compiled" - make install -e PREFIX="$ROOT/compiled" - fi -fi - -if [[ "$GOOS" != "windows" && "$GOARCH" == "amd64" ]]; then - if [[ ! -e "$ROOT/nasm-2.14.02" ]]; then - # sudo apt-get -y install asciidoc xmlto # this fails :( - cd "$ROOT" - curl -o nasm-2.14.02.tar.gz https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/nasm-2.14.02.tar.gz - echo 'b34bae344a3f2ed93b2ca7bf25f1ed3fb12da89eeda6096e3551fd66adeae9fc nasm-2.14.02.tar.gz' >nasm-2.14.02.tar.gz.sha256 - sha256sum -c nasm-2.14.02.tar.gz.sha256 - tar xf nasm-2.14.02.tar.gz - rm nasm-2.14.02.tar.gz nasm-2.14.02.tar.gz.sha256 - cd "$ROOT/nasm-2.14.02" - ./configure --prefix="$ROOT/compiled" - make -j$NPROC - make -j$NPROC install || echo "Installing docs fails but should be OK otherwise" - fi -fi - -if [[ ! -e "$ROOT/x264" ]]; then - git clone http://git.videolan.org/git/x264.git "$ROOT/x264" - cd "$ROOT/x264" - if [[ $GOARCH == "arm64" ]]; then - # newer git master, compiles on Apple Silicon - git checkout 66a5bc1bd1563d8227d5d18440b525a09bcf17ca - else - # older git master, does not compile on Apple Silicon - git checkout 545de2ffec6ae9a80738de1b2c8cf820249a2530 - fi - ./configure --prefix="$ROOT/compiled" --enable-pic --enable-static ${HOST_OS:-} --disable-cli --extra-cflags="$EXTRA_CFLAGS" --extra-asflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" $EXTRA_X264_FLAGS || (cat $ROOT/x264/config.log && exit 1) - make -j$NPROC - make -j$NPROC install-lib-static -fi - -if [[ "$GOOS" == "linux" && "$BUILD_TAGS" == *"debug-video"* ]]; then - sudo apt-get install -y libnuma-dev cmake - if [[ ! -e "$ROOT/x265" ]]; then - git clone https://bitbucket.org/multicoreware/x265_git.git "$ROOT/x265" - cd "$ROOT/x265" - git checkout 17839cc0dc5a389e27810944ae2128a65ac39318 - cd build/linux/ - cmake -DCMAKE_INSTALL_PREFIX=$ROOT/compiled -G "Unix Makefiles" ../../source - make -j$NPROC - make -j$NPROC install - fi - # VP8/9 support - if [[ ! -e "$ROOT/libvpx" ]]; then - git clone https://chromium.googlesource.com/webm/libvpx.git "$ROOT/libvpx" - cd "$ROOT/libvpx" - git checkout ab35ee100a38347433af24df05a5e1578172a2ae - ./configure --prefix="$ROOT/compiled" --disable-examples --disable-unit-tests --enable-vp9-highbitdepth --enable-shared --as=nasm - make -j$NPROC - make -j$NPROC install - fi -fi - -DISABLE_FFMPEG_COMPONENTS="" -EXTRA_FFMPEG_LDFLAGS="$EXTRA_LDFLAGS" -# all flags which should be present for production build, but should be replaced/removed for debug build -DEV_FFMPEG_FLAGS="" - -if [[ "$BUILDOS" == "darwin" && "$GOOS" == "darwin" ]]; then - EXTRA_FFMPEG_LDFLAGS="$EXTRA_FFMPEG_LDFLAGS -framework CoreFoundation -framework Security" -elif [[ "$GOOS" == "windows" ]]; then - EXTRA_FFMPEG_FLAGS="$EXTRA_FFMPEG_FLAGS --enable-cuda --enable-cuda-llvm --enable-cuvid --enable-nvenc --enable-decoder=h264_cuvid,hevc_cuvid,vp8_cuvid,vp9_cuvid --enable-filter=scale_cuda,signature_cuda,hwupload_cuda --enable-encoder=h264_nvenc,hevc_nvenc" -elif [[ -e "/usr/local/cuda/lib64" ]]; then - echo "CUDA SDK detected, building with GPU support" - EXTRA_FFMPEG_FLAGS="$EXTRA_FFMPEG_FLAGS --enable-nonfree --enable-cuda-nvcc --enable-libnpp --enable-cuda --enable-cuda-llvm --enable-cuvid --enable-nvenc --enable-decoder=h264_cuvid,hevc_cuvid,vp8_cuvid,vp9_cuvid --enable-filter=scale_npp,signature_cuda,hwupload_cuda --enable-encoder=h264_nvenc,hevc_nvenc" -else - echo "No CUDA SDK detected, building without GPU support" -fi - -if [[ $BUILD_TAGS == *"debug-video"* ]]; then - echo "video debug mode, building ffmpeg with tools, debug info and additional capabilities for running tests" - DEV_FFMPEG_FLAGS="--enable-muxer=md5,flv --enable-demuxer=hls --enable-filter=ssim,tinterlace --enable-encoder=wrapped_avframe,pcm_s16le " - DEV_FFMPEG_FLAGS+="--enable-shared --enable-debug=3 --disable-stripping --disable-optimizations --enable-encoder=libx265,libvpx_vp8,libvpx_vp9 " - DEV_FFMPEG_FLAGS+="--enable-decoder=hevc,libvpx_vp8,libvpx_vp9 --enable-libx265 --enable-libvpx --enable-bsf=noise " -else - # disable all unnecessary features for production build - DISABLE_FFMPEG_COMPONENTS+=" --disable-doc --disable-sdl2 --disable-iconv --disable-muxers --disable-demuxers --disable-parsers --disable-protocols " - DISABLE_FFMPEG_COMPONENTS+=" --disable-encoders --disable-decoders --disable-filters --disable-bsfs --disable-postproc --disable-lzma " -fi - -if [[ ! -e "$ROOT/ffmpeg/libavcodec/libavcodec.a" ]]; then - git clone https://github.com/livepeer/FFmpeg.git "$ROOT/ffmpeg" || echo "FFmpeg dir already exists" - cd "$ROOT/ffmpeg" - git checkout 2e18d069668c143f3c251067abd25389e411d022 - ./configure ${TARGET_OS:-} $DISABLE_FFMPEG_COMPONENTS --fatal-warnings \ - --enable-libx264 --enable-gpl \ - --enable-protocol=rtmp,file,pipe \ - --enable-muxer=mpegts,hls,segment,mp4,hevc,matroska,webm,null --enable-demuxer=flv,mpegts,mp4,mov,webm,matroska \ - --enable-bsf=h264_mp4toannexb,aac_adtstoasc,h264_metadata,h264_redundant_pps,hevc_mp4toannexb,extract_extradata \ - --enable-parser=aac,aac_latm,h264,hevc,vp8,vp9 \ - --enable-filter=abuffer,buffer,abuffersink,buffersink,afifo,fifo,aformat,format \ - --enable-filter=aresample,asetnsamples,fps,scale,hwdownload,select,livepeer_dnn,signature \ - --enable-encoder=aac,opus,libx264 \ - --enable-decoder=aac,opus,h264 \ - --extra-cflags="${EXTRA_CFLAGS} -I${ROOT}/compiled/include -I/usr/local/cuda/include" \ - --extra-ldflags="${EXTRA_FFMPEG_LDFLAGS} -L${ROOT}/compiled/lib -L/usr/local/cuda/lib64" \ - --prefix="$ROOT/compiled" \ - $EXTRA_FFMPEG_FLAGS \ - $DEV_FFMPEG_FLAGS || (tail -100 ${ROOT}/ffmpeg/ffbuild/config.log && exit 1) - # If configure fails, then print the last 100 log lines for debugging and exit. -fi - -if [[ ! -e "$ROOT/ffmpeg/libavcodec/libavcodec.a" || $BUILD_TAGS == *"debug-video"* ]]; then - cd "$ROOT/ffmpeg" - make -j$NPROC - make -j$NPROC install -fi +echo 'WARNING: downloading and executing lpms/install_ffmpeg.sh, use it directly in case of issues' +curl https://raw.githubusercontent.com/livepeer/lpms/d9c78b62effdb4f5c8fc438b6033da1090d04a03/install_ffmpeg.sh | bash -s $1 From a5cdcc6d3719a8e0bd1618c4cfc4cd03f27cc497 Mon Sep 17 00:00:00 2001 From: Josh Allmann Date: Wed, 24 Jul 2024 20:41:38 +0000 Subject: [PATCH 37/39] release v0.7.6 --- CHANGELOG.md | 33 ++++++++++++++++++++++++++++++++- CHANGELOG_PENDING.md | 5 ----- VERSION | 2 +- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49545e9b2c..fb3c5d8036 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,36 @@ # Changelog +## v0.7.6 + +- [#3055](https://github.com/livepeer/go-livepeer/pull/3055) census: Rename broadcaster metrics to gateway metrics +- [#3053](https://github.com/livepeer/go-livepeer/pull/3053) cli: add `-gateway` flag and deprecate `-broadcaster` flag. +- [#3056](https://github.com/livepeer/go-livepeer/pull/3056) cli: add `-pricePerGateway` flag and deprecate `-pricePerBroadcaster` flag. +- [#3060](https://github.com/livepeer/go-livepeer/pull/3060) refactor: rename internal references from Broadcaster to Gateway + +### Breaking Changes 🚨🚨 + +### Features βš’ + +#### General + +#### Broadcaster + +#### Orchestrator + +#### Transcoder + +### Bug Fixes 🐞 + +#### CLI + +#### General + +#### Broadcaster + +#### Orchestrator + +#### Transcoder + ## v0.7.5 ### Breaking Changes 🚨🚨 @@ -985,4 +1016,4 @@ Thanks everyone that submitted bug reports and assisted in testing! - [#1775](https://github.com/livepeer/go-livepeer/pull/1775) Fix transcoder load balancer race condition around session cleanup (@jailuthra) - [#1784](https://github.com/livepeer/go-livepeer/pull/1784) Use auth token sessionID to index into sessions map in transcoder load balancer (@jailuthra) -[Full list of changes](https://github.com/livepeer/go-livepeer/compare/v0.5.14...v0.5.15) +[Full list of changes](https://github.com/livepeer/go-livepeer/compare/v0.5.14...v0.5.15) \ No newline at end of file diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 28d9c39c4f..3ca5044811 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -2,11 +2,6 @@ ## vX.X -- [#3055](https://github.com/livepeer/go-livepeer/pull/3055) census: Rename broadcaster metrics to gateway metrics -- [#3053](https://github.com/livepeer/go-livepeer/pull/3053) cli: add `-gateway` flag and deprecate `-broadcaster` flag. -- [#3056](https://github.com/livepeer/go-livepeer/pull/3056) cli: add `-pricePerGateway` flag and deprecate `-pricePerBroadcaster` flag. -- [#3060](https://github.com/livepeer/go-livepeer/pull/3060) refactor: rename internal references from Broadcaster to Gateway - ### Breaking Changes 🚨🚨 ### Features βš’ diff --git a/VERSION b/VERSION index da2ac9c7e6..4d01880a7f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.5 \ No newline at end of file +0.7.6 \ No newline at end of file From e9d4c393ebf940888e037326c58d9b17c3c83264 Mon Sep 17 00:00:00 2001 From: Josh Allmann Date: Thu, 25 Jul 2024 21:36:12 +0000 Subject: [PATCH 38/39] cmd: Use `-gateway` consistently Avoid references to deprecated CLI flags. --- cmd/devtool/devtool.go | 7 +-- cmd/livepeer/starter/starter.go | 2 +- doc/verification.md | 2 +- test_args.sh | 82 ++++++++++++++++----------------- 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/cmd/devtool/devtool.go b/cmd/devtool/devtool.go index ffd696427e..1b4ed17f33 100644 --- a/cmd/devtool/devtool.go +++ b/cmd/devtool/devtool.go @@ -3,14 +3,15 @@ package main import ( "flag" "fmt" - "github.com/golang/glog" - "github.com/livepeer/go-livepeer/cmd/devtool/devtool" "io" "io/ioutil" "os" "path/filepath" "strconv" "strings" + + "github.com/golang/glog" + "github.com/livepeer/go-livepeer/cmd/devtool/devtool" ) var ( @@ -195,7 +196,7 @@ func createRunScript(ethController string, dataDir, serviceHost string, cfg devt } else { args = append( args, - "-broadcaster=true", + "-gateway=true", fmt.Sprintf("-rtmpAddr %s:%d", serviceHost, rtmpPort), ) diff --git a/cmd/livepeer/starter/starter.go b/cmd/livepeer/starter/starter.go index 384d89edf0..5ef0e1e694 100755 --- a/cmd/livepeer/starter/starter.go +++ b/cmd/livepeer/starter/starter.go @@ -511,7 +511,7 @@ func StartLivepeer(ctx context.Context, cfg LivepeerConfig) { } else if *cfg.Gateway { n.NodeType = core.BroadcasterNode } else if (cfg.Reward == nil || !*cfg.Reward) && !*cfg.InitializeRound { - exit("No services enabled; must be at least one of -broadcaster, -transcoder, -orchestrator, -redeemer, -reward or -initializeRound") + exit("No services enabled; must be at least one of -gateway, -transcoder, -orchestrator, -redeemer, -reward or -initializeRound") } lpmon.NodeID = *cfg.EthAcctAddr diff --git a/doc/verification.md b/doc/verification.md index b1085bebc3..359d5968c1 100644 --- a/doc/verification.md +++ b/doc/verification.md @@ -1,6 +1,6 @@ # Verification -The Livepeer node supports two types of verification when running with the `-broadcaster` flag: +The Livepeer node supports two types of verification when running with the `-gateway` flag: - Local verification - This currently involves pixel count and signature verification. diff --git a/test_args.sh b/test_args.sh index 6e1da41544..ca86d6304e 100755 --- a/test_args.sh +++ b/test_args.sh @@ -37,7 +37,7 @@ res=0 $TMPDIR/livepeer || res=$? [ $res -ne 0 ] -run_lp -broadcaster +run_lp -gateway [ -d "$DEFAULT_DATADIR"/offchain ] kill $pid @@ -45,7 +45,7 @@ kill $pid [ ! -d "$CUSTOM_DATADIR" ] # check custom datadir without a network (offchain) -run_lp -broadcaster -dataDir "$CUSTOM_DATADIR" +run_lp -gateway -dataDir "$CUSTOM_DATADIR" [ -d "$CUSTOM_DATADIR" ] [ ! -d "$CUSTOM_DATADIR"/offchain ] # sanity check that network isn't included kill $pid @@ -83,13 +83,13 @@ if [ -z ${MAINNET_ETH_URL+x} ]; then else # Exit early if -ethUrl is missing res=0 - $TMPDIR/livepeer -broadcaster -network mainnet $ETH_ARGS || res=$? + $TMPDIR/livepeer -gateway -network mainnet $ETH_ARGS || res=$? [ $res -ne 0 ] OLD_ETH_ARGS=$ETH_ARGS ETH_ARGS="${ETH_ARGS} -ethUrl ${MAINNET_ETH_URL}" - run_lp -broadcaster -network mainnet $ETH_ARGS + run_lp -gateway -network mainnet $ETH_ARGS [ -d "$DEFAULT_DATADIR"/mainnet ] kill $pid @@ -102,27 +102,27 @@ if [ -z ${RINKEBY_ETH_URL+x} ]; then else # Exit early if -ethUrl is missing res=0 - $TMPDIR/livepeer -broadcaster -network rinkeby $ETH_ARGS || res=$? + $TMPDIR/livepeer -gateway -network rinkeby $ETH_ARGS || res=$? [ $res -ne 0 ] OLD_ETH_ARGS=$ETH_ARGS ETH_ARGS="${ETH_ARGS} -ethUrl ${RINKEBY_ETH_URL}" - run_lp -broadcaster -network rinkeby $ETH_ARGS + run_lp -gateway -network rinkeby $ETH_ARGS [ -d "$DEFAULT_DATADIR"/rinkeby ] kill $pid # Error if flags to set MaxBroadcastPrice aren't provided correctly res=0 - $TMPDIR/livepeer -broadcaster -network rinkeby $ETH_ARGS -maxPricePerUnit 0 -pixelsPerUnit -5 || res=$? + $TMPDIR/livepeer -gateway -network rinkeby $ETH_ARGS -maxPricePerUnit 0 -pixelsPerUnit -5 || res=$? [ $res -ne 0 ] - run_lp -broadcaster -network anyNetwork $ETH_ARGS -v 99 + run_lp -gateway -network anyNetwork $ETH_ARGS -v 99 [ -d "$DEFAULT_DATADIR"/anyNetwork ] kill $pid # check custom datadir with a network - run_lp -broadcaster -dataDir "$CUSTOM_DATADIR" -network rinkeby $ETH_ARGS + run_lp -gateway -dataDir "$CUSTOM_DATADIR" -network rinkeby $ETH_ARGS [ ! -d "$CUSTOM_DATADIR"/rinkeby ] # sanity check that network isn't included kill $pid @@ -141,22 +141,22 @@ else # Broadcaster needs a valid rational number for -maxTicketEV res=0 - $TMPDIR/livepeer -broadcaster -maxTicketEV abcd -network rinkeby $ETH_ARGS || res=$? + $TMPDIR/livepeer -gateway -maxTicketEV abcd -network rinkeby $ETH_ARGS || res=$? [ $res -ne 0 ] # Broadcaster needs a non-negative number for -maxTicketEV res=0 - $TMPDIR/livepeer -broadcaster -maxTicketEV -1 -network rinkeby $ETH_ARGS || res=$? + $TMPDIR/livepeer -gateway -maxTicketEV -1 -network rinkeby $ETH_ARGS || res=$? [ $res -ne 0 ] # Broadcaster needs a positive number for -depositMultiplier res=0 - $TMPDIR/livepeer -broadcaster -depositMultiplier 0 -network rinkeby $ETH_ARGS || res=$? + $TMPDIR/livepeer -gateway -depositMultiplier 0 -network rinkeby $ETH_ARGS || res=$? [ $res -ne 0 ] # Check that local verification is enabled by default in on-chain mode - $TMPDIR/livepeer -broadcaster -transcodingOptions invalid -network rinkeby $ETH_ARGS 2>&1 | grep "Local verification enabled" + $TMPDIR/livepeer -gateway -transcodingOptions invalid -network rinkeby $ETH_ARGS 2>&1 | grep "Local verification enabled" # Check that local verification is disabled via -localVerify in on-chain mode - $TMPDIR/livepeer -broadcaster -transcodingOptions invalid -localVerify=false -network rinkeby $ETH_ARGS 2>&1 | grep -v "Local verification enabled" + $TMPDIR/livepeer -gateway -transcodingOptions invalid -localVerify=false -network rinkeby $ETH_ARGS 2>&1 | grep -v "Local verification enabled" ETH_ARGS=$OLD_ETH_ARGS fi @@ -168,101 +168,101 @@ $TMPDIR/livepeer -transcoder || res=$? # exit early if webhook url is not http res=0 -$TMPDIR/livepeer -broadcaster -authWebhookUrl tcp://host/ || res=$? +$TMPDIR/livepeer -gateway -authWebhookUrl tcp://host/ || res=$? [ $res -ne 0 ] # exit early if webhook url is not properly formatted res=0 -$TMPDIR/livepeer -broadcaster -authWebhookUrl http\\://host/ || res=$? +$TMPDIR/livepeer -gateway -authWebhookUrl http\\://host/ || res=$? [ $res -ne 0 ] # exit early if orchestrator webhook URL is not http res=0 -$TMPDIR/livepeer -broadcaster -orchWebhookUrl tcp://host/ || res=$? +$TMPDIR/livepeer -gateway -orchWebhookUrl tcp://host/ || res=$? [ $res -ne 0 ] # exit early if orchestrator webhook URL is not properly formatted res=0 -$TMPDIR/livepeer -broadcaster -orchWebhookUrl http\\://host/ || res=$? +$TMPDIR/livepeer -gateway -orchWebhookUrl http\\://host/ || res=$? [ $res -ne 0 ] # exit early if maxSessions less or equal to zero res=0 -$TMPDIR/livepeer -broadcaster -maxSessions -1 || res=$? +$TMPDIR/livepeer -gateway -maxSessions -1 || res=$? [ $res -ne 0 ] res=0 -$TMPDIR/livepeer -broadcaster -maxSessions 0 || res=$? +$TMPDIR/livepeer -gateway -maxSessions 0 || res=$? [ $res -ne 0 ] # Check that pprof is running on CLI port -run_lp -broadcaster +run_lp -gateway curl -sI http://127.0.0.1:5935/debug/pprof/allocs | grep "200 OK" kill $pid # exit early if verifier URL is not http res=0 -$TMPDIR/livepeer -broadcaster -verifierUrl tcp://host/ || res=$? +$TMPDIR/livepeer -gateway -verifierUrl tcp://host/ || res=$? [ $res -ne 0 ] # exit early if verifier URL is not properly formatted res=0 -$TMPDIR/livepeer -broadcaster -verifierUrl http\\://host/ || res=$? +$TMPDIR/livepeer -gateway -verifierUrl http\\://host/ || res=$? [ $res -ne 0 ] # Check that verifier shared path is required -$TMPDIR/livepeer -broadcaster -verifierUrl http://host 2>&1 | grep "Requires a path to the" +$TMPDIR/livepeer -gateway -verifierUrl http://host 2>&1 | grep "Requires a path to the" # Check OK with verifier shared path -run_lp -broadcaster -verifierUrl http://host -verifierPath path +run_lp -gateway -verifierUrl http://host -verifierPath path kill $pid # Check OK with verifier + external storage -run_lp -broadcaster -verifierUrl http://host -objectStore s3+https://ACCESS_KEY_ID:ACCESS_KEY_PASSWORD@s3api.example.com/bucket-name +run_lp -gateway -verifierUrl http://host -objectStore s3+https://ACCESS_KEY_ID:ACCESS_KEY_PASSWORD@s3api.example.com/bucket-name kill $pid # Check that HTTP ingest is disabled when -httpAddr is publicly accessible and there is no auth webhook URL and -httpIngest defaults to false -run_lp -broadcaster -httpAddr 0.0.0.0 +run_lp -gateway -httpAddr 0.0.0.0 curl -X PUT http://localhost:9935/live/movie/0.ts | grep "404 page not found" kill $pid # Check that HTTP ingest is disabled when -httpAddr is not publicly accessible and -httpIngest is set to false -run_lp -broadcaster -httpIngest=false +run_lp -gateway -httpIngest=false curl -X PUT http://localhost:9935/live/movie/0.ts | grep "404 page not found" kill $pid # Check that HTTP ingest is disabled when -httpAddr is publicly accessible and there is a auth webhook URL and -httpIngest is set to false -run_lp -broadcaster -httpAddr 0.0.0.0 -authWebhookUrl http://foo.com -httpIngest=false +run_lp -gateway -httpAddr 0.0.0.0 -authWebhookUrl http://foo.com -httpIngest=false curl -X PUT http://localhost:9935/live/movie/0.ts | grep "404 page not found" kill $pid # Check that HTTP ingest is enabled when -httpIngest is true -run_lp -broadcaster -httpAddr 0.0.0.0 -httpIngest +run_lp -gateway -httpAddr 0.0.0.0 -httpIngest curl -X PUT http://localhost:9935/live/movie/0.ts | grep -v "404 page not found" kill $pid # Check that HTTP ingest is enabled when -httpAddr sets the hostname to 127.0.0.1 -run_lp -broadcaster -httpAddr 127.0.0.1 +run_lp -gateway -httpAddr 127.0.0.1 curl -X PUT http://localhost:9935/live/movie/0.ts | grep -v "404 page not found" kill $pid # Check that HTTP ingest is enabled when -httpAddr sets the hostname to localhost -run_lp -broadcaster -httpAddr localhost +run_lp -gateway -httpAddr localhost curl -X PUT http://localhost:9935/live/movie/0.ts | grep -v "404 page not found" kill $pid # Check that HTTP ingest is enabled when there is an auth webhook URL -run_lp -broadcaster -httpAddr 0.0.0.0 -authWebhookUrl http://foo.com +run_lp -gateway -httpAddr 0.0.0.0 -authWebhookUrl http://foo.com curl -X PUT http://localhost:9935/live/movie/0.ts | grep -v "404 page not found" kill $pid # Check that the default presets are used -run_lp -broadcaster +run_lp -gateway curl -s --stderr - http://localhost:5935/getBroadcastConfig | grep P240p30fps16x9,P360p30fps16x9 kill $pid # Check that the presets passed in are used -run_lp -broadcaster -transcodingOptions P144p30fps16x9,P720p30fps16x9 +run_lp -gateway -transcodingOptions P144p30fps16x9,P720p30fps16x9 curl -s --stderr - http://localhost:5935/getBroadcastConfig | grep P144p30fps16x9,P720p30fps16x9 kill $pid @@ -270,25 +270,25 @@ kill $pid cat >$TMPDIR/profile.json <&1 | grep "No transcoding profiles found" +$TMPDIR/livepeer -gateway -transcodingOptions notarealfile 2>&1 | grep "No transcoding profiles found" # Check that it fails out on an malformed profiles json echo "not json" >$TMPDIR/invalid.json -$TMPDIR/livepeer -broadcaster -transcodingOptions $TMPDIR/invalid.json 2>&1 | grep "invalid character" +$TMPDIR/livepeer -gateway -transcodingOptions $TMPDIR/invalid.json 2>&1 | grep "invalid character" # Check that it fails out on an invalid schema - width / height as strings echo '[{"width":"1","height":"2"}]' >$TMPDIR/schema.json -$TMPDIR/livepeer -broadcaster -transcodingOptions $TMPDIR/schema.json 2>&1 | grep "cannot unmarshal string into Go struct field JsonProfile.width of type int" +$TMPDIR/livepeer -gateway -transcodingOptions $TMPDIR/schema.json 2>&1 | grep "cannot unmarshal string into Go struct field JsonProfile.width of type int" # Check that local verification is disabled by default in off-chain mode -$TMPDIR/livepeer -broadcaster -transcodingOptions invalid 2>&1 | grep -v "Local verification enabled" +$TMPDIR/livepeer -gateway -transcodingOptions invalid 2>&1 | grep -v "Local verification enabled" # Check that local verification is enabled via -localVerify in off-chain mode -$TMPDIR/livepeer -broadcaster -transcodingOptions invalid -localVerify=true 2>&1 | grep "Local verification enabled" +$TMPDIR/livepeer -gateway -transcodingOptions invalid -localVerify=true 2>&1 | grep "Local verification enabled" rm -rf $TMPDIR From 825b3e2034aef7856c50f62e249e571baef60c2b Mon Sep 17 00:00:00 2001 From: Josh Allmann Date: Wed, 7 Aug 2024 09:15:51 -0700 Subject: [PATCH 39/39] core: Rename 'InArray' to 'HasCapability' (#3118) --- core/capabilities.go | 2 +- core/capabilities_test.go | 20 ++++++++++---------- core/transcoder.go | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/capabilities.go b/core/capabilities.go index 7bd4f00f5f..e626fc54a1 100644 --- a/core/capabilities.go +++ b/core/capabilities.go @@ -496,7 +496,7 @@ func CapabilityToName(capability Capability) (string, error) { return capName, nil } -func InArray(capability Capability, caps []Capability) bool { +func HasCapability(caps []Capability, capability Capability) bool { for _, c := range caps { if capability == c { return true diff --git a/core/capabilities_test.go b/core/capabilities_test.go index b165a3d9ca..8985565078 100644 --- a/core/capabilities_test.go +++ b/core/capabilities_test.go @@ -148,22 +148,22 @@ func TestCapability_TranscoderCapabilities(t *testing.T) { if devicesAvailable { nvidiaCaps, err := TestTranscoderCapabilities(devices, NewNvidiaTranscoder) assert.Nil(t, err) - assert.False(t, InArray(Capability_H264_Decode_444_8bit, nvidiaCaps), "Nvidia device should not support decode of 444_8bit") - assert.False(t, InArray(Capability_H264_Decode_422_8bit, nvidiaCaps), "Nvidia device should not support decode of 422_8bit") - assert.False(t, InArray(Capability_H264_Decode_444_10bit, nvidiaCaps), "Nvidia device should not support decode of 444_10bit") - assert.False(t, InArray(Capability_H264_Decode_422_10bit, nvidiaCaps), "Nvidia device should not support decode of 422_10bit") - assert.False(t, InArray(Capability_H264_Decode_420_10bit, nvidiaCaps), "Nvidia device should not support decode of 420_10bit") + assert.False(t, HasCapability(nvidiaCaps, Capability_H264_Decode_444_8bit), "Nvidia device should not support decode of 444_8bit") + assert.False(t, HasCapability(nvidiaCaps, Capability_H264_Decode_422_8bit), "Nvidia device should not support decode of 422_8bit") + assert.False(t, HasCapability(nvidiaCaps, Capability_H264_Decode_444_10bit), "Nvidia device should not support decode of 444_10bit") + assert.False(t, HasCapability(nvidiaCaps, Capability_H264_Decode_422_10bit), "Nvidia device should not support decode of 422_10bit") + assert.False(t, HasCapability(nvidiaCaps, Capability_H264_Decode_420_10bit), "Nvidia device should not support decode of 420_10bit") } // Same test with software transcoder: softwareCaps, err := TestSoftwareTranscoderCapabilities(tmpdir) assert.Nil(t, err) // Software transcoder supports: [h264_444_8bit h264_422_8bit h264_444_10bit h264_422_10bit h264_420_10bit] - assert.True(t, InArray(Capability_H264_Decode_444_8bit, softwareCaps), "software decoder should support 444_8bit input") - assert.True(t, InArray(Capability_H264_Decode_422_8bit, softwareCaps), "software decoder should support 422_8bit input") - assert.True(t, InArray(Capability_H264_Decode_444_10bit, softwareCaps), "software decoder should support 444_10bit input") - assert.True(t, InArray(Capability_H264_Decode_422_10bit, softwareCaps), "software decoder should support 422_10bit input") - assert.True(t, InArray(Capability_H264_Decode_420_10bit, softwareCaps), "software decoder should support 420_10bit input") + assert.True(t, HasCapability(softwareCaps, Capability_H264_Decode_444_8bit), "software decoder should support 444_8bit input") + assert.True(t, HasCapability(softwareCaps, Capability_H264_Decode_422_8bit), "software decoder should support 422_8bit input") + assert.True(t, HasCapability(softwareCaps, Capability_H264_Decode_444_10bit), "software decoder should support 444_10bit input") + assert.True(t, HasCapability(softwareCaps, Capability_H264_Decode_422_10bit), "software decoder should support 422_10bit input") + assert.True(t, HasCapability(softwareCaps, Capability_H264_Decode_420_10bit), "software decoder should support 420_10bit input") } func TestCapability_JobCapabilities(t *testing.T) { diff --git a/core/transcoder.go b/core/transcoder.go index e91aa56693..79458a5b83 100644 --- a/core/transcoder.go +++ b/core/transcoder.go @@ -172,7 +172,7 @@ type transcodeTestParams struct { } func (params transcodeTestParams) IsRequired() bool { - return InArray(params.Cap, DefaultCapabilities()) + return HasCapability(DefaultCapabilities(), params.Cap) } func (params transcodeTestParams) Kind() string {