From b2942dbc7c7979a9ddce89d1a1645f16c6996e16 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 31 May 2015 15:34:21 +0100 Subject: [PATCH 1/7] api: get rid of errResolve --- bzz/api.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bzz/api.go b/bzz/api.go index d9fd7a6d7a..37304288ae 100644 --- a/bzz/api.go +++ b/bzz/api.go @@ -260,9 +260,7 @@ func (self *Api) Register(sender common.Address, hash common.Hash, domain string return } -type errResolve error - -func (self *Api) Resolve(hostport string) (contentHash Key, errR errResolve) { +func (self *Api) Resolve(hostport string) (contentHash Key, err error) { var host, port string var err error host, port, err = net.SplitHostPort(hostport) @@ -270,7 +268,7 @@ func (self *Api) Resolve(hostport string) (contentHash Key, errR errResolve) { if err.Error() == "missing port in address "+hostport { host = hostport } else { - errR = errResolve(fmt.Errorf("invalid host '%s': %v", hostport, err)) + err = fmt.Errorf("invalid host '%s': %v", hostport, err) return } } @@ -285,12 +283,12 @@ func (self *Api) Resolve(hostport string) (contentHash Key, errR errResolve) { var hash common.Hash hash, err = self.Resolver.KeyToContentHash(hostHash) if err != nil { - err = errResolve(fmt.Errorf("unable to resolve '%s': %v", hostport, err)) + err = fmt.Errorf("unable to resolve '%s': %v", hostport, err) } contentHash = Key(hash.Bytes()) dpaLogger.Debugf("Swarm: resolve host to contentHash: '%064x'", contentHash) } else { - err = errResolve(fmt.Errorf("no resolver '%s': %v", hostport, err)) + err = fmt.Errorf("no resolver '%s': %v", hostport, err) } } return From 4d825c4a747cb1be2c5fdc9304aebf0853a72517 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 31 May 2015 15:42:04 +0100 Subject: [PATCH 2/7] api: put errResolve to getEntry --- bzz/api.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/bzz/api.go b/bzz/api.go index 37304288ae..1252816575 100644 --- a/bzz/api.go +++ b/bzz/api.go @@ -260,15 +260,16 @@ func (self *Api) Register(sender common.Address, hash common.Hash, domain string return } -func (self *Api) Resolve(hostport string) (contentHash Key, err error) { - var host, port string - var err error - host, port, err = net.SplitHostPort(hostport) +type errResolve error + +func (self *Api) Resolve(hostPort string) (contentHash Key, err error) { + var host string + host, _, err = net.SplitHostPort(hostPort) if err != nil { - if err.Error() == "missing port in address "+hostport { - host = hostport + if err.Error() == "missing port in address "+hostPort { + host = hostPort } else { - err = fmt.Errorf("invalid host '%s': %v", hostport, err) + err = fmt.Errorf("invalid host '%s': %v", hostPort, err) return } } @@ -277,18 +278,16 @@ func (self *Api) Resolve(hostport string) (contentHash Key, err error) { dpaLogger.Debugf("Swarm: host is a contentHash: '%064x'", contentHash) } else { if self.Resolver != nil { - hostHash := common.BytesToHash(crypto.Sha3(common.Hex2Bytes(host))) - // TODO: should take port as block number versioning - _ = port + hostHash := common.BytesToHash(crypto.Sha3([]byte(host))) var hash common.Hash hash, err = self.Resolver.KeyToContentHash(hostHash) if err != nil { - err = fmt.Errorf("unable to resolve '%s': %v", hostport, err) + err = fmt.Errorf("unable to resolve '%s': %v", hostPort, err) } contentHash = Key(hash.Bytes()) - dpaLogger.Debugf("Swarm: resolve host to contentHash: '%064x'", contentHash) + dpaLogger.Debugf("Swarm: resolve host '%s' to contentHash: '%064x'", hostPort, contentHash) } else { - err = fmt.Errorf("no resolver '%s': %v", hostport, err) + err = fmt.Errorf("no resolver '%s': %v", hostPort, err) } } return @@ -307,7 +306,8 @@ func (self *Api) getPath(uri string) (reader SectionReader, mimeType string, sta var key Key key, err = self.Resolve(hostPort) if err != nil { - dpaLogger.Debugf("Swarm: rResolve error: %v", err) + err = errResolve(err) + dpaLogger.Debugf("Swarm: error : %v", err) return } From e7f2234c7f78eb0d0a9ac23b0e8f4e7ffcd0e67c Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 31 May 2015 20:48:16 +0100 Subject: [PATCH 3/7] add api test for Put/Get --- bzz/api.go | 45 ++++++++++++++++++++++++++---- bzz/api_test.go | 73 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 107 insertions(+), 11 deletions(-) diff --git a/bzz/api.go b/bzz/api.go index 3a15909f62..d11609d2f7 100644 --- a/bzz/api.go +++ b/bzz/api.go @@ -62,6 +62,30 @@ func NewApi(datadir, port string) (self *Api, err error) { return } +// Local swarm without netStore +func NewLocalApi(datadir string) (self *Api, err error) { + + self = &Api{ + Chunker: &TreeChunker{}, + } + dbStore, err := newDbStore(datadir) + dbStore.setCapacity(50000) + if err != nil { + return + } + memStore := newMemStore(dbStore) + localStore := &localStore{ + memStore, + dbStore, + } + + self.dpa = &DPA{ + Chunker: self.Chunker, + ChunkStore: localStore, + } + return +} + // Bzz returns the bzz protocol class instances of which run on every peer func (self *Api) Bzz() (p2p.Protocol, error) { return BzzProtocol(self.netStore) @@ -77,9 +101,15 @@ Start is called when the ethereum stack is started func (self *Api) Start(node *discover.Node, connectPeer func(string) error) { self.Chunker.Init() self.dpa.Start() - self.netStore.start(node, connectPeer) - dpaLogger.Infof("Swarm started.") - go startHttpServer(self, self.Port) + if node != nil && self.netStore != nil && connectPeer != nil { + self.netStore.start(node, connectPeer) + dpaLogger.Infof("Swarm network started.") + } else { + dpaLogger.Infof("Local Swarm started without network") + } + if self.Port != "" { + go startHttpServer(self, self.Port) + } } func (self *Api) Stop() { @@ -171,7 +201,7 @@ func (self *Api) Upload(lpath string) (string, error) { dpaLogger.Debugf("uploading '%s'", localpath) err := filepath.Walk(localpath, func(path string, info os.FileInfo, err error) error { if (err == nil) && !info.IsDir() { - //fmt.Printf("lp %s path %s\n", localpath, path) + dpaLogger.Debugf("localpath: '%s'; path: '%s'\n", localpath, path) if len(path) <= start { return fmt.Errorf("Path is too short") } @@ -253,6 +283,7 @@ func (self *Api) Register(sender common.Address, hash common.Hash, domain string domainhash := common.BytesToHash(crypto.Sha3([]byte(domain))) if self.Resolver != nil { + dpaLogger.Debugf("Swarm: host '%s' (hash: '%v') to be registered as '%v'", domain, domainhash.Hex(), hash.Hex()) _, err = self.Resolver.RegisterContentHash(sender, domainhash, hash) } else { err = fmt.Errorf("no registry: %v", err) @@ -266,10 +297,12 @@ func (self *Api) Resolve(hostPort string) (contentHash Key, err error) { var host string host, _, err = net.SplitHostPort(hostPort) if err != nil { - if err.Error() == "missing port in address "+hostPort { + porterr := "missing port in address " + hostPort + if err.Error() == porterr { host = hostPort + err = nil } else { - err = fmt.Errorf("invalid host '%s': %v", hostPort, err) + err = fmt.Errorf("invalid host '%s': %v (<>'%s')", hostPort, err, porterr) return } } diff --git a/bzz/api_test.go b/bzz/api_test.go index 36b7b1f020..5e07e20a29 100644 --- a/bzz/api_test.go +++ b/bzz/api_test.go @@ -1,10 +1,73 @@ package bzz import ( -// "net/http" -// "strings" -// "testing" -// "time" + // "net/http" + // "strings" + "testing" + // "time" + "os" + "path" + "runtime" -// "github.com/ethereum/go-ethereum/common/docserver" + // "github.com/ethereum/go-ethereum/common/docserver" ) + +var ( + testDir string + datadir = "/tmp/bzz" +) + +func init() { + _, filename, _, _ := runtime.Caller(1) + testDir = path.Join(path.Dir(filename), "bzztest") +} + +func testApi() (api *Api, err error) { + os.RemoveAll(datadir) + api, err = NewLocalApi(datadir) + if err != nil { + return + } + api.Start(nil, nil) + return +} + +func TestApiPut(t *testing.T) { + api, err := testApi() + if err != nil { + t.Errorf("unexpected error: %v", err) + } + expContent := "hello" + expMimeType := "text/plain" + expStatus := 0 + expSize := len(expContent) + bzzhash, err := api.Put(expContent, expMimeType) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + bytecontent, mimeType, status, size, err := api.Get(bzzhash) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + content := string(bytecontent) + if content != expContent { + t.Errorf("incorrect content. expected '%s', got '%s'", expContent, content) + } + if mimeType != expMimeType { + t.Errorf("incorrect mimeType. expected '%s', got '%s'", expMimeType, mimeType) + } + if status != expStatus { + t.Errorf("incorrect status. expected '%s', got '%s'", expStatus, status) + } + if size != expSize { + t.Errorf("incorrect size. expected '%d', got '%d'", expSize, size) + } +} + +func TestApiUpload(t *testing.T) { + api, err := testApi() + if err != nil { + t.Errorf("unexpected error: %v", err) + } + _ = api +} From c4bca77d962f6cd71c437fe4be4f4e137fb88730 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 31 May 2015 21:57:02 +0100 Subject: [PATCH 4/7] added api tests TestApiDirUpload and TestApiFileUpload (FAILING) --- bzz/api.go | 3 ++- bzz/api_test.go | 65 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/bzz/api.go b/bzz/api.go index d11609d2f7..3824b696cd 100644 --- a/bzz/api.go +++ b/bzz/api.go @@ -359,7 +359,8 @@ func (self *Api) getPath(uri string) (reader SectionReader, mimeType string, sta dpaLogger.Debugf("Swarm: content lookup key: '%064x' (%v)", key, mimeType) reader = self.dpa.Retrieve(key) } else { - dpaLogger.Debugf("Swarm: getEntry(%s): not found", path) + err = fmt.Errorf("manifest entry for '%s' not found", path) + dpaLogger.Debugf("Swarm: %v", err) } return } diff --git a/bzz/api_test.go b/bzz/api_test.go index 5e07e20a29..5feb327afa 100644 --- a/bzz/api_test.go +++ b/bzz/api_test.go @@ -1,15 +1,12 @@ package bzz import ( - // "net/http" - // "strings" - "testing" - // "time" + "bytes" + "io/ioutil" "os" "path" "runtime" - - // "github.com/ethereum/go-ethereum/common/docserver" + "testing" ) var ( @@ -36,6 +33,7 @@ func TestApiPut(t *testing.T) { api, err := testApi() if err != nil { t.Errorf("unexpected error: %v", err) + return } expContent := "hello" expMimeType := "text/plain" @@ -44,30 +42,71 @@ func TestApiPut(t *testing.T) { bzzhash, err := api.Put(expContent, expMimeType) if err != nil { t.Errorf("unexpected error: %v", err) + return } - bytecontent, mimeType, status, size, err := api.Get(bzzhash) + testGet(t, api, bzzhash, []byte(expContent), expMimeType, expStatus, expSize) +} + +func testGet(t *testing.T, api *Api, bzzhash string, expContent []byte, expMimeType string, expStatus int, expSize int) { + content, mimeType, status, size, err := api.Get(bzzhash) if err != nil { t.Errorf("unexpected error: %v", err) + return } - content := string(bytecontent) - if content != expContent { - t.Errorf("incorrect content. expected '%s', got '%s'", expContent, content) + if !bytes.Equal(content, expContent) { + t.Errorf("incorrect content. expected '%s...', got '%s...'", string(expContent), string(content)) } if mimeType != expMimeType { t.Errorf("incorrect mimeType. expected '%s', got '%s'", expMimeType, mimeType) } if status != expStatus { - t.Errorf("incorrect status. expected '%s', got '%s'", expStatus, status) + t.Errorf("incorrect status. expected '%d', got '%d'", expStatus, status) } if size != expSize { t.Errorf("incorrect size. expected '%d', got '%d'", expSize, size) } } -func TestApiUpload(t *testing.T) { +func TestApiDirUpload(t *testing.T) { api, err := testApi() if err != nil { t.Errorf("unexpected error: %v", err) + return + } + bzzhash, err := api.Upload(path.Join(testDir, "test0")) + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + content, err := ioutil.ReadFile(path.Join(testDir, "test0", "index.html")) + testGet(t, api, path.Join(bzzhash, "index.html"), content, "text/html", 0, 202) + testGet(t, api, bzzhash, content, "text/html", 0, 202) + + content, err = ioutil.ReadFile(path.Join(testDir, "test0", "index.css")) + testGet(t, api, path.Join(bzzhash, "index.css"), content, "text/plain", 0, 132) + + content, err = ioutil.ReadFile(path.Join(testDir, "test0", "img", "logo.png")) + testGet(t, api, path.Join(bzzhash, "img", "logo.png"), content, "image/png", 0, 18136) + + _, _, _, _, err = api.Get(bzzhash) + if err == nil { + t.Errorf("expected error: %v", err) } - _ = api +} + +func TestApiFileUpload(t *testing.T) { + api, err := testApi() + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + bzzhash, err := api.Upload(path.Join(testDir, "test0", "index.html")) + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + content, err := ioutil.ReadFile(path.Join(testDir, "test0", "index.html")) + testGet(t, api, path.Join(bzzhash), content, "text/html", 0, 202) } From 1cfa386536728e3ecb65a2d4fbb2099093093a34 Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 1 Jun 2015 16:26:27 +0100 Subject: [PATCH 5/7] "error creating swarm" message when no error fixed --- eth/backend.go | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index b33bcd958a..cdac2a8b8f 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -88,6 +88,7 @@ type Config struct { Dial bool Bzz bool BzzPort string + PowTest bool Etherbase string GasPrice *big.Int @@ -288,7 +289,14 @@ func New(config *Config) (*Ethereum, error) { AutoDAG: config.AutoDAG, } - eth.pow = ethash.New() + if config.PowTest { + eth.pow, err = ethash.NewForTesting() + if err != nil { + return nil, err + } + } else { + eth.pow = ethash.New() + } eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.pow, eth.EventMux()) eth.downloader = downloader.New(eth.EventMux(), eth.chainManager.HasBlock, eth.chainManager.GetBlock) eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State, eth.chainManager.GasLimit) @@ -312,11 +320,17 @@ func New(config *Config) (*Ethereum, error) { if config.Bzz { eth.Swarm, err = bzz.NewApi(config.DataDir, config.BzzPort) - var proto p2p.Protocol - proto, err = eth.Swarm.Bzz() - if err == nil { + if err != nil { glog.V(logger.Warn).Infof("BZZ: error creating swarm: %v. Protocol skipped", err) - protocols = append(protocols, proto) + } else { + var proto p2p.Protocol + proto, err = eth.Swarm.Bzz() + if err != nil { + glog.V(logger.Warn).Infof("BZZ: error creating swarm: %v. Protocol skipped", err) + eth.Swarm = nil + } else { + protocols = append(protocols, proto) + } } } From b2330c4e2eeb8e548fb42b141470329fdd2aed72 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 2 Jun 2015 00:52:06 +0100 Subject: [PATCH 6/7] js api and js console test changes * fix bigint issue causing trouble * js: simplify api by separating concerns * saveInfo saves a file and calculates hash for Url Hint support * register now just takes the trivial 3 params and for bzz nothing else needed * compiler: SaveInfo simplified * clean up TestContract * use ethash test mining to force mine transactions, * get rid of xeth ApplyTxs hack * instead watch txs directly and mine with processTxs() * return on first error * no need to specify gas/gasPrice in resolver, use default * transaction_pool GetTransactions now trigger checkQueue() and validatePool() * backend now uses ethash test if config.PowTest is set --- cmd/geth/admin.go | 89 +++++++++------- cmd/geth/js.go | 2 + cmd/geth/js_test.go | 170 +++++++++++++++++++++++-------- common/compiler/solidity.go | 8 +- common/compiler/solidity_test.go | 12 +-- common/resolver/resolver.go | 6 +- core/transaction_pool.go | 3 + eth/backend.go | 1 + 8 files changed, 195 insertions(+), 96 deletions(-) diff --git a/cmd/geth/admin.go b/cmd/geth/admin.go index 45decfa7f5..20654c0cfd 100644 --- a/cmd/geth/admin.go +++ b/cmd/geth/admin.go @@ -59,6 +59,7 @@ func (js *jsre) adminBindings() { cinfo.Set("stop", js.stopNatSpec) cinfo.Set("newRegistry", js.newRegistry) cinfo.Set("get", js.getContractInfo) + cinfo.Set("saveInfo", js.saveInfo) cinfo.Set("register", js.register) cinfo.Set("registerUrl", js.registerUrl) // cinfo.Set("verify", js.verify) @@ -678,12 +679,18 @@ func (js *jsre) waitForBlocks(call otto.FunctionCall) otto.Value { } if args == 0 { - height = js.xeth.CurrentBlock().Number() - height.Add(height, common.Big1) + height = new(big.Int).Add(js.xeth.CurrentBlock().Number(), common.Big1) } + height, err = waitForBlocks(js.wait, height, timer) + if err != nil { + return otto.UndefinedValue() + } + v, _ := call.Otto.ToValue(height.Uint64()) + return v +} - wait := js.wait - js.wait <- height +func waitForBlocks(wait chan *big.Int, height *big.Int, timer <-chan time.Time) (newHeight *big.Int, err error) { + wait <- height select { case <-timer: // if times out make sure the xeth loop does not block @@ -693,11 +700,10 @@ func (js *jsre) waitForBlocks(call otto.FunctionCall) otto.Value { case <-wait: } }() - return otto.UndefinedValue() - case height = <-wait: + return nil, fmt.Errorf("timeout") + case newHeight = <-wait: } - v, _ := call.Otto.ToValue(height.Uint64()) - return v + return } func (js *jsre) sleep(call otto.FunctionCall) otto.Value { @@ -729,23 +735,49 @@ func (js *jsre) setSolc(call otto.FunctionCall) otto.Value { } func (js *jsre) register(call otto.FunctionCall) otto.Value { - if len(call.ArgumentList) != 4 { - fmt.Println("requires 4 arguments: admin.contractInfo.register(fromaddress, contractaddress, contract, filename)") - return otto.UndefinedValue() + if len(call.ArgumentList) != 3 { + fmt.Println("requires 3 arguments: admin.contractInfo.register(fromaddress, contractaddress, contenthash)") + return otto.FalseValue() } sender, err := call.Argument(0).ToString() if err != nil { fmt.Println(err) - return otto.UndefinedValue() + return otto.FalseValue() } address, err := call.Argument(1).ToString() if err != nil { fmt.Println(err) - return otto.UndefinedValue() + return otto.FalseValue() } - raw, err := call.Argument(2).Export() + contentHashHex, err := call.Argument(2).ToString() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + + // sender and contract address are passed as hex strings + codeb := js.xeth.CodeAtBytes(address) + codeHash := common.BytesToHash(crypto.Sha3(codeb)) + contentHash := common.HexToHash(contentHashHex) + registry := resolver.New(js.xeth) + + _, err = registry.RegisterContentHash(common.HexToAddress(sender), codeHash, contentHash) + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + + return otto.TrueValue() +} + +func (js *jsre) saveInfo(call otto.FunctionCall) otto.Value { + if len(call.ArgumentList) != 2 { + fmt.Println("requires 2 arguments: admin.contractInfo.saveInfo(contract.info, filename)") + return otto.UndefinedValue() + } + raw, err := call.Argument(0).Export() if err != nil { fmt.Println(err) return otto.UndefinedValue() @@ -755,36 +787,20 @@ func (js *jsre) register(call otto.FunctionCall) otto.Value { fmt.Println(err) return otto.UndefinedValue() } - var contract compiler.Contract - err = json.Unmarshal(jsonraw, &contract) + var contractInfo compiler.ContractInfo + err = json.Unmarshal(jsonraw, &contractInfo) if err != nil { fmt.Println(err) return otto.UndefinedValue() } - filename, err := call.Argument(3).ToString() + filename, err := call.Argument(1).ToString() if err != nil { fmt.Println(err) return otto.UndefinedValue() } - contenthash, err := compiler.ExtractInfo(&contract, filename) - if err != nil { - fmt.Println(err) - return otto.UndefinedValue() - } - // sender and contract address are passed as hex strings - codeb := js.xeth.CodeAtBytes(address) - codehash := common.BytesToHash(crypto.Sha3(codeb)) - - if err != nil { - fmt.Println(err) - return otto.UndefinedValue() - } - - registry := resolver.New(js.xeth) - - _, err = registry.RegisterContentHash(common.HexToAddress(sender), codehash, contenthash) + contenthash, err := compiler.SaveInfo(&contractInfo, filename) if err != nil { fmt.Println(err) return otto.UndefinedValue() @@ -796,7 +812,7 @@ func (js *jsre) register(call otto.FunctionCall) otto.Value { func (js *jsre) registerUrl(call otto.FunctionCall) otto.Value { if len(call.ArgumentList) != 3 { - fmt.Println("requires 3 arguments: admin.contractInfo.register(fromaddress, contenthash, filename)") + fmt.Println("requires 3 arguments: admin.contractInfo.registerUrl(fromaddress, contenthash, url)") return otto.FalseValue() } sender, err := call.Argument(0).ToString() @@ -818,7 +834,6 @@ func (js *jsre) registerUrl(call otto.FunctionCall) otto.Value { } registry := resolver.New(js.xeth) - _, err = registry.RegisterUrl(common.HexToAddress(sender), common.HexToHash(contenthash), url) if err != nil { fmt.Println(err) @@ -830,7 +845,7 @@ func (js *jsre) registerUrl(call otto.FunctionCall) otto.Value { func (js *jsre) getContractInfo(call otto.FunctionCall) otto.Value { if len(call.ArgumentList) != 1 { - fmt.Println("requires 1 argument: admin.contractInfo.register(contractaddress)") + fmt.Println("requires 1 argument: admin.contractInfo.get(contractaddress)") return otto.FalseValue() } addr, err := call.Argument(0).ToString() diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 24daf6f583..216c5e3500 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -85,6 +85,7 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, bzzEnabled bool js.xeth = xeth.New(ethereum, f) js.wait = js.xeth.UpdateState() js.re = re.New(libPath) + // js.apiBindings(js.xeth) js.apiBindings(f) js.adminBindings() if bzzEnabled { @@ -113,6 +114,7 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, bzzEnabled bool func (js *jsre) apiBindings(f xeth.Frontend) { xe := xeth.New(js.ethereum, f) + // func (js *jsre) apiBindings(xe *xeth.XEth) { ethApi := rpc.NewEthereumApi(xe) jeth := rpc.NewJeth(ethApi, js.re) diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index d6d4e05fd0..95a9b97afc 100644 --- a/cmd/geth/js_test.go +++ b/cmd/geth/js_test.go @@ -3,12 +3,14 @@ package main import ( "fmt" "io/ioutil" + "math/big" "os" "path/filepath" "regexp" "runtime" "strconv" "testing" + "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" @@ -17,7 +19,6 @@ import ( "github.com/ethereum/go-ethereum/common/natspec" "github.com/ethereum/go-ethereum/common/resolver" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" ) @@ -41,7 +42,6 @@ var ( type testjethre struct { *jsre - stateDb *state.StateDB lastConfirm string ds *docserver.DocServer } @@ -79,6 +79,7 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) { MaxPeers: 0, Name: "test", SolcPath: testSolcPath, + PowTest: true, }) if err != nil { t.Fatal("%v", err) @@ -101,19 +102,12 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) { assetPath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") ds := docserver.New("/") - tf := &testjethre{ds: ds, stateDb: ethereum.ChainManager().State().Copy()} + tf := &testjethre{ds: ds} repl := newJSRE(ethereum, assetPath, "", false, "", false, tf) tf.jsre = repl return tmp, tf, ethereum } -// this line below is needed for transaction to be applied to the state in testing -// the heavy lifing is done in XEth.ApplyTestTxs -// this is fragile, overwriting xeth will result in -// process leaking since xeth loops cannot quit safely -// should be replaced by proper mining with testDAG for easy full integration tests -// txc, self.xeth = self.xeth.ApplyTestTxs(self.xeth.repl.stateDb, coinbase, txc) - func TestNodeInfo(t *testing.T) { t.Skip("broken after p2p update") tmp, repl, ethereum := testJEthRE(t) @@ -257,12 +251,9 @@ func TestContract(t *testing.T) { defer ethereum.Stop() defer os.RemoveAll(tmp) - var txc uint64 coinbase := common.HexToAddress(testAddress) resolver.New(repl.xeth).CreateContracts(coinbase) - // time.Sleep(1000 * time.Millisecond) - // checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `2`) source := `contract test {\n` + " /// @notice Will multiply `a` by 7." + `\n` + ` function multiply(uint a) returns(uint d) {\n` + @@ -270,14 +261,20 @@ func TestContract(t *testing.T) { ` }\n` + `}\n` - checkEvalJSON(t, repl, `admin.contractInfo.stop()`, `true`) + if checkEvalJSON(t, repl, `admin.contractInfo.stop()`, `true`) != nil { + return + } contractInfo, err := ioutil.ReadFile("info_test.json") if err != nil { t.Fatalf("%v", err) } - checkEvalJSON(t, repl, `primary = eth.accounts[0]`, `"`+testAddress+`"`) - checkEvalJSON(t, repl, `source = "`+source+`"`, `"`+source+`"`) + if checkEvalJSON(t, repl, `primary = eth.accounts[0]`, `"`+testAddress+`"`) != nil { + return + } + if checkEvalJSON(t, repl, `source = "`+source+`"`, `"`+source+`"`) != nil { + return + } // if solc is found with right version, test it, otherwise read from file sol, err := compiler.New("") @@ -297,71 +294,156 @@ func TestContract(t *testing.T) { t.Errorf("%v", err) } } else { - checkEvalJSON(t, repl, `contract = eth.compile.solidity(source).test`, string(contractInfo)) + if checkEvalJSON(t, repl, `contract = eth.compile.solidity(source).test`, string(contractInfo)) != nil { + return + } } - checkEvalJSON(t, repl, `contract.code`, `"0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"`) + if checkEvalJSON(t, repl, `contract.code`, `"0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"`) != nil { + return + } - checkEvalJSON( + if checkEvalJSON( t, repl, - `contractaddress = eth.sendTransaction({from: primary, data: contract.code })`, + `contractaddress = eth.sendTransaction({from: primary, data: contract.code, gasPrice:"1000", gas:"100000", amount:100 })`, `"0x291293d57e0a0ab47effe97c02577f90d9211567"`, - ) + ) != nil { + return + } + + if !processTxs(repl, t, 7) { + return + } callSetup := `abiDef = JSON.parse('[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]'); Multiply7 = eth.contract(abiDef); multiply7 = Multiply7.at(contractaddress); ` - // time.Sleep(1500 * time.Millisecond) _, err = repl.re.Run(callSetup) if err != nil { t.Errorf("unexpected error setting up contract, got %v", err) + return } - // checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `3`) - - // why is this sometimes failing? - // checkEvalJSON(t, repl, `multiply7.multiply.call(6)`, `42`) expNotice := "" if repl.lastConfirm != expNotice { t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm) + return } - txc, repl.xeth = repl.xeth.ApplyTestTxs(repl.stateDb, coinbase, txc) + if checkEvalJSON(t, repl, `admin.contractInfo.start()`, `true`) != nil { + return + } + if checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary })`, `undefined`) != nil { + return + } + + if !processTxs(repl, t, 1) { + return + } - checkEvalJSON(t, repl, `admin.contractInfo.start()`, `true`) - checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary, gas: "1000000", gasPrice: "100000" })`, `undefined`) expNotice = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x87e2802265838c7f14bb69eecd2112911af6767907a702eeaa445239fb20711b'): {"params":[{"to":"0x291293d57e0a0ab47effe97c02577f90d9211567","data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}]}` if repl.lastConfirm != expNotice { - t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm) + t.Errorf("incorrect confirmation message: expected\n%v, got\n%v", expNotice, repl.lastConfirm) + return } - var contenthash = `"0x86d2b7cf1e72e9a7a3f8d96601f0151742a2f780f1526414304fbe413dc7f9bd"` - if sol != nil { + var contentHash = `"0x86d2b7cf1e72e9a7a3f8d96601f0151742a2f780f1526414304fbe413dc7f9bd"` + if sol != nil && solcVersion != sol.Version() { modContractInfo := versionRE.ReplaceAll(contractInfo, []byte(`"compilerVersion":"`+sol.Version()+`"`)) - _ = modContractInfo - // contenthash = crypto.Sha3(modContractInfo) + fmt.Printf("modified contractinfo:\n%s\n", modContractInfo) + contentHash = `"` + common.ToHex(crypto.Sha3([]byte(modContractInfo))) + `"` } - checkEvalJSON(t, repl, `filename = "/tmp/info.json"`, `"/tmp/info.json"`) - checkEvalJSON(t, repl, `contenthash = admin.contractInfo.register(primary, contractaddress, contract, filename)`, contenthash) - checkEvalJSON(t, repl, `admin.contractInfo.registerUrl(primary, contenthash, "file://"+filename)`, `true`) - if err != nil { - t.Errorf("unexpected error registering, got %v", err) + if checkEvalJSON(t, repl, `filename = "/tmp/info.json"`, `"/tmp/info.json"`) != nil { + return + } + if checkEvalJSON(t, repl, `contentHash = admin.contractInfo.saveInfo(contract.info, filename)`, contentHash) != nil { + return + } + if checkEvalJSON(t, repl, `admin.contractInfo.register(primary, contractaddress, contentHash)`, `true`) != nil { + return + } + if checkEvalJSON(t, repl, `admin.contractInfo.registerUrl(primary, contentHash, "file://"+filename)`, `true`) != nil { + return } - checkEvalJSON(t, repl, `admin.contractInfo.start()`, `true`) + if checkEvalJSON(t, repl, `admin.contractInfo.start()`, `true`) != nil { + return + } - // update state - txc, repl.xeth = repl.xeth.ApplyTestTxs(repl.stateDb, coinbase, txc) + if !processTxs(repl, t, 3) { + return + } + + if checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary })`, `undefined`) != nil { + return + } + + if !processTxs(repl, t, 1) { + return + } - checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary, gas: "1000000", gasPrice: "100000" })`, `undefined`) expNotice = "Will multiply 6 by 7." if repl.lastConfirm != expNotice { - t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm) + t.Errorf("incorrect confirmation message: expected\n%v, got\n%v", expNotice, repl.lastConfirm) + return } } +func pendingTransactions(repl *testjethre, t *testing.T) (txc int64, err error) { + txs := repl.ethereum.TxPool().GetTransactions() + return int64(len(txs)), nil +} + +func processTxs(repl *testjethre, t *testing.T, expTxc int) bool { + var txc int64 + var err error + for i := 0; i < 50; i++ { + txc, err = pendingTransactions(repl, t) + if err != nil { + t.Errorf("unexpected error checking pending transactions: %v", err) + return false + } + if expTxc < int(txc) { + t.Errorf("too many pending transactions: expected %v, got %v", expTxc, txc) + return false + } else if expTxc == int(txc) { + break + } + time.Sleep(100 * time.Millisecond) + } + if int(txc) != expTxc { + t.Errorf("incorrect number of pending transactions, expected %v, got %v", expTxc, txc) + return false + } + + err = repl.ethereum.StartMining(runtime.NumCPU()) + if err != nil { + t.Errorf("unexpected error mining: %v", err) + return false + } + defer repl.ethereum.StopMining() + + timer := time.NewTimer(100 * time.Second) + height := new(big.Int).Add(repl.xeth.CurrentBlock().Number(), big.NewInt(1)) + _, err = waitForBlocks(repl.wait, height, timer.C) + if err != nil { + t.Errorf("error mining transactions: %v", err) + return false + } + txc, err = pendingTransactions(repl, t) + if err != nil { + t.Errorf("unexpected error checking pending transactions: %v", err) + return false + } + if txc != 0 { + t.Errorf("%d trasactions were not mined", txc) + return false + } + return true +} + func checkEvalJSON(t *testing.T, re *testjethre, expr, want string) error { val, err := re.re.Run("JSON.stringify(" + expr + ")") if err == nil && val.String() != want { diff --git a/common/compiler/solidity.go b/common/compiler/solidity.go index caf86974e5..4d5ffb473e 100644 --- a/common/compiler/solidity.go +++ b/common/compiler/solidity.go @@ -185,12 +185,12 @@ func (sol *Solidity) Compile(source string) (contracts map[string]*Contract, err return } -func ExtractInfo(contract *Contract, filename string) (contenthash common.Hash, err error) { - contractInfo, err := json.Marshal(contract.Info) +func SaveInfo(info *ContractInfo, filename string) (contenthash common.Hash, err error) { + infojson, err := json.Marshal(info) if err != nil { return } - contenthash = common.BytesToHash(crypto.Sha3(contractInfo)) - err = ioutil.WriteFile(filename, contractInfo, 0600) + contenthash = common.BytesToHash(crypto.Sha3(infojson)) + err = ioutil.WriteFile(filename, infojson, 0600) return } diff --git a/common/compiler/solidity_test.go b/common/compiler/solidity_test.go index 46f733e59d..7864283c65 100644 --- a/common/compiler/solidity_test.go +++ b/common/compiler/solidity_test.go @@ -72,19 +72,15 @@ func TestNoCompiler(t *testing.T) { } } -func TestExtractInfo(t *testing.T) { - var cinfo ContractInfo - err := json.Unmarshal([]byte(info), &cinfo) +func TestSaveInfo(t *testing.T) { + var cinfo *ContractInfo + err := json.Unmarshal([]byte(info), cinfo) if err != nil { t.Errorf("%v", err) } - contract := &Contract{ - Code: "", - Info: cinfo, - } filename := "/tmp/solctest.info.json" os.Remove(filename) - cinfohash, err := ExtractInfo(contract, filename) + cinfohash, err := SaveInfo(cinfo, filename) if err != nil { t.Errorf("error extracting info: %v", err) } diff --git a/common/resolver/resolver.go b/common/resolver/resolver.go index c45ee19828..b2400fe57e 100644 --- a/common/resolver/resolver.go +++ b/common/resolver/resolver.go @@ -36,8 +36,8 @@ var ( const ( txValue = "0" - txGas = "100000" - txGasPrice = "1000000000000" + txGas = "" + txGasPrice = "" ) func abiSignature(s string) string { @@ -284,7 +284,7 @@ func (self *Resolver) RegisterUrl(address common.Address, hash common.Hash, url // registers key -> conenthash in HashReg and // registers contenthash -> url in UrlHint // creates 3 transaction using address as sender -// transactions need to obe mined to take effect +// transactions need to be mined to take effect func (self *Resolver) RegisterAddrWithUrl(address common.Address, codehash, dochash common.Hash, url string) (txh string, err error) { _, err = self.RegisterContentHash(address, codehash, dochash) diff --git a/core/transaction_pool.go b/core/transaction_pool.go index c896488d1e..879c329249 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -231,6 +231,9 @@ func (tp *TxPool) GetTransaction(hash common.Hash) *types.Transaction { } func (self *TxPool) GetTransactions() (txs types.Transactions) { + self.checkQueue() + self.validatePool() + self.mu.RLock() defer self.mu.RUnlock() diff --git a/eth/backend.go b/eth/backend.go index cdac2a8b8f..17c9da829c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -290,6 +290,7 @@ func New(config *Config) (*Ethereum, error) { } if config.PowTest { + glog.V(logger.Info).Infof("ethash used in test mode") eth.pow, err = ethash.NewForTesting() if err != nil { return nil, err From e9ad659eb1867d54354c8c7819850b75978a6483 Mon Sep 17 00:00:00 2001 From: "Daniel A. Nagy" Date: Tue, 2 Jun 2015 12:22:50 +0200 Subject: [PATCH 7/7] bzzup shell script updated for compatibility with new resolver. --- bzz/bzzup/bzzup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bzz/bzzup/bzzup.sh b/bzz/bzzup/bzzup.sh index 52d07207e1..1593ff9b45 100755 --- a/bzz/bzzup/bzzup.sh +++ b/bzz/bzzup/bzzup.sh @@ -6,7 +6,7 @@ delimiter='{"entries":[{' if [ -f "$1" ]; then hash=`wget -q -O- --post-file="$1" http://localhost:8500/raw` -mime=`file --mime-type -b "$1"` +mime=`mimetype -b "$1"` wget -q -O- --post-data="$delimiter\"hash\":\"$hash\",\"contentType\":\"$mime\"}]}" http://localhost:8500/raw echo @@ -21,7 +21,7 @@ pushd "$bzzroot" > /dev/null (for path in `find . -type f` do -name=`echo "$path" | cut -c2-` +name=`echo "$path" | cut -c3-` [ _`basename "$name"` = "_$INDEX" ] && name=`dirname "$name"` echo -n "$delimiter" hash=`wget -q -O- --post-file="$path" http://localhost:8500/raw`