continue merging 1

Merge continue 2

Fake commit to restart the build servers

Fake commit to hopefully fix the PPA issue.

update versionOracle address for expanse

Merge continue 3

Merge continue 4

cleaned up a few Eth stragglers

Merge continue 5

Not sure why the merge tool changed this file and removed that but it
did.

merge continue 6

fixing expanse.js

Again not sure why this one got edited from the last one but -shrug-

fixing rpc calls for eth_ for compatibility

rpc calls still acting crazy

more rpc fixes

make jsre console accept both exp and eth cmds

rpc fixes continued

adding eth api calls

rpc and js-console both have eth calls on by default now
This commit is contained in:
Christopher Franko 2016-05-17 19:24:19 -04:00
parent 87272925b9
commit 61796668c8
89 changed files with 177 additions and 12161 deletions

View file

@ -81,3 +81,5 @@ included in our repository in the `COPYING.LESSER` file.
The go-expanse binaries (i.e. all code inside of the `cmd` directory) is licensed under the The go-expanse binaries (i.e. all code inside of the `cmd` directory) is licensed under the
[GNU General Public License v3.0](http://www.gnu.org/licenses/gpl-3.0.en.html), also included [GNU General Public License v3.0](http://www.gnu.org/licenses/gpl-3.0.en.html), also included
in our repository in the `COPYING` file. in our repository in the `COPYING` file.

View file

@ -24,7 +24,7 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/ethereum/go-expanse/common" "github.com/expanse-project/go-expanse/common"
) )

View file

@ -127,7 +127,7 @@ func (b *rpcBackend) ContractCall(contract common.Address, data []byte, pending
if pending { if pending {
block = "pending" block = "pending"
} }
res, err := b.request("eth_call", []interface{}{args, block}) res, err := b.request("exp_call", []interface{}{args, block})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -142,7 +142,7 @@ func (b *rpcBackend) ContractCall(contract common.Address, data []byte, pending
// PendingAccountNonce implements ContractTransactor.PendingAccountNonce, delegating // PendingAccountNonce implements ContractTransactor.PendingAccountNonce, delegating
// the current account nonce retrieval to the remote node. // the current account nonce retrieval to the remote node.
func (b *rpcBackend) PendingAccountNonce(account common.Address) (uint64, error) { func (b *rpcBackend) PendingAccountNonce(account common.Address) (uint64, error) {
res, err := b.request("eth_getTransactionCount", []interface{}{account.Hex(), "pending"}) res, err := b.request("exp_getTransactionCount", []interface{}{account.Hex(), "pending"})
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -160,7 +160,7 @@ func (b *rpcBackend) PendingAccountNonce(account common.Address) (uint64, error)
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice, delegating the // SuggestGasPrice implements ContractTransactor.SuggestGasPrice, delegating the
// gas price oracle request to the remote node. // gas price oracle request to the remote node.
func (b *rpcBackend) SuggestGasPrice() (*big.Int, error) { func (b *rpcBackend) SuggestGasPrice() (*big.Int, error) {
res, err := b.request("eth_gasPrice", nil) res, err := b.request("exp_gasPrice", nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -191,7 +191,7 @@ func (b *rpcBackend) EstimateGasLimit(sender common.Address, contract *common.Ad
Value: rpc.NewHexNumber(value), Value: rpc.NewHexNumber(value),
} }
// Execute the RPC call and retrieve the response // Execute the RPC call and retrieve the response
res, err := b.request("eth_estimateGas", []interface{}{args}) res, err := b.request("exp_estimateGas", []interface{}{args})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -213,7 +213,7 @@ func (b *rpcBackend) SendTransaction(tx *types.Transaction) error {
if err != nil { if err != nil {
return err return err
} }
res, err := b.request("eth_sendRawTransaction", []interface{}{common.ToHex(data)}) res, err := b.request("exp_sendRawTransaction", []interface{}{common.ToHex(data)})
if err != nil { if err != nil {
return err return err
} }

View file

@ -1,139 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of go-expanse.
//
// go-expanse is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-expanse 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-expanse. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"fmt"
"os"
"github.com/codegangsta/cli"
"github.com/expanse-project/go-expanse/cmd/utils"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/ethdb"
"github.com/expanse-project/go-expanse/tests"
)
var blocktestCommand = cli.Command{
Action: runBlockTest,
Name: "blocktest",
Usage: `loads a block test file`,
Description: `
The first argument should be a block test file.
The second argument is the name of a block test from the file.
The block test will be loaded into an in-memory database.
If loading succeeds, the RPC server is started. Clients will
be able to interact with the chain defined by the test.
`,
}
func runBlockTest(ctx *cli.Context) {
var (
file, testname string
rpc bool
)
args := ctx.Args()
switch {
case len(args) == 1:
file = args[0]
case len(args) == 2:
file, testname = args[0], args[1]
case len(args) == 3:
file, testname = args[0], args[1]
rpc = true
default:
utils.Fatalf(`Usage: expanse blocktest <path-to-test-file> [ <test-name> [ "rpc" ] ]`)
}
bt, err := tests.LoadBlockTests(file)
if err != nil {
utils.Fatalf("%v", err)
}
// run all tests if no test name is specified
if testname == "" {
ecode := 0
for name, test := range bt {
fmt.Printf("----------------- Running Block Test %q\n", name)
expanse, err := runOneBlockTest(ctx, test)
if err != nil {
fmt.Println(err)
fmt.Println("FAIL")
ecode = 1
}
if expanse != nil {
expanse.Stop()
expanse.WaitForShutdown()
}
}
os.Exit(ecode)
return
}
// otherwise, run the given test
test, ok := bt[testname]
if !ok {
utils.Fatalf("Test file does not contain test named %q", testname)
}
expanse, err := runOneBlockTest(ctx, test)
if err != nil {
utils.Fatalf("%v", err)
}
if rpc {
fmt.Println("Block Test post state validated, starting RPC interface.")
startExp(ctx, expanse)
utils.StartRPC(expanse, ctx)
expanse.WaitForShutdown()
}
}
func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*exp.Expanse, error) {
cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
db, _ := ethdb.NewMemDatabase()
cfg.NewDB = func(path string) (ethdb.Database, error) { return db, nil }
cfg.MaxPeers = 0 // disable network
cfg.Shh = false // disable whisper
cfg.NAT = nil // disable port mapping
expanse, err := exp.New(cfg)
if err != nil {
return nil, err
}
// import the genesis block
expanse.ResetWithGenesisBlock(test.Genesis)
// import pre accounts
_, err = test.InsertPreState(db, cfg.AccountManager)
if err != nil {
return expanse, fmt.Errorf("InsertPreState: %v", err)
}
cm := expanse.BlockChain()
validBlocks, err := test.TryBlocksInsert(cm)
if err != nil {
return expanse, fmt.Errorf("Block Test load error: %v", err)
}
newDB, err := cm.State()
if err != nil {
return expanse, fmt.Errorf("Block Test get state error: %v", err)
}
if err := test.ValidatePostState(newDB); err != nil {
return expanse, fmt.Errorf("post state validation failed: %v", err)
}
return expanse, test.ValidateImportedHeaders(cm, validBlocks)
}

View file

@ -32,7 +32,7 @@ import (
"github.com/expanse-project/go-expanse/cmd/utils" "github.com/expanse-project/go-expanse/cmd/utils"
"github.com/expanse-project/go-expanse/common" "github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/common/registrar" "github.com/expanse-project/go-expanse/common/registrar"
"github.com/expanse-project/go-expanse/eth" "github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/internal/web3ext" "github.com/expanse-project/go-expanse/internal/web3ext"
re "github.com/expanse-project/go-expanse/jsre" re "github.com/expanse-project/go-expanse/jsre"
"github.com/expanse-project/go-expanse/node" "github.com/expanse-project/go-expanse/node"
@ -174,8 +174,8 @@ func (js *jsre) apiBindings() error {
t, _ := js.re.Get("jeth") t, _ := js.re.Get("jeth")
jethObj := t.Object() jethObj := t.Object()
jethObj.Set("send", jexp.Send) jethObj.Set("send", jeth.Send)
jethObj.Set("sendAsync", jexp.Send) jethObj.Set("sendAsync", jeth.Send)
err = js.re.Compile("bignumber.js", re.BigNumber_JS) err = js.re.Compile("bignumber.js", re.BigNumber_JS)
if err != nil { if err != nil {
@ -228,21 +228,21 @@ func (js *jsre) apiBindings() error {
} }
// Override the unlockAccount and newAccount methods on the personal object since these require user interaction. // Override the unlockAccount and newAccount methods on the personal object since these require user interaction.
// Assign the jexp.unlockAccount and jexp.newAccount in the jsre the original web3 callbacks. These will be called // Assign the jeth.unlockAccount and jeth.newAccount in the jsre the original web3 callbacks. These will be called
// by the jexp.* methods after they got the password from the user and send the original web3 request to the backend. // by the jeth.* methods after they got the password from the user and send the original web3 request to the backend.
if persObj := p.Object(); persObj != nil { // make sure the personal api is enabled over the interface if persObj := p.Object(); persObj != nil { // make sure the personal api is enabled over the interface
js.re.Run(`jexp.unlockAccount = personal.unlockAccount;`) js.re.Run(`jeth.unlockAccount = personal.unlockAccount;`)
persObj.Set("unlockAccount", jexp.UnlockAccount) persObj.Set("unlockAccount", jeth.UnlockAccount)
js.re.Run(`jexp.newAccount = personal.newAccount;`) js.re.Run(`jeth.newAccount = personal.newAccount;`)
persObj.Set("newAccount", jexp.NewAccount) persObj.Set("newAccount", jeth.NewAccount)
} }
// The admin.sleep and admin.sleepBlocks are offered by the console and not by the RPC layer. // The admin.sleep and admin.sleepBlocks are offered by the console and not by the RPC layer.
// Bind these if the admin module is available. // Bind these if the admin module is available.
if a, err := js.re.Get("admin"); err == nil { if a, err := js.re.Get("admin"); err == nil {
if adminObj := a.Object(); adminObj != nil { if adminObj := a.Object(); adminObj != nil {
adminObj.Set("sleepBlocks", jexp.SleepBlocks) adminObj.Set("sleepBlocks", jeth.SleepBlocks)
adminObj.Set("sleep", jexp.Sleep) adminObj.Set("sleep", jeth.Sleep)
} }
} }

View file

@ -30,11 +30,11 @@ import (
"time" "time"
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
"github.com/expanse-org/ethash" "github.com/expanse-project/ethash"
"github.com/expanse-project/go-expanse/cmd/utils" "github.com/expanse-project/go-expanse/cmd/utils"
"github.com/expanse-project/go-expanse/common" "github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/core" "github.com/expanse-project/go-expanse/core"
"github.com/expanse-project/go-expanse/eth" "github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/ethdb" "github.com/expanse-project/go-expanse/ethdb"
"github.com/expanse-project/go-expanse/internal/debug" "github.com/expanse-project/go-expanse/internal/debug"
"github.com/expanse-project/go-expanse/logger" "github.com/expanse-project/go-expanse/logger"
@ -52,7 +52,7 @@ const (
versionMinor = 4 // Minor version component of the current release versionMinor = 4 // Minor version component of the current release
versionPatch = 4 // Patch version component of the current release versionPatch = 4 // Patch version component of the current release
versionMeta = "stable" // Version metadata to append to the version string versionMeta = "stable" // Version metadata to append to the version string
versionOracle = "0xfa7b9770ca4cb04296cac84f37736d4041251cdf" // Expanse address of the Gexp release oracle versionOracle = "0x926d69cc3bbf81d52cba6886d788df007a15a3cd" // Expanse address of the Gexp release oracle
) )
var ( var (

View file

@ -21,13 +21,14 @@ import "github.com/expanse-project/go-expanse/p2p/discover"
// FrontierBootNodes are the enode URLs of the P2P bootstrap nodes running on // FrontierBootNodes are the enode URLs of the P2P bootstrap nodes running on
// the Frontier network. // the Frontier network.
var FrontierBootNodes = []*discover.Node{ var FrontierBootNodes = []*discover.Node{
// ETH/DEV Go Bootnodes // EXP/DEV Go Bootnodes
discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE discover.MustParseNode("enode://7f335a047654f3e70d6f91312a7cf89c39704011f1a584e2698250db3d63817e74b88e26b7854111e16b2c9d0c7173c05419aeee2d0321850227b126d8b1be3f@46.101.156.249:42786"),
discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"), // BR discover.MustParseNode("enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786"),
discover.MustParseNode("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"), // SG discover.MustParseNode("enode://96d3919b903e7f5ad59ac2f73c43be9172d9d27e2771355db03fd194732b795829a31fe2ea6de109d0804786c39a807e155f065b4b94c6fce167becd0ac02383@45.55.22.34:42786"),
discover.MustParseNode("enode://5f6c625bf287e3c08aad568de42d868781e961cbda805c8397cfb7be97e229419bef9a5a25a75f97632787106bba8a7caf9060fab3887ad2cfbeb182ab0f433f@46.101.182.53:42786"),
// ETH/DEV Cpp Bootnodes discover.MustParseNode("enode://d33a8d4c2c38a08971ed975b750f21d54c927c0bf7415931e214465a8d01651ecffe4401e1db913f398383381413c78105656d665d83f385244ab302d6138414@128.199.183.48:42786"),
discover.MustParseNode("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"), discover.MustParseNode("enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786"),
discover.MustParseNode("enode://f6f0d6b9b7d02ec9e8e4a16e38675f3621ea5e69860c739a65c1597ca28aefb3cec7a6d84e471ac927d42a1b64c1cbdefad75e7ce8872d57548ddcece20afdd1@159.203.64.95:42786"),
} }
// TestNetBootNodes are the enode URLs of the P2P bootstrap nodes running on the // TestNetBootNodes are the enode URLs of the P2P bootstrap nodes running on the

View file

@ -31,13 +31,13 @@ import (
"time" "time"
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
"github.com/ethereum/ethash" "github.com/expanse-project/ethash"
"github.com/expanse-project/go-expanse/accounts" "github.com/expanse-project/go-expanse/accounts"
"github.com/expanse-project/go-expanse/common" "github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/core" "github.com/expanse-project/go-expanse/core"
"github.com/expanse-project/go-expanse/core/state" "github.com/expanse-project/go-expanse/core/state"
"github.com/expanse-project/go-expanse/crypto" "github.com/expanse-project/go-expanse/crypto"
"github.com/expanse-project/go-expanse/eth" "github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/ethdb" "github.com/expanse-project/go-expanse/ethdb"
"github.com/expanse-project/go-expanse/event" "github.com/expanse-project/go-expanse/event"
"github.com/expanse-project/go-expanse/logger" "github.com/expanse-project/go-expanse/logger"

View file

@ -24,9 +24,9 @@ import (
const ( const (
DefaultIPCSocket = "gexp.ipc" // Default (relative) name of the IPC RPC socket DefaultIPCSocket = "gexp.ipc" // Default (relative) name of the IPC RPC socket
DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server
DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server DefaultHTTPPort = 9659 // Default TCP port for the HTTP RPC server
DefaultWSHost = "localhost" // Default host interface for the websocket RPC server DefaultWSHost = "localhost" // Default host interface for the websocket RPC server
DefaultWSPort = 8546 // Default TCP port for the websocket RPC server DefaultWSPort = 9656 // Default TCP port for the websocket RPC server
) )
// DefaultDataDir is the default data directory to use for the databases and other // DefaultDataDir is the default data directory to use for the databases and other
@ -36,11 +36,11 @@ func DefaultDataDir() string {
home := HomeDir() home := HomeDir()
if home != "" { if home != "" {
if runtime.GOOS == "darwin" { if runtime.GOOS == "darwin" {
return filepath.Join(home, "Library", "Ethereum") return filepath.Join(home, "Library", "Expanse")
} else if runtime.GOOS == "windows" { } else if runtime.GOOS == "windows" {
return filepath.Join(home, "AppData", "Roaming", "Ethereum") return filepath.Join(home, "AppData", "Roaming", "Expanse")
} else { } else {
return filepath.Join(home, ".ethereum") return filepath.Join(home, ".expanse")
} }
} }
// As we cannot guess a stable location, return empty and handle later // As we cannot guess a stable location, return empty and handle later

View file

@ -1,292 +0,0 @@
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package common
import (
"bytes"
"fmt"
"math/big"
"reflect"
)
type RlpEncode interface {
RlpEncode() []byte
}
type RlpEncodeDecode interface {
RlpEncode
RlpValue() []interface{}
}
type RlpEncodable interface {
RlpData() interface{}
}
func Rlp(encoder RlpEncode) []byte {
return encoder.RlpEncode()
}
type RlpEncoder struct {
rlpData []byte
}
func NewRlpEncoder() *RlpEncoder {
encoder := &RlpEncoder{}
return encoder
}
func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte {
return Encode(rlpData)
}
const (
RlpEmptyList = 0x80
RlpEmptyStr = 0x40
)
const rlpEof = -1
func Char(c []byte) int {
if len(c) > 0 {
return int(c[0])
}
return rlpEof
}
func DecodeWithReader(reader *bytes.Buffer) interface{} {
var slice []interface{}
// Read the next byte
char := Char(reader.Next(1))
switch {
case char <= 0x7f:
return char
case char <= 0xb7:
return reader.Next(int(char - 0x80))
case char <= 0xbf:
length := ReadVarInt(reader.Next(int(char - 0xb7)))
return reader.Next(int(length))
case char <= 0xf7:
length := int(char - 0xc0)
for i := 0; i < length; i++ {
obj := DecodeWithReader(reader)
slice = append(slice, obj)
}
return slice
case char <= 0xff:
length := ReadVarInt(reader.Next(int(char - 0xf7)))
for i := uint64(0); i < length; i++ {
obj := DecodeWithReader(reader)
slice = append(slice, obj)
}
return slice
default:
panic(fmt.Sprintf("byte not supported: %q", char))
}
return slice
}
var (
directRlp = big.NewInt(0x7f)
numberRlp = big.NewInt(0xb7)
zeroRlp = big.NewInt(0x0)
)
func intlen(i int64) (length int) {
for i > 0 {
i = i >> 8
length++
}
return
}
func Encode(object interface{}) []byte {
var buff bytes.Buffer
if object != nil {
switch t := object.(type) {
case *Value:
buff.Write(Encode(t.Val))
case RlpEncodable:
buff.Write(Encode(t.RlpData()))
// Code dup :-/
case int:
buff.Write(Encode(big.NewInt(int64(t))))
case uint:
buff.Write(Encode(big.NewInt(int64(t))))
case int8:
buff.Write(Encode(big.NewInt(int64(t))))
case int16:
buff.Write(Encode(big.NewInt(int64(t))))
case int32:
buff.Write(Encode(big.NewInt(int64(t))))
case int64:
buff.Write(Encode(big.NewInt(t)))
case uint16:
buff.Write(Encode(big.NewInt(int64(t))))
case uint32:
buff.Write(Encode(big.NewInt(int64(t))))
case uint64:
buff.Write(Encode(big.NewInt(int64(t))))
case byte:
buff.Write(Encode(big.NewInt(int64(t))))
case *big.Int:
// Not sure how this is possible while we check for nil
if t == nil {
buff.WriteByte(0xc0)
} else {
buff.Write(Encode(t.Bytes()))
}
case Bytes:
buff.Write(Encode([]byte(t)))
case []byte:
if len(t) == 1 && t[0] <= 0x7f {
buff.Write(t)
} else if len(t) < 56 {
buff.WriteByte(byte(len(t) + 0x80))
buff.Write(t)
} else {
b := big.NewInt(int64(len(t)))
buff.WriteByte(byte(len(b.Bytes()) + 0xb7))
buff.Write(b.Bytes())
buff.Write(t)
}
case string:
buff.Write(Encode([]byte(t)))
case []interface{}:
// Inline function for writing the slice header
WriteSliceHeader := func(length int) {
if length < 56 {
buff.WriteByte(byte(length + 0xc0))
} else {
b := big.NewInt(int64(length))
buff.WriteByte(byte(len(b.Bytes()) + 0xf7))
buff.Write(b.Bytes())
}
}
var b bytes.Buffer
for _, val := range t {
b.Write(Encode(val))
}
WriteSliceHeader(len(b.Bytes()))
buff.Write(b.Bytes())
default:
// This is how it should have been from the start
// needs refactoring (@fjl)
v := reflect.ValueOf(t)
switch v.Kind() {
case reflect.Slice:
var b bytes.Buffer
for i := 0; i < v.Len(); i++ {
b.Write(Encode(v.Index(i).Interface()))
}
blen := b.Len()
if blen < 56 {
buff.WriteByte(byte(blen) + 0xc0)
} else {
ilen := byte(intlen(int64(blen)))
buff.WriteByte(ilen + 0xf7)
t := make([]byte, ilen)
for i := byte(0); i < ilen; i++ {
t[ilen-i-1] = byte(blen >> (i * 8))
}
buff.Write(t)
}
buff.ReadFrom(&b)
}
}
} else {
// Empty list for nil
buff.WriteByte(0xc0)
}
return buff.Bytes()
}
// TODO Use a bytes.Buffer instead of a raw byte slice.
// Cleaner code, and use draining instead of seeking the next bytes to read
func Decode(data []byte, pos uint64) (interface{}, uint64) {
var slice []interface{}
char := int(data[pos])
switch {
case char <= 0x7f:
return data[pos], pos + 1
case char <= 0xb7:
b := uint64(data[pos]) - 0x80
return data[pos+1 : pos+1+b], pos + 1 + b
case char <= 0xbf:
b := uint64(data[pos]) - 0xb7
b2 := ReadVarInt(data[pos+1 : pos+1+b])
return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2
case char <= 0xf7:
b := uint64(data[pos]) - 0xc0
prevPos := pos
pos++
for i := uint64(0); i < b; {
var obj interface{}
// Get the next item in the data list and append it
obj, prevPos = Decode(data, pos)
slice = append(slice, obj)
// Increment i by the amount bytes read in the previous
// read
i += (prevPos - pos)
pos = prevPos
}
return slice, pos
case char <= 0xff:
l := uint64(data[pos]) - 0xf7
b := ReadVarInt(data[pos+1 : pos+1+l])
pos = pos + l + 1
prevPos := b
for i := uint64(0); i < uint64(b); {
var obj interface{}
obj, prevPos = Decode(data, pos)
slice = append(slice, obj)
i += (prevPos - pos)
pos = prevPos
}
return slice, pos
default:
panic(fmt.Sprintf("byte not supported: %q", char))
}
return slice, 0
}

View file

@ -295,8 +295,6 @@ func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff *
x.Set(params.MinimumDifficulty) x.Set(params.MinimumDifficulty)
} }
}
return x return x
} }

View file

@ -47,5 +47,5 @@ func Canary(statedb *state.StateDB) bool {
if (statedb.GetState(vitalik, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) { if (statedb.GetState(vitalik, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) {
r++ r++
} }
return r > 1 return r > 10
} }

View file

@ -32,10 +32,6 @@ var (
Big0 = big.NewInt(0) Big0 = big.NewInt(0)
) )
var (
Big0 = big.NewInt(0)
)
/* /*
The State Transitioning Model The State Transitioning Model

View file

@ -30,7 +30,6 @@ import (
"github.com/expanse-project/go-expanse/event" "github.com/expanse-project/go-expanse/event"
"github.com/expanse-project/go-expanse/logger" "github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog" "github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/params"
) )
var ( var (

View file

@ -168,7 +168,7 @@ func (tx *Transaction) Size() common.StorageSize {
// Frontier / Homestead. however, the first time called it runs // Frontier / Homestead. however, the first time called it runs
// signature validations, so we need two versions. This makes it // signature validations, so we need two versions. This makes it
// easier to ensure backwards compatibility of things like package rpc // easier to ensure backwards compatibility of things like package rpc
// where eth_getblockbynumber uses tx.From() and needs to work for // where exp_getblockbynumber uses tx.From() and needs to work for
// both txs before and after the first homestead block. Signatures // both txs before and after the first homestead block. Signatures
// valid in homestead are a subset of valid ones in Frontier) // valid in homestead are a subset of valid ones in Frontier)
func (tx *Transaction) From() (common.Address, error) { func (tx *Transaction) From() (common.Address, error) {
@ -186,7 +186,7 @@ func (tx *Transaction) From() (common.Address, error) {
// Frontier / Homestead. however, the first time called it runs // Frontier / Homestead. however, the first time called it runs
// signature validations, so we need two versions. This makes it // signature validations, so we need two versions. This makes it
// easier to ensure backwards compatibility of things like package rpc // easier to ensure backwards compatibility of things like package rpc
// where eth_getblockbynumber uses tx.From() and needs to work for // where exp_getblockbynumber uses tx.From() and needs to work for
// both txs before and after the first homestead block. Signatures // both txs before and after the first homestead block. Signatures
// valid in homestead are a subset of valid ones in Frontier) // valid in homestead are a subset of valid ones in Frontier)
func (tx *Transaction) FromFrontier() (common.Address, error) { func (tx *Transaction) FromFrontier() (common.Address, error) {

View file

@ -16,11 +16,7 @@
package vm package vm
import ( import "math/big"
"math/big"
"github.com/expanse-project/go-expanse/params"
)
type jumpPtr struct { type jumpPtr struct {
fn instrFn fn instrFn

View file

@ -1,211 +0,0 @@
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package crypto
import (
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"time"
"github.com/expanse-project/go-expanse/common"
)
type KeyStore interface {
// create new key using io.Reader entropy source and optionally using auth string
GenerateNewKey(io.Reader, string) (*Key, error)
GetKey(common.Address, string) (*Key, error) // get key from addr and auth string
GetKeyAddresses() ([]common.Address, error) // get all addresses
StoreKey(*Key, string) error // store key optionally using auth string
DeleteKey(common.Address, string) error // delete key by addr and auth string
Cleanup(keyAddr common.Address) (err error)
}
type keyStorePlain struct {
keysDirPath string
}
func NewKeyStorePlain(path string) KeyStore {
return &keyStorePlain{path}
}
func (ks keyStorePlain) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
return GenerateNewKeyDefault(ks, rand, auth)
}
func GenerateNewKeyDefault(ks KeyStore, rand io.Reader, auth string) (key *Key, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("GenerateNewKey error: %v", r)
}
}()
key = NewKey(rand)
err = ks.StoreKey(key, auth)
return key, err
}
func (ks keyStorePlain) GetKey(keyAddr common.Address, auth string) (key *Key, err error) {
key = new(Key)
err = getKey(ks.keysDirPath, keyAddr, key)
return
}
func getKey(keysDirPath string, keyAddr common.Address, content interface{}) (err error) {
fileContent, err := getKeyFile(keysDirPath, keyAddr)
if err != nil {
return
}
return json.Unmarshal(fileContent, content)
}
func (ks keyStorePlain) GetKeyAddresses() (addresses []common.Address, err error) {
return getKeyAddresses(ks.keysDirPath)
}
func (ks keyStorePlain) Cleanup(keyAddr common.Address) (err error) {
return cleanup(ks.keysDirPath, keyAddr)
}
func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) {
keyJSON, err := json.Marshal(key)
if err != nil {
return
}
err = writeKeyFile(key.Address, ks.keysDirPath, keyJSON)
return
}
func (ks keyStorePlain) DeleteKey(keyAddr common.Address, auth string) (err error) {
return deleteKey(ks.keysDirPath, keyAddr)
}
func deleteKey(keysDirPath string, keyAddr common.Address) (err error) {
var path string
path, err = getKeyFilePath(keysDirPath, keyAddr)
if err == nil {
addrHex := hex.EncodeToString(keyAddr[:])
if path == filepath.Join(keysDirPath, addrHex, addrHex) {
path = filepath.Join(keysDirPath, addrHex)
}
err = os.RemoveAll(path)
}
return
}
func getKeyFilePath(keysDirPath string, keyAddr common.Address) (keyFilePath string, err error) {
addrHex := hex.EncodeToString(keyAddr[:])
matches, err := filepath.Glob(filepath.Join(keysDirPath, fmt.Sprintf("*--%s", addrHex)))
if len(matches) > 0 {
if err == nil {
keyFilePath = matches[len(matches)-1]
}
return
}
keyFilePath = filepath.Join(keysDirPath, addrHex, addrHex)
_, err = os.Stat(keyFilePath)
return
}
func cleanup(keysDirPath string, keyAddr common.Address) (err error) {
fileInfos, err := ioutil.ReadDir(keysDirPath)
if err != nil {
return
}
var paths []string
account := hex.EncodeToString(keyAddr[:])
for _, fileInfo := range fileInfos {
path := filepath.Join(keysDirPath, fileInfo.Name())
if len(path) >= 40 {
addr := path[len(path)-40 : len(path)]
if addr == account {
if path == filepath.Join(keysDirPath, addr, addr) {
path = filepath.Join(keysDirPath, addr)
}
paths = append(paths, path)
}
}
}
if len(paths) > 1 {
for i := 0; err == nil && i < len(paths)-1; i++ {
err = os.RemoveAll(paths[i])
if err != nil {
break
}
}
}
return
}
func getKeyFile(keysDirPath string, keyAddr common.Address) (fileContent []byte, err error) {
var keyFilePath string
keyFilePath, err = getKeyFilePath(keysDirPath, keyAddr)
if err == nil {
fileContent, err = ioutil.ReadFile(keyFilePath)
}
return
}
func writeKeyFile(addr common.Address, keysDirPath string, content []byte) (err error) {
filename := keyFileName(addr)
// read, write and dir search for user
err = os.MkdirAll(keysDirPath, 0700)
if err != nil {
return err
}
// read, write for user
return ioutil.WriteFile(filepath.Join(keysDirPath, filename), content, 0600)
}
// keyFilePath implements the naming convention for keyfiles:
// UTC--<created_at UTC ISO8601>-<address hex>
func keyFileName(keyAddr common.Address) string {
ts := time.Now().UTC()
return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:]))
}
func toISO8601(t time.Time) string {
var tz string
name, offset := t.Zone()
if name == "UTC" {
tz = "Z"
} else {
tz = fmt.Sprintf("%03d00", offset/3600)
}
return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz)
}
func getKeyAddresses(keysDirPath string) (addresses []common.Address, err error) {
fileInfos, err := ioutil.ReadDir(keysDirPath)
if err != nil {
return nil, err
}
for _, fileInfo := range fileInfos {
filename := fileInfo.Name()
if len(filename) >= 40 {
addr := filename[len(filename)-40 : len(filename)]
address, err := hex.DecodeString(addr)
if err == nil {
addresses = append(addresses, common.BytesToAddress(address))
}
}
}
return addresses, err
}

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package eth package exp
import ( import (
"bytes" "bytes"
@ -31,7 +31,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/ethereum/ethash" "github.com/expanse-project/ethash"
"github.com/expanse-project/go-expanse/accounts" "github.com/expanse-project/go-expanse/accounts"
"github.com/expanse-project/go-expanse/common" "github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/common/compiler" "github.com/expanse-project/go-expanse/common/compiler"
@ -1437,7 +1437,7 @@ func (s *PublicTransactionPoolAPI) Resend(tx Tx, gasPrice, gasLimit *rpc.HexNumb
// PrivateAdminAPI is the collection of Etheruem APIs exposed over the private // PrivateAdminAPI is the collection of Etheruem APIs exposed over the private
// admin endpoint. // admin endpoint.
type PrivateAdminAPI struct { type PrivateAdminAPI struct {
eth *Expanse exp *Expanse
} }
// NewPrivateAdminAPI creates a new API definition for the private admin methods // NewPrivateAdminAPI creates a new API definition for the private admin methods
@ -1526,7 +1526,7 @@ func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) {
// PublicDebugAPI is the collection of Etheruem APIs exposed over the public // PublicDebugAPI is the collection of Etheruem APIs exposed over the public
// debugging endpoint. // debugging endpoint.
type PublicDebugAPI struct { type PublicDebugAPI struct {
eth *Expanse exp *Expanse
} }
// NewPublicDebugAPI creates a new API definition for the public debug methods // NewPublicDebugAPI creates a new API definition for the public debug methods
@ -1587,12 +1587,12 @@ func (api *PublicDebugAPI) SeedHash(number uint64) (string, error) {
// debugging endpoint. // debugging endpoint.
type PrivateDebugAPI struct { type PrivateDebugAPI struct {
config *core.ChainConfig config *core.ChainConfig
eth *Expanse exp *Expanse
} }
// NewPrivateDebugAPI creates a new API definition for the private debug methods // NewPrivateDebugAPI creates a new API definition for the private debug methods
// of the Expanse service. // of the Expanse service.
func NewPrivateDebugAPI(config *core.ChainConfig, eth *Expanse) *PrivateDebugAPI { func NewPrivateDebugAPI(config *core.ChainConfig, exp *Expanse) *PrivateDebugAPI {
return &PrivateDebugAPI{config: config, exp: exp} return &PrivateDebugAPI{config: config, exp: exp}
} }

View file

@ -28,7 +28,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/ethereum/ethash" "github.com/expanse-project/ethash"
"github.com/expanse-project/go-expanse/accounts" "github.com/expanse-project/go-expanse/accounts"
"github.com/expanse-project/go-expanse/common" "github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/common/compiler" "github.com/expanse-project/go-expanse/common/compiler"
@ -37,8 +37,8 @@ import (
"github.com/expanse-project/go-expanse/core" "github.com/expanse-project/go-expanse/core"
"github.com/expanse-project/go-expanse/core/types" "github.com/expanse-project/go-expanse/core/types"
"github.com/expanse-project/go-expanse/core/vm" "github.com/expanse-project/go-expanse/core/vm"
"github.com/expanse-project/go-expanse/eth/downloader" "github.com/expanse-project/go-expanse/exp/downloader"
"github.com/expanse-project/go-expanse/eth/filters" "github.com/expanse-project/go-expanse/exp/filters"
"github.com/expanse-project/go-expanse/ethdb" "github.com/expanse-project/go-expanse/ethdb"
"github.com/expanse-project/go-expanse/event" "github.com/expanse-project/go-expanse/event"
"github.com/expanse-project/go-expanse/logger" "github.com/expanse-project/go-expanse/logger"
@ -151,7 +151,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Expanse, error) {
return nil, err return nil, err
} }
if db, ok := chainDb.(*ethdb.LDBDatabase); ok { if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
db.Meter("eth/db/chaindata/") db.Meter("exp/db/chaindata/")
} }
if err := upgradeChainDatabase(chainDb); err != nil { if err := upgradeChainDatabase(chainDb); err != nil {
return nil, err return nil, err
@ -165,7 +165,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Expanse, error) {
return nil, err return nil, err
} }
if db, ok := dappDb.(*ethdb.LDBDatabase); ok { if db, ok := dappDb.(*ethdb.LDBDatabase); ok {
db.Meter("eth/db/dapp/") db.Meter("exp/db/dapp/")
} }
glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId) glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId)
@ -261,7 +261,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Expanse, error) {
} }
return nil, err return nil, err
} }
exp.gpo = NewGasPriceOracle(eth) exp.gpo = NewGasPriceOracle(exp)
newPool := core.NewTxPool(exp.chainConfig, exp.EventMux(), exp.blockchain.State, exp.blockchain.GasLimit) newPool := core.NewTxPool(exp.chainConfig, exp.EventMux(), exp.blockchain.State, exp.blockchain.GasLimit)
exp.txPool = newPool exp.txPool = newPool
@ -269,7 +269,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Expanse, error) {
if exp.protocolManager, err = NewProtocolManager(exp.chainConfig, config.FastSync, config.NetworkId, exp.eventMux, exp.txPool, exp.pow, exp.blockchain, chainDb); err != nil { if exp.protocolManager, err = NewProtocolManager(exp.chainConfig, config.FastSync, config.NetworkId, exp.eventMux, exp.txPool, exp.pow, exp.blockchain, chainDb); err != nil {
return nil, err return nil, err
} }
exp.miner = miner.New(eth, exp.chainConfig, exp.EventMux(), exp.pow) exp.miner = miner.New(exp, exp.chainConfig, exp.EventMux(), exp.pow)
exp.miner.SetGasPrice(config.GasPrice) exp.miner.SetGasPrice(config.GasPrice)
exp.miner.SetExtra(config.ExtraData) exp.miner.SetExtra(config.ExtraData)
@ -352,9 +352,43 @@ func (s *Expanse) APIs() []rpc.API {
Namespace: "admin", Namespace: "admin",
Version: "1.0", Version: "1.0",
Service: ethreg.NewPrivateRegistarAPI(s.chainConfig, s.blockchain, s.chainDb, s.txPool, s.accountManager), Service: ethreg.NewPrivateRegistarAPI(s.chainConfig, s.blockchain, s.chainDb, s.txPool, s.accountManager),
}, {
Namespace: "eth",
Version: "1.0",
Service: NewPublicEthereumAPI(s),
Public: true,
}, {
Namespace: "eth",
Version: "1.0",
Service: NewPublicAccountAPI(s.accountManager),
Public: true,
}, {
Namespace: "eth",
Version: "1.0",
Service: NewPublicBlockChainAPI(s.chainConfig, s.blockchain, s.miner, s.chainDb, s.gpo, s.eventMux, s.accountManager),
Public: true,
}, {
Namespace: "eth",
Version: "1.0",
Service: NewPublicTransactionPoolAPI(s),
Public: true,
}, {
Namespace: "eth",
Version: "1.0",
Service: NewPublicMinerAPI(s),
Public: true,
}, {
Namespace: "eth",
Version: "1.0",
Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux),
Public: true,
}, {
Namespace: "eth",
Version: "1.0",
Service: filters.NewPublicFilterAPI(s.chainDb, s.eventMux),
Public: true,
}, },
} }
>>>>>>> ethereum/master:eth/backend.go
} }
func (s *Expanse) ResetWithGenesisBlock(gb *types.Block) { func (s *Expanse) ResetWithGenesisBlock(gb *types.Block) {

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package eth package exp
import ( import (
"math/big" "math/big"
@ -43,9 +43,9 @@ type ContractBackend struct {
// Etheruem object. // Etheruem object.
func NewContractBackend(exp *Expanse) *ContractBackend { func NewContractBackend(exp *Expanse) *ContractBackend {
return &ContractBackend{ return &ContractBackend{
eapi: NewPublicEthereumAPI(eth), eapi: NewPublicEthereumAPI(exp),
bcapi: NewPublicBlockChainAPI(exp.chainConfig, exp.blockchain, exp.miner, exp.chainDb, exp.gpo, exp.eventMux, exp.accountManager), bcapi: NewPublicBlockChainAPI(exp.chainConfig, exp.blockchain, exp.miner, exp.chainDb, exp.gpo, exp.eventMux, exp.accountManager),
txapi: NewPublicTransactionPoolAPI(eth), txapi: NewPublicTransactionPoolAPI(exp),
} }
} }

View file

@ -192,36 +192,36 @@ web3._extend({
const Eth_JS = ` const Eth_JS = `
web3._extend({ web3._extend({
property: 'eth', property: 'exp',
methods: methods:
[ [
new web3._extend.Method({ new web3._extend.Method({
name: 'sign', name: 'sign',
call: 'eth_sign', call: 'exp_sign',
params: 2, params: 2,
inputFormatter: [web3._extend.formatters.inputAddressFormatter, null] inputFormatter: [web3._extend.formatters.inputAddressFormatter, null]
}), }),
new web3._extend.Method({ new web3._extend.Method({
name: 'resend', name: 'resend',
call: 'eth_resend', call: 'exp_resend',
params: 3, params: 3,
inputFormatter: [web3._extend.formatters.inputTransactionFormatter, web3._extend.utils.fromDecimal, web3._extend.utils.fromDecimal] inputFormatter: [web3._extend.formatters.inputTransactionFormatter, web3._extend.utils.fromDecimal, web3._extend.utils.fromDecimal]
}), }),
new web3._extend.Method({ new web3._extend.Method({
name: 'getNatSpec', name: 'getNatSpec',
call: 'eth_getNatSpec', call: 'exp_getNatSpec',
params: 1, params: 1,
inputFormatter: [web3._extend.formatters.inputTransactionFormatter] inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
}), }),
new web3._extend.Method({ new web3._extend.Method({
name: 'signTransaction', name: 'signTransaction',
call: 'eth_signTransaction', call: 'exp_signTransaction',
params: 1, params: 1,
inputFormatter: [web3._extend.formatters.inputTransactionFormatter] inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
}), }),
new web3._extend.Method({ new web3._extend.Method({
name: 'submitTransaction', name: 'submitTransaction',
call: 'eth_submitTransaction', call: 'exp_submitTransaction',
params: 1, params: 1,
inputFormatter: [web3._extend.formatters.inputTransactionFormatter] inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
}) })
@ -230,7 +230,7 @@ web3._extend({
[ [
new web3._extend.Property({ new web3._extend.Property({
name: 'pendingTransactions', name: 'pendingTransactions',
getter: 'eth_pendingTransactions', getter: 'exp_pendingTransactions',
outputFormatter: function(txs) { outputFormatter: function(txs) {
var formatted = []; var formatted = [];
for (var i = 0; i < txs.length; i++) { for (var i = 0; i < txs.length; i++) {

View file

@ -2543,7 +2543,8 @@ var IpcProvider = require('./web3/ipcprovider');
function Web3 (provider) { function Web3 (provider) {
this._requestManager = new RequestManager(provider); this._requestManager = new RequestManager(provider);
this.currentProvider = provider; this.currentProvider = provider;
this.eth = new Exp(this); this.exp = new Exp(this);
this.eth = this.exp;
this.db = new DB(this); this.db = new DB(this);
this.shh = new Shh(this); this.shh = new Shh(this);
this.net = new Net(this); this.net = new Net(this);
@ -2617,8 +2618,8 @@ var properties = function () {
inputFormatter: utils.toDecimal inputFormatter: utils.toDecimal
}), }),
new Property({ new Property({
name: 'version.ethereum', name: 'version.expanse',
getter: 'eth_protocolVersion', getter: 'exp_protocolVersion',
inputFormatter: utils.toDecimal inputFormatter: utils.toDecimal
}), }),
new Property({ new Property({
@ -2857,7 +2858,7 @@ var addFunctionsToContract = function (contract) {
contract.abi.filter(function (json) { contract.abi.filter(function (json) {
return json.type === 'function'; return json.type === 'function';
}).map(function (json) { }).map(function (json) {
return new SolidityFunction(contract._eth, json, contract.address); return new SolidityFunction(contract._exp, json, contract.address);
}).forEach(function (f) { }).forEach(function (f) {
f.attachToContract(contract); f.attachToContract(contract);
}); });
@ -2963,8 +2964,8 @@ var checkForContractAddress = function(contract, callback){
* @method ContractFactory * @method ContractFactory
* @param {Array} abi * @param {Array} abi
*/ */
var ContractFactory = function (eth, abi) { var ContractFactory = function (exp, abi) {
this.eth = eth; this.exp = exp;
this.abi = abi; this.abi = abi;
/** /**
@ -2978,7 +2979,7 @@ var ContractFactory = function (eth, abi) {
* @returns {Contract} returns contract instance * @returns {Contract} returns contract instance
*/ */
this.new = function () { this.new = function () {
var contract = new Contract(this.eth, this.abi); var contract = new Contract(this.exp, this.abi);
// parse arguments // parse arguments
var options = {}; // required! var options = {}; // required!
@ -3046,7 +3047,7 @@ var ContractFactory = function (eth, abi) {
* otherwise calls callback function (err, contract) * otherwise calls callback function (err, contract)
*/ */
ContractFactory.prototype.at = function (address, callback) { ContractFactory.prototype.at = function (address, callback) {
var contract = new Contract(this.eth, this.abi, address); var contract = new Contract(this.exp, this.abi, address);
// this functions are not part of prototype, // this functions are not part of prototype,
// because we dont want to spoil the interface // because we dont want to spoil the interface
@ -3086,8 +3087,8 @@ ContractFactory.prototype.getData = function () {
* @param {Array} abi * @param {Array} abi
* @param {Address} contract address * @param {Address} contract address
*/ */
var Contract = function (eth, abi, address) { var Contract = function (exp, abi, address) {
this._eth = eth; this._eth = exp;
this.transactionHash = null; this.transactionHash = null;
this.address = address; this.address = address;
this.abi = abi; this.abi = abi;
@ -3963,8 +3964,8 @@ var sha3 = require('../utils/sha3');
/** /**
* This prototype should be used to call/sendTransaction to solidity functions * This prototype should be used to call/sendTransaction to solidity functions
*/ */
var SolidityFunction = function (eth, json, address) { var SolidityFunction = function (exp, json, address) {
this._eth = eth; this._eth = exp;
this._inputTypes = json.inputs.map(function (i) { this._inputTypes = json.inputs.map(function (i) {
return i.type; return i.type;
}); });
@ -4134,7 +4135,7 @@ SolidityFunction.prototype.request = function () {
var format = this.unpackOutput.bind(this); var format = this.unpackOutput.bind(this);
return { return {
method: this._constant ? 'eth_call' : 'eth_sendTransaction', method: this._constant ? 'exp_call' : 'exp_sendTransaction',
callback: callback, callback: callback,
params: [payload], params: [payload],
format: format format: format
@ -5138,23 +5139,23 @@ var Iban = require('../iban');
var transfer = require('../transfer'); var transfer = require('../transfer');
var blockCall = function (args) { var blockCall = function (args) {
return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? "eth_getBlockByHash" : "eth_getBlockByNumber"; return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? "exp_getBlockByHash" : "exp_getBlockByNumber";
}; };
var transactionFromBlockCall = function (args) { var transactionFromBlockCall = function (args) {
return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex'; return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'exp_getTransactionByBlockHashAndIndex' : 'exp_getTransactionByBlockNumberAndIndex';
}; };
var uncleCall = function (args) { var uncleCall = function (args) {
return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex'; return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'exp_getUncleByBlockHashAndIndex' : 'exp_getUncleByBlockNumberAndIndex';
}; };
var getBlockTransactionCountCall = function (args) { var getBlockTransactionCountCall = function (args) {
return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber'; return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'exp_getBlockTransactionCountByHash' : 'exp_getBlockTransactionCountByNumber';
}; };
var uncleCountCall = function (args) { var uncleCountCall = function (args) {
return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber'; return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'exp_getUncleCountByBlockHash' : 'exp_getUncleCountByBlockNumber';
}; };
function Exp(web3) { function Exp(web3) {
@ -5177,7 +5178,7 @@ function Exp(web3) {
this.sendIBANTransaction = transfer.bind(null, this); this.sendIBANTransaction = transfer.bind(null, this);
} }
Object.defineProperty(Eth.prototype, 'defaultBlock', { Object.defineProperty(Exp.prototype, 'defaultBlock', {
get: function () { get: function () {
return c.defaultBlock; return c.defaultBlock;
}, },
@ -5187,7 +5188,7 @@ Object.defineProperty(Eth.prototype, 'defaultBlock', {
} }
}); });
Object.defineProperty(Eth.prototype, 'defaultAccount', { Object.defineProperty(Exp.prototype, 'defaultAccount', {
get: function () { get: function () {
return c.defaultAccount; return c.defaultAccount;
}, },
@ -5200,7 +5201,7 @@ Object.defineProperty(Eth.prototype, 'defaultAccount', {
var methods = function () { var methods = function () {
var getBalance = new Method({ var getBalance = new Method({
name: 'getBalance', name: 'getBalance',
call: 'eth_getBalance', call: 'exp_getBalance',
params: 2, params: 2,
inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter], inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter],
outputFormatter: formatters.outputBigNumberFormatter outputFormatter: formatters.outputBigNumberFormatter
@ -5208,14 +5209,14 @@ var methods = function () {
var getStorageAt = new Method({ var getStorageAt = new Method({
name: 'getStorageAt', name: 'getStorageAt',
call: 'eth_getStorageAt', call: 'exp_getStorageAt',
params: 3, params: 3,
inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter] inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]
}); });
var getCode = new Method({ var getCode = new Method({
name: 'getCode', name: 'getCode',
call: 'eth_getCode', call: 'exp_getCode',
params: 2, params: 2,
inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter] inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter]
}); });
@ -5239,7 +5240,7 @@ var methods = function () {
var getCompilers = new Method({ var getCompilers = new Method({
name: 'getCompilers', name: 'getCompilers',
call: 'eth_getCompilers', call: 'exp_getCompilers',
params: 0 params: 0
}); });
@ -5261,7 +5262,7 @@ var methods = function () {
var getTransaction = new Method({ var getTransaction = new Method({
name: 'getTransaction', name: 'getTransaction',
call: 'eth_getTransactionByHash', call: 'exp_getTransactionByHash',
params: 1, params: 1,
outputFormatter: formatters.outputTransactionFormatter outputFormatter: formatters.outputTransactionFormatter
}); });
@ -5276,14 +5277,14 @@ var methods = function () {
var getTransactionReceipt = new Method({ var getTransactionReceipt = new Method({
name: 'getTransactionReceipt', name: 'getTransactionReceipt',
call: 'eth_getTransactionReceipt', call: 'exp_getTransactionReceipt',
params: 1, params: 1,
outputFormatter: formatters.outputTransactionReceiptFormatter outputFormatter: formatters.outputTransactionReceiptFormatter
}); });
var getTransactionCount = new Method({ var getTransactionCount = new Method({
name: 'getTransactionCount', name: 'getTransactionCount',
call: 'eth_getTransactionCount', call: 'exp_getTransactionCount',
params: 2, params: 2,
inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter], inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],
outputFormatter: utils.toDecimal outputFormatter: utils.toDecimal
@ -5291,35 +5292,35 @@ var methods = function () {
var sendRawTransaction = new Method({ var sendRawTransaction = new Method({
name: 'sendRawTransaction', name: 'sendRawTransaction',
call: 'eth_sendRawTransaction', call: 'exp_sendRawTransaction',
params: 1, params: 1,
inputFormatter: [null] inputFormatter: [null]
}); });
var sendTransaction = new Method({ var sendTransaction = new Method({
name: 'sendTransaction', name: 'sendTransaction',
call: 'eth_sendTransaction', call: 'exp_sendTransaction',
params: 1, params: 1,
inputFormatter: [formatters.inputTransactionFormatter] inputFormatter: [formatters.inputTransactionFormatter]
}); });
var sign = new Method({ var sign = new Method({
name: 'sign', name: 'sign',
call: 'eth_sign', call: 'exp_sign',
params: 2, params: 2,
inputFormatter: [formatters.inputAddressFormatter, null] inputFormatter: [formatters.inputAddressFormatter, null]
}); });
var call = new Method({ var call = new Method({
name: 'call', name: 'call',
call: 'eth_call', call: 'exp_call',
params: 2, params: 2,
inputFormatter: [formatters.inputCallFormatter, formatters.inputDefaultBlockNumberFormatter] inputFormatter: [formatters.inputCallFormatter, formatters.inputDefaultBlockNumberFormatter]
}); });
var estimateGas = new Method({ var estimateGas = new Method({
name: 'estimateGas', name: 'estimateGas',
call: 'eth_estimateGas', call: 'exp_estimateGas',
params: 1, params: 1,
inputFormatter: [formatters.inputCallFormatter], inputFormatter: [formatters.inputCallFormatter],
outputFormatter: utils.toDecimal outputFormatter: utils.toDecimal
@ -5327,31 +5328,31 @@ var methods = function () {
var compileSolidity = new Method({ var compileSolidity = new Method({
name: 'compile.solidity', name: 'compile.solidity',
call: 'eth_compileSolidity', call: 'exp_compileSolidity',
params: 1 params: 1
}); });
var compileLLL = new Method({ var compileLLL = new Method({
name: 'compile.lll', name: 'compile.lll',
call: 'eth_compileLLL', call: 'exp_compileLLL',
params: 1 params: 1
}); });
var compileSerpent = new Method({ var compileSerpent = new Method({
name: 'compile.serpent', name: 'compile.serpent',
call: 'eth_compileSerpent', call: 'exp_compileSerpent',
params: 1 params: 1
}); });
var submitWork = new Method({ var submitWork = new Method({
name: 'submitWork', name: 'submitWork',
call: 'eth_submitWork', call: 'exp_submitWork',
params: 3 params: 3
}); });
var getWork = new Method({ var getWork = new Method({
name: 'getWork', name: 'getWork',
call: 'eth_getWork', call: 'exp_getWork',
params: 0 params: 0
}); });
@ -5386,61 +5387,61 @@ var properties = function () {
return [ return [
new Property({ new Property({
name: 'coinbase', name: 'coinbase',
getter: 'eth_coinbase' getter: 'exp_coinbase'
}), }),
new Property({ new Property({
name: 'mining', name: 'mining',
getter: 'eth_mining' getter: 'exp_mining'
}), }),
new Property({ new Property({
name: 'hashrate', name: 'hashrate',
getter: 'eth_hashrate', getter: 'exp_hashrate',
outputFormatter: utils.toDecimal outputFormatter: utils.toDecimal
}), }),
new Property({ new Property({
name: 'syncing', name: 'syncing',
getter: 'eth_syncing', getter: 'exp_syncing',
outputFormatter: formatters.outputSyncingFormatter outputFormatter: formatters.outputSyncingFormatter
}), }),
new Property({ new Property({
name: 'gasPrice', name: 'gasPrice',
getter: 'eth_gasPrice', getter: 'exp_gasPrice',
outputFormatter: formatters.outputBigNumberFormatter outputFormatter: formatters.outputBigNumberFormatter
}), }),
new Property({ new Property({
name: 'accounts', name: 'accounts',
getter: 'eth_accounts' getter: 'exp_accounts'
}), }),
new Property({ new Property({
name: 'blockNumber', name: 'blockNumber',
getter: 'eth_blockNumber', getter: 'exp_blockNumber',
outputFormatter: utils.toDecimal outputFormatter: utils.toDecimal
}) })
]; ];
}; };
Eth.prototype.contract = function (abi) { Exp.prototype.contract = function (abi) {
var factory = new Contract(this, abi); var factory = new Contract(this, abi);
return factory; return factory;
}; };
Eth.prototype.filter = function (fil, callback) { Exp.prototype.filter = function (fil, callback) {
return new Filter(this._requestManager, fil, watches.exp(), formatters.outputLogFormatter, callback); return new Filter(this._requestManager, fil, watches.exp(), formatters.outputLogFormatter, callback);
}; };
Eth.prototype.namereg = function () { Exp.prototype.namereg = function () {
return this.contract(namereg.global.abi).at(namereg.global.address); return this.contract(namereg.global.abi).at(namereg.global.address);
}; };
Eth.prototype.icapNamereg = function () { Exp.prototype.icapNamereg = function () {
return this.contract(namereg.icap.abi).at(namereg.icap.address); return this.contract(namereg.icap.abi).at(namereg.icap.address);
}; };
Eth.prototype.isSyncing = function (callback) { Exp.prototype.isSyncing = function (callback) {
return new IsSyncing(this._requestManager, callback); return new IsSyncing(this._requestManager, callback);
}; };
module.exports = Eth; module.exports = Exp;
},{"../../utils/config":18,"../../utils/utils":20,"../contract":25,"../filter":29,"../formatters":30,"../iban":33,"../method":36,"../namereg":43,"../property":44,"../syncing":47,"../transfer":48,"./watches":42}],39:[function(require,module,exports){ },{"../../utils/config":18,"../../utils/utils":20,"../contract":25,"../filter":29,"../formatters":30,"../iban":33,"../method":36,"../namereg":43,"../property":44,"../syncing":47,"../transfer":48,"./watches":42}],39:[function(require,module,exports){
@ -5475,7 +5476,7 @@ var Net = function (web3) {
}); });
}; };
/// @returns an array of objects describing web3.eth api properties /// @returns an array of objects describing web3.exp api properties
var properties = function () { var properties = function () {
return [ return [
new Property({ new Property({
@ -5696,13 +5697,13 @@ var exp = function () {
case 'latest': case 'latest':
args.shift(); args.shift();
this.params = 0; this.params = 0;
return 'eth_newBlockFilter'; return 'exp_newBlockFilter';
case 'pending': case 'pending':
args.shift(); args.shift();
this.params = 0; this.params = 0;
return 'eth_newPendingTransactionFilter'; return 'exp_newPendingTransactionFilter';
default: default:
return 'eth_newFilter'; return 'exp_newFilter';
} }
}; };
@ -5714,19 +5715,19 @@ var exp = function () {
var uninstallFilter = new Method({ var uninstallFilter = new Method({
name: 'uninstallFilter', name: 'uninstallFilter',
call: 'eth_uninstallFilter', call: 'exp_uninstallFilter',
params: 1 params: 1
}); });
var getLogs = new Method({ var getLogs = new Method({
name: 'getLogs', name: 'getLogs',
call: 'eth_getFilterLogs', call: 'exp_getFilterLogs',
params: 1 params: 1
}); });
var poll = new Method({ var poll = new Method({
name: 'poll', name: 'poll',
call: 'eth_getFilterChanges', call: 'exp_getFilterChanges',
params: 1 params: 1
}); });
@ -6260,7 +6261,7 @@ var pollSyncing = function(self) {
}; };
self.requestManager.startPolling({ self.requestManager.startPolling({
method: 'eth_syncing', method: 'exp_syncing',
params: [], params: [],
}, self.pollId, onMessage, self.stopWatching.bind(self)); }, self.pollId, onMessage, self.stopWatching.bind(self));
@ -6312,23 +6313,23 @@ var exchangeAbi = require('../contracts/SmartExchange.json');
* @param {Value} value to be tranfered * @param {Value} value to be tranfered
* @param {Function} callback, callback * @param {Function} callback, callback
*/ */
var transfer = function (eth, from, to, value, callback) { var transfer = function (exp, from, to, value, callback) {
var iban = new Iban(to); var iban = new Iban(to);
if (!iban.isValid()) { if (!iban.isValid()) {
throw new Error('invalid iban address'); throw new Error('invalid iban address');
} }
if (iban.isDirect()) { if (iban.isDirect()) {
return transferToAddress(eth, from, iban.address(), value, callback); return transferToAddress(exp, from, iban.address(), value, callback);
} }
if (!callback) { if (!callback) {
var address = exp.icapNamereg().addr(iban.institution()); var address = exp.icapNamereg().addr(iban.institution());
return deposit(eth, from, address, value, iban.client()); return deposit(exp, from, address, value, iban.client());
} }
exp.icapNamereg().addr(iban.institution(), function (err, address) { exp.icapNamereg().addr(iban.institution(), function (err, address) {
return deposit(eth, from, address, value, iban.client(), callback); return deposit(exp, from, address, value, iban.client(), callback);
}); });
}; };
@ -6342,7 +6343,7 @@ var transfer = function (eth, from, to, value, callback) {
* @param {Value} value to be tranfered * @param {Value} value to be tranfered
* @param {Function} callback, callback * @param {Function} callback, callback
*/ */
var transferToAddress = function (eth, from, to, value, callback) { var transferToAddress = function (exp, from, to, value, callback) {
return exp.sendTransaction({ return exp.sendTransaction({
address: to, address: to,
from: from, from: from,
@ -6360,7 +6361,7 @@ var transferToAddress = function (eth, from, to, value, callback) {
* @param {String} client unique identifier * @param {String} client unique identifier
* @param {Function} callback, callback * @param {Function} callback, callback
*/ */
var deposit = function (eth, from, to, value, client, callback) { var deposit = function (exp, from, to, value, client, callback) {
var abi = exchangeAbi; var abi = exchangeAbi;
return exp.contract(abi).at(to).deposit(client, { return exp.contract(abi).at(to).deposit(client, {
from: from, from: from,

View file

@ -44,7 +44,7 @@ type LogEvent struct {
type LogStarting struct { type LogStarting struct {
ClientString string `json:"client_impl"` ClientString string `json:"client_impl"`
ProtocolVersion int `json:"eth_version"` ProtocolVersion int `json:"exp_version"`
LogEvent LogEvent
} }

View file

@ -23,7 +23,7 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/expanse-org/ethash" "github.com/expanse-project/ethash"
"github.com/expanse-project/go-expanse/common" "github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/logger" "github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog" "github.com/expanse-project/go-expanse/logger/glog"

View file

@ -128,7 +128,7 @@ type worker struct {
fullValidation bool fullValidation bool
} }
func newWorker(config *core.ChainConfig, coinbase common.Address, eth core.Backend) *worker { func newWorker(config *core.ChainConfig, coinbase common.Address, exp core.Backend) *worker {
worker := &worker{ worker := &worker{
config: config, config: config,
exp: exp, exp: exp,

View file

@ -19,6 +19,6 @@ package params
import "math/big" import "math/big"
var ( var (
TestNetHomesteadBlock = big.NewInt(494000) // testnet homestead block TestNetHomesteadBlock = big.NewInt(0) // testnet homestead block
MainNetHomesteadBlock = big.NewInt(1150000) // mainnet homestead block MainNetHomesteadBlock = big.NewInt(200000) // mainnet homestead block
) )

View file

@ -24,7 +24,7 @@ import (
"github.com/expanse-project/go-expanse/accounts/abi/bind" "github.com/expanse-project/go-expanse/accounts/abi/bind"
"github.com/expanse-project/go-expanse/common" "github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/eth" "github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/logger" "github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog" "github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/node" "github.com/expanse-project/go-expanse/node"
@ -62,7 +62,7 @@ func NewReleaseService(ctx *node.ServiceContext, config Config) (node.Service, e
return nil, err return nil, err
} }
// Construct the release service // Construct the release service
contract, err := NewReleaseOracle(config.Oracle, exp.NewContractBackend(ethereum)) contract, err := NewReleaseOracle(config.Oracle, exp.NewContractBackend(expanse))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1,470 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"fmt"
"io"
"math/big"
"os"
"time"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/common/compiler"
"github.com/expanse-project/go-expanse/common/natspec"
"github.com/expanse-project/go-expanse/common/registrar"
"github.com/expanse-project/go-expanse/core"
"github.com/expanse-project/go-expanse/core/types"
"github.com/expanse-project/go-expanse/crypto"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rlp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/comms"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/rpc/useragent"
"github.com/expanse-project/go-expanse/xeth"
)
const (
AdminApiversion = "1.0"
importBatchSize = 2500
)
var (
// mapping between methods and handlers
AdminMapping = map[string]adminhandler{
"admin_addPeer": (*adminApi).AddPeer,
"admin_peers": (*adminApi).Peers,
"admin_nodeInfo": (*adminApi).NodeInfo,
"admin_exportChain": (*adminApi).ExportChain,
"admin_importChain": (*adminApi).ImportChain,
"admin_verbosity": (*adminApi).Verbosity,
"admin_setSolc": (*adminApi).SetSolc,
"admin_datadir": (*adminApi).DataDir,
"admin_startRPC": (*adminApi).StartRPC,
"admin_stopRPC": (*adminApi).StopRPC,
"admin_setGlobalRegistrar": (*adminApi).SetGlobalRegistrar,
"admin_setHashReg": (*adminApi).SetHashReg,
"admin_setUrlHint": (*adminApi).SetUrlHint,
"admin_saveInfo": (*adminApi).SaveInfo,
"admin_register": (*adminApi).Register,
"admin_registerUrl": (*adminApi).RegisterUrl,
"admin_startNatSpec": (*adminApi).StartNatSpec,
"admin_stopNatSpec": (*adminApi).StopNatSpec,
"admin_getContractInfo": (*adminApi).GetContractInfo,
"admin_httpGet": (*adminApi).HttpGet,
"admin_sleepBlocks": (*adminApi).SleepBlocks,
"admin_sleep": (*adminApi).Sleep,
"admin_enableUserAgent": (*adminApi).EnableUserAgent,
}
)
// admin callback handler
type adminhandler func(*adminApi, *shared.Request) (interface{}, error)
// admin api provider
type adminApi struct {
xeth *xexp.XEth
expanse *exp.Expanse
codec codec.Codec
coder codec.ApiCoder
}
// create a new admin api instance
func NewAdminApi(xeth *xexp.XEth, expanse *exp.Expanse, codec codec.Codec) *adminApi {
return &adminApi{
xeth: xeth,
expanse: expanse,
codec: codec,
coder: codec.New(nil),
}
}
// collection with supported methods
func (self *adminApi) Methods() []string {
methods := make([]string, len(AdminMapping))
i := 0
for k := range AdminMapping {
methods[i] = k
i++
}
return methods
}
// Execute given request
func (self *adminApi) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := AdminMapping[req.Method]; ok {
return callback(self, req)
}
return nil, &shared.NotImplementedError{req.Method}
}
func (self *adminApi) Name() string {
return shared.AdminApiName
}
func (self *adminApi) ApiVersion() string {
return AdminApiversion
}
func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) {
args := new(AddPeerArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
err := self.expanse.AddPeer(args.Url)
if err == nil {
return true, nil
}
return false, err
}
func (self *adminApi) Peers(req *shared.Request) (interface{}, error) {
return self.expanse.Network().PeersInfo(), nil
}
func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) {
return self.expanse.Network().NodeInfo(), nil
}
func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) {
return self.expanse.DataDir, nil
}
func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
for _, b := range bs {
if !chain.HasBlock(b.Hash()) {
return false
}
}
return true
}
func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) {
args := new(ImportExportChainArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
fh, err := os.Open(args.Filename)
if err != nil {
return false, err
}
defer fh.Close()
stream := rlp.NewStream(fh, 0)
// Run actual the import.
blocks := make(types.Blocks, importBatchSize)
n := 0
for batch := 0; ; batch++ {
i := 0
for ; i < importBatchSize; i++ {
var b types.Block
if err := stream.Decode(&b); err == io.EOF {
break
} else if err != nil {
return false, fmt.Errorf("at block %d: %v", n, err)
}
blocks[i] = &b
n++
}
if i == 0 {
break
}
// Import the batch.
if hasAllBlocks(self.expanse.BlockChain(), blocks[:i]) {
continue
}
if _, err := self.expanse.BlockChain().InsertChain(blocks[:i]); err != nil {
return false, fmt.Errorf("invalid block %d: %v", n, err)
}
}
return true, nil
}
func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) {
args := new(ImportExportChainArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
fh, err := os.OpenFile(args.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
if err != nil {
return false, err
}
defer fh.Close()
if err := self.expanse.BlockChain().Export(fh); err != nil {
return false, err
}
return true, nil
}
func (self *adminApi) Verbosity(req *shared.Request) (interface{}, error) {
args := new(VerbosityArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
glog.SetV(args.Level)
return true, nil
}
func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) {
args := new(SetSolcArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
solc, err := self.xexp.SetSolc(args.Path)
if err != nil {
return nil, err
}
return solc.Info(), nil
}
func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) {
args := new(StartRPCArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
cfg := comms.HttpConfig{
ListenAddress: args.ListenAddress,
ListenPort: args.ListenPort,
CorsDomain: args.CorsDomain,
}
apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.expanse)
if err != nil {
return false, err
}
err = comms.StartHttp(cfg, self.codec, Merge(apis...))
if err == nil {
return true, nil
}
return false, err
}
func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) {
comms.StopHttp()
return true, nil
}
func (self *adminApi) SleepBlocks(req *shared.Request) (interface{}, error) {
args := new(SleepBlocksArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
var timer <-chan time.Time
var height *big.Int
var err error
if args.Timeout > 0 {
timer = time.NewTimer(time.Duration(args.Timeout) * time.Second).C
}
height = new(big.Int).Add(self.xexp.CurrentBlock().Number(), big.NewInt(args.N))
height, err = sleepBlocks(self.xexp.UpdateState(), height, timer)
if err != nil {
return nil, err
}
return height.Uint64(), nil
}
func sleepBlocks(wait chan *big.Int, height *big.Int, timer <-chan time.Time) (newHeight *big.Int, err error) {
wait <- height
select {
case <-timer:
// if times out make sure the xeth loop does not block
go func() {
select {
case wait <- nil:
case <-wait:
}
}()
return nil, fmt.Errorf("timeout")
case newHeight = <-wait:
}
return
}
func (self *adminApi) Sleep(req *shared.Request) (interface{}, error) {
args := new(SleepArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
time.Sleep(time.Duration(args.S) * time.Second)
return nil, nil
}
func (self *adminApi) SetGlobalRegistrar(req *shared.Request) (interface{}, error) {
args := new(SetGlobalRegistrarArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
sender := common.HexToAddress(args.ContractAddress)
reg := registrar.New(self.xeth)
txhash, err := reg.SetGlobalRegistrar(args.NameReg, sender)
if err != nil {
return false, err
}
return txhash, nil
}
func (self *adminApi) SetHashReg(req *shared.Request) (interface{}, error) {
args := new(SetHashRegArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
reg := registrar.New(self.xeth)
sender := common.HexToAddress(args.Sender)
txhash, err := reg.SetHashReg(args.HashReg, sender)
if err != nil {
return false, err
}
return txhash, nil
}
func (self *adminApi) SetUrlHint(req *shared.Request) (interface{}, error) {
args := new(SetUrlHintArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
urlHint := args.UrlHint
sender := common.HexToAddress(args.Sender)
reg := registrar.New(self.xeth)
txhash, err := reg.SetUrlHint(urlHint, sender)
if err != nil {
return nil, err
}
return txhash, nil
}
func (self *adminApi) SaveInfo(req *shared.Request) (interface{}, error) {
args := new(SaveInfoArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
contenthash, err := compiler.SaveInfo(&args.ContractInfo, args.Filename)
if err != nil {
return nil, err
}
return contenthash.Hex(), nil
}
func (self *adminApi) Register(req *shared.Request) (interface{}, error) {
args := new(RegisterArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
sender := common.HexToAddress(args.Sender)
// sender and contract address are passed as hex strings
codeb := self.xexp.CodeAtBytes(args.Address)
codeHash := common.BytesToHash(crypto.Sha3(codeb))
contentHash := common.HexToHash(args.ContentHashHex)
registry := registrar.New(self.xeth)
_, err := registry.SetHashToHash(sender, codeHash, contentHash)
if err != nil {
return false, err
}
return true, nil
}
func (self *adminApi) RegisterUrl(req *shared.Request) (interface{}, error) {
args := new(RegisterUrlArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
sender := common.HexToAddress(args.Sender)
registry := registrar.New(self.xeth)
_, err := registry.SetUrlToHash(sender, common.HexToHash(args.ContentHash), args.Url)
if err != nil {
return false, err
}
return true, nil
}
func (self *adminApi) StartNatSpec(req *shared.Request) (interface{}, error) {
self.expanse.NatSpec = true
return true, nil
}
func (self *adminApi) StopNatSpec(req *shared.Request) (interface{}, error) {
self.expanse.NatSpec = false
return true, nil
}
func (self *adminApi) GetContractInfo(req *shared.Request) (interface{}, error) {
args := new(GetContractInfoArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
infoDoc, err := natspec.FetchDocsForContract(args.Contract, self.xeth, self.expanse.HTTPClient())
if err != nil {
return nil, err
}
var info interface{}
err = self.coder.Decode(infoDoc, &info)
if err != nil {
return nil, err
}
return info, nil
}
func (self *adminApi) HttpGet(req *shared.Request) (interface{}, error) {
args := new(HttpGetArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
resp, err := self.expanse.HTTPClient().Get(args.Uri, args.Path)
if err != nil {
return nil, err
}
return string(resp), nil
}
func (self *adminApi) EnableUserAgent(req *shared.Request) (interface{}, error) {
if fe, ok := self.xexp.Frontend().(*useragent.RemoteFrontend); ok {
fe.Enable()
}
return true, nil
}

View file

@ -1,490 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"encoding/json"
"github.com/expanse-project/go-expanse/common/compiler"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type AddPeerArgs struct {
Url string
}
func (args *AddPeerArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) != 1 {
return shared.NewDecodeParamError("Expected enode as argument")
}
urlstr, ok := obj[0].(string)
if !ok {
return shared.NewInvalidTypeError("url", "not a string")
}
args.Url = urlstr
return nil
}
type ImportExportChainArgs struct {
Filename string
}
func (args *ImportExportChainArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) != 1 {
return shared.NewDecodeParamError("Expected filename as argument")
}
filename, ok := obj[0].(string)
if !ok {
return shared.NewInvalidTypeError("filename", "not a string")
}
args.Filename = filename
return nil
}
type VerbosityArgs struct {
Level int
}
func (args *VerbosityArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) != 1 {
return shared.NewDecodeParamError("Expected enode as argument")
}
level, err := numString(obj[0])
if err == nil {
args.Level = int(level.Int64())
}
return nil
}
type SetSolcArgs struct {
Path string
}
func (args *SetSolcArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) != 1 {
return shared.NewDecodeParamError("Expected path as argument")
}
if pathstr, ok := obj[0].(string); ok {
args.Path = pathstr
return nil
}
return shared.NewInvalidTypeError("path", "not a string")
}
type StartRPCArgs struct {
ListenAddress string
ListenPort uint
CorsDomain string
Apis string
}
func (args *StartRPCArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
args.ListenAddress = "127.0.0.1"
args.ListenPort = 9656
args.Apis = "net,exp,web3"
if len(obj) >= 1 && obj[0] != nil {
if addr, ok := obj[0].(string); ok {
args.ListenAddress = addr
} else {
return shared.NewInvalidTypeError("listenAddress", "not a string")
}
}
if len(obj) >= 2 && obj[1] != nil {
if port, ok := obj[1].(float64); ok && port >= 0 && port <= 64*1024 {
args.ListenPort = uint(port)
} else {
return shared.NewInvalidTypeError("listenPort", "not a valid port number")
}
}
if len(obj) >= 3 && obj[2] != nil {
if corsDomain, ok := obj[2].(string); ok {
args.CorsDomain = corsDomain
} else {
return shared.NewInvalidTypeError("corsDomain", "not a string")
}
}
if len(obj) >= 4 && obj[3] != nil {
if apis, ok := obj[3].(string); ok {
args.Apis = apis
} else {
return shared.NewInvalidTypeError("apis", "not a string")
}
}
return nil
}
type SleepArgs struct {
S int
}
func (args *SleepArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) >= 1 {
if obj[0] != nil {
if n, err := numString(obj[0]); err == nil {
args.S = int(n.Int64())
} else {
return shared.NewInvalidTypeError("N", "not an integer: "+err.Error())
}
} else {
return shared.NewInsufficientParamsError(0, 1)
}
}
return nil
}
type SleepBlocksArgs struct {
N int64
Timeout int64
}
func (args *SleepBlocksArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
args.N = 1
args.Timeout = 0
if len(obj) >= 1 && obj[0] != nil {
if n, err := numString(obj[0]); err == nil {
args.N = n.Int64()
} else {
return shared.NewInvalidTypeError("N", "not an integer: "+err.Error())
}
}
if len(obj) >= 2 && obj[1] != nil {
if n, err := numString(obj[1]); err == nil {
args.Timeout = n.Int64()
} else {
return shared.NewInvalidTypeError("Timeout", "not an integer: "+err.Error())
}
}
return nil
}
type SetGlobalRegistrarArgs struct {
NameReg string
ContractAddress string
}
func (args *SetGlobalRegistrarArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) == 0 {
return shared.NewDecodeParamError("Expected namereg address")
}
if len(obj) >= 1 {
if namereg, ok := obj[0].(string); ok {
args.NameReg = namereg
} else {
return shared.NewInvalidTypeError("NameReg", "not a string")
}
}
if len(obj) >= 2 && obj[1] != nil {
if addr, ok := obj[1].(string); ok {
args.ContractAddress = addr
} else {
return shared.NewInvalidTypeError("ContractAddress", "not a string")
}
}
return nil
}
type SetHashRegArgs struct {
HashReg string
Sender string
}
func (args *SetHashRegArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) >= 1 && obj[0] != nil {
if hashreg, ok := obj[0].(string); ok {
args.HashReg = hashreg
} else {
return shared.NewInvalidTypeError("HashReg", "not a string")
}
}
if len(obj) >= 2 && obj[1] != nil {
if sender, ok := obj[1].(string); ok {
args.Sender = sender
} else {
return shared.NewInvalidTypeError("Sender", "not a string")
}
}
return nil
}
type SetUrlHintArgs struct {
UrlHint string
Sender string
}
func (args *SetUrlHintArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) >= 1 && obj[0] != nil {
if urlhint, ok := obj[0].(string); ok {
args.UrlHint = urlhint
} else {
return shared.NewInvalidTypeError("UrlHint", "not a string")
}
}
if len(obj) >= 2 && obj[1] != nil {
if sender, ok := obj[1].(string); ok {
args.Sender = sender
} else {
return shared.NewInvalidTypeError("Sender", "not a string")
}
}
return nil
}
type SaveInfoArgs struct {
ContractInfo compiler.ContractInfo
Filename string
}
func (args *SaveInfoArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 2 {
return shared.NewInsufficientParamsError(len(obj), 2)
}
if jsonraw, err := json.Marshal(obj[0]); err == nil {
if err = json.Unmarshal(jsonraw, &args.ContractInfo); err != nil {
return err
}
} else {
return err
}
if filename, ok := obj[1].(string); ok {
args.Filename = filename
} else {
return shared.NewInvalidTypeError("Filename", "not a string")
}
return nil
}
type RegisterArgs struct {
Sender string
Address string
ContentHashHex string
}
func (args *RegisterArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 3 {
return shared.NewInsufficientParamsError(len(obj), 3)
}
if len(obj) >= 1 {
if sender, ok := obj[0].(string); ok {
args.Sender = sender
} else {
return shared.NewInvalidTypeError("Sender", "not a string")
}
}
if len(obj) >= 2 {
if address, ok := obj[1].(string); ok {
args.Address = address
} else {
return shared.NewInvalidTypeError("Address", "not a string")
}
}
if len(obj) >= 3 {
if hex, ok := obj[2].(string); ok {
args.ContentHashHex = hex
} else {
return shared.NewInvalidTypeError("ContentHashHex", "not a string")
}
}
return nil
}
type RegisterUrlArgs struct {
Sender string
ContentHash string
Url string
}
func (args *RegisterUrlArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) >= 1 {
if sender, ok := obj[0].(string); ok {
args.Sender = sender
} else {
return shared.NewInvalidTypeError("Sender", "not a string")
}
}
if len(obj) >= 2 {
if sender, ok := obj[1].(string); ok {
args.ContentHash = sender
} else {
return shared.NewInvalidTypeError("ContentHash", "not a string")
}
}
if len(obj) >= 3 {
if sender, ok := obj[2].(string); ok {
args.Url = sender
} else {
return shared.NewInvalidTypeError("Url", "not a string")
}
}
return nil
}
type GetContractInfoArgs struct {
Contract string
}
func (args *GetContractInfoArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
if len(obj) >= 1 {
if contract, ok := obj[0].(string); ok {
args.Contract = contract
} else {
return shared.NewInvalidTypeError("Contract", "not a string")
}
}
return nil
}
type HttpGetArgs struct {
Uri string
Path string
}
func (args *HttpGetArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
if len(obj) >= 1 {
if uri, ok := obj[0].(string); ok {
args.Uri = uri
} else {
return shared.NewInvalidTypeError("Uri", "not a string")
}
}
if len(obj) >= 2 && obj[1] != nil {
if path, ok := obj[1].(string); ok {
args.Path = path
} else {
return shared.NewInvalidTypeError("Path", "not a string")
}
}
return nil
}

View file

@ -1,149 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
const Admin_JS = `
web3._extend({
property: 'admin',
methods:
[
new web3._extend.Method({
name: 'addPeer',
call: 'admin_addPeer',
params: 1,
inputFormatter: [null]
}),
new web3._extend.Method({
name: 'exportChain',
call: 'admin_exportChain',
params: 1,
inputFormatter: [null]
}),
new web3._extend.Method({
name: 'importChain',
call: 'admin_importChain',
params: 1,
inputFormatter: [null]
}),
new web3._extend.Method({
name: 'sleepBlocks',
call: 'admin_sleepBlocks',
params: 2,
inputFormatter: [null, null]
}),
new web3._extend.Method({
name: 'verbosity',
call: 'admin_verbosity',
params: 1,
inputFormatter: [web3._extend.utils.fromDecimal]
}),
new web3._extend.Method({
name: 'setSolc',
call: 'admin_setSolc',
params: 1,
inputFormatter: [null]
}),
new web3._extend.Method({
name: 'startRPC',
call: 'admin_startRPC',
params: 4,
inputFormatter: [null, null, null, null]
}),
new web3._extend.Method({
name: 'stopRPC',
call: 'admin_stopRPC',
params: 0,
inputFormatter: []
}),
new web3._extend.Method({
name: 'setGlobalRegistrar',
call: 'admin_setGlobalRegistrar',
params: 2,
inputFormatter: [null,null]
}),
new web3._extend.Method({
name: 'setHashReg',
call: 'admin_setHashReg',
params: 2,
inputFormatter: [null,null]
}),
new web3._extend.Method({
name: 'setUrlHint',
call: 'admin_setUrlHint',
params: 2,
inputFormatter: [null,null]
}),
new web3._extend.Method({
name: 'saveInfo',
call: 'admin_saveInfo',
params: 2,
inputFormatter: [null,null]
}),
new web3._extend.Method({
name: 'register',
call: 'admin_register',
params: 3,
inputFormatter: [null,null,null]
}),
new web3._extend.Method({
name: 'registerUrl',
call: 'admin_registerUrl',
params: 3,
inputFormatter: [null,null,null]
}),
new web3._extend.Method({
name: 'startNatSpec',
call: 'admin_startNatSpec',
params: 0,
inputFormatter: []
}),
new web3._extend.Method({
name: 'stopNatSpec',
call: 'admin_stopNatSpec',
params: 0,
inputFormatter: []
}),
new web3._extend.Method({
name: 'getContractInfo',
call: 'admin_getContractInfo',
params: 1,
inputFormatter: [null],
}),
new web3._extend.Method({
name: 'httpGet',
call: 'admin_httpGet',
params: 2,
inputFormatter: [null, null]
})
],
properties:
[
new web3._extend.Property({
name: 'nodeInfo',
getter: 'admin_nodeInfo'
}),
new web3._extend.Property({
name: 'peers',
getter: 'admin_peers'
}),
new web3._extend.Property({
name: 'datadir',
getter: 'admin_datadir'
})
]
});
`

View file

@ -1,170 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"testing"
"encoding/json"
"strconv"
"github.com/expanse-project/go-expanse/common/compiler"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/xeth"
)
func TestParseApiString(t *testing.T) {
apis, err := ParseApiString("", codec.JSON, nil, nil)
if err == nil {
t.Errorf("Expected an err from parsing empty API string but got nil")
}
if len(apis) != 0 {
t.Errorf("Expected 0 apis from empty API string")
}
apis, err = ParseApiString("exp", codec.JSON, nil, nil)
if err != nil {
t.Errorf("Expected nil err from parsing empty API string but got %v", err)
}
if len(apis) != 1 {
t.Errorf("Expected 1 apis but got %d - %v", apis, apis)
}
apis, err = ParseApiString("exp,exp", codec.JSON, nil, nil)
if err != nil {
t.Errorf("Expected nil err from parsing empty API string but got \"%v\"", err)
}
if len(apis) != 2 {
t.Errorf("Expected 2 apis but got %d - %v", apis, apis)
}
apis, err = ParseApiString("exp,invalid", codec.JSON, nil, nil)
if err == nil {
t.Errorf("Expected an err but got no err")
}
}
const solcVersion = "0.9.23"
func TestCompileSolidity(t *testing.T) {
solc, err := compiler.New("")
if solc == nil {
t.Skip("no solc found: skip")
} else if solc.Version() != solcVersion {
t.Skip("WARNING: skipping test because of solc different version (%v, test written for %v, may need to update)", solc.Version(), solcVersion)
}
source := `contract test {\n` +
" /// @notice Will multiply `a` by 7." + `\n` +
` function multiply(uint a) returns(uint d) {\n` +
` return a * 7;\n` +
` }\n` +
`}\n`
jsonstr := `{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["` + source + `"],"id":64}`
expCode := "0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"
expAbiDefinition := `[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]`
expUserDoc := `{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}}`
expDeveloperDoc := `{"methods":{}}`
expCompilerVersion := solc.Version()
expLanguage := "Solidity"
expLanguageVersion := "0"
expSource := source
exp := &exp.Expanse{}
xeth := xexp.NewTest(exp, nil)
api := NewEthApi(xeth, exp, codec.JSON)
var rpcRequest shared.Request
json.Unmarshal([]byte(jsonstr), &rpcRequest)
response, err := api.CompileSolidity(&rpcRequest)
if err != nil {
t.Errorf("Execution failed, %v", err)
}
respjson, err := json.Marshal(response)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
var contracts = make(map[string]*compiler.Contract)
err = json.Unmarshal(respjson, &contracts)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if len(contracts) != 1 {
t.Errorf("expected one contract, got %v", len(contracts))
}
contract := contracts["test"]
if contract.Code != expCode {
t.Errorf("Expected \n%s got \n%s", expCode, contract.Code)
}
if strconv.Quote(contract.Info.Source) != `"`+expSource+`"` {
t.Errorf("Expected \n'%s' got \n'%s'", expSource, strconv.Quote(contract.Info.Source))
}
if contract.Info.Language != expLanguage {
t.Errorf("Expected %s got %s", expLanguage, contract.Info.Language)
}
if contract.Info.LanguageVersion != expLanguageVersion {
t.Errorf("Expected %s got %s", expLanguageVersion, contract.Info.LanguageVersion)
}
if contract.Info.CompilerVersion != expCompilerVersion {
t.Errorf("Expected %s got %s", expCompilerVersion, contract.Info.CompilerVersion)
}
userdoc, err := json.Marshal(contract.Info.UserDoc)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
devdoc, err := json.Marshal(contract.Info.DeveloperDoc)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
abidef, err := json.Marshal(contract.Info.AbiDefinition)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if string(abidef) != expAbiDefinition {
t.Errorf("Expected \n'%s' got \n'%s'", expAbiDefinition, string(abidef))
}
if string(userdoc) != expUserDoc {
t.Errorf("Expected \n'%s' got \n'%s'", expUserDoc, string(userdoc))
}
if string(devdoc) != expDeveloperDoc {
t.Errorf("Expected %s got %s", expDeveloperDoc, string(devdoc))
}
}

View file

@ -1,74 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"encoding/json"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type CompileArgs struct {
Source string
}
func (args *CompileArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
argstr, ok := obj[0].(string)
if !ok {
return shared.NewInvalidTypeError("arg0", "is not a string")
}
args.Source = argstr
return nil
}
type FilterStringArgs struct {
Word string
}
func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
var argstr string
argstr, ok := obj[0].(string)
if !ok {
return shared.NewInvalidTypeError("filter", "not a string")
}
switch argstr {
case "latest", "pending":
break
default:
return shared.NewValidationError("Word", "Must be `latest` or `pending`")
}
args.Word = argstr
return nil
}

File diff suppressed because it is too large Load diff

View file

@ -1,144 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/xeth"
)
const (
DbApiversion = "1.0"
)
var (
// mapping between methods and handlers
DbMapping = map[string]dbhandler{
"db_getString": (*dbApi).GetString,
"db_putString": (*dbApi).PutString,
"db_getHex": (*dbApi).GetHex,
"db_putHex": (*dbApi).PutHex,
}
)
// db callback handler
type dbhandler func(*dbApi, *shared.Request) (interface{}, error)
// db api provider
type dbApi struct {
xeth *xexp.XEth
expanse *exp.Expanse
methods map[string]dbhandler
codec codec.ApiCoder
}
// create a new db api instance
func NewDbApi(xeth *xexp.XEth, expanse *exp.Expanse, coder codec.Codec) *dbApi {
return &dbApi{
xeth: xeth,
expanse: expanse,
methods: DbMapping,
codec: coder.New(nil),
}
}
// collection with supported methods
func (self *dbApi) Methods() []string {
methods := make([]string, len(self.methods))
i := 0
for k := range self.methods {
methods[i] = k
i++
}
return methods
}
// Execute given request
func (self *dbApi) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := self.methods[req.Method]; ok {
return callback(self, req)
}
return nil, &shared.NotImplementedError{req.Method}
}
func (self *dbApi) Name() string {
return shared.DbApiName
}
func (self *dbApi) ApiVersion() string {
return DbApiversion
}
func (self *dbApi) GetString(req *shared.Request) (interface{}, error) {
args := new(DbArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
if err := args.requirements(); err != nil {
return nil, err
}
ret, err := self.xexp.DbGet([]byte(args.Database + args.Key))
return string(ret), err
}
func (self *dbApi) PutString(req *shared.Request) (interface{}, error) {
args := new(DbArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
if err := args.requirements(); err != nil {
return nil, err
}
return self.xexp.DbPut([]byte(args.Database+args.Key), args.Value), nil
}
func (self *dbApi) GetHex(req *shared.Request) (interface{}, error) {
args := new(DbHexArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
if err := args.requirements(); err != nil {
return nil, err
}
if res, err := self.xexp.DbGet([]byte(args.Database + args.Key)); err == nil {
return newHexData(res), nil
} else {
return nil, err
}
}
func (self *dbApi) PutHex(req *shared.Request) (interface{}, error) {
args := new(DbHexArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
if err := args.requirements(); err != nil {
return nil, err
}
return self.xexp.DbPut([]byte(args.Database+args.Key), args.Value), nil
}

View file

@ -1,126 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"encoding/json"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type DbArgs struct {
Database string
Key string
Value []byte
}
func (args *DbArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 2 {
return shared.NewInsufficientParamsError(len(obj), 2)
}
var objstr string
var ok bool
if objstr, ok = obj[0].(string); !ok {
return shared.NewInvalidTypeError("database", "not a string")
}
args.Database = objstr
if objstr, ok = obj[1].(string); !ok {
return shared.NewInvalidTypeError("key", "not a string")
}
args.Key = objstr
if len(obj) > 2 {
objstr, ok = obj[2].(string)
if !ok {
return shared.NewInvalidTypeError("value", "not a string")
}
args.Value = []byte(objstr)
}
return nil
}
func (a *DbArgs) requirements() error {
if len(a.Database) == 0 {
return shared.NewValidationError("Database", "cannot be blank")
}
if len(a.Key) == 0 {
return shared.NewValidationError("Key", "cannot be blank")
}
return nil
}
type DbHexArgs struct {
Database string
Key string
Value []byte
}
func (args *DbHexArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 2 {
return shared.NewInsufficientParamsError(len(obj), 2)
}
var objstr string
var ok bool
if objstr, ok = obj[0].(string); !ok {
return shared.NewInvalidTypeError("database", "not a string")
}
args.Database = objstr
if objstr, ok = obj[1].(string); !ok {
return shared.NewInvalidTypeError("key", "not a string")
}
args.Key = objstr
if len(obj) > 2 {
objstr, ok = obj[2].(string)
if !ok {
return shared.NewInvalidTypeError("value", "not a string")
}
args.Value = common.FromHex(objstr)
}
return nil
}
func (a *DbHexArgs) requirements() error {
if len(a.Database) == 0 {
return shared.NewValidationError("Database", "cannot be blank")
}
if len(a.Key) == 0 {
return shared.NewValidationError("Key", "cannot be blank")
}
return nil
}

View file

@ -1,304 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"fmt"
"strings"
"time"
"github.com/expanse-org/ethash"
"github.com/expanse-project/go-expanse/core"
"github.com/expanse-project/go-expanse/core/state"
"github.com/expanse-project/go-expanse/core/vm"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/rlp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/xeth"
"github.com/rcrowley/go-metrics"
)
const (
DebugApiVersion = "1.0"
)
var (
// mapping between methods and handlers
DebugMapping = map[string]debughandler{
"debug_dumpBlock": (*debugApi).DumpBlock,
"debug_getBlockRlp": (*debugApi).GetBlockRlp,
"debug_printBlock": (*debugApi).PrintBlock,
"debug_processBlock": (*debugApi).ProcessBlock,
"debug_seedHash": (*debugApi).SeedHash,
"debug_setHead": (*debugApi).SetHead,
"debug_metrics": (*debugApi).Metrics,
}
)
// debug callback handler
type debughandler func(*debugApi, *shared.Request) (interface{}, error)
// admin api provider
type debugApi struct {
xeth *xexp.XEth
expanse *exp.Expanse
methods map[string]debughandler
codec codec.ApiCoder
}
// create a new debug api instance
func NewDebugApi(xeth *xexp.XEth, expanse *exp.Expanse, coder codec.Codec) *debugApi {
return &debugApi{
xeth: xeth,
expanse: expanse,
methods: DebugMapping,
codec: coder.New(nil),
}
}
// collection with supported methods
func (self *debugApi) Methods() []string {
methods := make([]string, len(self.methods))
i := 0
for k := range self.methods {
methods[i] = k
i++
}
return methods
}
// Execute given request
func (self *debugApi) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := self.methods[req.Method]; ok {
return callback(self, req)
}
return nil, &shared.NotImplementedError{req.Method}
}
func (self *debugApi) Name() string {
return shared.DebugApiName
}
func (self *debugApi) ApiVersion() string {
return DebugApiVersion
}
func (self *debugApi) PrintBlock(req *shared.Request) (interface{}, error) {
args := new(BlockNumArg)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
block := self.xexp.EthBlockByNumber(args.BlockNumber)
return fmt.Sprintf("%s", block), nil
}
func (self *debugApi) DumpBlock(req *shared.Request) (interface{}, error) {
args := new(BlockNumArg)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
block := self.xexp.EthBlockByNumber(args.BlockNumber)
if block == nil {
return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
}
stateDb, err := state.New(block.Root(), self.expanse.ChainDb())
if err != nil {
return nil, err
}
return stateDb.RawDump(), nil
}
func (self *debugApi) GetBlockRlp(req *shared.Request) (interface{}, error) {
args := new(BlockNumArg)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
block := self.xexp.EthBlockByNumber(args.BlockNumber)
if block == nil {
return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
}
encoded, err := rlp.EncodeToBytes(block)
return fmt.Sprintf("%x", encoded), err
}
func (self *debugApi) SetHead(req *shared.Request) (interface{}, error) {
args := new(BlockNumArg)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
self.expanse.BlockChain().SetHead(uint64(args.BlockNumber))
return nil, nil
}
func (self *debugApi) ProcessBlock(req *shared.Request) (interface{}, error) {
args := new(BlockNumArg)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
block := self.xexp.EthBlockByNumber(args.BlockNumber)
if block == nil {
return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
}
old := vm.Debug
defer func() { vm.Debug = old }()
vm.Debug = true
var (
blockchain = self.expanse.BlockChain()
validator = blockchain.Validator()
processor = blockchain.Processor()
)
err := core.ValidateHeader(blockchain.AuxValidator(), block.Header(), blockchain.GetHeader(block.ParentHash()), true, false)
if err != nil {
return false, err
}
statedb, err := state.New(blockchain.GetBlock(block.ParentHash()).Root(), self.expanse.ChainDb())
if err != nil {
return false, err
}
receipts, _, usedGas, err := processor.Process(block, statedb)
if err != nil {
return false, err
}
err = validator.ValidateState(block, blockchain.GetBlock(block.ParentHash()), statedb, receipts, usedGas)
if err != nil {
return false, err
}
return true, nil
}
func (self *debugApi) SeedHash(req *shared.Request) (interface{}, error) {
args := new(BlockNumArg)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
if hash, err := ethash.GetSeedHash(uint64(args.BlockNumber)); err == nil {
return fmt.Sprintf("0x%x", hash), nil
} else {
return nil, err
}
}
func (self *debugApi) Metrics(req *shared.Request) (interface{}, error) {
args := new(MetricsArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
// Create a rate formatter
units := []string{"", "K", "M", "G", "T", "E", "P"}
round := func(value float64, prec int) string {
unit := 0
for value >= 1000 {
unit, value, prec = unit+1, value/1000, 2
}
return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value)
}
format := func(total float64, rate float64) string {
return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2))
}
// Iterate over all the metrics, and just dump for now
counters := make(map[string]interface{})
metrics.DefaultRegistry.Each(func(name string, metric interface{}) {
// Create or retrieve the counter hierarchy for this metric
root, parts := counters, strings.Split(name, "/")
for _, part := range parts[:len(parts)-1] {
if _, ok := root[part]; !ok {
root[part] = make(map[string]interface{})
}
root = root[part].(map[string]interface{})
}
name = parts[len(parts)-1]
// Fill the counter with the metric details, formatting if requested
if args.Raw {
switch metric := metric.(type) {
case metrics.Meter:
root[name] = map[string]interface{}{
"AvgRate01Min": metric.Rate1(),
"AvgRate05Min": metric.Rate5(),
"AvgRate15Min": metric.Rate15(),
"MeanRate": metric.RateMean(),
"Overall": float64(metric.Count()),
}
case metrics.Timer:
root[name] = map[string]interface{}{
"AvgRate01Min": metric.Rate1(),
"AvgRate05Min": metric.Rate5(),
"AvgRate15Min": metric.Rate15(),
"MeanRate": metric.RateMean(),
"Overall": float64(metric.Count()),
"Percentiles": map[string]interface{}{
"5": metric.Percentile(0.05),
"20": metric.Percentile(0.2),
"50": metric.Percentile(0.5),
"80": metric.Percentile(0.8),
"95": metric.Percentile(0.95),
},
}
default:
root[name] = "Unknown metric type"
}
} else {
switch metric := metric.(type) {
case metrics.Meter:
root[name] = map[string]interface{}{
"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
"Overall": format(float64(metric.Count()), metric.RateMean()),
}
case metrics.Timer:
root[name] = map[string]interface{}{
"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
"Overall": format(float64(metric.Count()), metric.RateMean()),
"Maximum": time.Duration(metric.Max()).String(),
"Minimum": time.Duration(metric.Min()).String(),
"Percentiles": map[string]interface{}{
"5": time.Duration(metric.Percentile(0.05)).String(),
"20": time.Duration(metric.Percentile(0.2)).String(),
"50": time.Duration(metric.Percentile(0.5)).String(),
"80": time.Duration(metric.Percentile(0.8)).String(),
"95": time.Duration(metric.Percentile(0.95)).String(),
},
}
default:
root[name] = "Unknown metric type"
}
}
})
return counters, nil
}

View file

@ -1,87 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"encoding/json"
"fmt"
"math/big"
"reflect"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type WaitForBlockArgs struct {
MinHeight int
Timeout int // in seconds
}
func (args *WaitForBlockArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) > 2 {
return fmt.Errorf("waitForArgs needs 0, 1, 2 arguments")
}
// default values when not provided
args.MinHeight = -1
args.Timeout = -1
if len(obj) >= 1 {
var minHeight *big.Int
if minHeight, err = numString(obj[0]); err != nil {
return err
}
args.MinHeight = int(minHeight.Int64())
}
if len(obj) >= 2 {
timeout, err := numString(obj[1])
if err != nil {
return err
}
args.Timeout = int(timeout.Int64())
}
return nil
}
type MetricsArgs struct {
Raw bool
}
func (args *MetricsArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) > 1 {
return fmt.Errorf("metricsArgs needs 0, 1 arguments")
}
// default values when not provided
if len(obj) >= 1 && obj[0] != nil {
if value, ok := obj[0].(bool); !ok {
return fmt.Errorf("invalid argument %v", reflect.TypeOf(obj[0]))
} else {
args.Raw = value
}
}
return nil
}

View file

@ -1,71 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
const Debug_JS = `
web3._extend({
property: 'debug',
methods:
[
new web3._extend.Method({
name: 'printBlock',
call: 'debug_printBlock',
params: 1,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
}),
new web3._extend.Method({
name: 'getBlockRlp',
call: 'debug_getBlockRlp',
params: 1,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
}),
new web3._extend.Method({
name: 'setHead',
call: 'debug_setHead',
params: 1,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
}),
new web3._extend.Method({
name: 'processBlock',
call: 'debug_processBlock',
params: 1,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
}),
new web3._extend.Method({
name: 'seedHash',
call: 'debug_seedHash',
params: 1,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
}),
new web3._extend.Method({
name: 'dumpBlock',
call: 'debug_dumpBlock',
params: 1,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
}),
new web3._extend.Method({
name: 'metrics',
call: 'debug_metrics',
params: 1,
inputFormatter: [null]
})
],
properties:
[
]
});
`

View file

@ -1,769 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"bytes"
"encoding/json"
"math/big"
"fmt"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/common/natspec"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/rlp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/xeth"
"gopkg.in/fatih/set.v0"
)
const (
EthApiVersion = "1.0"
)
// exp api provider
// See https://github.com/expanse-project/wiki/wiki/JSON-RPC
type ethApi struct {
xeth *xexp.XEth
expanse *exp.Expanse
methods map[string]ethhandler
codec codec.ApiCoder
}
// exp callback handler
type ethhandler func(*ethApi, *shared.Request) (interface{}, error)
var (
ethMapping = map[string]ethhandler{
"eth_accounts": (*ethApi).Accounts,
"eth_blockNumber": (*ethApi).BlockNumber,
"eth_getBalance": (*ethApi).GetBalance,
"eth_protocolVersion": (*ethApi).ProtocolVersion,
"eth_coinbase": (*ethApi).Coinbase,
"eth_mining": (*ethApi).IsMining,
"eth_syncing": (*ethApi).IsSyncing,
"eth_gasPrice": (*ethApi).GasPrice,
"eth_getStorage": (*ethApi).GetStorage,
"eth_storageAt": (*ethApi).GetStorage,
"eth_getStorageAt": (*ethApi).GetStorageAt,
"eth_getTransactionCount": (*ethApi).GetTransactionCount,
"eth_getBlockTransactionCountByHash": (*ethApi).GetBlockTransactionCountByHash,
"eth_getBlockTransactionCountByNumber": (*ethApi).GetBlockTransactionCountByNumber,
"eth_getUncleCountByBlockHash": (*ethApi).GetUncleCountByBlockHash,
"eth_getUncleCountByBlockNumber": (*ethApi).GetUncleCountByBlockNumber,
"eth_getData": (*ethApi).GetData,
"eth_getCode": (*ethApi).GetData,
"eth_getNatSpec": (*ethApi).GetNatSpec,
"eth_sign": (*ethApi).Sign,
"eth_sendRawTransaction": (*ethApi).SubmitTransaction,
"eth_submitTransaction": (*ethApi).SubmitTransaction,
"eth_sendTransaction": (*ethApi).SendTransaction,
"eth_signTransaction": (*ethApi).SignTransaction,
"eth_transact": (*ethApi).SendTransaction,
"eth_estimateGas": (*ethApi).EstimateGas,
"eth_call": (*ethApi).Call,
"eth_flush": (*ethApi).Flush,
"eth_getBlockByHash": (*ethApi).GetBlockByHash,
"eth_getBlockByNumber": (*ethApi).GetBlockByNumber,
"eth_getTransactionByHash": (*ethApi).GetTransactionByHash,
"eth_getTransactionByBlockNumberAndIndex": (*ethApi).GetTransactionByBlockNumberAndIndex,
"eth_getTransactionByBlockHashAndIndex": (*ethApi).GetTransactionByBlockHashAndIndex,
"eth_getUncleByBlockHashAndIndex": (*ethApi).GetUncleByBlockHashAndIndex,
"eth_getUncleByBlockNumberAndIndex": (*ethApi).GetUncleByBlockNumberAndIndex,
"eth_getCompilers": (*ethApi).GetCompilers,
"eth_compileSolidity": (*ethApi).CompileSolidity,
"eth_newFilter": (*ethApi).NewFilter,
"eth_newBlockFilter": (*ethApi).NewBlockFilter,
"eth_newPendingTransactionFilter": (*ethApi).NewPendingTransactionFilter,
"eth_uninstallFilter": (*ethApi).UninstallFilter,
"eth_getFilterChanges": (*ethApi).GetFilterChanges,
"eth_getFilterLogs": (*ethApi).GetFilterLogs,
"eth_getLogs": (*ethApi).GetLogs,
"eth_hashrate": (*ethApi).Hashrate,
"eth_getWork": (*ethApi).GetWork,
"eth_submitWork": (*ethApi).SubmitWork,
"eth_submitHashrate": (*ethApi).SubmitHashrate,
"eth_resend": (*ethApi).Resend,
"eth_pendingTransactions": (*ethApi).PendingTransactions,
"eth_getTransactionReceipt": (*ethApi).GetTransactionReceipt,
"exp_accounts": (*ethApi).Accounts,
"exp_blockNumber": (*ethApi).BlockNumber,
"exp_getBalance": (*ethApi).GetBalance,
"exp_protocolVersion": (*ethApi).ProtocolVersion,
"exp_coinbase": (*ethApi).Coinbase,
"exp_mining": (*ethApi).IsMining,
"exp_syncing": (*ethApi).IsSyncing,
"exp_gasPrice": (*ethApi).GasPrice,
"exp_getStorage": (*ethApi).GetStorage,
"exp_storageAt": (*ethApi).GetStorage,
"exp_getStorageAt": (*ethApi).GetStorageAt,
"exp_getTransactionCount": (*ethApi).GetTransactionCount,
"exp_getBlockTransactionCountByHash": (*ethApi).GetBlockTransactionCountByHash,
"exp_getBlockTransactionCountByNumber": (*ethApi).GetBlockTransactionCountByNumber,
"exp_getUncleCountByBlockHash": (*ethApi).GetUncleCountByBlockHash,
"exp_getUncleCountByBlockNumber": (*ethApi).GetUncleCountByBlockNumber,
"exp_getData": (*ethApi).GetData,
"exp_getCode": (*ethApi).GetData,
"exp_sign": (*ethApi).Sign,
"exp_sendRawTransaction": (*ethApi).SendTransaction,
"exp_sendTransaction": (*ethApi).SendTransaction,
"exp_transact": (*ethApi).SendTransaction,
"exp_estimateGas": (*ethApi).EstimateGas,
"exp_call": (*ethApi).Call,
"exp_flush": (*ethApi).Flush,
"exp_getBlockByHash": (*ethApi).GetBlockByHash,
"exp_getBlockByNumber": (*ethApi).GetBlockByNumber,
"exp_getTransactionByHash": (*ethApi).GetTransactionByHash,
"exp_getTransactionByBlockNumberAndIndex": (*ethApi).GetTransactionByBlockNumberAndIndex,
"exp_getTransactionByBlockHashAndIndex": (*ethApi).GetTransactionByBlockHashAndIndex,
"exp_getUncleByBlockHashAndIndex": (*ethApi).GetUncleByBlockHashAndIndex,
"exp_getUncleByBlockNumberAndIndex": (*ethApi).GetUncleByBlockNumberAndIndex,
"exp_getCompilers": (*ethApi).GetCompilers,
"exp_compileSolidity": (*ethApi).CompileSolidity,
"exp_newFilter": (*ethApi).NewFilter,
"exp_newBlockFilter": (*ethApi).NewBlockFilter,
"exp_newPendingTransactionFilter": (*ethApi).NewPendingTransactionFilter,
"exp_uninstallFilter": (*ethApi).UninstallFilter,
"exp_getFilterChanges": (*ethApi).GetFilterChanges,
"exp_getFilterLogs": (*ethApi).GetFilterLogs,
"exp_getLogs": (*ethApi).GetLogs,
"exp_hashrate": (*ethApi).Hashrate,
"exp_getWork": (*ethApi).GetWork,
"exp_submitWork": (*ethApi).SubmitWork,
"exp_submitHashrate": (*ethApi).SubmitHashrate,
"exp_resend": (*ethApi).Resend,
"exp_pendingTransactions": (*ethApi).PendingTransactions,
"exp_getTransactionReceipt": (*ethApi).GetTransactionReceipt,
}
)
// create new ethApi instance
func NewEthApi(xeth *xexp.XEth, exp *exp.Expanse, codec codec.Codec) *ethApi {
return &ethApi{xeth, exp, ethMapping, codec.New(nil)}
}
// collection with supported methods
func (self *ethApi) Methods() []string {
methods := make([]string, len(self.methods))
i := 0
for k := range self.methods {
methods[i] = k
i++
}
return methods
}
// Execute given request
func (self *ethApi) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := self.methods[req.Method]; ok {
return callback(self, req)
}
return nil, shared.NewNotImplementedError(req.Method)
}
func (self *ethApi) Name() string {
return shared.EthApiName
}
func (self *ethApi) ApiVersion() string {
return EthApiVersion
}
func (self *ethApi) Accounts(req *shared.Request) (interface{}, error) {
return self.xexp.Accounts(), nil
}
func (self *ethApi) Hashrate(req *shared.Request) (interface{}, error) {
return newHexNum(self.xexp.HashRate()), nil
}
func (self *ethApi) BlockNumber(req *shared.Request) (interface{}, error) {
num := self.xexp.CurrentBlock().Number()
return newHexNum(num.Bytes()), nil
}
func (self *ethApi) GetBalance(req *shared.Request) (interface{}, error) {
args := new(GetBalanceArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
return self.xexp.AtStateNum(args.BlockNumber).BalanceAt(args.Address), nil
}
func (self *ethApi) ProtocolVersion(req *shared.Request) (interface{}, error) {
return self.xexp.EthVersion(), nil
}
func (self *ethApi) Coinbase(req *shared.Request) (interface{}, error) {
return newHexData(self.xexp.Coinbase()), nil
}
func (self *ethApi) IsMining(req *shared.Request) (interface{}, error) {
return self.xexp.IsMining(), nil
}
func (self *ethApi) IsSyncing(req *shared.Request) (interface{}, error) {
origin, current, height := self.expanse.Downloader().Progress()
if current < height {
return map[string]interface{}{
"startingBlock": newHexNum(big.NewInt(int64(origin)).Bytes()),
"currentBlock": newHexNum(big.NewInt(int64(current)).Bytes()),
"highestBlock": newHexNum(big.NewInt(int64(height)).Bytes()),
}, nil
}
return false, nil
}
func (self *ethApi) GasPrice(req *shared.Request) (interface{}, error) {
return newHexNum(self.xexp.DefaultGasPrice().Bytes()), nil
}
func (self *ethApi) GetStorage(req *shared.Request) (interface{}, error) {
args := new(GetStorageArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
return self.xexp.AtStateNum(args.BlockNumber).State().SafeGet(args.Address).Storage(), nil
}
func (self *ethApi) GetStorageAt(req *shared.Request) (interface{}, error) {
args := new(GetStorageAtArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
return self.xexp.AtStateNum(args.BlockNumber).StorageAt(args.Address, args.Key), nil
}
func (self *ethApi) GetTransactionCount(req *shared.Request) (interface{}, error) {
args := new(GetTxCountArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
count := self.xexp.AtStateNum(args.BlockNumber).TxCountAt(args.Address)
return fmt.Sprintf("%#x", count), nil
}
func (self *ethApi) GetBlockTransactionCountByHash(req *shared.Request) (interface{}, error) {
args := new(HashArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
block := self.xexp.EthBlockByHash(args.Hash)
if block == nil {
return nil, nil
}
return fmt.Sprintf("%#x", len(block.Transactions())), nil
}
func (self *ethApi) GetBlockTransactionCountByNumber(req *shared.Request) (interface{}, error) {
args := new(BlockNumArg)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
block := self.xexp.EthBlockByNumber(args.BlockNumber)
if block == nil {
return nil, nil
}
return fmt.Sprintf("%#x", len(block.Transactions())), nil
}
func (self *ethApi) GetUncleCountByBlockHash(req *shared.Request) (interface{}, error) {
args := new(HashArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
block := self.xexp.EthBlockByHash(args.Hash)
if block == nil {
return nil, nil
}
return fmt.Sprintf("%#x", len(block.Uncles())), nil
}
func (self *ethApi) GetUncleCountByBlockNumber(req *shared.Request) (interface{}, error) {
args := new(BlockNumArg)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
block := self.xexp.EthBlockByNumber(args.BlockNumber)
if block == nil {
return nil, nil
}
return fmt.Sprintf("%#x", len(block.Uncles())), nil
}
func (self *ethApi) GetData(req *shared.Request) (interface{}, error) {
args := new(GetDataArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
v := self.xexp.AtStateNum(args.BlockNumber).CodeAtBytes(args.Address)
return newHexData(v), nil
}
func (self *ethApi) Sign(req *shared.Request) (interface{}, error) {
args := new(NewSigArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
v, err := self.xexp.Sign(args.From, args.Data, false)
if err != nil {
return nil, err
}
return v, nil
}
func (self *ethApi) SubmitTransaction(req *shared.Request) (interface{}, error) {
args := new(NewDataArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
v, err := self.xexp.PushTx(args.Data)
if err != nil {
return nil, err
}
return v, nil
}
// JsonTransaction is returned as response by the JSON RPC. It contains the
// signed RLP encoded transaction as Raw and the signed transaction object as Tx.
type JsonTransaction struct {
Raw string `json:"raw"`
Tx *tx `json:"tx"`
}
func (self *ethApi) SignTransaction(req *shared.Request) (interface{}, error) {
args := new(NewTxArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
// nonce may be nil ("guess" mode)
var nonce string
if args.Nonce != nil {
nonce = args.Nonce.String()
}
var gas, price string
if args.Gas != nil {
gas = args.Gas.String()
}
if args.GasPrice != nil {
price = args.GasPrice.String()
}
tx, err := self.xexp.SignTransaction(args.From, args.To, nonce, args.Value.String(), gas, price, args.Data)
if err != nil {
return nil, err
}
data, err := rlp.EncodeToBytes(tx)
if err != nil {
return nil, err
}
return JsonTransaction{"0x" + common.Bytes2Hex(data), newTx(tx)}, nil
}
func (self *ethApi) SendTransaction(req *shared.Request) (interface{}, error) {
args := new(NewTxArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
// nonce may be nil ("guess" mode)
var nonce string
if args.Nonce != nil {
nonce = args.Nonce.String()
}
var gas, price string
if args.Gas != nil {
gas = args.Gas.String()
}
if args.GasPrice != nil {
price = args.GasPrice.String()
}
v, err := self.xexp.Transact(args.From, args.To, nonce, args.Value.String(), gas, price, args.Data)
if err != nil {
return nil, err
}
return v, nil
}
func (self *ethApi) GetNatSpec(req *shared.Request) (interface{}, error) {
args := new(NewTxArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
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.expanse.HTTPClient())
return notice, nil
}
func (self *ethApi) EstimateGas(req *shared.Request) (interface{}, error) {
_, gas, err := self.doCall(req.Params)
if err != nil {
return nil, err
}
// TODO unwrap the parent method's ToHex call
if len(gas) == 0 {
return newHexNum(0), nil
} else {
return newHexNum(common.String2Big(gas)), err
}
}
func (self *ethApi) Call(req *shared.Request) (interface{}, error) {
v, _, err := self.doCall(req.Params)
if err != nil {
return nil, err
}
// TODO unwrap the parent method's ToHex call
if v == "0x0" {
return newHexData([]byte{}), nil
} else {
return newHexData(common.FromHex(v)), nil
}
}
func (self *ethApi) Flush(req *shared.Request) (interface{}, error) {
return nil, shared.NewNotImplementedError(req.Method)
}
func (self *ethApi) doCall(params json.RawMessage) (string, string, error) {
args := new(CallArgs)
if err := self.codec.Decode(params, &args); err != nil {
return "", "", err
}
return self.xexp.AtStateNum(args.BlockNumber).Call(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
}
func (self *ethApi) GetBlockByHash(req *shared.Request) (interface{}, error) {
args := new(GetBlockByHashArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
block := self.xexp.EthBlockByHash(args.BlockHash)
if block == nil {
return nil, nil
}
return NewBlockRes(block, self.xexp.Td(block.Hash()), args.IncludeTxs), nil
}
func (self *ethApi) GetBlockByNumber(req *shared.Request) (interface{}, error) {
args := new(GetBlockByNumberArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
block := self.xexp.EthBlockByNumber(args.BlockNumber)
if block == nil {
return nil, nil
}
return NewBlockRes(block, self.xexp.Td(block.Hash()), args.IncludeTxs), nil
}
func (self *ethApi) GetTransactionByHash(req *shared.Request) (interface{}, error) {
args := new(HashArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
tx, bhash, bnum, txi := self.xexp.EthTransactionByHash(args.Hash)
if tx != nil {
v := NewTransactionRes(tx)
// if the blockhash is 0, assume this is a pending transaction
if bytes.Compare(bhash.Bytes(), bytes.Repeat([]byte{0}, 32)) != 0 {
v.BlockHash = newHexData(bhash)
v.BlockNumber = newHexNum(bnum)
v.TxIndex = newHexNum(txi)
}
return v, nil
}
return nil, nil
}
func (self *ethApi) GetTransactionByBlockHashAndIndex(req *shared.Request) (interface{}, error) {
args := new(HashIndexArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
raw := self.xexp.EthBlockByHash(args.Hash)
if raw == nil {
return nil, nil
}
block := NewBlockRes(raw, self.xexp.Td(raw.Hash()), true)
if args.Index >= int64(len(block.Transactions)) || args.Index < 0 {
return nil, nil
} else {
return block.Transactions[args.Index], nil
}
}
func (self *ethApi) GetTransactionByBlockNumberAndIndex(req *shared.Request) (interface{}, error) {
args := new(BlockNumIndexArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
raw := self.xexp.EthBlockByNumber(args.BlockNumber)
if raw == nil {
return nil, nil
}
block := NewBlockRes(raw, self.xexp.Td(raw.Hash()), true)
if args.Index >= int64(len(block.Transactions)) || args.Index < 0 {
// return NewValidationError("Index", "does not exist")
return nil, nil
}
return block.Transactions[args.Index], nil
}
func (self *ethApi) GetUncleByBlockHashAndIndex(req *shared.Request) (interface{}, error) {
args := new(HashIndexArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
raw := self.xexp.EthBlockByHash(args.Hash)
if raw == nil {
return nil, nil
}
block := NewBlockRes(raw, self.xexp.Td(raw.Hash()), false)
if args.Index >= int64(len(block.Uncles)) || args.Index < 0 {
// return NewValidationError("Index", "does not exist")
return nil, nil
}
return block.Uncles[args.Index], nil
}
func (self *ethApi) GetUncleByBlockNumberAndIndex(req *shared.Request) (interface{}, error) {
args := new(BlockNumIndexArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
raw := self.xexp.EthBlockByNumber(args.BlockNumber)
if raw == nil {
return nil, nil
}
block := NewBlockRes(raw, self.xexp.Td(raw.Hash()), true)
if args.Index >= int64(len(block.Uncles)) || args.Index < 0 {
return nil, nil
} else {
return block.Uncles[args.Index], nil
}
}
func (self *ethApi) GetCompilers(req *shared.Request) (interface{}, error) {
var lang string
if solc, _ := self.xexp.Solc(); solc != nil {
lang = "Solidity"
}
c := []string{lang}
return c, nil
}
func (self *ethApi) CompileSolidity(req *shared.Request) (interface{}, error) {
solc, _ := self.xexp.Solc()
if solc == nil {
return nil, shared.NewNotAvailableError(req.Method, "solc (solidity compiler) not found")
}
args := new(SourceArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
contracts, err := solc.Compile(args.Source)
if err != nil {
return nil, err
}
return contracts, nil
}
func (self *ethApi) NewFilter(req *shared.Request) (interface{}, error) {
args := new(BlockFilterArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
id := self.xexp.NewLogFilter(args.Earliest, args.Latest, args.Skip, args.Max, args.Address, args.Topics)
return newHexNum(big.NewInt(int64(id)).Bytes()), nil
}
func (self *ethApi) NewBlockFilter(req *shared.Request) (interface{}, error) {
return newHexNum(self.xexp.NewBlockFilter()), nil
}
func (self *ethApi) NewPendingTransactionFilter(req *shared.Request) (interface{}, error) {
return newHexNum(self.xexp.NewTransactionFilter()), nil
}
func (self *ethApi) UninstallFilter(req *shared.Request) (interface{}, error) {
args := new(FilterIdArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
return self.xexp.UninstallFilter(args.Id), nil
}
func (self *ethApi) GetFilterChanges(req *shared.Request) (interface{}, error) {
args := new(FilterIdArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
switch self.xexp.GetFilterType(args.Id) {
case xexp.BlockFilterTy:
return NewHashesRes(self.xexp.BlockFilterChanged(args.Id)), nil
case xexp.TransactionFilterTy:
return NewHashesRes(self.xexp.TransactionFilterChanged(args.Id)), nil
case xexp.LogFilterTy:
return NewLogsRes(self.xexp.LogFilterChanged(args.Id)), nil
default:
return []string{}, nil // reply empty string slice
}
}
func (self *ethApi) GetFilterLogs(req *shared.Request) (interface{}, error) {
args := new(FilterIdArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
return NewLogsRes(self.xexp.Logs(args.Id)), nil
}
func (self *ethApi) GetLogs(req *shared.Request) (interface{}, error) {
args := new(BlockFilterArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
return NewLogsRes(self.xexp.AllLogs(args.Earliest, args.Latest, args.Skip, args.Max, args.Address, args.Topics)), nil
}
func (self *ethApi) GetWork(req *shared.Request) (interface{}, error) {
self.xexp.SetMining(true, 0)
ret, err := self.xexp.RemoteMining().GetWork()
if err != nil {
return nil, shared.NewNotReadyError("mining work")
} else {
return ret, nil
}
}
func (self *ethApi) SubmitWork(req *shared.Request) (interface{}, error) {
args := new(SubmitWorkArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
return self.xexp.RemoteMining().SubmitWork(args.Nonce, common.HexToHash(args.Digest), common.HexToHash(args.Header)), nil
}
func (self *ethApi) SubmitHashrate(req *shared.Request) (interface{}, error) {
args := new(SubmitHashRateArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return false, shared.NewDecodeParamError(err.Error())
}
self.xexp.RemoteMining().SubmitHashrate(common.HexToHash(args.Id), args.Rate)
return true, nil
}
func (self *ethApi) Resend(req *shared.Request) (interface{}, error) {
args := new(ResendArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
from := common.HexToAddress(args.Tx.From)
pending := self.expanse.TxPool().GetTransactions()
for _, p := range pending {
if pFrom, err := p.FromFrontier(); err == nil && pFrom == from && p.SigHash() == args.Tx.tx.SigHash() {
self.expanse.TxPool().RemoveTx(common.HexToHash(args.Tx.Hash))
return self.xexp.Transact(args.Tx.From, args.Tx.To, args.Tx.Nonce, args.Tx.Value, args.GasLimit, args.GasPrice, args.Tx.Data)
}
}
return nil, fmt.Errorf("Transaction %s not found", args.Tx.Hash)
}
func (self *ethApi) PendingTransactions(req *shared.Request) (interface{}, error) {
txs := self.expanse.TxPool().GetTransactions()
// grab the accounts from the account manager. This will help with determining which
// transactions should be returned.
accounts, err := self.expanse.AccountManager().Accounts()
if err != nil {
return nil, err
}
// Add the accouns to a new set
accountSet := set.New()
for _, account := range accounts {
accountSet.Add(account.Address)
}
var ltxs []*tx
for _, tx := range txs {
if from, _ := tx.FromFrontier(); accountSet.Has(from) {
ltxs = append(ltxs, newTx(tx))
}
}
return ltxs, nil
}
func (self *ethApi) GetTransactionReceipt(req *shared.Request) (interface{}, error) {
args := new(HashArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
txhash := common.BytesToHash(common.FromHex(args.Hash))
tx, bhash, bnum, txi := self.xexp.EthTransactionByHash(args.Hash)
rec := self.xexp.GetTxReceipt(txhash)
// We could have an error of "not found". Should disambiguate
// if err != nil {
// return err, nil
// }
if rec != nil && tx != nil {
v := NewReceiptRes(rec)
v.BlockHash = newHexData(bhash)
v.BlockNumber = newHexNum(bnum)
v.TransactionIndex = newHexNum(txi)
return v, nil
}
return nil, nil
}

File diff suppressed because it is too large Load diff

View file

@ -1,66 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
// JS api provided by web3.js
// eth_sign not standard
const Eth_JS = `
web3._extend({
property: 'exp',
methods:
[
new web3._extend.Method({
name: 'sign',
call: 'eth_sign',
params: 2,
inputFormatter: [web3._extend.utils.toAddress, null]
}),
new web3._extend.Method({
name: 'resend',
call: 'eth_resend',
params: 3,
inputFormatter: [web3._extend.formatters.inputTransactionFormatter, web3._extend.utils.fromDecimal, web3._extend.utils.fromDecimal]
}),
new web3._extend.Method({
name: 'getNatSpec',
call: 'eth_getNatSpec',
params: 1,
inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'signTransaction',
call: 'eth_signTransaction',
params: 1,
inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'submitTransaction',
call: 'eth_submitTransaction',
params: 1,
inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
})
],
properties:
[
new web3._extend.Property({
name: 'pendingTransactions',
getter: 'eth_pendingTransactions'
})
]
});
`

View file

@ -1,86 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rpc/shared"
)
const (
MergedApiVersion = "1.0"
)
// combines multiple API's
type MergedApi struct {
apis map[string]string
methods map[string]shared.ExpanseApi
}
// create new merged api instance
func newMergedApi(apis ...shared.ExpanseApi) *MergedApi {
mergedApi := new(MergedApi)
mergedApi.apis = make(map[string]string, len(apis))
mergedApi.methods = make(map[string]shared.ExpanseApi)
for _, api := range apis {
mergedApi.apis[api.Name()] = api.ApiVersion()
for _, method := range api.Methods() {
mergedApi.methods[method] = api
}
}
return mergedApi
}
// Supported RPC methods
func (self *MergedApi) Methods() []string {
all := make([]string, len(self.methods))
for method, _ := range self.methods {
all = append(all, method)
}
return all
}
// Call the correct API's Execute method for the given request
func (self *MergedApi) Execute(req *shared.Request) (interface{}, error) {
glog.V(logger.Detail).Infof("%s %s", req.Method, req.Params)
if res, _ := self.handle(req); res != nil {
return res, nil
}
if api, found := self.methods[req.Method]; found {
return api.Execute(req)
}
return nil, shared.NewNotImplementedError(req.Method)
}
func (self *MergedApi) Name() string {
return shared.MergedApiName
}
func (self *MergedApi) ApiVersion() string {
return MergedApiVersion
}
func (self *MergedApi) handle(req *shared.Request) (interface{}, error) {
if req.Method == "modules" { // provided API's
return self.apis, nil
}
return nil, nil
}

View file

@ -1,177 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"github.com/expanse-org/ethash"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
)
const (
MinerApiVersion = "1.0"
)
var (
// mapping between methods and handlers
MinerMapping = map[string]minerhandler{
"miner_hashrate": (*minerApi).Hashrate,
"miner_makeDAG": (*minerApi).MakeDAG,
"miner_setExtra": (*minerApi).SetExtra,
"miner_setGasPrice": (*minerApi).SetGasPrice,
"miner_setEtherbase": (*minerApi).SetEtherbase,
"miner_startAutoDAG": (*minerApi).StartAutoDAG,
"miner_start": (*minerApi).StartMiner,
"miner_stopAutoDAG": (*minerApi).StopAutoDAG,
"miner_stop": (*minerApi).StopMiner,
}
)
// miner callback handler
type minerhandler func(*minerApi, *shared.Request) (interface{}, error)
// miner api provider
type minerApi struct {
expanse *exp.Expanse
methods map[string]minerhandler
codec codec.ApiCoder
}
// create a new miner api instance
func NewMinerApi(expanse *exp.Expanse, coder codec.Codec) *minerApi {
return &minerApi{
expanse: expanse,
methods: MinerMapping,
codec: coder.New(nil),
}
}
// Execute given request
func (self *minerApi) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := self.methods[req.Method]; ok {
return callback(self, req)
}
return nil, &shared.NotImplementedError{req.Method}
}
// collection with supported methods
func (self *minerApi) Methods() []string {
methods := make([]string, len(self.methods))
i := 0
for k := range self.methods {
methods[i] = k
i++
}
return methods
}
func (self *minerApi) Name() string {
return shared.MinerApiName
}
func (self *minerApi) ApiVersion() string {
return MinerApiVersion
}
func (self *minerApi) StartMiner(req *shared.Request) (interface{}, error) {
args := new(StartMinerArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, err
}
if args.Threads == -1 { // (not specified by user, use default)
args.Threads = self.expanse.MinerThreads
}
self.expanse.StartAutoDAG()
err := self.expanse.StartMining(args.Threads, "")
if err == nil {
return true, nil
}
return false, err
}
func (self *minerApi) StopMiner(req *shared.Request) (interface{}, error) {
self.expanse.StopMining()
return true, nil
}
func (self *minerApi) Hashrate(req *shared.Request) (interface{}, error) {
return self.expanse.Miner().HashRate(), nil
}
func (self *minerApi) SetExtra(req *shared.Request) (interface{}, error) {
args := new(SetExtraArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, err
}
if err := self.expanse.Miner().SetExtra([]byte(args.Data)); err != nil {
return false, err
}
return true, nil
}
func (self *minerApi) SetGasPrice(req *shared.Request) (interface{}, error) {
args := new(GasPriceArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return false, err
}
self.expanse.Miner().SetGasPrice(common.String2Big(args.Price))
return true, nil
}
func (self *minerApi) SetEtherbase(req *shared.Request) (interface{}, error) {
args := new(SetEtherbaseArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return false, err
}
self.expanse.SetEtherbase(args.Etherbase)
return nil, nil
}
func (self *minerApi) StartAutoDAG(req *shared.Request) (interface{}, error) {
self.expanse.StartAutoDAG()
return true, nil
}
func (self *minerApi) StopAutoDAG(req *shared.Request) (interface{}, error) {
self.expanse.StopAutoDAG()
return true, nil
}
func (self *minerApi) MakeDAG(req *shared.Request) (interface{}, error) {
args := new(MakeDAGArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, err
}
if args.BlockNumber < 0 {
return false, shared.NewValidationError("BlockNumber", "BlockNumber must be positive")
}
err := ethash.MakeDAG(uint64(args.BlockNumber), "")
if err == nil {
return true, nil
}
return false, err
}

View file

@ -1,142 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"encoding/json"
"math/big"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type StartMinerArgs struct {
Threads int
}
func (args *StartMinerArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) == 0 || obj[0] == nil {
args.Threads = -1
return nil
}
var num *big.Int
if num, err = numString(obj[0]); err != nil {
return err
}
args.Threads = int(num.Int64())
return nil
}
type SetExtraArgs struct {
Data string
}
func (args *SetExtraArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
extrastr, ok := obj[0].(string)
if !ok {
return shared.NewInvalidTypeError("Price", "not a string")
}
args.Data = extrastr
return nil
}
type GasPriceArgs struct {
Price string
}
func (args *GasPriceArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
if pricestr, ok := obj[0].(string); ok {
args.Price = pricestr
return nil
}
return shared.NewInvalidTypeError("Price", "not a string")
}
type SetEtherbaseArgs struct {
Etherbase common.Address
}
func (args *SetEtherbaseArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
if addr, ok := obj[0].(string); ok {
args.Etherbase = common.HexToAddress(addr)
if (args.Etherbase == common.Address{}) {
return shared.NewInvalidTypeError("Etherbase", "not a valid address")
}
return nil
}
return shared.NewInvalidTypeError("Etherbase", "not a string")
}
type MakeDAGArgs struct {
BlockNumber int64
}
func (args *MakeDAGArgs) UnmarshalJSON(b []byte) (err error) {
args.BlockNumber = -1
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
if err := blockHeight(obj[0], &args.BlockNumber); err != nil {
return err
}
return nil
}

View file

@ -1,83 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
const Miner_JS = `
web3._extend({
property: 'miner',
methods:
[
new web3._extend.Method({
name: 'start',
call: 'miner_start',
params: 1,
inputFormatter: [null]
}),
new web3._extend.Method({
name: 'stop',
call: 'miner_stop',
params: 1,
inputFormatter: [null]
}),
new web3._extend.Method({
name: 'setEtherbase',
call: 'miner_setEtherbase',
params: 1,
inputFormatter: [web3._extend.formatters.formatInputInt],
outputFormatter: web3._extend.formatters.formatOutputBool
}),
new web3._extend.Method({
name: 'setExtra',
call: 'miner_setExtra',
params: 1,
inputFormatter: [null]
}),
new web3._extend.Method({
name: 'setGasPrice',
call: 'miner_setGasPrice',
params: 1,
inputFormatter: [web3._extend.utils.fromDecial]
}),
new web3._extend.Method({
name: 'startAutoDAG',
call: 'miner_startAutoDAG',
params: 0,
inputFormatter: []
}),
new web3._extend.Method({
name: 'stopAutoDAG',
call: 'miner_stopAutoDAG',
params: 0,
inputFormatter: []
}),
new web3._extend.Method({
name: 'makeDAG',
call: 'miner_makeDAG',
params: 1,
inputFormatter: [web3._extend.formatters.inputDefaultBlockNumberFormatter]
})
],
properties:
[
new web3._extend.Property({
name: 'hashrate',
getter: 'miner_hashrate',
outputFormatter: web3._extend.utils.toDecimal
})
]
});
`

View file

@ -1,99 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/xeth"
)
const (
NetApiVersion = "1.0"
)
var (
// mapping between methods and handlers
netMapping = map[string]nethandler{
"net_peerCount": (*netApi).PeerCount,
"net_listening": (*netApi).IsListening,
"net_version": (*netApi).Version,
}
)
// net callback handler
type nethandler func(*netApi, *shared.Request) (interface{}, error)
// net api provider
type netApi struct {
xeth *xexp.XEth
expanse *exp.Expanse
methods map[string]nethandler
codec codec.ApiCoder
}
// create a new net api instance
func NewNetApi(xeth *xexp.XEth, exp *exp.Expanse, coder codec.Codec) *netApi {
return &netApi{
xeth: xeth,
expanse: exp,
methods: netMapping,
codec: coder.New(nil),
}
}
// collection with supported methods
func (self *netApi) Methods() []string {
methods := make([]string, len(self.methods))
i := 0
for k := range self.methods {
methods[i] = k
i++
}
return methods
}
// Execute given request
func (self *netApi) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := self.methods[req.Method]; ok {
return callback(self, req)
}
return nil, shared.NewNotImplementedError(req.Method)
}
func (self *netApi) Name() string {
return shared.NetApiName
}
func (self *netApi) ApiVersion() string {
return NetApiVersion
}
// Number of connected peers
func (self *netApi) PeerCount(req *shared.Request) (interface{}, error) {
return newHexNum(self.xexp.PeerCount()), nil
}
func (self *netApi) IsListening(req *shared.Request) (interface{}, error) {
return self.xexp.IsListening(), nil
}
func (self *netApi) Version(req *shared.Request) (interface{}, error) {
return self.xexp.NetworkVersion(), nil
}

View file

@ -1,522 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"bytes"
"encoding/binary"
"encoding/hex"
"encoding/json"
"math/big"
"strings"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/core/types"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type hexdata struct {
data []byte
isNil bool
}
func (d *hexdata) String() string {
return "0x" + common.Bytes2Hex(d.data)
}
func (d *hexdata) MarshalJSON() ([]byte, error) {
if d.isNil {
return json.Marshal(nil)
}
return json.Marshal(d.String())
}
func newHexData(input interface{}) *hexdata {
d := new(hexdata)
if input == nil {
d.isNil = true
return d
}
switch input := input.(type) {
case []byte:
d.data = input
case common.Hash:
d.data = input.Bytes()
case *common.Hash:
if input == nil {
d.isNil = true
} else {
d.data = input.Bytes()
}
case common.Address:
d.data = input.Bytes()
case *common.Address:
if input == nil {
d.isNil = true
} else {
d.data = input.Bytes()
}
case types.Bloom:
d.data = input.Bytes()
case *types.Bloom:
if input == nil {
d.isNil = true
} else {
d.data = input.Bytes()
}
case *big.Int:
if input == nil {
d.isNil = true
} else {
d.data = input.Bytes()
}
case int64:
d.data = big.NewInt(input).Bytes()
case uint64:
buff := make([]byte, 8)
binary.BigEndian.PutUint64(buff, input)
d.data = buff
case int:
d.data = big.NewInt(int64(input)).Bytes()
case uint:
d.data = big.NewInt(int64(input)).Bytes()
case int8:
d.data = big.NewInt(int64(input)).Bytes()
case uint8:
d.data = big.NewInt(int64(input)).Bytes()
case int16:
d.data = big.NewInt(int64(input)).Bytes()
case uint16:
buff := make([]byte, 2)
binary.BigEndian.PutUint16(buff, input)
d.data = buff
case int32:
d.data = big.NewInt(int64(input)).Bytes()
case uint32:
buff := make([]byte, 4)
binary.BigEndian.PutUint32(buff, input)
d.data = buff
case string: // hexstring
// aaargh ffs TODO: avoid back-and-forth hex encodings where unneeded
bytes, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
if err != nil {
d.isNil = true
} else {
d.data = bytes
}
default:
d.isNil = true
}
return d
}
type hexnum struct {
data []byte
isNil bool
}
func (d *hexnum) String() string {
// Get hex string from bytes
out := common.Bytes2Hex(d.data)
// Trim leading 0s
out = strings.TrimLeft(out, "0")
// Output "0x0" when value is 0
if len(out) == 0 {
out = "0"
}
return "0x" + out
}
func (d *hexnum) MarshalJSON() ([]byte, error) {
if d.isNil {
return json.Marshal(nil)
}
return json.Marshal(d.String())
}
func newHexNum(input interface{}) *hexnum {
d := new(hexnum)
d.data = newHexData(input).data
return d
}
type BlockRes struct {
fullTx bool
BlockNumber *hexnum `json:"number"`
BlockHash *hexdata `json:"hash"`
ParentHash *hexdata `json:"parentHash"`
Nonce *hexdata `json:"nonce"`
Sha3Uncles *hexdata `json:"sha3Uncles"`
LogsBloom *hexdata `json:"logsBloom"`
TransactionRoot *hexdata `json:"transactionsRoot"`
StateRoot *hexdata `json:"stateRoot"`
ReceiptRoot *hexdata `json:"receiptRoot"`
Miner *hexdata `json:"miner"`
Difficulty *hexnum `json:"difficulty"`
TotalDifficulty *hexnum `json:"totalDifficulty"`
Size *hexnum `json:"size"`
ExtraData *hexdata `json:"extraData"`
GasLimit *hexnum `json:"gasLimit"`
GasUsed *hexnum `json:"gasUsed"`
UnixTimestamp *hexnum `json:"timestamp"`
Transactions []*TransactionRes `json:"transactions"`
Uncles []*UncleRes `json:"uncles"`
}
func (b *BlockRes) MarshalJSON() ([]byte, error) {
if b.fullTx {
var ext struct {
BlockNumber *hexnum `json:"number"`
BlockHash *hexdata `json:"hash"`
ParentHash *hexdata `json:"parentHash"`
Nonce *hexdata `json:"nonce"`
Sha3Uncles *hexdata `json:"sha3Uncles"`
LogsBloom *hexdata `json:"logsBloom"`
TransactionRoot *hexdata `json:"transactionsRoot"`
StateRoot *hexdata `json:"stateRoot"`
ReceiptRoot *hexdata `json:"receiptRoot"`
Miner *hexdata `json:"miner"`
Difficulty *hexnum `json:"difficulty"`
TotalDifficulty *hexnum `json:"totalDifficulty"`
Size *hexnum `json:"size"`
ExtraData *hexdata `json:"extraData"`
GasLimit *hexnum `json:"gasLimit"`
GasUsed *hexnum `json:"gasUsed"`
UnixTimestamp *hexnum `json:"timestamp"`
Transactions []*TransactionRes `json:"transactions"`
Uncles []*hexdata `json:"uncles"`
}
ext.BlockNumber = b.BlockNumber
ext.BlockHash = b.BlockHash
ext.ParentHash = b.ParentHash
ext.Nonce = b.Nonce
ext.Sha3Uncles = b.Sha3Uncles
ext.LogsBloom = b.LogsBloom
ext.TransactionRoot = b.TransactionRoot
ext.StateRoot = b.StateRoot
ext.ReceiptRoot = b.ReceiptRoot
ext.Miner = b.Miner
ext.Difficulty = b.Difficulty
ext.TotalDifficulty = b.TotalDifficulty
ext.Size = b.Size
ext.ExtraData = b.ExtraData
ext.GasLimit = b.GasLimit
ext.GasUsed = b.GasUsed
ext.UnixTimestamp = b.UnixTimestamp
ext.Transactions = b.Transactions
ext.Uncles = make([]*hexdata, len(b.Uncles))
for i, u := range b.Uncles {
ext.Uncles[i] = u.BlockHash
}
return json.Marshal(ext)
} else {
var ext struct {
BlockNumber *hexnum `json:"number"`
BlockHash *hexdata `json:"hash"`
ParentHash *hexdata `json:"parentHash"`
Nonce *hexdata `json:"nonce"`
Sha3Uncles *hexdata `json:"sha3Uncles"`
LogsBloom *hexdata `json:"logsBloom"`
TransactionRoot *hexdata `json:"transactionsRoot"`
StateRoot *hexdata `json:"stateRoot"`
ReceiptRoot *hexdata `json:"receiptRoot"`
Miner *hexdata `json:"miner"`
Difficulty *hexnum `json:"difficulty"`
TotalDifficulty *hexnum `json:"totalDifficulty"`
Size *hexnum `json:"size"`
ExtraData *hexdata `json:"extraData"`
GasLimit *hexnum `json:"gasLimit"`
GasUsed *hexnum `json:"gasUsed"`
UnixTimestamp *hexnum `json:"timestamp"`
Transactions []*hexdata `json:"transactions"`
Uncles []*hexdata `json:"uncles"`
}
ext.BlockNumber = b.BlockNumber
ext.BlockHash = b.BlockHash
ext.ParentHash = b.ParentHash
ext.Nonce = b.Nonce
ext.Sha3Uncles = b.Sha3Uncles
ext.LogsBloom = b.LogsBloom
ext.TransactionRoot = b.TransactionRoot
ext.StateRoot = b.StateRoot
ext.ReceiptRoot = b.ReceiptRoot
ext.Miner = b.Miner
ext.Difficulty = b.Difficulty
ext.TotalDifficulty = b.TotalDifficulty
ext.Size = b.Size
ext.ExtraData = b.ExtraData
ext.GasLimit = b.GasLimit
ext.GasUsed = b.GasUsed
ext.UnixTimestamp = b.UnixTimestamp
ext.Transactions = make([]*hexdata, len(b.Transactions))
for i, tx := range b.Transactions {
ext.Transactions[i] = tx.Hash
}
ext.Uncles = make([]*hexdata, len(b.Uncles))
for i, u := range b.Uncles {
ext.Uncles[i] = u.BlockHash
}
return json.Marshal(ext)
}
}
func NewBlockRes(block *types.Block, td *big.Int, fullTx bool) *BlockRes {
if block == nil {
return nil
}
res := new(BlockRes)
res.fullTx = fullTx
res.BlockNumber = newHexNum(block.Number())
res.BlockHash = newHexData(block.Hash())
res.ParentHash = newHexData(block.ParentHash())
res.Nonce = newHexData(block.Nonce())
res.Sha3Uncles = newHexData(block.UncleHash())
res.LogsBloom = newHexData(block.Bloom())
res.TransactionRoot = newHexData(block.TxHash())
res.StateRoot = newHexData(block.Root())
res.ReceiptRoot = newHexData(block.ReceiptHash())
res.Miner = newHexData(block.Coinbase())
res.Difficulty = newHexNum(block.Difficulty())
res.TotalDifficulty = newHexNum(td)
res.Size = newHexNum(block.Size().Int64())
res.ExtraData = newHexData(block.Extra())
res.GasLimit = newHexNum(block.GasLimit())
res.GasUsed = newHexNum(block.GasUsed())
res.UnixTimestamp = newHexNum(block.Time())
txs := block.Transactions()
res.Transactions = make([]*TransactionRes, len(txs))
for i, tx := range txs {
res.Transactions[i] = NewTransactionRes(tx)
res.Transactions[i].BlockHash = res.BlockHash
res.Transactions[i].BlockNumber = res.BlockNumber
res.Transactions[i].TxIndex = newHexNum(i)
}
uncles := block.Uncles()
res.Uncles = make([]*UncleRes, len(uncles))
for i, uncle := range uncles {
res.Uncles[i] = NewUncleRes(uncle)
}
return res
}
type TransactionRes struct {
Hash *hexdata `json:"hash"`
Nonce *hexnum `json:"nonce"`
BlockHash *hexdata `json:"blockHash"`
BlockNumber *hexnum `json:"blockNumber"`
TxIndex *hexnum `json:"transactionIndex"`
From *hexdata `json:"from"`
To *hexdata `json:"to"`
Value *hexnum `json:"value"`
Gas *hexnum `json:"gas"`
GasPrice *hexnum `json:"gasPrice"`
Input *hexdata `json:"input"`
}
func NewTransactionRes(tx *types.Transaction) *TransactionRes {
if tx == nil {
return nil
}
var v = new(TransactionRes)
v.Hash = newHexData(tx.Hash())
v.Nonce = newHexNum(tx.Nonce())
// v.BlockHash =
// v.BlockNumber =
// v.TxIndex =
from, _ := tx.FromFrontier()
v.From = newHexData(from)
v.To = newHexData(tx.To())
v.Value = newHexNum(tx.Value())
v.Gas = newHexNum(tx.Gas())
v.GasPrice = newHexNum(tx.GasPrice())
v.Input = newHexData(tx.Data())
return v
}
type UncleRes struct {
BlockNumber *hexnum `json:"number"`
BlockHash *hexdata `json:"hash"`
ParentHash *hexdata `json:"parentHash"`
Nonce *hexdata `json:"nonce"`
Sha3Uncles *hexdata `json:"sha3Uncles"`
ReceiptHash *hexdata `json:"receiptHash"`
LogsBloom *hexdata `json:"logsBloom"`
TransactionRoot *hexdata `json:"transactionsRoot"`
StateRoot *hexdata `json:"stateRoot"`
Miner *hexdata `json:"miner"`
Difficulty *hexnum `json:"difficulty"`
ExtraData *hexdata `json:"extraData"`
GasLimit *hexnum `json:"gasLimit"`
GasUsed *hexnum `json:"gasUsed"`
UnixTimestamp *hexnum `json:"timestamp"`
}
func NewUncleRes(h *types.Header) *UncleRes {
if h == nil {
return nil
}
var v = new(UncleRes)
v.BlockNumber = newHexNum(h.Number)
v.BlockHash = newHexData(h.Hash())
v.ParentHash = newHexData(h.ParentHash)
v.Sha3Uncles = newHexData(h.UncleHash)
v.Nonce = newHexData(h.Nonce[:])
v.LogsBloom = newHexData(h.Bloom)
v.TransactionRoot = newHexData(h.TxHash)
v.StateRoot = newHexData(h.Root)
v.Miner = newHexData(h.Coinbase)
v.Difficulty = newHexNum(h.Difficulty)
v.ExtraData = newHexData(h.Extra)
v.GasLimit = newHexNum(h.GasLimit)
v.GasUsed = newHexNum(h.GasUsed)
v.UnixTimestamp = newHexNum(h.Time)
v.ReceiptHash = newHexData(h.ReceiptHash)
return v
}
// type FilterLogRes struct {
// Hash string `json:"hash"`
// Address string `json:"address"`
// Data string `json:"data"`
// BlockNumber string `json:"blockNumber"`
// TransactionHash string `json:"transactionHash"`
// BlockHash string `json:"blockHash"`
// TransactionIndex string `json:"transactionIndex"`
// LogIndex string `json:"logIndex"`
// }
// type FilterWhisperRes struct {
// Hash string `json:"hash"`
// From string `json:"from"`
// To string `json:"to"`
// Expiry string `json:"expiry"`
// Sent string `json:"sent"`
// Ttl string `json:"ttl"`
// Topics string `json:"topics"`
// Payload string `json:"payload"`
// WorkProved string `json:"workProved"`
// }
type ReceiptRes struct {
TransactionHash *hexdata `json:"transactionHash"`
TransactionIndex *hexnum `json:"transactionIndex"`
BlockNumber *hexnum `json:"blockNumber"`
BlockHash *hexdata `json:"blockHash"`
CumulativeGasUsed *hexnum `json:"cumulativeGasUsed"`
GasUsed *hexnum `json:"gasUsed"`
ContractAddress *hexdata `json:"contractAddress"`
Logs *[]interface{} `json:"logs"`
}
func NewReceiptRes(rec *types.Receipt) *ReceiptRes {
if rec == nil {
return nil
}
var v = new(ReceiptRes)
v.TransactionHash = newHexData(rec.TxHash)
if rec.GasUsed != nil {
v.GasUsed = newHexNum(rec.GasUsed.Bytes())
}
v.CumulativeGasUsed = newHexNum(rec.CumulativeGasUsed)
// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
if bytes.Compare(rec.ContractAddress.Bytes(), bytes.Repeat([]byte{0}, 20)) != 0 {
v.ContractAddress = newHexData(rec.ContractAddress)
}
logs := make([]interface{}, len(rec.Logs))
for i, log := range rec.Logs {
logs[i] = NewLogRes(log)
}
v.Logs = &logs
return v
}
func numString(raw interface{}) (*big.Int, error) {
var number *big.Int
// Parse as integer
num, ok := raw.(float64)
if ok {
number = big.NewInt(int64(num))
return number, nil
}
// Parse as string/hexstring
str, ok := raw.(string)
if ok {
number = common.String2Big(str)
return number, nil
}
return nil, shared.NewInvalidTypeError("", "not a number or string")
}
func blockHeight(raw interface{}, number *int64) error {
// Parse as integer
num, ok := raw.(float64)
if ok {
*number = int64(num)
return nil
}
// Parse as string/hexstring
str, ok := raw.(string)
if !ok {
return shared.NewInvalidTypeError("", "not a number or string")
}
switch str {
case "earliest":
*number = 0
case "latest":
*number = -1
case "pending":
*number = -2
default:
if common.HasHexPrefix(str) {
*number = common.String2Big(str).Int64()
} else {
return shared.NewInvalidTypeError("blockNumber", "is not a valid string")
}
}
return nil
}
func blockHeightFromJson(msg json.RawMessage, number *int64) error {
var raw interface{}
if err := json.Unmarshal(msg, &raw); err != nil {
return shared.NewDecodeParamError(err.Error())
}
return blockHeight(raw, number)
}

View file

@ -1,139 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"fmt"
"time"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/xeth"
)
const (
PersonalApiVersion = "1.0"
)
var (
// mapping between methods and handlers
personalMapping = map[string]personalhandler{
"personal_listAccounts": (*personalApi).ListAccounts,
"personal_newAccount": (*personalApi).NewAccount,
"personal_unlockAccount": (*personalApi).UnlockAccount,
}
)
// net callback handler
type personalhandler func(*personalApi, *shared.Request) (interface{}, error)
// net api provider
type personalApi struct {
xeth *xexp.XEth
expanse *exp.Expanse
methods map[string]personalhandler
codec codec.ApiCoder
}
// create a new net api instance
func NewPersonalApi(xeth *xexp.XEth, exp *exp.Expanse, coder codec.Codec) *personalApi {
return &personalApi{
xeth: xeth,
expanse: exp,
methods: personalMapping,
codec: coder.New(nil),
}
}
// collection with supported methods
func (self *personalApi) Methods() []string {
methods := make([]string, len(self.methods))
i := 0
for k := range self.methods {
methods[i] = k
i++
}
return methods
}
// Execute given request
func (self *personalApi) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := self.methods[req.Method]; ok {
return callback(self, req)
}
return nil, shared.NewNotImplementedError(req.Method)
}
func (self *personalApi) Name() string {
return shared.PersonalApiName
}
func (self *personalApi) ApiVersion() string {
return PersonalApiVersion
}
func (self *personalApi) ListAccounts(req *shared.Request) (interface{}, error) {
return self.xexp.Accounts(), nil
}
func (self *personalApi) NewAccount(req *shared.Request) (interface{}, error) {
args := new(NewAccountArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
var passwd string
if args.Passphrase == nil {
fe := self.xexp.Frontend()
if fe == nil {
return false, fmt.Errorf("unable to create account: unable to interact with user")
}
var ok bool
passwd, ok = fe.AskPassword()
if !ok {
return false, fmt.Errorf("unable to create account: no password given")
}
} else {
passwd = *args.Passphrase
}
am := self.expanse.AccountManager()
acc, err := am.NewAccount(passwd)
return acc.Address.Hex(), err
}
func (self *personalApi) UnlockAccount(req *shared.Request) (interface{}, error) {
args := new(UnlockAccountArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
if args.Passphrase == nil {
fe := self.xexp.Frontend()
if fe == nil {
return false, fmt.Errorf("No password provided")
}
return fe.UnlockAccount(common.HexToAddress(args.Address).Bytes()), nil
}
am := self.expanse.AccountManager()
addr := common.HexToAddress(args.Address)
err := am.TimedUnlock(addr, *args.Passphrase, time.Duration(args.Duration)*time.Second)
return err == nil, err
}

View file

@ -1,85 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"encoding/json"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type NewAccountArgs struct {
Passphrase *string
}
func (args *NewAccountArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) >= 1 && obj[0] != nil {
if passphrasestr, ok := obj[0].(string); ok {
args.Passphrase = &passphrasestr
} else {
return shared.NewInvalidTypeError("passphrase", "not a string")
}
}
return nil
}
type UnlockAccountArgs struct {
Address string
Passphrase *string
Duration int
}
func (args *UnlockAccountArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
args.Duration = 0
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
if addrstr, ok := obj[0].(string); ok {
args.Address = addrstr
} else {
return shared.NewInvalidTypeError("address", "not a string")
}
if len(obj) >= 2 && obj[1] != nil {
if passphrasestr, ok := obj[1].(string); ok {
args.Passphrase = &passphrasestr
} else {
return shared.NewInvalidTypeError("passphrase", "not a string")
}
}
if len(obj) >= 3 && obj[2] != nil {
if duration, ok := obj[2].(float64); ok {
args.Duration = int(duration)
}
}
return nil
}

View file

@ -1,46 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
const Personal_JS = `
web3._extend({
property: 'personal',
methods:
[
new web3._extend.Method({
name: 'newAccount',
call: 'personal_newAccount',
params: 1,
inputFormatter: [null],
outputFormatter: web3._extend.utils.toAddress
}),
new web3._extend.Method({
name: 'unlockAccount',
call: 'personal_unlockAccount',
params: 3,
inputFormatter: [null, null, null]
})
],
properties:
[
new web3._extend.Property({
name: 'listAccounts',
getter: 'personal_listAccounts'
})
]
});
`

View file

@ -1,196 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"math/big"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/xeth"
)
const (
ShhApiVersion = "1.0"
)
var (
// mapping between methods and handlers
shhMapping = map[string]shhhandler{
"shh_version": (*shhApi).Version,
"shh_post": (*shhApi).Post,
"shh_hasIdentity": (*shhApi).HasIdentity,
"shh_newIdentity": (*shhApi).NewIdentity,
"shh_newFilter": (*shhApi).NewFilter,
"shh_uninstallFilter": (*shhApi).UninstallFilter,
"shh_getMessages": (*shhApi).GetMessages,
"shh_getFilterChanges": (*shhApi).GetFilterChanges,
}
)
func newWhisperOfflineError(method string) error {
return shared.NewNotAvailableError(method, "whisper offline")
}
// net callback handler
type shhhandler func(*shhApi, *shared.Request) (interface{}, error)
// shh api provider
type shhApi struct {
xeth *xexp.XEth
expanse *exp.Expanse
methods map[string]shhhandler
codec codec.ApiCoder
}
// create a new whisper api instance
func NewShhApi(xeth *xexp.XEth, exp *exp.Expanse, coder codec.Codec) *shhApi {
return &shhApi{
xeth: xeth,
expanse: exp,
methods: shhMapping,
codec: coder.New(nil),
}
}
// collection with supported methods
func (self *shhApi) Methods() []string {
methods := make([]string, len(self.methods))
i := 0
for k := range self.methods {
methods[i] = k
i++
}
return methods
}
// Execute given request
func (self *shhApi) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := self.methods[req.Method]; ok {
return callback(self, req)
}
return nil, shared.NewNotImplementedError(req.Method)
}
func (self *shhApi) Name() string {
return shared.ShhApiName
}
func (self *shhApi) ApiVersion() string {
return ShhApiVersion
}
func (self *shhApi) Version(req *shared.Request) (interface{}, error) {
w := self.xexp.Whisper()
if w == nil {
return nil, newWhisperOfflineError(req.Method)
}
return w.Version(), nil
}
func (self *shhApi) Post(req *shared.Request) (interface{}, error) {
w := self.xexp.Whisper()
if w == nil {
return nil, newWhisperOfflineError(req.Method)
}
args := new(WhisperMessageArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, err
}
err := w.Post(args.Payload, args.To, args.From, args.Topics, args.Priority, args.Ttl)
if err != nil {
return false, err
}
return true, nil
}
func (self *shhApi) HasIdentity(req *shared.Request) (interface{}, error) {
w := self.xexp.Whisper()
if w == nil {
return nil, newWhisperOfflineError(req.Method)
}
args := new(WhisperIdentityArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, err
}
return w.HasIdentity(args.Identity), nil
}
func (self *shhApi) NewIdentity(req *shared.Request) (interface{}, error) {
w := self.xexp.Whisper()
if w == nil {
return nil, newWhisperOfflineError(req.Method)
}
return w.NewIdentity(), nil
}
func (self *shhApi) NewFilter(req *shared.Request) (interface{}, error) {
args := new(WhisperFilterArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, err
}
id := self.xexp.NewWhisperFilter(args.To, args.From, args.Topics)
return newHexNum(big.NewInt(int64(id)).Bytes()), nil
}
func (self *shhApi) UninstallFilter(req *shared.Request) (interface{}, error) {
args := new(FilterIdArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, err
}
return self.xexp.UninstallWhisperFilter(args.Id), nil
}
func (self *shhApi) GetFilterChanges(req *shared.Request) (interface{}, error) {
w := self.xexp.Whisper()
if w == nil {
return nil, newWhisperOfflineError(req.Method)
}
// Retrieve all the new messages arrived since the last request
args := new(FilterIdArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, err
}
return self.xexp.WhisperMessagesChanged(args.Id), nil
}
func (self *shhApi) GetMessages(req *shared.Request) (interface{}, error) {
w := self.xexp.Whisper()
if w == nil {
return nil, newWhisperOfflineError(req.Method)
}
// Retrieve all the cached messages matching a specific, existing filter
args := new(FilterIdArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, err
}
return self.xexp.WhisperMessages(args.Id), nil
}

View file

@ -1,174 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"encoding/json"
"fmt"
"math/big"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type WhisperMessageArgs struct {
Payload string
To string
From string
Topics []string
Priority uint32
Ttl uint32
}
func (args *WhisperMessageArgs) UnmarshalJSON(b []byte) (err error) {
var obj []struct {
Payload string
To string
From string
Topics []string
Priority interface{}
Ttl interface{}
}
if err = json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
args.Payload = obj[0].Payload
args.To = obj[0].To
args.From = obj[0].From
args.Topics = obj[0].Topics
var num *big.Int
if num, err = numString(obj[0].Priority); err != nil {
return err
}
args.Priority = uint32(num.Int64())
if num, err = numString(obj[0].Ttl); err != nil {
return err
}
args.Ttl = uint32(num.Int64())
return nil
}
type WhisperIdentityArgs struct {
Identity string
}
func (args *WhisperIdentityArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
argstr, ok := obj[0].(string)
if !ok {
return shared.NewInvalidTypeError("arg0", "not a string")
}
args.Identity = argstr
return nil
}
type WhisperFilterArgs struct {
To string
From string
Topics [][]string
}
// UnmarshalJSON implements the json.Unmarshaler interface, invoked to convert a
// JSON message blob into a WhisperFilterArgs structure.
func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
// Unmarshal the JSON message and sanity check
var obj []struct {
To interface{} `json:"to"`
From interface{} `json:"from"`
Topics interface{} `json:"topics"`
}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
if len(obj) < 1 {
return shared.NewInsufficientParamsError(len(obj), 1)
}
// Retrieve the simple data contents of the filter arguments
if obj[0].To == nil {
args.To = ""
} else {
argstr, ok := obj[0].To.(string)
if !ok {
return shared.NewInvalidTypeError("to", "is not a string")
}
args.To = argstr
}
if obj[0].From == nil {
args.From = ""
} else {
argstr, ok := obj[0].From.(string)
if !ok {
return shared.NewInvalidTypeError("from", "is not a string")
}
args.From = argstr
}
// Construct the nested topic array
if obj[0].Topics != nil {
// Make sure we have an actual topic array
list, ok := obj[0].Topics.([]interface{})
if !ok {
return shared.NewInvalidTypeError("topics", "is not an array")
}
// Iterate over each topic and handle nil, string or array
topics := make([][]string, len(list))
for idx, field := range list {
switch value := field.(type) {
case nil:
topics[idx] = []string{}
case string:
topics[idx] = []string{value}
case []interface{}:
topics[idx] = make([]string, len(value))
for i, nested := range value {
switch value := nested.(type) {
case nil:
topics[idx][i] = ""
case string:
topics[idx][i] = value
default:
return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d][%d]", idx, i), "is not a string")
}
}
default:
return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d]", idx), "not a string or array")
}
}
args.Topics = topics
}
return nil
}

View file

@ -1,92 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/xeth"
)
const (
TxPoolApiVersion = "1.0"
)
var (
// mapping between methods and handlers
txpoolMapping = map[string]txpoolhandler{
"txpool_status": (*txPoolApi).Status,
}
)
// net callback handler
type txpoolhandler func(*txPoolApi, *shared.Request) (interface{}, error)
// txpool api provider
type txPoolApi struct {
xeth *xexp.XEth
expanse *exp.Expanse
methods map[string]txpoolhandler
codec codec.ApiCoder
}
// create a new txpool api instance
func NewTxPoolApi(xeth *xexp.XEth, exp *exp.Expanse, coder codec.Codec) *txPoolApi {
return &txPoolApi{
xeth: xeth,
expanse: exp,
methods: txpoolMapping,
codec: coder.New(nil),
}
}
// collection with supported methods
func (self *txPoolApi) Methods() []string {
methods := make([]string, len(self.methods))
i := 0
for k := range self.methods {
methods[i] = k
i++
}
return methods
}
// Execute given request
func (self *txPoolApi) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := self.methods[req.Method]; ok {
return callback(self, req)
}
return nil, shared.NewNotImplementedError(req.Method)
}
func (self *txPoolApi) Name() string {
return shared.TxPoolApiName
}
func (self *txPoolApi) ApiVersion() string {
return TxPoolApiVersion
}
func (self *txPoolApi) Status(req *shared.Request) (interface{}, error) {
pending, queue := self.expanse.TxPool().Stats()
return map[string]int{
"pending": pending,
"queued": queue,
}, nil
}

View file

@ -1,218 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"strings"
"fmt"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/xeth"
)
var (
// Mapping between the different methods each api supports
AutoCompletion = map[string][]string{
"admin": []string{
"addPeer",
"datadir",
"enableUserAgent",
"exportChain",
"getContractInfo",
"httpGet",
"importChain",
"nodeInfo",
"peers",
"register",
"registerUrl",
"saveInfo",
"setGlobalRegistrar",
"setHashReg",
"setUrlHint",
"setSolc",
"sleep",
"sleepBlocks",
"startNatSpec",
"startRPC",
"stopNatSpec",
"stopRPC",
"verbosity",
},
"db": []string{
"getString",
"putString",
"getHex",
"putHex",
},
"debug": []string{
"dumpBlock",
"getBlockRlp",
"metrics",
"printBlock",
"processBlock",
"seedHash",
"setHead",
},
"exp": []string{
"accounts",
"blockNumber",
"call",
"contract",
"coinbase",
"compile.lll",
"compile.serpent",
"compile.solidity",
"contract",
"defaultAccount",
"defaultBlock",
"estimateGas",
"filter",
"getBalance",
"getBlock",
"getBlockTransactionCount",
"getBlockUncleCount",
"getCode",
"getNatSpec",
"getCompilers",
"gasPrice",
"getStorageAt",
"getTransaction",
"getTransactionCount",
"getTransactionFromBlock",
"getTransactionReceipt",
"getUncle",
"hashrate",
"mining",
"namereg",
"pendingTransactions",
"resend",
"sendRawTransaction",
"sendTransaction",
"sign",
"syncing",
},
"miner": []string{
"hashrate",
"makeDAG",
"setEtherbase",
"setExtra",
"setGasPrice",
"startAutoDAG",
"start",
"stopAutoDAG",
"stop",
},
"net": []string{
"peerCount",
"listening",
},
"personal": []string{
"listAccounts",
"newAccount",
"unlockAccount",
},
"shh": []string{
"post",
"newIdentity",
"hasIdentity",
"newGroup",
"addToGroup",
"filter",
},
"txpool": []string{
"status",
},
"web3": []string{
"sha3",
"version",
"fromWei",
"toWei",
"toHex",
"toAscii",
"fromAscii",
"toBigNumber",
"isAddress",
},
}
)
// Parse a comma separated API string to individual api's
func ParseApiString(apistr string, codec codec.Codec, xeth *xexp.XEth, exp *exp.Expanse) ([]shared.ExpanseApi, error) {
if len(strings.TrimSpace(apistr)) == 0 {
return nil, fmt.Errorf("Empty apistr provided")
}
names := strings.Split(apistr, ",")
apis := make([]shared.ExpanseApi, len(names))
for i, name := range names {
switch strings.ToLower(strings.TrimSpace(name)) {
case shared.AdminApiName:
apis[i] = NewAdminApi(xeth, exp, codec)
case shared.DebugApiName:
apis[i] = NewDebugApi(xeth, exp, codec)
case shared.DbApiName:
apis[i] = NewDbApi(xeth, exp, codec)
case shared.EthApiName:
apis[i] = NewEthApi(xeth, exp, codec)
case shared.MinerApiName:
apis[i] = NewMinerApi(exp, codec)
case shared.NetApiName:
apis[i] = NewNetApi(xeth, exp, codec)
case shared.ShhApiName:
apis[i] = NewShhApi(xeth, exp, codec)
case shared.TxPoolApiName:
apis[i] = NewTxPoolApi(xeth, exp, codec)
case shared.PersonalApiName:
apis[i] = NewPersonalApi(xeth, exp, codec)
case shared.Web3ApiName:
apis[i] = NewWeb3Api(xeth, codec)
default:
return nil, fmt.Errorf("Unknown API '%s'", name)
}
}
return apis, nil
}
func Javascript(name string) string {
switch strings.ToLower(strings.TrimSpace(name)) {
case shared.AdminApiName:
return Admin_JS
case shared.DebugApiName:
return Debug_JS
case shared.DbApiName:
return Db_JS
case shared.EthApiName:
return Eth_JS
case shared.MinerApiName:
return Miner_JS
case shared.NetApiName:
return Net_JS
case shared.ShhApiName:
return Shh_JS
case shared.TxPoolApiName:
return TxPool_JS
case shared.PersonalApiName:
return Personal_JS
}
return ""
}

View file

@ -1,99 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package api
import (
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/crypto"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/xeth"
)
const (
Web3ApiVersion = "1.0"
)
var (
// mapping between methods and handlers
Web3Mapping = map[string]web3handler{
"web3_sha3": (*web3Api).Sha3,
"web3_clientVersion": (*web3Api).ClientVersion,
}
)
// web3 callback handler
type web3handler func(*web3Api, *shared.Request) (interface{}, error)
// web3 api provider
type web3Api struct {
xeth *xexp.XEth
methods map[string]web3handler
codec codec.ApiCoder
}
// create a new web3 api instance
func NewWeb3Api(xeth *xexp.XEth, coder codec.Codec) *web3Api {
return &web3Api{
xeth: xeth,
methods: Web3Mapping,
codec: coder.New(nil),
}
}
// collection with supported methods
func (self *web3Api) Methods() []string {
methods := make([]string, len(self.methods))
i := 0
for k := range self.methods {
methods[i] = k
i++
}
return methods
}
// Execute given request
func (self *web3Api) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := self.methods[req.Method]; ok {
return callback(self, req)
}
return nil, &shared.NotImplementedError{req.Method}
}
func (self *web3Api) Name() string {
return shared.Web3ApiName
}
func (self *web3Api) ApiVersion() string {
return Web3ApiVersion
}
// Calculates the sha3 over req.Params.Data
func (self *web3Api) Sha3(req *shared.Request) (interface{}, error) {
args := new(Sha3Args)
if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, err
}
return common.ToHex(crypto.Sha3(common.FromHex(args.Data))), nil
}
// returns the xeth client vrsion
func (self *web3Api) ClientVersion(req *shared.Request) (interface{}, error) {
return self.xexp.ClientVersion(), nil
}

View file

@ -1,65 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package codec
import (
"net"
"strconv"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type Codec int
// (de)serialization support for rpc interface
type ApiCoder interface {
// Parse message to request from underlying stream
ReadRequest() ([]*shared.Request, bool, error)
// Parse response message from underlying stream
ReadResponse() (interface{}, error)
// Read raw message from underlying stream
Recv() (interface{}, error)
// Encode response to encoded form in underlying stream
WriteResponse(interface{}) error
// Decode single message from data
Decode([]byte, interface{}) error
// Encode msg to encoded form
Encode(msg interface{}) ([]byte, error)
// close the underlying stream
Close()
}
// supported codecs
const (
JSON Codec = iota
nCodecs
)
var (
// collection with supported coders
coders = make([]func(net.Conn) ApiCoder, nCodecs)
)
// create a new coder instance
func (c Codec) New(conn net.Conn) ApiCoder {
switch c {
case JSON:
return NewJsonCoder(conn)
}
panic("codec: request for codec #" + strconv.Itoa(int(c)) + " is unavailable")
}

View file

@ -1,149 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package codec
import (
"encoding/json"
"fmt"
"net"
"time"
"strings"
"github.com/expanse-project/go-expanse/rpc/shared"
)
const (
READ_TIMEOUT = 60 // in seconds
MAX_REQUEST_SIZE = 1024 * 1024
MAX_RESPONSE_SIZE = 1024 * 1024
)
// Json serialization support
type JsonCodec struct {
c net.Conn
d *json.Decoder
}
// Create new JSON coder instance
func NewJsonCoder(conn net.Conn) ApiCoder {
return &JsonCodec{
c: conn,
d: json.NewDecoder(conn),
}
}
// Read incoming request and parse it to RPC request
func (self *JsonCodec) ReadRequest() (requests []*shared.Request, isBatch bool, err error) {
deadline := time.Now().Add(READ_TIMEOUT * time.Second)
if err := self.c.SetDeadline(deadline); err != nil {
return nil, false, err
}
var incoming json.RawMessage
err = self.d.Decode(&incoming)
if err == nil {
isBatch = incoming[0] == '['
if isBatch {
requests = make([]*shared.Request, 0)
err = json.Unmarshal(incoming, &requests)
} else {
requests = make([]*shared.Request, 1)
var singleRequest shared.Request
if err = json.Unmarshal(incoming, &singleRequest); err == nil {
requests[0] = &singleRequest
}
}
return
}
self.c.Close()
return nil, false, err
}
func (self *JsonCodec) Recv() (interface{}, error) {
var msg json.RawMessage
err := self.d.Decode(&msg)
if err != nil {
self.c.Close()
return nil, err
}
return msg, err
}
func (self *JsonCodec) ReadResponse() (interface{}, error) {
in, err := self.Recv()
if err != nil {
return nil, err
}
if msg, ok := in.(json.RawMessage); ok {
var req *shared.Request
if err = json.Unmarshal(msg, &req); err == nil && strings.HasPrefix(req.Method, "agent_") {
return req, nil
}
var failure *shared.ErrorResponse
if err = json.Unmarshal(msg, &failure); err == nil && failure.Error != nil {
return failure, fmt.Errorf(failure.Error.Message)
}
var success *shared.SuccessResponse
if err = json.Unmarshal(msg, &success); err == nil {
return success, nil
}
}
return in, err
}
// Decode data
func (self *JsonCodec) Decode(data []byte, msg interface{}) error {
return json.Unmarshal(data, msg)
}
// Encode message
func (self *JsonCodec) Encode(msg interface{}) ([]byte, error) {
return json.Marshal(msg)
}
// Parse JSON data from conn to obj
func (self *JsonCodec) WriteResponse(res interface{}) error {
data, err := json.Marshal(res)
if err != nil {
self.c.Close()
return err
}
bytesWritten := 0
for bytesWritten < len(data) {
n, err := self.c.Write(data[bytesWritten:])
if err != nil {
self.c.Close()
return err
}
bytesWritten += n
}
return nil
}
// Close decoder and encoder
func (self *JsonCodec) Close() {
self.c.Close()
}

View file

@ -1,157 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package codec
import (
"bytes"
"io"
"net"
"testing"
"time"
)
type jsonTestConn struct {
buffer *bytes.Buffer
}
func newJsonTestConn(data []byte) *jsonTestConn {
return &jsonTestConn{
buffer: bytes.NewBuffer(data),
}
}
func (self *jsonTestConn) Read(p []byte) (n int, err error) {
return self.buffer.Read(p)
}
func (self *jsonTestConn) Write(p []byte) (n int, err error) {
return self.buffer.Write(p)
}
func (self *jsonTestConn) Close() error {
// not implemented
return nil
}
func (self *jsonTestConn) LocalAddr() net.Addr {
// not implemented
return nil
}
func (self *jsonTestConn) RemoteAddr() net.Addr {
// not implemented
return nil
}
func (self *jsonTestConn) SetDeadline(t time.Time) error {
return nil
}
func (self *jsonTestConn) SetReadDeadline(t time.Time) error {
return nil
}
func (self *jsonTestConn) SetWriteDeadline(t time.Time) error {
return nil
}
func TestJsonDecoderWithValidRequest(t *testing.T) {
reqdata := []byte(`{"jsonrpc":"2.0","method":"modules","params":[],"id":64}`)
decoder := newJsonTestConn(reqdata)
jsonDecoder := NewJsonCoder(decoder)
requests, batch, err := jsonDecoder.ReadRequest()
if err != nil {
t.Errorf("Read valid request failed - %v", err)
}
if len(requests) != 1 {
t.Errorf("Expected to get a single request but got %d", len(requests))
}
if batch {
t.Errorf("Got batch indication while expecting single request")
}
if requests[0].Id != float64(64) {
t.Errorf("Expected req.Id == 64 but got %v", requests[0].Id)
}
if requests[0].Method != "modules" {
t.Errorf("Expected req.Method == 'modules' got '%s'", requests[0].Method)
}
}
func TestJsonDecoderWithValidBatchRequest(t *testing.T) {
reqdata := []byte(`[{"jsonrpc":"2.0","method":"modules","params":[],"id":64},
{"jsonrpc":"2.0","method":"modules","params":[],"id":64}]`)
decoder := newJsonTestConn(reqdata)
jsonDecoder := NewJsonCoder(decoder)
requests, batch, err := jsonDecoder.ReadRequest()
if err != nil {
t.Errorf("Read valid batch request failed - %v", err)
}
if len(requests) != 2 {
t.Errorf("Expected to get two requests but got %d", len(requests))
}
if !batch {
t.Errorf("Got no batch indication while expecting batch request")
}
for i := 0; i < len(requests); i++ {
if requests[i].Id != float64(64) {
t.Errorf("Expected req.Id == 64 but got %v", requests[i].Id)
}
if requests[i].Method != "modules" {
t.Errorf("Expected req.Method == 'modules' got '%s'", requests[i].Method)
}
}
}
func TestJsonDecoderWithInvalidIncompleteMessage(t *testing.T) {
reqdata := []byte(`{"jsonrpc":"2.0","method":"modules","pa`)
decoder := newJsonTestConn(reqdata)
jsonDecoder := NewJsonCoder(decoder)
requests, batch, err := jsonDecoder.ReadRequest()
if err != io.ErrUnexpectedEOF {
t.Errorf("Expected to read an incomplete request err but got %v", err)
}
// remaining message
decoder.Write([]byte(`rams":[],"id:64"}`))
requests, batch, err = jsonDecoder.ReadRequest()
if err == nil {
t.Errorf("Expected an error but got nil")
}
if len(requests) != 0 {
t.Errorf("Expected to get no requests but got %d", len(requests))
}
if batch {
t.Errorf("Got batch indication while expecting non batch")
}
}

View file

@ -1,150 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package comms
import (
"io"
"net"
"fmt"
"strings"
"strconv"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
)
const (
maxHttpSizeReqLength = 1024 * 1024 // 1MB
)
var (
// List with all API's which are offered over the in proc interface by default
DefaultInProcApis = shared.AllApis
// List with all API's which are offered over the IPC interface by default
DefaultIpcApis = shared.AllApis
// List with API's which are offered over thr HTTP/RPC interface by default
DefaultHttpRpcApis = strings.Join([]string{
shared.DbApiName, shared.EthApiName, shared.NetApiName, shared.Web3ApiName,
}, ",")
)
type ExpanseClient interface {
// Close underlaying connection
Close()
// Send request
Send(interface{}) error
// Receive response
Recv() (interface{}, error)
// List with modules this client supports
SupportedModules() (map[string]string, error)
}
func handle(id int, conn net.Conn, api shared.ExpanseApi, c codec.Codec) {
codec := c.New(conn)
defer func() {
if r := recover(); r != nil {
glog.Errorf("panic: %v\n", r)
}
codec.Close()
}()
for {
requests, isBatch, err := codec.ReadRequest()
if err == io.EOF {
return
} else if err != nil {
glog.V(logger.Debug).Infof("Closed IPC Conn %06d recv err - %v\n", id, err)
return
}
if isBatch {
responses := make([]*interface{}, len(requests))
responseCount := 0
for _, req := range requests {
res, err := api.Execute(req)
if req.Id != nil {
rpcResponse := shared.NewRpcResponse(req.Id, req.Jsonrpc, res, err)
responses[responseCount] = rpcResponse
responseCount += 1
}
}
err = codec.WriteResponse(responses[:responseCount])
if err != nil {
glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err)
return
}
} else {
var rpcResponse interface{}
res, err := api.Execute(requests[0])
rpcResponse = shared.NewRpcResponse(requests[0].Id, requests[0].Jsonrpc, res, err)
err = codec.WriteResponse(rpcResponse)
if err != nil {
glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err)
return
}
}
}
}
// Endpoint must be in the form of:
// ${protocol}:${path}
// e.g. ipc:/tmp/gexp.ipc
// rpc:localhost:9656
func ClientFromEndpoint(endpoint string, c codec.Codec) (ExpanseClient, error) {
if strings.HasPrefix(endpoint, "ipc:") {
cfg := IpcConfig{
Endpoint: endpoint[4:],
}
return NewIpcClient(cfg, codec.JSON)
}
if strings.HasPrefix(endpoint, "rpc:") {
parts := strings.Split(endpoint, ":")
addr := "http://localhost"
port := uint(9656)
if len(parts) >= 3 {
addr = parts[1] + ":" + parts[2]
}
if len(parts) >= 4 {
p, err := strconv.Atoi(parts[3])
if err != nil {
return nil, err
}
port = uint(p)
}
cfg := HttpConfig{
ListenAddress: addr,
ListenPort: port,
}
return NewHttpClient(cfg, codec.JSON), nil
}
return nil, fmt.Errorf("Invalid endpoint")
}

View file

@ -1,345 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package comms
import (
"encoding/json"
"fmt"
"net"
"net/http"
"strings"
"sync"
"time"
"bytes"
"io"
"io/ioutil"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/rs/cors"
)
const (
serverIdleTimeout = 10 * time.Second // idle keep-alive connections
serverReadTimeout = 15 * time.Second // per-request read timeout
serverWriteTimeout = 15 * time.Second // per-request read timeout
)
var (
httpServerMu sync.Mutex
httpServer *stopServer
)
type HttpConfig struct {
ListenAddress string
ListenPort uint
CorsDomain string
}
// stopServer augments http.Server with idle connection tracking.
// Idle keep-alive connections are shut down when Close is called.
type stopServer struct {
*http.Server
l net.Listener
// connection tracking state
mu sync.Mutex
shutdown bool // true when Stop has returned
idle map[net.Conn]struct{}
}
type handler struct {
codec codec.Codec
api shared.ExpanseApi
}
// StartHTTP starts listening for RPC requests sent via HTTP.
func StartHttp(cfg HttpConfig, codec codec.Codec, api shared.ExpanseApi) error {
httpServerMu.Lock()
defer httpServerMu.Unlock()
addr := fmt.Sprintf("%s:%d", cfg.ListenAddress, cfg.ListenPort)
if httpServer != nil {
if addr != httpServer.Addr {
return fmt.Errorf("RPC service already running on %s ", httpServer.Addr)
}
return nil // RPC service already running on given host/port
}
// Set up the request handler, wrapping it with CORS headers if configured.
handler := http.Handler(&handler{codec, api})
if len(cfg.CorsDomain) > 0 {
opts := cors.Options{
AllowedMethods: []string{"POST"},
AllowedOrigins: strings.Split(cfg.CorsDomain, " "),
}
handler = cors.New(opts).Handler(handler)
}
// Start the server.
s, err := listenHTTP(addr, handler)
if err != nil {
glog.V(logger.Error).Infof("Can't listen on %s:%d: %v", cfg.ListenAddress, cfg.ListenPort, err)
return err
}
httpServer = s
return nil
}
func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
// Limit request size to resist DoS
if req.ContentLength > maxHttpSizeReqLength {
err := fmt.Errorf("Request too large")
response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err)
sendJSON(w, &response)
return
}
defer req.Body.Close()
payload, err := ioutil.ReadAll(req.Body)
if err != nil {
err := fmt.Errorf("Could not read request body")
response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err)
sendJSON(w, &response)
return
}
c := h.codec.New(nil)
var rpcReq shared.Request
if err = c.Decode(payload, &rpcReq); err == nil {
reply, err := h.api.Execute(&rpcReq)
res := shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err)
sendJSON(w, &res)
return
}
var reqBatch []shared.Request
if err = c.Decode(payload, &reqBatch); err == nil {
resBatch := make([]*interface{}, len(reqBatch))
resCount := 0
for i, rpcReq := range reqBatch {
reply, err := h.api.Execute(&rpcReq)
if rpcReq.Id != nil { // this leaves nil entries in the response batch for later removal
resBatch[i] = shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err)
resCount += 1
}
}
// make response omitting nil entries
sendJSON(w, resBatch[:resCount])
return
}
// invalid request
err = fmt.Errorf("Could not decode request")
res := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32600, err)
sendJSON(w, res)
}
func sendJSON(w io.Writer, v interface{}) {
if glog.V(logger.Detail) {
if payload, err := json.MarshalIndent(v, "", "\t"); err == nil {
glog.Infof("Sending payload: %s", payload)
}
}
if err := json.NewEncoder(w).Encode(v); err != nil {
glog.V(logger.Error).Infoln("Error sending JSON:", err)
}
}
// Stop closes all active HTTP connections and shuts down the server.
func StopHttp() {
httpServerMu.Lock()
defer httpServerMu.Unlock()
if httpServer != nil {
httpServer.Close()
httpServer = nil
}
}
func listenHTTP(addr string, h http.Handler) (*stopServer, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
s := &stopServer{l: l, idle: make(map[net.Conn]struct{})}
s.Server = &http.Server{
Addr: addr,
Handler: h,
ReadTimeout: serverReadTimeout,
WriteTimeout: serverWriteTimeout,
ConnState: s.connState,
}
go s.Serve(l)
return s, nil
}
func (s *stopServer) connState(c net.Conn, state http.ConnState) {
s.mu.Lock()
defer s.mu.Unlock()
// Close c immediately if we're past shutdown.
if s.shutdown {
if state != http.StateClosed {
c.Close()
}
return
}
if state == http.StateIdle {
s.idle[c] = struct{}{}
} else {
delete(s.idle, c)
}
}
func (s *stopServer) Close() {
s.mu.Lock()
defer s.mu.Unlock()
// Shut down the acceptor. No new connections can be created.
s.l.Close()
// Drop all idle connections. Non-idle connections will be
// closed by connState as soon as they become idle.
s.shutdown = true
for c := range s.idle {
glog.V(logger.Detail).Infof("closing idle connection %v", c.RemoteAddr())
c.Close()
delete(s.idle, c)
}
}
type httpClient struct {
address string
port uint
codec codec.ApiCoder
lastRes interface{}
lastErr error
}
// Create a new in process client
func NewHttpClient(cfg HttpConfig, c codec.Codec) *httpClient {
return &httpClient{
address: cfg.ListenAddress,
port: cfg.ListenPort,
codec: c.New(nil),
}
}
func (self *httpClient) Close() {
// do nothing
}
func (self *httpClient) Send(req interface{}) error {
var body []byte
var err error
self.lastRes = nil
self.lastErr = nil
if body, err = self.codec.Encode(req); err != nil {
return err
}
httpReq, err := http.NewRequest("POST", fmt.Sprintf("%s:%d", self.address, self.port), bytes.NewBuffer(body))
if err != nil {
return err
}
httpReq.Header.Set("Content-Type", "application/json")
client := http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.Status == "200 OK" {
reply, _ := ioutil.ReadAll(resp.Body)
var rpcSuccessResponse shared.SuccessResponse
if err = self.codec.Decode(reply, &rpcSuccessResponse); err == nil {
self.lastRes = &rpcSuccessResponse
self.lastErr = err
return nil
} else {
var rpcErrorResponse shared.ErrorResponse
if err = self.codec.Decode(reply, &rpcErrorResponse); err == nil {
self.lastRes = &rpcErrorResponse
self.lastErr = err
return nil
} else {
return err
}
}
}
return fmt.Errorf("Not implemented")
}
func (self *httpClient) Recv() (interface{}, error) {
return self.lastRes, self.lastErr
}
func (self *httpClient) SupportedModules() (map[string]string, error) {
var body []byte
var err error
payload := shared.Request{
Id: 1,
Jsonrpc: "2.0",
Method: "modules",
}
if body, err = self.codec.Encode(payload); err != nil {
return nil, err
}
req, err := http.NewRequest("POST", fmt.Sprintf("%s:%d", self.address, self.port), bytes.NewBuffer(body))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.Status == "200 OK" {
reply, _ := ioutil.ReadAll(resp.Body)
var rpcRes shared.SuccessResponse
if err = self.codec.Decode(reply, &rpcRes); err != nil {
return nil, err
}
result := make(map[string]string)
if modules, ok := rpcRes.Result.(map[string]interface{}); ok {
for a, v := range modules {
result[a] = fmt.Sprintf("%s", v)
}
return result, nil
}
err = fmt.Errorf("Unable to parse module response - %v", rpcRes.Result)
} else {
fmt.Printf("resp.Status = %s\n", resp.Status)
fmt.Printf("err = %v\n", err)
}
return nil, err
}

View file

@ -1,82 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package comms
import (
"fmt"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type InProcClient struct {
api shared.ExpanseApi
codec codec.Codec
lastId interface{}
lastJsonrpc string
lastErr error
lastRes interface{}
}
// Create a new in process client
func NewInProcClient(codec codec.Codec) *InProcClient {
return &InProcClient{
codec: codec,
}
}
func (self *InProcClient) Close() {
// do nothing
}
// Need to setup api support
func (self *InProcClient) Initialize(offeredApi shared.ExpanseApi) {
self.api = offeredApi
}
func (self *InProcClient) Send(req interface{}) error {
if r, ok := req.(*shared.Request); ok {
self.lastId = r.Id
self.lastJsonrpc = r.Jsonrpc
self.lastRes, self.lastErr = self.api.Execute(r)
return self.lastErr
}
return fmt.Errorf("Invalid request (%T)", req)
}
func (self *InProcClient) Recv() (interface{}, error) {
return *shared.NewRpcResponse(self.lastId, self.lastJsonrpc, self.lastRes, self.lastErr), nil
}
func (self *InProcClient) SupportedModules() (map[string]string, error) {
req := shared.Request{
Id: 1,
Jsonrpc: "2.0",
Method: "modules",
}
if res, err := self.api.Execute(&req); err == nil {
if result, ok := res.(map[string]string); ok {
return result, nil
}
} else {
return nil, err
}
return nil, fmt.Errorf("Invalid response")
}

View file

@ -1,137 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package comms
import (
"fmt"
"math/rand"
"net"
"os"
"encoding/json"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
)
type Stopper interface {
Stop()
}
type InitFunc func(conn net.Conn) (Stopper, shared.ExpanseApi, error)
type IpcConfig struct {
Endpoint string
}
type ipcClient struct {
endpoint string
c net.Conn
codec codec.Codec
coder codec.ApiCoder
}
func (self *ipcClient) Close() {
self.coder.Close()
}
func (self *ipcClient) Send(msg interface{}) error {
var err error
if err = self.coder.WriteResponse(msg); err != nil {
if err = self.reconnect(); err == nil {
err = self.coder.WriteResponse(msg)
}
}
return err
}
func (self *ipcClient) Recv() (interface{}, error) {
return self.coder.ReadResponse()
}
func (self *ipcClient) SupportedModules() (map[string]string, error) {
req := shared.Request{
Id: 1,
Jsonrpc: "2.0",
Method: "modules",
}
if err := self.coder.WriteResponse(req); err != nil {
return nil, err
}
res, err := self.coder.ReadResponse()
if err != nil {
return nil, err
}
if sucRes, ok := res.(*shared.SuccessResponse); ok {
data, _ := json.Marshal(sucRes.Result)
modules := make(map[string]string)
err = json.Unmarshal(data, &modules)
if err == nil {
return modules, nil
}
}
return nil, fmt.Errorf("Invalid response")
}
// Create a new IPC client, UNIX domain socket on posix, named pipe on Windows
func NewIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
return newIpcClient(cfg, codec)
}
// Start IPC server
func StartIpc(cfg IpcConfig, codec codec.Codec, initializer InitFunc) error {
l, err := ipcListen(cfg)
if err != nil {
return err
}
go ipcLoop(cfg, codec, initializer, l)
return nil
}
func ipcLoop(cfg IpcConfig, codec codec.Codec, initializer InitFunc, l net.Listener) {
glog.V(logger.Info).Infof("IPC service started (%s)\n", cfg.Endpoint)
defer os.Remove(cfg.Endpoint)
defer l.Close()
for {
conn, err := l.Accept()
if err != nil {
glog.V(logger.Debug).Infof("accept: %v", err)
return
}
id := newIpcConnId()
go func() {
defer conn.Close()
glog.V(logger.Debug).Infof("new connection with id %06d started", id)
stopper, api, err := initializer(conn)
if err != nil {
glog.V(logger.Error).Infof("Unable to initialize IPC connection: %v", err)
return
}
defer stopper.Stop()
handle(id, conn, api, codec)
}()
}
}
func newIpcConnId() int {
return rand.Int() % 1000000
}

View file

@ -1,82 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package comms
import (
"net"
"os"
"path/filepath"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/rpc/useragent"
)
func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
c, err := net.DialUnix("unix", nil, &net.UnixAddr{cfg.Endpoint, "unix"})
if err != nil {
return nil, err
}
coder := codec.New(c)
msg := shared.Request{
Id: 0,
Method: useragent.EnableUserAgentMethod,
Jsonrpc: shared.JsonRpcVersion,
Params: []byte("[]"),
}
coder.WriteResponse(msg)
coder.Recv()
return &ipcClient{cfg.Endpoint, c, codec, coder}, nil
}
func (self *ipcClient) reconnect() error {
self.coder.Close()
c, err := net.DialUnix("unix", nil, &net.UnixAddr{self.endpoint, "unix"})
if err == nil {
self.coder = self.codec.New(c)
msg := shared.Request{
Id: 0,
Method: useragent.EnableUserAgentMethod,
Jsonrpc: shared.JsonRpcVersion,
Params: []byte("[]"),
}
self.coder.WriteResponse(msg)
self.coder.Recv()
}
return err
}
func ipcListen(cfg IpcConfig) (net.Listener, error) {
// Ensure the IPC path exists and remove any previous leftover
if err := os.MkdirAll(filepath.Dir(cfg.Endpoint), 0751); err != nil {
return nil, err
}
os.Remove(cfg.Endpoint)
l, err := net.Listen("unix", cfg.Endpoint)
if err != nil {
return nil, err
}
os.Chmod(cfg.Endpoint, 0600)
return l, nil
}

View file

@ -1,697 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
// +build windows
package comms
import (
"fmt"
"io"
"net"
"os"
"sync"
"syscall"
"time"
"unsafe"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/rpc/useragent"
)
var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe")
procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW")
procCreateEventW = modkernel32.NewProc("CreateEventW")
procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult")
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
)
func createNamedPipe(name *uint16, openMode uint32, pipeMode uint32, maxInstances uint32, outBufSize uint32, inBufSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(openMode), uintptr(pipeMode), uintptr(maxInstances), uintptr(outBufSize), uintptr(inBufSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func cancelIoEx(handle syscall.Handle, overlapped *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func connectNamedPipe(handle syscall.Handle, overlapped *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func disconnectNamedPipe(handle syscall.Handle) (err error) {
r1, _, e1 := syscall.Syscall(procDisconnectNamedPipe.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func waitNamedPipe(name *uint16, timeout uint32) (err error) {
r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func createEvent(sa *syscall.SecurityAttributes, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) {
var _p0 uint32
if manualReset {
_p0 = 1
} else {
_p0 = 0
}
var _p1 uint32
if initialState {
_p1 = 1
} else {
_p1 = 0
}
r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(sa)), uintptr(_p0), uintptr(_p1), uintptr(unsafe.Pointer(name)), 0, 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getOverlappedResult(handle syscall.Handle, overlapped *syscall.Overlapped, transferred *uint32, wait bool) (err error) {
var _p0 uint32
if wait {
_p0 = 1
} else {
_p0 = 0
}
r1, _, e1 := syscall.Syscall6(procGetOverlappedResult.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transferred)), uintptr(_p0), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
const (
// openMode
pipe_access_duplex = 0x3
pipe_access_inbound = 0x1
pipe_access_outbound = 0x2
// openMode write flags
file_flag_first_pipe_instance = 0x00080000
file_flag_write_through = 0x80000000
file_flag_overlapped = 0x40000000
// openMode ACL flags
write_dac = 0x00040000
write_owner = 0x00080000
access_system_security = 0x01000000
// pipeMode
pipe_type_byte = 0x0
pipe_type_message = 0x4
// pipeMode read mode flags
pipe_readmode_byte = 0x0
pipe_readmode_message = 0x2
// pipeMode wait mode flags
pipe_wait = 0x0
pipe_nowait = 0x1
// pipeMode remote-client mode flags
pipe_accept_remote_clients = 0x0
pipe_reject_remote_clients = 0x8
pipe_unlimited_instances = 255
nmpwait_wait_forever = 0xFFFFFFFF
// the two not-an-errors below occur if a client connects to the pipe between
// the server's CreateNamedPipe and ConnectNamedPipe calls.
error_no_data syscall.Errno = 0xE8
error_pipe_connected syscall.Errno = 0x217
error_pipe_busy syscall.Errno = 0xE7
error_sem_timeout syscall.Errno = 0x79
error_bad_pathname syscall.Errno = 0xA1
error_invalid_name syscall.Errno = 0x7B
error_io_incomplete syscall.Errno = 0x3e4
)
var _ net.Conn = (*PipeConn)(nil)
var _ net.Listener = (*PipeListener)(nil)
// ErrClosed is the error returned by PipeListener.Accept when Close is called
// on the PipeListener.
var ErrClosed = PipeError{"Pipe has been closed.", false}
// PipeError is an error related to a call to a pipe
type PipeError struct {
msg string
timeout bool
}
// Error implements the error interface
func (e PipeError) Error() string {
return e.msg
}
// Timeout implements net.AddrError.Timeout()
func (e PipeError) Timeout() bool {
return e.timeout
}
// Temporary implements net.AddrError.Temporary()
func (e PipeError) Temporary() bool {
return false
}
// Dial connects to a named pipe with the given address. If the specified pipe is not available,
// it will wait indefinitely for the pipe to become available.
//
// The address must be of the form \\.\\pipe\<name> for local pipes and \\<computer>\pipe\<name>
// for remote pipes.
//
// Dial will return a PipeError if you pass in a badly formatted pipe name.
//
// Examples:
// // local pipe
// conn, err := Dial(`\\.\pipe\mypipename`)
//
// // remote pipe
// conn, err := Dial(`\\othercomp\pipe\mypipename`)
func Dial(address string) (*PipeConn, error) {
for {
conn, err := dial(address, nmpwait_wait_forever)
if err == nil {
return conn, nil
}
if isPipeNotReady(err) {
<-time.After(100 * time.Millisecond)
continue
}
return nil, err
}
}
// DialTimeout acts like Dial, but will time out after the duration of timeout
func DialTimeout(address string, timeout time.Duration) (*PipeConn, error) {
deadline := time.Now().Add(timeout)
now := time.Now()
for now.Before(deadline) {
millis := uint32(deadline.Sub(now) / time.Millisecond)
conn, err := dial(address, millis)
if err == nil {
return conn, nil
}
if err == error_sem_timeout {
// This is WaitNamedPipe's timeout error, so we know we're done
return nil, PipeError{fmt.Sprintf(
"Timed out waiting for pipe '%s' to come available", address), true}
}
if isPipeNotReady(err) {
left := deadline.Sub(time.Now())
retry := 100 * time.Millisecond
if left > retry {
<-time.After(retry)
} else {
<-time.After(left - time.Millisecond)
}
now = time.Now()
continue
}
return nil, err
}
return nil, PipeError{fmt.Sprintf(
"Timed out waiting for pipe '%s' to come available", address), true}
}
// isPipeNotReady checks the error to see if it indicates the pipe is not ready
func isPipeNotReady(err error) bool {
// Pipe Busy means another client just grabbed the open pipe end,
// and the server hasn't made a new one yet.
// File Not Found means the server hasn't created the pipe yet.
// Neither is a fatal error.
return err == syscall.ERROR_FILE_NOT_FOUND || err == error_pipe_busy
}
// newOverlapped creates a structure used to track asynchronous
// I/O requests that have been issued.
func newOverlapped() (*syscall.Overlapped, error) {
event, err := createEvent(nil, true, true, nil)
if err != nil {
return nil, err
}
return &syscall.Overlapped{HEvent: event}, nil
}
// waitForCompletion waits for an asynchronous I/O request referred to by overlapped to complete.
// This function returns the number of bytes transferred by the operation and an error code if
// applicable (nil otherwise).
func waitForCompletion(handle syscall.Handle, overlapped *syscall.Overlapped) (uint32, error) {
_, err := syscall.WaitForSingleObject(overlapped.HEvent, syscall.INFINITE)
if err != nil {
return 0, err
}
var transferred uint32
err = getOverlappedResult(handle, overlapped, &transferred, true)
return transferred, err
}
// dial is a helper to initiate a connection to a named pipe that has been started by a server.
// The timeout is only enforced if the pipe server has already created the pipe, otherwise
// this function will return immediately.
func dial(address string, timeout uint32) (*PipeConn, error) {
name, err := syscall.UTF16PtrFromString(string(address))
if err != nil {
return nil, err
}
// If at least one instance of the pipe has been created, this function
// will wait timeout milliseconds for it to become available.
// It will return immediately regardless of timeout, if no instances
// of the named pipe have been created yet.
// If this returns with no error, there is a pipe available.
if err := waitNamedPipe(name, timeout); err != nil {
if err == error_bad_pathname {
// badly formatted pipe name
return nil, badAddr(address)
}
return nil, err
}
pathp, err := syscall.UTF16PtrFromString(address)
if err != nil {
return nil, err
}
handle, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE,
uint32(syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE), nil, syscall.OPEN_EXISTING,
syscall.FILE_FLAG_OVERLAPPED, 0)
if err != nil {
return nil, err
}
return &PipeConn{handle: handle, addr: PipeAddr(address)}, nil
}
// Listen returns a new PipeListener that will listen on a pipe with the given
// address. The address must be of the form \\.\pipe\<name>
//
// Listen will return a PipeError for an incorrectly formatted pipe name.
func Listen(address string) (*PipeListener, error) {
handle, err := createPipe(address, true)
if err == error_invalid_name {
return nil, badAddr(address)
}
if err != nil {
return nil, err
}
return &PipeListener{
addr: PipeAddr(address),
handle: handle,
}, nil
}
// PipeListener is a named pipe listener. Clients should typically
// use variables of type net.Listener instead of assuming named pipe.
type PipeListener struct {
addr PipeAddr
handle syscall.Handle
closed bool
// acceptHandle contains the current handle waiting for
// an incoming connection or nil.
acceptHandle syscall.Handle
// acceptOverlapped is set before waiting on a connection.
// If not waiting, it is nil.
acceptOverlapped *syscall.Overlapped
// acceptMutex protects the handle and overlapped structure.
acceptMutex sync.Mutex
}
// Accept implements the Accept method in the net.Listener interface; it
// waits for the next call and returns a generic net.Conn.
func (l *PipeListener) Accept() (net.Conn, error) {
c, err := l.AcceptPipe()
for err == error_no_data {
// Ignore clients that connect and immediately disconnect.
c, err = l.AcceptPipe()
}
if err != nil {
return nil, err
}
return c, nil
}
// AcceptPipe accepts the next incoming call and returns the new connection.
// It might return an error if a client connected and immediately cancelled
// the connection.
func (l *PipeListener) AcceptPipe() (*PipeConn, error) {
if l == nil || l.addr == "" || l.closed {
return nil, syscall.EINVAL
}
// the first time we call accept, the handle will have been created by the Listen
// call. This is to prevent race conditions where the client thinks the server
// isn't listening because it hasn't actually called create yet. After the first time, we'll
// have to create a new handle each time
handle := l.handle
if handle == 0 {
var err error
handle, err = createPipe(string(l.addr), false)
if err != nil {
return nil, err
}
} else {
l.handle = 0
}
overlapped, err := newOverlapped()
if err != nil {
return nil, err
}
defer syscall.CloseHandle(overlapped.HEvent)
if err := connectNamedPipe(handle, overlapped); err != nil && err != error_pipe_connected {
if err == error_io_incomplete || err == syscall.ERROR_IO_PENDING {
l.acceptMutex.Lock()
l.acceptOverlapped = overlapped
l.acceptHandle = handle
l.acceptMutex.Unlock()
defer func() {
l.acceptMutex.Lock()
l.acceptOverlapped = nil
l.acceptHandle = 0
l.acceptMutex.Unlock()
}()
_, err = waitForCompletion(handle, overlapped)
}
if err == syscall.ERROR_OPERATION_ABORTED {
// Return error compatible to net.Listener.Accept() in case the
// listener was closed.
return nil, ErrClosed
}
if err != nil {
return nil, err
}
}
return &PipeConn{handle: handle, addr: l.addr}, nil
}
// Close stops listening on the address.
// Already Accepted connections are not closed.
func (l *PipeListener) Close() error {
if l.closed {
return nil
}
l.closed = true
if l.handle != 0 {
err := disconnectNamedPipe(l.handle)
if err != nil {
return err
}
err = syscall.CloseHandle(l.handle)
if err != nil {
return err
}
l.handle = 0
}
l.acceptMutex.Lock()
defer l.acceptMutex.Unlock()
if l.acceptOverlapped != nil && l.acceptHandle != 0 {
// Cancel the pending IO. This call does not block, so it is safe
// to hold onto the mutex above.
if err := cancelIoEx(l.acceptHandle, l.acceptOverlapped); err != nil {
return err
}
err := syscall.CloseHandle(l.acceptOverlapped.HEvent)
if err != nil {
return err
}
l.acceptOverlapped.HEvent = 0
err = syscall.CloseHandle(l.acceptHandle)
if err != nil {
return err
}
l.acceptHandle = 0
}
return nil
}
// Addr returns the listener's network address, a PipeAddr.
func (l *PipeListener) Addr() net.Addr { return l.addr }
// PipeConn is the implementation of the net.Conn interface for named pipe connections.
type PipeConn struct {
handle syscall.Handle
addr PipeAddr
// these aren't actually used yet
readDeadline *time.Time
writeDeadline *time.Time
}
type iodata struct {
n uint32
err error
}
// completeRequest looks at iodata to see if a request is pending. If so, it waits for it to either complete or to
// abort due to hitting the specified deadline. Deadline may be set to nil to wait forever. If no request is pending,
// the content of iodata is returned.
func (c *PipeConn) completeRequest(data iodata, deadline *time.Time, overlapped *syscall.Overlapped) (int, error) {
if data.err == error_io_incomplete || data.err == syscall.ERROR_IO_PENDING {
var timer <-chan time.Time
if deadline != nil {
if timeDiff := deadline.Sub(time.Now()); timeDiff > 0 {
timer = time.After(timeDiff)
}
}
done := make(chan iodata)
go func() {
n, err := waitForCompletion(c.handle, overlapped)
done <- iodata{n, err}
}()
select {
case data = <-done:
case <-timer:
syscall.CancelIoEx(c.handle, overlapped)
data = iodata{0, timeout(c.addr.String())}
}
}
// Windows will produce ERROR_BROKEN_PIPE upon closing
// a handle on the other end of a connection. Go RPC
// expects an io.EOF error in this case.
if data.err == syscall.ERROR_BROKEN_PIPE {
data.err = io.EOF
}
return int(data.n), data.err
}
// Read implements the net.Conn Read method.
func (c *PipeConn) Read(b []byte) (int, error) {
// Use ReadFile() rather than Read() because the latter
// contains a workaround that eats ERROR_BROKEN_PIPE.
overlapped, err := newOverlapped()
if err != nil {
return 0, err
}
defer syscall.CloseHandle(overlapped.HEvent)
var n uint32
err = syscall.ReadFile(c.handle, b, &n, overlapped)
return c.completeRequest(iodata{n, err}, c.readDeadline, overlapped)
}
// Write implements the net.Conn Write method.
func (c *PipeConn) Write(b []byte) (int, error) {
overlapped, err := newOverlapped()
if err != nil {
return 0, err
}
defer syscall.CloseHandle(overlapped.HEvent)
var n uint32
err = syscall.WriteFile(c.handle, b, &n, overlapped)
return c.completeRequest(iodata{n, err}, c.writeDeadline, overlapped)
}
// Close closes the connection.
func (c *PipeConn) Close() error {
return syscall.CloseHandle(c.handle)
}
// LocalAddr returns the local network address.
func (c *PipeConn) LocalAddr() net.Addr {
return c.addr
}
// RemoteAddr returns the remote network address.
func (c *PipeConn) RemoteAddr() net.Addr {
// not sure what to do here, we don't have remote addr....
return c.addr
}
// SetDeadline implements the net.Conn SetDeadline method.
// Note that timeouts are only supported on Windows Vista/Server 2008 and above
func (c *PipeConn) SetDeadline(t time.Time) error {
c.SetReadDeadline(t)
c.SetWriteDeadline(t)
return nil
}
// SetReadDeadline implements the net.Conn SetReadDeadline method.
// Note that timeouts are only supported on Windows Vista/Server 2008 and above
func (c *PipeConn) SetReadDeadline(t time.Time) error {
c.readDeadline = &t
return nil
}
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
// Note that timeouts are only supported on Windows Vista/Server 2008 and above
func (c *PipeConn) SetWriteDeadline(t time.Time) error {
c.writeDeadline = &t
return nil
}
// PipeAddr represents the address of a named pipe.
type PipeAddr string
// Network returns the address's network name, "pipe".
func (a PipeAddr) Network() string { return "pipe" }
// String returns the address of the pipe
func (a PipeAddr) String() string {
return string(a)
}
// createPipe is a helper function to make sure we always create pipes
// with the same arguments, since subsequent calls to create pipe need
// to use the same arguments as the first one. If first is set, fail
// if the pipe already exists.
func createPipe(address string, first bool) (syscall.Handle, error) {
n, err := syscall.UTF16PtrFromString(address)
if err != nil {
return 0, err
}
mode := uint32(pipe_access_duplex | syscall.FILE_FLAG_OVERLAPPED)
if first {
mode |= file_flag_first_pipe_instance
}
return createNamedPipe(n,
mode,
pipe_type_byte,
pipe_unlimited_instances,
512, 512, 0, nil)
}
func badAddr(addr string) PipeError {
return PipeError{fmt.Sprintf("Invalid pipe address '%s'.", addr), false}
}
func timeout(addr string) PipeError {
return PipeError{fmt.Sprintf("Pipe IO timed out waiting for '%s'", addr), true}
}
func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
c, err := Dial(cfg.Endpoint)
if err != nil {
return nil, err
}
coder := codec.New(c)
msg := shared.Request{
Id: 0,
Method: useragent.EnableUserAgentMethod,
Jsonrpc: shared.JsonRpcVersion,
Params: []byte("[]"),
}
coder.WriteResponse(msg)
coder.Recv()
return &ipcClient{cfg.Endpoint, c, codec, coder}, nil
}
func (self *ipcClient) reconnect() error {
c, err := Dial(self.endpoint)
if err == nil {
self.coder = self.codec.New(c)
req := shared.Request{
Id: 0,
Method: useragent.EnableUserAgentMethod,
Jsonrpc: shared.JsonRpcVersion,
Params: []byte("[]"),
}
self.coder.WriteResponse(req)
self.coder.Recv()
}
return err
}
func ipcListen(cfg IpcConfig) (net.Listener, error) {
os.Remove(cfg.Endpoint) // in case it still exists from a previous run
l, err := Listen(cfg.Endpoint)
if err != nil {
return nil, err
}
os.Chmod(cfg.Endpoint, 0600)
return l, nil
}

View file

@ -1,178 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package rpc
import (
"encoding/json"
"fmt"
"github.com/expanse-project/go-expanse/cmd/utils"
"github.com/expanse-project/go-expanse/jsre"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rpc/comms"
"github.com/expanse-project/go-expanse/rpc/shared"
"github.com/expanse-project/go-expanse/rpc/useragent"
"github.com/expanse-project/go-expanse/xeth"
"github.com/robertkrimen/otto"
)
type Jeth struct {
ethApi shared.ExpanseApi
re *jsre.JSRE
client comms.ExpanseClient
fe xexp.Frontend
}
func NewJeth(ethApi shared.ExpanseApi, re *jsre.JSRE, client comms.ExpanseClient, fe xexp.Frontend) *Jeth {
return &Jeth{ethApi, re, client, fe}
}
func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface{}) (response otto.Value) {
m := shared.NewRpcErrorResponse(id, shared.JsonRpcVersion, code, fmt.Errorf(msg))
errObj, _ := json.Marshal(m.Error)
errRes, _ := json.Marshal(m)
call.Otto.Run("ret_error = " + string(errObj))
res, _ := call.Otto.Run("ret_response = " + string(errRes))
return res
}
func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
reqif, err := call.Argument(0).Export()
if err != nil {
return self.err(call, -32700, err.Error(), nil)
}
jsonreq, err := json.Marshal(reqif)
var reqs []shared.Request
batch := true
err = json.Unmarshal(jsonreq, &reqs)
if err != nil {
reqs = make([]shared.Request, 1)
err = json.Unmarshal(jsonreq, &reqs[0])
batch = false
}
call.Otto.Set("response_len", len(reqs))
call.Otto.Run("var ret_response = new Array(response_len);")
for i, req := range reqs {
var respif interface{}
err := self.client.Send(&req)
if err != nil {
return self.err(call, -32603, err.Error(), req.Id)
}
recv:
respif, err = self.client.Recv()
if err != nil {
return self.err(call, -32603, err.Error(), req.Id)
}
agentreq, isRequest := respif.(*shared.Request)
if isRequest {
self.handleRequest(agentreq)
goto recv // receive response after agent interaction
}
sucres, isSuccessResponse := respif.(*shared.SuccessResponse)
errres, isErrorResponse := respif.(*shared.ErrorResponse)
if !isSuccessResponse && !isErrorResponse {
return self.err(call, -32603, fmt.Sprintf("Invalid response type (%T)", respif), req.Id)
}
call.Otto.Set("ret_jsonrpc", shared.JsonRpcVersion)
call.Otto.Set("ret_id", req.Id)
var res []byte
if isSuccessResponse {
res, err = json.Marshal(sucres.Result)
} else if isErrorResponse {
res, err = json.Marshal(errres.Error)
}
call.Otto.Set("ret_result", string(res))
call.Otto.Set("response_idx", i)
response, err = call.Otto.Run(`
ret_response[response_idx] = { jsonrpc: ret_jsonrpc, id: ret_id, result: JSON.parse(ret_result) };
`)
}
if !batch {
call.Otto.Run("ret_response = ret_response[0];")
}
if call.Argument(1).IsObject() {
call.Otto.Set("callback", call.Argument(1))
call.Otto.Run(`
if (Object.prototype.toString.call(callback) == '[object Function]') {
callback(null, ret_response);
}
`)
}
return
}
// handleRequest will handle user agent requests by interacting with the user and sending
// the user response back to the gexp service
func (self *Jeth) handleRequest(req *shared.Request) bool {
var err error
var args []interface{}
if err = json.Unmarshal(req.Params, &args); err != nil {
glog.V(logger.Info).Infof("Unable to parse agent request - %v\n", err)
return false
}
switch req.Method {
case useragent.AskPasswordMethod:
return self.askPassword(req.Id, req.Jsonrpc, args)
case useragent.ConfirmTransactionMethod:
return self.confirmTransaction(req.Id, req.Jsonrpc, args)
}
return false
}
// askPassword will ask the user to supply the password for a given account
func (self *Jeth) askPassword(id interface{}, jsonrpc string, args []interface{}) bool {
var err error
var passwd string
if len(args) >= 1 {
if account, ok := args[0].(string); ok {
fmt.Printf("Unlock account %s\n", account)
} else {
return false
}
}
passwd, err = utils.PromptPassword("Passphrase: ", true)
if err = self.client.Send(shared.NewRpcResponse(id, jsonrpc, passwd, err)); err != nil {
glog.V(logger.Info).Infof("Unable to send user agent ask password response - %v\n", err)
}
return err == nil
}
func (self *Jeth) confirmTransaction(id interface{}, jsonrpc string, args []interface{}) bool {
// Accept all tx which are send from this console
return self.client.Send(shared.NewRpcResponse(id, jsonrpc, true, nil)) == nil
}

View file

@ -32,9 +32,9 @@ import (
const ( const (
jsonRPCVersion = "2.0" jsonRPCVersion = "2.0"
serviceMethodSeparator = "_" serviceMethodSeparator = "_"
subscribeMethod = "eth_subscribe" subscribeMethod = "exp_subscribe"
unsubscribeMethod = "eth_unsubscribe" unsubscribeMethod = "exp_unsubscribe"
notificationMethod = "eth_subscription" notificationMethod = "exp_subscription"
) )
// JSON-RPC request // JSON-RPC request

View file

@ -34,8 +34,8 @@ const (
notificationBufferSize = 10000 // max buffered notifications before codec is closed notificationBufferSize = 10000 // max buffered notifications before codec is closed
DefaultIPCApis = "admin,eth,debug,miner,net,shh,txpool,personal,web3" DefaultIPCApis = "admin,exp,eth,debug,miner,net,shh,txpool,personal,web3"
DefaultHTTPApis = "eth,net,web3" DefaultHTTPApis = "exp,eth,net,web3"
) )
// CodecOption specifies which type of messages this codec supports // CodecOption specifies which type of messages this codec supports

View file

@ -1,126 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package shared
import "fmt"
type InvalidTypeError struct {
method string
msg string
}
func (e *InvalidTypeError) Error() string {
return fmt.Sprintf("invalid type on field %s: %s", e.method, e.msg)
}
func NewInvalidTypeError(method, msg string) *InvalidTypeError {
return &InvalidTypeError{
method: method,
msg: msg,
}
}
type InsufficientParamsError struct {
have int
want int
}
func (e *InsufficientParamsError) Error() string {
return fmt.Sprintf("insufficient params, want %d have %d", e.want, e.have)
}
func NewInsufficientParamsError(have int, want int) *InsufficientParamsError {
return &InsufficientParamsError{
have: have,
want: want,
}
}
type NotImplementedError struct {
Method string
}
func (e *NotImplementedError) Error() string {
return fmt.Sprintf("%s method not implemented", e.Method)
}
func NewNotImplementedError(method string) *NotImplementedError {
return &NotImplementedError{
Method: method,
}
}
type NotReadyError struct {
Resource string
}
func (e *NotReadyError) Error() string {
return fmt.Sprintf("%s not ready", e.Resource)
}
func NewNotReadyError(resource string) *NotReadyError {
return &NotReadyError{
Resource: resource,
}
}
type DecodeParamError struct {
err string
}
func (e *DecodeParamError) Error() string {
return fmt.Sprintf("could not decode, %s", e.err)
}
func NewDecodeParamError(errstr string) error {
return &DecodeParamError{
err: errstr,
}
}
type ValidationError struct {
ParamName string
msg string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("%s not valid, %s", e.ParamName, e.msg)
}
func NewValidationError(param string, msg string) error {
return &ValidationError{
ParamName: param,
msg: msg,
}
}
type NotAvailableError struct {
Method string
Reason string
}
func (e *NotAvailableError) Error() string {
return fmt.Sprintf("%s method not available: %s", e.Method, e.Reason)
}
func NewNotAvailableError(method string, reason string) *NotAvailableError {
return &NotAvailableError{
Method: method,
Reason: reason,
}
}

View file

@ -1,108 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package shared
import (
"encoding/json"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
)
// Expanse RPC API interface
type ExpanseApi interface {
// API identifier
Name() string
// API version
ApiVersion() string
// Execute the given request and returns the response or an error
Execute(*Request) (interface{}, error)
// List of supported RCP methods this API provides
Methods() []string
}
// RPC request
type Request struct {
Id interface{} `json:"id"`
Jsonrpc string `json:"jsonrpc"`
Method string `json:"method"`
Params json.RawMessage `json:"params"`
}
// RPC response
type Response struct {
Id interface{} `json:"id"`
Jsonrpc string `json:"jsonrpc"`
}
// RPC success response
type SuccessResponse struct {
Id interface{} `json:"id"`
Jsonrpc string `json:"jsonrpc"`
Result interface{} `json:"result"`
}
// RPC error response
type ErrorResponse struct {
Id interface{} `json:"id"`
Jsonrpc string `json:"jsonrpc"`
Error *ErrorObject `json:"error"`
}
// RPC error response details
type ErrorObject struct {
Code int `json:"code"`
Message string `json:"message"`
// Data interface{} `json:"data"`
}
// Create RPC error response, this allows for custom error codes
func NewRpcErrorResponse(id interface{}, jsonrpcver string, errCode int, err error) *ErrorResponse {
jsonerr := &ErrorObject{errCode, err.Error()}
response := ErrorResponse{Jsonrpc: jsonrpcver, Id: id, Error: jsonerr}
glog.V(logger.Detail).Infof("Generated error response: %s", response)
return &response
}
// Create RPC response
func NewRpcResponse(id interface{}, jsonrpcver string, reply interface{}, err error) *interface{} {
var response interface{}
switch err.(type) {
case nil:
response = &SuccessResponse{Jsonrpc: jsonrpcver, Id: id, Result: reply}
case *NotImplementedError:
jsonerr := &ErrorObject{-32601, err.Error()}
response = &ErrorResponse{Jsonrpc: jsonrpcver, Id: id, Error: jsonerr}
case *NotReadyError:
jsonerr := &ErrorObject{-32000, err.Error()}
response = &ErrorResponse{Jsonrpc: jsonrpcver, Id: id, Error: jsonerr}
case *DecodeParamError, *InsufficientParamsError, *ValidationError, *InvalidTypeError:
jsonerr := &ErrorObject{-32602, err.Error()}
response = &ErrorResponse{Jsonrpc: jsonrpcver, Id: id, Error: jsonerr}
default:
jsonerr := &ErrorObject{-32603, err.Error()}
response = &ErrorResponse{Jsonrpc: jsonrpcver, Id: id, Error: jsonerr}
}
glog.V(logger.Detail).Infof("Generated response: %T %s", response, response)
return &response
}

View file

@ -1,166 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
package useragent
import (
"encoding/json"
"fmt"
"net"
"github.com/expanse-project/go-expanse/accounts"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rpc/shared"
)
// remoteFrontend implements xexp.Frontend and will communicate with an external
// user agent over a connection
type RemoteFrontend struct {
enabled bool
mgr *accounts.Manager
d *json.Decoder
e *json.Encoder
n int
}
// NewRemoteFrontend creates a new frontend which will interact with an user agent
// over the given connection
func NewRemoteFrontend(conn net.Conn, mgr *accounts.Manager) *RemoteFrontend {
return &RemoteFrontend{false, mgr, json.NewDecoder(conn), json.NewEncoder(conn), 0}
}
// Enable will enable user interaction
func (fe *RemoteFrontend) Enable() {
fe.enabled = true
}
func (fe *RemoteFrontend) AskPassword() (string, bool) {
if !fe.enabled {
return "", false
}
err := fe.send(AskPasswordMethod)
if err != nil {
glog.V(logger.Error).Infof("Unable to send password request to agent - %v\n", err)
return "", false
}
passwdRes, err := fe.recv()
if err != nil {
glog.V(logger.Error).Infof("Unable to recv password response from agent - %v\n", err)
return "", false
}
if passwd, ok := passwdRes.Result.(string); ok {
return passwd, true
}
return "", false
}
// UnlockAccount asks the user agent for the user password and tries to unlock the account.
// It will try 3 attempts before giving up.
func (fe *RemoteFrontend) UnlockAccount(address []byte) bool {
if !fe.enabled {
return false
}
err := fe.send(AskPasswordMethod, common.Bytes2Hex(address))
if err != nil {
glog.V(logger.Error).Infof("Unable to send password request to agent - %v\n", err)
return false
}
passwdRes, err := fe.recv()
if err != nil {
glog.V(logger.Error).Infof("Unable to recv password response from agent - %v\n", err)
return false
}
if passwd, ok := passwdRes.Result.(string); ok {
err = fe.mgr.Unlock(common.BytesToAddress(address), passwd)
}
if err == nil {
return true
}
glog.V(logger.Debug).Infoln("3 invalid account unlock attempts")
return false
}
// ConfirmTransaction asks the user for approval
func (fe *RemoteFrontend) ConfirmTransaction(tx string) bool {
if !fe.enabled {
return true // backwards compatibility
}
err := fe.send(ConfirmTransactionMethod, tx)
if err != nil {
glog.V(logger.Error).Infof("Unable to send tx confirmation request to agent - %v\n", err)
return false
}
confirmResponse, err := fe.recv()
if err != nil {
glog.V(logger.Error).Infof("Unable to recv tx confirmation response from agent - %v\n", err)
return false
}
if confirmed, ok := confirmResponse.Result.(bool); ok {
return confirmed
}
return false
}
// send request to the agent
func (fe *RemoteFrontend) send(method string, params ...interface{}) error {
fe.n += 1
p, err := json.Marshal(params)
if err != nil {
glog.V(logger.Info).Infof("Unable to send agent request %v\n", err)
return err
}
req := shared.Request{
Method: method,
Jsonrpc: shared.JsonRpcVersion,
Id: fe.n,
Params: p,
}
return fe.e.Encode(&req)
}
// recv user response from agent
func (fe *RemoteFrontend) recv() (*shared.SuccessResponse, error) {
var res json.RawMessage
if err := fe.d.Decode(&res); err != nil {
return nil, err
}
var response shared.SuccessResponse
if err := json.Unmarshal(res, &response); err == nil {
return &response, nil
}
return nil, fmt.Errorf("Invalid user agent response")
}

View file

@ -1,77 +0,0 @@
// Copyright 2015 The go-expanse Authors
// This file is part of the go-expanse library.
//
// The go-expanse 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-expanse 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-expanse library. If not, see <http://www.gnu.org/licenses/>.
// Package rpc implements the Expanse JSON-RPC API.
package rpc
import (
"encoding/json"
"fmt"
"reflect"
"sync/atomic"
"github.com/expanse-project/go-expanse/rpc/comms"
"github.com/expanse-project/go-expanse/rpc/shared"
)
// Xeth is a native API interface to a remote node.
type Xeth struct {
client comms.ExpanseClient
reqId uint32
}
// NewXeth constructs a new native API interface to a remote node.
func NewXeth(client comms.ExpanseClient) *Xeth {
return &Xeth{
client: client,
}
}
// Call invokes a method with the given parameters are the remote node.
func (self *Xeth) Call(method string, params []interface{}) (map[string]interface{}, error) {
// Assemble the json RPC request
data, err := json.Marshal(params)
if err != nil {
return nil, err
}
req := &shared.Request{
Id: atomic.AddUint32(&self.reqId, 1),
Jsonrpc: "2.0",
Method: method,
Params: data,
}
// Send the request over and retrieve the response
if err := self.client.Send(req); err != nil {
return nil, err
}
res, err := self.client.Recv()
if err != nil {
return nil, err
}
// Ensure the response is valid, and extract the results
success, isSuccessResponse := res.(*shared.SuccessResponse)
failure, isFailureResponse := res.(*shared.ErrorResponse)
switch {
case isFailureResponse:
return nil, fmt.Errorf("Method invocation failed: %v", failure.Error)
case isSuccessResponse:
return success.Result.(map[string]interface{}), nil
default:
return nil, fmt.Errorf("Invalid response type: %v", reflect.TypeOf(res))
}
}

View file

@ -26,7 +26,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/expanse-org/ethash" "github.com/expanse-project/ethash"
"github.com/expanse-project/go-expanse/common" "github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/core" "github.com/expanse-project/go-expanse/core"
"github.com/expanse-project/go-expanse/core/state" "github.com/expanse-project/go-expanse/core/state"

View file

@ -1,7 +1,6 @@
// Copyright 2014 The go-ethereum Authors // Copyright 2014 The go-ethereum Authors
// Copyright 2015 go-expanse Authors // Copyright 2015 go-expanse Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
>>>>>>> ethereum/master
// //
// The go-expanse library is free software: you can redistribute it and/or modify // The go-expanse 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 // it under the terms of the GNU Lesser General Public License as published by

View file

@ -21,7 +21,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math/big"
"runtime" "runtime"
"github.com/expanse-project/go-expanse/common" "github.com/expanse-project/go-expanse/common"
@ -92,8 +91,6 @@ func RunTransactionTests(file string, skipTests []string) error {
} }
func runTransactionTests(tests map[string]TransactionTest, skipTests []string) error { func runTransactionTests(tests map[string]TransactionTest, skipTests []string) error {
params.HomesteadBlock = big.NewInt(900000)
skipTest := make(map[string]bool, len(skipTests)) skipTest := make(map[string]bool, len(skipTests))
for _, name := range skipTests { for _, name := range skipTests {
skipTest[name] = true skipTest[name] = true

View file

@ -22,12 +22,8 @@ import (
"testing" "testing"
"time" "time"
<<<<<<< HEAD
"github.com/expanse-project/go-expanse/crypto"
=======
"github.com/expanse-project/go-expanse/crypto" "github.com/expanse-project/go-expanse/crypto"
"github.com/expanse-project/go-expanse/crypto/secp256k1" "github.com/expanse-project/go-expanse/crypto/secp256k1"
>>>>>>> ethereum/master
) )
// Tests whether a message can be wrapped without any identity or encryption. // Tests whether a message can be wrapped without any identity or encryption.

View file

@ -21,15 +21,6 @@ import (
"sync" "sync"
"time" "time"
<<<<<<< HEAD
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/crypto"
"github.com/expanse-project/go-expanse/crypto/ecies"
"github.com/expanse-project/go-expanse/event/filter"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/p2p"
=======
"github.com/expanse-project/go-expanse/common" "github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/crypto" "github.com/expanse-project/go-expanse/crypto"
"github.com/expanse-project/go-expanse/crypto/ecies" "github.com/expanse-project/go-expanse/crypto/ecies"
@ -38,8 +29,6 @@ import (
"github.com/expanse-project/go-expanse/logger/glog" "github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/p2p" "github.com/expanse-project/go-expanse/p2p"
"github.com/expanse-project/go-expanse/rpc" "github.com/expanse-project/go-expanse/rpc"
>>>>>>> ethereum/master
"gopkg.in/fatih/set.v0" "gopkg.in/fatih/set.v0"
) )