diff --git a/cmd/geth/js.go b/cmd/geth/js.go
index cdafab7fa1..60b7acd128 100644
--- a/cmd/geth/js.go
+++ b/cmd/geth/js.go
@@ -18,6 +18,7 @@ package main
import (
"bufio"
+ "encoding/json"
"fmt"
"math/big"
"os"
@@ -30,9 +31,9 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/natspec"
- "github.com/ethereum/go-ethereum/common/registrar"
"github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/eth/natspec"
+ "github.com/ethereum/go-ethereum/eth/registrar"
re "github.com/ethereum/go-ethereum/jsre"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
@@ -368,15 +369,23 @@ func (self *jsre) AskPassword() (string, bool) {
return pass, true
}
-func (self *jsre) ConfirmTransaction(tx string) bool {
+func (self *jsre) ConfirmTransaction(txs string) bool {
// Retrieve the Ethereum instance from the node
var ethereum *eth.Ethereum
if err := self.stack.Service(ðereum); err != nil {
return false
}
// If natspec is enabled, ask for permission
- if ethereum.NatSpec {
- notice := natspec.GetNotice(self.xeth, tx, ethereum.HTTPClient())
+ if ethereum.NatSpecEnabled {
+ var tx natspec.SendTxArgs
+ err := json.Unmarshal([]byte(txs), &tx)
+ if err != nil {
+ return false
+ }
+ notice, err := ethereum.NatSpec().GetNatSpec(&tx)
+ if err != nil {
+ return false
+ }
fmt.Println(notice)
answer, _ := self.Prompt("Confirm Transaction [y/n]")
return strings.HasPrefix(strings.Trim(answer, " "), "y")
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 63efa08ee3..970de33ae7 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -604,6 +604,7 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node.
BootstrapNodes: MakeBootstrapNodes(ctx),
ListenAddr: MakeListenAddress(ctx),
NAT: MakeNAT(ctx),
+ DocRoot: ctx.GlobalString(DocRootFlag.Name),
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
}
@@ -620,8 +621,7 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node.
Etherbase: MakeEtherbase(accman, ctx),
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
ExtraData: MakeMinerExtra(extra, ctx),
- NatSpec: ctx.GlobalBool(NatspecEnabledFlag.Name),
- DocRoot: ctx.GlobalString(DocRootFlag.Name),
+ NatSpecEnabled: ctx.GlobalBool(NatspecEnabledFlag.Name),
GasPrice: common.String2Big(ctx.GlobalString(GasPriceFlag.Name)),
GpoMinGasPrice: common.String2Big(ctx.GlobalString(GpoMinGasPriceFlag.Name)),
GpoMaxGasPrice: common.String2Big(ctx.GlobalString(GpoMaxGasPriceFlag.Name)),
diff --git a/common/bytes.go b/common/bytes.go
index ba6987a9ec..c6e2cd3127 100644
--- a/common/bytes.go
+++ b/common/bytes.go
@@ -23,9 +23,14 @@ import (
"encoding/hex"
"fmt"
"math/big"
+ "regexp"
"strings"
)
+var (
+ hexRe = regexp.MustCompile("^(0x)?([a-fA-f0-9]{2})+$")
+)
+
func ToHex(b []byte) string {
hex := Bytes2Hex(b)
// Prefer output of "0x0" instead of "0x"
@@ -139,8 +144,14 @@ func HasHexPrefix(str string) bool {
}
func IsHex(str string) bool {
- l := len(str)
- return l >= 4 && l%2 == 0 && str[0:2] == "0x"
+ return hexRe.MatchString(str)
+}
+
+func NormaliseHex(str string) (string, bool) {
+ if HasHexPrefix(str) {
+ str = str[2:]
+ }
+ return str, IsHex(str)
}
func Bytes2Hex(d []byte) string {
@@ -202,8 +213,8 @@ func ParseData(data ...interface{}) (ret []byte) {
switch t := item.(type) {
case string:
var str []byte
- if IsHex(t) {
- str = Hex2Bytes(t[2:])
+ if n, ok := NormaliseHex(t); ok {
+ str = Hex2Bytes(n)
} else {
str = []byte(t)
}
diff --git a/common/httpclient/httpclient.go b/common/httpclient/httpclient.go
deleted file mode 100644
index 23373ecaf5..0000000000
--- a/common/httpclient/httpclient.go
+++ /dev/null
@@ -1,124 +0,0 @@
-// 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 .
-
-package httpclient
-
-import (
- "fmt"
- "io/ioutil"
- "net/http"
- "path/filepath"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto"
-)
-
-type HTTPClient struct {
- *http.Transport
- DocRoot string
- schemes []string
-}
-
-func New(docRoot string) (self *HTTPClient) {
- self = &HTTPClient{
- Transport: &http.Transport{},
- DocRoot: docRoot,
- schemes: []string{"file"},
- }
- self.RegisterProtocol("file", http.NewFileTransport(http.Dir(self.DocRoot)))
- return
-}
-
-// Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.
-
-// A Client is higher-level than a RoundTripper (such as Transport) and additionally handles HTTP details such as cookies and redirects.
-
-func (self *HTTPClient) Client() *http.Client {
- return &http.Client{
- Transport: self,
- }
-}
-
-func (self *HTTPClient) RegisterScheme(scheme string, rt http.RoundTripper) {
- self.schemes = append(self.schemes, scheme)
- self.RegisterProtocol(scheme, rt)
-}
-
-func (self *HTTPClient) HasScheme(scheme string) bool {
- for _, s := range self.schemes {
- if s == scheme {
- return true
- }
- }
- return false
-}
-
-func (self *HTTPClient) GetAuthContent(uri string, hash common.Hash) ([]byte, error) {
- // retrieve content
- content, err := self.Get(uri, "")
- if err != nil {
- return nil, err
- }
-
- // check hash to authenticate content
- chash := crypto.Sha3Hash(content)
- if chash != hash {
- return nil, fmt.Errorf("content hash mismatch %x != %x (exp)", hash[:], chash[:])
- }
-
- 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 *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()
- }
- }()
-
- var content []byte
- content, err = ioutil.ReadAll(resp.Body)
- if err != nil {
- 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)
- if err != nil {
- return nil, err
- }
- err = ioutil.WriteFile(abspath, content, 0600)
- if err != nil {
- return nil, err
- }
- }
-
- return content, nil
-
-}
diff --git a/eth/api.go b/eth/api.go
index a1630e2d10..b9788787c8 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -32,12 +32,13 @@ import (
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/compiler"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/eth/compiler"
+ "github.com/ethereum/go-ethereum/eth/natspec"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
@@ -882,19 +883,9 @@ func (s *PublicTransactionPoolAPI) sign(address common.Address, tx *types.Transa
return tx.WithSignature(signature)
}
-type SendTxArgs struct {
- From common.Address `json:"from"`
- To common.Address `json:"to"`
- Gas *rpc.HexNumber `json:"gas"`
- GasPrice *rpc.HexNumber `json:"gasPrice"`
- Value *rpc.HexNumber `json:"value"`
- Data string `json:"data"`
- Nonce *rpc.HexNumber `json:"nonce"`
-}
-
// SendTransaction will create a transaction for the given transaction argument, sign it and submit it to the
// transaction pool.
-func (s *PublicTransactionPoolAPI) SendTransaction(args SendTxArgs) (common.Hash, error) {
+func (s *PublicTransactionPoolAPI) SendTransaction(args *natspec.SendTxArgs) (common.Hash, error) {
if args.Gas == nil {
args.Gas = rpc.NewHexNumber(defaultGas)
}
diff --git a/eth/backend.go b/eth/backend.go
index abd1214caa..238cc59dd4 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -30,12 +30,12 @@ import (
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/compiler"
- "github.com/ethereum/go-ethereum/common/httpclient"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/eth/compiler"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/filters"
+ "github.com/ethereum/go-ethereum/eth/natspec"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
@@ -70,7 +70,6 @@ type Config struct {
DatabaseCache int
NatSpec bool
- DocRoot string
AutoDAG bool
PowTest bool
ExtraData []byte
@@ -80,6 +79,7 @@ type Config struct {
GasPrice *big.Int
MinerThreads int
SolcPath string
+ NatSpecEnabled bool
GpoMinGasPrice *big.Int
GpoMaxGasPrice *big.Int
@@ -108,6 +108,8 @@ type Ethereum struct {
protocolManager *ProtocolManager
SolcPath string
solc *compiler.Solidity
+ natSpec *natspec.NatSpec
+ NatSpecEnabled bool
GpoMinGasPrice *big.Int
GpoMaxGasPrice *big.Int
@@ -116,14 +118,12 @@ type Ethereum struct {
GpobaseStepUp int
GpobaseCorrectionFactor int
- httpclient *httpclient.HTTPClient
-
eventMux *event.TypeMux
+ http *node.HTTPClient
miner *miner.Miner
Mining bool
MinerThreads int
- NatSpec bool
AutoDAG bool
PowTest bool
autodagquit chan bool
@@ -196,9 +196,9 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
accountManager: config.AccountManager,
etherbase: config.Etherbase,
netVersionId: config.NetworkId,
- NatSpec: config.NatSpec,
MinerThreads: config.MinerThreads,
SolcPath: config.SolcPath,
+ NatSpecEnabled: config.NatSpecEnabled,
AutoDAG: config.AutoDAG,
PowTest: config.PowTest,
GpoMinGasPrice: config.GpoMinGasPrice,
@@ -207,9 +207,12 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
GpobaseStepDown: config.GpobaseStepDown,
GpobaseStepUp: config.GpobaseStepUp,
GpobaseCorrectionFactor: config.GpobaseCorrectionFactor,
- httpclient: httpclient.New(config.DocRoot),
}
+ backend := NewPublicBlockChainAPI(eth.BlockChain(), eth.ChainDb(), eth.EventMux(), eth.AccountManager())
+ // eth.natSpec = natspec.New(backend, ctx.HTTP, registrar.New(backend))
+ eth.natSpec = natspec.New(backend, ctx.HTTP, nil)
+
if config.PowTest {
glog.V(logger.Info).Infof("ethash used in test mode")
eth.pow, err = ethash.NewForTesting()
@@ -307,6 +310,10 @@ func (s *Ethereum) APIs() []rpc.API {
Namespace: "debug",
Version: "1.0",
Service: NewPrivateDebugAPI(s),
+ }, {
+ Namespace: "eth",
+ Version: "1.0",
+ Service: s.natSpec,
},
}
}
@@ -327,6 +334,8 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) {
return
}
+func (self *Ethereum) URLSchemes() []node.URLScheme { return nil }
+
// set in js console via admin interface or wrapper from cli flags
func (self *Ethereum) SetEtherbase(etherbase common.Address) {
self.etherbase = etherbase
@@ -341,6 +350,7 @@ func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager
func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain }
func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
+func (s *Ethereum) NatSpec() *natspec.NatSpec { return s.natSpec }
func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb }
func (s *Ethereum) DappDb() ethdb.Database { return s.dappDb }
func (s *Ethereum) IsListening() bool { return true } // Always listening
@@ -449,10 +459,10 @@ func (self *Ethereum) StopAutoDAG() {
glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG OFF (ethash dir: %s)", ethash.DefaultDir)
}
-// HTTPClient returns the light http client used for fetching offchain docs
+// HTTP returns the light http client used for fetching offchain docs
// (natspec, source for verification)
-func (self *Ethereum) HTTPClient() *httpclient.HTTPClient {
- return self.httpclient
+func (self *Ethereum) HTTP() *node.HTTPClient {
+ return self.http
}
func (self *Ethereum) Solc() (*compiler.Solidity, error) {
diff --git a/common/compiler/solidity.go b/eth/compiler/solidity.go
similarity index 100%
rename from common/compiler/solidity.go
rename to eth/compiler/solidity.go
diff --git a/common/compiler/solidity_test.go b/eth/compiler/solidity_test.go
similarity index 100%
rename from common/compiler/solidity_test.go
rename to eth/compiler/solidity_test.go
diff --git a/common/natspec/natspec.go b/eth/natspec/natspec.go
similarity index 55%
rename from common/natspec/natspec.go
rename to eth/natspec/natspec.go
index d9627b4e1c..eabcd7b199 100644
--- a/common/natspec/natspec.go
+++ b/eth/natspec/natspec.go
@@ -23,58 +23,70 @@ import (
"strings"
"github.com/ethereum/go-ethereum/common"
- "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"
+ "github.com/ethereum/go-ethereum/eth/registrar"
+ "github.com/ethereum/go-ethereum/node"
+ rpc "github.com/ethereum/go-ethereum/rpc/v2"
"github.com/robertkrimen/otto"
)
type abi2method map[[8]byte]*method
type NatSpec struct {
- jsvm *otto.Otto
- abiDocJson []byte
- userDoc userDoc
- tx, data string
+ backend Backend
+ http *node.HTTPClient
+ reg *registrar.Registrar
}
-// main entry point for to get natspec notice for a transaction
-// 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 *httpclient.HTTPClient) (notice string) {
- ns, err := New(xeth, tx, http)
- if err != nil {
- if ns == nil {
- return getFallbackNotice(fmt.Sprintf("no NatSpec info found for contract: %v", err), tx)
- } else {
- return getFallbackNotice(fmt.Sprintf("invalid NatSpec info: %v", err), tx)
- }
- }
-
- notice, err = ns.Notice()
- if err != nil {
- return getFallbackNotice(fmt.Sprintf("NatSpec notice error: %v", err), tx)
- }
-
- return
+type Backend interface {
+ GetCode(address common.Address, blockNr rpc.BlockNumber) (string, error)
}
-func getFallbackNotice(comment, tx string) string {
- return fmt.Sprintf("About to submit transaction (%s): %s", comment, tx)
-}
-
-type transaction struct {
- To string `json:"to"`
- Data string `json:"data"`
-}
-
-type jsonTx struct {
- Params []transaction `json:"params"`
+func New(backend Backend, http *node.HTTPClient, reg *registrar.Registrar) *NatSpec {
+ return &NatSpec{backend, http, reg}
}
type contractInfo struct {
+ jsvm *otto.Otto
+ abiDocJson []byte
+ userDoc userDoc
+ tx *SendTxArgs
+}
+
+type SendTxArgs struct {
+ From common.Address `json:"from"`
+ To common.Address `json:"to"`
+ Gas *rpc.HexNumber `json:"gas"`
+ GasPrice *rpc.HexNumber `json:"gasPrice"`
+ Value *rpc.HexNumber `json:"value"`
+ Data string `json:"data"`
+ Nonce *rpc.HexNumber `json:"nonce"`
+}
+
+func (self *NatSpec) GetNatSpec(tx *SendTxArgs) (string, error) {
+ to := tx.To
+ // in principle this could be cached, but practically swarm takes care of that
+ info, err := self.GetContractInfo(to)
+ if err != nil {
+ if info == nil {
+ return "", fmt.Errorf("no contract info found for %v: %v", to, err)
+ } else {
+ return "", fmt.Errorf("invalid contract info for %v: %v", to, err)
+ }
+ }
+ ns, err := newContractInfo(info, tx)
+ if err != nil {
+ return "", fmt.Errorf("invalid contract info for %v: %v", to, err)
+ }
+ notice, err := ns.notice()
+ if err != nil {
+ return "", fmt.Errorf("NatSpec notice error for contract %v: %v", to, err)
+ }
+
+ return notice, nil
+}
+
+type ContractInfo struct {
Source string `json:"source"`
Language string `json:"language"`
Version string `json:"compilerVersion"`
@@ -83,81 +95,56 @@ type contractInfo struct {
DeveloperDoc json.RawMessage `json:"developerDoc"`
}
-func New(xeth *xeth.XEth, jsontx string, http *httpclient.HTTPClient) (self *NatSpec, err error) {
-
- // extract contract address from tx
- var tx jsonTx
- err = json.Unmarshal([]byte(jsontx), &tx)
- if err != nil {
- return
- }
- t := tx.Params[0]
- contractAddress := t.To
-
- content, err := FetchDocsForContract(contractAddress, xeth, http)
- if err != nil {
- return
- }
-
- self, err = NewWithDocs(content, jsontx, t.Data)
- return
-}
-
-// also called by admin.contractInfo.get
-func FetchDocsForContract(contractAddress string, xeth *xeth.XEth, client *httpclient.HTTPClient) (content []byte, err error) {
+func (self *NatSpec) GetContractInfo(to common.Address) (*ContractInfo, error) {
// retrieve contract hash from state
- codehex := xeth.CodeAt(contractAddress)
- codeb := xeth.CodeAtBytes(contractAddress)
-
- if codehex == "0x" {
- err = fmt.Errorf("contract (%v) not found", contractAddress)
- return
+ codehex, err := self.backend.GetCode(to, -1)
+ if err != nil || len(codehex) <= 3 {
+ return nil, fmt.Errorf("contract (%v) not found", to)
}
- codehash := common.BytesToHash(crypto.Sha3(codeb))
- // set up nameresolver with natspecreg + urlhint contract addresses
- reg := registrar.New(xeth)
+ codehash := common.BytesToHash(crypto.Sha3(common.FromHex(codehex)))
// resolve host via HashReg/UrlHint Resolver
- hash, err := reg.HashToHash(codehash)
+ hash, err := self.reg.HashToHash(codehash)
if err != nil {
- return
+ return nil, fmt.Errorf("no content hash registered for contract %v: %v", to, err)
}
- if client.HasScheme("bzz") {
- content, err = client.Get("bzz://"+hash.Hex()[2:], "")
- if err == nil { // non-fatal
- return
+ var data []byte
+ if self.http.HasScheme("bzz") {
+ data, err = self.http.GetBody("bzz://" + hash.Hex()[2:])
+ if err != nil { // non-fatal
+ data = nil
}
- err = nil
- //falling back to urlhint
}
- uri, err := reg.HashToUrl(hash)
- if err != nil {
- return
+ //falling back to urlhint
+ if data == nil {
+ uri, err := self.reg.HashToUrl(hash)
+ if err != nil {
+ return nil, err
+ }
+
+ // get content via http client and authenticate content using hash
+ data, err = self.http.GetAuthBody(uri, hash)
+ if err != nil {
+ return nil, err
+ }
}
- // get content via http client and authenticate content using hash
- content, err = client.GetAuthContent(uri, hash)
+ var info ContractInfo
+ err = json.Unmarshal(data, &info)
if err != nil {
- return
+ return nil, err
}
- return
+ return &info, nil
}
-func NewWithDocs(infoDoc []byte, tx string, data string) (self *NatSpec, err error) {
+func newContractInfo(info *ContractInfo, tx *SendTxArgs) (self *contractInfo, err error) {
- var contract contractInfo
- err = json.Unmarshal(infoDoc, &contract)
- if err != nil {
- return
- }
-
- self = &NatSpec{
+ self = &contractInfo{
jsvm: otto.New(),
- abiDocJson: []byte(contract.AbiDefinition),
- userDoc: contract.UserDoc,
+ abiDocJson: []byte(info.AbiDefinition),
+ userDoc: info.UserDoc,
tx: tx,
- data: data,
}
// load and require natspec js (but it is meant to be protected environment)
@@ -192,7 +179,7 @@ type userDoc struct {
Methods map[string]*method `json:methods`
}
-func (self *NatSpec) makeAbi2method(abiKey [8]byte) (meth *method) {
+func (self *contractInfo) makeAbi2method(abiKey [8]byte) (meth *method) {
for signature, m := range self.userDoc.Methods {
name := strings.Split(signature, "(")[0]
hash := []byte(common.Bytes2Hex(crypto.Sha3([]byte(signature))))
@@ -207,26 +194,30 @@ func (self *NatSpec) makeAbi2method(abiKey [8]byte) (meth *method) {
return
}
-func (self *NatSpec) Notice() (notice string, err error) {
+func (self *contractInfo) notice() (notice string, err error) {
var abiKey [8]byte
- if len(self.data) < 10 {
+ if len(self.tx.Data) < 10 {
err = fmt.Errorf("Invalid transaction data")
return
}
- copy(abiKey[:], self.data[2:10])
+ copy(abiKey[:], self.tx.Data[2:10])
meth := self.makeAbi2method(abiKey)
if meth == nil {
err = fmt.Errorf("abi key does not match any method")
return
}
- notice, err = self.noticeForMethod(self.tx, meth.name, meth.Notice)
+ notice, err = self.noticeForMethod(meth.name, meth.Notice)
return
}
-func (self *NatSpec) noticeForMethod(tx string, name, expression string) (notice string, err error) {
+func (self *contractInfo) noticeForMethod(name, expression string) (notice string, err error) {
+ tx, err := json.Marshal(self.tx)
+ if err != nil {
+ return "", nil
+ }
- if _, err = self.jsvm.Run("var transaction = " + tx + ";"); err != nil {
+ if _, err = self.jsvm.Run("var transaction = " + string(tx) + ";"); err != nil {
return "", fmt.Errorf("natspec.js error setting transaction: %v", err)
}
@@ -247,12 +238,13 @@ func (self *NatSpec) noticeForMethod(tx string, name, expression string) (notice
if err != nil {
return "", fmt.Errorf("natspec.js error evaluating expression: %v", err)
}
+
evalError := "Natspec evaluation failed, wrong input params"
if value.String() == evalError {
return "", fmt.Errorf("natspec.js error evaluating expression: wrong input params in expression '%s'", expression)
}
if len(value.String()) == 0 {
- return "", fmt.Errorf("natspec.js error evaluating expression")
+ return "", fmt.Errorf("natspec.js error evaluating expression: empty notice")
}
return value.String(), nil
diff --git a/common/natspec/natspec_e2e_test.go b/eth/natspec/natspec_e2e_test.go
similarity index 100%
rename from common/natspec/natspec_e2e_test.go
rename to eth/natspec/natspec_e2e_test.go
diff --git a/common/natspec/natspec_e2e_test.go.orig b/eth/natspec/natspec_e2e_test.go.orig
similarity index 100%
rename from common/natspec/natspec_e2e_test.go.orig
rename to eth/natspec/natspec_e2e_test.go.orig
diff --git a/common/natspec/natspec_js.go b/eth/natspec/natspec_js.go
similarity index 100%
rename from common/natspec/natspec_js.go
rename to eth/natspec/natspec_js.go
diff --git a/common/natspec/natspec_test.go b/eth/natspec/natspec_test.go
similarity index 100%
rename from common/natspec/natspec_test.go
rename to eth/natspec/natspec_test.go
diff --git a/common/registrar/contracts.go b/eth/registrar/contracts.go
similarity index 100%
rename from common/registrar/contracts.go
rename to eth/registrar/contracts.go
diff --git a/common/registrar/ethreg/ethreg.go b/eth/registrar/ethreg/ethreg.go
similarity index 100%
rename from common/registrar/ethreg/ethreg.go
rename to eth/registrar/ethreg/ethreg.go
diff --git a/common/registrar/registrar.go b/eth/registrar/registrar.go
similarity index 100%
rename from common/registrar/registrar.go
rename to eth/registrar/registrar.go
diff --git a/common/registrar/registrar_test.go b/eth/registrar/registrar_test.go
similarity index 100%
rename from common/registrar/registrar_test.go
rename to eth/registrar/registrar_test.go
diff --git a/node/config.go b/node/config.go
index 93f0ba79d6..d7c3db3099 100644
--- a/node/config.go
+++ b/node/config.go
@@ -49,6 +49,10 @@ type Config struct {
// in memory.
DataDir string
+ // Document Root, durectory path for serving files from local file system
+ // used as root for Node#HTTP.Get("file://") requestss
+ DocRoot string
+
// This field should be a valid secp256k1 private key that will be used for both
// remote peer identification as well as network traffic encryption. If no key
// is configured, the preset one is loaded from the data dir, generating it if
diff --git a/node/http.go b/node/http.go
new file mode 100644
index 0000000000..08f8584571
--- /dev/null
+++ b/node/http.go
@@ -0,0 +1,139 @@
+package node
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+func newHTTP(docRoot string) *HTTPClient {
+ t := &http.Transport{}
+ if len(docRoot) > 0 {
+ t.RegisterProtocol("file", http.NewFileTransport(http.Dir(docRoot)))
+ }
+ return &HTTPClient{
+ Client: &http.Client{Transport: t},
+ transport: t,
+ schemes: []string{"file"},
+ }
+}
+
+func (self *HTTPClient) registerSchemes(schemes []URLScheme) {
+ for _, scheme := range schemes {
+ self.schemes = append(self.schemes, scheme.Name)
+ self.transport.RegisterProtocol(scheme.Name, scheme.RoundTripper)
+ }
+}
+
+type HTTPClient struct {
+ *http.Client
+ transport *http.Transport
+ schemes []string
+}
+
+// Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.
+
+// A Client is higher-level than a RoundTripper (such as Transport) and additionally handles HTTP details such as cookies and redirects.
+
+type URLScheme struct {
+ Name string
+ RoundTripper http.RoundTripper
+}
+
+func (self *HTTPClient) HasScheme(scheme string) bool {
+ for _, s := range self.schemes {
+ if s == scheme {
+ return true
+ }
+ }
+ return false
+}
+
+// GetBody(uri) downloads the document at uri, if path is non-empty it
+// GetBody(uri) fetches the uri and returns the body
+func (self *HTTPClient) GetBody(uri string) ([]byte, error) {
+ // retrieve body
+ resp, err := self.Get(uri)
+ if err != nil {
+ return nil, err
+ }
+ defer func() {
+ if resp != nil {
+ resp.Body.Close()
+ }
+ }()
+
+ var body []byte
+ body, err = ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ if resp.StatusCode/100 != 2 {
+ return body, fmt.Errorf("HTTP error: %s", resp.Status)
+ }
+ return body, nil
+}
+
+// Download(uri, path) fetches the uri and writes the body into the file
+func (self *HTTPClient) Download(uri, path string) error {
+
+ resp, err := self.Get(uri)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if resp != nil {
+ resp.Body.Close()
+ }
+ }()
+
+ var abspath string
+ abspath, err = filepath.Abs(path)
+ if err != nil {
+ return err
+ }
+ w, err := os.Create(abspath)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+ _, err = io.Copy(w, resp.Body)
+ if err != nil {
+ return err
+ }
+
+ return nil
+
+}
+
+func (self *HTTPClient) GetAuthBody(uri string, hash common.Hash) ([]byte, error) {
+ // retrieve body
+ body, err := self.GetBody(uri)
+ if err != nil {
+ return nil, err
+ }
+
+ // check hash to authenticate body
+ chash := crypto.Sha3Hash(body)
+ if chash != hash {
+ return nil, fmt.Errorf("body hash mismatch %x != %x (exp)", hash[:], chash[:])
+ }
+
+ return body, nil
+
+}
+
+// type HTTPClientAPI interface {
+// Get(uri string) (*http.Response, err)
+// Download(uri, path string) error
+// GetBody(uri) ([]byte, error)
+// HasScheme(scheme string) bool
+// GetAuthBody(uri string, hash common.Hash) ([]byte, error)
+// }
diff --git a/common/httpclient/httpclient_test.go b/node/http_test.go
similarity index 65%
rename from common/httpclient/httpclient_test.go
rename to node/http_test.go
index 6c3782e15a..ad66a6a396 100644
--- a/common/httpclient/httpclient_test.go
+++ b/node/http_test.go
@@ -14,9 +14,10 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package httpclient
+package node
import (
+ "errors"
"io/ioutil"
"net/http"
"os"
@@ -27,20 +28,20 @@ import (
"github.com/ethereum/go-ethereum/crypto"
)
-func TestGetAuthContent(t *testing.T) {
+func TestGetAuthBody(t *testing.T) {
dir, err := ioutil.TempDir("", "httpclient-test")
if err != nil {
t.Fatal("cannot create temporary directory:", err)
}
defer os.RemoveAll(dir)
- client := New(dir)
+ client := newHTTP(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 := client.GetAuthContent("file:///test.content", hash)
+ content, err := client.GetAuthBody("file:///test.content", hash)
if err != nil {
t.Errorf("no error expected, got %v", err)
}
@@ -49,8 +50,8 @@ func TestGetAuthContent(t *testing.T) {
}
hash = common.Hash{}
- content, err = client.GetAuthContent("file:///test.content", hash)
- expected := "content hash mismatch 0000000000000000000000000000000000000000000000000000000000000000 != 9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658 (exp)"
+ content, err = client.GetAuthBody("file:///test.content", hash)
+ expected := "body hash mismatch 0000000000000000000000000000000000000000000000000000000000000000 != 9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658 (exp)"
if err == nil {
t.Errorf("expected error, got nothing")
} else {
@@ -61,17 +62,26 @@ func TestGetAuthContent(t *testing.T) {
}
-type rt struct{}
+type rterr error
+type rt struct{ error }
-func (rt) RoundTrip(req *http.Request) (resp *http.Response, err error) { return }
+// roundtripper with an error. this can prove the roundtrip for testing
+// without having the need to write a Response
+func (e rt) RoundTrip(req *http.Request) (resp *http.Response, err error) {
+ return &http.Response{}, e.error
+}
-func TestRegisterScheme(t *testing.T) {
- client := New("/tmp/")
+func TestHasScheme(t *testing.T) {
+ client := newHTTP("")
if client.HasScheme("scheme") {
t.Errorf("expected scheme not to be registered")
}
- client.RegisterScheme("scheme", rt{})
+ client.registerSchemes([]URLScheme{{"scheme", &rt{rterr(errors.New("rt"))}}})
if !client.HasScheme("scheme") {
t.Errorf("expected scheme to be registered")
}
+ body, err := client.GetBody("scheme://url.com")
+ if _, ok := err.(rterr); !ok {
+ t.Fatalf("failed to use registered scheme. Got error %v and body %v", body, err)
+ }
}
diff --git a/node/node.go b/node/node.go
index 5d7b5869c5..b9c2c0eb5e 100644
--- a/node/node.go
+++ b/node/node.go
@@ -44,6 +44,7 @@ var (
type Node struct {
datadir string // Path to the currently used data directory
eventmux *event.TypeMux // Event multiplexer used between the services of a stack
+ http *HTTPClient // HTTP Client that services can register their URL schemes
serverConfig *p2p.Server // Configuration of the underlying P2P networking layer
server *p2p.Server // Currently running P2P networking layer
@@ -68,6 +69,7 @@ func New(conf *Config) (*Node, error) {
if conf.DataDir != "" {
nodeDbPath = filepath.Join(conf.DataDir, datadirNodeDatabase)
}
+ httpClient := newHTTP(conf.DocRoot)
return &Node{
datadir: conf.DataDir,
serverConfig: &p2p.Server{
@@ -87,6 +89,7 @@ func New(conf *Config) (*Node, error) {
},
serviceFuncs: []ServiceConstructor{},
eventmux: new(event.TypeMux),
+ http: httpClient,
}, nil
}
@@ -123,6 +126,7 @@ func (n *Node) Start() error {
datadir: n.datadir,
services: make(map[reflect.Type]Service),
EventMux: n.eventmux,
+ HTTP: n.http,
}
for kind, s := range services { // copy needed for threaded access
ctx.services[kind] = s
@@ -132,6 +136,7 @@ func (n *Node) Start() error {
if err != nil {
return err
}
+ n.http.registerSchemes(service.URLSchemes())
kind := reflect.TypeOf(service)
if _, exists := services[kind]; exists {
return &DuplicateServiceError{Kind: kind}
@@ -163,6 +168,7 @@ func (n *Node) Start() error {
// Mark the service started for potential cleanup
started = append(started, kind)
}
+
// Finish initializing the startup
n.services = services
n.server = running
@@ -290,6 +296,10 @@ func (n *Node) APIs() []rpc.API {
Version: "1.0",
Service: NewPublicDebugAPI(n),
Public: true,
+ }, {
+ Namespace: "http",
+ Version: "1.0",
+ Service: n.http,
},
}
// Inject all the APIs owned by various services
diff --git a/node/node_example_test.go b/node/node_example_test.go
index ef41dddaf4..03eb027a20 100644
--- a/node/node_example_test.go
+++ b/node/node_example_test.go
@@ -31,14 +31,17 @@ import (
//
// The following methods are needed to implement a node.Service:
// - Protocols() []p2p.Protocol - devp2p protocols the service can communicate on
+// - APIs() []rpc.API - APIs exposed to the rpc
+// - URLSchemes() []URLScheme - URL schemes handled by the service registered on Node#HTTP
// - Start() error - method invoked when the node is ready to start the service
// - Stop() error - method invoked when the node terminates the service
type SampleService struct{}
-func (s *SampleService) Protocols() []p2p.Protocol { return nil }
-func (s *SampleService) APIs() []rpc.API { return nil }
-func (s *SampleService) Start(*p2p.Server) error { fmt.Println("Service starting..."); return nil }
-func (s *SampleService) Stop() error { fmt.Println("Service stopping..."); return nil }
+func (s *SampleService) Protocols() []p2p.Protocol { return nil }
+func (s *SampleService) APIs() []rpc.API { return nil }
+func (s *SampleService) URLSchemes() []node.URLScheme { return nil }
+func (s *SampleService) Start(*p2p.Server) error { fmt.Println("Service starting..."); return nil }
+func (s *SampleService) Stop() error { fmt.Println("Service stopping..."); return nil }
func ExampleUsage() {
// Create a network node to run protocols with the default values. The below list
diff --git a/node/node_test.go b/node/node_test.go
index ef096fc917..b3e4af76cb 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -18,6 +18,7 @@ package node
import (
"errors"
+ "fmt"
"io/ioutil"
"os"
"reflect"
@@ -131,6 +132,36 @@ func TestServiceRegistry(t *testing.T) {
}
}
+// Tests whether services can be registered and duplicates caught.
+func TestServiceURLSchemes(t *testing.T) {
+ stack, err := New(testNodeConfig)
+ if err != nil {
+ t.Fatalf("failed to create protocol stack: %v", err)
+ }
+ var h *HTTPClient
+ newSchemeUserService := func(ctx *ServiceContext) (Service, error) {
+ h = ctx.HTTP
+ return new(SchemeUserService), nil
+ }
+ // Register a batch of unique services and ensure they start successfully
+ services := []ServiceConstructor{NewSchemeService, newSchemeUserService}
+ for i, constructor := range services {
+ if err := stack.Register(constructor); err != nil {
+ t.Fatalf("service #%d: registration failed: %v", i, err)
+ }
+ }
+ if err := stack.Start(); err != nil {
+ t.Fatalf("failed to start original service stack: %v", err)
+ }
+ defer stack.Stop()
+
+ body, err := h.GetBody("rt://url.com")
+ if _, ok := err.(rterr); !ok {
+ t.Fatalf("failed to use registered scheme. Got error %v and body %v", body, err)
+ }
+
+}
+
// Tests that registered services get started and stopped correctly.
func TestServiceLifeCycle(t *testing.T) {
stack, err := New(testNodeConfig)
diff --git a/node/service.go b/node/service.go
index b83d4c80d9..6dc3c43e31 100644
--- a/node/service.go
+++ b/node/service.go
@@ -33,6 +33,7 @@ type ServiceContext struct {
datadir string // Data directory for protocol persistence
services map[reflect.Type]Service // Index of the already constructed services
EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
+ HTTP *HTTPClient // HTTP Client services register their URL schemes with
}
// OpenDatabase opens an existing database with the given name (or creates one
@@ -74,6 +75,9 @@ type Service interface {
// APIs retrieves the list of RPC descriptors the service provides
APIs() []rpc.API
+ // Url Schemes to register on the node http client
+ URLSchemes() []URLScheme
+
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
Start(server *p2p.Server) error
diff --git a/node/utils_test.go b/node/utils_test.go
index 2b7bfadbea..4601b85e23 100644
--- a/node/utils_test.go
+++ b/node/utils_test.go
@@ -20,6 +20,7 @@
package node
import (
+ "errors"
"reflect"
"github.com/ethereum/go-ethereum/p2p"
@@ -31,6 +32,7 @@ type NoopService struct{}
func (s *NoopService) Protocols() []p2p.Protocol { return nil }
func (s *NoopService) APIs() []rpc.API { return nil }
+func (s *NoopService) URLSchemes() []URLScheme { return nil }
func (s *NoopService) Start(*p2p.Server) error { return nil }
func (s *NoopService) Stop() error { return nil }
@@ -48,6 +50,26 @@ func NewNoopServiceB(*ServiceContext) (Service, error) { return new(NoopServiceB
func NewNoopServiceC(*ServiceContext) (Service, error) { return new(NoopServiceC), nil }
func NewNoopServiceD(*ServiceContext) (Service, error) { return new(NoopServiceD), nil }
+// Scheme Service is a service that registers a url scheme on the node
+type SchemeService struct{ NoopService }
+
+func NewSchemeService(*ServiceContext) (Service, error) { return new(SchemeService), nil }
+
+// func (s *NoopService) Protocols() []p2p.Protocol { return nil }
+// func (s *NoopService) APIs() []rpc.API { return nil }
+// func (s *NoopService) URLSchemes() []URLScheme { return nil }
+// func (s *NoopService) Start(*p2p.Server) error { return nil }
+// func (s *NoopService) Stop() error { return nil }
+
+func (*SchemeService) URLSchemes() []URLScheme {
+ return []URLScheme{{"rt", &rt{rterr(errors.New("rt"))}}}
+}
+
+// Scheme User Service is a service that expects a http client on the service context
+type SchemeUserService struct {
+ NoopService
+}
+
// InstrumentedService is an implementation of Service for which all interface
// methods can be instrumented both return value as well as event hook wise.
type InstrumentedService struct {
@@ -73,6 +95,10 @@ func (s *InstrumentedService) APIs() []rpc.API {
return nil
}
+func (s *InstrumentedService) URLSchemes() []URLScheme {
+ return nil
+}
+
func (s *InstrumentedService) Start(server *p2p.Server) error {
if s.startHook != nil {
s.startHook(server)
diff --git a/rpc/api/admin.go b/rpc/api/admin.go
index 1133c9bca3..541bab8110 100644
--- a/rpc/api/admin.go
+++ b/rpc/api/admin.go
@@ -24,13 +24,13 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/compiler"
- "github.com/ethereum/go-ethereum/common/natspec"
- "github.com/ethereum/go-ethereum/common/registrar"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/eth/compiler"
+ // "github.com/ethereum/go-ethereum/eth/natspec"
+ "github.com/ethereum/go-ethereum/eth/registrar"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/discover"
@@ -426,12 +426,12 @@ func (self *adminApi) RegisterUrl(req *shared.Request) (interface{}, error) {
}
func (self *adminApi) StartNatSpec(req *shared.Request) (interface{}, error) {
- self.ethereum.NatSpec = true
+ self.ethereum.NatSpecEnabled = true
return true, nil
}
func (self *adminApi) StopNatSpec(req *shared.Request) (interface{}, error) {
- self.ethereum.NatSpec = false
+ self.ethereum.NatSpecEnabled = false
return true, nil
}
@@ -441,13 +441,7 @@ func (self *adminApi) GetContractInfo(req *shared.Request) (interface{}, error)
return nil, shared.NewDecodeParamError(err.Error())
}
- infoDoc, err := natspec.FetchDocsForContract(args.Contract, self.xeth, self.ethereum.HTTPClient())
- if err != nil {
- return nil, err
- }
-
- var info interface{}
- err = self.coder.Decode(infoDoc, &info)
+ info, err := self.ethereum.NatSpec().GetContractInfo(common.HexToAddress(args.Contract))
if err != nil {
return nil, err
}
@@ -461,12 +455,12 @@ func (self *adminApi) HttpGet(req *shared.Request) (interface{}, error) {
return nil, shared.NewDecodeParamError(err.Error())
}
- resp, err := self.ethereum.HTTPClient().Get(args.Uri, args.Path)
+ body, err := self.ethereum.HTTP().GetBody(args.Uri)
if err != nil {
return nil, err
}
- return string(resp), nil
+ return string(body), nil
}
func (self *adminApi) EnableUserAgent(req *shared.Request) (interface{}, error) {
diff --git a/rpc/api/admin_args.go b/rpc/api/admin_args.go
index e3a2f72bf9..59dfa5df30 100644
--- a/rpc/api/admin_args.go
+++ b/rpc/api/admin_args.go
@@ -19,7 +19,7 @@ package api
import (
"encoding/json"
- "github.com/ethereum/go-ethereum/common/compiler"
+ "github.com/ethereum/go-ethereum/eth/compiler"
"github.com/ethereum/go-ethereum/rpc/shared"
)
diff --git a/rpc/api/eth.go b/rpc/api/eth.go
index db7a643d82..96bc6d5edd 100644
--- a/rpc/api/eth.go
+++ b/rpc/api/eth.go
@@ -24,8 +24,8 @@ import (
"fmt"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/natspec"
"github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/eth/natspec"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared"
@@ -372,10 +372,11 @@ func (self *ethApi) GetNatSpec(req *shared.Request) (interface{}, error) {
return nil, shared.NewDecodeParamError(err.Error())
}
- var jsontx = fmt.Sprintf(`{"params":[{"to":"%s","data": "%s"}]}`, args.To, args.Data)
- notice := natspec.GetNotice(self.xeth, jsontx, self.ethereum.HTTPClient())
-
- return notice, nil
+ tx := &natspec.SendTxArgs{
+ To: common.HexToAddress(args.To),
+ Data: args.Data,
+ }
+ return self.ethereum.NatSpec().GetNatSpec(tx)
}
func (self *ethApi) EstimateGas(req *shared.Request) (interface{}, error) {
diff --git a/whisper/whisper.go b/whisper/whisper.go
index e99950b760..bf23bb2404 100644
--- a/whisper/whisper.go
+++ b/whisper/whisper.go
@@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/event/filter"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
rpc "github.com/ethereum/go-ethereum/rpc/v2"
@@ -112,6 +113,8 @@ func (s *Whisper) APIs() []rpc.API {
}
}
+func (self *Whisper) URLSchemes() []node.URLScheme { return nil }
+
// Protocols returns the whisper sub-protocols ran by this particular client.
func (self *Whisper) Protocols() []p2p.Protocol {
return []p2p.Protocol{self.protocol}
diff --git a/xeth/xeth.go b/xeth/xeth.go
index 5a5399a3e7..e54a06242d 100644
--- a/xeth/xeth.go
+++ b/xeth/xeth.go
@@ -29,13 +29,13 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/compiler"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/eth/compiler"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
@@ -865,7 +865,8 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
return common.ToHex(res), gas.String(), err
}
-func (self *XEth) ConfirmTransaction(tx string) bool {
+func (self *XEth) ConfirmTransaction(to, data string) bool {
+ tx := fmt.Sprintf(`{"params":[{"to":"%s","data": "%s"}]}`, to, data)
return self.frontend.ConfirmTransaction(tx)
}
@@ -962,9 +963,7 @@ func (self *XEth) SignTransaction(fromStr, toStr, nonceStr, valueStr, gasStr, ga
func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
- // this minimalistic recoding is enough (works for natspec.js)
- var jsontx = fmt.Sprintf(`{"params":[{"to":"%s","data": "%s"}]}`, toStr, codeStr)
- if !self.ConfirmTransaction(jsontx) {
+ if !self.ConfirmTransaction(toStr, codeStr) {
err := fmt.Errorf("Transaction not confirmed")
return "", err
}