diff --git a/cmd/swarm/main.go b/cmd/swarm/main.go index 4233c7c982..3ae45d4c2f 100644 --- a/cmd/swarm/main.go +++ b/cmd/swarm/main.go @@ -560,7 +560,7 @@ func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *node. } // In production, mockStore must be always nil. - return swarm.NewSwarm(ctx, swapClient, ensClient, bzzconfig, bzzconfig.SwapEnabled, bzzconfig.SyncEnabled, bzzconfig.Cors, bzzconfig.PssEnabled, bzzconfig.ResourceEnabled, nil) + return swarm.NewSwarm(ctx, swapClient, ensClient, bzzconfig, nil) } //register within the ethereum node if err := stack.Register(boot); err != nil { diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 4b53e785d6..2d9553a7bd 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -23,7 +23,6 @@ import ( "errors" "fmt" "math/big" - "strconv" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -77,13 +76,19 @@ type rpcBlock struct { 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") +func (ec *Client) BlockNumber(ctx context.Context) (big.Int, error) { + var numberstr string + number := &big.Int{} + err := ec.c.CallContext(ctx, &numberstr, "eth_blockNumber") if err != nil { - return 0, err + return *number, err } - return strconv.ParseUint(number, 10, 64) + var ok bool + number, ok = number.SetString(numberstr, 10) + if !ok { + err = errors.New("Failed to parse bigint") + } + return *number, err } func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { diff --git a/swarm/api/api.go b/swarm/api/api.go index 0e11028ec4..1393fa4406 100644 --- a/swarm/api/api.go +++ b/swarm/api/api.go @@ -365,13 +365,13 @@ func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storag } // Look up mutable resource updates at specific periods and versions -func (self *Api) DbLookup(key storage.Key, name string, period uint32, version uint32) (storage.Key, io.ReadSeeker, int, error) { +func (self *Api) DbLookup(key storage.Key, name string, period uint32, version uint32) (storage.Key, []byte, error) { var err error if version != 0 { if period == 0 { currentblocknumber, err := self.resource.GetBlock() if err != nil { - return nil, nil, 0, fmt.Errorf("Could not determine latest block: %v", err) + return nil, nil, fmt.Errorf("Could not determine latest block: %v", err) } 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) } if err != nil { - return nil, nil, 0, err + return nil, nil, err } key, data, err := self.resource.GetContent(name) if err != nil { - return nil, nil, 0, err + return nil, nil, err } - return key, bytes.NewReader(data), len(data), nil + return key, data, nil } func (self *Api) DbCreate(name string, frequency uint64) (err error) { diff --git a/swarm/api/config.go b/swarm/api/config.go index 31281f9bff..93b386cc11 100644 --- a/swarm/api/config.go +++ b/swarm/api/config.go @@ -110,8 +110,8 @@ func (self *Config) Init(prvKey *ecdsa.PrivateKey) { self.PublicKey = pubkeyhex self.BzzKey = keyhex - self.Swap.Init(self.Contract, prvKey) - //self.SyncParams.Init(self.Path) - //self.HiveParams.Init(self.Path) + if self.SwapEnabled { + self.Swap.Init(self.Contract, prvKey) + } self.StoreParams.Init(self.Path) } diff --git a/swarm/api/config_test.go b/swarm/api/config_test.go index 993388686b..5a5f176c0b 100644 --- a/swarm/api/config_test.go +++ b/swarm/api/config_test.go @@ -49,12 +49,9 @@ func TestConfig(t *testing.T) { if one.PublicKey == "" { t.Fatal("Expected PublicKey to be set") } - - //the Init function should append subdirs to the given path - if one.Swap.PayProfile.Beneficiary == (common.Address{}) { + if one.Swap.PayProfile.Beneficiary == (common.Address{}) && one.SwapEnabled { t.Fatal("Failed to correctly initialize SwapParams") } - if one.StoreParams.ChunkDbPath == one.Path { t.Fatal("Failed to correctly initialize StoreParams") } diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go index 26c59c313e..2a8046f1c7 100644 --- a/swarm/api/http/server.go +++ b/swarm/api/http/server.go @@ -295,13 +295,12 @@ func (s *Server) HandlePostDb(w http.ResponseWriter, r *Request) { if r.ContentLength == 0 { frequency, err := strconv.ParseUint(r.uri.Path, 10, 64) if err != nil { - w.WriteHeader(http.StatusBadRequest) - http.ServeContent(w, &r.Request, "", time.Now(), bytes.NewReader([]byte(err.Error()))) + s.BadRequest(w, r, fmt.Sprintf("Cannot parse frequency parameter: %v", err)) return } err = s.api.DbCreate(r.uri.Addr, frequency) if err != nil { - w.WriteHeader(http.StatusInternalServerError) + s.Error(w, r, fmt.Errorf("Resource creation failed: %v", err)) return } } else { @@ -324,8 +323,8 @@ func (s *Server) HandlePostDb(w http.ResponseWriter, r *Request) { // bzz-db[-[immutable|-raw]]:// - get latest update // bzz-db[-[immutable|-raw]]:/// - get latest update on period n // bzz-db[-[immutable|-raw]]://// - get update version m of period n +// = ens name or hash func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) { - w.Header().Set("Content-Type", "application/octet-stream") rootKey, err := s.api.Resolve(r.uri) if err != nil { @@ -340,34 +339,39 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) { var updateKey storage.Key var period uint64 var version uint64 - var data io.ReadSeeker + var data []byte var dataLength int now := time.Now() switch len(params) { case 0: - updateKey, data, dataLength, err = s.api.DbLookup(rootKey, r.uri.Addr, 0, 0) - break + updateKey, data, err = s.api.DbLookup(rootKey, r.uri.Addr, 0, 0) case 2: version, err = strconv.ParseUint(params[1], 10, 32) if err != nil { break } + updateKey, data, err = s.api.DbLookup(rootKey, r.uri.Addr, uint32(period), uint32(version)) case 1: + version, err = strconv.ParseUint(params[1], 10, 32) + if err != nil { + break + } period, err = strconv.ParseUint(params[0], 10, 32) if err != nil { break } - updateKey, data, dataLength, err = s.api.DbLookup(rootKey, r.uri.Addr, uint32(period), uint32(version)) - break + updateKey, data, err = s.api.DbLookup(rootKey, r.uri.Addr, uint32(period), uint32(version)) default: - w.WriteHeader(http.StatusBadRequest) - err = fmt.Errorf("params 0-2") + s.BadRequest(w, r, fmt.Sprintf("Invalid mutable resource request")) + return } if err != nil { - w.WriteHeader(http.StatusInternalServerError) + s.Error(w, r, fmt.Errorf("Mutable resource lookup failed: %v", err)) return } if !r.uri.DbRaw() { + w.Header().Set("Content-Type", "application/octet-stream") + } else { entry := api.ManifestEntry{ Hash: rootKey.Hex(), Path: updateKey.Hex(), @@ -376,9 +380,9 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) { ModTime: now, Status: http.StatusOK, } - mode := (6 << 2) | (4 << 1) | 4 + mode := 0644 if s.api.DbIsValidated() { - mode |= 2 << 1 + mode |= (2 << 3) | 2 } entry.Mode = int64(mode) manifest := api.Manifest{ @@ -388,12 +392,13 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) { } manifestJson, err := json.Marshal(manifest) if err != nil { - w.WriteHeader(http.StatusInternalServerError) + s.Error(w, r, fmt.Errorf("Could not convert manifest to json: %v", err)) return } - data = bytes.NewReader(manifestJson) + w.Header().Set("Content-Type", api.DbManifestType) + data = []byte(manifestJson) } - http.ServeContent(w, &r.Request, "", now, data) + http.ServeContent(w, &r.Request, "", now, bytes.NewReader(data)) } // HandleGet handles a GET request to diff --git a/swarm/api/http/server_test.go b/swarm/api/http/server_test.go index e2165f1d61..42c9ce3f56 100644 --- a/swarm/api/http/server_test.go +++ b/swarm/api/http/server_test.go @@ -47,46 +47,53 @@ func TestBzzGetDb(t *testing.T) { keybytes := make([]byte, common.HashLength) // nearest we get to source of info _, err := rand.Read(keybytes) if err != nil { - fmt.Printf("err: %v\n", err) - return + t.Fatal(err) } url := fmt.Sprintf("%s/bzz-db:/%s/42", srv.URL, fmt.Sprintf("%x", keybytes)) resp, err := http.Post(url, "application/octet-stream", nil) if err != nil { - fmt.Printf("err: %v\n", err) - return + t.Fatal(err) } b, err := ioutil.ReadAll(resp.Body) - fmt.Printf("Create: %s : %s\n", resp.Status, b) + if err != nil { + t.Fatal(err) + } + log.Debug("Create", "status", resp.Status, "body", b) - url = fmt.Sprintf("%s/bzz-db:/%s", srv.URL, fmt.Sprintf("%x", keybytes)) + url = fmt.Sprintf("%s/bzz-db:/%x", srv.URL, keybytes) data := []byte("foo") resp, err = http.Post(url, "application/octet-stream", bytes.NewReader(data)) if err != nil { - fmt.Printf("err: %v\n", err) - return + t.Fatal(err) } b, err = ioutil.ReadAll(resp.Body) - fmt.Printf("Update: %s : %s\n", resp.Status, b) + if err != nil { + t.Fatal(err) + } + log.Debug("Update", "status", resp.Status, "body", b) url = fmt.Sprintf("%s/bzz-db-raw:/%s", srv.URL, fmt.Sprintf("%x", keybytes)) resp, err = http.Get(url) if err != nil { - fmt.Printf("err: %v\n", err) - return + t.Fatal(err) } b, err = ioutil.ReadAll(resp.Body) - fmt.Printf("Get: %s : %s\n", resp.Status, b) + if err != nil { + t.Fatal(err) + } + log.Debug("Get raw", "status", resp.Status, "body", 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 + t.Fatal(err) } b, err = ioutil.ReadAll(resp.Body) - fmt.Printf("Get: %s : %s\n", resp.Status, b) + if err != nil { + t.Fatal(err) + } + log.Debug("Get manifest", "status", resp.Status, "body", b) } diff --git a/swarm/storage/resource.go b/swarm/storage/resource.go index 23e1a6336b..c51a85105b 100644 --- a/swarm/storage/resource.go +++ b/swarm/storage/resource.go @@ -4,6 +4,7 @@ import ( "context" "encoding/binary" "fmt" + "math/big" "path/filepath" "sync" "time" @@ -12,7 +13,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" ) @@ -58,6 +58,10 @@ type ResourceValidator interface { sign(common.Hash) (Signature, error) // SignFunc } +type ethApi interface { + BlockNumber(context.Context) (big.Int, error) +} + // Mutable resource is an entity which allows updates to a resource // without resorting to ENS on each update. // The update scheme is built on swarm chunks with chunk keys following @@ -119,8 +123,10 @@ type ResourceValidator interface { // TODO: Include modtime in chunk data + signature type ResourceHandler struct { ChunkStore + ctx context.Context + cancelFunc func() validator ResourceValidator - ethClient *ethclient.Client + ethClient ethApi resources map[string]*resource hashLock sync.Mutex resourceLock sync.RWMutex @@ -134,7 +140,7 @@ type ResourceHandler struct { // Create or open resource update chunk store // // If validator is nil, signature and access validation will be deactivated -func NewResourceHandler(datadir string, cloudStore CloudStore, ethClient *ethclient.Client, validator ResourceValidator) (*ResourceHandler, error) { +func NewResourceHandler(datadir string, cloudStore CloudStore, ethClient ethApi, validator ResourceValidator) (*ResourceHandler, error) { hashfunc := MakeHashFunc(SHA3Hash) @@ -602,17 +608,11 @@ func (self *ResourceHandler) Close() { } func (self *ResourceHandler) GetBlock() (uint64, error) { - return self.ethClient.BlockNumber(self.ctx) - // get the block height and convert to uint64 - // var currentblock string - // err := self.rpcClient.Call(¤tblock, "eth_blockNumber") - // if err != nil { - // return 0, err - // } - // if currentblock == "0x0" { - // return 0, nil - // } - // return strconv.ParseUint(currentblock, 10, 64) + bigblocknumber, err := self.ethClient.BlockNumber(self.ctx) + if err != nil { + return 0, err + } + return bigblocknumber.Uint64(), nil } // Calculate the period index (aka major version number) from a given block number @@ -776,10 +776,7 @@ func isSafeName(name string) bool { if err != nil { return false } - if validname != name { - return false - } - return true + return validname == name } // convenience for creating signature hashes of update data diff --git a/swarm/storage/resource_test.go b/swarm/storage/resource_test.go index 2da9b7704a..dd96f0b3d7 100644 --- a/swarm/storage/resource_test.go +++ b/swarm/storage/resource_test.go @@ -2,6 +2,7 @@ package storage import ( "bytes" + "context" "crypto/ecdsa" "crypto/rand" "encoding/binary" @@ -9,8 +10,6 @@ import ( "io/ioutil" "math/big" "os" - "path/filepath" - "strconv" "strings" "testing" "time" @@ -22,9 +21,7 @@ import ( "github.com/ethereum/go-ethereum/contracts/ens/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" ) var ( @@ -50,7 +47,7 @@ func init() { // so we use this wrapper to fake returning the block count type fakeBackend struct { *backends.SimulatedBackend - blocknumber uint64 + blocknumber int64 } func (f *fakeBackend) Commit() { @@ -60,13 +57,10 @@ func (f *fakeBackend) Commit() { f.blocknumber++ } -// for faking the rpc service, since we don't need the whole node stack -type FakeRPC struct { - backend *fakeBackend -} - -func (r *FakeRPC) BlockNumber() (string, error) { - return strconv.FormatUint(r.backend.blocknumber, 10), nil +func (f *fakeBackend) BlockNumber(context context.Context) (big.Int, error) { + f.blocknumber++ + biggie := big.NewInt(f.blocknumber) + return *biggie, nil } // check that signature address matches update signer address @@ -84,8 +78,9 @@ func TestResourceReverse(t *testing.T) { // set up rpc and create resourcehandler rh, _, _, teardownTest, err := setupTest(nil, newTestValidator(signer.signContent)) if err != nil { - teardownTest(t, err) + t.Fatal(err) } + defer teardownTest() // generate a hash for block 4200 version 1 key := rh.resourceHash(period, version, rh.nameHash(safeName)) @@ -94,14 +89,14 @@ func TestResourceReverse(t *testing.T) { data := make([]byte, 8) _, err = rand.Read(data) if err != nil { - teardownTest(t, err) + t.Fatal(err) } testHasher.Reset() testHasher.Write(data) digest := rh.keyDataHash(key, data) sig, err := rh.validator.sign(digest) if err != nil { - teardownTest(t, err) + t.Fatal(err) } chunk := newUpdateChunk(key, &sig, period, version, safeName, data) @@ -111,31 +106,30 @@ func TestResourceReverse(t *testing.T) { checkdigest := rh.keyDataHash(chunk.Key, checkdata) recoveredaddress, err := getAddressFromDataSig(checkdigest, *checksig) if err != nil { - teardownTest(t, fmt.Errorf("Retrieve address from signature fail: %v", err)) + t.Fatalf("Retrieve address from signature fail: %v", err) } originaladdress := crypto.PubkeyToAddress(signer.privKey.PublicKey) // check that the metadata retrieved from the chunk matches what we gave it if recoveredaddress != originaladdress { - teardownTest(t, fmt.Errorf("addresses dont match: %x != %x", originaladdress, recoveredaddress)) + t.Fatalf("addresses dont match: %x != %x", originaladdress, recoveredaddress) } if !bytes.Equal(key[:], chunk.Key[:]) { - teardownTest(t, fmt.Errorf("Expected chunk key '%x', was '%x'", key, chunk.Key)) + t.Fatalf("Expected chunk key '%x', was '%x'", key, chunk.Key) } if period != checkperiod { - teardownTest(t, fmt.Errorf("Expected period '%d', was '%d'", period, checkperiod)) + t.Fatalf("Expected period '%d', was '%d'", period, checkperiod) } if version != checkversion { - teardownTest(t, fmt.Errorf("Expected version '%d', was '%d'", version, checkversion)) + t.Fatalf("Expected version '%d', was '%d'", version, checkversion) } if safeName != checkname { - teardownTest(t, fmt.Errorf("Expected name '%s', was '%s'", safeName, checkname)) + t.Fatalf("Expected name '%s', was '%s'", safeName, checkname) } if !bytes.Equal(data, checkdata) { - teardownTest(t, fmt.Errorf("Expectedn data '%x', was '%x'", data, checkdata)) + t.Fatalf("Expectedn data '%x', was '%x'", data, checkdata) } - teardownTest(t, nil) } // make updates and retrieve them based on periods and versions @@ -143,34 +137,35 @@ func TestResourceHandler(t *testing.T) { // make fake backend, set up rpc and create resourcehandler backend := &fakeBackend{ - blocknumber: startBlock, + blocknumber: int64(startBlock), } rh, datadir, _, teardownTest, err := setupTest(backend, nil) if err != nil { - teardownTest(t, err) + t.Fatal(err) } + defer teardownTest() // create a new resource _, err = rh.NewResource(safeName, resourceFrequency) if err != nil { - teardownTest(t, err) + t.Fatal(err) } // check that the new resource is stored correctly namehash := rh.nameHash(safeName) chunk, err := rh.ChunkStore.(*resourceChunkStore).localStore.(*LocalStore).memStore.Get(Key(namehash[:])) if err != nil { - teardownTest(t, err) + t.Fatal(err) } else if len(chunk.SData) < 16 { - teardownTest(t, fmt.Errorf("chunk data must be minimum 16 bytes, is %d", len(chunk.SData))) + t.Fatalf("chunk data must be minimum 16 bytes, is %d", len(chunk.SData)) } startblocknumber := binary.LittleEndian.Uint64(chunk.SData[:8]) chunkfrequency := binary.LittleEndian.Uint64(chunk.SData[8:]) - if startblocknumber != backend.blocknumber { - teardownTest(t, fmt.Errorf("stored block number %d does not match provided block number %d", startblocknumber, backend.blocknumber)) + if startblocknumber != uint64(backend.blocknumber) { + t.Fatalf("stored block number %d does not match provided block number %d", startblocknumber, backend.blocknumber) } if chunkfrequency != resourceFrequency { - teardownTest(t, fmt.Errorf("stored frequency %d does not match provided frequency %d", chunkfrequency, resourceFrequency)) + t.Fatalf("stored frequency %d does not match provided frequency %d", chunkfrequency, resourceFrequency) } // update halfway to first period @@ -179,7 +174,7 @@ func TestResourceHandler(t *testing.T) { data := []byte("blinky") resourcekey["blinky"], err = rh.Update(safeName, data) if err != nil { - teardownTest(t, err) + t.Fatal(err) } // update on first period @@ -187,7 +182,7 @@ func TestResourceHandler(t *testing.T) { data = []byte("pinky") resourcekey["pinky"], err = rh.Update(safeName, data) if err != nil { - teardownTest(t, err) + t.Fatal(err) } // update on second period @@ -195,7 +190,7 @@ func TestResourceHandler(t *testing.T) { data = []byte("inky") resourcekey["inky"], err = rh.Update(safeName, data) if err != nil { - teardownTest(t, err) + t.Fatal(err) } // update just after second period @@ -203,7 +198,7 @@ func TestResourceHandler(t *testing.T) { data = []byte("clyde") resourcekey["clyde"], err = rh.Update(safeName, data) if err != nil { - teardownTest(t, err) + t.Fatal(err) } time.Sleep(time.Second) rh.Close() @@ -215,43 +210,42 @@ func TestResourceHandler(t *testing.T) { rh2, err := NewResourceHandler(datadir, &testCloudStore{}, rh.ethClient, nil) _, err = rh2.LookupLatestByName(safeName, true) if err != nil { - teardownTest(t, err) + t.Fatal(err) } // last update should be "clyde", version two, blockheight startblocknumber + (resourcefrequency * 3) if !bytes.Equal(rh2.resources[safeName].data, []byte("clyde")) { - teardownTest(t, fmt.Errorf("resource data was %v, expected %v", rh2.resources[safeName].data, []byte("clyde"))) + t.Fatalf("resource data was %v, expected %v", rh2.resources[safeName].data, []byte("clyde")) } if rh2.resources[safeName].version != 2 { - teardownTest(t, fmt.Errorf("resource version was %d, expected 2", rh2.resources[safeName].version)) + t.Fatalf("resource version was %d, expected 2", rh2.resources[safeName].version) } if rh2.resources[safeName].lastPeriod != 3 { - teardownTest(t, fmt.Errorf("resource period was %d, expected 3", rh2.resources[safeName].lastPeriod)) + t.Fatalf("resource period was %d, expected 3", rh2.resources[safeName].lastPeriod) } log.Debug("Latest lookup", "period", rh2.resources[safeName].lastPeriod, "version", rh2.resources[safeName].version, "data", rh2.resources[safeName].data) // specific block, latest version rsrc, err := rh2.LookupHistoricalByName(safeName, 3, true) if err != nil { - teardownTest(t, err) + t.Fatal(err) } // check data if !bytes.Equal(rsrc.data, []byte("clyde")) { - teardownTest(t, fmt.Errorf("resource data (historical) was %v, expected %v", rh2.resources[domainName].data, []byte("clyde"))) + t.Fatalf("resource data (historical) was %v, expected %v", rh2.resources[domainName].data, []byte("clyde")) } log.Debug("Historical lookup", "period", rh2.resources[safeName].lastPeriod, "version", rh2.resources[safeName].version, "data", rh2.resources[safeName].data) // specific block, specific version rsrc, err = rh2.LookupVersionByName(safeName, 3, 1, true) if err != nil { - teardownTest(t, err) + t.Fatal(err) } // check data if !bytes.Equal(rsrc.data, []byte("inky")) { - teardownTest(t, fmt.Errorf("resource data (historical) was %v, expected %v", rh2.resources[domainName].data, []byte("inky"))) + t.Fatalf("resource data (historical) was %v, expected %v", rh2.resources[domainName].data, []byte("inky")) } log.Debug("Specific version lookup", "period", rh2.resources[safeName].lastPeriod, "version", rh2.resources[safeName].version, "data", rh2.resources[safeName].data) - teardownTest(t, nil) } @@ -283,34 +277,33 @@ func TestResourceENSOwner(t *testing.T) { // set up rpc and create resourcehandler with ENS sim backend rh, _, _, teardownTest, err := setupTest(contractbackend, validator) if err != nil { - teardownTest(t, err) + t.Fatal(err) } + defer teardownTest() // create new resource when we are owner = ok _, err = rh.NewResource(safeName, resourceFrequency) if err != nil { - teardownTest(t, fmt.Errorf("Create resource fail: %v", err)) + t.Fatalf("Create resource fail: %v", err) } data := []byte("foo") // update resource when we are owner = ok _, err = rh.Update(safeName, data) if err != nil { - teardownTest(t, fmt.Errorf("Update resource fail: %v", err)) + t.Fatalf("Update resource fail: %v", err) } // update resource when we are owner = ok signertwo, err := newTestSigner() if err != nil { - teardownTest(t, err) + t.Fatal(err) } rh.validator.(*ENSValidator).signFunc = signertwo.signContent _, err = rh.Update(safeName, data) if err == nil { - teardownTest(t, fmt.Errorf("Expected resource update fail due to owner mismatch")) + t.Fatalf("Expected resource update fail due to owner mismatch") } - - teardownTest(t, nil) } // fast-forward blockheight @@ -321,7 +314,7 @@ func fwdBlocks(count int, backend *fakeBackend) { } // create rpc and resourcehandler -func setupTest(contractbackend bind.ContractBackend, validator ResourceValidator) (rh *ResourceHandler, datadir string, signer *testSigner, teardown func(*testing.T, error), err error) { +func setupTest(backend ethApi, validator ResourceValidator) (rh *ResourceHandler, datadir string, signer *testSigner, teardown func(), err error) { var fsClean func() var rpcClean func() @@ -337,55 +330,18 @@ func setupTest(contractbackend bind.ContractBackend, validator ResourceValidator // temp datadir datadir, err = ioutil.TempDir("", "rh") if err != nil { - return + return nil, "", nil, nil, err } fsClean = func() { os.RemoveAll(datadir) } - // starting the whole stack just to get blocknumbers is too cumbersome - // so we fake the rpc server to get blocknumbers for testing - ipcpath := filepath.Join(datadir, "test.ipc") - ipcl, err := rpc.CreateIPCListener(ipcpath) - if err != nil { - return - } - rpcserver := rpc.NewServer() - var fake *fakeBackend - if contractbackend != nil { - fake = contractbackend.(*fakeBackend) - } - rpcserver.RegisterName("eth", &FakeRPC{ - backend: fake, - }) - go func() { - rpcserver.ServeListener(ipcl) - }() - rpcClean = func() { - rpcserver.Stop() - } - - // connect to fake rpc - rpcClient, err := rpc.Dial(ipcpath) - if err != nil { - return - } - - ethClient := ethclient.NewClient(rpcClient) - - rh, err = NewResourceHandler(datadir, &testCloudStore{}, ethClient, validator) - teardown = func(t *testing.T, err error) { - cleanF() - if err != nil { - t.Fatal(err) - } - } - - return + rh, err = NewResourceHandler(datadir, &testCloudStore{}, backend, validator) + return rh, datadir, signer, cleanF, nil } // Set up simulated ENS backend for use with ENSResourceHandler tests -func setupENS(addr common.Address, transactOpts *bind.TransactOpts, sub string, top string) (common.Address, bind.ContractBackend, error) { +func setupENS(addr common.Address, transactOpts *bind.TransactOpts, sub string, top string) (common.Address, *fakeBackend, error) { // create the domain hash values to pass to the ENS contract methods var tophash [32]byte diff --git a/swarm/swarm.go b/swarm/swarm.go index 766c210d3d..c650567947 100644 --- a/swarm/swarm.go +++ b/swarm/swarm.go @@ -54,15 +54,13 @@ type Swarm struct { storage storage.ChunkStore // internal access to storage, common interface to cloud storage backends dpa *storage.DPA // distributed preimage archive, the local API to the storage with document level storage/retrieval support //depo network.StorageHandler // remote request handler, interface between bzz protocol and the storage - cloud storage.CloudStore // procurement, cloud storage backend (can multi-cloud) - bzz *network.Bzz // the logistic manager - backend chequebook.Backend // simple blockchain Backend - privateKey *ecdsa.PrivateKey - corsString string - swapEnabled bool - lstore *storage.LocalStore // local store, needs to store for releasing resources after node stopped - sfs *fuse.SwarmFS // need this to cleanup all the active mounts on node exit - ps *pss.Pss + cloud storage.CloudStore // procurement, cloud storage backend (can multi-cloud) + bzz *network.Bzz // the logistic manager + backend chequebook.Backend // simple blockchain Backend + privateKey *ecdsa.PrivateKey + lstore *storage.LocalStore // local store, needs to store for releasing resources after node stopped + sfs *fuse.SwarmFS // need this to cleanup all the active mounts on node exit + ps *pss.Pss } type SwarmAPI struct { @@ -83,7 +81,7 @@ func (self *Swarm) API() *SwarmAPI { // implements node.Service // If mockStore is not nil, it will be used as the storage for chunk data. // 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, resourceEnabled bool, mockStore *mock.NodeStore) (self *Swarm, err error) { +func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, ensClient *ethclient.Client, config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err error) { if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) { return nil, fmt.Errorf("empty public key") @@ -93,11 +91,9 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, ensClient *e } self = &Swarm{ - config: config, - swapEnabled: swapEnabled, - backend: backend, - privateKey: config.Swap.PrivateKey(), - corsString: cors, + config: config, + backend: backend, + privateKey: config.Swap.PrivateKey(), } log.Debug(fmt.Sprintf("Setting up Swarm service components")) @@ -139,7 +135,7 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, ensClient *e log.Debug(fmt.Sprintf("-> Content Store API")) // Pss = postal service over swarm (devp2p over bzz) - if pssEnabled { + if self.config.PssEnabled { pssparams := pss.NewPssParams(self.privateKey) self.ps = pss.NewPss(to, self.dpa, pssparams) if pss.IsActiveHandshake { @@ -162,7 +158,7 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, ensClient *e var resourceHandler *storage.ResourceHandler // if use resource updates - if resourceEnabled { + if self.config.ResourceEnabled { var resourceValidator storage.ResourceValidator if self.dns != nil { resourceValidator, err = storage.NewENSValidator(config.EnsRoot, ensClient, transactOpts, storage.NewGenericResourceSigner(self.privateKey)) @@ -204,7 +200,7 @@ func (self *Swarm) Start(srv *p2p.Server) error { log.Warn("Updated bzz local addr", "oaddr", fmt.Sprintf("%x", newaddr.OAddr), "uaddr", fmt.Sprintf("%x", newaddr.UAddr)) // set chequebook - if self.swapEnabled { + if self.config.SwapEnabled { ctx := context.Background() // The initial setup has no deadline. err := self.SetChequebook(ctx) if err != nil { @@ -237,14 +233,14 @@ func (self *Swarm) Start(srv *p2p.Server) error { addr := net.JoinHostPort(self.config.ListenAddr, self.config.Port) go httpapi.StartHttpServer(self.api, &httpapi.ServerConfig{ Addr: addr, - CorsString: self.corsString, + CorsString: self.config.Cors, }) } log.Debug(fmt.Sprintf("Swarm http proxy started on port: %v", self.config.Port)) - if self.corsString != "" { - log.Debug(fmt.Sprintf("Swarm http proxy started with corsdomain: %v", self.corsString)) + if self.config.Cors != "" { + log.Debug(fmt.Sprintf("Swarm http proxy started with corsdomain: %v", self.config.Cors)) } return nil diff --git a/swarm/testutil/http.go b/swarm/testutil/http.go index 4cec635936..3556101850 100644 --- a/swarm/testutil/http.go +++ b/swarm/testutil/http.go @@ -17,21 +17,29 @@ package testutil import ( - "crypto/ecdsa" + "context" "io/ioutil" + "math/big" "net/http/httptest" "os" - "path/filepath" "strconv" "testing" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/swarm/api" httpapi "github.com/ethereum/go-ethereum/swarm/api/http" "github.com/ethereum/go-ethereum/swarm/storage" ) +type fakeBackend struct { + blocknumber int64 +} + +func (f *fakeBackend) BlockNumber(ctx context.Context) (big.Int, error) { + f.blocknumber++ + biggie := big.NewInt(f.blocknumber) + return *biggie, nil +} + func NewTestSwarmServer(t *testing.T) *TestSwarmServer { dir, err := ioutil.TempDir("", "swarm-storage-test") if err != nil { @@ -60,28 +68,8 @@ func NewTestSwarmServer(t *testing.T) *TestSwarmServer { if err != nil { t.Fatal(err) } - ipcPath := filepath.Join(resourceDir, "test.ipc") - ipcl, err := rpc.CreateIPCListener(ipcPath) - if err != nil { - t.Fatal(err) - } - rpcServer := rpc.NewServer() - rpcServer.RegisterName("eth", &FakeRPC{}) - go func() { - rpcServer.ServeListener(ipcl) - }() - rpcClean := func() { - rpcServer.Stop() - } - // connect to fake rpc - rpcClient, err := rpc.Dial(ipcPath) - if err != nil { - t.Fatal(err) - } - ethClient := ethclient.NewClient(rpcClient) - - rh, err := storage.NewResourceHandler(resourceDir, &testCloudStore{}, ethClient, nil) + rh, err := storage.NewResourceHandler(resourceDir, &testCloudStore{}, &fakeBackend{}, nil) if err != nil { t.Fatal(err) } @@ -94,8 +82,9 @@ func NewTestSwarmServer(t *testing.T) *TestSwarmServer { dir: dir, hasher: storage.MakeHashFunc(storage.SHA3Hash)(), cleanup: func() { + srv.Close() rh.Close() - rpcClean() + dpa.Stop() os.RemoveAll(dir) os.RemoveAll(resourceDir) }, @@ -104,17 +93,14 @@ func NewTestSwarmServer(t *testing.T) *TestSwarmServer { type TestSwarmServer struct { *httptest.Server - hasher storage.SwarmHash - privatekey *ecdsa.PrivateKey - Dpa *storage.DPA - dir string - cleanup func() + hasher storage.SwarmHash + Dpa *storage.DPA + dir string + cleanup func() } func (t *TestSwarmServer) Close() { - t.Server.Close() - t.Dpa.Stop() - os.RemoveAll(t.dir) + t.cleanup() } type testCloudStore struct {