From b635d7fdc1ef9cda8036077d2faaac16eb59f142 Mon Sep 17 00:00:00 2001 From: lash Date: Sun, 14 Jan 2018 06:07:52 +0100 Subject: [PATCH] swarm/storage: Add proper backend + wrapper for simulated testbackend --- swarm/storage/resource.go | 20 ++++- swarm/storage/resource_test.go | 134 +++++++++++++++++++++------------ 2 files changed, 101 insertions(+), 53 deletions(-) diff --git a/swarm/storage/resource.go b/swarm/storage/resource.go index 8383742461..2ed12bfc97 100644 --- a/swarm/storage/resource.go +++ b/swarm/storage/resource.go @@ -11,9 +11,11 @@ import ( "golang.org/x/net/idna" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/ens" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" ) @@ -99,7 +101,9 @@ type resource struct { // TODO: signature validation type ResourceHandler struct { ChunkStore - ethapi *rpc.Client + ethapi *ethclient.Client + rpcClient *rpc.Client + ensapi *ens.ENS resources map[string]*resource hashLock sync.Mutex resourceLock sync.RWMutex @@ -109,7 +113,7 @@ type ResourceHandler struct { } // Create or open resource update chunk store -func NewResourceHandler(privKey *ecdsa.PrivateKey, datadir string, cloudStore CloudStore, ethapi *rpc.Client) (*ResourceHandler, error) { +func NewResourceHandler(privKey *ecdsa.PrivateKey, datadir string, cloudStore CloudStore, rpcclient *rpc.Client, ensAddr common.Address) (*ResourceHandler, error) { path := filepath.Join(datadir, "resource") dbStore, err := NewDbStore(datadir, nil, singletonSwarmDbCapacity, 0) if err != nil { @@ -120,9 +124,17 @@ func NewResourceHandler(privKey *ecdsa.PrivateKey, datadir string, cloudStore Cl DbStore: dbStore, } hasher := MakeHashFunc("SHA3") + transactOpts := bind.NewKeyedTransactor(privKey) + ethapi := ethclient.NewClient(rpcclient) + ensinstance, err := ens.NewENS(transactOpts, ensAddr, ethapi) + if err != nil { + return nil, err + } return &ResourceHandler{ ChunkStore: newResourceChunkStore(path, hasher, localStore, cloudStore), - ethapi: ethapi, + ethapi: ethclient.NewClient(rpcclient), + rpcClient: rpcclient, + ensapi: ensinstance, resources: make(map[string]*resource), hasher: hasher(), privKey: privKey, @@ -519,7 +531,7 @@ func (self *ResourceHandler) Close() { func (self *ResourceHandler) getBlock() (uint64, error) { // get the block height and convert to uint64 var currentblock string - err := self.ethapi.Call(¤tblock, "eth_blockNumber") + err := self.rpcClient.Call(¤tblock, "eth_blockNumber") if err != nil { return 0, err } diff --git a/swarm/storage/resource_test.go b/swarm/storage/resource_test.go index e0fdf8793c..145be03fa4 100644 --- a/swarm/storage/resource_test.go +++ b/swarm/storage/resource_test.go @@ -19,6 +19,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/ens" "github.com/ethereum/go-ethereum/contracts/ens/contract" "github.com/ethereum/go-ethereum/core" @@ -29,26 +30,46 @@ import ( ) var ( + zeroAddr = common.Address{} blockCount = uint64(4200) cleanF func() hashfunc = sha3.NewKeccak256() + domainName = "føø.bar" ) func init() { log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))) } +type fakeBackend struct { + *backends.SimulatedBackend + blocknumber uint64 +} + +func (f *fakeBackend) Commit() { + if f.SimulatedBackend != nil { + f.SimulatedBackend.Commit() + } + f.blocknumber++ +} + type FakeRPC struct { - blockcount *uint64 + backend *fakeBackend } func (r *FakeRPC) BlockNumber() (string, error) { - return strconv.FormatUint(*r.blockcount, 10), nil + return strconv.FormatUint(r.backend.blocknumber, 10), nil } func TestResourceValidContent(t *testing.T) { - rh, privkey, _, err, teardownTest := setupTest() + // privkey for signing updates + privkey, err := crypto.GenerateKey() + if err != nil { + return + } + + rh, _, err, teardownTest := setupTest(privkey, nil, zeroAddr) if err != nil { teardownTest(t, err) } @@ -97,8 +118,14 @@ func TestResourceValidContent(t *testing.T) { } func TestResourceReverseLookup(t *testing.T) { - //rh, privkey, datadir, err, teardownTest := setupTest() - rh, _, _, err, teardownTest := setupTest() + + // privkey for signing updates + privkey, err := crypto.GenerateKey() + if err != nil { + return + } + + rh, _, err, teardownTest := setupTest(privkey, nil, zeroAddr) if err != nil { teardownTest(t, err) } @@ -149,7 +176,13 @@ func TestResourceReverseLookup(t *testing.T) { func TestResourceHandler(t *testing.T) { - rh, privkey, datadir, err, teardownTest := setupTest() + // privkey for signing updates + privkey, err := crypto.GenerateKey() + if err != nil { + return + } + + rh, datadir, err, teardownTest := setupTest(privkey, nil, zeroAddr) if err != nil { teardownTest(t, err) } @@ -218,7 +251,7 @@ func TestResourceHandler(t *testing.T) { // it will match on second iteration startblocknumber + (resourcefrequency * 3) blockCount = startblocknumber + (resourcefrequency * 4) - rh2, err := NewResourceHandler(privkey, datadir, &testCloudStore{}, rh.ethapi) + rh2, err := NewResourceHandler(privkey, datadir, &testCloudStore{}, rh.rpcClient, ens.MainNetAddress) _, err = rh2.LookupLatest(resourcename, true) if err != nil { teardownTest(t, err) @@ -280,7 +313,33 @@ func TestResourceHandler(t *testing.T) { } -func setupTest() (rh *ResourceHandler, privkey *ecdsa.PrivateKey, datadir string, err error, teardown func(*testing.T, error)) { +func TestResourceENS(t *testing.T) { + + // privkey for signing updates + privkey, err := crypto.GenerateKey() + if err != nil { + return + } + + domainparts := strings.Split(domainName, ".") + addr, contractbackend, err := setupENS(privkey, domainparts[0], domainparts[1]) + if err != nil { + t.Fatal(err) + } + + rh, _, err, teardownTest := setupTest(privkey, contractbackend, addr) + if err != nil { + teardownTest(t, err) + } + + _, err = rh.NewResource(domainName, 42) + if err != nil { + teardownTest(t, err) + } + teardownTest(t, nil) +} + +func setupTest(privkey *ecdsa.PrivateKey, contractbackend bind.ContractBackend, ensaddr common.Address) (rh *ResourceHandler, datadir string, err error, teardown func(*testing.T, error)) { var fsClean func() var rpcClean func() @@ -293,12 +352,6 @@ func setupTest() (rh *ResourceHandler, privkey *ecdsa.PrivateKey, datadir string } } - // privkey for signing updates - privkey, err = crypto.GenerateKey() - if err != nil { - return - } - // temp datadir datadir, err = ioutil.TempDir("", "rh") if err != nil { @@ -316,8 +369,12 @@ func setupTest() (rh *ResourceHandler, privkey *ecdsa.PrivateKey, datadir string return } rpcserver := rpc.NewServer() + var fake *fakeBackend + if contractbackend != nil { + fake = contractbackend.(*fakeBackend) + } rpcserver.RegisterName("eth", &FakeRPC{ - blockcount: &blockCount, + backend: fake, }) go func() { rpcserver.ServeListener(ipcl) @@ -332,7 +389,7 @@ func setupTest() (rh *ResourceHandler, privkey *ecdsa.PrivateKey, datadir string return } - rh, err = NewResourceHandler(privkey, datadir, &testCloudStore{}, rpcclient) + rh, err = NewResourceHandler(privkey, datadir, &testCloudStore{}, rpcclient, ensaddr) teardown = func(t *testing.T, err error) { cleanF() if err != nil { @@ -342,22 +399,7 @@ func setupTest() (rh *ResourceHandler, privkey *ecdsa.PrivateKey, datadir string return } - -func TestResourceENS(t *testing.T) { - _, privkey, _, err, teardownTest := setupTest() - if err != nil { - teardownTest(t, err) - } - err = setupENS(privkey, "foo", "bar") - if err != nil { - teardownTest(t, err) - } - teardownTest(t, nil) -} - -func setupENS(privkey *ecdsa.PrivateKey, sub string, top string) error { - // ens backend - //key := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") +func setupENS(privkey *ecdsa.PrivateKey, sub string, top string) (common.Address, bind.ContractBackend, error) { var tophash [32]byte var subhash [32]byte hashfunc.Reset() @@ -367,45 +409,39 @@ func setupENS(privkey *ecdsa.PrivateKey, sub string, top string) error { hashfunc.Write([]byte(sub)) copy(subhash[:], hashfunc.Sum(nil)) addr := crypto.PubkeyToAddress(privkey.PublicKey) - contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) + contractBackend := &fakeBackend{ + SimulatedBackend: backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}), + } transactOpts := bind.NewKeyedTransactor(privkey) - _, _, ensinstance, err := contract.DeployENS(transactOpts, contractBackend) + ensAddr, _, ensinstance, err := contract.DeployENS(transactOpts, contractBackend) if err != nil { - return fmt.Errorf("can't deploy: %v", err) + return zeroAddr, nil, fmt.Errorf("can't deploy: %v", err) } - // Deploy the registrar. - // regAddr, _, reginstance, err := contract.DeployFIFSRegistrar(transactOpts, contractBackend, ensAddr, [32]byte{}) - // if err != nil { - // return fmt.Errorf("can't deploy Registrar: %v", err) - // } - // contractBackend.Commit() - // - // Set the registrar as owner of the ENS root. if _, err = ensinstance.SetOwner(transactOpts, [32]byte{}, addr); err != nil { - return fmt.Errorf("can't setowner: %v", err) + return zeroAddr, nil, fmt.Errorf("can't setowner: %v", err) } contractBackend.Commit() if _, err = ensinstance.SetSubnodeOwner(transactOpts, [32]byte{}, tophash, addr); err != nil { - return fmt.Errorf("can't register top: %v", err) + return zeroAddr, nil, fmt.Errorf("can't register top: %v", err) } contractBackend.Commit() if _, err = ensinstance.SetSubnodeOwner(transactOpts, ens.EnsNode(top), subhash, addr); err != nil { - return fmt.Errorf("can't register top: %v", err) + return zeroAddr, nil, fmt.Errorf("can't register top: %v", err) } contractBackend.Commit() nodeowner, err := ensinstance.Owner(&bind.CallOpts{}, ens.EnsNode(strings.Join([]string{sub, top}, "."))) if err != nil { - return fmt.Errorf("can't retrieve owner: %v", err) + return zeroAddr, nil, fmt.Errorf("can't retrieve owner: %v", err) } else if !bytes.Equal(nodeowner.Bytes(), addr.Bytes()) { - return fmt.Errorf("retrieved owner doesn't match; expected '%x', got '%x'", addr, nodeowner) + return zeroAddr, nil, fmt.Errorf("retrieved owner doesn't match; expected '%x', got '%x'", addr, nodeowner) } - return nil + return ensAddr, contractBackend, nil } type testCloudStore struct {