swarm, cmd/swarm, ethclient: Fullstack mut.rsrc. w api

Add ethclient.Client.BlockNumber method for access to current block
number (needed by ResourceHandler)
Add placeholder manifest support
This commit is contained in:
lash 2018-01-19 20:39:49 +01:00
parent 1bf4f4a37f
commit 249e1a8aaa
12 changed files with 197 additions and 91 deletions

View file

@ -560,7 +560,7 @@ func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *node.
} }
// In production, mockStore must be always nil. // In production, mockStore must be always nil.
return swarm.NewSwarm(ctx, swapClient, ensClient, bzzconfig, bzzconfig.SwapEnabled, bzzconfig.SyncEnabled, bzzconfig.Cors, bzzconfig.PssEnabled, nil) return swarm.NewSwarm(ctx, swapClient, ensClient, bzzconfig, bzzconfig.SwapEnabled, bzzconfig.SyncEnabled, bzzconfig.Cors, bzzconfig.PssEnabled, bzzconfig.ResourceEnabled, nil)
} }
//register within the ethereum node //register within the ethereum node
if err := stack.Register(boot); err != nil { if err := stack.Register(boot); err != nil {

View file

@ -23,6 +23,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"strconv"
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -76,6 +77,15 @@ type rpcBlock struct {
UncleHashes []common.Hash `json:"uncles"` UncleHashes []common.Hash `json:"uncles"`
} }
func (ec *Client) BlockNumber(ctx context.Context) (uint64, error) {
var number string
err := ec.c.CallContext(ctx, &number, "eth_blockNumber")
if err != nil {
return 0, err
}
return strconv.ParseUint(number, 10, 64)
}
func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) {
var raw json.RawMessage var raw json.RawMessage
err := ec.c.CallContext(ctx, &raw, method, args...) err := ec.c.CallContext(ctx, &raw, method, args...)

View file

@ -365,13 +365,13 @@ func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storag
} }
// Look up mutable resource updates at specific periods and versions // Look up mutable resource updates at specific periods and versions
func (self *Api) DbLookup(key storage.Key, name string, period uint32, version uint32) (io.ReadSeeker, error) { func (self *Api) DbLookup(key storage.Key, name string, period uint32, version uint32) (storage.Key, io.ReadSeeker, int, error) {
var err error var err error
if version != 0 { if version != 0 {
if period == 0 { if period == 0 {
currentblocknumber, err := self.resource.GetBlock() currentblocknumber, err := self.resource.GetBlock()
if err != nil { if err != nil {
return nil, fmt.Errorf("Could not determine latest block: %v", err) return nil, nil, 0, fmt.Errorf("Could not determine latest block: %v", err)
} }
period = self.resource.BlockToPeriod(name, currentblocknumber) period = self.resource.BlockToPeriod(name, currentblocknumber)
} }
@ -382,13 +382,13 @@ func (self *Api) DbLookup(key storage.Key, name string, period uint32, version u
_, err = self.resource.LookupLatestByName(name, true) _, err = self.resource.LookupLatestByName(name, true)
} }
if err != nil { if err != nil {
return nil, err return nil, nil, 0, err
} }
data, err := self.resource.GetData(name) key, data, err := self.resource.GetContent(name)
if err != nil { if err != nil {
return nil, err return nil, nil, 0, err
} }
return bytes.NewReader(data), nil return key, bytes.NewReader(data), len(data), nil
} }
func (self *Api) DbCreate(name string, frequency uint64) (err error) { func (self *Api) DbCreate(name string, frequency uint64) (err error) {
@ -406,3 +406,7 @@ func (self *Api) DbUpdate(name string, data []byte) (storage.Key, uint32, uint32
func (self *Api) DbHashSize() int { func (self *Api) DbHashSize() int {
return self.resource.HashSize() return self.resource.HashSize()
} }
func (self *Api) DbIsValidated() bool {
return self.resource.IsValidated()
}

View file

@ -46,22 +46,23 @@ type Config struct {
*network.HiveParams *network.HiveParams
Swap *swap.SwapParams Swap *swap.SwapParams
//*network.SyncParams //*network.SyncParams
Contract common.Address Contract common.Address
EnsRoot common.Address EnsRoot common.Address
EnsApi string EnsApi string
Path string Path string
ListenAddr string ListenAddr string
Port string Port string
PublicKey string PublicKey string
BzzKey string BzzKey string
NetworkId uint64 NetworkId uint64
SwapEnabled bool SwapEnabled bool
SyncEnabled bool SyncEnabled bool
PssEnabled bool PssEnabled bool
SwapApi string ResourceEnabled bool
Cors string SwapApi string
BzzAccount string Cors string
BootNodes string BzzAccount string
BootNodes string
} }
//create a default config with all parameters to set to defaults //create a default config with all parameters to set to defaults
@ -72,18 +73,19 @@ func NewConfig() (self *Config) {
ChunkerParams: storage.NewChunkerParams(), ChunkerParams: storage.NewChunkerParams(),
HiveParams: network.NewHiveParams(), HiveParams: network.NewHiveParams(),
//SyncParams: network.NewDefaultSyncParams(), //SyncParams: network.NewDefaultSyncParams(),
Swap: swap.NewDefaultSwapParams(), Swap: swap.NewDefaultSwapParams(),
ListenAddr: DefaultHTTPListenAddr, ListenAddr: DefaultHTTPListenAddr,
Port: DefaultHTTPPort, Port: DefaultHTTPPort,
Path: node.DefaultDataDir(), Path: node.DefaultDataDir(),
EnsApi: node.DefaultIPCEndpoint("geth"), EnsApi: node.DefaultIPCEndpoint("geth"),
EnsRoot: ens.TestNetAddress, EnsRoot: ens.TestNetAddress,
NetworkId: network.NetworkID, NetworkId: network.NetworkID,
SwapEnabled: false, SwapEnabled: false,
SyncEnabled: true, SyncEnabled: true,
PssEnabled: true, PssEnabled: true,
SwapApi: "", ResourceEnabled: true,
BootNodes: "", SwapApi: "",
BootNodes: "",
} }
return return

View file

@ -327,7 +327,7 @@ func (s *Server) HandlePostDb(w http.ResponseWriter, r *Request) {
func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) { func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) {
w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Type", "application/octet-stream")
key, err := s.api.Resolve(r.uri) rootKey, err := s.api.Resolve(r.uri)
if err != nil { if err != nil {
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
return return
@ -337,12 +337,15 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) {
if len(r.uri.Path) > 0 { if len(r.uri.Path) > 0 {
params = strings.Split(r.uri.Path, "/") params = strings.Split(r.uri.Path, "/")
} }
var updateKey storage.Key
var period uint64 var period uint64
var version uint64 var version uint64
var data io.ReadSeeker var data io.ReadSeeker
var dataLength int
now := time.Now()
switch len(params) { switch len(params) {
case 0: case 0:
data, err = s.api.DbLookup(key, r.uri.Addr, 0, 0) updateKey, data, dataLength, err = s.api.DbLookup(rootKey, r.uri.Addr, 0, 0)
break break
case 2: case 2:
version, err = strconv.ParseUint(params[1], 10, 32) version, err = strconv.ParseUint(params[1], 10, 32)
@ -354,7 +357,7 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) {
if err != nil { if err != nil {
break break
} }
data, err = s.api.DbLookup(key, r.uri.Addr, uint32(period), uint32(version)) updateKey, data, dataLength, err = s.api.DbLookup(rootKey, r.uri.Addr, uint32(period), uint32(version))
break break
default: default:
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
@ -365,9 +368,32 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) {
return return
} }
if !r.uri.DbRaw() { if !r.uri.DbRaw() {
entry := api.ManifestEntry{
Hash: rootKey.Hex(),
Path: updateKey.Hex(),
ContentType: api.DbManifestType,
Size: int64(dataLength),
ModTime: now,
Status: http.StatusOK,
}
mode := (6 << 2) | (4 << 1) | 4
if s.api.DbIsValidated() {
mode |= 2 << 1
}
entry.Mode = int64(mode)
manifest := api.Manifest{
Entries: []api.ManifestEntry{
entry,
},
}
manifestJson, err := json.Marshal(manifest)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
data = bytes.NewReader(manifestJson)
} }
http.ServeContent(w, &r.Request, "", time.Now(), data) http.ServeContent(w, &r.Request, "", now, data)
} }
// HandleGet handles a GET request to // HandleGet handles a GET request to

View file

@ -78,6 +78,16 @@ func TestBzzGetDb(t *testing.T) {
} }
b, err = ioutil.ReadAll(resp.Body) b, err = ioutil.ReadAll(resp.Body)
fmt.Printf("Get: %s : %s\n", resp.Status, b) fmt.Printf("Get: %s : %s\n", resp.Status, b)
url = fmt.Sprintf("%s/bzz-db:/%s", srv.URL, fmt.Sprintf("%x", keybytes))
resp, err = http.Get(url)
if err != nil {
fmt.Printf("err: %v\n", err)
return
}
b, err = ioutil.ReadAll(resp.Body)
fmt.Printf("Get: %s : %s\n", resp.Status, b)
} }
func TestBzzGetPath(t *testing.T) { func TestBzzGetPath(t *testing.T) {

View file

@ -33,7 +33,8 @@ import (
) )
const ( const (
ManifestType = "application/bzz-manifest+json" ManifestType = "application/bzz-manifest+json"
DbManifestType = "application/bzz-db-manifest+json"
) )
// Manifest represents a swarm manifest // Manifest represents a swarm manifest

View file

@ -1,10 +1,10 @@
package storage package storage
import ( import (
"context"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"path/filepath" "path/filepath"
"strconv"
"sync" "sync"
"time" "time"
@ -12,8 +12,8 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
) )
const ( const (
@ -37,6 +37,7 @@ type resource struct {
nameHash common.Hash nameHash common.Hash
startBlock uint64 startBlock uint64
lastPeriod uint32 lastPeriod uint32
lastKey Key
frequency uint64 frequency uint64
version uint32 version uint32
data []byte data []byte
@ -114,26 +115,30 @@ type ResourceValidator interface {
// stored using a separate store, and forwarding/syncing protocols carry per-chunk // stored using a separate store, and forwarding/syncing protocols carry per-chunk
// flags to tell whether the chunk can be validated or not; if not it is to be // flags to tell whether the chunk can be validated or not; if not it is to be
// treated as a resource update chunk. // treated as a resource update chunk.
//
// TODO: Include modtime in chunk data + signature
type ResourceHandler struct { type ResourceHandler struct {
ChunkStore ChunkStore
validator ResourceValidator validator ResourceValidator
rpcClient *rpc.Client ethClient *ethclient.Client
resources map[string]*resource resources map[string]*resource
hashLock sync.Mutex hashLock sync.Mutex
resourceLock sync.RWMutex resourceLock sync.RWMutex
hasher SwarmHash hasher SwarmHash
nameHash nameHashFunc nameHash nameHashFunc
storeTimeout time.Duration storeTimeout time.Duration
ctx context.Context
cancelFunc func()
} }
// Create or open resource update chunk store // Create or open resource update chunk store
// //
// If validator is nil, signature and access validation will be deactivated // If validator is nil, signature and access validation will be deactivated
func NewResourceHandler(datadir string, cloudStore CloudStore, rpcClient *rpc.Client, validator ResourceValidator) (*ResourceHandler, error) { func NewResourceHandler(datadir string, cloudStore CloudStore, ethClient *ethclient.Client, validator ResourceValidator) (*ResourceHandler, error) {
hashfunc := MakeHashFunc(SHA3Hash) hashfunc := MakeHashFunc(SHA3Hash)
path := filepath.Join(datadir, dbDirName) path := filepath.Join(datadir, DbDirName)
dbStore, err := NewDbStore(datadir, hashfunc, singletonSwarmDbCapacity, 0) dbStore, err := NewDbStore(datadir, hashfunc, singletonSwarmDbCapacity, 0)
if err != nil { if err != nil {
return nil, err return nil, err
@ -143,6 +148,7 @@ func NewResourceHandler(datadir string, cloudStore CloudStore, rpcClient *rpc.Cl
DbStore: dbStore, DbStore: dbStore,
} }
ctx, cancel := context.WithCancel(context.Background())
rh := &ResourceHandler{ rh := &ResourceHandler{
ChunkStore: newResourceChunkStore(path, hashfunc, localStore, cloudStore), ChunkStore: newResourceChunkStore(path, hashfunc, localStore, cloudStore),
rpcClient: rpcClient, rpcClient: rpcClient,
@ -150,6 +156,8 @@ func NewResourceHandler(datadir string, cloudStore CloudStore, rpcClient *rpc.Cl
hasher: hashfunc(), hasher: hashfunc(),
validator: validator, validator: validator,
storeTimeout: defaultStoreTimeout, storeTimeout: defaultStoreTimeout,
ctx: ctx,
cancelFunc: cancel,
} }
if rh.validator != nil { if rh.validator != nil {
@ -167,17 +175,22 @@ func NewResourceHandler(datadir string, cloudStore CloudStore, rpcClient *rpc.Cl
return rh, nil return rh, nil
} }
func (self *ResourceHandler) IsValidated() bool {
return self.validator == nil
}
func (self *ResourceHandler) HashSize() int { func (self *ResourceHandler) HashSize() int {
return self.validator.hashSize() return self.validator.hashSize()
} }
// get data from current resource // get data from current resource
func (self *ResourceHandler) GetData(name string) ([]byte, error) {
func (self *ResourceHandler) GetContent(name string) (Key, []byte, error) {
rsrc := self.getResource(name) rsrc := self.getResource(name)
if rsrc == nil || !rsrc.isSynced() { if rsrc == nil || !rsrc.isSynced() {
return nil, fmt.Errorf("Resource does not exist or is not synced") return nil, nil, fmt.Errorf("Resource does not exist or is not synced")
} }
return rsrc.data, nil return rsrc.lastKey, rsrc.data, nil
} }
func (self *ResourceHandler) GetLastPeriod(name string) (uint32, error) { func (self *ResourceHandler) GetLastPeriod(name string) (uint32, error) {
@ -430,6 +443,7 @@ func (self *ResourceHandler) updateResourceIndex(rsrc *resource, chunk *Chunk) (
if *rsrc.name != name { if *rsrc.name != name {
return nil, fmt.Errorf("Update belongs to '%s', but have '%s'", name, *rsrc.name) return nil, fmt.Errorf("Update belongs to '%s', but have '%s'", name, *rsrc.name)
} }
log.Trace("update", "name", *rsrc.name, "rootkey", rsrc.nameHash, "updatekey", chunk.Key, "period", period, "version", version)
// only check signature if validator is present // only check signature if validator is present
if self.validator != nil { if self.validator != nil {
digest := self.keyDataHash(chunk.Key, data) digest := self.keyDataHash(chunk.Key, data)
@ -440,6 +454,7 @@ func (self *ResourceHandler) updateResourceIndex(rsrc *resource, chunk *Chunk) (
} }
// update our rsrcs entry map // update our rsrcs entry map
rsrc.lastKey = chunk.Key
rsrc.lastPeriod = period rsrc.lastPeriod = period
rsrc.version = version rsrc.version = version
rsrc.updated = time.Now() rsrc.updated = time.Now()
@ -582,20 +597,22 @@ func (self *ResourceHandler) Update(name string, data []byte) (Key, error) {
// Closes the datastore. // Closes the datastore.
// Always call this at shutdown to avoid data corruption. // Always call this at shutdown to avoid data corruption.
func (self *ResourceHandler) Close() { func (self *ResourceHandler) Close() {
self.cancelFunc()
self.ChunkStore.Close() self.ChunkStore.Close()
} }
func (self *ResourceHandler) GetBlock() (uint64, error) { func (self *ResourceHandler) GetBlock() (uint64, error) {
return self.ethClient.BlockNumber(self.ctx)
// get the block height and convert to uint64 // get the block height and convert to uint64
var currentblock string // var currentblock string
err := self.rpcClient.Call(&currentblock, "eth_blockNumber") // err := self.rpcClient.Call(&currentblock, "eth_blockNumber")
if err != nil { // if err != nil {
return 0, err // return 0, err
} // }
if currentblock == "0x0" { // if currentblock == "0x0" {
return 0, nil // return 0, nil
} // }
return strconv.ParseUint(currentblock, 10, 64) // return strconv.ParseUint(currentblock, 10, 64)
} }
// Calculate the period index (aka major version number) from a given block number // Calculate the period index (aka major version number) from a given block number

View file

@ -0,0 +1,20 @@
package storage
import (
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
// matches the SignFunc type
func NewGenericResourceSigner(privKey *ecdsa.PrivateKey) SignFunc {
return func(data common.Hash) (signature Signature, err error) {
signaturebytes, err := crypto.Sign(data.Bytes(), privKey)
if err != nil {
return
}
copy(signature[:], signaturebytes)
return
}
}

View file

@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/contracts/ens/contract" "github.com/ethereum/go-ethereum/contracts/ens/contract"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -211,8 +212,8 @@ func TestResourceHandler(t *testing.T) {
// it will match on second iteration startblocknumber + (resourceFrequency * 3) // it will match on second iteration startblocknumber + (resourceFrequency * 3)
fwdBlocks(int(resourceFrequency*2)-1, backend) fwdBlocks(int(resourceFrequency*2)-1, backend)
rh2, err := NewResourceHandler(datadir, &testCloudStore{}, rh.rpcClient, nil) rh2, err := NewResourceHandler(datadir, &testCloudStore{}, rh.ethClient, nil)
_, err = rh2.LookupLatest(safeName, true) _, err = rh2.LookupLatestByName(safeName, true)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
@ -230,7 +231,7 @@ func TestResourceHandler(t *testing.T) {
log.Debug("Latest lookup", "period", rh2.resources[safeName].lastPeriod, "version", rh2.resources[safeName].version, "data", rh2.resources[safeName].data) log.Debug("Latest lookup", "period", rh2.resources[safeName].lastPeriod, "version", rh2.resources[safeName].version, "data", rh2.resources[safeName].data)
// specific block, latest version // specific block, latest version
rsrc, err := rh2.LookupHistorical(safeName, 3, true) rsrc, err := rh2.LookupHistoricalByName(safeName, 3, true)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
@ -241,7 +242,7 @@ func TestResourceHandler(t *testing.T) {
log.Debug("Historical lookup", "period", rh2.resources[safeName].lastPeriod, "version", rh2.resources[safeName].version, "data", rh2.resources[safeName].data) log.Debug("Historical lookup", "period", rh2.resources[safeName].lastPeriod, "version", rh2.resources[safeName].version, "data", rh2.resources[safeName].data)
// specific block, specific version // specific block, specific version
rsrc, err = rh2.LookupVersion(safeName, 3, 1, true) rsrc, err = rh2.LookupVersionByName(safeName, 3, 1, true)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
@ -365,12 +366,14 @@ func setupTest(contractbackend bind.ContractBackend, validator ResourceValidator
} }
// connect to fake rpc // connect to fake rpc
rpcclient, err := rpc.Dial(ipcpath) rpcClient, err := rpc.Dial(ipcpath)
if err != nil { if err != nil {
return return
} }
rh, err = NewResourceHandler(datadir, &testCloudStore{}, rpcclient, validator) ethClient := ethclient.NewClient(rpcClient)
rh, err = NewResourceHandler(datadir, &testCloudStore{}, ethClient, validator)
teardown = func(t *testing.T, err error) { teardown = func(t *testing.T, err error) {
cleanF() cleanF()
if err != nil { if err != nil {
@ -426,8 +429,9 @@ func setupENS(addr common.Address, transactOpts *bind.TransactOpts, sub string,
// implementation of an external signer to pass to validator // implementation of an external signer to pass to validator
type testSigner struct { type testSigner struct {
privKey *ecdsa.PrivateKey privKey *ecdsa.PrivateKey
hasher SwarmHash hasher SwarmHash
signContent SignFunc
} }
func newTestSigner() (*testSigner, error) { func newTestSigner() (*testSigner, error) {
@ -436,21 +440,12 @@ func newTestSigner() (*testSigner, error) {
return nil, err return nil, err
} }
return &testSigner{ return &testSigner{
privKey: privKey, privKey: privKey,
hasher: testHasher, hasher: testHasher,
signContent: NewGenericResourceSigner(privKey),
}, nil }, nil
} }
// matches the SignFunc type
func (self *testSigner) signContent(data common.Hash) (signature Signature, err error) {
signaturebytes, err := crypto.Sign(data.Bytes(), self.privKey)
if err != nil {
return
}
copy(signature[:], signaturebytes)
return
}
type testCloudStore struct { type testCloudStore struct {
} }

View file

@ -22,6 +22,7 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"fmt" "fmt"
"net" "net"
"path/filepath"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -82,7 +83,8 @@ func (self *Swarm) API() *SwarmAPI {
// implements node.Service // implements node.Service
// If mockStore is not nil, it will be used as the storage for chunk data. // If mockStore is not nil, it will be used as the storage for chunk data.
// MockStore should be used only for testing. // MockStore should be used only for testing.
func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, ensClient *ethclient.Client, config *api.Config, swapEnabled, syncEnabled bool, cors string, pssEnabled bool, mockStore *mock.NodeStore) (self *Swarm, err error) { func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, ensClient *ethclient.Client, config *api.Config, swapEnabled, syncEnabled bool, cors string, pssEnabled bool, resourceEnabled bool, mockStore *mock.NodeStore) (self *Swarm, err error) {
if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) { if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) {
return nil, fmt.Errorf("empty public key") return nil, fmt.Errorf("empty public key")
} }
@ -158,7 +160,23 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, ensClient *e
} }
log.Debug(fmt.Sprintf("-> Swarm Domain Name Registrar @ address %v", config.EnsRoot.Hex())) log.Debug(fmt.Sprintf("-> Swarm Domain Name Registrar @ address %v", config.EnsRoot.Hex()))
self.api = api.NewApi(self.dpa, self.dns) var resourceHandler *storage.ResourceHandler
// if use resource updates
if resourceEnabled {
var resourceValidator storage.ResourceValidator
if self.dns != nil {
resourceValidator, err = storage.NewENSValidator(config.EnsRoot, ensClient, transactOpts, storage.NewGenericResourceSigner(self.privateKey))
if err != nil {
return nil, err
}
}
resourceHandler, err = storage.NewResourceHandler(filepath.Join(self.config.Path, storage.DbDirName), self.cloud, ensClient, resourceValidator)
if err != nil {
return nil, err
}
}
self.api = api.NewApi(self.dpa, self.dns, resourceHandler)
// Manifests for Smart Hosting // Manifests for Smart Hosting
log.Debug(fmt.Sprintf("-> Web3 virtual server API")) log.Debug(fmt.Sprintf("-> Web3 virtual server API"))
@ -360,7 +378,7 @@ func NewLocalSwarm(datadir, port string) (self *Swarm, err error) {
} }
self = &Swarm{ self = &Swarm{
api: api.NewApi(dpa, nil), api: api.NewApi(dpa, nil, nil),
config: config, config: config,
} }

View file

@ -25,6 +25,7 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
httpapi "github.com/ethereum/go-ethereum/swarm/api/http" httpapi "github.com/ethereum/go-ethereum/swarm/api/http"
@ -55,30 +56,32 @@ func NewTestSwarmServer(t *testing.T) *TestSwarmServer {
dpa.Start() dpa.Start()
// mutable resources test setup // mutable resources test setup
resourcedir, err := ioutil.TempDir("", "swarm-resource-test") resourceDir, err := ioutil.TempDir("", "swarm-resource-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
ipcpath := filepath.Join(resourcedir, "test.ipc") ipcPath := filepath.Join(resourceDir, "test.ipc")
ipcl, err := rpc.CreateIPCListener(ipcpath) ipcl, err := rpc.CreateIPCListener(ipcPath)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
rpcserver := rpc.NewServer() rpcServer := rpc.NewServer()
rpcserver.RegisterName("eth", &FakeRPC{}) rpcServer.RegisterName("eth", &FakeRPC{})
go func() { go func() {
rpcserver.ServeListener(ipcl) rpcServer.ServeListener(ipcl)
}() }()
rpcClean := func() { rpcClean := func() {
rpcserver.Stop() rpcServer.Stop()
} }
// connect to fake rpc // connect to fake rpc
rpcclient, err := rpc.Dial(ipcpath) rpcClient, err := rpc.Dial(ipcPath)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
rh, err := storage.NewResourceHandler(resourcedir, &testCloudStore{}, rpcclient, nil) ethClient := ethclient.NewClient(rpcClient)
rh, err := storage.NewResourceHandler(resourceDir, &testCloudStore{}, ethClient, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -94,7 +97,7 @@ func NewTestSwarmServer(t *testing.T) *TestSwarmServer {
rh.Close() rh.Close()
rpcClean() rpcClean()
os.RemoveAll(dir) os.RemoveAll(dir)
os.RemoveAll(resourcedir) os.RemoveAll(resourceDir)
}, },
} }
} }