Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
mybee
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
mybee
Commits
99cf7b95
Unverified
Commit
99cf7b95
authored
Dec 08, 2020
by
Pavle Batuta
Committed by
GitHub
Dec 08, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add ENS contract address parameter to config (#1029)
parent
aad68011
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
143 additions
and
67 deletions
+143
-67
ens.go
pkg/resolver/client/ens/ens.go
+69
-17
ens_integration_test.go
pkg/resolver/client/ens/ens_integration_test.go
+14
-7
ens_test.go
pkg/resolver/client/ens/ens_test.go
+44
-28
export_test.go
pkg/resolver/client/ens/export_test.go
+6
-5
multiresolver.go
pkg/resolver/multiresolver/multiresolver.go
+10
-10
No files found.
pkg/resolver/client/ens/ens.go
View file @
99cf7b95
...
...
@@ -5,11 +5,12 @@
package
ens
import
(
"bytes"
"errors"
"fmt"
"strings"
"github.com/ethereum/go-ethereum/
accounts/abi/bind
"
"github.com/ethereum/go-ethereum/
common
"
"github.com/ethereum/go-ethereum/ethclient"
goens
"github.com/wealdtech/go-ens/v3"
...
...
@@ -17,7 +18,10 @@ import (
"github.com/ethersphere/bee/pkg/swarm"
)
const
swarmContentHashPrefix
=
"/swarm/"
const
(
defaultENSContractAddress
=
"00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
swarmContentHashPrefix
=
"/swarm/"
)
// Address is the swarm bzz address.
type
Address
=
swarm
.
Address
...
...
@@ -36,15 +40,19 @@ var (
ErrInvalidContentHash
=
errors
.
New
(
"invalid swarm content hash"
)
// errNotImplemented denotes that the function has not been implemented.
errNotImplemented
=
errors
.
New
(
"function not implemented"
)
// errNameNotRegistered denotes that the name is not registered.
errNameNotRegistered
=
errors
.
New
(
"name is not registered"
)
)
// Client is a name resolution client that can connect to ENS via an
// Ethereum endpoint.
type
Client
struct
{
endpoint
string
ethCl
*
ethclient
.
Client
dialFn
func
(
string
)
(
*
ethclient
.
Client
,
error
)
resolveFn
func
(
bind
.
ContractBackend
,
string
)
(
string
,
error
)
endpoint
string
contractAddr
string
ethCl
*
ethclient
.
Client
connectFn
func
(
string
,
string
)
(
*
ethclient
.
Client
,
*
goens
.
Registry
,
error
)
resolveFn
func
(
*
goens
.
Registry
,
common
.
Address
,
string
)
(
string
,
error
)
registry
*
goens
.
Registry
}
// Option is a function that applies an option to a Client.
...
...
@@ -54,7 +62,7 @@ type Option func(*Client)
func
NewClient
(
endpoint
string
,
opts
...
Option
)
(
client
.
Interface
,
error
)
{
c
:=
&
Client
{
endpoint
:
endpoint
,
dialFn
:
ethclient
.
Dial
,
connectFn
:
wrap
Dial
,
resolveFn
:
wrapResolve
,
}
...
...
@@ -63,20 +71,32 @@ func NewClient(endpoint string, opts ...Option) (client.Interface, error) {
o
(
c
)
}
//
Connect to the name resolution service
.
if
c
.
dialFn
==
nil
{
return
nil
,
fmt
.
Errorf
(
"dialFn: %w"
,
errNotImplemented
)
//
Set the default ENS contract address
.
if
c
.
contractAddr
==
""
{
c
.
contractAddr
=
defaultENSContractAddress
}
ethCl
,
err
:=
c
.
dialFn
(
c
.
endpoint
)
// Establish a connection to the ENS.
if
c
.
connectFn
==
nil
{
return
nil
,
fmt
.
Errorf
(
"connectFn: %w"
,
errNotImplemented
)
}
ethCl
,
registry
,
err
:=
c
.
connectFn
(
c
.
endpoint
,
c
.
contractAddr
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"%v: %w"
,
err
,
ErrFailedToConnect
)
}
c
.
ethCl
=
ethCl
c
.
registry
=
registry
return
c
,
nil
}
// WithContractAddress will set the ENS contract address.
func
WithContractAddress
(
addr
string
)
Option
{
return
func
(
c
*
Client
)
{
c
.
contractAddr
=
addr
}
}
// IsConnected returns true if there is an active RPC connection with an
// Ethereum node at the configured endpoint.
func
(
c
*
Client
)
IsConnected
()
bool
{
...
...
@@ -94,7 +114,7 @@ func (c *Client) Resolve(name string) (Address, error) {
return
swarm
.
ZeroAddress
,
fmt
.
Errorf
(
"resolveFn: %w"
,
errNotImplemented
)
}
hash
,
err
:=
c
.
resolveFn
(
c
.
ethCl
,
name
)
hash
,
err
:=
c
.
resolveFn
(
c
.
registry
,
common
.
HexToAddress
(
c
.
contractAddr
)
,
name
)
if
err
!=
nil
{
return
swarm
.
ZeroAddress
,
fmt
.
Errorf
(
"%v: %w"
,
err
,
ErrResolveFailed
)
}
...
...
@@ -121,18 +141,50 @@ func (c *Client) Close() error {
return
nil
}
func
wrapResolve
(
backend
bind
.
ContractBackend
,
name
string
)
(
string
,
error
)
{
func
wrapDial
(
endpoint
string
,
contractAddr
string
)
(
*
ethclient
.
Client
,
*
goens
.
Registry
,
error
)
{
// Dial the eth client.
ethCl
,
err
:=
ethclient
.
Dial
(
endpoint
)
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"dial: %w"
,
err
)
}
// Obtain the ENS registry.
registry
,
err
:=
goens
.
NewRegistryAt
(
ethCl
,
common
.
HexToAddress
(
contractAddr
))
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"new registry: %w"
,
err
)
}
// Ensure that the ENS registry client is deployed to the given contract address.
_
,
err
=
registry
.
Owner
(
""
)
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"owner: %w"
,
err
)
}
return
ethCl
,
registry
,
nil
}
func
wrapResolve
(
registry
*
goens
.
Registry
,
addr
common
.
Address
,
name
string
)
(
string
,
error
)
{
// Ensure the name is registered.
ownerAddress
,
err
:=
registry
.
Owner
(
name
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"owner: %w"
,
err
)
}
// If the name is not registered, return an error.
if
bytes
.
Equal
(
ownerAddress
.
Bytes
(),
goens
.
UnknownAddress
.
Bytes
())
{
return
""
,
errNameNotRegistered
}
//
Connect to the ENS resolver for the provided
name.
ensR
,
err
:=
goens
.
NewResolver
(
backend
,
name
)
//
Obtain the resolver for this domain
name.
ensR
,
err
:=
registry
.
Resolver
(
name
)
if
err
!=
nil
{
return
""
,
err
return
""
,
fmt
.
Errorf
(
"resolver: %w"
,
err
)
}
// Try and read out the content hash record.
ch
,
err
:=
ensR
.
Contenthash
()
if
err
!=
nil
{
return
""
,
err
return
""
,
fmt
.
Errorf
(
"contenthash: %w"
,
err
)
}
return
goens
.
ContenthashToString
(
ch
)
...
...
pkg/resolver/client/ens/ens_integration_test.go
View file @
99cf7b95
...
...
@@ -20,11 +20,12 @@ func TestENSntegration(t *testing.T) {
defaultAddr
:=
swarm
.
MustParseHexAddress
(
"00cb23598c2e520b6a6aae3ddc94fed4435a2909690bdd709bf9d9e7c2aadfad"
)
testCases
:=
[]
struct
{
desc
string
endpoint
string
name
string
wantAdr
swarm
.
Address
wantErr
error
desc
string
endpoint
string
contractAddress
string
name
string
wantAdr
swarm
.
Address
wantErr
error
}{
// TODO: add a test targeting a resolver with an invalid contenthash
// record.
...
...
@@ -53,6 +54,12 @@ func TestENSntegration(t *testing.T) {
name
:
"nocontent.resolver.test.swarm.eth"
,
wantErr
:
ens
.
ErrResolveFailed
,
},
{
desc
:
"invalid contract address"
,
contractAddress
:
"0xFFFFFFFF"
,
name
:
"example.resolver.test.swarm.eth"
,
wantErr
:
ens
.
ErrFailedToConnect
,
},
{
desc
:
"ok"
,
name
:
"example.resolver.test.swarm.eth"
,
...
...
@@ -65,9 +72,9 @@ func TestENSntegration(t *testing.T) {
tC
.
endpoint
=
defaultEndpoint
}
ensClient
,
err
:=
ens
.
NewClient
(
tC
.
endpoint
)
ensClient
,
err
:=
ens
.
NewClient
(
tC
.
endpoint
,
ens
.
WithContractAddress
(
tC
.
contractAddress
)
)
if
err
!=
nil
{
if
!
errors
.
Is
(
err
,
ens
.
ErrFailedToConnect
)
{
if
!
errors
.
Is
(
err
,
tC
.
wantErr
)
{
t
.
Errorf
(
"got %v, want %v"
,
err
,
tC
.
wantErr
)
}
return
...
...
pkg/resolver/client/ens/ens_test.go
View file @
99cf7b95
...
...
@@ -8,9 +8,10 @@ import (
"errors"
"testing"
"github.com/ethereum/go-ethereum/
accounts/abi/bind
"
"github.com/ethereum/go-ethereum/
common
"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
goens
"github.com/wealdtech/go-ens/v3"
"github.com/ethersphere/bee/pkg/resolver/client/ens"
"github.com/ethersphere/bee/pkg/swarm"
...
...
@@ -20,29 +21,30 @@ func TestNewENSClient(t *testing.T) {
testCases
:=
[]
struct
{
desc
string
endpoint
string
dialFn
func
(
string
)
(
*
ethclient
.
Client
,
error
)
address
string
connectFn
func
(
string
,
string
)
(
*
ethclient
.
Client
,
*
goens
.
Registry
,
error
)
wantErr
error
wantEndpoint
string
}{
{
desc
:
"nil dial function"
,
endpoint
:
"someaddress.net"
,
dialFn
:
nil
,
wantErr
:
ens
.
ErrNotImplemented
,
desc
:
"nil dial function"
,
endpoint
:
"someaddress.net"
,
connectFn
:
nil
,
wantErr
:
ens
.
ErrNotImplemented
,
},
{
desc
:
"error in dial function"
,
endpoint
:
"someaddress.com"
,
dialFn
:
func
(
string
)
(
*
ethclient
.
Client
,
error
)
{
return
nil
,
errors
.
New
(
"dial error"
)
connectFn
:
func
(
s1
,
s2
string
)
(
*
ethclient
.
Client
,
*
goens
.
Registry
,
error
)
{
return
nil
,
nil
,
errors
.
New
(
"dial error"
)
},
wantErr
:
ens
.
ErrFailedToConnect
,
},
{
desc
:
"regular endpoint"
,
endpoint
:
"someaddress.org"
,
dialFn
:
func
(
string
)
(
*
ethclient
.
Client
,
error
)
{
return
&
ethclient
.
Client
{},
nil
connectFn
:
func
(
s1
,
s2
string
)
(
*
ethclient
.
Client
,
*
goens
.
Registry
,
error
)
{
return
&
ethclient
.
Client
{},
nil
,
nil
},
wantEndpoint
:
"someaddress.org"
,
},
...
...
@@ -50,7 +52,8 @@ func TestNewENSClient(t *testing.T) {
for
_
,
tC
:=
range
testCases
{
t
.
Run
(
tC
.
desc
,
func
(
t
*
testing
.
T
)
{
cl
,
err
:=
ens
.
NewClient
(
tC
.
endpoint
,
ens
.
WithDialFunc
(
tC
.
dialFn
),
ens
.
WithConnectFunc
(
tC
.
connectFn
),
ens
.
WithContractAddress
(
tC
.
address
),
)
if
err
!=
nil
{
if
!
errors
.
Is
(
err
,
tC
.
wantErr
)
{
...
...
@@ -75,8 +78,8 @@ func TestClose(t *testing.T) {
ethCl
:=
ethclient
.
NewClient
(
rpc
.
DialInProc
(
rpcServer
))
cl
,
err
:=
ens
.
NewClient
(
""
,
ens
.
With
DialFunc
(
func
(
string
)
(
*
ethclient
.
Client
,
error
)
{
return
ethCl
,
nil
ens
.
With
ConnectFunc
(
func
(
endpoint
,
contractAddr
string
)
(
*
ethclient
.
Client
,
*
goens
.
Registry
,
error
)
{
return
ethCl
,
nil
,
nil
}),
)
if
err
!=
nil
{
...
...
@@ -94,8 +97,8 @@ func TestClose(t *testing.T) {
})
t
.
Run
(
"not connected"
,
func
(
t
*
testing
.
T
)
{
cl
,
err
:=
ens
.
NewClient
(
""
,
ens
.
With
DialFunc
(
func
(
string
)
(
*
ethclient
.
Client
,
error
)
{
return
nil
,
nil
ens
.
With
ConnectFunc
(
func
(
endpoint
,
contractAddr
string
)
(
*
ethclient
.
Client
,
*
goens
.
Registry
,
error
)
{
return
nil
,
nil
,
nil
}),
)
if
err
!=
nil
{
...
...
@@ -114,13 +117,16 @@ func TestClose(t *testing.T) {
}
func
TestResolve
(
t
*
testing
.
T
)
{
addr
:=
swarm
.
MustParseHexAddress
(
"aaabbbcc"
)
testContractAddrString
:=
"00000000000C2E074eC69A0dFb2997BA6C702e1B"
testContractAddr
:=
common
.
HexToAddress
(
testContractAddrString
)
testSwarmAddr
:=
swarm
.
MustParseHexAddress
(
"aaabbbcc"
)
testCases
:=
[]
struct
{
desc
string
name
string
resolveFn
func
(
bind
.
ContractBackend
,
string
)
(
string
,
error
)
wantErr
error
desc
string
name
string
contractAddr
string
resolveFn
func
(
*
goens
.
Registry
,
common
.
Address
,
string
)
(
string
,
error
)
wantErr
error
}{
{
desc
:
"nil resolve function"
,
...
...
@@ -129,38 +135,48 @@ func TestResolve(t *testing.T) {
},
{
desc
:
"resolve function internal error"
,
resolveFn
:
func
(
bind
.
ContractBackend
,
string
)
(
string
,
error
)
{
resolveFn
:
func
(
*
goens
.
Registry
,
common
.
Address
,
string
)
(
string
,
error
)
{
return
""
,
errors
.
New
(
"internal error"
)
},
wantErr
:
ens
.
ErrResolveFailed
,
},
{
desc
:
"resolver returns empty string"
,
resolveFn
:
func
(
bind
.
ContractBackend
,
string
)
(
string
,
error
)
{
resolveFn
:
func
(
*
goens
.
Registry
,
common
.
Address
,
string
)
(
string
,
error
)
{
return
""
,
nil
},
wantErr
:
ens
.
ErrInvalidContentHash
,
},
{
desc
:
"resolve does not prefix address with /swarm"
,
resolveFn
:
func
(
bind
.
ContractBackend
,
string
)
(
string
,
error
)
{
return
a
ddr
.
String
(),
nil
resolveFn
:
func
(
*
goens
.
Registry
,
common
.
Address
,
string
)
(
string
,
error
)
{
return
testSwarmA
ddr
.
String
(),
nil
},
wantErr
:
ens
.
ErrInvalidContentHash
,
},
{
desc
:
"resolve returns prefixed address"
,
resolveFn
:
func
(
bind
.
ContractBackend
,
string
)
(
string
,
error
)
{
return
ens
.
SwarmContentHashPrefix
+
a
ddr
.
String
(),
nil
resolveFn
:
func
(
*
goens
.
Registry
,
common
.
Address
,
string
)
(
string
,
error
)
{
return
ens
.
SwarmContentHashPrefix
+
testSwarmA
ddr
.
String
(),
nil
},
wantErr
:
ens
.
ErrInvalidContentHash
,
},
{
desc
:
"expect properly set contract address"
,
resolveFn
:
func
(
b
*
goens
.
Registry
,
c
common
.
Address
,
s
string
)
(
string
,
error
)
{
if
c
!=
testContractAddr
{
return
""
,
errors
.
New
(
"invalid contract address"
)
}
return
ens
.
SwarmContentHashPrefix
+
testSwarmAddr
.
String
(),
nil
},
},
}
for
_
,
tC
:=
range
testCases
{
t
.
Run
(
tC
.
desc
,
func
(
t
*
testing
.
T
)
{
cl
,
err
:=
ens
.
NewClient
(
"example.com"
,
ens
.
WithDialFunc
(
func
(
string
)
(
*
ethclient
.
Client
,
error
)
{
return
nil
,
nil
ens
.
WithContractAddress
(
testContractAddrString
),
ens
.
WithConnectFunc
(
func
(
endpoint
,
contractAddr
string
)
(
*
ethclient
.
Client
,
*
goens
.
Registry
,
error
)
{
return
nil
,
nil
,
nil
}),
ens
.
WithResolveFunc
(
tC
.
resolveFn
),
)
...
...
pkg/resolver/client/ens/export_test.go
View file @
99cf7b95
...
...
@@ -5,23 +5,24 @@
package
ens
import
(
"github.com/ethereum/go-ethereum/
accounts/abi/bind
"
"github.com/ethereum/go-ethereum/
common
"
"github.com/ethereum/go-ethereum/ethclient"
goens
"github.com/wealdtech/go-ens/v3"
)
const
SwarmContentHashPrefix
=
swarmContentHashPrefix
var
ErrNotImplemented
=
errNotImplemented
// With
Dial
Func will set the Dial function implementaton.
func
With
DialFunc
(
fn
func
(
ep
string
)
(
*
ethclient
.
Client
,
error
))
Option
{
// With
Connect
Func will set the Dial function implementaton.
func
With
ConnectFunc
(
fn
func
(
endpoint
string
,
contractAddr
string
)
(
*
ethclient
.
Client
,
*
goens
.
Registry
,
error
))
Option
{
return
func
(
c
*
Client
)
{
c
.
dial
Fn
=
fn
c
.
connect
Fn
=
fn
}
}
// WithResolveFunc will set the Resolve function implementation.
func
WithResolveFunc
(
fn
func
(
backend
bind
.
ContractBackend
,
input
string
)
(
string
,
error
))
Option
{
func
WithResolveFunc
(
fn
func
(
registry
*
goens
.
Registry
,
addr
common
.
Address
,
input
string
)
(
string
,
error
))
Option
{
return
func
(
c
*
Client
)
{
c
.
resolveFn
=
fn
}
...
...
pkg/resolver/multiresolver/multiresolver.go
View file @
99cf7b95
...
...
@@ -74,14 +74,9 @@ func NewMultiResolver(opts ...Option) *MultiResolver {
// Attempt to conect to each resolver using the connection string.
for
_
,
c
:=
range
mr
.
cfgs
{
// Warn user that the resolver address field is not used.
if
c
.
Address
!=
""
{
log
.
Warningf
(
"name resolver: connection string %q contains resolver address field, which is currently unused"
,
c
.
Address
)
}
// NOTE: if we want to create a specific client based on the TLD
// we can do it here.
mr
.
connectENSClient
(
c
.
TLD
,
c
.
Endpoint
)
mr
.
connectENSClient
(
c
.
TLD
,
c
.
Address
,
c
.
Endpoint
)
}
return
mr
...
...
@@ -189,13 +184,18 @@ func getTLD(name string) string {
return
path
.
Ext
(
strings
.
ToLower
(
name
))
}
func
(
mr
*
MultiResolver
)
connectENSClient
(
tld
string
,
endpoint
string
)
{
func
(
mr
*
MultiResolver
)
connectENSClient
(
tld
string
,
address
string
,
endpoint
string
)
{
log
:=
mr
.
logger
log
.
Debugf
(
"name resolver: resolver for %q: connecting to endpoint %s"
,
tld
,
endpoint
)
ensCl
,
err
:=
ens
.
NewClient
(
endpoint
)
if
address
==
""
{
log
.
Debugf
(
"name resolver: resolver for %q: connecting to endpoint %s"
,
tld
,
endpoint
)
}
else
{
log
.
Debugf
(
"name resolver: resolver for %q: connecting to endpoint %s with contract address %s"
,
tld
,
endpoint
,
address
)
}
ensCl
,
err
:=
ens
.
NewClient
(
endpoint
,
ens
.
WithContractAddress
(
address
))
if
err
!=
nil
{
log
.
Errorf
(
"name resolver: resolver for %q domain
: failed to connect to
%q: %v"
,
tld
,
endpoint
,
err
)
log
.
Errorf
(
"name resolver: resolver for %q domain
on endpoint
%q: %v"
,
tld
,
endpoint
,
err
)
}
else
{
log
.
Infof
(
"name resolver: resolver for %q domain: connected to %s"
,
tld
,
endpoint
)
mr
.
PushResolver
(
tld
,
ensCl
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment