aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2015-11-03 18:47:07 +0800
committerJeffrey Wilcke <geffobscura@gmail.com>2015-11-03 18:47:07 +0800
commite5532154a50114d5ffb1ffd850b746cab00cb899 (patch)
tree0042cc997ccf4166b9b52464339d52d37d7a8ad6 /common
parent9666db2a442887ccf8ec2d81f5e2fedc1a3a3d3e (diff)
parentf75becc264f8bde0f58391fc226243d03e78aa7b (diff)
downloadgo-tangerine-e5532154a50114d5ffb1ffd850b746cab00cb899.tar
go-tangerine-e5532154a50114d5ffb1ffd850b746cab00cb899.tar.gz
go-tangerine-e5532154a50114d5ffb1ffd850b746cab00cb899.tar.bz2
go-tangerine-e5532154a50114d5ffb1ffd850b746cab00cb899.tar.lz
go-tangerine-e5532154a50114d5ffb1ffd850b746cab00cb899.tar.xz
go-tangerine-e5532154a50114d5ffb1ffd850b746cab00cb899.tar.zst
go-tangerine-e5532154a50114d5ffb1ffd850b746cab00cb899.zip
Merge branch 'release/1.3.0'
Conflicts: VERSION cmd/geth/main.go
Diffstat (limited to 'common')
-rw-r--r--common/big.go3
-rw-r--r--common/httpclient/httpclient.go (renamed from common/docserver/docserver.go)52
-rw-r--r--common/httpclient/httpclient_test.go (renamed from common/docserver/docserver_test.go)20
-rw-r--r--common/icap.go190
-rw-r--r--common/icap_test.go91
-rw-r--r--common/natspec/natspec.go14
-rw-r--r--common/natspec/natspec_e2e_test.go125
-rw-r--r--common/natspec/natspec_e2e_test.go.orig2
-rw-r--r--common/path.go56
-rw-r--r--common/registrar/registrar.go52
-rw-r--r--common/registrar/registrar_test.go62
11 files changed, 514 insertions, 153 deletions
diff --git a/common/big.go b/common/big.go
index a5d512d0d..4ce87ee0c 100644
--- a/common/big.go
+++ b/common/big.go
@@ -27,6 +27,9 @@ var (
BigTrue = Big1
BigFalse = Big0
Big32 = big.NewInt(32)
+ Big36 = big.NewInt(36)
+ Big97 = big.NewInt(97)
+ Big98 = big.NewInt(98)
Big256 = big.NewInt(0xff)
Big257 = big.NewInt(257)
MaxBig = String2Big("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
diff --git a/common/docserver/docserver.go b/common/httpclient/httpclient.go
index dac542ba7..23373ecaf 100644
--- a/common/docserver/docserver.go
+++ b/common/httpclient/httpclient.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-package docserver
+package httpclient
import (
"fmt"
@@ -26,14 +26,14 @@ import (
"github.com/ethereum/go-ethereum/crypto"
)
-type DocServer struct {
+type HTTPClient struct {
*http.Transport
DocRoot string
schemes []string
}
-func New(docRoot string) (self *DocServer) {
- self = &DocServer{
+func New(docRoot string) (self *HTTPClient) {
+ self = &HTTPClient{
Transport: &http.Transport{},
DocRoot: docRoot,
schemes: []string{"file"},
@@ -46,18 +46,18 @@ func New(docRoot string) (self *DocServer) {
// A Client is higher-level than a RoundTripper (such as Transport) and additionally handles HTTP details such as cookies and redirects.
-func (self *DocServer) Client() *http.Client {
+func (self *HTTPClient) Client() *http.Client {
return &http.Client{
Transport: self,
}
}
-func (self *DocServer) RegisterScheme(scheme string, rt http.RoundTripper) {
+func (self *HTTPClient) RegisterScheme(scheme string, rt http.RoundTripper) {
self.schemes = append(self.schemes, scheme)
self.RegisterProtocol(scheme, rt)
}
-func (self *DocServer) HasScheme(scheme string) bool {
+func (self *HTTPClient) HasScheme(scheme string) bool {
for _, s := range self.schemes {
if s == scheme {
return true
@@ -66,49 +66,59 @@ func (self *DocServer) HasScheme(scheme string) bool {
return false
}
-func (self *DocServer) GetAuthContent(uri string, hash common.Hash) (content []byte, err error) {
+func (self *HTTPClient) GetAuthContent(uri string, hash common.Hash) ([]byte, error) {
// retrieve content
- content, err = self.Get(uri, "")
+ content, err := self.Get(uri, "")
if err != nil {
- return
+ return nil, err
}
// check hash to authenticate content
chash := crypto.Sha3Hash(content)
if chash != hash {
- content = nil
- err = fmt.Errorf("content hash mismatch %x != %x (exp)", hash[:], chash[:])
+ return nil, fmt.Errorf("content hash mismatch %x != %x (exp)", hash[:], chash[:])
}
- return
+ return content, nil
}
// Get(uri, path) downloads the document at uri, if path is non-empty it
// is interpreted as a filepath to which the contents are saved
-func (self *DocServer) Get(uri, path string) (content []byte, err error) {
+func (self *HTTPClient) Get(uri, path string) ([]byte, error) {
// retrieve content
resp, err := self.Client().Get(uri)
-
+ if err != nil {
+ return nil, err
+ }
defer func() {
if resp != nil {
resp.Body.Close()
}
}()
- if err != nil {
- return
- }
+
+ var content []byte
content, err = ioutil.ReadAll(resp.Body)
if err != nil {
- return
+ return nil, err
+ }
+
+ if resp.StatusCode/100 != 2 {
+ return content, fmt.Errorf("HTTP error: %s", resp.Status)
}
if path != "" {
var abspath string
abspath, err = filepath.Abs(path)
- ioutil.WriteFile(abspath, content, 0700)
+ if err != nil {
+ return nil, err
+ }
+ err = ioutil.WriteFile(abspath, content, 0600)
+ if err != nil {
+ return nil, err
+ }
}
- return
+ return content, nil
}
diff --git a/common/docserver/docserver_test.go b/common/httpclient/httpclient_test.go
index 632603add..6c3782e15 100644
--- a/common/docserver/docserver_test.go
+++ b/common/httpclient/httpclient_test.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-package docserver
+package httpclient
import (
"io/ioutil"
@@ -28,19 +28,19 @@ import (
)
func TestGetAuthContent(t *testing.T) {
- dir, err := ioutil.TempDir("", "docserver-test")
+ dir, err := ioutil.TempDir("", "httpclient-test")
if err != nil {
t.Fatal("cannot create temporary directory:", err)
}
defer os.RemoveAll(dir)
- ds := New(dir)
+ client := New(dir)
text := "test"
hash := crypto.Sha3Hash([]byte(text))
if err := ioutil.WriteFile(path.Join(dir, "test.content"), []byte(text), os.ModePerm); err != nil {
t.Fatal("could not write test file", err)
}
- content, err := ds.GetAuthContent("file:///test.content", hash)
+ content, err := client.GetAuthContent("file:///test.content", hash)
if err != nil {
t.Errorf("no error expected, got %v", err)
}
@@ -49,7 +49,7 @@ func TestGetAuthContent(t *testing.T) {
}
hash = common.Hash{}
- content, err = ds.GetAuthContent("file:///test.content", hash)
+ content, err = client.GetAuthContent("file:///test.content", hash)
expected := "content hash mismatch 0000000000000000000000000000000000000000000000000000000000000000 != 9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658 (exp)"
if err == nil {
t.Errorf("expected error, got nothing")
@@ -66,12 +66,12 @@ type rt struct{}
func (rt) RoundTrip(req *http.Request) (resp *http.Response, err error) { return }
func TestRegisterScheme(t *testing.T) {
- ds := New("/tmp/")
- if ds.HasScheme("scheme") {
+ client := New("/tmp/")
+ if client.HasScheme("scheme") {
t.Errorf("expected scheme not to be registered")
}
- ds.RegisterScheme("scheme", rt{})
- if !ds.HasScheme("scheme") {
+ client.RegisterScheme("scheme", rt{})
+ if !client.HasScheme("scheme") {
t.Errorf("expected scheme to be registered")
}
-} \ No newline at end of file
+}
diff --git a/common/icap.go b/common/icap.go
new file mode 100644
index 000000000..a36e669b3
--- /dev/null
+++ b/common/icap.go
@@ -0,0 +1,190 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Spec at https://github.com/ethereum/wiki/wiki/ICAP:-Inter-exchange-Client-Address-Protocol
+
+package common
+
+import (
+ "errors"
+ "math/big"
+ "strconv"
+ "strings"
+)
+
+var (
+ Base36Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ ICAPLengthError = errors.New("Invalid ICAP length")
+ ICAPEncodingError = errors.New("Invalid ICAP encoding")
+ ICAPChecksumError = errors.New("Invalid ICAP checksum")
+ ICAPCountryCodeError = errors.New("Invalid ICAP country code")
+ ICAPAssetIdentError = errors.New("Invalid ICAP asset identifier")
+ ICAPInstCodeError = errors.New("Invalid ICAP institution code")
+ ICAPClientIdentError = errors.New("Invalid ICAP client identifier")
+)
+
+func ICAPToAddress(s string) (Address, error) {
+ switch len(s) {
+ case 35: // "XE" + 2 digit checksum + 31 base-36 chars of address
+ return parseICAP(s)
+ case 34: // "XE" + 2 digit checksum + 30 base-36 chars of address
+ return parseICAP(s)
+ case 20: // "XE" + 2 digit checksum + 3-char asset identifier +
+ // 4-char institution identifier + 9-char institution client identifier
+ return parseIndirectICAP(s)
+ default:
+ return Address{}, ICAPLengthError
+ }
+}
+
+func parseICAP(s string) (Address, error) {
+ if !strings.HasPrefix(s, "XE") {
+ return Address{}, ICAPCountryCodeError
+ }
+ if err := validCheckSum(s); err != nil {
+ return Address{}, err
+ }
+ // checksum is ISO13616, Ethereum address is base-36
+ bigAddr, _ := new(big.Int).SetString(s[4:], 36)
+ return BigToAddress(bigAddr), nil
+}
+
+func parseIndirectICAP(s string) (Address, error) {
+ if !strings.HasPrefix(s, "XE") {
+ return Address{}, ICAPCountryCodeError
+ }
+ if s[4:7] != "ETH" {
+ return Address{}, ICAPAssetIdentError
+ }
+ if err := validCheckSum(s); err != nil {
+ return Address{}, err
+ }
+ // TODO: integrate with ICAP namereg
+ return Address{}, errors.New("not implemented")
+}
+
+func AddressToICAP(a Address) (string, error) {
+ enc := base36Encode(a.Big())
+ // zero padd encoded address to Direct ICAP length if needed
+ if len(enc) < 30 {
+ enc = join(strings.Repeat("0", 30-len(enc)), enc)
+ }
+ icap := join("XE", checkDigits(enc), enc)
+ return icap, nil
+}
+
+// TODO: integrate with ICAP namereg when it's available
+func AddressToIndirectICAP(a Address, instCode string) (string, error) {
+ // return addressToIndirectICAP(a, instCode)
+ return "", errors.New("not implemented")
+}
+
+func addressToIndirectICAP(a Address, instCode string) (string, error) {
+ // TODO: add addressToClientIdent which grabs client ident from ICAP namereg
+ //clientIdent := addressToClientIdent(a)
+ clientIdent := "todo"
+ return clientIdentToIndirectICAP(instCode, clientIdent)
+}
+
+func clientIdentToIndirectICAP(instCode, clientIdent string) (string, error) {
+ if len(instCode) != 4 || !validBase36(instCode) {
+ return "", ICAPInstCodeError
+ }
+ if len(clientIdent) != 9 || !validBase36(instCode) {
+ return "", ICAPClientIdentError
+ }
+
+ // currently ETH is only valid asset identifier
+ s := join("ETH", instCode, clientIdent)
+ return join("XE", checkDigits(s), s), nil
+}
+
+// https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN
+func validCheckSum(s string) error {
+ s = join(s[4:], s[:4])
+ expanded, err := iso13616Expand(s)
+ if err != nil {
+ return err
+ }
+ checkSumNum, _ := new(big.Int).SetString(expanded, 10)
+ if checkSumNum.Mod(checkSumNum, Big97).Cmp(Big1) != 0 {
+ return ICAPChecksumError
+ }
+ return nil
+}
+
+func checkDigits(s string) string {
+ expanded, _ := iso13616Expand(strings.Join([]string{s, "XE00"}, ""))
+ num, _ := new(big.Int).SetString(expanded, 10)
+ num.Sub(Big98, num.Mod(num, Big97))
+
+ checkDigits := num.String()
+ // zero padd checksum
+ if len(checkDigits) == 1 {
+ checkDigits = join("0", checkDigits)
+ }
+ return checkDigits
+}
+
+// not base-36, but expansion to decimal literal: A = 10, B = 11, ... Z = 35
+func iso13616Expand(s string) (string, error) {
+ var parts []string
+ if !validBase36(s) {
+ return "", ICAPEncodingError
+ }
+ for _, c := range s {
+ i := uint64(c)
+ if i >= 65 {
+ parts = append(parts, strconv.FormatUint(uint64(c)-55, 10))
+ } else {
+ parts = append(parts, string(c))
+ }
+ }
+ return join(parts...), nil
+}
+
+func base36Encode(i *big.Int) string {
+ var chars []rune
+ x := new(big.Int)
+ for {
+ x.Mod(i, Big36)
+ chars = append(chars, rune(Base36Chars[x.Uint64()]))
+ i.Div(i, Big36)
+ if i.Cmp(Big0) == 0 {
+ break
+ }
+ }
+ // reverse slice
+ for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
+ chars[i], chars[j] = chars[j], chars[i]
+ }
+ return string(chars)
+}
+
+func validBase36(s string) bool {
+ for _, c := range s {
+ i := uint64(c)
+ // 0-9 or A-Z
+ if i < 48 || (i > 57 && i < 65) || i > 90 {
+ return false
+ }
+ }
+ return true
+}
+
+func join(s ...string) string {
+ return strings.Join(s, "")
+}
diff --git a/common/icap_test.go b/common/icap_test.go
new file mode 100644
index 000000000..6306686d1
--- /dev/null
+++ b/common/icap_test.go
@@ -0,0 +1,91 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package common
+
+import "testing"
+
+/* More test vectors:
+https://github.com/ethereum/web3.js/blob/master/test/iban.fromAddress.js
+https://github.com/ethereum/web3.js/blob/master/test/iban.toAddress.js
+https://github.com/ethereum/web3.js/blob/master/test/iban.isValid.js
+https://github.com/ethereum/libethereum/blob/develop/test/libethcore/icap.cpp
+*/
+
+type icapTest struct {
+ name string
+ addr string
+ icap string
+}
+
+var icapOKTests = []icapTest{
+ {"Direct1", "0x52dc504a422f0e2a9e7632a34a50f1a82f8224c7", "XE499OG1EH8ZZI0KXC6N83EKGT1BM97P2O7"},
+ {"Direct2", "0x11c5496aee77c1ba1f0854206a26dda82a81d6d8", "XE1222Q908LN1QBBU6XUQSO1OHWJIOS46OO"},
+ {"DirectZeroPrefix", "0x00c5496aee77c1ba1f0854206a26dda82a81d6d8", "XE7338O073KYGTWWZN0F2WZ0R8PX5ZPPZS"},
+ {"DirectDoubleZeroPrefix", "0x0000a5327eab78357cbf2ae8f3d49fd9d90c7d22", "XE0600DQK33XDTYUCRI0KYM5ELAKXDWWF6"},
+}
+
+var icapInvalidTests = []icapTest{
+ {"DirectInvalidCheckSum", "", "XE7438O073KYGTWWZN0F2WZ0R8PX5ZPPZS"},
+ {"DirectInvalidCountryCode", "", "XD7338O073KYGTWWZN0F2WZ0R8PX5ZPPZS"},
+ {"DirectInvalidLength36", "", "XE499OG1EH8ZZI0KXC6N83EKGT1BM97P2O77"},
+ {"DirectInvalidLength33", "", "XE499OG1EH8ZZI0KXC6N83EKGT1BM97P2"},
+
+ {"IndirectInvalidCheckSum", "", "XE35ETHXREGGOPHERSSS"},
+ {"IndirectInvalidAssetIdentifier", "", "XE34ETHXREGGOPHERSSS"},
+ {"IndirectInvalidLength19", "", "XE34ETHXREGGOPHERSS"},
+ {"IndirectInvalidLength21", "", "XE34ETHXREGGOPHERSSSS"},
+}
+
+func TestICAPOK(t *testing.T) {
+ for _, test := range icapOKTests {
+ decodeEncodeTest(HexToAddress(test.addr), test.icap, t)
+ }
+}
+
+func TestICAPInvalid(t *testing.T) {
+ for _, test := range icapInvalidTests {
+ failedDecodingTest(test.icap, t)
+ }
+}
+
+func decodeEncodeTest(addr0 Address, icap0 string, t *testing.T) {
+ icap1, err := AddressToICAP(addr0)
+ if err != nil {
+ t.Errorf("ICAP encoding failed: %s", err)
+ }
+ if icap1 != icap0 {
+ t.Errorf("ICAP mismatch: have: %s want: %s", icap1, icap0)
+ }
+
+ addr1, err := ICAPToAddress(icap0)
+ if err != nil {
+ t.Errorf("ICAP decoding failed: %s", err)
+ }
+ if addr1 != addr0 {
+ t.Errorf("Address mismatch: have: %x want: %x", addr1, addr0)
+ }
+}
+
+func failedDecodingTest(icap string, t *testing.T) {
+ addr, err := ICAPToAddress(icap)
+ if err == nil {
+ t.Errorf("Expected ICAP decoding to fail.")
+ }
+ if addr != (Address{}) {
+ t.Errorf("Expected empty Address on failed ICAP decoding.")
+ }
+}
diff --git a/common/natspec/natspec.go b/common/natspec/natspec.go
index 0265c2e13..d9627b4e1 100644
--- a/common/natspec/natspec.go
+++ b/common/natspec/natspec.go
@@ -23,7 +23,7 @@ import (
"strings"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/docserver"
+ "github.com/ethereum/go-ethereum/common/httpclient"
"github.com/ethereum/go-ethereum/common/registrar"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/xeth"
@@ -43,7 +43,7 @@ type NatSpec struct {
// the implementation is frontend friendly in that it always gives back
// a notice that is safe to display
// :FIXME: the second return value is an error, which can be used to fine-tune bahaviour
-func GetNotice(xeth *xeth.XEth, tx string, http *docserver.DocServer) (notice string) {
+func GetNotice(xeth *xeth.XEth, tx string, http *httpclient.HTTPClient) (notice string) {
ns, err := New(xeth, tx, http)
if err != nil {
if ns == nil {
@@ -83,7 +83,7 @@ type contractInfo struct {
DeveloperDoc json.RawMessage `json:"developerDoc"`
}
-func New(xeth *xeth.XEth, jsontx string, http *docserver.DocServer) (self *NatSpec, err error) {
+func New(xeth *xeth.XEth, jsontx string, http *httpclient.HTTPClient) (self *NatSpec, err error) {
// extract contract address from tx
var tx jsonTx
@@ -104,7 +104,7 @@ func New(xeth *xeth.XEth, jsontx string, http *docserver.DocServer) (self *NatSp
}
// also called by admin.contractInfo.get
-func FetchDocsForContract(contractAddress string, xeth *xeth.XEth, ds *docserver.DocServer) (content []byte, err error) {
+func FetchDocsForContract(contractAddress string, xeth *xeth.XEth, client *httpclient.HTTPClient) (content []byte, err error) {
// retrieve contract hash from state
codehex := xeth.CodeAt(contractAddress)
codeb := xeth.CodeAtBytes(contractAddress)
@@ -122,8 +122,8 @@ func FetchDocsForContract(contractAddress string, xeth *xeth.XEth, ds *docserver
if err != nil {
return
}
- if ds.HasScheme("bzz") {
- content, err = ds.Get("bzz://"+hash.Hex()[2:], "")
+ if client.HasScheme("bzz") {
+ content, err = client.Get("bzz://"+hash.Hex()[2:], "")
if err == nil { // non-fatal
return
}
@@ -137,7 +137,7 @@ func FetchDocsForContract(contractAddress string, xeth *xeth.XEth, ds *docserver
}
// get content via http client and authenticate content using hash
- content, err = ds.GetAuthContent(uri, hash)
+ content, err = client.GetAuthContent(uri, hash)
if err != nil {
return
}
diff --git a/common/natspec/natspec_e2e_test.go b/common/natspec/natspec_e2e_test.go
index 57f81f652..5c0d43091 100644
--- a/common/natspec/natspec_e2e_test.go
+++ b/common/natspec/natspec_e2e_test.go
@@ -21,14 +21,14 @@ import (
"io/ioutil"
"math/big"
"os"
+ "path/filepath"
"runtime"
- "strings"
"testing"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/docserver"
+ "github.com/ethereum/go-ethereum/common/httpclient"
"github.com/ethereum/go-ethereum/common/registrar"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
@@ -38,7 +38,9 @@ import (
)
const (
+ testAddress = "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
testBalance = "10000000000000000000"
+ testKey = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674"
testFileName = "long_file_name_for_testing_registration_of_URLs_longer_than_32_bytes.content"
@@ -48,7 +50,7 @@ const (
testExpNotice2 = `About to submit transaction (NatSpec notice error: abi key does not match any method): {"params":[{"to":"%s","data": "0x31e12c20"}]}`
- testExpNotice3 = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x1392c62d05b2d149e22a339c531157ae06b44d39a674cce500064b12b9aeb019'): {"params":[{"to":"%s","data": "0x300a3bbfb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066696c653a2f2f2f746573742e636f6e74656e74"}]}`
+ testExpNotice3 = `About to submit transaction (no NatSpec info found for contract: HashToHash: content hash not found for '0x1392c62d05b2d149e22a339c531157ae06b44d39a674cce500064b12b9aeb019'): {"params":[{"to":"%s","data": "0x300a3bbfb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066696c653a2f2f2f746573742e636f6e74656e74"}]}`
)
const (
@@ -100,6 +102,10 @@ type testFrontend struct {
wantNatSpec bool
}
+func (self *testFrontend) AskPassword() (string, bool) {
+ return "", true
+}
+
func (self *testFrontend) UnlockAccount(acc []byte) bool {
self.ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "password")
return true
@@ -107,50 +113,50 @@ func (self *testFrontend) UnlockAccount(acc []byte) bool {
func (self *testFrontend) ConfirmTransaction(tx string) bool {
if self.wantNatSpec {
- ds := docserver.New("/tmp/")
- self.lastConfirm = GetNotice(self.xeth, tx, ds)
+ client := httpclient.New("/tmp/")
+ self.lastConfirm = GetNotice(self.xeth, tx, client)
}
return true
}
func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
- os.RemoveAll("/tmp/eth-natspec/")
-
- err = os.MkdirAll("/tmp/eth-natspec/keystore", os.ModePerm)
+ tmp, err := ioutil.TempDir("", "natspec-test")
if err != nil {
- panic(err)
+ t.Fatal(err)
}
-
- // create a testAddress
- ks := crypto.NewKeyStorePassphrase("/tmp/eth-natspec/keystore")
+ db, _ := ethdb.NewMemDatabase()
+ addr := common.HexToAddress(testAddress)
+ core.WriteGenesisBlockForTesting(db, core.GenesisAccount{addr, common.String2Big(testBalance)})
+ ks := crypto.NewKeyStorePassphrase(filepath.Join(tmp, "keystore"), crypto.LightScryptN, crypto.LightScryptP)
am := accounts.NewManager(ks)
- testAccount, err := am.NewAccount("password")
+ keyb, err := crypto.HexToECDSA(testKey)
if err != nil {
- panic(err)
+ t.Fatal(err)
+ }
+ key := crypto.NewKeyFromECDSA(keyb)
+ err = ks.StoreKey(key, "")
+ if err != nil {
+ t.Fatal(err)
}
- testAddress := strings.TrimPrefix(testAccount.Address.Hex(), "0x")
-
- db, _ := ethdb.NewMemDatabase()
- // set up mock genesis with balance on the testAddress
- core.WriteGenesisBlockForTesting(db, core.GenesisAccount{common.HexToAddress(testAddress), common.String2Big(testBalance)})
-
- // only use minimalistic stack with no networking
- ethereum, err = eth.New(&eth.Config{
- DataDir: "/tmp/eth-natspec",
- AccountManager: am,
- MaxPeers: 0,
- PowTest: true,
- Etherbase: common.HexToAddress(testAddress),
- NewDB: func(path string) (ethdb.Database, error) { return db, nil },
- })
-
+ err = am.Unlock(key.Address, "")
if err != nil {
- panic(err)
+ t.Fatal(err)
}
- return
+ // only use minimalistic stack with no networking
+ return eth.New(&eth.Config{
+ DataDir: tmp,
+ AccountManager: am,
+ Etherbase: common.HexToAddress(testAddress),
+ MaxPeers: 0,
+ PowTest: true,
+ NewDB: func(path string) (ethdb.Database, error) { return db, nil },
+ GpoMinGasPrice: common.Big1,
+ GpobaseCorrectionFactor: 1,
+ GpoMaxGasPrice: common.Big1,
+ })
}
func testInit(t *testing.T) (self *testFrontend) {
@@ -174,36 +180,49 @@ func testInit(t *testing.T) (self *testFrontend) {
// initialise the registry contracts
reg := registrar.New(self.xeth)
- var registrarTxhash, hashRegTxhash, urlHintTxhash string
- registrarTxhash, err = reg.SetGlobalRegistrar("", addr)
+ registrar.GlobalRegistrarAddr = "0x0"
+
+ var txG, txH, txU string
+ txG, err = reg.SetGlobalRegistrar("", addr)
if err != nil {
- t.Errorf("error creating GlobalRegistrar: %v", err)
+ t.Fatalf("error creating GlobalRegistrar: %v", err)
}
+ if !processTxs(self, t, 1) {
+ t.Fatalf("error mining txs")
+ }
+ recG := self.xeth.GetTxReceipt(common.HexToHash(txG))
+ if recG == nil {
+ t.Fatalf("blockchain error creating GlobalRegistrar")
+ }
+ registrar.GlobalRegistrarAddr = recG.ContractAddress.Hex()
- hashRegTxhash, err = reg.SetHashReg("", addr)
+ txH, err = reg.SetHashReg("", addr)
if err != nil {
t.Errorf("error creating HashReg: %v", err)
}
- urlHintTxhash, err = reg.SetUrlHint("", addr)
+ if !processTxs(self, t, 1) {
+ t.Errorf("error mining txs")
+ }
+ recH := self.xeth.GetTxReceipt(common.HexToHash(txH))
+ if recH == nil {
+ t.Fatalf("blockchain error creating HashReg")
+ }
+ registrar.HashRegAddr = recH.ContractAddress.Hex()
+
+ txU, err = reg.SetUrlHint("", addr)
if err != nil {
t.Errorf("error creating UrlHint: %v", err)
}
- if !processTxs(self, t, 3) {
+ if !processTxs(self, t, 1) {
t.Errorf("error mining txs")
}
- _ = registrarTxhash
- _ = hashRegTxhash
- _ = urlHintTxhash
-
- /* TODO:
- * lookup receipt and contract addresses by tx hash
- * name registration for HashReg and UrlHint addresses
- * mine those transactions
- * then set once more SetHashReg SetUrlHint
- */
+ recU := self.xeth.GetTxReceipt(common.HexToHash(txU))
+ if recU == nil {
+ t.Fatalf("blockchain error creating UrlHint")
+ }
+ registrar.UrlHintAddr = recU.ContractAddress.Hex()
return
-
}
// end to end test
@@ -215,7 +234,7 @@ func TestNatspecE2E(t *testing.T) {
addr, _ := tf.ethereum.Etherbase()
// create a contractInfo file (mock cloud-deployed contract metadocs)
- // incidentally this is the info for the registry contract itself
+ // incidentally this is the info for the HashReg contract itself
ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm)
dochash := crypto.Sha3Hash([]byte(testContractInfo))
@@ -223,10 +242,6 @@ func TestNatspecE2E(t *testing.T) {
codeb := tf.xeth.CodeAtBytes(registrar.HashRegAddr)
codehash := crypto.Sha3Hash(codeb)
- // use resolver to register codehash->dochash->url
- // test if globalregistry works
- // registrar.HashRefAddr = "0x0"
- // registrar.UrlHintAddr = "0x0"
reg := registrar.New(tf.xeth)
_, err := reg.SetHashToHash(addr, codehash, dochash)
if err != nil {
@@ -306,7 +321,7 @@ func processTxs(repl *testFrontend, t *testing.T, expTxc int) bool {
return false
}
- err = repl.ethereum.StartMining(runtime.NumCPU())
+ err = repl.ethereum.StartMining(runtime.NumCPU(), "")
if err != nil {
t.Errorf("unexpected error mining: %v", err)
return false
diff --git a/common/natspec/natspec_e2e_test.go.orig b/common/natspec/natspec_e2e_test.go.orig
index ae8e17ad9..601a9edbd 100644
--- a/common/natspec/natspec_e2e_test.go.orig
+++ b/common/natspec/natspec_e2e_test.go.orig
@@ -106,7 +106,7 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
}
// create a testAddress
- ks := crypto.NewKeyStorePassphrase("/tmp/eth-natspec/keystore")
+ ks := crypto.NewKeyStorePassphrase("/tmp/eth-natspec/keystore", crypto.LightScryptN, crypto.LightScryptP)
am := accounts.NewManager(ks)
testAccount, err := am.NewAccount("password")
if err != nil {
diff --git a/common/path.go b/common/path.go
index 8b3c7d14b..39eacacee 100644
--- a/common/path.go
+++ b/common/path.go
@@ -23,8 +23,6 @@ import (
"path/filepath"
"runtime"
"strings"
-
- "github.com/kardianos/osext"
)
// MakeName creates a node name that follows the ethereum convention
@@ -65,49 +63,29 @@ func AbsolutePath(Datadir string, filename string) string {
return filepath.Join(Datadir, filename)
}
-func DefaultAssetPath() string {
- var assetPath string
- pwd, _ := os.Getwd()
- srcdir := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist")
-
- // If the current working directory is the go-ethereum dir
- // assume a debug build and use the source directory as
- // asset directory.
- if pwd == srcdir {
- assetPath = filepath.Join(pwd, "assets")
+func HomeDir() (home string) {
+ if usr, err := user.Current(); err == nil {
+ home = usr.HomeDir
} else {
- switch runtime.GOOS {
- case "darwin":
- // Get Binary Directory
- exedir, _ := osext.ExecutableFolder()
- assetPath = filepath.Join(exedir, "..", "Resources")
- case "linux":
- assetPath = filepath.Join("usr", "share", "mist")
- case "windows":
- assetPath = filepath.Join(".", "assets")
- default:
- assetPath = "."
- }
- }
-
- // Check if the assetPath exists. If not, try the source directory
- // This happens when binary is run from outside cmd/mist directory
- if _, err := os.Stat(assetPath); os.IsNotExist(err) {
- assetPath = filepath.Join(srcdir, "assets")
+ home = os.Getenv("HOME")
}
-
- return assetPath
+ return
}
func DefaultDataDir() string {
- usr, _ := user.Current()
- if runtime.GOOS == "darwin" {
- return filepath.Join(usr.HomeDir, "Library", "Ethereum")
- } else if runtime.GOOS == "windows" {
- return filepath.Join(usr.HomeDir, "AppData", "Roaming", "Ethereum")
- } else {
- return filepath.Join(usr.HomeDir, ".ethereum")
+ // Try to place the data folder in the user's home dir
+ home := HomeDir()
+ if home != "" {
+ if runtime.GOOS == "darwin" {
+ return filepath.Join(home, "Library", "Ethereum")
+ } else if runtime.GOOS == "windows" {
+ return filepath.Join(home, "AppData", "Roaming", "Ethereum")
+ } else {
+ return filepath.Join(home, ".ethereum")
+ }
}
+ // As we cannot guess a stable location, return empty and handle later
+ return ""
}
func DefaultIpcPath() string {
diff --git a/common/registrar/registrar.go b/common/registrar/registrar.go
index d891e161e..24e45edb3 100644
--- a/common/registrar/registrar.go
+++ b/common/registrar/registrar.go
@@ -48,17 +48,16 @@ The Registrar uses 3 contracts on the blockchain:
These contracts are (currently) not included in the genesis block.
Each Set<X> needs to be called once on each blockchain/network once.
-Contract addresses need to be set (HashReg and UrlHint retrieved from the global
-registrar the first time any Registrar method is called in a client session
-
-So the caller needs to make sure the relevant environment initialised the desired
-contracts
+Contract addresses need to be set the first time any Registrar method is called
+in a client session.
+This is done for frontier by default, otherwise the caller needs to make sure
+the relevant environment initialised the desired contracts
*/
var (
- UrlHintAddr = "0x0"
- HashRegAddr = "0x0"
- GlobalRegistrarAddr = "0x0"
- // GlobalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b"
+ // GlobalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b" // olympic
+ GlobalRegistrarAddr = "0x33990122638b9132ca29c723bdf037f1a891a70c" // frontier
+ HashRegAddr = "0x23bf622b5a65f6060d855fca401133ded3520620" // frontier
+ UrlHintAddr = "0x73ed5ef6c010727dfd2671dbb70faac19ec18626" // frontier
zero = regexp.MustCompile("^(0x)?0*$")
)
@@ -113,7 +112,7 @@ func (self *Registrar) SetGlobalRegistrar(namereg string, addr common.Address) (
GlobalRegistrarAddr = namereg
return
}
- if GlobalRegistrarAddr == "0x0" || GlobalRegistrarAddr == "0x" {
+ if zero.MatchString(GlobalRegistrarAddr) {
if (addr == common.Address{}) {
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation not given")
return
@@ -200,6 +199,9 @@ func (self *Registrar) SetUrlHint(urlhint string, addr common.Address) (txhash s
// ReserveName(from, name) reserves name for the sender address in the globalRegistrar
// the tx needs to be mined to take effect
func (self *Registrar) ReserveName(address common.Address, name string) (txh string, err error) {
+ if zero.MatchString(GlobalRegistrarAddr) {
+ return "", fmt.Errorf("GlobalRegistrar address is not set")
+ }
nameHex, extra := encodeName(name, 2)
abi := reserveAbi + nameHex + extra
glog.V(logger.Detail).Infof("Reserve data: %s", abi)
@@ -215,6 +217,10 @@ func (self *Registrar) ReserveName(address common.Address, name string) (txh str
// in the globalRegistrar using from as the sender of the transaction
// the tx needs to be mined to take effect
func (self *Registrar) SetAddressToName(from common.Address, name string, address common.Address) (txh string, err error) {
+ if zero.MatchString(GlobalRegistrarAddr) {
+ return "", fmt.Errorf("GlobalRegistrar address is not set")
+ }
+
nameHex, extra := encodeName(name, 6)
addrHex := encodeAddress(address)
@@ -231,6 +237,10 @@ func (self *Registrar) SetAddressToName(from common.Address, name string, addres
// NameToAddr(from, name) queries the registrar for the address on name
func (self *Registrar) NameToAddr(from common.Address, name string) (address common.Address, err error) {
+ if zero.MatchString(GlobalRegistrarAddr) {
+ return address, fmt.Errorf("GlobalRegistrar address is not set")
+ }
+
nameHex, extra := encodeName(name, 2)
abi := resolveAbi + nameHex + extra
glog.V(logger.Detail).Infof("NameToAddr data: %s", abi)
@@ -249,6 +259,9 @@ func (self *Registrar) NameToAddr(from common.Address, name string) (address com
// called as first step in the registration process on HashReg
func (self *Registrar) SetOwner(address common.Address) (txh string, err error) {
+ if zero.MatchString(HashRegAddr) {
+ return "", fmt.Errorf("HashReg address is not set")
+ }
return self.backend.Transact(
address.Hex(),
HashRegAddr,
@@ -261,6 +274,10 @@ func (self *Registrar) SetOwner(address common.Address) (txh string, err error)
// e.g., the contract Info combined Json Doc's ContentHash
// to CodeHash of a contract or hash of a domain
func (self *Registrar) SetHashToHash(address common.Address, codehash, dochash common.Hash) (txh string, err error) {
+ if zero.MatchString(HashRegAddr) {
+ return "", fmt.Errorf("HashReg address is not set")
+ }
+
_, err = self.SetOwner(address)
if err != nil {
return
@@ -284,6 +301,10 @@ func (self *Registrar) SetHashToHash(address common.Address, codehash, dochash c
// FIXME: silently doing nothing if sender is not the owner
// note that with content addressed storage, this step is no longer necessary
func (self *Registrar) SetUrlToHash(address common.Address, hash common.Hash, url string) (txh string, err error) {
+ if zero.MatchString(UrlHintAddr) {
+ return "", fmt.Errorf("UrlHint address is not set")
+ }
+
hashHex := common.Bytes2Hex(hash[:])
var urlHex string
urlb := []byte(url)
@@ -321,13 +342,17 @@ func (self *Registrar) SetUrlToHash(address common.Address, hash common.Hash, ur
// resolution is costless non-transactional
// implemented as direct retrieval from db
func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err error) {
+ if zero.MatchString(HashRegAddr) {
+ return common.Hash{}, fmt.Errorf("HashReg address is not set")
+ }
+
// look up in hashReg
at := HashRegAddr[2:]
key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:]))
hash := self.backend.StorageAt(at, key)
if hash == "0x0" || len(hash) < 3 || (hash == common.Hash{}.Hex()) {
- err = fmt.Errorf("content hash not found for '%v'", khash.Hex())
+ err = fmt.Errorf("HashToHash: content hash not found for '%v'", khash.Hex())
return
}
copy(chash[:], common.Hex2BytesFixed(hash[2:], 32))
@@ -339,6 +364,9 @@ func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err err
// implemented as direct retrieval from db
// if we use content addressed storage, this step is no longer necessary
func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) {
+ if zero.MatchString(UrlHintAddr) {
+ return "", fmt.Errorf("UrlHint address is not set")
+ }
// look up in URL reg
var str string = " "
var idx uint32
@@ -358,7 +386,7 @@ func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) {
}
if len(uri) == 0 {
- err = fmt.Errorf("GetURLhint: URL hint not found for '%v'", chash.Hex())
+ err = fmt.Errorf("HashToUrl: URL hint not found for '%v'", chash.Hex())
}
return
}
diff --git a/common/registrar/registrar_test.go b/common/registrar/registrar_test.go
index 63f283563..68ee65ab4 100644
--- a/common/registrar/registrar_test.go
+++ b/common/registrar/registrar_test.go
@@ -36,29 +36,31 @@ var (
)
func NewTestBackend() *testBackend {
- HashRegAddr = common.BigToAddress(common.Big0).Hex() //[2:]
- UrlHintAddr = common.BigToAddress(common.Big1).Hex() //[2:]
self := &testBackend{}
self.contracts = make(map[string](map[string]string))
+ return self
+}
+func (self *testBackend) initHashReg() {
self.contracts[HashRegAddr[2:]] = make(map[string]string)
key := storageAddress(storageMapping(storageIdx2Addr(1), codehash[:]))
self.contracts[HashRegAddr[2:]][key] = hash.Hex()
+}
+func (self *testBackend) initUrlHint() {
self.contracts[UrlHintAddr[2:]] = make(map[string]string)
mapaddr := storageMapping(storageIdx2Addr(1), hash[:])
- key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(0)))
+ key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(0)))
self.contracts[UrlHintAddr[2:]][key] = common.ToHex([]byte(url))
key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(1)))
self.contracts[UrlHintAddr[2:]][key] = "0x0"
- return self
}
func (self *testBackend) StorageAt(ca, sa string) (res string) {
c := self.contracts[ca]
if c == nil {
- return
+ return "0x0"
}
res = c[sa]
return
@@ -84,9 +86,31 @@ func TestSetGlobalRegistrar(t *testing.T) {
func TestHashToHash(t *testing.T) {
b := NewTestBackend()
res := New(b)
- // res.SetHashReg()
+ HashRegAddr = "0x0"
got, err := res.HashToHash(codehash)
+ if err == nil {
+ t.Errorf("expected error")
+ } else {
+ exp := "HashReg address is not set"
+ if err.Error() != exp {
+ t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
+ }
+ }
+
+ HashRegAddr = common.BigToAddress(common.Big1).Hex() //[2:]
+ got, err = res.HashToHash(codehash)
+ if err == nil {
+ t.Errorf("expected error")
+ } else {
+ exp := "HashToHash: content hash not found for '" + codehash.Hex() + "'"
+ if err.Error() != exp {
+ t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
+ }
+ }
+
+ b.initHashReg()
+ got, err = res.HashToHash(codehash)
if err != nil {
t.Errorf("expected no error, got %v", err)
} else {
@@ -99,11 +123,33 @@ func TestHashToHash(t *testing.T) {
func TestHashToUrl(t *testing.T) {
b := NewTestBackend()
res := New(b)
- // res.SetUrlHint()
+ UrlHintAddr = "0x0"
got, err := res.HashToUrl(hash)
+ if err == nil {
+ t.Errorf("expected error")
+ } else {
+ exp := "UrlHint address is not set"
+ if err.Error() != exp {
+ t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
+ }
+ }
+
+ UrlHintAddr = common.BigToAddress(common.Big2).Hex() //[2:]
+ got, err = res.HashToUrl(hash)
+ if err == nil {
+ t.Errorf("expected error")
+ } else {
+ exp := "HashToUrl: URL hint not found for '" + hash.Hex() + "'"
+ if err.Error() != exp {
+ t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
+ }
+ }
+
+ b.initUrlHint()
+ got, err = res.HashToUrl(hash)
if err != nil {
- t.Errorf("expected error, got %v", err)
+ t.Errorf("expected no error, got %v", err)
} else {
if got != url {
t.Errorf("incorrect result, expected '%v', got '%s'", url, got)