Merge pull request #1429 from obscuren/rebase-registrar
Rebase registrar
This commit is contained in:
commit
916d155467
@ -86,7 +86,6 @@ func runBlockTest(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, error) {
|
func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, error) {
|
||||||
// TODO remove in favor of logic contained in tests package
|
|
||||||
cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
|
cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
|
||||||
cfg.NewDB = func(path string) (common.Database, error) { return ethdb.NewMemDatabase() }
|
cfg.NewDB = func(path string) (common.Database, error) { return ethdb.NewMemDatabase() }
|
||||||
cfg.MaxPeers = 0 // disable network
|
cfg.MaxPeers = 0 // disable network
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
var (
|
|
||||||
globalRegistrar = `var GlobalRegistrar = web3.eth.contract([{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"name","outputs":[{"name":"o_name","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"content","outputs":[{"name":"","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"addr","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"subRegistrar","outputs":[{"name":"o_subRegistrar","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_newOwner","type":"address"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_registrar","type":"address"}],"name":"setSubRegistrar","outputs":[],"type":"function"},{"constant":false,"inputs":[],"name":"Registrar","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_a","type":"address"},{"name":"_primary","type":"bool"}],"name":"setAddress","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_content","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"disown","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"address"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"}],"name":"Changed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"addr","type":"address"}],"name":"PrimaryChanged","type":"event"}]);`
|
|
||||||
globalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b"
|
|
||||||
)
|
|
@ -32,16 +32,17 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/docserver"
|
"github.com/ethereum/go-ethereum/common/docserver"
|
||||||
"github.com/ethereum/go-ethereum/common/natspec"
|
"github.com/ethereum/go-ethereum/common/natspec"
|
||||||
|
"github.com/ethereum/go-ethereum/common/registrar"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
re "github.com/ethereum/go-ethereum/jsre"
|
re "github.com/ethereum/go-ethereum/jsre"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/rpc/api"
|
"github.com/ethereum/go-ethereum/rpc/api"
|
||||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
"github.com/ethereum/go-ethereum/rpc/comms"
|
"github.com/ethereum/go-ethereum/rpc/comms"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
"github.com/peterh/liner"
|
"github.com/peterh/liner"
|
||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
"github.com/ethereum/go-ethereum/rpc/shared"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type prompter interface {
|
type prompter interface {
|
||||||
@ -69,6 +70,7 @@ func (r dumbterm) PasswordPrompt(p string) (string, error) {
|
|||||||
func (r dumbterm) AppendHistory(string) {}
|
func (r dumbterm) AppendHistory(string) {}
|
||||||
|
|
||||||
type jsre struct {
|
type jsre struct {
|
||||||
|
ds *docserver.DocServer
|
||||||
re *re.JSRE
|
re *re.JSRE
|
||||||
ethereum *eth.Ethereum
|
ethereum *eth.Ethereum
|
||||||
xeth *xeth.XEth
|
xeth *xeth.XEth
|
||||||
@ -143,6 +145,7 @@ func newLightweightJSRE(libPath string, client comms.EthereumClient, interactive
|
|||||||
js := &jsre{ps1: "> "}
|
js := &jsre{ps1: "> "}
|
||||||
js.wait = make(chan *big.Int)
|
js.wait = make(chan *big.Int)
|
||||||
js.client = client
|
js.client = client
|
||||||
|
js.ds = docserver.New("/")
|
||||||
|
|
||||||
if f == nil {
|
if f == nil {
|
||||||
f = js
|
f = js
|
||||||
@ -180,6 +183,7 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, client comms.Et
|
|||||||
if f == nil {
|
if f == nil {
|
||||||
f = js
|
f = js
|
||||||
}
|
}
|
||||||
|
js.ds = docserver.New("/")
|
||||||
js.xeth = xeth.New(ethereum, f)
|
js.xeth = xeth.New(ethereum, f)
|
||||||
js.wait = js.xeth.UpdateState()
|
js.wait = js.xeth.UpdateState()
|
||||||
js.client = client
|
js.client = client
|
||||||
@ -331,15 +335,13 @@ func (js *jsre) apiBindings(f xeth.Frontend) error {
|
|||||||
utils.Fatalf("Error setting namespaces: %v", err)
|
utils.Fatalf("Error setting namespaces: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
js.re.Eval(globalRegistrar + "registrar = GlobalRegistrar.at(\"" + globalRegistrarAddr + "\");")
|
js.re.Eval(`var GlobalRegistrar = eth.contract(` + registrar.GlobalRegistrarAbi + `); registrar = GlobalRegistrar.at("` + registrar.GlobalRegistrarAddr + `");`)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var ds, _ = docserver.New("/")
|
|
||||||
|
|
||||||
func (self *jsre) ConfirmTransaction(tx string) bool {
|
func (self *jsre) ConfirmTransaction(tx string) bool {
|
||||||
if self.ethereum.NatSpec {
|
if self.ethereum.NatSpec {
|
||||||
notice := natspec.GetNotice(self.xeth, tx, ds)
|
notice := natspec.GetNotice(self.xeth, tx, self.ds)
|
||||||
fmt.Println(notice)
|
fmt.Println(notice)
|
||||||
answer, _ := self.Prompt("Confirm Transaction [y/n]")
|
answer, _ := self.Prompt("Confirm Transaction [y/n]")
|
||||||
return strings.HasPrefix(strings.Trim(answer, " "), "y")
|
return strings.HasPrefix(strings.Trim(answer, " "), "y")
|
||||||
|
@ -3,21 +3,22 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/compiler"
|
"github.com/ethereum/go-ethereum/common/compiler"
|
||||||
"github.com/ethereum/go-ethereum/common/docserver"
|
"github.com/ethereum/go-ethereum/common/docserver"
|
||||||
"github.com/ethereum/go-ethereum/common/natspec"
|
"github.com/ethereum/go-ethereum/common/natspec"
|
||||||
"github.com/ethereum/go-ethereum/common/resolver"
|
"github.com/ethereum/go-ethereum/common/registrar"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
@ -43,7 +44,6 @@ var (
|
|||||||
|
|
||||||
type testjethre struct {
|
type testjethre struct {
|
||||||
*jsre
|
*jsre
|
||||||
stateDb *state.StateDB
|
|
||||||
lastConfirm string
|
lastConfirm string
|
||||||
ds *docserver.DocServer
|
ds *docserver.DocServer
|
||||||
}
|
}
|
||||||
@ -64,6 +64,10 @@ func (self *testjethre) ConfirmTransaction(tx string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
|
func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
|
||||||
|
return testREPL(t, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *eth.Ethereum) {
|
||||||
tmp, err := ioutil.TempDir("", "geth-test")
|
tmp, err := ioutil.TempDir("", "geth-test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -74,14 +78,19 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
|
|||||||
|
|
||||||
ks := crypto.NewKeyStorePlain(filepath.Join(tmp, "keystore"))
|
ks := crypto.NewKeyStorePlain(filepath.Join(tmp, "keystore"))
|
||||||
am := accounts.NewManager(ks)
|
am := accounts.NewManager(ks)
|
||||||
ethereum, err := eth.New(ð.Config{
|
conf := ð.Config{
|
||||||
NodeKey: testNodeKey,
|
NodeKey: testNodeKey,
|
||||||
DataDir: tmp,
|
DataDir: tmp,
|
||||||
AccountManager: am,
|
AccountManager: am,
|
||||||
MaxPeers: 0,
|
MaxPeers: 0,
|
||||||
Name: "test",
|
Name: "test",
|
||||||
SolcPath: testSolcPath,
|
SolcPath: testSolcPath,
|
||||||
})
|
PowTest: true,
|
||||||
|
}
|
||||||
|
if config != nil {
|
||||||
|
config(conf)
|
||||||
|
}
|
||||||
|
ethereum, err := eth.New(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("%v", err)
|
t.Fatal("%v", err)
|
||||||
}
|
}
|
||||||
@ -102,25 +111,16 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assetPath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext")
|
assetPath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext")
|
||||||
ds, err := docserver.New("/")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error creating DocServer: %v", err)
|
|
||||||
}
|
|
||||||
tf := &testjethre{ds: ds, stateDb: ethereum.ChainManager().State().Copy()}
|
|
||||||
client := comms.NewInProcClient(codec.JSON)
|
client := comms.NewInProcClient(codec.JSON)
|
||||||
|
ds := docserver.New("/")
|
||||||
|
tf := &testjethre{ds: ds}
|
||||||
repl := newJSRE(ethereum, assetPath, "", client, false, tf)
|
repl := newJSRE(ethereum, assetPath, "", client, false, tf)
|
||||||
tf.jsre = repl
|
tf.jsre = repl
|
||||||
return tmp, tf, ethereum
|
return tmp, tf, ethereum
|
||||||
}
|
}
|
||||||
|
|
||||||
// this line below is needed for transaction to be applied to the state in testing
|
|
||||||
// the heavy lifing is done in XEth.ApplyTestTxs
|
|
||||||
// this is fragile, overwriting xeth will result in
|
|
||||||
// process leaking since xeth loops cannot quit safely
|
|
||||||
// should be replaced by proper mining with testDAG for easy full integration tests
|
|
||||||
// txc, self.xeth = self.xeth.ApplyTestTxs(self.xeth.repl.stateDb, coinbase, txc)
|
|
||||||
|
|
||||||
func TestNodeInfo(t *testing.T) {
|
func TestNodeInfo(t *testing.T) {
|
||||||
|
t.Skip("broken after p2p update")
|
||||||
tmp, repl, ethereum := testJEthRE(t)
|
tmp, repl, ethereum := testJEthRE(t)
|
||||||
if err := ethereum.Start(); err != nil {
|
if err := ethereum.Start(); err != nil {
|
||||||
t.Fatalf("error starting ethereum: %v", err)
|
t.Fatalf("error starting ethereum: %v", err)
|
||||||
@ -254,8 +254,12 @@ func TestSignature(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestContract(t *testing.T) {
|
func TestContract(t *testing.T) {
|
||||||
t.Skip()
|
t.Skip("contract testing is implemented with mining in ethash test mode. This takes about 7seconds to run. Unskip and run on demand")
|
||||||
tmp, repl, ethereum := testJEthRE(t)
|
coinbase := common.HexToAddress(testAddress)
|
||||||
|
tmp, repl, ethereum := testREPL(t, func(conf *eth.Config) {
|
||||||
|
conf.Etherbase = testAddress
|
||||||
|
conf.PowTest = true
|
||||||
|
})
|
||||||
if err := ethereum.Start(); err != nil {
|
if err := ethereum.Start(); err != nil {
|
||||||
t.Errorf("error starting ethereum: %v", err)
|
t.Errorf("error starting ethereum: %v", err)
|
||||||
return
|
return
|
||||||
@ -263,12 +267,26 @@ func TestContract(t *testing.T) {
|
|||||||
defer ethereum.Stop()
|
defer ethereum.Stop()
|
||||||
defer os.RemoveAll(tmp)
|
defer os.RemoveAll(tmp)
|
||||||
|
|
||||||
var txc uint64
|
reg := registrar.New(repl.xeth)
|
||||||
coinbase := common.HexToAddress(testAddress)
|
_, err := reg.SetGlobalRegistrar("", coinbase)
|
||||||
resolver.New(repl.xeth).CreateContracts(coinbase)
|
if err != nil {
|
||||||
// time.Sleep(1000 * time.Millisecond)
|
t.Errorf("error setting HashReg: %v", err)
|
||||||
|
}
|
||||||
|
_, err = reg.SetHashReg("", coinbase)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error setting HashReg: %v", err)
|
||||||
|
}
|
||||||
|
_, err = reg.SetUrlHint("", coinbase)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error setting HashReg: %v", err)
|
||||||
|
}
|
||||||
|
/* TODO:
|
||||||
|
* lookup receipt and contract addresses by tx hash
|
||||||
|
* name registration for HashReg and UrlHint addresses
|
||||||
|
* mine those transactions
|
||||||
|
* then set once more SetHashReg SetUrlHint
|
||||||
|
*/
|
||||||
|
|
||||||
// checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `2`)
|
|
||||||
source := `contract test {\n` +
|
source := `contract test {\n` +
|
||||||
" /// @notice Will multiply `a` by 7." + `\n` +
|
" /// @notice Will multiply `a` by 7." + `\n` +
|
||||||
` function multiply(uint a) returns(uint d) {\n` +
|
` function multiply(uint a) returns(uint d) {\n` +
|
||||||
@ -276,14 +294,20 @@ func TestContract(t *testing.T) {
|
|||||||
` }\n` +
|
` }\n` +
|
||||||
`}\n`
|
`}\n`
|
||||||
|
|
||||||
checkEvalJSON(t, repl, `admin.contractInfo.stop()`, `true`)
|
if checkEvalJSON(t, repl, `admin.stopNatSpec()`, `true`) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
contractInfo, err := ioutil.ReadFile("info_test.json")
|
contractInfo, err := ioutil.ReadFile("info_test.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%v", err)
|
t.Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
checkEvalJSON(t, repl, `primary = eth.accounts[0]`, `"`+testAddress+`"`)
|
if checkEvalJSON(t, repl, `primary = eth.accounts[0]`, `"`+testAddress+`"`) != nil {
|
||||||
checkEvalJSON(t, repl, `source = "`+source+`"`, `"`+source+`"`)
|
return
|
||||||
|
}
|
||||||
|
if checkEvalJSON(t, repl, `source = "`+source+`"`, `"`+source+`"`) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// if solc is found with right version, test it, otherwise read from file
|
// if solc is found with right version, test it, otherwise read from file
|
||||||
sol, err := compiler.New("")
|
sol, err := compiler.New("")
|
||||||
@ -303,69 +327,160 @@ func TestContract(t *testing.T) {
|
|||||||
t.Errorf("%v", err)
|
t.Errorf("%v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
checkEvalJSON(t, repl, `contract = eth.compile.solidity(source).test`, string(contractInfo))
|
if checkEvalJSON(t, repl, `contract = eth.compile.solidity(source).test`, string(contractInfo)) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkEvalJSON(t, repl, `contract.code`, `"0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"`)
|
if checkEvalJSON(t, repl, `contract.code`, `"0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"`) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
checkEvalJSON(
|
if checkEvalJSON(
|
||||||
t, repl,
|
t, repl,
|
||||||
`contractaddress = eth.sendTransaction({from: primary, data: contract.code })`,
|
`contractaddress = eth.sendTransaction({from: primary, data: contract.code})`,
|
||||||
`"0x5dcaace5982778b409c524873b319667eba5d074"`,
|
`"0x46d69d55c3c4b86a924a92c9fc4720bb7bce1d74"`,
|
||||||
)
|
) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !processTxs(repl, t, 8) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
callSetup := `abiDef = JSON.parse('[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]');
|
callSetup := `abiDef = JSON.parse('[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]');
|
||||||
Multiply7 = eth.contract(abiDef);
|
Multiply7 = eth.contract(abiDef);
|
||||||
multiply7 = Multiply7.at(contractaddress);
|
multiply7 = Multiply7.at(contractaddress);
|
||||||
`
|
`
|
||||||
// time.Sleep(1500 * time.Millisecond)
|
|
||||||
_, err = repl.re.Run(callSetup)
|
_, err = repl.re.Run(callSetup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error setting up contract, got %v", err)
|
t.Errorf("unexpected error setting up contract, got %v", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `3`)
|
|
||||||
|
|
||||||
// why is this sometimes failing?
|
|
||||||
// checkEvalJSON(t, repl, `multiply7.multiply.call(6)`, `42`)
|
|
||||||
expNotice := ""
|
expNotice := ""
|
||||||
if repl.lastConfirm != expNotice {
|
if repl.lastConfirm != expNotice {
|
||||||
t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
|
t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
txc, repl.xeth = repl.xeth.ApplyTestTxs(repl.stateDb, coinbase, txc)
|
if checkEvalJSON(t, repl, `admin.startNatSpec()`, `true`) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary })`, `"0x4ef9088431a8033e4580d00e4eb2487275e031ff4163c7529df0ef45af17857b"`) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
checkEvalJSON(t, repl, `admin.contractInfo.start()`, `true`)
|
if !processTxs(repl, t, 1) {
|
||||||
checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary, gas: "1000000", gasPrice: "100000" })`, `undefined`)
|
return
|
||||||
expNotice = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x87e2802265838c7f14bb69eecd2112911af6767907a702eeaa445239fb20711b'): {"params":[{"to":"0x5dcaace5982778b409c524873b319667eba5d074","data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}]}`
|
}
|
||||||
|
|
||||||
|
expNotice = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x87e2802265838c7f14bb69eecd2112911af6767907a702eeaa445239fb20711b'): {"params":[{"to":"0x46d69d55c3c4b86a924a92c9fc4720bb7bce1d74","data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}]}`
|
||||||
if repl.lastConfirm != expNotice {
|
if repl.lastConfirm != expNotice {
|
||||||
t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
|
t.Errorf("incorrect confirmation message: expected\n%v, got\n%v", expNotice, repl.lastConfirm)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var contenthash = `"0x86d2b7cf1e72e9a7a3f8d96601f0151742a2f780f1526414304fbe413dc7f9bd"`
|
var contentHash = `"0x86d2b7cf1e72e9a7a3f8d96601f0151742a2f780f1526414304fbe413dc7f9bd"`
|
||||||
if sol != nil {
|
if sol != nil && solcVersion != sol.Version() {
|
||||||
modContractInfo := versionRE.ReplaceAll(contractInfo, []byte(`"compilerVersion":"`+sol.Version()+`"`))
|
modContractInfo := versionRE.ReplaceAll(contractInfo, []byte(`"compilerVersion":"`+sol.Version()+`"`))
|
||||||
_ = modContractInfo
|
fmt.Printf("modified contractinfo:\n%s\n", modContractInfo)
|
||||||
// contenthash = crypto.Sha3(modContractInfo)
|
contentHash = `"` + common.ToHex(crypto.Sha3([]byte(modContractInfo))) + `"`
|
||||||
}
|
}
|
||||||
checkEvalJSON(t, repl, `filename = "/tmp/info.json"`, `"/tmp/info.json"`)
|
if checkEvalJSON(t, repl, `filename = "/tmp/info.json"`, `"/tmp/info.json"`) != nil {
|
||||||
checkEvalJSON(t, repl, `contenthash = admin.contractInfo.register(primary, contractaddress, contract, filename)`, contenthash)
|
return
|
||||||
checkEvalJSON(t, repl, `admin.contractInfo.registerUrl(primary, contenthash, "file://"+filename)`, `true`)
|
}
|
||||||
if err != nil {
|
if checkEvalJSON(t, repl, `contentHash = admin.saveInfo(contract.info, filename)`, contentHash) != nil {
|
||||||
t.Errorf("unexpected error registering, got %v", err)
|
return
|
||||||
|
}
|
||||||
|
if checkEvalJSON(t, repl, `admin.register(primary, contractaddress, contentHash)`, `true`) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if checkEvalJSON(t, repl, `admin.registerUrl(primary, contentHash, "file://"+filename)`, `true`) != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
checkEvalJSON(t, repl, `admin.contractInfo.start()`, `true`)
|
if checkEvalJSON(t, repl, `admin.startNatSpec()`, `true`) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// update state
|
if !processTxs(repl, t, 3) {
|
||||||
txc, repl.xeth = repl.xeth.ApplyTestTxs(repl.stateDb, coinbase, txc)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary })`, `"0x66d7635c12ad0b231e66da2f987ca3dfdca58ffe49c6442aa55960858103fd0c"`) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !processTxs(repl, t, 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary, gas: "1000000", gasPrice: "100000" })`, `undefined`)
|
|
||||||
expNotice = "Will multiply 6 by 7."
|
expNotice = "Will multiply 6 by 7."
|
||||||
if repl.lastConfirm != expNotice {
|
if repl.lastConfirm != expNotice {
|
||||||
t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
|
t.Errorf("incorrect confirmation message: expected\n%v, got\n%v", expNotice, repl.lastConfirm)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pendingTransactions(repl *testjethre, t *testing.T) (txc int64, err error) {
|
||||||
|
txs := repl.ethereum.TxPool().GetTransactions()
|
||||||
|
return int64(len(txs)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processTxs(repl *testjethre, t *testing.T, expTxc int) bool {
|
||||||
|
var txc int64
|
||||||
|
var err error
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
txc, err = pendingTransactions(repl, t)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error checking pending transactions: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if expTxc < int(txc) {
|
||||||
|
t.Errorf("too many pending transactions: expected %v, got %v", expTxc, txc)
|
||||||
|
return false
|
||||||
|
} else if expTxc == int(txc) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
if int(txc) != expTxc {
|
||||||
|
t.Errorf("incorrect number of pending transactions, expected %v, got %v", expTxc, txc)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = repl.ethereum.StartMining(runtime.NumCPU())
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error mining: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer repl.ethereum.StopMining()
|
||||||
|
|
||||||
|
timer := time.NewTimer(100 * time.Second)
|
||||||
|
height := new(big.Int).Add(repl.xeth.CurrentBlock().Number(), big.NewInt(1))
|
||||||
|
repl.wait <- height
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
// if times out make sure the xeth loop does not block
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case repl.wait <- nil:
|
||||||
|
case <-repl.wait:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
case <-repl.wait:
|
||||||
|
}
|
||||||
|
txc, err = pendingTransactions(repl, t)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error checking pending transactions: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if txc != 0 {
|
||||||
|
t.Errorf("%d trasactions were not mined", txc)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkEvalJSON(t *testing.T, re *testjethre, expr, want string) error {
|
func checkEvalJSON(t *testing.T, re *testjethre, expr, want string) error {
|
||||||
|
@ -185,12 +185,12 @@ func (sol *Solidity) Compile(source string) (contracts map[string]*Contract, err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExtractInfo(contract *Contract, filename string) (contenthash common.Hash, err error) {
|
func SaveInfo(info *ContractInfo, filename string) (contenthash common.Hash, err error) {
|
||||||
contractInfo, err := json.Marshal(contract.Info)
|
infojson, err := json.Marshal(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
contenthash = common.BytesToHash(crypto.Sha3(contractInfo))
|
contenthash = common.BytesToHash(crypto.Sha3(infojson))
|
||||||
err = ioutil.WriteFile(filename, contractInfo, 0600)
|
err = ioutil.WriteFile(filename, infojson, 0600)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -72,19 +72,15 @@ func TestNoCompiler(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractInfo(t *testing.T) {
|
func TestSaveInfo(t *testing.T) {
|
||||||
var cinfo ContractInfo
|
var cinfo ContractInfo
|
||||||
err := json.Unmarshal([]byte(info), &cinfo)
|
err := json.Unmarshal([]byte(info), &cinfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%v", err)
|
t.Errorf("%v", err)
|
||||||
}
|
}
|
||||||
contract := &Contract{
|
|
||||||
Code: "",
|
|
||||||
Info: cinfo,
|
|
||||||
}
|
|
||||||
filename := "/tmp/solctest.info.json"
|
filename := "/tmp/solctest.info.json"
|
||||||
os.Remove(filename)
|
os.Remove(filename)
|
||||||
cinfohash, err := ExtractInfo(contract, filename)
|
cinfohash, err := SaveInfo(&cinfo, filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error extracting info: %v", err)
|
t.Errorf("error extracting info: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -4,34 +4,26 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// http://golang.org/pkg/net/http/#RoundTripper
|
|
||||||
var (
|
|
||||||
schemes = map[string]func(*DocServer) http.RoundTripper{
|
|
||||||
// Simple File server from local disk file:///etc/passwd :)
|
|
||||||
"file": fileServerOnDocRoot,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func fileServerOnDocRoot(ds *DocServer) http.RoundTripper {
|
|
||||||
return http.NewFileTransport(http.Dir(ds.DocRoot))
|
|
||||||
}
|
|
||||||
|
|
||||||
type DocServer struct {
|
type DocServer struct {
|
||||||
*http.Transport
|
*http.Transport
|
||||||
DocRoot string
|
DocRoot string
|
||||||
|
schemes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(docRoot string) (self *DocServer, err error) {
|
func New(docRoot string) (self *DocServer) {
|
||||||
self = &DocServer{
|
self = &DocServer{
|
||||||
Transport: &http.Transport{},
|
Transport: &http.Transport{},
|
||||||
DocRoot: docRoot,
|
DocRoot: docRoot,
|
||||||
|
schemes: []string{"file"},
|
||||||
}
|
}
|
||||||
err = self.RegisterProtocols(schemes)
|
self.DocRoot = "/tmp/"
|
||||||
|
self.RegisterProtocol("file", http.NewFileTransport(http.Dir(self.DocRoot)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,16 +37,44 @@ func (self *DocServer) Client() *http.Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DocServer) RegisterProtocols(schemes map[string]func(*DocServer) http.RoundTripper) (err error) {
|
func (self *DocServer) RegisterScheme(scheme string, rt http.RoundTripper) {
|
||||||
for scheme, rtf := range schemes {
|
self.schemes = append(self.schemes, scheme)
|
||||||
self.RegisterProtocol(scheme, rtf(self))
|
self.RegisterProtocol(scheme, rt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *DocServer) HasScheme(scheme string) bool {
|
||||||
|
for _, s := range self.schemes {
|
||||||
|
if s == scheme {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DocServer) GetAuthContent(uri string, hash common.Hash) (content []byte, err error) {
|
func (self *DocServer) GetAuthContent(uri string, hash common.Hash) (content []byte, err error) {
|
||||||
|
// retrieve content
|
||||||
|
content, err = self.Get(uri, "")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check hash to authenticate content
|
||||||
|
chash := crypto.Sha3Hash(content)
|
||||||
|
if chash != hash {
|
||||||
|
content = nil
|
||||||
|
err = fmt.Errorf("content hash mismatch %x != %x (exp)", hash[:], chash[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get(uri, path) downloads the document at uri, if path is non-empty it
|
||||||
|
// is interpreted as a filepath to which the contents are saved
|
||||||
|
func (self *DocServer) Get(uri, path string) (content []byte, err error) {
|
||||||
// retrieve content
|
// retrieve content
|
||||||
resp, err := self.Client().Get(uri)
|
resp, err := self.Client().Get(uri)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
@ -68,13 +88,10 @@ func (self *DocServer) GetAuthContent(uri string, hash common.Hash) (content []b
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check hash to authenticate content
|
if path != "" {
|
||||||
hashbytes := crypto.Sha3(content)
|
var abspath string
|
||||||
var chash common.Hash
|
abspath, err = filepath.Abs(path)
|
||||||
copy(chash[:], hashbytes)
|
ioutil.WriteFile(abspath, content, 0700)
|
||||||
if chash != hash {
|
|
||||||
content = nil
|
|
||||||
err = fmt.Errorf("content hash mismatch")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -2,6 +2,7 @@ package docserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ func TestGetAuthContent(t *testing.T) {
|
|||||||
copy(hash[:], crypto.Sha3([]byte(text)))
|
copy(hash[:], crypto.Sha3([]byte(text)))
|
||||||
ioutil.WriteFile("/tmp/test.content", []byte(text), os.ModePerm)
|
ioutil.WriteFile("/tmp/test.content", []byte(text), os.ModePerm)
|
||||||
|
|
||||||
ds, err := New("/tmp/")
|
ds := New("/tmp/")
|
||||||
content, err := ds.GetAuthContent("file:///test.content", hash)
|
content, err := ds.GetAuthContent("file:///test.content", hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("no error expected, got %v", err)
|
t.Errorf("no error expected, got %v", err)
|
||||||
@ -26,7 +27,7 @@ func TestGetAuthContent(t *testing.T) {
|
|||||||
|
|
||||||
hash = common.Hash{}
|
hash = common.Hash{}
|
||||||
content, err = ds.GetAuthContent("file:///test.content", hash)
|
content, err = ds.GetAuthContent("file:///test.content", hash)
|
||||||
expected := "content hash mismatch"
|
expected := "content hash mismatch 0000000000000000000000000000000000000000000000000000000000000000 != 9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658 (exp)"
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("expected error, got nothing")
|
t.Errorf("expected error, got nothing")
|
||||||
} else {
|
} else {
|
||||||
@ -36,3 +37,18 @@ func TestGetAuthContent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type rt struct{}
|
||||||
|
|
||||||
|
func (rt) RoundTrip(req *http.Request) (resp *http.Response, err error) { return }
|
||||||
|
|
||||||
|
func TestRegisterScheme(t *testing.T) {
|
||||||
|
ds := New("/tmp/")
|
||||||
|
if ds.HasScheme("scheme") {
|
||||||
|
t.Errorf("expected scheme not to be registered")
|
||||||
|
}
|
||||||
|
ds.RegisterScheme("scheme", rt{})
|
||||||
|
if !ds.HasScheme("scheme") {
|
||||||
|
t.Errorf("expected scheme to be registered")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/docserver"
|
"github.com/ethereum/go-ethereum/common/docserver"
|
||||||
"github.com/ethereum/go-ethereum/common/resolver"
|
"github.com/ethereum/go-ethereum/common/registrar"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
)
|
)
|
||||||
@ -88,7 +88,7 @@ func New(xeth *xeth.XEth, jsontx string, http *docserver.DocServer) (self *NatSp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// also called by admin.contractInfo.get
|
// also called by admin.contractInfo.get
|
||||||
func FetchDocsForContract(contractAddress string, xeth *xeth.XEth, http *docserver.DocServer) (content []byte, err error) {
|
func FetchDocsForContract(contractAddress string, xeth *xeth.XEth, ds *docserver.DocServer) (content []byte, err error) {
|
||||||
// retrieve contract hash from state
|
// retrieve contract hash from state
|
||||||
codehex := xeth.CodeAt(contractAddress)
|
codehex := xeth.CodeAt(contractAddress)
|
||||||
codeb := xeth.CodeAtBytes(contractAddress)
|
codeb := xeth.CodeAtBytes(contractAddress)
|
||||||
@ -99,20 +99,32 @@ func FetchDocsForContract(contractAddress string, xeth *xeth.XEth, http *docserv
|
|||||||
}
|
}
|
||||||
codehash := common.BytesToHash(crypto.Sha3(codeb))
|
codehash := common.BytesToHash(crypto.Sha3(codeb))
|
||||||
// set up nameresolver with natspecreg + urlhint contract addresses
|
// set up nameresolver with natspecreg + urlhint contract addresses
|
||||||
res := resolver.New(xeth)
|
reg := registrar.New(xeth)
|
||||||
|
|
||||||
// resolve host via HashReg/UrlHint Resolver
|
// resolve host via HashReg/UrlHint Resolver
|
||||||
uri, hash, err := res.KeyToUrl(codehash)
|
hash, err := reg.HashToHash(codehash)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ds.HasScheme("bzz") {
|
||||||
|
content, err = ds.Get("bzz://"+hash.Hex()[2:], "")
|
||||||
|
if err == nil { // non-fatal
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = nil
|
||||||
|
//falling back to urlhint
|
||||||
|
}
|
||||||
|
|
||||||
|
uri, err := reg.HashToUrl(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// get content via http client and authenticate content using hash
|
// get content via http client and authenticate content using hash
|
||||||
content, err = http.GetAuthContent(uri, hash)
|
content, err = ds.GetAuthContent(uri, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,16 +3,18 @@ package natspec
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/docserver"
|
"github.com/ethereum/go-ethereum/common/docserver"
|
||||||
"github.com/ethereum/go-ethereum/common/resolver"
|
"github.com/ethereum/go-ethereum/common/registrar"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
xe "github.com/ethereum/go-ethereum/xeth"
|
xe "github.com/ethereum/go-ethereum/xeth"
|
||||||
@ -73,13 +75,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type testFrontend struct {
|
type testFrontend struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
// resolver *resolver.Resolver
|
|
||||||
ethereum *eth.Ethereum
|
ethereum *eth.Ethereum
|
||||||
xeth *xe.XEth
|
xeth *xe.XEth
|
||||||
coinbase common.Address
|
wait chan *big.Int
|
||||||
stateDb *state.StateDB
|
|
||||||
txc uint64
|
|
||||||
lastConfirm string
|
lastConfirm string
|
||||||
wantNatSpec bool
|
wantNatSpec bool
|
||||||
}
|
}
|
||||||
@ -91,10 +90,7 @@ func (self *testFrontend) UnlockAccount(acc []byte) bool {
|
|||||||
|
|
||||||
func (self *testFrontend) ConfirmTransaction(tx string) bool {
|
func (self *testFrontend) ConfirmTransaction(tx string) bool {
|
||||||
if self.wantNatSpec {
|
if self.wantNatSpec {
|
||||||
ds, err := docserver.New("/tmp/")
|
ds := docserver.New("/tmp/")
|
||||||
if err != nil {
|
|
||||||
self.t.Errorf("Error creating DocServer: %v", err)
|
|
||||||
}
|
|
||||||
self.lastConfirm = GetNotice(self.xeth, tx, ds)
|
self.lastConfirm = GetNotice(self.xeth, tx, ds)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -128,6 +124,8 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
|
|||||||
DataDir: "/tmp/eth-natspec",
|
DataDir: "/tmp/eth-natspec",
|
||||||
AccountManager: am,
|
AccountManager: am,
|
||||||
MaxPeers: 0,
|
MaxPeers: 0,
|
||||||
|
PowTest: true,
|
||||||
|
Etherbase: testAddress,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -153,86 +151,106 @@ func testInit(t *testing.T) (self *testFrontend) {
|
|||||||
// mock frontend
|
// mock frontend
|
||||||
self = &testFrontend{t: t, ethereum: ethereum}
|
self = &testFrontend{t: t, ethereum: ethereum}
|
||||||
self.xeth = xe.New(ethereum, self)
|
self.xeth = xe.New(ethereum, self)
|
||||||
|
self.wait = self.xeth.UpdateState()
|
||||||
addr, _ := ethereum.Etherbase()
|
addr, _ := self.ethereum.Etherbase()
|
||||||
self.coinbase = addr
|
|
||||||
self.stateDb = self.ethereum.ChainManager().State().Copy()
|
|
||||||
|
|
||||||
// initialise the registry contracts
|
// initialise the registry contracts
|
||||||
// self.resolver.CreateContracts(addr)
|
reg := registrar.New(self.xeth)
|
||||||
resolver.New(self.xeth).CreateContracts(addr)
|
var registrarTxhash, hashRegTxhash, urlHintTxhash string
|
||||||
self.applyTxs()
|
registrarTxhash, err = reg.SetGlobalRegistrar("", addr)
|
||||||
// t.Logf("HashReg contract registered at %v", resolver.HashRegContractAddress)
|
if err != nil {
|
||||||
// t.Logf("URLHint contract registered at %v", resolver.UrlHintContractAddress)
|
t.Errorf("error creating GlobalRegistrar: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hashRegTxhash, err = reg.SetHashReg("", addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error creating HashReg: %v", err)
|
||||||
|
}
|
||||||
|
urlHintTxhash, err = reg.SetUrlHint("", addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error creating UrlHint: %v", err)
|
||||||
|
}
|
||||||
|
if !processTxs(self, t, 3) {
|
||||||
|
t.Errorf("error mining txs")
|
||||||
|
}
|
||||||
|
_ = registrarTxhash
|
||||||
|
_ = hashRegTxhash
|
||||||
|
_ = urlHintTxhash
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
* lookup receipt and contract addresses by tx hash
|
||||||
|
* name registration for HashReg and UrlHint addresses
|
||||||
|
* mine those transactions
|
||||||
|
* then set once more SetHashReg SetUrlHint
|
||||||
|
*/
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is needed for transaction to be applied to the state in testing
|
|
||||||
// the heavy lifing is done in XEth.ApplyTestTxs
|
|
||||||
// this is fragile,
|
|
||||||
// and does process leaking since xeth loops cannot quit safely
|
|
||||||
// should be replaced by proper mining with testDAG for easy full integration tests
|
|
||||||
func (self *testFrontend) applyTxs() {
|
|
||||||
self.txc, self.xeth = self.xeth.ApplyTestTxs(self.stateDb, self.coinbase, self.txc)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// end to end test
|
// end to end test
|
||||||
func TestNatspecE2E(t *testing.T) {
|
func TestNatspecE2E(t *testing.T) {
|
||||||
t.Skip()
|
t.Skip()
|
||||||
|
|
||||||
tf := testInit(t)
|
tf := testInit(t)
|
||||||
defer tf.ethereum.Stop()
|
defer tf.ethereum.Stop()
|
||||||
|
addr, _ := tf.ethereum.Etherbase()
|
||||||
|
|
||||||
// create a contractInfo file (mock cloud-deployed contract metadocs)
|
// create a contractInfo file (mock cloud-deployed contract metadocs)
|
||||||
// incidentally this is the info for the registry contract itself
|
// incidentally this is the info for the registry contract itself
|
||||||
ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm)
|
ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm)
|
||||||
dochash := common.BytesToHash(crypto.Sha3([]byte(testContractInfo)))
|
dochash := crypto.Sha3Hash([]byte(testContractInfo))
|
||||||
|
|
||||||
// take the codehash for the contract we wanna test
|
// take the codehash for the contract we wanna test
|
||||||
// codehex := tf.xeth.CodeAt(resolver.HashRegContractAddress)
|
codeb := tf.xeth.CodeAtBytes(registrar.HashRegAddr)
|
||||||
codeb := tf.xeth.CodeAtBytes(resolver.HashRegContractAddress)
|
codehash := crypto.Sha3Hash(codeb)
|
||||||
codehash := common.BytesToHash(crypto.Sha3(codeb))
|
|
||||||
|
|
||||||
// use resolver to register codehash->dochash->url
|
// use resolver to register codehash->dochash->url
|
||||||
registry := resolver.New(tf.xeth)
|
// test if globalregistry works
|
||||||
_, err := registry.Register(tf.coinbase, codehash, dochash, "file:///"+testFileName)
|
// registrar.HashRefAddr = "0x0"
|
||||||
|
// registrar.UrlHintAddr = "0x0"
|
||||||
|
reg := registrar.New(tf.xeth)
|
||||||
|
_, err := reg.SetHashToHash(addr, codehash, dochash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error registering: %v", err)
|
t.Errorf("error registering: %v", err)
|
||||||
}
|
}
|
||||||
// apply txs to the state
|
_, err = reg.SetUrlToHash(addr, dochash, "file:///"+testFileName)
|
||||||
tf.applyTxs()
|
if err != nil {
|
||||||
|
t.Errorf("error registering: %v", err)
|
||||||
|
}
|
||||||
|
if !processTxs(tf, t, 5) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// NatSpec info for register method of HashReg contract installed
|
// NatSpec info for register method of HashReg contract installed
|
||||||
// now using the same transactions to check confirm messages
|
// now using the same transactions to check confirm messages
|
||||||
|
|
||||||
tf.wantNatSpec = true // this is set so now the backend uses natspec confirmation
|
tf.wantNatSpec = true // this is set so now the backend uses natspec confirmation
|
||||||
_, err = registry.RegisterContentHash(tf.coinbase, codehash, dochash)
|
_, err = reg.SetHashToHash(addr, codehash, dochash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error calling contract registry: %v", err)
|
t.Errorf("error calling contract registry: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("GlobalRegistrar: %v, HashReg: %v, UrlHint: %v\n", registrar.GlobalRegistrarAddr, registrar.HashRegAddr, registrar.UrlHintAddr)
|
||||||
if tf.lastConfirm != testExpNotice {
|
if tf.lastConfirm != testExpNotice {
|
||||||
t.Errorf("Wrong confirm message. expected '%v', got '%v'", testExpNotice, tf.lastConfirm)
|
t.Errorf("Wrong confirm message. expected\n'%v', got\n'%v'", testExpNotice, tf.lastConfirm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test unknown method
|
// test unknown method
|
||||||
exp := fmt.Sprintf(testExpNotice2, resolver.HashRegContractAddress)
|
exp := fmt.Sprintf(testExpNotice2, registrar.HashRegAddr)
|
||||||
_, err = registry.SetOwner(tf.coinbase)
|
_, err = reg.SetOwner(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error setting owner: %v", err)
|
t.Errorf("error setting owner: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tf.lastConfirm != exp {
|
if tf.lastConfirm != exp {
|
||||||
t.Errorf("Wrong confirm message, expected '%v', got '%v'", exp, tf.lastConfirm)
|
t.Errorf("Wrong confirm message, expected\n'%v', got\n'%v'", exp, tf.lastConfirm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test unknown contract
|
// test unknown contract
|
||||||
exp = fmt.Sprintf(testExpNotice3, resolver.UrlHintContractAddress)
|
exp = fmt.Sprintf(testExpNotice3, registrar.UrlHintAddr)
|
||||||
|
|
||||||
_, err = registry.RegisterUrl(tf.coinbase, dochash, "file:///test.content")
|
_, err = reg.SetUrlToHash(addr, dochash, "file:///test.content")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error registering: %v", err)
|
t.Errorf("error registering: %v", err)
|
||||||
}
|
}
|
||||||
@ -242,3 +260,63 @@ func TestNatspecE2E(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pendingTransactions(repl *testFrontend, t *testing.T) (txc int64, err error) {
|
||||||
|
txs := repl.ethereum.TxPool().GetTransactions()
|
||||||
|
return int64(len(txs)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processTxs(repl *testFrontend, t *testing.T, expTxc int) bool {
|
||||||
|
var txc int64
|
||||||
|
var err error
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
txc, err = pendingTransactions(repl, t)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error checking pending transactions: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if expTxc < int(txc) {
|
||||||
|
t.Errorf("too many pending transactions: expected %v, got %v", expTxc, txc)
|
||||||
|
return false
|
||||||
|
} else if expTxc == int(txc) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
if int(txc) != expTxc {
|
||||||
|
t.Errorf("incorrect number of pending transactions, expected %v, got %v", expTxc, txc)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repl.ethereum.StartMining(runtime.NumCPU())
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error mining: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer repl.ethereum.StopMining()
|
||||||
|
|
||||||
|
timer := time.NewTimer(100 * time.Second)
|
||||||
|
height := new(big.Int).Add(repl.xeth.CurrentBlock().Number(), big.NewInt(1))
|
||||||
|
repl.wait <- height
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
// if times out make sure the xeth loop does not block
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case repl.wait <- nil:
|
||||||
|
case <-repl.wait:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
case <-repl.wait:
|
||||||
|
}
|
||||||
|
txc, err = pendingTransactions(repl, t)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error checking pending transactions: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if txc != 0 {
|
||||||
|
t.Errorf("%d trasactions were not mined", txc)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
253
common/natspec/natspec_e2e_test.go.orig
Normal file
253
common/natspec/natspec_e2e_test.go.orig
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
package natspec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/docserver"
|
||||||
|
"github.com/ethereum/go-ethereum/common/registrar"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
|
xe "github.com/ethereum/go-ethereum/xeth"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testBalance = "10000000000000000000"
|
||||||
|
|
||||||
|
testFileName = "long_file_name_for_testing_registration_of_URLs_longer_than_32_bytes.content"
|
||||||
|
|
||||||
|
testNotice = "Register key `utils.toHex(_key)` <- content `utils.toHex(_content)`"
|
||||||
|
|
||||||
|
testExpNotice = "Register key 0xadd1a7d961cff0242089674ec2ef6fca671ab15e1fe80e38859fc815b98d88ab <- content 0xb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7"
|
||||||
|
|
||||||
|
testExpNotice2 = `About to submit transaction (NatSpec notice error: abi key does not match any method): {"params":[{"to":"%s","data": "0x31e12c20"}]}`
|
||||||
|
|
||||||
|
testExpNotice3 = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x1392c62d05b2d149e22a339c531157ae06b44d39a674cce500064b12b9aeb019'): {"params":[{"to":"%s","data": "0x300a3bbfb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066696c653a2f2f2f746573742e636f6e74656e74"}]}`
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testUserDoc = `
|
||||||
|
{
|
||||||
|
"methods": {
|
||||||
|
"register(uint256,uint256)": {
|
||||||
|
"notice": "` + testNotice + `"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"invariants": [
|
||||||
|
{ "notice": "" }
|
||||||
|
],
|
||||||
|
"construction": [
|
||||||
|
{ "notice": "" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
testAbiDefinition = `
|
||||||
|
[{
|
||||||
|
"name": "register",
|
||||||
|
"constant": false,
|
||||||
|
"type": "function",
|
||||||
|
"inputs": [{
|
||||||
|
"name": "_key",
|
||||||
|
"type": "uint256"
|
||||||
|
}, {
|
||||||
|
"name": "_content",
|
||||||
|
"type": "uint256"
|
||||||
|
}],
|
||||||
|
"outputs": []
|
||||||
|
}]
|
||||||
|
`
|
||||||
|
|
||||||
|
testContractInfo = `
|
||||||
|
{
|
||||||
|
"userDoc": ` + testUserDoc + `,
|
||||||
|
"abiDefinition": ` + testAbiDefinition + `
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
type testFrontend struct {
|
||||||
|
t *testing.T
|
||||||
|
ethereum *eth.Ethereum
|
||||||
|
xeth *xe.XEth
|
||||||
|
coinbase common.Address
|
||||||
|
stateDb *state.StateDB
|
||||||
|
txc uint64
|
||||||
|
lastConfirm string
|
||||||
|
wantNatSpec bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *testFrontend) UnlockAccount(acc []byte) bool {
|
||||||
|
self.ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "password")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *testFrontend) ConfirmTransaction(tx string) bool {
|
||||||
|
if self.wantNatSpec {
|
||||||
|
ds := docserver.New("/tmp/")
|
||||||
|
self.lastConfirm = GetNotice(self.xeth, tx, ds)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
|
||||||
|
|
||||||
|
os.RemoveAll("/tmp/eth-natspec/")
|
||||||
|
|
||||||
|
err = os.MkdirAll("/tmp/eth-natspec/keystore", os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a testAddress
|
||||||
|
ks := crypto.NewKeyStorePassphrase("/tmp/eth-natspec/keystore")
|
||||||
|
am := accounts.NewManager(ks)
|
||||||
|
testAccount, err := am.NewAccount("password")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
testAddress := strings.TrimPrefix(testAccount.Address.Hex(), "0x")
|
||||||
|
|
||||||
|
// set up mock genesis with balance on the testAddress
|
||||||
|
core.GenesisAccounts = []byte(`{
|
||||||
|
"` + testAddress + `": {"balance": "` + testBalance + `"}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
// only use minimalistic stack with no networking
|
||||||
|
ethereum, err = eth.New(ð.Config{
|
||||||
|
DataDir: "/tmp/eth-natspec",
|
||||||
|
AccountManager: am,
|
||||||
|
MaxPeers: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func testInit(t *testing.T) (self *testFrontend) {
|
||||||
|
// initialise and start minimal ethereum stack
|
||||||
|
ethereum, err := testEth(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error creating ethereum: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ethereum.Start()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error starting ethereum: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// mock frontend
|
||||||
|
self = &testFrontend{t: t, ethereum: ethereum}
|
||||||
|
self.xeth = xe.New(ethereum, self)
|
||||||
|
|
||||||
|
addr, _ := ethereum.Etherbase()
|
||||||
|
self.coinbase = addr
|
||||||
|
self.stateDb = self.ethereum.ChainManager().State().Copy()
|
||||||
|
|
||||||
|
// initialise the registry contracts
|
||||||
|
reg := registrar.New(self.xeth)
|
||||||
|
err = reg.SetHashReg("", addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error creating HashReg: %v", err)
|
||||||
|
}
|
||||||
|
err = reg.SetUrlHint("", addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error creating UrlHint: %v", err)
|
||||||
|
}
|
||||||
|
self.applyTxs()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is needed for transaction to be applied to the state in testing
|
||||||
|
// the heavy lifing is done in XEth.ApplyTestTxs
|
||||||
|
// this is fragile,
|
||||||
|
// and does process leaking since xeth loops cannot quit safely
|
||||||
|
// should be replaced by proper mining with testDAG for easy full integration tests
|
||||||
|
func (self *testFrontend) applyTxs() {
|
||||||
|
self.txc, self.xeth = self.xeth.ApplyTestTxs(self.stateDb, self.coinbase, self.txc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// end to end test
|
||||||
|
func TestNatspecE2E(t *testing.T) {
|
||||||
|
t.Skip()
|
||||||
|
|
||||||
|
tf := testInit(t)
|
||||||
|
defer tf.ethereum.Stop()
|
||||||
|
|
||||||
|
// create a contractInfo file (mock cloud-deployed contract metadocs)
|
||||||
|
// incidentally this is the info for the registry contract itself
|
||||||
|
ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm)
|
||||||
|
dochash := common.BytesToHash(crypto.Sha3([]byte(testContractInfo)))
|
||||||
|
|
||||||
|
// take the codehash for the contract we wanna test
|
||||||
|
// codehex := tf.xeth.CodeAt(registar.HashRegAddr)
|
||||||
|
codeb := tf.xeth.CodeAtBytes(registrar.HashRegAddr)
|
||||||
|
codehash := common.BytesToHash(crypto.Sha3(codeb))
|
||||||
|
|
||||||
|
// use resolver to register codehash->dochash->url
|
||||||
|
// test if globalregistry works
|
||||||
|
// registrar.HashRefAddr = "0x0"
|
||||||
|
// registrar.UrlHintAddr = "0x0"
|
||||||
|
reg := registrar.New(tf.xeth)
|
||||||
|
_, err := reg.SetHashToHash(tf.coinbase, codehash, dochash)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error registering: %v", err)
|
||||||
|
}
|
||||||
|
_, err = reg.SetUrlToHash(tf.coinbase, dochash, "file:///"+testFileName)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error registering: %v", err)
|
||||||
|
}
|
||||||
|
// apply txs to the state
|
||||||
|
tf.applyTxs()
|
||||||
|
|
||||||
|
// NatSpec info for register method of HashReg contract installed
|
||||||
|
// now using the same transactions to check confirm messages
|
||||||
|
|
||||||
|
tf.wantNatSpec = true // this is set so now the backend uses natspec confirmation
|
||||||
|
_, err = reg.SetHashToHash(tf.coinbase, codehash, dochash)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error calling contract registry: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("GlobalRegistrar: %v, HashReg: %v, UrlHint: %v\n", registrar.GlobalRegistrarAddr, registrar.HashRegAddr, registrar.UrlHintAddr)
|
||||||
|
if tf.lastConfirm != testExpNotice {
|
||||||
|
t.Errorf("Wrong confirm message. expected '%v', got '%v'", testExpNotice, tf.lastConfirm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test unknown method
|
||||||
|
exp := fmt.Sprintf(testExpNotice2, registrar.HashRegAddr)
|
||||||
|
_, err = reg.SetOwner(tf.coinbase)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error setting owner: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tf.lastConfirm != exp {
|
||||||
|
t.Errorf("Wrong confirm message, expected '%v', got '%v'", exp, tf.lastConfirm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test unknown contract
|
||||||
|
exp = fmt.Sprintf(testExpNotice3, registrar.UrlHintAddr)
|
||||||
|
|
||||||
|
_, err = reg.SetUrlToHash(tf.coinbase, dochash, "file:///test.content")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error registering: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tf.lastConfirm != exp {
|
||||||
|
t.Errorf("Wrong confirm message, expected '%v', got '%v'", exp, tf.lastConfirm)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
147
common/registrar/contracts.go
Normal file
147
common/registrar/contracts.go
Normal file
File diff suppressed because one or more lines are too long
32
common/registrar/ethreg/ethreg.go
Normal file
32
common/registrar/ethreg/ethreg.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package ethreg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/registrar"
|
||||||
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// implements a versioned Registrar on an archiving full node
|
||||||
|
type EthReg struct {
|
||||||
|
backend *xeth.XEth
|
||||||
|
registry *registrar.Registrar
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(xe *xeth.XEth) (self *EthReg) {
|
||||||
|
self = &EthReg{backend: xe}
|
||||||
|
self.registry = registrar.New(xe)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *EthReg) Registry() *registrar.Registrar {
|
||||||
|
return self.registry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *EthReg) Resolver(n *big.Int) *registrar.Registrar {
|
||||||
|
xe := self.backend
|
||||||
|
if n != nil {
|
||||||
|
xe = self.backend.AtStateNum(n.Int64())
|
||||||
|
}
|
||||||
|
return registrar.New(xe)
|
||||||
|
}
|
392
common/registrar/registrar.go
Normal file
392
common/registrar/registrar.go
Normal file
@ -0,0 +1,392 @@
|
|||||||
|
package registrar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Registrar implements the Ethereum name registrar services mapping
|
||||||
|
- arbitrary strings to ethereum addresses
|
||||||
|
- hashes to hashes
|
||||||
|
- hashes to arbitrary strings
|
||||||
|
(likely will provide lookup service for all three)
|
||||||
|
|
||||||
|
The Registrar is used by
|
||||||
|
* the roundtripper transport implementation of
|
||||||
|
url schemes to resolve domain names and services that register these names
|
||||||
|
* contract info retrieval (NatSpec).
|
||||||
|
|
||||||
|
The Registrar uses 3 contracts on the blockchain:
|
||||||
|
* GlobalRegistrar: Name (string) -> Address (Owner)
|
||||||
|
* HashReg : Key Hash (hash of domain name or contract code) -> Content Hash
|
||||||
|
* UrlHint : Content Hash -> Url Hint
|
||||||
|
|
||||||
|
These contracts are (currently) not included in the genesis block.
|
||||||
|
Each Set<X> needs to be called once on each blockchain/network once.
|
||||||
|
|
||||||
|
Contract addresses need to be set (HashReg and UrlHint retrieved from the global
|
||||||
|
registrar the first time any Registrar method is called in a client session
|
||||||
|
|
||||||
|
So the caller needs to make sure the relevant environment initialised the desired
|
||||||
|
contracts
|
||||||
|
*/
|
||||||
|
var (
|
||||||
|
UrlHintAddr = "0x0"
|
||||||
|
HashRegAddr = "0x0"
|
||||||
|
GlobalRegistrarAddr = "0x0"
|
||||||
|
// GlobalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b"
|
||||||
|
|
||||||
|
zero = regexp.MustCompile("^(0x)?0*$")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
trueHex = "0000000000000000000000000000000000000000000000000000000000000001"
|
||||||
|
falseHex = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
)
|
||||||
|
|
||||||
|
func abiSignature(s string) string {
|
||||||
|
return common.ToHex(crypto.Sha3([]byte(s))[:4])
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
HashRegName = "HashReg"
|
||||||
|
UrlHintName = "UrlHint"
|
||||||
|
|
||||||
|
registerContentHashAbi = abiSignature("register(uint256,uint256)")
|
||||||
|
registerUrlAbi = abiSignature("register(uint256,uint8,uint256)")
|
||||||
|
setOwnerAbi = abiSignature("setowner()")
|
||||||
|
reserveAbi = abiSignature("reserve(bytes32)")
|
||||||
|
resolveAbi = abiSignature("addr(bytes32)")
|
||||||
|
registerAbi = abiSignature("setAddress(bytes32,address,bool)")
|
||||||
|
addressAbiPrefix = falseHex[:24]
|
||||||
|
)
|
||||||
|
|
||||||
|
// Registrar's backend is defined as an interface (implemented by xeth, but could be remote)
|
||||||
|
type Backend interface {
|
||||||
|
StorageAt(string, string) string
|
||||||
|
Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error)
|
||||||
|
Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Registrar should also just implement The Resolver and Registry interfaces
|
||||||
|
// Simplify for now.
|
||||||
|
type VersionedRegistrar interface {
|
||||||
|
Resolver(*big.Int) *Registrar
|
||||||
|
Registry() *Registrar
|
||||||
|
}
|
||||||
|
|
||||||
|
type Registrar struct {
|
||||||
|
backend Backend
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(b Backend) (res *Registrar) {
|
||||||
|
res = &Registrar{b}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Registrar) SetGlobalRegistrar(namereg string, addr common.Address) (txhash string, err error) {
|
||||||
|
if namereg != "" {
|
||||||
|
GlobalRegistrarAddr = namereg
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if GlobalRegistrarAddr == "0x0" || GlobalRegistrarAddr == "0x" {
|
||||||
|
if (addr == common.Address{}) {
|
||||||
|
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation not given")
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "800000", "", GlobalRegistrarCode)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation failed: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Registrar) SetHashReg(hashreg string, addr common.Address) (txhash string, err error) {
|
||||||
|
if hashreg != "" {
|
||||||
|
HashRegAddr = hashreg
|
||||||
|
} else {
|
||||||
|
if !zero.MatchString(HashRegAddr) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nameHex, extra := encodeName(HashRegName, 2)
|
||||||
|
hashRegAbi := resolveAbi + nameHex + extra
|
||||||
|
glog.V(logger.Detail).Infof("\ncall HashRegAddr %v with %v\n", GlobalRegistrarAddr, hashRegAbi)
|
||||||
|
var res string
|
||||||
|
res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", hashRegAbi)
|
||||||
|
if len(res) >= 40 {
|
||||||
|
HashRegAddr = "0x" + res[len(res)-40:len(res)]
|
||||||
|
}
|
||||||
|
if err != nil || zero.MatchString(HashRegAddr) {
|
||||||
|
if (addr == common.Address{}) {
|
||||||
|
err = fmt.Errorf("HashReg address not found and sender for creation not given")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "", "", HashRegCode)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("HashReg address not found and sender for creation failed: %v", err)
|
||||||
|
}
|
||||||
|
glog.V(logger.Detail).Infof("created HashRegAddr @ txhash %v\n", txhash)
|
||||||
|
} else {
|
||||||
|
glog.V(logger.Detail).Infof("HashRegAddr found at @ %v\n", HashRegAddr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Registrar) SetUrlHint(urlhint string, addr common.Address) (txhash string, err error) {
|
||||||
|
if urlhint != "" {
|
||||||
|
UrlHintAddr = urlhint
|
||||||
|
} else {
|
||||||
|
if !zero.MatchString(UrlHintAddr) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nameHex, extra := encodeName(UrlHintName, 2)
|
||||||
|
urlHintAbi := resolveAbi + nameHex + extra
|
||||||
|
glog.V(logger.Detail).Infof("UrlHint address query data: %s to %s", urlHintAbi, GlobalRegistrarAddr)
|
||||||
|
var res string
|
||||||
|
res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", urlHintAbi)
|
||||||
|
if len(res) >= 40 {
|
||||||
|
UrlHintAddr = "0x" + res[len(res)-40:len(res)]
|
||||||
|
}
|
||||||
|
if err != nil || zero.MatchString(UrlHintAddr) {
|
||||||
|
if (addr == common.Address{}) {
|
||||||
|
err = fmt.Errorf("UrlHint address not found and sender for creation not given")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "210000", "", UrlHintCode)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("UrlHint address not found and sender for creation failed: %v", err)
|
||||||
|
}
|
||||||
|
glog.V(logger.Detail).Infof("created UrlHint @ txhash %v\n", txhash)
|
||||||
|
} else {
|
||||||
|
glog.V(logger.Detail).Infof("UrlHint found @ %v\n", HashRegAddr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReserveName(from, name) reserves name for the sender address in the globalRegistrar
|
||||||
|
// the tx needs to be mined to take effect
|
||||||
|
func (self *Registrar) ReserveName(address common.Address, name string) (txh string, err error) {
|
||||||
|
nameHex, extra := encodeName(name, 2)
|
||||||
|
abi := reserveAbi + nameHex + extra
|
||||||
|
glog.V(logger.Detail).Infof("Reserve data: %s", abi)
|
||||||
|
return self.backend.Transact(
|
||||||
|
address.Hex(),
|
||||||
|
GlobalRegistrarAddr,
|
||||||
|
"", "", "", "",
|
||||||
|
abi,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAddressToName(from, name, addr) will set the Address to address for name
|
||||||
|
// in the globalRegistrar using from as the sender of the transaction
|
||||||
|
// the tx needs to be mined to take effect
|
||||||
|
func (self *Registrar) SetAddressToName(from common.Address, name string, address common.Address) (txh string, err error) {
|
||||||
|
nameHex, extra := encodeName(name, 6)
|
||||||
|
addrHex := encodeAddress(address)
|
||||||
|
|
||||||
|
abi := registerAbi + nameHex + addrHex + trueHex + extra
|
||||||
|
glog.V(logger.Detail).Infof("SetAddressToName data: %s to %s ", abi, GlobalRegistrarAddr)
|
||||||
|
|
||||||
|
return self.backend.Transact(
|
||||||
|
from.Hex(),
|
||||||
|
GlobalRegistrarAddr,
|
||||||
|
"", "", "", "",
|
||||||
|
abi,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NameToAddr(from, name) queries the registrar for the address on name
|
||||||
|
func (self *Registrar) NameToAddr(from common.Address, name string) (address common.Address, err error) {
|
||||||
|
nameHex, extra := encodeName(name, 2)
|
||||||
|
abi := resolveAbi + nameHex + extra
|
||||||
|
glog.V(logger.Detail).Infof("NameToAddr data: %s", abi)
|
||||||
|
res, _, err := self.backend.Call(
|
||||||
|
from.Hex(),
|
||||||
|
GlobalRegistrarAddr,
|
||||||
|
"", "", "",
|
||||||
|
abi,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
address = common.HexToAddress(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// called as first step in the registration process on HashReg
|
||||||
|
func (self *Registrar) SetOwner(address common.Address) (txh string, err error) {
|
||||||
|
return self.backend.Transact(
|
||||||
|
address.Hex(),
|
||||||
|
HashRegAddr,
|
||||||
|
"", "", "", "",
|
||||||
|
setOwnerAbi,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registers some content hash to a key/code hash
|
||||||
|
// e.g., the contract Info combined Json Doc's ContentHash
|
||||||
|
// to CodeHash of a contract or hash of a domain
|
||||||
|
func (self *Registrar) SetHashToHash(address common.Address, codehash, dochash common.Hash) (txh string, err error) {
|
||||||
|
_, err = self.SetOwner(address)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
codehex := common.Bytes2Hex(codehash[:])
|
||||||
|
dochex := common.Bytes2Hex(dochash[:])
|
||||||
|
|
||||||
|
data := registerContentHashAbi + codehex + dochex
|
||||||
|
glog.V(logger.Detail).Infof("SetHashToHash data: %s sent to %v\n", data, HashRegAddr)
|
||||||
|
return self.backend.Transact(
|
||||||
|
address.Hex(),
|
||||||
|
HashRegAddr,
|
||||||
|
"", "", "", "",
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUrlToHash(from, hash, url) registers a url to a content hash so that the content can be fetched
|
||||||
|
// address is used as sender for the transaction and will be the owner of a new
|
||||||
|
// registry entry on first time use
|
||||||
|
// FIXME: silently doing nothing if sender is not the owner
|
||||||
|
// note that with content addressed storage, this step is no longer necessary
|
||||||
|
func (self *Registrar) SetUrlToHash(address common.Address, hash common.Hash, url string) (txh string, err error) {
|
||||||
|
hashHex := common.Bytes2Hex(hash[:])
|
||||||
|
var urlHex string
|
||||||
|
urlb := []byte(url)
|
||||||
|
var cnt byte
|
||||||
|
n := len(urlb)
|
||||||
|
|
||||||
|
for n > 0 {
|
||||||
|
if n > 32 {
|
||||||
|
n = 32
|
||||||
|
}
|
||||||
|
urlHex = common.Bytes2Hex(urlb[:n])
|
||||||
|
urlb = urlb[n:]
|
||||||
|
n = len(urlb)
|
||||||
|
bcnt := make([]byte, 32)
|
||||||
|
bcnt[31] = cnt
|
||||||
|
data := registerUrlAbi +
|
||||||
|
hashHex +
|
||||||
|
common.Bytes2Hex(bcnt) +
|
||||||
|
common.Bytes2Hex(common.Hex2BytesFixed(urlHex, 32))
|
||||||
|
txh, err = self.backend.Transact(
|
||||||
|
address.Hex(),
|
||||||
|
UrlHintAddr,
|
||||||
|
"", "", "", "",
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cnt++
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashToHash(key) resolves contenthash for key (a hash) using HashReg
|
||||||
|
// resolution is costless non-transactional
|
||||||
|
// implemented as direct retrieval from db
|
||||||
|
func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err error) {
|
||||||
|
// look up in hashReg
|
||||||
|
at := HashRegAddr[2:]
|
||||||
|
key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:]))
|
||||||
|
hash := self.backend.StorageAt(at, key)
|
||||||
|
|
||||||
|
if hash == "0x0" || len(hash) < 3 || (hash == common.Hash{}.Hex()) {
|
||||||
|
err = fmt.Errorf("content hash not found for '%v'", khash.Hex())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(chash[:], common.Hex2BytesFixed(hash[2:], 32))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashToUrl(contenthash) resolves the url for contenthash using UrlHint
|
||||||
|
// resolution is costless non-transactional
|
||||||
|
// implemented as direct retrieval from db
|
||||||
|
// if we use content addressed storage, this step is no longer necessary
|
||||||
|
func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) {
|
||||||
|
// look up in URL reg
|
||||||
|
var str string = " "
|
||||||
|
var idx uint32
|
||||||
|
for len(str) > 0 {
|
||||||
|
mapaddr := storageMapping(storageIdx2Addr(1), chash[:])
|
||||||
|
key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx)))
|
||||||
|
hex := self.backend.StorageAt(UrlHintAddr[2:], key)
|
||||||
|
str = string(common.Hex2Bytes(hex[2:]))
|
||||||
|
l := 0
|
||||||
|
for (l < len(str)) && (str[l] == 0) {
|
||||||
|
l++
|
||||||
|
}
|
||||||
|
|
||||||
|
str = str[l:]
|
||||||
|
uri = uri + str
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(uri) == 0 {
|
||||||
|
err = fmt.Errorf("GetURLhint: URL hint not found for '%v'", chash.Hex())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func storageIdx2Addr(varidx uint32) []byte {
|
||||||
|
data := make([]byte, 32)
|
||||||
|
binary.BigEndian.PutUint32(data[28:32], varidx)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func storageMapping(addr, key []byte) []byte {
|
||||||
|
data := make([]byte, 64)
|
||||||
|
copy(data[0:32], key[0:32])
|
||||||
|
copy(data[32:64], addr[0:32])
|
||||||
|
sha := crypto.Sha3(data)
|
||||||
|
return sha
|
||||||
|
}
|
||||||
|
|
||||||
|
func storageFixedArray(addr, idx []byte) []byte {
|
||||||
|
var carry byte
|
||||||
|
for i := 31; i >= 0; i-- {
|
||||||
|
var b byte = addr[i] + idx[i] + carry
|
||||||
|
if b < addr[i] {
|
||||||
|
carry = 1
|
||||||
|
} else {
|
||||||
|
carry = 0
|
||||||
|
}
|
||||||
|
addr[i] = b
|
||||||
|
}
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func storageAddress(addr []byte) string {
|
||||||
|
return common.ToHex(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeAddress(address common.Address) string {
|
||||||
|
return addressAbiPrefix + address.Hex()[2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeName(name string, index uint8) (string, string) {
|
||||||
|
extra := common.Bytes2Hex([]byte(name))
|
||||||
|
if len(name) > 32 {
|
||||||
|
return fmt.Sprintf("%064x", index), extra
|
||||||
|
}
|
||||||
|
return extra + falseHex[len(extra):], ""
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package resolver
|
package registrar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@ -20,22 +20,22 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func NewTestBackend() *testBackend {
|
func NewTestBackend() *testBackend {
|
||||||
HashRegContractAddress = common.BigToAddress(common.Big0).Hex()[2:]
|
HashRegAddr = common.BigToAddress(common.Big0).Hex() //[2:]
|
||||||
UrlHintContractAddress = common.BigToAddress(common.Big1).Hex()[2:]
|
UrlHintAddr = common.BigToAddress(common.Big1).Hex() //[2:]
|
||||||
self := &testBackend{}
|
self := &testBackend{}
|
||||||
self.contracts = make(map[string](map[string]string))
|
self.contracts = make(map[string](map[string]string))
|
||||||
|
|
||||||
self.contracts[HashRegContractAddress] = make(map[string]string)
|
self.contracts[HashRegAddr[2:]] = make(map[string]string)
|
||||||
key := storageAddress(storageMapping(storageIdx2Addr(1), codehash[:]))
|
key := storageAddress(storageMapping(storageIdx2Addr(1), codehash[:]))
|
||||||
self.contracts[HashRegContractAddress][key] = hash.Hex()
|
self.contracts[HashRegAddr[2:]][key] = hash.Hex()
|
||||||
|
|
||||||
self.contracts[UrlHintContractAddress] = make(map[string]string)
|
self.contracts[UrlHintAddr[2:]] = make(map[string]string)
|
||||||
mapaddr := storageMapping(storageIdx2Addr(1), hash[:])
|
mapaddr := storageMapping(storageIdx2Addr(1), hash[:])
|
||||||
|
|
||||||
key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(0)))
|
key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(0)))
|
||||||
self.contracts[UrlHintContractAddress][key] = common.ToHex([]byte(url))
|
self.contracts[UrlHintAddr[2:]][key] = common.ToHex([]byte(url))
|
||||||
key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(1)))
|
key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(1)))
|
||||||
self.contracts[UrlHintContractAddress][key] = "0x00"
|
self.contracts[UrlHintAddr[2:]][key] = "0x0"
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,11 +52,25 @@ func (self *testBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, ga
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyToContentHash(t *testing.T) {
|
func (self *testBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error) {
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetGlobalRegistrar(t *testing.T) {
|
||||||
b := NewTestBackend()
|
b := NewTestBackend()
|
||||||
res := New(b)
|
res := New(b)
|
||||||
|
_, err := res.SetGlobalRegistrar("addresshex", common.BigToAddress(common.Big1))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v'", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
got, err := res.KeyToContentHash(codehash)
|
func TestHashToHash(t *testing.T) {
|
||||||
|
b := NewTestBackend()
|
||||||
|
res := New(b)
|
||||||
|
// res.SetHashReg()
|
||||||
|
|
||||||
|
got, err := res.HashToHash(codehash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expected no error, got %v", err)
|
t.Errorf("expected no error, got %v", err)
|
||||||
} else {
|
} else {
|
||||||
@ -66,28 +80,17 @@ func TestKeyToContentHash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContentHashToUrl(t *testing.T) {
|
func TestHashToUrl(t *testing.T) {
|
||||||
b := NewTestBackend()
|
b := NewTestBackend()
|
||||||
res := New(b)
|
res := New(b)
|
||||||
got, err := res.ContentHashToUrl(hash)
|
// res.SetUrlHint()
|
||||||
|
|
||||||
|
got, err := res.HashToUrl(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expected no error, got %v", err)
|
t.Errorf("expected error, got %v", err)
|
||||||
} else {
|
} else {
|
||||||
if got != url {
|
if got != url {
|
||||||
t.Errorf("incorrect result, expected '%v', got '%s'", url, got)
|
t.Errorf("incorrect result, expected '%v', got '%s'", url, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyToUrl(t *testing.T) {
|
|
||||||
b := NewTestBackend()
|
|
||||||
res := New(b)
|
|
||||||
got, _, err := res.KeyToUrl(codehash)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("expected no error, got %v", err)
|
|
||||||
} else {
|
|
||||||
if got != url {
|
|
||||||
t.Errorf("incorrect result, expected \n'%s', got \n'%s'", url, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
const ( // built-in contracts address and code
|
|
||||||
ContractCodeURLhint = "0x60c180600c6000396000f30060003560e060020a90048063300a3bbf14601557005b6024600435602435604435602a565b60006000f35b6000600084815260200190815260200160002054600160a060020a0316600014806078575033600160a060020a03166000600085815260200190815260200160002054600160a060020a0316145b607f5760bc565b336000600085815260200190815260200160002081905550806001600085815260200190815260200160002083610100811060b657005b01819055505b50505056"
|
|
||||||
/*
|
|
||||||
contract URLhint {
|
|
||||||
function register(uint256 _hash, uint8 idx, uint256 _url) {
|
|
||||||
if (owner[_hash] == 0 || owner[_hash] == msg.sender) {
|
|
||||||
owner[_hash] = msg.sender;
|
|
||||||
url[_hash][idx] = _url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mapping (uint256 => address) owner;
|
|
||||||
mapping (uint256 => uint256[256]) url;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
ContractCodeHashReg = "0x609880600c6000396000f30060003560e060020a9004806331e12c2014601f578063d66d6c1014602b57005b6025603d565b60006000f35b6037600435602435605d565b60006000f35b600054600160a060020a0316600014605357605b565b336000819055505b565b600054600160a060020a031633600160a060020a031614607b576094565b8060016000848152602001908152602001600020819055505b505056"
|
|
||||||
/*
|
|
||||||
contract HashReg {
|
|
||||||
function setowner() {
|
|
||||||
if (owner == 0) {
|
|
||||||
owner = msg.sender;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function register(uint256 _key, uint256 _content) {
|
|
||||||
if (msg.sender == owner) {
|
|
||||||
content[_key] = _content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
address owner;
|
|
||||||
mapping (uint256 => uint256) content;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
)
|
|
@ -1,232 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
Resolver implements the Ethereum DNS mapping
|
|
||||||
HashReg : Key Hash (hash of domain name or contract code) -> Content Hash
|
|
||||||
UrlHint : Content Hash -> Url Hint
|
|
||||||
|
|
||||||
The resolver is meant to be called by the roundtripper transport implementation
|
|
||||||
of a url scheme
|
|
||||||
*/
|
|
||||||
|
|
||||||
// // contract addresses will be hardcoded after they're created
|
|
||||||
var UrlHintContractAddress, HashRegContractAddress string
|
|
||||||
|
|
||||||
const (
|
|
||||||
txValue = "0"
|
|
||||||
txGas = "100000"
|
|
||||||
txGasPrice = "1000000000000"
|
|
||||||
)
|
|
||||||
|
|
||||||
func abi(s string) string {
|
|
||||||
return common.ToHex(crypto.Sha3([]byte(s))[:4])
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
registerContentHashAbi = abi("register(uint256,uint256)")
|
|
||||||
registerUrlAbi = abi("register(uint256,uint8,uint256)")
|
|
||||||
setOwnerAbi = abi("setowner()")
|
|
||||||
)
|
|
||||||
|
|
||||||
type Backend interface {
|
|
||||||
StorageAt(string, string) string
|
|
||||||
Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Resolver struct {
|
|
||||||
backend Backend
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(eth Backend) *Resolver {
|
|
||||||
return &Resolver{eth}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for testing and play temporarily
|
|
||||||
// ideally the HashReg and UrlHint contracts should be in the genesis block
|
|
||||||
// if we got build-in support for natspec/contract info
|
|
||||||
// there should be only one of these officially endorsed
|
|
||||||
// addresses as constants
|
|
||||||
// TODO: could get around this with namereg, check
|
|
||||||
func (self *Resolver) CreateContracts(addr common.Address) (err error) {
|
|
||||||
HashRegContractAddress, err = self.backend.Transact(addr.Hex(), "", "", txValue, txGas, txGasPrice, ContractCodeHashReg)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
UrlHintContractAddress, err = self.backend.Transact(addr.Hex(), "", "", txValue, txGas, txGasPrice, ContractCodeURLhint)
|
|
||||||
glog.V(logger.Detail).Infof("HashReg @ %v\nUrlHint @ %v\n", HashRegContractAddress, UrlHintContractAddress)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// called as first step in the registration process on HashReg
|
|
||||||
func (self *Resolver) SetOwner(address common.Address) (txh string, err error) {
|
|
||||||
return self.backend.Transact(
|
|
||||||
address.Hex(),
|
|
||||||
HashRegContractAddress,
|
|
||||||
"", txValue, txGas, txGasPrice,
|
|
||||||
setOwnerAbi,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// registers some content hash to a key/code hash
|
|
||||||
// e.g., the contract Info combined Json Doc's ContentHash
|
|
||||||
// to CodeHash of a contract or hash of a domain
|
|
||||||
// kept
|
|
||||||
func (self *Resolver) RegisterContentHash(address common.Address, codehash, dochash common.Hash) (txh string, err error) {
|
|
||||||
_, err = self.SetOwner(address)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
codehex := common.Bytes2Hex(codehash[:])
|
|
||||||
dochex := common.Bytes2Hex(dochash[:])
|
|
||||||
|
|
||||||
data := registerContentHashAbi + codehex + dochex
|
|
||||||
return self.backend.Transact(
|
|
||||||
address.Hex(),
|
|
||||||
HashRegContractAddress,
|
|
||||||
"", txValue, txGas, txGasPrice,
|
|
||||||
data,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// registers a url to a content hash so that the content can be fetched
|
|
||||||
// address is used as sender for the transaction and will be the owner of a new
|
|
||||||
// registry entry on first time use
|
|
||||||
// FIXME: silently doing nothing if sender is not the owner
|
|
||||||
// note that with content addressed storage, this step is no longer necessary
|
|
||||||
// it could be purely
|
|
||||||
func (self *Resolver) RegisterUrl(address common.Address, hash common.Hash, url string) (txh string, err error) {
|
|
||||||
hashHex := common.Bytes2Hex(hash[:])
|
|
||||||
var urlHex string
|
|
||||||
urlb := []byte(url)
|
|
||||||
var cnt byte
|
|
||||||
n := len(urlb)
|
|
||||||
|
|
||||||
for n > 0 {
|
|
||||||
if n > 32 {
|
|
||||||
n = 32
|
|
||||||
}
|
|
||||||
urlHex = common.Bytes2Hex(urlb[:n])
|
|
||||||
urlb = urlb[n:]
|
|
||||||
n = len(urlb)
|
|
||||||
bcnt := make([]byte, 32)
|
|
||||||
bcnt[31] = cnt
|
|
||||||
data := registerUrlAbi +
|
|
||||||
hashHex +
|
|
||||||
common.Bytes2Hex(bcnt) +
|
|
||||||
common.Bytes2Hex(common.Hex2BytesFixed(urlHex, 32))
|
|
||||||
txh, err = self.backend.Transact(
|
|
||||||
address.Hex(),
|
|
||||||
UrlHintContractAddress,
|
|
||||||
"", txValue, txGas, txGasPrice,
|
|
||||||
data,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cnt++
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Resolver) Register(address common.Address, codehash, dochash common.Hash, url string) (txh string, err error) {
|
|
||||||
|
|
||||||
_, err = self.RegisterContentHash(address, codehash, dochash)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return self.RegisterUrl(address, dochash, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolution is costless non-transactional
|
|
||||||
// implemented as direct retrieval from db
|
|
||||||
func (self *Resolver) KeyToContentHash(khash common.Hash) (chash common.Hash, err error) {
|
|
||||||
// look up in hashReg
|
|
||||||
at := common.Bytes2Hex(common.FromHex(HashRegContractAddress))
|
|
||||||
key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:]))
|
|
||||||
hash := self.backend.StorageAt(at, key)
|
|
||||||
|
|
||||||
if hash == "0x0" || len(hash) < 3 {
|
|
||||||
err = fmt.Errorf("content hash not found for '%v'", khash.Hex())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
copy(chash[:], common.Hex2BytesFixed(hash[2:], 32))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieves the url-hint for the content hash -
|
|
||||||
// if we use content addressed storage, this step is no longer necessary
|
|
||||||
func (self *Resolver) ContentHashToUrl(chash common.Hash) (uri string, err error) {
|
|
||||||
// look up in URL reg
|
|
||||||
var str string = " "
|
|
||||||
var idx uint32
|
|
||||||
for len(str) > 0 {
|
|
||||||
mapaddr := storageMapping(storageIdx2Addr(1), chash[:])
|
|
||||||
key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx)))
|
|
||||||
hex := self.backend.StorageAt(UrlHintContractAddress, key)
|
|
||||||
str = string(common.Hex2Bytes(hex[2:]))
|
|
||||||
l := len(str)
|
|
||||||
for (l > 0) && (str[l-1] == 0) {
|
|
||||||
l--
|
|
||||||
}
|
|
||||||
str = str[:l]
|
|
||||||
uri = uri + str
|
|
||||||
idx++
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(uri) == 0 {
|
|
||||||
err = fmt.Errorf("GetURLhint: URL hint not found for '%v'", chash.Hex())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Resolver) KeyToUrl(key common.Hash) (uri string, hash common.Hash, err error) {
|
|
||||||
// look up in urlHint
|
|
||||||
hash, err = self.KeyToContentHash(key)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
uri, err = self.ContentHashToUrl(hash)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func storageIdx2Addr(varidx uint32) []byte {
|
|
||||||
data := make([]byte, 32)
|
|
||||||
binary.BigEndian.PutUint32(data[28:32], varidx)
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
func storageMapping(addr, key []byte) []byte {
|
|
||||||
data := make([]byte, 64)
|
|
||||||
copy(data[0:32], key[0:32])
|
|
||||||
copy(data[32:64], addr[0:32])
|
|
||||||
sha := crypto.Sha3(data)
|
|
||||||
return sha
|
|
||||||
}
|
|
||||||
|
|
||||||
func storageFixedArray(addr, idx []byte) []byte {
|
|
||||||
var carry byte
|
|
||||||
for i := 31; i >= 0; i-- {
|
|
||||||
var b byte = addr[i] + idx[i] + carry
|
|
||||||
if b < addr[i] {
|
|
||||||
carry = 1
|
|
||||||
} else {
|
|
||||||
carry = 0
|
|
||||||
}
|
|
||||||
addr[i] = b
|
|
||||||
}
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func storageAddress(addr []byte) string {
|
|
||||||
return common.ToHex(addr)
|
|
||||||
}
|
|
@ -70,6 +70,7 @@ type Config struct {
|
|||||||
VmDebug bool
|
VmDebug bool
|
||||||
NatSpec bool
|
NatSpec bool
|
||||||
AutoDAG bool
|
AutoDAG bool
|
||||||
|
PowTest bool
|
||||||
|
|
||||||
MaxPeers int
|
MaxPeers int
|
||||||
MaxPendingPeers int
|
MaxPendingPeers int
|
||||||
@ -221,6 +222,7 @@ type Ethereum struct {
|
|||||||
NatSpec bool
|
NatSpec bool
|
||||||
DataDir string
|
DataDir string
|
||||||
AutoDAG bool
|
AutoDAG bool
|
||||||
|
PowTest bool
|
||||||
autodagquit chan bool
|
autodagquit chan bool
|
||||||
etherbase common.Address
|
etherbase common.Address
|
||||||
clientVersion string
|
clientVersion string
|
||||||
@ -329,6 +331,7 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
MinerThreads: config.MinerThreads,
|
MinerThreads: config.MinerThreads,
|
||||||
SolcPath: config.SolcPath,
|
SolcPath: config.SolcPath,
|
||||||
AutoDAG: config.AutoDAG,
|
AutoDAG: config.AutoDAG,
|
||||||
|
PowTest: config.PowTest,
|
||||||
GpoMinGasPrice: config.GpoMinGasPrice,
|
GpoMinGasPrice: config.GpoMinGasPrice,
|
||||||
GpoMaxGasPrice: config.GpoMaxGasPrice,
|
GpoMaxGasPrice: config.GpoMaxGasPrice,
|
||||||
GpoFullBlockRatio: config.GpoFullBlockRatio,
|
GpoFullBlockRatio: config.GpoFullBlockRatio,
|
||||||
@ -337,7 +340,15 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
GpobaseCorrectionFactor: config.GpobaseCorrectionFactor,
|
GpobaseCorrectionFactor: config.GpobaseCorrectionFactor,
|
||||||
}
|
}
|
||||||
|
|
||||||
eth.pow = ethash.New()
|
if config.PowTest {
|
||||||
|
glog.V(logger.Info).Infof("ethash used in test mode")
|
||||||
|
eth.pow, err = ethash.NewForTesting()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eth.pow = ethash.New()
|
||||||
|
}
|
||||||
genesis := core.GenesisBlock(uint64(config.GenesisNonce), stateDb)
|
genesis := core.GenesisBlock(uint64(config.GenesisNonce), stateDb)
|
||||||
eth.chainManager, err = core.NewChainManager(genesis, blockDb, stateDb, extraDb, eth.pow, eth.EventMux())
|
eth.chainManager, err = core.NewChainManager(genesis, blockDb, stateDb, extraDb, eth.pow, eth.EventMux())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -97,7 +97,15 @@ var isMemberFunction = function(object, member) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isBigNumber = function (object) {
|
var isBigNumber = function (object) {
|
||||||
return typeof BigNumber !== 'undefined' && object instanceof BigNumber;
|
var result = typeof BigNumber !== 'undefined' && object instanceof BigNumber;
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
if(typeof(object) === "object") {
|
||||||
|
result = object.constructor.toString().indexOf("function BigNumber(") == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
};
|
};
|
||||||
|
|
||||||
function prettyPrint(/* */) {
|
function prettyPrint(/* */) {
|
||||||
|
236
rpc/api/admin.go
236
rpc/api/admin.go
@ -3,10 +3,18 @@ package api
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/compiler"
|
||||||
|
"github.com/ethereum/go-ethereum/common/docserver"
|
||||||
|
"github.com/ethereum/go-ethereum/common/natspec"
|
||||||
|
"github.com/ethereum/go-ethereum/common/registrar"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
@ -24,17 +32,29 @@ const (
|
|||||||
var (
|
var (
|
||||||
// mapping between methods and handlers
|
// mapping between methods and handlers
|
||||||
AdminMapping = map[string]adminhandler{
|
AdminMapping = map[string]adminhandler{
|
||||||
"admin_addPeer": (*adminApi).AddPeer,
|
"admin_addPeer": (*adminApi).AddPeer,
|
||||||
"admin_peers": (*adminApi).Peers,
|
"admin_peers": (*adminApi).Peers,
|
||||||
"admin_nodeInfo": (*adminApi).NodeInfo,
|
"admin_nodeInfo": (*adminApi).NodeInfo,
|
||||||
"admin_exportChain": (*adminApi).ExportChain,
|
"admin_exportChain": (*adminApi).ExportChain,
|
||||||
"admin_importChain": (*adminApi).ImportChain,
|
"admin_importChain": (*adminApi).ImportChain,
|
||||||
"admin_verbosity": (*adminApi).Verbosity,
|
"admin_verbosity": (*adminApi).Verbosity,
|
||||||
"admin_chainSyncStatus": (*adminApi).ChainSyncStatus,
|
"admin_chainSyncStatus": (*adminApi).ChainSyncStatus,
|
||||||
"admin_setSolc": (*adminApi).SetSolc,
|
"admin_setSolc": (*adminApi).SetSolc,
|
||||||
"admin_datadir": (*adminApi).DataDir,
|
"admin_datadir": (*adminApi).DataDir,
|
||||||
"admin_startRPC": (*adminApi).StartRPC,
|
"admin_startRPC": (*adminApi).StartRPC,
|
||||||
"admin_stopRPC": (*adminApi).StopRPC,
|
"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,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -47,6 +67,7 @@ type adminApi struct {
|
|||||||
ethereum *eth.Ethereum
|
ethereum *eth.Ethereum
|
||||||
codec codec.Codec
|
codec codec.Codec
|
||||||
coder codec.ApiCoder
|
coder codec.ApiCoder
|
||||||
|
ds *docserver.DocServer
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a new admin api instance
|
// create a new admin api instance
|
||||||
@ -56,6 +77,7 @@ func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, codec codec.Codec) *ad
|
|||||||
ethereum: ethereum,
|
ethereum: ethereum,
|
||||||
codec: codec,
|
codec: codec,
|
||||||
coder: codec.New(nil),
|
coder: codec.New(nil),
|
||||||
|
ds: docserver.New("/"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,3 +266,195 @@ func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) {
|
|||||||
comms.StopHttp()
|
comms.StopHttp()
|
||||||
return true, nil
|
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.xeth.CurrentBlock().Number(), big.NewInt(args.N))
|
||||||
|
height, err = sleepBlocks(self.xeth.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.xeth.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.ethereum.NatSpec = true
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *adminApi) StopNatSpec(req *shared.Request) (interface{}, error) {
|
||||||
|
self.ethereum.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.ds)
|
||||||
|
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.ds.Get(args.Uri, args.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(resp), nil
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/compiler"
|
||||||
"github.com/ethereum/go-ethereum/rpc/shared"
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ func (args *StartRPCArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
args.ListenPort = 8545
|
args.ListenPort = 8545
|
||||||
args.Apis = "net,eth,web3"
|
args.Apis = "net,eth,web3"
|
||||||
|
|
||||||
if len(obj) >= 1 {
|
if len(obj) >= 1 && obj[0] != nil {
|
||||||
if addr, ok := obj[0].(string); ok {
|
if addr, ok := obj[0].(string); ok {
|
||||||
args.ListenAddress = addr
|
args.ListenAddress = addr
|
||||||
} else {
|
} else {
|
||||||
@ -121,7 +122,7 @@ func (args *StartRPCArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(obj) >= 2 {
|
if len(obj) >= 2 && obj[1] != nil {
|
||||||
if port, ok := obj[1].(float64); ok && port >= 0 && port <= 64*1024 {
|
if port, ok := obj[1].(float64); ok && port >= 0 && port <= 64*1024 {
|
||||||
args.ListenPort = uint(port)
|
args.ListenPort = uint(port)
|
||||||
} else {
|
} else {
|
||||||
@ -129,7 +130,7 @@ func (args *StartRPCArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(obj) >= 3 {
|
if len(obj) >= 3 && obj[2] != nil {
|
||||||
if corsDomain, ok := obj[2].(string); ok {
|
if corsDomain, ok := obj[2].(string); ok {
|
||||||
args.CorsDomain = corsDomain
|
args.CorsDomain = corsDomain
|
||||||
} else {
|
} else {
|
||||||
@ -137,7 +138,7 @@ func (args *StartRPCArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(obj) >= 4 {
|
if len(obj) >= 4 && obj[3] != nil {
|
||||||
if apis, ok := obj[3].(string); ok {
|
if apis, ok := obj[3].(string); ok {
|
||||||
args.Apis = apis
|
args.Apis = apis
|
||||||
} else {
|
} else {
|
||||||
@ -147,3 +148,327 @@ func (args *StartRPCArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
|
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
@ -9,73 +9,128 @@ web3._extend({
|
|||||||
name: 'addPeer',
|
name: 'addPeer',
|
||||||
call: 'admin_addPeer',
|
call: 'admin_addPeer',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.utils.formatInputString],
|
inputFormatter: [null]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'exportChain',
|
name: 'exportChain',
|
||||||
call: 'admin_exportChain',
|
call: 'admin_exportChain',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.utils.formatInputString],
|
inputFormatter: [null]
|
||||||
outputFormatter: function(obj) { return obj; }
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'importChain',
|
name: 'importChain',
|
||||||
call: 'admin_importChain',
|
call: 'admin_importChain',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.utils.formatInputString],
|
inputFormatter: [null]
|
||||||
outputFormatter: function(obj) { return obj; }
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'sleepBlocks',
|
||||||
|
call: 'admin_sleepBlocks',
|
||||||
|
params: 2,
|
||||||
|
inputFormatter: [null, null]
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'verbosity',
|
name: 'verbosity',
|
||||||
call: 'admin_verbosity',
|
call: 'admin_verbosity',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.utils.formatInputInt],
|
inputFormatter: [web3._extend.utils.fromDecimal]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'setSolc',
|
name: 'setSolc',
|
||||||
call: 'admin_setSolc',
|
call: 'admin_setSolc',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.utils.formatInputString],
|
inputFormatter: [null]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'startRPC',
|
name: 'startRPC',
|
||||||
call: 'admin_startRPC',
|
call: 'admin_startRPC',
|
||||||
params: 4,
|
params: 4,
|
||||||
inputFormatter: [web3._extend.utils.formatInputString,web3._extend.utils.formatInputInteger,web3._extend.utils.formatInputString,web3._extend.utils.formatInputString],
|
inputFormatter: [null, null, null, null]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'stopRPC',
|
name: 'stopRPC',
|
||||||
call: 'admin_stopRPC',
|
call: 'admin_stopRPC',
|
||||||
params: 0,
|
params: 0,
|
||||||
inputFormatter: [],
|
inputFormatter: []
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
}),
|
||||||
|
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:
|
properties:
|
||||||
[
|
[
|
||||||
new web3._extend.Property({
|
new web3._extend.Property({
|
||||||
name: 'nodeInfo',
|
name: 'nodeInfo',
|
||||||
getter: 'admin_nodeInfo',
|
getter: 'admin_nodeInfo'
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Property({
|
new web3._extend.Property({
|
||||||
name: 'peers',
|
name: 'peers',
|
||||||
getter: 'admin_peers',
|
getter: 'admin_peers'
|
||||||
outputFormatter: function(obj) { return obj; }
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Property({
|
new web3._extend.Property({
|
||||||
name: 'datadir',
|
name: 'datadir',
|
||||||
getter: 'admin_datadir',
|
getter: 'admin_datadir'
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Property({
|
new web3._extend.Property({
|
||||||
name: 'chainSyncStatus',
|
name: 'chainSyncStatus',
|
||||||
getter: 'admin_chainSyncStatus',
|
getter: 'admin_chainSyncStatus'
|
||||||
outputFormatter: function(obj) { return obj; }
|
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -5,34 +5,6 @@ web3._extend({
|
|||||||
property: 'db',
|
property: 'db',
|
||||||
methods:
|
methods:
|
||||||
[
|
[
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'getString',
|
|
||||||
call: 'db_getString',
|
|
||||||
params: 2,
|
|
||||||
inputFormatter: [web3._extend.formatters.formatInputString, web3._extend.formatters.formatInputString],
|
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'putString',
|
|
||||||
call: 'db_putString',
|
|
||||||
params: 3,
|
|
||||||
inputFormatter: [web3._extend.formatters.formatInputString, web3._extend.formatters.formatInputString, web3._extend.formatters.formatInputString],
|
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'getHex',
|
|
||||||
call: 'db_getHex',
|
|
||||||
params: 2,
|
|
||||||
inputFormatter: [web3._extend.formatters.formatInputString, web3._extend.formatters.formatInputString],
|
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'putHex',
|
|
||||||
call: 'db_putHex',
|
|
||||||
params: 3,
|
|
||||||
inputFormatter: [web3._extend.formatters.formatInputString, web3._extend.formatters.formatInputString, web3._extend.formatters.formatInputString],
|
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
properties:
|
properties:
|
||||||
[
|
[
|
||||||
|
@ -9,50 +9,43 @@ web3._extend({
|
|||||||
name: 'printBlock',
|
name: 'printBlock',
|
||||||
call: 'debug_printBlock',
|
call: 'debug_printBlock',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputInt],
|
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'getBlockRlp',
|
name: 'getBlockRlp',
|
||||||
call: 'debug_getBlockRlp',
|
call: 'debug_getBlockRlp',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputInt],
|
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'setHead',
|
name: 'setHead',
|
||||||
call: 'debug_setHead',
|
call: 'debug_setHead',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputInt],
|
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'processBlock',
|
name: 'processBlock',
|
||||||
call: 'debug_processBlock',
|
call: 'debug_processBlock',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputInt],
|
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
|
||||||
outputFormatter: function(obj) { return obj; }
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'seedHash',
|
name: 'seedHash',
|
||||||
call: 'debug_seedHash',
|
call: 'debug_seedHash',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputInt],
|
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
}),
|
||||||
}) ,
|
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'dumpBlock',
|
name: 'dumpBlock',
|
||||||
call: 'debug_dumpBlock',
|
call: 'debug_dumpBlock',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputInt],
|
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
|
||||||
outputFormatter: function(obj) { return obj; }
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'metrics',
|
name: 'metrics',
|
||||||
call: 'debug_metrics',
|
call: 'debug_metrics',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputBool],
|
inputFormatter: [null]
|
||||||
outputFormatter: function(obj) { return obj; }
|
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
properties:
|
properties:
|
||||||
|
@ -12,23 +12,20 @@ web3._extend({
|
|||||||
name: 'sign',
|
name: 'sign',
|
||||||
call: 'eth_sign',
|
call: 'eth_sign',
|
||||||
params: 2,
|
params: 2,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputString,web3._extend.formatters.formatInputString],
|
inputFormatter: [web3._extend.utils.toAddress, null]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'resend',
|
name: 'resend',
|
||||||
call: 'eth_resend',
|
call: 'eth_resend',
|
||||||
params: 3,
|
params: 3,
|
||||||
inputFormatter: [function(obj) { return obj; },web3._extend.formatters.formatInputString,web3._extend.formatters.formatInputString],
|
inputFormatter: [web3._extend.formatters.inputTransactionFormatter, web3._extend.utils.fromDecimal, web3._extend.utils.fromDecimal]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
properties:
|
properties:
|
||||||
[
|
[
|
||||||
new web3._extend.Property({
|
new web3._extend.Property({
|
||||||
name: 'pendingTransactions',
|
name: 'pendingTransactions',
|
||||||
getter: 'eth_pendingTransactions',
|
getter: 'eth_pendingTransactions'
|
||||||
outputFormatter: function(obj) { return obj; }
|
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -9,50 +9,43 @@ web3._extend({
|
|||||||
name: 'start',
|
name: 'start',
|
||||||
call: 'miner_start',
|
call: 'miner_start',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputInt],
|
inputFormatter: [null]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'stop',
|
name: 'stop',
|
||||||
call: 'miner_stop',
|
call: 'miner_stop',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputInt],
|
inputFormatter: [null]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'setExtra',
|
name: 'setExtra',
|
||||||
call: 'miner_setExtra',
|
call: 'miner_setExtra',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.utils.formatInputString],
|
inputFormatter: [null]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'setGasPrice',
|
name: 'setGasPrice',
|
||||||
call: 'miner_setGasPrice',
|
call: 'miner_setGasPrice',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.utils.formatInputString],
|
inputFormatter: [web3._extend.utils.fromDecial]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'startAutoDAG',
|
name: 'startAutoDAG',
|
||||||
call: 'miner_startAutoDAG',
|
call: 'miner_startAutoDAG',
|
||||||
params: 0,
|
params: 0,
|
||||||
inputFormatter: [],
|
inputFormatter: []
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'stopAutoDAG',
|
name: 'stopAutoDAG',
|
||||||
call: 'miner_stopAutoDAG',
|
call: 'miner_stopAutoDAG',
|
||||||
params: 0,
|
params: 0,
|
||||||
inputFormatter: [],
|
inputFormatter: []
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'makeDAG',
|
name: 'makeDAG',
|
||||||
call: 'miner_makeDAG',
|
call: 'miner_makeDAG',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.inputDefaultBlockNumberFormatter],
|
inputFormatter: [web3._extend.formatters.inputDefaultBlockNumberFormatter]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
properties:
|
properties:
|
||||||
|
@ -14,10 +14,8 @@ const (
|
|||||||
var (
|
var (
|
||||||
// mapping between methods and handlers
|
// mapping between methods and handlers
|
||||||
netMapping = map[string]nethandler{
|
netMapping = map[string]nethandler{
|
||||||
"net_version": (*netApi).Version,
|
|
||||||
"net_peerCount": (*netApi).PeerCount,
|
"net_peerCount": (*netApi).PeerCount,
|
||||||
"net_listening": (*netApi).IsListening,
|
"net_listening": (*netApi).IsListening,
|
||||||
"net_peers": (*netApi).Peers,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -70,11 +68,6 @@ func (self *netApi) ApiVersion() string {
|
|||||||
return NetApiVersion
|
return NetApiVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network version
|
|
||||||
func (self *netApi) Version(req *shared.Request) (interface{}, error) {
|
|
||||||
return self.xeth.NetworkVersion(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Number of connected peers
|
// Number of connected peers
|
||||||
func (self *netApi) PeerCount(req *shared.Request) (interface{}, error) {
|
func (self *netApi) PeerCount(req *shared.Request) (interface{}, error) {
|
||||||
return newHexNum(self.xeth.PeerCount()), nil
|
return newHexNum(self.xeth.PeerCount()), nil
|
||||||
@ -84,6 +77,3 @@ func (self *netApi) IsListening(req *shared.Request) (interface{}, error) {
|
|||||||
return self.xeth.IsListening(), nil
|
return self.xeth.IsListening(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *netApi) Peers(req *shared.Request) (interface{}, error) {
|
|
||||||
return self.ethereum.PeersInfo(), nil
|
|
||||||
}
|
|
||||||
|
@ -2,46 +2,18 @@ package api
|
|||||||
|
|
||||||
const Net_JS = `
|
const Net_JS = `
|
||||||
web3._extend({
|
web3._extend({
|
||||||
property: 'network',
|
property: 'net',
|
||||||
methods:
|
methods:
|
||||||
[
|
[
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'addPeer',
|
name: 'addPeer',
|
||||||
call: 'net_addPeer',
|
call: 'net_addPeer',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.utils.formatInputString],
|
inputFormatter: [null]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'getPeerCount',
|
|
||||||
call: 'net_peerCount',
|
|
||||||
params: 0,
|
|
||||||
inputFormatter: [],
|
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
properties:
|
properties:
|
||||||
[
|
[
|
||||||
new web3._extend.Property({
|
|
||||||
name: 'listening',
|
|
||||||
getter: 'net_listening',
|
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
|
||||||
new web3._extend.Property({
|
|
||||||
name: 'peerCount',
|
|
||||||
getter: 'net_peerCount',
|
|
||||||
outputFormatter: web3._extend.utils.toDecimal
|
|
||||||
}),
|
|
||||||
new web3._extend.Property({
|
|
||||||
name: 'peers',
|
|
||||||
getter: 'net_peers',
|
|
||||||
outputFormatter: function(obj) { return obj; }
|
|
||||||
}),
|
|
||||||
new web3._extend.Property({
|
|
||||||
name: 'version',
|
|
||||||
getter: 'net_version',
|
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
|
||||||
})
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
|
@ -9,23 +9,21 @@ web3._extend({
|
|||||||
name: 'newAccount',
|
name: 'newAccount',
|
||||||
call: 'personal_newAccount',
|
call: 'personal_newAccount',
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputString],
|
inputFormatter: [null],
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
outputFormatter: web3._extend.utils.toAddress
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'unlockAccount',
|
name: 'unlockAccount',
|
||||||
call: 'personal_unlockAccount',
|
call: 'personal_unlockAccount',
|
||||||
params: 3,
|
params: 3,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputString,web3._extend.formatters.formatInputString,web3._extend.formatters.formatInputInt],
|
inputFormatter: [null, null, null]
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
properties:
|
properties:
|
||||||
[
|
[
|
||||||
new web3._extend.Property({
|
new web3._extend.Property({
|
||||||
name: 'listAccounts',
|
name: 'listAccounts',
|
||||||
getter: 'personal_listAccounts',
|
getter: 'personal_listAccounts'
|
||||||
outputFormatter: function(obj) { return obj; }
|
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -5,25 +5,13 @@ web3._extend({
|
|||||||
property: 'shh',
|
property: 'shh',
|
||||||
methods:
|
methods:
|
||||||
[
|
[
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'post',
|
|
||||||
call: 'shh_post',
|
|
||||||
params: 6,
|
|
||||||
inputFormatter: [web3._extend.formatters.formatInputString,
|
|
||||||
web3._extend.formatters.formatInputString,
|
|
||||||
web3._extend.formatters.formatInputString,
|
|
||||||
,
|
|
||||||
, web3._extend.formatters.formatInputInt
|
|
||||||
, web3._extend.formatters.formatInputInt],
|
|
||||||
outputFormatter: web3._extend.formatters.formatOutputBool
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
properties:
|
properties:
|
||||||
[
|
[
|
||||||
new web3._extend.Property({
|
new web3._extend.Property({
|
||||||
name: 'version',
|
name: 'version',
|
||||||
getter: 'shh_version',
|
getter: 'shh_version'
|
||||||
outputFormatter: web3._extend.formatters.formatOutputInt
|
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -36,6 +36,7 @@ var (
|
|||||||
"debug": []string{
|
"debug": []string{
|
||||||
"dumpBlock",
|
"dumpBlock",
|
||||||
"getBlockRlp",
|
"getBlockRlp",
|
||||||
|
"metrics",
|
||||||
"printBlock",
|
"printBlock",
|
||||||
"processBlock",
|
"processBlock",
|
||||||
"seedHash",
|
"seedHash",
|
||||||
@ -44,49 +45,38 @@ var (
|
|||||||
"eth": []string{
|
"eth": []string{
|
||||||
"accounts",
|
"accounts",
|
||||||
"blockNumber",
|
"blockNumber",
|
||||||
"getBalance",
|
|
||||||
"protocolVersion",
|
|
||||||
"coinbase",
|
|
||||||
"mining",
|
|
||||||
"gasPrice",
|
|
||||||
"getStorage",
|
|
||||||
"storageAt",
|
|
||||||
"getStorageAt",
|
|
||||||
"getTransactionCount",
|
|
||||||
"getBlockTransactionCountByHash",
|
|
||||||
"getBlockTransactionCountByNumber",
|
|
||||||
"getUncleCountByBlockHash",
|
|
||||||
"getUncleCountByBlockNumber",
|
|
||||||
"getData",
|
|
||||||
"getCode",
|
|
||||||
"sign",
|
|
||||||
"sendRawTransaction",
|
|
||||||
"sendTransaction",
|
|
||||||
"transact",
|
|
||||||
"estimateGas",
|
|
||||||
"call",
|
"call",
|
||||||
"flush",
|
"contract",
|
||||||
"getBlockByHash",
|
"coinbase",
|
||||||
"getBlockByNumber",
|
"compile.lll",
|
||||||
"getTransactionByHash",
|
"compile.serpent",
|
||||||
"getTransactionByBlockHashAndIndex",
|
"compile.solidity",
|
||||||
"getUncleByBlockHashAndIndex",
|
"contract",
|
||||||
"getUncleByBlockNumberAndIndex",
|
"defaultAccount",
|
||||||
|
"defaultBlock",
|
||||||
|
"estimateGas",
|
||||||
|
"filter",
|
||||||
|
"getBalance",
|
||||||
|
"getBlock",
|
||||||
|
"getBlockTransactionCount",
|
||||||
|
"getBlockUncleCount",
|
||||||
|
"getCode",
|
||||||
"getCompilers",
|
"getCompilers",
|
||||||
"compileSolidity",
|
"gasPrice",
|
||||||
"newFilter",
|
"getStorageAt",
|
||||||
"newBlockFilter",
|
"getTransaction",
|
||||||
"newPendingTransactionFilter",
|
"getTransactionCount",
|
||||||
"uninstallFilter",
|
"getTransactionFromBlock",
|
||||||
"getFilterChanges",
|
"getTransactionReceipt",
|
||||||
"getFilterLogs",
|
"getUncle",
|
||||||
"getLogs",
|
|
||||||
"hashrate",
|
"hashrate",
|
||||||
"getWork",
|
"mining",
|
||||||
"submitWork",
|
"namereg",
|
||||||
"pendingTransactions",
|
"pendingTransactions",
|
||||||
"resend",
|
"resend",
|
||||||
"getTransactionReceipt",
|
"sendRawTransaction",
|
||||||
|
"sendTransaction",
|
||||||
|
"sign",
|
||||||
},
|
},
|
||||||
"miner": []string{
|
"miner": []string{
|
||||||
"hashrate",
|
"hashrate",
|
||||||
@ -109,13 +99,12 @@ var (
|
|||||||
"unlockAccount",
|
"unlockAccount",
|
||||||
},
|
},
|
||||||
"shh": []string{
|
"shh": []string{
|
||||||
"version",
|
|
||||||
"post",
|
"post",
|
||||||
|
"newIdentify",
|
||||||
"hasIdentity",
|
"hasIdentity",
|
||||||
"newIdentity",
|
"newGroup",
|
||||||
"newFilter",
|
"addToGroup",
|
||||||
"uninstallFilter",
|
"filter",
|
||||||
"getFilterChanges",
|
|
||||||
},
|
},
|
||||||
"txpool": []string{
|
"txpool": []string{
|
||||||
"status",
|
"status",
|
||||||
|
28
xeth/xeth.go
28
xeth/xeth.go
@ -203,34 +203,6 @@ func (self *XEth) AtStateNum(num int64) *XEth {
|
|||||||
return self.WithState(st)
|
return self.WithState(st)
|
||||||
}
|
}
|
||||||
|
|
||||||
// applies queued transactions originating from address onto the latest state
|
|
||||||
// and creates a block
|
|
||||||
// only used in tests
|
|
||||||
// - could be removed in favour of mining on testdag (natspec e2e + networking)
|
|
||||||
// + filters
|
|
||||||
func (self *XEth) ApplyTestTxs(statedb *state.StateDB, address common.Address, txc uint64) (uint64, *XEth) {
|
|
||||||
chain := self.backend.ChainManager()
|
|
||||||
header := chain.CurrentBlock().Header()
|
|
||||||
coinbase := statedb.GetStateObject(address)
|
|
||||||
coinbase.SetGasLimit(big.NewInt(10000000))
|
|
||||||
txs := self.backend.TxPool().GetQueuedTransactions()
|
|
||||||
|
|
||||||
for i := 0; i < len(txs); i++ {
|
|
||||||
for _, tx := range txs {
|
|
||||||
if tx.Nonce() == txc {
|
|
||||||
_, _, err := core.ApplyMessage(core.NewEnv(statedb, self.backend.ChainManager(), tx, header), tx, coinbase)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
txc++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xeth := self.WithState(statedb)
|
|
||||||
return txc, xeth
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *XEth) WithState(statedb *state.StateDB) *XEth {
|
func (self *XEth) WithState(statedb *state.StateDB) *XEth {
|
||||||
xeth := &XEth{
|
xeth := &XEth{
|
||||||
backend: self.backend,
|
backend: self.backend,
|
||||||
|
Loading…
Reference in New Issue
Block a user