diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index a6dc9e349a91..3a5faf03e2a7 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -320,7 +320,7 @@ var (
Usage: "Target EL engine API URL",
Category: flags.BeaconCategory,
}
- BlsyncJWTSecretFlag = &cli.StringFlag{
+ BlsyncJWTSecretFlag = &flags.DirectoryFlag{
Name: "blsync.jwtsecret",
Usage: "Path to a JWT secret to use for target engine API endpoint",
Category: flags.BeaconCategory,
diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go
index 55b53ded40ff..3abb0fa65f1c 100644
--- a/core/state/statedb_hooked.go
+++ b/core/state/statedb_hooked.go
@@ -150,7 +150,7 @@ func (s *hookedStateDB) Snapshot() int {
}
func (s *hookedStateDB) AddPreimage(hash common.Hash, bytes []byte) {
- s.inner.Snapshot()
+ s.inner.AddPreimage(hash, bytes)
}
func (s *hookedStateDB) Witness() *stateless.Witness {
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index 0972644d800e..f10626c01fb7 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -630,6 +630,23 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er
return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data))
}
+// RevertErrorData returns the 'revert reason' data of a contract call.
+//
+// This can be used with CallContract and EstimateGas, and only when the server is Geth.
+func RevertErrorData(err error) ([]byte, bool) {
+ var ec rpc.Error
+ var ed rpc.DataError
+ if errors.As(err, &ec) && errors.As(err, &ed) && ec.ErrorCode() == 3 {
+ if eds, ok := ed.ErrorData().(string); ok {
+ revertData, err := hexutil.Decode(eds)
+ if err == nil {
+ return revertData, true
+ }
+ }
+ }
+ return nil, false
+}
+
func toBlockNumArg(number *big.Int) string {
if number == nil {
return "latest"
diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go
index 1b7e26fb74f5..4ad8a552d268 100644
--- a/ethclient/ethclient_test.go
+++ b/ethclient/ethclient_test.go
@@ -14,18 +14,20 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package ethclient
+package ethclient_test
import (
"bytes"
"context"
"errors"
+ "fmt"
"math/big"
"reflect"
"testing"
"time"
"github.com/ethereum/go-ethereum"
+ "github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
@@ -33,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/ethconfig"
+ "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
@@ -40,154 +43,33 @@ import (
// Verify that Client implements the ethereum interfaces.
var (
- _ = ethereum.ChainReader(&Client{})
- _ = ethereum.TransactionReader(&Client{})
- _ = ethereum.ChainStateReader(&Client{})
- _ = ethereum.ChainSyncReader(&Client{})
- _ = ethereum.ContractCaller(&Client{})
- _ = ethereum.GasEstimator(&Client{})
- _ = ethereum.GasPricer(&Client{})
- _ = ethereum.LogFilterer(&Client{})
- _ = ethereum.PendingStateReader(&Client{})
- // _ = ethereum.PendingStateEventer(&Client{})
- _ = ethereum.PendingContractCaller(&Client{})
+ _ = ethereum.ChainReader(ðclient.Client{})
+ _ = ethereum.TransactionReader(ðclient.Client{})
+ _ = ethereum.ChainStateReader(ðclient.Client{})
+ _ = ethereum.ChainSyncReader(ðclient.Client{})
+ _ = ethereum.ContractCaller(ðclient.Client{})
+ _ = ethereum.GasEstimator(ðclient.Client{})
+ _ = ethereum.GasPricer(ðclient.Client{})
+ _ = ethereum.LogFilterer(ðclient.Client{})
+ _ = ethereum.PendingStateReader(ðclient.Client{})
+ // _ = ethereum.PendingStateEventer(ðclient.Client{})
+ _ = ethereum.PendingContractCaller(ðclient.Client{})
)
-func TestToFilterArg(t *testing.T) {
- blockHashErr := errors.New("cannot specify both BlockHash and FromBlock/ToBlock")
- addresses := []common.Address{
- common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"),
- }
- blockHash := common.HexToHash(
- "0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb",
- )
-
- for _, testCase := range []struct {
- name string
- input ethereum.FilterQuery
- output interface{}
- err error
- }{
- {
- "without BlockHash",
- ethereum.FilterQuery{
- Addresses: addresses,
- FromBlock: big.NewInt(1),
- ToBlock: big.NewInt(2),
- Topics: [][]common.Hash{},
- },
- map[string]interface{}{
- "address": addresses,
- "fromBlock": "0x1",
- "toBlock": "0x2",
- "topics": [][]common.Hash{},
- },
- nil,
- },
- {
- "with nil fromBlock and nil toBlock",
- ethereum.FilterQuery{
- Addresses: addresses,
- Topics: [][]common.Hash{},
- },
- map[string]interface{}{
- "address": addresses,
- "fromBlock": "0x0",
- "toBlock": "latest",
- "topics": [][]common.Hash{},
- },
- nil,
- },
- {
- "with negative fromBlock and negative toBlock",
- ethereum.FilterQuery{
- Addresses: addresses,
- FromBlock: big.NewInt(-1),
- ToBlock: big.NewInt(-1),
- Topics: [][]common.Hash{},
- },
- map[string]interface{}{
- "address": addresses,
- "fromBlock": "pending",
- "toBlock": "pending",
- "topics": [][]common.Hash{},
- },
- nil,
- },
- {
- "with blockhash",
- ethereum.FilterQuery{
- Addresses: addresses,
- BlockHash: &blockHash,
- Topics: [][]common.Hash{},
- },
- map[string]interface{}{
- "address": addresses,
- "blockHash": blockHash,
- "topics": [][]common.Hash{},
- },
- nil,
- },
- {
- "with blockhash and from block",
- ethereum.FilterQuery{
- Addresses: addresses,
- BlockHash: &blockHash,
- FromBlock: big.NewInt(1),
- Topics: [][]common.Hash{},
- },
- nil,
- blockHashErr,
- },
- {
- "with blockhash and to block",
- ethereum.FilterQuery{
- Addresses: addresses,
- BlockHash: &blockHash,
- ToBlock: big.NewInt(1),
- Topics: [][]common.Hash{},
- },
- nil,
- blockHashErr,
- },
- {
- "with blockhash and both from / to block",
- ethereum.FilterQuery{
- Addresses: addresses,
- BlockHash: &blockHash,
- FromBlock: big.NewInt(1),
- ToBlock: big.NewInt(2),
- Topics: [][]common.Hash{},
- },
- nil,
- blockHashErr,
- },
- } {
- t.Run(testCase.name, func(t *testing.T) {
- output, err := toFilterArg(testCase.input)
- if (testCase.err == nil) != (err == nil) {
- t.Fatalf("expected error %v but got %v", testCase.err, err)
- }
- if testCase.err != nil {
- if testCase.err.Error() != err.Error() {
- t.Fatalf("expected error %v but got %v", testCase.err, err)
- }
- } else if !reflect.DeepEqual(testCase.output, output) {
- t.Fatalf("expected filter arg %v but got %v", testCase.output, output)
- }
- })
- }
-}
-
var (
- testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
- testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
- testBalance = big.NewInt(2e15)
+ testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
+ testBalance = big.NewInt(2e15)
+ revertContractAddr = common.HexToAddress("290f1b36649a61e369c6276f6d29463335b4400c")
+ revertCode = common.FromHex("7f08c379a0000000000000000000000000000000000000000000000000000000006000526020600452600a6024527f75736572206572726f7200000000000000000000000000000000000000000000604452604e6000fd")
)
var genesis = &core.Genesis{
- Config: params.AllEthashProtocolChanges,
- Alloc: types.GenesisAlloc{testAddr: {Balance: testBalance}},
+ Config: params.AllEthashProtocolChanges,
+ Alloc: types.GenesisAlloc{
+ testAddr: {Balance: testBalance},
+ revertContractAddr: {Code: revertCode},
+ },
ExtraData: []byte("test genesis"),
Timestamp: 9000,
BaseFee: big.NewInt(params.InitialBaseFee),
@@ -209,27 +91,30 @@ var testTx2 = types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &
To: &common.Address{2},
})
-func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
+func newTestBackend(config *node.Config) (*node.Node, []*types.Block, error) {
// Generate test chain.
blocks := generateTestChain()
// Create node
- n, err := node.New(&node.Config{})
+ if config == nil {
+ config = new(node.Config)
+ }
+ n, err := node.New(config)
if err != nil {
- t.Fatalf("can't create new node: %v", err)
+ return nil, nil, fmt.Errorf("can't create new node: %v", err)
}
// Create Ethereum Service
- config := ðconfig.Config{Genesis: genesis, RPCGasCap: 1000000}
- ethservice, err := eth.New(n, config)
+ ecfg := ðconfig.Config{Genesis: genesis, RPCGasCap: 1000000}
+ ethservice, err := eth.New(n, ecfg)
if err != nil {
- t.Fatalf("can't create new ethereum service: %v", err)
+ return nil, nil, fmt.Errorf("can't create new ethereum service: %v", err)
}
// Import the test chain.
if err := n.Start(); err != nil {
- t.Fatalf("can't start test node: %v", err)
+ return nil, nil, fmt.Errorf("can't start test node: %v", err)
}
if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil {
- t.Fatalf("can't import test blocks: %v", err)
+ return nil, nil, fmt.Errorf("can't import test blocks: %v", err)
}
// Ensure the tx indexing is fully generated
for ; ; time.Sleep(time.Millisecond * 100) {
@@ -238,7 +123,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
break
}
}
- return n, blocks
+ return n, blocks, nil
}
func generateTestChain() []*types.Block {
@@ -256,7 +141,10 @@ func generateTestChain() []*types.Block {
}
func TestEthClient(t *testing.T) {
- backend, chain := newTestBackend(t)
+ backend, chain, err := newTestBackend(nil)
+ if err != nil {
+ t.Fatal(err)
+ }
client := backend.Attach()
defer backend.Close()
defer client.Close()
@@ -324,7 +212,7 @@ func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) {
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
@@ -373,7 +261,7 @@ func testBalanceAt(t *testing.T, client *rpc.Client) {
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
@@ -389,7 +277,7 @@ func testBalanceAt(t *testing.T, client *rpc.Client) {
}
func testTransactionInBlock(t *testing.T, client *rpc.Client) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
// Get current block by number.
block, err := ec.BlockByNumber(context.Background(), nil)
@@ -421,7 +309,7 @@ func testTransactionInBlock(t *testing.T, client *rpc.Client) {
}
func testChainID(t *testing.T, client *rpc.Client) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
id, err := ec.ChainID(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -432,7 +320,7 @@ func testChainID(t *testing.T, client *rpc.Client) {
}
func testGetBlock(t *testing.T, client *rpc.Client) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
// Get current block number
blockNumber, err := ec.BlockNumber(context.Background())
@@ -477,7 +365,7 @@ func testGetBlock(t *testing.T, client *rpc.Client) {
}
func testStatusFunctions(t *testing.T, client *rpc.Client) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
// Sync progress
progress, err := ec.SyncProgress(context.Background())
@@ -540,7 +428,7 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) {
}
func testCallContractAtHash(t *testing.T, client *rpc.Client) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
// EstimateGas
msg := ethereum.CallMsg{
@@ -567,7 +455,7 @@ func testCallContractAtHash(t *testing.T, client *rpc.Client) {
}
func testCallContract(t *testing.T, client *rpc.Client) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
// EstimateGas
msg := ethereum.CallMsg{
@@ -594,7 +482,7 @@ func testCallContract(t *testing.T, client *rpc.Client) {
}
func testAtFunctions(t *testing.T, client *rpc.Client) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
block, err := ec.HeaderByNumber(context.Background(), big.NewInt(1))
if err != nil {
@@ -697,7 +585,7 @@ func testAtFunctions(t *testing.T, client *rpc.Client) {
}
func testTransactionSender(t *testing.T, client *rpc.Client) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
ctx := context.Background()
// Retrieve testTx1 via RPC.
@@ -737,7 +625,7 @@ func testTransactionSender(t *testing.T, client *rpc.Client) {
}
}
-func sendTransaction(ec *Client) error {
+func sendTransaction(ec *ethclient.Client) error {
chainID, err := ec.ChainID(context.Background())
if err != nil {
return err
@@ -760,3 +648,40 @@ func sendTransaction(ec *Client) error {
}
return ec.SendTransaction(context.Background(), tx)
}
+
+// Here we show how to get the error message of reverted contract call.
+func ExampleRevertErrorData() {
+ // First create an ethclient.Client instance.
+ ctx := context.Background()
+ ec, _ := ethclient.DialContext(ctx, exampleNode.HTTPEndpoint())
+
+ // Call the contract.
+ // Note we expect the call to return an error.
+ contract := common.HexToAddress("290f1b36649a61e369c6276f6d29463335b4400c")
+ call := ethereum.CallMsg{To: &contract, Gas: 30000}
+ result, err := ec.CallContract(ctx, call, nil)
+ if len(result) > 0 {
+ panic("got result")
+ }
+ if err == nil {
+ panic("call did not return error")
+ }
+
+ // Extract the low-level revert data from the error.
+ revertData, ok := ethclient.RevertErrorData(err)
+ if !ok {
+ panic("unpacking revert failed")
+ }
+ fmt.Printf("revert: %x\n", revertData)
+
+ // Parse the revert data to obtain the error message.
+ message, err := abi.UnpackRevert(revertData)
+ if err != nil {
+ panic("parsing ABI error failed: " + err.Error())
+ }
+ fmt.Println("message:", message)
+
+ // Output:
+ // revert: 08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a75736572206572726f72
+ // message: user error
+}
diff --git a/ethclient/example_test.go b/ethclient/example_test.go
new file mode 100644
index 000000000000..5d0038f0c7ba
--- /dev/null
+++ b/ethclient/example_test.go
@@ -0,0 +1,35 @@
+// Copyright 2024 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package ethclient_test
+
+import (
+ "github.com/ethereum/go-ethereum/node"
+)
+
+var exampleNode *node.Node
+
+// launch example server
+func init() {
+ config := &node.Config{
+ HTTPHost: "127.0.0.1",
+ }
+ n, _, err := newTestBackend(config)
+ if err != nil {
+ panic("can't launch node: " + err.Error())
+ }
+ exampleNode = n
+}
diff --git a/ethclient/types_test.go b/ethclient/types_test.go
new file mode 100644
index 000000000000..02f9f2175880
--- /dev/null
+++ b/ethclient/types_test.go
@@ -0,0 +1,153 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package ethclient
+
+import (
+ "errors"
+ "math/big"
+ "reflect"
+ "testing"
+
+ "github.com/ethereum/go-ethereum"
+ "github.com/ethereum/go-ethereum/common"
+)
+
+func TestToFilterArg(t *testing.T) {
+ blockHashErr := errors.New("cannot specify both BlockHash and FromBlock/ToBlock")
+ addresses := []common.Address{
+ common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"),
+ }
+ blockHash := common.HexToHash(
+ "0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb",
+ )
+
+ for _, testCase := range []struct {
+ name string
+ input ethereum.FilterQuery
+ output interface{}
+ err error
+ }{
+ {
+ "without BlockHash",
+ ethereum.FilterQuery{
+ Addresses: addresses,
+ FromBlock: big.NewInt(1),
+ ToBlock: big.NewInt(2),
+ Topics: [][]common.Hash{},
+ },
+ map[string]interface{}{
+ "address": addresses,
+ "fromBlock": "0x1",
+ "toBlock": "0x2",
+ "topics": [][]common.Hash{},
+ },
+ nil,
+ },
+ {
+ "with nil fromBlock and nil toBlock",
+ ethereum.FilterQuery{
+ Addresses: addresses,
+ Topics: [][]common.Hash{},
+ },
+ map[string]interface{}{
+ "address": addresses,
+ "fromBlock": "0x0",
+ "toBlock": "latest",
+ "topics": [][]common.Hash{},
+ },
+ nil,
+ },
+ {
+ "with negative fromBlock and negative toBlock",
+ ethereum.FilterQuery{
+ Addresses: addresses,
+ FromBlock: big.NewInt(-1),
+ ToBlock: big.NewInt(-1),
+ Topics: [][]common.Hash{},
+ },
+ map[string]interface{}{
+ "address": addresses,
+ "fromBlock": "pending",
+ "toBlock": "pending",
+ "topics": [][]common.Hash{},
+ },
+ nil,
+ },
+ {
+ "with blockhash",
+ ethereum.FilterQuery{
+ Addresses: addresses,
+ BlockHash: &blockHash,
+ Topics: [][]common.Hash{},
+ },
+ map[string]interface{}{
+ "address": addresses,
+ "blockHash": blockHash,
+ "topics": [][]common.Hash{},
+ },
+ nil,
+ },
+ {
+ "with blockhash and from block",
+ ethereum.FilterQuery{
+ Addresses: addresses,
+ BlockHash: &blockHash,
+ FromBlock: big.NewInt(1),
+ Topics: [][]common.Hash{},
+ },
+ nil,
+ blockHashErr,
+ },
+ {
+ "with blockhash and to block",
+ ethereum.FilterQuery{
+ Addresses: addresses,
+ BlockHash: &blockHash,
+ ToBlock: big.NewInt(1),
+ Topics: [][]common.Hash{},
+ },
+ nil,
+ blockHashErr,
+ },
+ {
+ "with blockhash and both from / to block",
+ ethereum.FilterQuery{
+ Addresses: addresses,
+ BlockHash: &blockHash,
+ FromBlock: big.NewInt(1),
+ ToBlock: big.NewInt(2),
+ Topics: [][]common.Hash{},
+ },
+ nil,
+ blockHashErr,
+ },
+ } {
+ t.Run(testCase.name, func(t *testing.T) {
+ output, err := toFilterArg(testCase.input)
+ if (testCase.err == nil) != (err == nil) {
+ t.Fatalf("expected error %v but got %v", testCase.err, err)
+ }
+ if testCase.err != nil {
+ if testCase.err.Error() != err.Error() {
+ t.Fatalf("expected error %v but got %v", testCase.err, err)
+ }
+ } else if !reflect.DeepEqual(testCase.output, output) {
+ t.Fatalf("expected filter arg %v but got %v", testCase.output, output)
+ }
+ })
+ }
+}
diff --git a/go.mod b/go.mod
index d5ae754df2ce..68461bac77b5 100644
--- a/go.mod
+++ b/go.mod
@@ -31,7 +31,7 @@ require (
github.com/fsnotify/fsnotify v1.6.0
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
github.com/gofrs/flock v0.8.1
- github.com/golang-jwt/jwt/v4 v4.5.0
+ github.com/golang-jwt/jwt/v4 v4.5.1
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/google/gofuzz v1.2.0
github.com/google/uuid v1.3.0
diff --git a/go.sum b/go.sum
index 4d6c4dbf166b..82bee92d3d5a 100644
--- a/go.sum
+++ b/go.sum
@@ -213,8 +213,8 @@ github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-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-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
+github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=