Skip to content

Commit 68306c7

Browse files
authored
Add GETH_HEADERS to be set as a config environment variable (#44)
* Add GETH_HEADERS to be set as a config environment variable * Fix lint error * Rename GethHeaders to GethHeadersEnv * Added GethHeaders tests * Empty CI commit * Empty commit - to get CI working * Add explanation of GETH_HEADERS in README * Revert "Add explanation of GETH_HEADERS in README" This reverts commit 726b8fd. * Fix: Add explanation of GETH_HEADERS in README
1 parent 52fe4d8 commit 68306c7

File tree

7 files changed

+63
-8
lines changed

7 files changed

+63
-8
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ at port `8080`.
6565
* `PORT`(required) - Which port to use for Rosetta.
6666
* `GETH` (optional) - Point to a remote `geth` node instead of initializing one
6767
* `SKIP_GETH_ADMIN` (optional, default: `FALSE`) - Instruct Rosetta to not use the `geth` `admin` RPC calls. This is typically disabled by hosted blockchain node services.
68+
* `GETH_HEADERS` (optional) - Pass a key:value comma-separated list to be passed to the `geth` clients. e.g. `X-Auth-Token:12345-ABCDE,X-Other-Header:SomeOtherValue`
6869

6970
#### Mainnet:Online
7071
```text

cmd/run.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func runRunCmd(cmd *cobra.Command, args []string) error {
9191
}
9292

9393
var err error
94-
client, err = ethereum.NewClient(cfg.GethURL, cfg.Params, cfg.SkipGethAdmin)
94+
client, err = ethereum.NewClient(cfg.GethURL, cfg.Params, cfg.SkipGethAdmin, cfg.GethHeaders)
9595
if err != nil {
9696
return fmt.Errorf("%w: cannot initialize ethereum client", err)
9797
}

configuration/configuration.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020
"os"
2121
"strconv"
22+
"strings"
2223

2324
"github.com/coinbase/rosetta-ethereum/ethereum"
2425

@@ -86,6 +87,11 @@ const (
8687
// by hosted node services. When not set, defaults to false.
8788
SkipGethAdminEnv = "SKIP_GETH_ADMIN"
8889

90+
// GethHeadersEnv is an optional environment variable
91+
// of a comma-separated list of key:value pairs to apply
92+
// to geth clients as headers. When not set, defaults to []
93+
GethHeadersEnv = "GETH_HEADERS"
94+
8995
// MiddlewareVersion is the version of rosetta-ethereum.
9096
MiddlewareVersion = "0.0.4"
9197
)
@@ -100,6 +106,7 @@ type Configuration struct {
100106
Port int
101107
GethArguments string
102108
SkipGethAdmin bool
109+
GethHeaders []*ethereum.HTTPHeader
103110

104111
// Block Reward Data
105112
Params *params.ChainConfig
@@ -179,6 +186,20 @@ func LoadConfiguration() (*Configuration, error) {
179186
config.SkipGethAdmin = val
180187
}
181188

189+
envGethHeaders := os.Getenv(GethHeadersEnv)
190+
if len(envGethHeaders) > 0 {
191+
headers := strings.Split(envGethHeaders, ",")
192+
headerKVs := make([]*ethereum.HTTPHeader, len(headers))
193+
for i, pair := range headers {
194+
kv := strings.Split(pair, ":")
195+
headerKVs[i] = &ethereum.HTTPHeader{
196+
Key: kv[0],
197+
Value: kv[1],
198+
}
199+
}
200+
config.GethHeaders = headerKVs
201+
}
202+
182203
portValue := os.Getenv(PortEnv)
183204
if len(portValue) == 0 {
184205
return nil, errors.New("PORT must be populated")

configuration/configuration_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func TestLoadConfiguration(t *testing.T) {
3333
Port string
3434
Geth string
3535
SkipGethAdmin string
36+
GethHeaders string
3637

3738
cfg *Configuration
3839
err error
@@ -54,6 +55,7 @@ func TestLoadConfiguration(t *testing.T) {
5455
Network: Mainnet,
5556
Port: "1000",
5657
SkipGethAdmin: "FALSE",
58+
GethHeaders: "",
5759
cfg: &Configuration{
5860
Mode: Online,
5961
Network: &types.NetworkIdentifier{
@@ -66,6 +68,7 @@ func TestLoadConfiguration(t *testing.T) {
6668
GethURL: DefaultGethURL,
6769
GethArguments: ethereum.MainnetGethArguments,
6870
SkipGethAdmin: false,
71+
GethHeaders: nil,
6972
},
7073
},
7174
"all set (mainnet) + geth": {
@@ -74,6 +77,7 @@ func TestLoadConfiguration(t *testing.T) {
7477
Port: "1000",
7578
Geth: "http://blah",
7679
SkipGethAdmin: "TRUE",
80+
GethHeaders: "X-Auth-Token:12345-ABCDE,X-Api-Version:2",
7781
cfg: &Configuration{
7882
Mode: Online,
7983
Network: &types.NetworkIdentifier{
@@ -87,6 +91,10 @@ func TestLoadConfiguration(t *testing.T) {
8791
RemoteGeth: true,
8892
GethArguments: ethereum.MainnetGethArguments,
8993
SkipGethAdmin: true,
94+
GethHeaders: []*ethereum.HTTPHeader{
95+
{Key: "X-Auth-Token", Value: "12345-ABCDE"},
96+
{Key: "X-Api-Version", Value: "2"},
97+
},
9098
},
9199
},
92100
"all set (ropsten)": {
@@ -104,6 +112,7 @@ func TestLoadConfiguration(t *testing.T) {
104112
Port: 1000,
105113
GethURL: DefaultGethURL,
106114
GethArguments: ethereum.RopstenGethArguments,
115+
GethHeaders: nil,
107116
},
108117
},
109118
"all set (rinkeby)": {
@@ -121,6 +130,7 @@ func TestLoadConfiguration(t *testing.T) {
121130
Port: 1000,
122131
GethURL: DefaultGethURL,
123132
GethArguments: ethereum.RinkebyGethArguments,
133+
GethHeaders: nil,
124134
},
125135
},
126136
"all set (goerli)": {
@@ -138,13 +148,15 @@ func TestLoadConfiguration(t *testing.T) {
138148
Port: 1000,
139149
GethURL: DefaultGethURL,
140150
GethArguments: ethereum.GoerliGethArguments,
151+
GethHeaders: nil,
141152
},
142153
},
143154
"all set (testnet)": {
144155
Mode: string(Online),
145156
Network: Testnet,
146157
Port: "1000",
147158
SkipGethAdmin: "TRUE",
159+
GethHeaders: "X-Auth-Token:12345-ABCDE,X-Api-Version:2",
148160
cfg: &Configuration{
149161
Mode: Online,
150162
Network: &types.NetworkIdentifier{
@@ -157,6 +169,10 @@ func TestLoadConfiguration(t *testing.T) {
157169
GethURL: DefaultGethURL,
158170
GethArguments: ethereum.RopstenGethArguments,
159171
SkipGethAdmin: true,
172+
GethHeaders: []*ethereum.HTTPHeader{
173+
{Key: "X-Auth-Token", Value: "12345-ABCDE"},
174+
{Key: "X-Api-Version", Value: "2"},
175+
},
160176
},
161177
},
162178
"invalid mode": {
@@ -186,6 +202,7 @@ func TestLoadConfiguration(t *testing.T) {
186202
os.Setenv(PortEnv, test.Port)
187203
os.Setenv(GethEnv, test.Geth)
188204
os.Setenv(SkipGethAdminEnv, test.SkipGethAdmin)
205+
os.Setenv(GethHeadersEnv, test.GethHeaders)
189206

190207
cfg, err := LoadConfiguration()
191208
if test.err != nil {

ethereum/client.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,20 +65,24 @@ type Client struct {
6565
}
6666

6767
// NewClient creates a Client that from the provided url and params.
68-
func NewClient(url string, params *params.ChainConfig, skipAdminCalls bool) (*Client, error) {
68+
func NewClient(url string, params *params.ChainConfig, skipAdminCalls bool, headers []*HTTPHeader) (*Client, error) {
6969
c, err := rpc.DialHTTPWithClient(url, &http.Client{
7070
Timeout: gethHTTPTimeout,
7171
})
7272
if err != nil {
7373
return nil, fmt.Errorf("%w: unable to dial node", err)
7474
}
7575

76+
for _, header := range headers {
77+
c.SetHeader(header.Key, header.Value)
78+
}
79+
7680
tc, err := loadTraceConfig()
7781
if err != nil {
7882
return nil, fmt.Errorf("%w: unable to load trace config", err)
7983
}
8084

81-
g, err := newGraphQLClient(url)
85+
g, err := newGraphQLClient(url, headers)
8286
if err != nil {
8387
return nil, fmt.Errorf("%w: unable to create GraphQL client", err)
8488
}

ethereum/graphql_client.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ const (
3535
// GraphQLClient is a client used to make graphQL
3636
// queries to geth's graphql endpoint.
3737
type GraphQLClient struct {
38-
client *http.Client
39-
url string
38+
client *http.Client
39+
url string
40+
headers []*HTTPHeader
4041
}
4142

4243
// Query makes a query to the graphQL endpoint.
@@ -56,6 +57,10 @@ func (g *GraphQLClient) Query(ctx context.Context, input string) (string, error)
5657
g.url,
5758
bytes.NewBuffer(jsonValue),
5859
)
60+
for _, header := range g.headers {
61+
request.Header.Set(header.Key, header.Value)
62+
}
63+
5964
if err != nil {
6065
return "", err
6166
}
@@ -74,7 +79,7 @@ func (g *GraphQLClient) Query(ctx context.Context, input string) (string, error)
7479
return string(data), nil
7580
}
7681

77-
func newGraphQLClient(baseURL string) (*GraphQLClient, error) {
82+
func newGraphQLClient(baseURL string, headers []*HTTPHeader) (*GraphQLClient, error) {
7883
// Compute GraphQL Endpoint
7984
u, err := url.Parse(baseURL)
8085
if err != nil {
@@ -97,7 +102,8 @@ func newGraphQLClient(baseURL string) (*GraphQLClient, error) {
97102
client.Transport = customTransport
98103

99104
return &GraphQLClient{
100-
client: client,
101-
url: u.String(),
105+
client: client,
106+
url: u.String(),
107+
headers: headers,
102108
}, nil
103109
}

ethereum/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,12 @@ type GraphQL interface {
216216
Query(ctx context.Context, input string) (string, error)
217217
}
218218

219+
// HTTPHeader is key, value pair to be set on the HTTP and GraphQL client.
220+
type HTTPHeader struct {
221+
Key string
222+
Value string
223+
}
224+
219225
// CallType returns a boolean indicating
220226
// if the provided trace type is a call type.
221227
func CallType(t string) bool {

0 commit comments

Comments
 (0)