swarm/storage: Change validator, subclassing -> member

This commit is contained in:
lash 2018-01-17 03:54:14 +01:00
parent c45ce79937
commit 52e529e04b
3 changed files with 112 additions and 119 deletions

View file

@ -91,15 +91,15 @@ type resource struct {
// 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.
type ResourceHandler interface {
ChunkStore type ResourceValidator interface {
NewResource(name string, frequency uint64) (*resource, error) isOwner(string) (bool, error)
Update(name string, data []byte) (Key, error) nameHash(string) common.Hash
resourceHash(namehash common.Hash, period uint32, version uint32) Key
} }
type RawResourceHandler struct { type ResourceHandler struct {
ChunkStore ChunkStore
validator ResourceValidator
rpcClient *rpc.Client rpcClient *rpc.Client
resources map[string]*resource resources map[string]*resource
hashLock sync.Mutex hashLock sync.Mutex
@ -107,11 +107,10 @@ type RawResourceHandler struct {
hasher SwarmHash hasher SwarmHash
privKey *ecdsa.PrivateKey privKey *ecdsa.PrivateKey
maxChunkData int64 maxChunkData int64
nameHashFunc func(string) common.Hash
} }
// Create or open resource update chunk store // Create or open resource update chunk store
func NewRawResourceHandler(privKey *ecdsa.PrivateKey, datadir string, cloudStore CloudStore, rpcClient *rpc.Client, nameHashFunc func(string) common.Hash) (*RawResourceHandler, error) { func NewResourceHandler(privKey *ecdsa.PrivateKey, datadir string, cloudStore CloudStore, rpcClient *rpc.Client, validator ResourceValidator) (*ResourceHandler, error) {
path := filepath.Join(datadir, "resource") path := filepath.Join(datadir, "resource")
dbStore, err := NewDbStore(datadir, nil, singletonSwarmDbCapacity, 0) dbStore, err := NewDbStore(datadir, nil, singletonSwarmDbCapacity, 0)
if err != nil { if err != nil {
@ -123,7 +122,7 @@ func NewRawResourceHandler(privKey *ecdsa.PrivateKey, datadir string, cloudStore
} }
hasher := MakeHashFunc("SHA3") hasher := MakeHashFunc("SHA3")
rh := &RawResourceHandler{ rh := &ResourceHandler{
ChunkStore: newResourceChunkStore(path, hasher, localStore, cloudStore), ChunkStore: newResourceChunkStore(path, hasher, localStore, cloudStore),
rpcClient: rpcClient, rpcClient: rpcClient,
resources: make(map[string]*resource), resources: make(map[string]*resource),
@ -132,14 +131,16 @@ func NewRawResourceHandler(privKey *ecdsa.PrivateKey, datadir string, cloudStore
maxChunkData: DefaultBranches * int64(hasher().Size()), maxChunkData: DefaultBranches * int64(hasher().Size()),
} }
if nameHashFunc == nil { if validator != nil {
rh.nameHashFunc = func(name string) common.Hash { rh.validator = validator
} else {
rh.validator = NewGenericValidator(func(name string) common.Hash {
rh.hashLock.Lock() rh.hashLock.Lock()
defer rh.hashLock.Unlock() defer rh.hashLock.Unlock()
rh.hasher.Reset() rh.hasher.Reset()
rh.hasher.Write([]byte(name)) rh.hasher.Write([]byte(name))
return common.BytesToHash(rh.hasher.Sum(nil)) return common.BytesToHash(rh.hasher.Sum(nil))
} })
} }
return rh, nil return rh, nil
@ -186,14 +187,21 @@ func NewResource(name string, startBlock uint64, frequency uint64, nameHashFunc
// Creates a new root entry for a mutable resource identified by `name` with the specified `frequency`. // Creates a new root entry for a mutable resource identified by `name` with the specified `frequency`.
// //
// The start block of the resource update will be the actual current block height of the connected network. // The start block of the resource update will be the actual current block height of the connected network.
func (self *RawResourceHandler) NewResource(name string, frequency uint64) (*resource, error) { func (self *ResourceHandler) NewResource(name string, frequency uint64) (*resource, error) {
ok, err := self.validator.isOwner(name)
if err != nil {
return nil, err
} else if !ok {
return nil, fmt.Errorf("Not owner of '%s'", name)
}
validname, err := validateInput(name, frequency) validname, err := validateInput(name, frequency)
if err != nil { if err != nil {
return nil, err return nil, err
} }
nameHash := self.nameHashFunc(validname) nameHash := self.validator.nameHash(validname)
// get our blockheight at this time // get our blockheight at this time
currentblock, err := self.getBlock() currentblock, err := self.getBlock()
@ -236,7 +244,7 @@ func (self *RawResourceHandler) NewResource(name string, frequency uint64) (*res
// //
// Method will fail if resource is already registered in this session, unless // Method will fail if resource is already registered in this session, unless
// `allowOverwrite` is set // `allowOverwrite` is set
func (self *RawResourceHandler) SetExternalResource(rsrc *resource, allowOverwrite bool) error { func (self *ResourceHandler) SetExternalResource(rsrc *resource, allowOverwrite bool) error {
utfname, err := idna.ToUnicode(rsrc.name) utfname, err := idna.ToUnicode(rsrc.name)
if err != nil { if err != nil {
@ -273,7 +281,7 @@ func (self *RawResourceHandler) SetExternalResource(rsrc *resource, allowOverwri
// root chunk. // root chunk.
// It is the callers responsibility to make sure that this chunk exists (if the resource // It is the callers responsibility to make sure that this chunk exists (if the resource
// update root data was retrieved externally, it typically doesn't) // update root data was retrieved externally, it typically doesn't)
func (self *RawResourceHandler) LookupVersion(name string, period uint32, version uint32, refresh bool) (*resource, error) { func (self *ResourceHandler) LookupVersion(name string, period uint32, version uint32, refresh bool) (*resource, error) {
rsrc, err := self.loadResource(name, refresh) rsrc, err := self.loadResource(name, refresh)
if err != nil { if err != nil {
return nil, err return nil, err
@ -289,7 +297,7 @@ func (self *RawResourceHandler) LookupVersion(name string, period uint32, versio
// and returned. // and returned.
// //
// See also (*ResourceHandler).LookupVersion // See also (*ResourceHandler).LookupVersion
func (self *RawResourceHandler) LookupHistorical(name string, period uint32, refresh bool) (*resource, error) { func (self *ResourceHandler) LookupHistorical(name string, period uint32, refresh bool) (*resource, error) {
rsrc, err := self.loadResource(name, refresh) rsrc, err := self.loadResource(name, refresh)
if err != nil { if err != nil {
return nil, err return nil, err
@ -307,7 +315,7 @@ func (self *RawResourceHandler) LookupHistorical(name string, period uint32, ref
// Version iteration is done as in (*ResourceHandler).LookupHistorical // Version iteration is done as in (*ResourceHandler).LookupHistorical
// //
// See also (*ResourceHandler).LookupHistorical // See also (*ResourceHandler).LookupHistorical
func (self *RawResourceHandler) LookupLatest(name string, refresh bool) (*resource, error) { func (self *ResourceHandler) LookupLatest(name string, refresh bool) (*resource, error) {
// get our blockheight at this time and the next block of the update period // get our blockheight at this time and the next block of the update period
rsrc, err := self.loadResource(name, refresh) rsrc, err := self.loadResource(name, refresh)
@ -323,7 +331,7 @@ func (self *RawResourceHandler) LookupLatest(name string, refresh bool) (*resour
} }
// base code for public lookup methods // base code for public lookup methods
func (self *RawResourceHandler) lookup(rsrc *resource, name string, period uint32, version uint32, refresh bool) (*resource, error) { func (self *ResourceHandler) lookup(rsrc *resource, name string, period uint32, version uint32, refresh bool) (*resource, error) {
if period == 0 { if period == 0 {
return nil, fmt.Errorf("period must be >0") return nil, fmt.Errorf("period must be >0")
@ -366,7 +374,7 @@ func (self *RawResourceHandler) lookup(rsrc *resource, name string, period uint3
} }
// load existing mutable resource into resource struct // load existing mutable resource into resource struct
func (self *RawResourceHandler) loadResource(name string, refresh bool) (*resource, error) { func (self *ResourceHandler) loadResource(name string, refresh bool) (*resource, error) {
// if the resource is not known to this session we must load it // if the resource is not known to this session we must load it
// if refresh is set, we force load // if refresh is set, we force load
@ -379,7 +387,7 @@ func (self *RawResourceHandler) loadResource(name string, refresh bool) (*resour
return nil, err return nil, err
} }
rsrc.name = validname rsrc.name = validname
rsrc.nameHash = self.nameHashFunc(validname) rsrc.nameHash = self.validator.nameHash(validname)
// get the root info chunk and update the cached value // get the root info chunk and update the cached value
chunk, err := self.Get(Key(rsrc.nameHash[:])) chunk, err := self.Get(Key(rsrc.nameHash[:]))
@ -409,7 +417,7 @@ func (self *RawResourceHandler) loadResource(name string, refresh bool) (*resour
} }
// update mutable resource index map with specified content // update mutable resource index map with specified content
func (self *RawResourceHandler) updateResourceIndex(rsrc *resource, chunk *Chunk, indexname *string) (*resource, error) { func (self *ResourceHandler) updateResourceIndex(rsrc *resource, chunk *Chunk, indexname *string) (*resource, error) {
// rsrc update data chunks are total hacks // rsrc update data chunks are total hacks
// and have no size prefix :D // and have no size prefix :D
@ -455,7 +463,14 @@ func parseUpdate(blob []byte) (period uint32, version uint32, ensname []byte, da
// It is the caller's responsibility to make sure that this data is not stale. // It is the caller's responsibility to make sure that this data is not stale.
// //
// A resource update cannot span chunks, and thus has max length 4096 // A resource update cannot span chunks, and thus has max length 4096
func (self *RawResourceHandler) Update(name string, data []byte) (Key, error) { func (self *ResourceHandler) Update(name string, data []byte) (Key, error) {
ok, err := self.validator.isOwner(name)
if err != nil {
return nil, err
} else if !ok {
return nil, fmt.Errorf("Not owner of '%s'", name)
}
// can be only one chunk long minus 65 byte signature // can be only one chunk long minus 65 byte signature
if int64(len(data)) > self.maxChunkData { if int64(len(data)) > self.maxChunkData {
@ -527,11 +542,11 @@ func (self *RawResourceHandler) 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 *RawResourceHandler) Close() { func (self *ResourceHandler) Close() {
self.ChunkStore.Close() self.ChunkStore.Close()
} }
func (self *RawResourceHandler) getBlock() (uint64, error) { func (self *ResourceHandler) getBlock() (uint64, error) {
// 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")
@ -544,28 +559,28 @@ func (self *RawResourceHandler) getBlock() (uint64, error) {
return strconv.ParseUint(currentblock, 10, 64) return strconv.ParseUint(currentblock, 10, 64)
} }
func (self *RawResourceHandler) BlockToPeriod(name string, blocknumber uint64) uint32 { func (self *ResourceHandler) BlockToPeriod(name string, blocknumber uint64) uint32 {
return getNextPeriod(self.resources[name].startBlock, blocknumber, self.resources[name].frequency) return getNextPeriod(self.resources[name].startBlock, blocknumber, self.resources[name].frequency)
} }
func (self *RawResourceHandler) PeriodToBlock(name string, period uint32) uint64 { func (self *ResourceHandler) PeriodToBlock(name string, period uint32) uint64 {
return self.resources[name].startBlock + (uint64(period) * self.resources[name].frequency) return self.resources[name].startBlock + (uint64(period) * self.resources[name].frequency)
} }
func (self *RawResourceHandler) getResource(name string) *resource { func (self *ResourceHandler) getResource(name string) *resource {
self.resourceLock.RLock() self.resourceLock.RLock()
defer self.resourceLock.RUnlock() defer self.resourceLock.RUnlock()
rsrc := self.resources[name] rsrc := self.resources[name]
return rsrc return rsrc
} }
func (self *RawResourceHandler) setResource(name string, rsrc *resource) { func (self *ResourceHandler) setResource(name string, rsrc *resource) {
self.resourceLock.Lock() self.resourceLock.Lock()
defer self.resourceLock.Unlock() defer self.resourceLock.Unlock()
self.resources[name] = rsrc self.resources[name] = rsrc
} }
func (self *RawResourceHandler) resourceHash(namehash common.Hash, period uint32, version uint32) Key { func (self *ResourceHandler) resourceHash(namehash common.Hash, period uint32, version uint32) Key {
// format is: hash(namehash|period|version) // format is: hash(namehash|period|version)
self.hashLock.Lock() self.hashLock.Lock()
defer self.hashLock.Unlock() defer self.hashLock.Unlock()
@ -579,7 +594,7 @@ func (self *RawResourceHandler) resourceHash(namehash common.Hash, period uint32
return self.hasher.Sum(nil) return self.hasher.Sum(nil)
} }
func (self *RawResourceHandler) signContent(data []byte) ([]byte, error) { func (self *ResourceHandler) signContent(data []byte) ([]byte, error) {
self.hashLock.Lock() self.hashLock.Lock()
self.hasher.Reset() self.hasher.Reset()
self.hasher.Write(data) self.hasher.Write(data)
@ -596,7 +611,7 @@ func (self *RawResourceHandler) signContent(data []byte) ([]byte, error) {
return datawithsign, nil return datawithsign, nil
} }
func (self *RawResourceHandler) getContentAccount(chunkdata []byte) (common.Address, error) { func (self *ResourceHandler) getContentAccount(chunkdata []byte) (common.Address, error) {
if len(chunkdata) <= signatureLength { if len(chunkdata) <= signatureLength {
return common.Address{}, fmt.Errorf("zero-length data") return common.Address{}, fmt.Errorf("zero-length data")
} }
@ -612,7 +627,7 @@ func (self *RawResourceHandler) getContentAccount(chunkdata []byte) (common.Addr
return crypto.PubkeyToAddress(*pub), nil return crypto.PubkeyToAddress(*pub), nil
} }
func (self *RawResourceHandler) verifyContent(chunkdata []byte) error { func (self *ResourceHandler) verifyContent(chunkdata []byte) error {
address, err := self.getContentAccount(chunkdata) address, err := self.getContentAccount(chunkdata)
if err != nil { if err != nil {
return err return err
@ -621,7 +636,7 @@ func (self *RawResourceHandler) verifyContent(chunkdata []byte) error {
return nil return nil
} }
func (self *RawResourceHandler) hasUpdate(name string, period uint32) bool { func (self *ResourceHandler) hasUpdate(name string, period uint32) bool {
if self.resources[name].lastPeriod == period { if self.resources[name].lastPeriod == period {
return true return true
} }

View file

@ -1,74 +1,54 @@
package storage package storage
import ( import (
"crypto/ecdsa"
"fmt"
"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"
"github.com/ethereum/go-ethereum/contracts/ens" "github.com/ethereum/go-ethereum/contracts/ens"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rpc"
) )
// Implements Mutable Resources as offchain ENS resolvers // ENS validation of mutable resource owners
// type ENSValidator struct {
// The data part of the update is forced to be a valid ENS content hash owner common.Address
// api *ens.ENS
// Also, the ENSResourceHandler only allows creation and update of
// Resources from the ENS owner's address
//
type ENSResourceHandler struct {
*RawResourceHandler
addr common.Address
ensapi *ens.ENS
} }
func NewENSResourceHandler(privKey *ecdsa.PrivateKey, datadir string, cloudStore CloudStore, rpcClient *rpc.Client, backend bind.ContractBackend, ensAddr common.Address) (*ENSResourceHandler, error) { func NewENSValidator(owneraddress common.Address, contractaddress common.Address, backend bind.ContractBackend, transactOpts *bind.TransactOpts) (*ENSValidator, error) {
transactOpts := bind.NewKeyedTransactor(privKey) var err error
ensinstance, err := ens.NewENS(transactOpts, ensAddr, backend) validator := &ENSValidator{}
validator.api, err = ens.NewENS(transactOpts, contractaddress, backend)
if err != nil { if err != nil {
return nil, err return nil, err
} }
rh, err := NewRawResourceHandler(privKey, datadir, cloudStore, rpcClient, ens.EnsNode) validator.owner = owneraddress
if err != nil { return validator, nil
return nil, err
}
rh.nameHashFunc = func(name string) common.Hash {
return ens.EnsNode(name)
}
return &ENSResourceHandler{
RawResourceHandler: rh,
addr: crypto.PubkeyToAddress(privKey.PublicKey),
ensapi: ensinstance,
}, nil
} }
func (self *ENSResourceHandler) NewResource(name string, frequency uint64) (*resource, error) { func (self *ENSValidator) isOwner(name string) (bool, error) {
ok, err := self.IsOwner(name) owneraddr, err := self.api.Owner(self.nameHash(name))
if err != nil { if err != nil {
return nil, err return false, err
} else if !ok {
return nil, fmt.Errorf("Not Owner")
} }
return self.RawResourceHandler.NewResource(name, frequency) return owneraddr == self.owner, nil
} }
func (self *ENSResourceHandler) Update(name string, data []byte) (Key, error) { func (self *ENSValidator) nameHash(name string) common.Hash {
ok, err := self.IsOwner(name) return ens.EnsNode(name)
if err != nil {
return nil, err
} else if !ok {
return nil, fmt.Errorf("Not Owner")
}
return self.RawResourceHandler.Update(name, data)
} }
func (self *ENSResourceHandler) IsOwner(name string) (bool, error) { // Default fallthrough validation of mutable resource ownership
owneraddr, err := self.ensapi.Owner(self.RawResourceHandler.nameHashFunc(name)) type GenericValidator struct {
if err != nil { hashFunc func(string) common.Hash
return false, fmt.Errorf("ENS error: %v", err) }
}
return owneraddr == self.addr, nil func NewGenericValidator(hashFunc func(string) common.Hash) *GenericValidator {
return &GenericValidator{
hashFunc: hashFunc,
}
}
func (self *GenericValidator) isOwner(name string) (bool, error) {
return true, nil
}
func (self *GenericValidator) nameHash(name string) common.Hash {
return self.hashFunc(name)
} }

View file

@ -74,7 +74,7 @@ func TestResourceSignature(t *testing.T) {
} }
// set up rpc and create resourcehandler // set up rpc and create resourcehandler
rh, _, err, teardownTest := setupTest(privkey, nil, zeroAddr) rh, _, err, teardownTest := setupTest(privkey, nil, nil)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
@ -110,8 +110,7 @@ func TestResourceSignature(t *testing.T) {
// check that we can recover the owner account from the update chunk's signature // check that we can recover the owner account from the update chunk's signature
// TODO: change this to verifyContent on ENS integration // TODO: change this to verifyContent on ENS integration
rawrh := rh.(*RawResourceHandler) recoveredaddress, err := rh.getContentAccount(chunk.SData)
recoveredaddress, err := rawrh.getContentAccount(chunk.SData)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
@ -136,7 +135,7 @@ func TestResourceReverseLookup(t *testing.T) {
backend := &fakeBackend{ backend := &fakeBackend{
blocknumber: startBlock, blocknumber: startBlock,
} }
rh, _, err, teardownTest := setupTest(privkey, backend, zeroAddr) rh, _, err, teardownTest := setupTest(privkey, backend, nil)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
@ -154,8 +153,7 @@ func TestResourceReverseLookup(t *testing.T) {
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
rawrh := rh.(*RawResourceHandler) chunk, err := rh.ChunkStore.(*resourceChunkStore).localStore.(*LocalStore).memStore.Get(Key(resourcekey))
chunk, err := rawrh.ChunkStore.(*resourceChunkStore).localStore.(*LocalStore).memStore.Get(Key(resourcekey))
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
@ -197,7 +195,7 @@ func TestResourceHandler(t *testing.T) {
backend := &fakeBackend{ backend := &fakeBackend{
blocknumber: startBlock, blocknumber: startBlock,
} }
rh, datadir, err, teardownTest := setupTest(privkey, backend, zeroAddr) rh, datadir, err, teardownTest := setupTest(privkey, backend, nil)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
@ -213,9 +211,8 @@ func TestResourceHandler(t *testing.T) {
} }
// check that the new resource is stored correctly // check that the new resource is stored correctly
rawrh := rh.(*RawResourceHandler) namehash := rh.validator.nameHash(resourcevalidname)
namehash := rawrh.nameHashFunc(resourcevalidname) chunk, err := rh.ChunkStore.(*resourceChunkStore).localStore.(*LocalStore).memStore.Get(Key(namehash[:]))
chunk, err := rawrh.ChunkStore.(*resourceChunkStore).localStore.(*LocalStore).memStore.Get(Key(namehash[:]))
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} else if len(chunk.SData) < 16 { } else if len(chunk.SData) < 16 {
@ -265,7 +262,7 @@ 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 := NewRawResourceHandler(privkey, datadir, &testCloudStore{}, rawrh.rpcClient, nil) rh2, err := NewResourceHandler(privkey, datadir, &testCloudStore{}, rh.rpcClient, nil)
_, err = rh2.LookupLatest(domainName, true) _, err = rh2.LookupLatest(domainName, true)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
@ -282,7 +279,7 @@ func TestResourceHandler(t *testing.T) {
teardownTest(t, fmt.Errorf("resource period was %d, expected 3", rh2.resources[domainName].lastPeriod)) teardownTest(t, fmt.Errorf("resource period was %d, expected 3", rh2.resources[domainName].lastPeriod))
} }
rsrc, err := NewResource(domainName, startblocknumber, resourceFrequency, rh2.nameHashFunc) rsrc, err := NewResource(domainName, startblocknumber, resourceFrequency, rh2.validator.nameHash)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
@ -342,15 +339,24 @@ func TestResourceENSOwner(t *testing.T) {
return return
} }
// ens address and transact options
addr := crypto.PubkeyToAddress(privkey.PublicKey)
transactOpts := bind.NewKeyedTransactor(privkey)
// set up ENS sim // set up ENS sim
domainparts := strings.Split(domainName, ".") domainparts := strings.Split(domainName, ".")
addr, contractbackend, err := setupENS(privkey, domainparts[0], domainparts[1]) contractAddr, contractbackend, err := setupENS(addr, transactOpts, domainparts[0], domainparts[1])
if err != nil {
t.Fatal(err)
}
validator, err := NewENSValidator(addr, contractAddr, contractbackend, transactOpts)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// set up rpc and create resourcehandler with ENS sim backend // set up rpc and create resourcehandler with ENS sim backend
rh, _, err, teardownTest := setupTest(privkey, contractbackend, addr) rh, _, err, teardownTest := setupTest(privkey, contractbackend, validator)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, err)
} }
@ -358,20 +364,20 @@ func TestResourceENSOwner(t *testing.T) {
// create new resource when we are owner = ok // create new resource when we are owner = ok
_, err = rh.NewResource(domainName, 42) _, err = rh.NewResource(domainName, 42)
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, fmt.Errorf("Create resource fail: %v", err))
} }
// update resource when we are owner = ok // update resource when we are owner = ok
_, err = rh.Update(domainName, []byte("foo")) _, err = rh.Update(domainName, []byte("foo"))
if err != nil { if err != nil {
teardownTest(t, err) teardownTest(t, fmt.Errorf("Update resource fail: %v", err))
} }
// create new resource when we are NOT owner = !ok // create new resource when we are NOT owner = !ok
rawrh := rh.(*ENSResourceHandler) addrtwo := crypto.PubkeyToAddress(privkeytwo.PublicKey)
rawrh.privKey = privkeytwo validator.owner = addrtwo
rawrh.addr = crypto.PubkeyToAddress(privkeytwo.PublicKey)
_, err = rawrh.NewResource(domainName, 42) _, err = rh.NewResource(domainName, 42)
if err == nil { if err == nil {
teardownTest(t, fmt.Errorf("Expected resource create fail due to owner mismatch")) teardownTest(t, fmt.Errorf("Expected resource create fail due to owner mismatch"))
} }
@ -392,7 +398,7 @@ func fwdBlocks(count int, backend *fakeBackend) {
} }
// create rpc and resourcehandler // create rpc and resourcehandler
func setupTest(privkey *ecdsa.PrivateKey, contractbackend bind.ContractBackend, ensaddr common.Address) (rh ResourceHandler, datadir string, err error, teardown func(*testing.T, error)) { func setupTest(privkey *ecdsa.PrivateKey, contractbackend bind.ContractBackend, validator ResourceValidator) (rh *ResourceHandler, datadir string, err error, teardown func(*testing.T, error)) {
var fsClean func() var fsClean func()
var rpcClean func() var rpcClean func()
@ -443,11 +449,7 @@ func setupTest(privkey *ecdsa.PrivateKey, contractbackend bind.ContractBackend,
} }
// choose if with ens or not // choose if with ens or not
if ensaddr != zeroAddr { rh, err = NewResourceHandler(privkey, datadir, &testCloudStore{}, rpcclient, validator)
rh, err = NewENSResourceHandler(privkey, datadir, &testCloudStore{}, rpcclient, contractbackend, ensaddr)
} else {
rh, err = NewRawResourceHandler(privkey, datadir, &testCloudStore{}, rpcclient, nil)
}
teardown = func(t *testing.T, err error) { teardown = func(t *testing.T, err error) {
cleanF() cleanF()
if err != nil { if err != nil {
@ -459,7 +461,7 @@ func setupTest(privkey *ecdsa.PrivateKey, contractbackend bind.ContractBackend,
} }
// Set up simulated ENS backend for use with ENSResourceHandler tests // Set up simulated ENS backend for use with ENSResourceHandler tests
func setupENS(privkey *ecdsa.PrivateKey, sub string, top string) (common.Address, bind.ContractBackend, error) { func setupENS(addr common.Address, transactOpts *bind.TransactOpts, sub string, top string) (common.Address, bind.ContractBackend, error) {
// create the domain hash values to pass to the ENS contract methods // create the domain hash values to pass to the ENS contract methods
var tophash [32]byte var tophash [32]byte
@ -472,16 +474,12 @@ func setupENS(privkey *ecdsa.PrivateKey, sub string, top string) (common.Address
hasher.Write([]byte(sub)) hasher.Write([]byte(sub))
copy(subhash[:], hasher.Sum(nil)) copy(subhash[:], hasher.Sum(nil))
// private key -> address is owner of domain
addr := crypto.PubkeyToAddress(privkey.PublicKey)
// initialize contract backend and deploy // initialize contract backend and deploy
transactOpts := bind.NewKeyedTransactor(privkey)
contractBackend := &fakeBackend{ contractBackend := &fakeBackend{
SimulatedBackend: backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}), SimulatedBackend: backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}),
} }
ensAddr, _, ensinstance, err := contract.DeployENS(transactOpts, contractBackend) contractAddress, _, ensinstance, err := contract.DeployENS(transactOpts, contractBackend)
if err != nil { if err != nil {
return zeroAddr, nil, fmt.Errorf("can't deploy: %v", err) return zeroAddr, nil, fmt.Errorf("can't deploy: %v", err)
} }
@ -502,7 +500,7 @@ func setupENS(privkey *ecdsa.PrivateKey, sub string, top string) (common.Address
} }
contractBackend.Commit() contractBackend.Commit()
return ensAddr, contractBackend, nil return contractAddress, contractBackend, nil
} }
type testCloudStore struct { type testCloudStore struct {