mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
swarm/api: Fix error reporting in api.Resolve
Previously, resolve errors were being swallowed and the returned error was a generic "not a content hash" which isn't helpful. This updates the Resolve function to fail fast rather than only returning an error at the end, and also adds test coverage. Signed-off-by: Lewis Marshall <lewis@lmars.net>
This commit is contained in:
parent
7c707d14d1
commit
e265db9ff5
3 changed files with 150 additions and 23 deletions
|
|
@ -25,12 +25,13 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
|
||||||
"mime"
|
"mime"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -84,26 +85,32 @@ type ErrResolve error
|
||||||
func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||||
log.Trace(fmt.Sprintf("Resolving : %v", uri.Addr))
|
log.Trace(fmt.Sprintf("Resolving : %v", uri.Addr))
|
||||||
|
|
||||||
var err error
|
// if the URI is immutable, check if the address is a hash
|
||||||
if !uri.Immutable() {
|
isHash := hashMatcher.MatchString(uri.Addr)
|
||||||
if self.dns != nil {
|
if uri.Immutable() {
|
||||||
resolved, err := self.dns.Resolve(uri.Addr)
|
if !isHash {
|
||||||
if err == nil {
|
return nil, fmt.Errorf("immutable address not a content hash: %q", uri.Addr)
|
||||||
return resolved[:], nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("no DNS to resolve name")
|
|
||||||
}
|
}
|
||||||
|
return common.Hex2Bytes(uri.Addr), nil
|
||||||
}
|
}
|
||||||
if hashMatcher.MatchString(uri.Addr) {
|
|
||||||
return storage.Key(common.Hex2Bytes(uri.Addr)), nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("'%s' does not resolve: %v but is not a content hash", uri.Addr, err)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("'%s' is not a content hash", uri.Addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// if DNS is not configured, check if the address is a hash
|
||||||
|
if self.dns == nil {
|
||||||
|
if !isHash {
|
||||||
|
return nil, fmt.Errorf("no DNS to resolve name: %q", uri.Addr)
|
||||||
|
}
|
||||||
|
return common.Hex2Bytes(uri.Addr), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// try and resolve the address
|
||||||
|
resolved, err := self.dns.Resolve(uri.Addr)
|
||||||
|
if err == nil {
|
||||||
|
return resolved[:], nil
|
||||||
|
} else if !isHash {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return common.Hex2Bytes(uri.Addr), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Put provides singleton manifest creation on top of dpa store
|
// Put provides singleton manifest creation on top of dpa store
|
||||||
func (self *Api) Put(content, contentType string) (storage.Key, error) {
|
func (self *Api) Put(content, contentType string) (storage.Key, error) {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
@ -117,3 +118,122 @@ func TestApiPut(t *testing.T) {
|
||||||
checkResponse(t, resp, exp)
|
checkResponse(t, resp, exp)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testResolver implements the Resolver interface and either returns the given
|
||||||
|
// hash if it is set, or returns a "name not found" error
|
||||||
|
type testResolver struct {
|
||||||
|
hash *common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestResolver(addr string) *testResolver {
|
||||||
|
r := &testResolver{}
|
||||||
|
if addr != "" {
|
||||||
|
hash := common.HexToHash(addr)
|
||||||
|
r.hash = &hash
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testResolver) Resolve(addr string) (common.Hash, error) {
|
||||||
|
if t.hash == nil {
|
||||||
|
return common.Hash{}, fmt.Errorf("DNS name not found: %q", addr)
|
||||||
|
}
|
||||||
|
return *t.hash, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestAPIResolve tests resolving URIs which can either contain content hashes
|
||||||
|
// or ENS names
|
||||||
|
func TestAPIResolve(t *testing.T) {
|
||||||
|
ensAddr := "swarm.eth"
|
||||||
|
hashAddr := "1111111111111111111111111111111111111111111111111111111111111111"
|
||||||
|
resolvedAddr := "2222222222222222222222222222222222222222222222222222222222222222"
|
||||||
|
doesResolve := newTestResolver(resolvedAddr)
|
||||||
|
doesntResolve := newTestResolver("")
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
desc string
|
||||||
|
dns Resolver
|
||||||
|
addr string
|
||||||
|
immutable bool
|
||||||
|
result string
|
||||||
|
expectErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []*test{
|
||||||
|
{
|
||||||
|
desc: "DNS not configured, hash address, returns hash address",
|
||||||
|
dns: nil,
|
||||||
|
addr: hashAddr,
|
||||||
|
result: hashAddr,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "DNS not configured, ENS address, returns error",
|
||||||
|
dns: nil,
|
||||||
|
addr: ensAddr,
|
||||||
|
expectErr: errors.New(`no DNS to resolve name: "swarm.eth"`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "DNS configured, hash address, hash resolves, returns resolved address",
|
||||||
|
dns: doesResolve,
|
||||||
|
addr: hashAddr,
|
||||||
|
result: resolvedAddr,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "DNS configured, immutable hash address, hash resolves, returns hash address",
|
||||||
|
dns: doesResolve,
|
||||||
|
addr: hashAddr,
|
||||||
|
immutable: true,
|
||||||
|
result: hashAddr,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "DNS configured, hash address, hash doesn't resolve, returns hash address",
|
||||||
|
dns: doesntResolve,
|
||||||
|
addr: hashAddr,
|
||||||
|
result: hashAddr,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "DNS configured, ENS address, name resolves, returns resolved address",
|
||||||
|
dns: doesResolve,
|
||||||
|
addr: ensAddr,
|
||||||
|
result: resolvedAddr,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "DNS configured, immutable ENS address, name resolves, returns error",
|
||||||
|
dns: doesResolve,
|
||||||
|
addr: ensAddr,
|
||||||
|
immutable: true,
|
||||||
|
expectErr: errors.New(`immutable address not a content hash: "swarm.eth"`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "DNS configured, ENS address, name doesn't resolve, returns error",
|
||||||
|
dns: doesntResolve,
|
||||||
|
addr: ensAddr,
|
||||||
|
expectErr: errors.New(`DNS name not found: "swarm.eth"`),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, x := range tests {
|
||||||
|
t.Run(x.desc, func(t *testing.T) {
|
||||||
|
api := &Api{dns: x.dns}
|
||||||
|
uri := &URI{Addr: x.addr, Scheme: "bzz"}
|
||||||
|
if x.immutable {
|
||||||
|
uri.Scheme = "bzzi"
|
||||||
|
}
|
||||||
|
res, err := api.Resolve(uri)
|
||||||
|
if err == nil {
|
||||||
|
if x.expectErr != nil {
|
||||||
|
t.Fatalf("expected error %q, got result %q", x.expectErr, res)
|
||||||
|
}
|
||||||
|
if res.String() != x.result {
|
||||||
|
t.Fatalf("expected result %q, got %q", x.result, res)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if x.expectErr == nil {
|
||||||
|
t.Fatalf("expected no error, got %q", err)
|
||||||
|
}
|
||||||
|
if err.Error() != x.expectErr.Error() {
|
||||||
|
t.Fatalf("expected error %q, got %q", x.expectErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,9 @@ func TestBzzrGetPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
nonhashresponses := []string{
|
nonhashresponses := []string{
|
||||||
"error resolving name: 'name' does not resolve: no DNS to resolve name but is not a content hash\n",
|
"error resolving name: no DNS to resolve name: \"name\"\n",
|
||||||
"error resolving nonhash: 'nonhash' is not a content hash\n",
|
"error resolving nonhash: immutable address not a content hash: \"nonhash\"\n",
|
||||||
"error resolving nonhash: 'nonhash' does not resolve: no DNS to resolve name but is not a content hash\n",
|
"error resolving nonhash: no DNS to resolve name: \"nonhash\"\n",
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, url := range nonhashtests {
|
for i, url := range nonhashtests {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue