mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 09:23:48 +00:00
swarm/storage: Change validator, subclassing -> member
This commit is contained in:
parent
c45ce79937
commit
52e529e04b
3 changed files with 112 additions and 119 deletions
|
|
@ -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(¤tblock, "eth_blockNumber")
|
err := self.rpcClient.Call(¤tblock, "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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
|
||||||
|
func (self *ENSValidator) isOwner(name string) (bool, error) {
|
||||||
|
owneraddr, err := self.api.Owner(self.nameHash(name))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return owneraddr == self.owner, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ENSValidator) nameHash(name string) common.Hash {
|
||||||
return ens.EnsNode(name)
|
return ens.EnsNode(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ENSResourceHandler{
|
// Default fallthrough validation of mutable resource ownership
|
||||||
RawResourceHandler: rh,
|
type GenericValidator struct {
|
||||||
addr: crypto.PubkeyToAddress(privKey.PublicKey),
|
hashFunc func(string) common.Hash
|
||||||
ensapi: ensinstance,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ENSResourceHandler) NewResource(name string, frequency uint64) (*resource, error) {
|
func NewGenericValidator(hashFunc func(string) common.Hash) *GenericValidator {
|
||||||
ok, err := self.IsOwner(name)
|
return &GenericValidator{
|
||||||
if err != nil {
|
hashFunc: hashFunc,
|
||||||
return nil, err
|
|
||||||
} else if !ok {
|
|
||||||
return nil, fmt.Errorf("Not Owner")
|
|
||||||
}
|
}
|
||||||
return self.RawResourceHandler.NewResource(name, frequency)
|
}
|
||||||
|
func (self *GenericValidator) isOwner(name string) (bool, error) {
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ENSResourceHandler) Update(name string, data []byte) (Key, error) {
|
func (self *GenericValidator) nameHash(name string) common.Hash {
|
||||||
ok, err := self.IsOwner(name)
|
return self.hashFunc(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) {
|
|
||||||
owneraddr, err := self.ensapi.Owner(self.RawResourceHandler.nameHashFunc(name))
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("ENS error: %v", err)
|
|
||||||
}
|
|
||||||
return owneraddr == self.addr, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue