mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
Merge aab01f8067 into 6e6931ef73
This commit is contained in:
commit
9a1a25531e
30 changed files with 414 additions and 301 deletions
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
15
eth/api.go
15
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
139
node/http.go
Normal file
139
node/http.go
Normal file
|
|
@ -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)
|
||||
// }
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
10
node/node.go
10
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue