Merge pull request #1840 from ethersphere/console
console, cli, api fixes
This commit is contained in:
commit
dce503779b
@ -45,9 +45,12 @@ import (
|
|||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var passwordRegexp = regexp.MustCompile("personal.[nu]")
|
var (
|
||||||
|
passwordRegexp = regexp.MustCompile("personal.[nu]")
|
||||||
const passwordRepl = ""
|
leadingSpace = regexp.MustCompile("^ ")
|
||||||
|
onlyws = regexp.MustCompile("^\\s*$")
|
||||||
|
exit = regexp.MustCompile("^\\s*exit\\s*;*\\s*$")
|
||||||
|
)
|
||||||
|
|
||||||
type prompter interface {
|
type prompter interface {
|
||||||
AppendHistory(string)
|
AppendHistory(string)
|
||||||
@ -74,6 +77,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 {
|
||||||
|
docRoot string
|
||||||
ds *docserver.DocServer
|
ds *docserver.DocServer
|
||||||
re *re.JSRE
|
re *re.JSRE
|
||||||
ethereum *eth.Ethereum
|
ethereum *eth.Ethereum
|
||||||
@ -145,14 +149,14 @@ func apiWordCompleter(line string, pos int) (head string, completions []string,
|
|||||||
return begin, completionWords, end
|
return begin, completionWords, end
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLightweightJSRE(libPath string, client comms.EthereumClient, datadir string, interactive bool) *jsre {
|
func newLightweightJSRE(docRoot string, client comms.EthereumClient, datadir string, interactive bool) *jsre {
|
||||||
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("/")
|
js.ds = docserver.New(docRoot)
|
||||||
|
|
||||||
// update state in separare forever blocks
|
// update state in separare forever blocks
|
||||||
js.re = re.New(libPath)
|
js.re = re.New(docRoot)
|
||||||
if err := js.apiBindings(js); err != nil {
|
if err := js.apiBindings(js); err != nil {
|
||||||
utils.Fatalf("Unable to initialize console - %v", err)
|
utils.Fatalf("Unable to initialize console - %v", err)
|
||||||
}
|
}
|
||||||
@ -176,25 +180,25 @@ func newLightweightJSRE(libPath string, client comms.EthereumClient, datadir str
|
|||||||
return js
|
return js
|
||||||
}
|
}
|
||||||
|
|
||||||
func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre {
|
func newJSRE(ethereum *eth.Ethereum, docRoot, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre {
|
||||||
js := &jsre{ethereum: ethereum, ps1: "> "}
|
js := &jsre{ethereum: ethereum, ps1: "> ", docRoot: docRoot}
|
||||||
// set default cors domain used by startRpc from CLI flag
|
// set default cors domain used by startRpc from CLI flag
|
||||||
js.corsDomain = corsDomain
|
js.corsDomain = corsDomain
|
||||||
if f == nil {
|
if f == nil {
|
||||||
f = js
|
f = js
|
||||||
}
|
}
|
||||||
js.ds = docserver.New("/")
|
js.ds = docserver.New(docRoot)
|
||||||
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
|
||||||
if clt, ok := js.client.(*comms.InProcClient); ok {
|
if clt, ok := js.client.(*comms.InProcClient); ok {
|
||||||
if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, ethereum); err == nil {
|
if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, ethereum, docRoot); err == nil {
|
||||||
clt.Initialize(api.Merge(offeredApis...))
|
clt.Initialize(api.Merge(offeredApis...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update state in separare forever blocks
|
// update state in separare forever blocks
|
||||||
js.re = re.New(libPath)
|
js.re = re.New(docRoot)
|
||||||
if err := js.apiBindings(f); err != nil {
|
if err := js.apiBindings(f); err != nil {
|
||||||
utils.Fatalf("Unable to connect - %v", err)
|
utils.Fatalf("Unable to connect - %v", err)
|
||||||
}
|
}
|
||||||
@ -277,7 +281,7 @@ func (js *jsre) apiBindings(f xeth.Frontend) error {
|
|||||||
apiNames = append(apiNames, a)
|
apiNames = append(apiNames, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.ethereum)
|
apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.ethereum, js.docRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Unable to determine supported api's: %v", err)
|
utils.Fatalf("Unable to determine supported api's: %v", err)
|
||||||
}
|
}
|
||||||
@ -334,6 +338,14 @@ func (js *jsre) apiBindings(f xeth.Frontend) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *jsre) AskPassword() (string, bool) {
|
||||||
|
pass, err := self.PasswordPrompt("Passphrase: ")
|
||||||
|
if err != nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return pass, true
|
||||||
|
}
|
||||||
|
|
||||||
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, self.ds)
|
notice := natspec.GetNotice(self.xeth, tx, self.ds)
|
||||||
@ -405,18 +417,17 @@ func (self *jsre) interactive() {
|
|||||||
fmt.Println("caught interrupt, exiting")
|
fmt.Println("caught interrupt, exiting")
|
||||||
return
|
return
|
||||||
case input, ok := <-inputln:
|
case input, ok := <-inputln:
|
||||||
if !ok || indentCount <= 0 && input == "exit" {
|
if !ok || indentCount <= 0 && exit.MatchString(input) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if input == "" {
|
if onlyws.MatchString(input) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
str += input + "\n"
|
str += input + "\n"
|
||||||
self.setIndent()
|
self.setIndent()
|
||||||
if indentCount <= 0 {
|
if indentCount <= 0 {
|
||||||
hist := hidepassword(str[:len(str)-1])
|
if mustLogInHistory(str) {
|
||||||
if len(hist) > 0 {
|
self.AppendHistory(str[:len(str)-1])
|
||||||
self.AppendHistory(hist)
|
|
||||||
}
|
}
|
||||||
self.parseInput(str)
|
self.parseInput(str)
|
||||||
str = ""
|
str = ""
|
||||||
@ -425,12 +436,10 @@ func (self *jsre) interactive() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hidepassword(input string) string {
|
func mustLogInHistory(input string) bool {
|
||||||
if passwordRegexp.MatchString(input) {
|
return len(input) == 0 ||
|
||||||
return passwordRepl
|
passwordRegexp.MatchString(input) ||
|
||||||
} else {
|
leadingSpace.MatchString(input)
|
||||||
return input
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *jsre) withHistory(datadir string, op func(*os.File)) {
|
func (self *jsre) withHistory(datadir string, op func(*os.File)) {
|
||||||
|
@ -58,11 +58,6 @@ var (
|
|||||||
gitCommit string // set via linker flagg
|
gitCommit string // set via linker flagg
|
||||||
nodeNameVersion string
|
nodeNameVersion string
|
||||||
app *cli.App
|
app *cli.App
|
||||||
|
|
||||||
ExtraDataFlag = cli.StringFlag{
|
|
||||||
Name: "extradata",
|
|
||||||
Usage: "Extra data for the miner",
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -176,8 +171,12 @@ It is safe to transfer the entire directory or the individual keys therein
|
|||||||
between ethereum nodes by simply copying.
|
between ethereum nodes by simply copying.
|
||||||
Make sure you backup your keys regularly.
|
Make sure you backup your keys regularly.
|
||||||
|
|
||||||
In order to use your account to send transactions, you need to unlock them using the
|
In order to use your account to send transactions, you need to unlock them using
|
||||||
'--unlock' option. The argument is a comma
|
the '--unlock' option. The argument is a space separated list of addresses or
|
||||||
|
indexes. If used non-interactively with a passwordfile, the file should contain
|
||||||
|
the respective passwords one per line. If you unlock n accounts and the password
|
||||||
|
file contains less than n entries, then the last password is meant to apply to
|
||||||
|
all remaining accounts.
|
||||||
|
|
||||||
And finally. DO NOT FORGET YOUR PASSWORD.
|
And finally. DO NOT FORGET YOUR PASSWORD.
|
||||||
`,
|
`,
|
||||||
@ -227,7 +226,7 @@ format to the newest format or change the password for an account.
|
|||||||
|
|
||||||
For non-interactive use the passphrase can be specified with the --password flag:
|
For non-interactive use the passphrase can be specified with the --password flag:
|
||||||
|
|
||||||
ethereum --password <passwordfile> account new
|
ethereum --password <passwordfile> account update <address>
|
||||||
|
|
||||||
Since only one password can be given, only format update can be performed,
|
Since only one password can be given, only format update can be performed,
|
||||||
changing your password is only possible interactively.
|
changing your password is only possible interactively.
|
||||||
@ -354,7 +353,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
|
|||||||
utils.GpobaseStepDownFlag,
|
utils.GpobaseStepDownFlag,
|
||||||
utils.GpobaseStepUpFlag,
|
utils.GpobaseStepUpFlag,
|
||||||
utils.GpobaseCorrectionFactorFlag,
|
utils.GpobaseCorrectionFactorFlag,
|
||||||
ExtraDataFlag,
|
utils.ExtraDataFlag,
|
||||||
}
|
}
|
||||||
app.Before = func(ctx *cli.Context) error {
|
app.Before = func(ctx *cli.Context) error {
|
||||||
utils.SetupLogger(ctx)
|
utils.SetupLogger(ctx)
|
||||||
@ -380,8 +379,8 @@ func main() {
|
|||||||
|
|
||||||
// makeExtra resolves extradata for the miner from a flag or returns a default.
|
// makeExtra resolves extradata for the miner from a flag or returns a default.
|
||||||
func makeExtra(ctx *cli.Context) []byte {
|
func makeExtra(ctx *cli.Context) []byte {
|
||||||
if ctx.GlobalIsSet(ExtraDataFlag.Name) {
|
if ctx.GlobalIsSet(utils.ExtraDataFlag.Name) {
|
||||||
return []byte(ctx.GlobalString(ExtraDataFlag.Name))
|
return []byte(ctx.GlobalString(utils.ExtraDataFlag.Name))
|
||||||
}
|
}
|
||||||
return makeDefaultExtra()
|
return makeDefaultExtra()
|
||||||
}
|
}
|
||||||
@ -517,28 +516,29 @@ func execJSFiles(ctx *cli.Context) {
|
|||||||
ethereum.WaitForShutdown()
|
ethereum.WaitForShutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
func unlockAccount(ctx *cli.Context, am *accounts.Manager, addr string, i int) (addrHex, auth string) {
|
func unlockAccount(ctx *cli.Context, am *accounts.Manager, addr string, i int, inputpassphrases []string) (addrHex, auth string, passphrases []string) {
|
||||||
utils.CheckLegalese(utils.MustDataDir(ctx))
|
utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name))
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
passphrases = inputpassphrases
|
||||||
addrHex, err = utils.ParamToAddress(addr, am)
|
addrHex, err = utils.ParamToAddress(addr, am)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Attempt to unlock the account 3 times
|
// Attempt to unlock the account 3 times
|
||||||
attempts := 3
|
attempts := 3
|
||||||
for tries := 0; tries < attempts; tries++ {
|
for tries := 0; tries < attempts; tries++ {
|
||||||
msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", addr, tries+1, attempts)
|
msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", addr, tries+1, attempts)
|
||||||
auth = getPassPhrase(ctx, msg, false, i)
|
auth, passphrases = getPassPhrase(ctx, msg, false, i, passphrases)
|
||||||
err = am.Unlock(common.HexToAddress(addrHex), auth)
|
err = am.Unlock(common.HexToAddress(addrHex), auth)
|
||||||
if err == nil {
|
if err == nil || passphrases != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Unlock account failed '%v'", err)
|
utils.Fatalf("Unlock account '%s' (%v) failed: %v", addr, addrHex, err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Account '%s' unlocked.\n", addr)
|
fmt.Printf("Account '%s' (%v) unlocked.\n", addr, addrHex)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,12 +582,13 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
|||||||
am := eth.AccountManager()
|
am := eth.AccountManager()
|
||||||
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
|
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
|
||||||
accounts := strings.Split(account, " ")
|
accounts := strings.Split(account, " ")
|
||||||
|
var passphrases []string
|
||||||
for i, account := range accounts {
|
for i, account := range accounts {
|
||||||
if len(account) > 0 {
|
if len(account) > 0 {
|
||||||
if account == "primary" {
|
if account == "primary" {
|
||||||
utils.Fatalf("the 'primary' keyword is deprecated. You can use integer indexes, but the indexes are not permanent, they can change if you add external keys, export your keys or copy your keystore to another node.")
|
utils.Fatalf("the 'primary' keyword is deprecated. You can use integer indexes, but the indexes are not permanent, they can change if you add external keys, export your keys or copy your keystore to another node.")
|
||||||
}
|
}
|
||||||
unlockAccount(ctx, am, account, i)
|
_, _, passphrases = unlockAccount(ctx, am, account, i, passphrases)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Start auxiliary services if enabled.
|
// Start auxiliary services if enabled.
|
||||||
@ -624,7 +625,7 @@ func accountList(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPassPhrase(ctx *cli.Context, desc string, confirmation bool, i int) (passphrase string) {
|
func getPassPhrase(ctx *cli.Context, desc string, confirmation bool, i int, inputpassphrases []string) (passphrase string, passphrases []string) {
|
||||||
passfile := ctx.GlobalString(utils.PasswordFileFlag.Name)
|
passfile := ctx.GlobalString(utils.PasswordFileFlag.Name)
|
||||||
if len(passfile) == 0 {
|
if len(passfile) == 0 {
|
||||||
fmt.Println(desc)
|
fmt.Println(desc)
|
||||||
@ -644,6 +645,8 @@ func getPassPhrase(ctx *cli.Context, desc string, confirmation bool, i int) (pas
|
|||||||
passphrase = auth
|
passphrase = auth
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
passphrases = inputpassphrases
|
||||||
|
if passphrases == nil {
|
||||||
passbytes, err := ioutil.ReadFile(passfile)
|
passbytes, err := ioutil.ReadFile(passfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Unable to read password file '%s': %v", passfile, err)
|
utils.Fatalf("Unable to read password file '%s': %v", passfile, err)
|
||||||
@ -651,7 +654,8 @@ func getPassPhrase(ctx *cli.Context, desc string, confirmation bool, i int) (pas
|
|||||||
// this is backwards compatible if the same password unlocks several accounts
|
// this is backwards compatible if the same password unlocks several accounts
|
||||||
// it also has the consequence that trailing newlines will not count as part
|
// it also has the consequence that trailing newlines will not count as part
|
||||||
// of the password, so --password <(echo -n 'pass') will now work without -n
|
// of the password, so --password <(echo -n 'pass') will now work without -n
|
||||||
passphrases := strings.Split(string(passbytes), "\n")
|
passphrases = strings.Split(string(passbytes), "\n")
|
||||||
|
}
|
||||||
if i >= len(passphrases) {
|
if i >= len(passphrases) {
|
||||||
passphrase = passphrases[len(passphrases)-1]
|
passphrase = passphrases[len(passphrases)-1]
|
||||||
} else {
|
} else {
|
||||||
@ -665,7 +669,7 @@ func accountCreate(ctx *cli.Context) {
|
|||||||
utils.CheckLegalese(utils.MustDataDir(ctx))
|
utils.CheckLegalese(utils.MustDataDir(ctx))
|
||||||
|
|
||||||
am := utils.MakeAccountManager(ctx)
|
am := utils.MakeAccountManager(ctx)
|
||||||
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0)
|
passphrase, _ := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, nil)
|
||||||
acct, err := am.NewAccount(passphrase)
|
acct, err := am.NewAccount(passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Could not create the account: %v", err)
|
utils.Fatalf("Could not create the account: %v", err)
|
||||||
@ -682,8 +686,8 @@ func accountUpdate(ctx *cli.Context) {
|
|||||||
utils.Fatalf("account address or index must be given as argument")
|
utils.Fatalf("account address or index must be given as argument")
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, authFrom := unlockAccount(ctx, am, arg, 0)
|
addr, authFrom, passphrases := unlockAccount(ctx, am, arg, 0, nil)
|
||||||
authTo := getPassPhrase(ctx, "Please give a new password. Do not forget this password.", true, 0)
|
authTo, _ := getPassPhrase(ctx, "Please give a new password. Do not forget this password.", true, 0, passphrases)
|
||||||
err := am.Update(common.HexToAddress(addr), authFrom, authTo)
|
err := am.Update(common.HexToAddress(addr), authFrom, authTo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Could not update the account: %v", err)
|
utils.Fatalf("Could not update the account: %v", err)
|
||||||
@ -703,7 +707,7 @@ func importWallet(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
am := utils.MakeAccountManager(ctx)
|
am := utils.MakeAccountManager(ctx)
|
||||||
passphrase := getPassPhrase(ctx, "", false, 0)
|
passphrase, _ := getPassPhrase(ctx, "", false, 0, nil)
|
||||||
|
|
||||||
acct, err := am.ImportPreSaleKey(keyJson, passphrase)
|
acct, err := am.ImportPreSaleKey(keyJson, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -720,7 +724,7 @@ func accountImport(ctx *cli.Context) {
|
|||||||
utils.Fatalf("keyfile must be given as argument")
|
utils.Fatalf("keyfile must be given as argument")
|
||||||
}
|
}
|
||||||
am := utils.MakeAccountManager(ctx)
|
am := utils.MakeAccountManager(ctx)
|
||||||
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0)
|
passphrase, _ := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, nil)
|
||||||
acct, err := am.Import(keyfile, passphrase)
|
acct, err := am.Import(keyfile, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Could not create the account: %v", err)
|
utils.Fatalf("Could not create the account: %v", err)
|
||||||
|
@ -40,7 +40,9 @@ const (
|
|||||||
importBatchSize = 2500
|
importBatchSize = 2500
|
||||||
)
|
)
|
||||||
|
|
||||||
var interruptCallbacks = []func(os.Signal){}
|
var (
|
||||||
|
interruptCallbacks = []func(os.Signal){}
|
||||||
|
)
|
||||||
|
|
||||||
func openLogFile(Datadir string, filename string) *os.File {
|
func openLogFile(Datadir string, filename string) *os.File {
|
||||||
path := common.AbsolutePath(Datadir, filename)
|
path := common.AbsolutePath(Datadir, filename)
|
||||||
|
@ -183,6 +183,10 @@ var (
|
|||||||
Usage: "Sets the minimal gasprice when mining transactions",
|
Usage: "Sets the minimal gasprice when mining transactions",
|
||||||
Value: new(big.Int).Mul(big.NewInt(50), common.Shannon).String(),
|
Value: new(big.Int).Mul(big.NewInt(50), common.Shannon).String(),
|
||||||
}
|
}
|
||||||
|
ExtraDataFlag = cli.StringFlag{
|
||||||
|
Name: "extradata",
|
||||||
|
Usage: "Extra data for the miner",
|
||||||
|
}
|
||||||
|
|
||||||
UnlockedAccountFlag = cli.StringFlag{
|
UnlockedAccountFlag = cli.StringFlag{
|
||||||
Name: "unlock",
|
Name: "unlock",
|
||||||
@ -345,7 +349,7 @@ var (
|
|||||||
// ATM the url is left to the user and deployment to
|
// ATM the url is left to the user and deployment to
|
||||||
JSpathFlag = cli.StringFlag{
|
JSpathFlag = cli.StringFlag{
|
||||||
Name: "jspath",
|
Name: "jspath",
|
||||||
Usage: "JS library path to be used with console and js subcommands",
|
Usage: "JS root path for loadScript and document root for admin.httpGet",
|
||||||
Value: ".",
|
Value: ".",
|
||||||
}
|
}
|
||||||
SolcPathFlag = cli.StringFlag{
|
SolcPathFlag = cli.StringFlag{
|
||||||
@ -612,7 +616,7 @@ func StartIPC(eth *eth.Ethereum, ctx *cli.Context) error {
|
|||||||
xeth := xeth.New(eth, fe)
|
xeth := xeth.New(eth, fe)
|
||||||
codec := codec.JSON
|
codec := codec.JSON
|
||||||
|
|
||||||
apis, err := api.ParseApiString(ctx.GlobalString(IPCApiFlag.Name), codec, xeth, eth)
|
apis, err := api.ParseApiString(ctx.GlobalString(IPCApiFlag.Name), codec, xeth, eth, ctx.GlobalString(JSpathFlag.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -633,7 +637,7 @@ func StartRPC(eth *eth.Ethereum, ctx *cli.Context) error {
|
|||||||
xeth := xeth.New(eth, nil)
|
xeth := xeth.New(eth, nil)
|
||||||
codec := codec.JSON
|
codec := codec.JSON
|
||||||
|
|
||||||
apis, err := api.ParseApiString(ctx.GlobalString(RpcApiFlag.Name), codec, xeth, eth)
|
apis, err := api.ParseApiString(ctx.GlobalString(RpcApiFlag.Name), codec, xeth, eth, ctx.GlobalString(JSpathFlag.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -95,14 +95,20 @@ func (self *DocServer) Get(uri, path string) (content []byte, err error) {
|
|||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err = ioutil.ReadAll(resp.Body)
|
content, err = ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode/100 != 2 {
|
||||||
|
return content, fmt.Errorf("HTTP error: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
if path != "" {
|
if path != "" {
|
||||||
var abspath string
|
var abspath string
|
||||||
abspath, err = filepath.Abs(path)
|
abspath, err = filepath.Abs(path)
|
||||||
|
@ -21,8 +21,8 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -38,7 +38,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
testAddress = "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
|
||||||
testBalance = "10000000000000000000"
|
testBalance = "10000000000000000000"
|
||||||
|
testKey = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674"
|
||||||
|
|
||||||
testFileName = "long_file_name_for_testing_registration_of_URLs_longer_than_32_bytes.content"
|
testFileName = "long_file_name_for_testing_registration_of_URLs_longer_than_32_bytes.content"
|
||||||
|
|
||||||
@ -48,7 +50,7 @@ const (
|
|||||||
|
|
||||||
testExpNotice2 = `About to submit transaction (NatSpec notice error: abi key does not match any method): {"params":[{"to":"%s","data": "0x31e12c20"}]}`
|
testExpNotice2 = `About to submit transaction (NatSpec notice error: abi key does not match any method): {"params":[{"to":"%s","data": "0x31e12c20"}]}`
|
||||||
|
|
||||||
testExpNotice3 = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x1392c62d05b2d149e22a339c531157ae06b44d39a674cce500064b12b9aeb019'): {"params":[{"to":"%s","data": "0x300a3bbfb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066696c653a2f2f2f746573742e636f6e74656e74"}]}`
|
testExpNotice3 = `About to submit transaction (no NatSpec info found for contract: HashToHash: content hash not found for '0x1392c62d05b2d149e22a339c531157ae06b44d39a674cce500064b12b9aeb019'): {"params":[{"to":"%s","data": "0x300a3bbfb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066696c653a2f2f2f746573742e636f6e74656e74"}]}`
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -100,6 +102,10 @@ type testFrontend struct {
|
|||||||
wantNatSpec bool
|
wantNatSpec bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *testFrontend) AskPassword() (string, bool) {
|
||||||
|
return "", true
|
||||||
|
}
|
||||||
|
|
||||||
func (self *testFrontend) UnlockAccount(acc []byte) bool {
|
func (self *testFrontend) UnlockAccount(acc []byte) bool {
|
||||||
self.ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "password")
|
self.ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "password")
|
||||||
return true
|
return true
|
||||||
@ -115,42 +121,42 @@ func (self *testFrontend) ConfirmTransaction(tx string) bool {
|
|||||||
|
|
||||||
func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
|
func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
|
||||||
|
|
||||||
os.RemoveAll("/tmp/eth-natspec/")
|
tmp, err := ioutil.TempDir("", "natspec-test")
|
||||||
|
|
||||||
err = os.MkdirAll("/tmp/eth-natspec/keystore", os.ModePerm)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
t.Fatal(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")
|
|
||||||
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
// set up mock genesis with balance on the testAddress
|
addr := common.HexToAddress(testAddress)
|
||||||
core.WriteGenesisBlockForTesting(db, core.GenesisAccount{common.HexToAddress(testAddress), common.String2Big(testBalance)})
|
core.WriteGenesisBlockForTesting(db, core.GenesisAccount{addr, common.String2Big(testBalance)})
|
||||||
|
ks := crypto.NewKeyStorePassphrase(filepath.Join(tmp, "keystore"))
|
||||||
|
am := accounts.NewManager(ks)
|
||||||
|
keyb, err := crypto.HexToECDSA(testKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
key := crypto.NewKeyFromECDSA(keyb)
|
||||||
|
err = ks.StoreKey(key, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = am.Unlock(key.Address, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// only use minimalistic stack with no networking
|
// only use minimalistic stack with no networking
|
||||||
ethereum, err = eth.New(ð.Config{
|
return eth.New(ð.Config{
|
||||||
DataDir: "/tmp/eth-natspec",
|
DataDir: tmp,
|
||||||
AccountManager: am,
|
AccountManager: am,
|
||||||
|
Etherbase: common.HexToAddress(testAddress),
|
||||||
MaxPeers: 0,
|
MaxPeers: 0,
|
||||||
PowTest: true,
|
PowTest: true,
|
||||||
Etherbase: common.HexToAddress(testAddress),
|
|
||||||
NewDB: func(path string) (ethdb.Database, error) { return db, nil },
|
NewDB: func(path string) (ethdb.Database, error) { return db, nil },
|
||||||
|
GpoMinGasPrice: common.Big1,
|
||||||
|
GpobaseCorrectionFactor: 1,
|
||||||
|
GpoMaxGasPrice: common.Big1,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInit(t *testing.T) (self *testFrontend) {
|
func testInit(t *testing.T) (self *testFrontend) {
|
||||||
@ -174,36 +180,49 @@ func testInit(t *testing.T) (self *testFrontend) {
|
|||||||
|
|
||||||
// initialise the registry contracts
|
// initialise the registry contracts
|
||||||
reg := registrar.New(self.xeth)
|
reg := registrar.New(self.xeth)
|
||||||
var registrarTxhash, hashRegTxhash, urlHintTxhash string
|
registrar.GlobalRegistrarAddr = "0x0"
|
||||||
registrarTxhash, err = reg.SetGlobalRegistrar("", addr)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("error creating GlobalRegistrar: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hashRegTxhash, err = reg.SetHashReg("", addr)
|
var txG, txH, txU string
|
||||||
|
txG, err = reg.SetGlobalRegistrar("", addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error creating GlobalRegistrar: %v", err)
|
||||||
|
}
|
||||||
|
if !processTxs(self, t, 1) {
|
||||||
|
t.Fatalf("error mining txs")
|
||||||
|
}
|
||||||
|
recG := self.xeth.GetTxReceipt(common.HexToHash(txG))
|
||||||
|
if recG == nil {
|
||||||
|
t.Fatalf("blockchain error creating GlobalRegistrar")
|
||||||
|
}
|
||||||
|
registrar.GlobalRegistrarAddr = recG.ContractAddress.Hex()
|
||||||
|
|
||||||
|
txH, err = reg.SetHashReg("", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error creating HashReg: %v", err)
|
t.Errorf("error creating HashReg: %v", err)
|
||||||
}
|
}
|
||||||
urlHintTxhash, err = reg.SetUrlHint("", addr)
|
if !processTxs(self, t, 1) {
|
||||||
|
t.Errorf("error mining txs")
|
||||||
|
}
|
||||||
|
recH := self.xeth.GetTxReceipt(common.HexToHash(txH))
|
||||||
|
if recH == nil {
|
||||||
|
t.Fatalf("blockchain error creating HashReg")
|
||||||
|
}
|
||||||
|
registrar.HashRegAddr = recH.ContractAddress.Hex()
|
||||||
|
|
||||||
|
txU, err = reg.SetUrlHint("", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error creating UrlHint: %v", err)
|
t.Errorf("error creating UrlHint: %v", err)
|
||||||
}
|
}
|
||||||
if !processTxs(self, t, 3) {
|
if !processTxs(self, t, 1) {
|
||||||
t.Errorf("error mining txs")
|
t.Errorf("error mining txs")
|
||||||
}
|
}
|
||||||
_ = registrarTxhash
|
recU := self.xeth.GetTxReceipt(common.HexToHash(txU))
|
||||||
_ = hashRegTxhash
|
if recU == nil {
|
||||||
_ = urlHintTxhash
|
t.Fatalf("blockchain error creating UrlHint")
|
||||||
|
}
|
||||||
/* TODO:
|
registrar.UrlHintAddr = recU.ContractAddress.Hex()
|
||||||
* 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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// end to end test
|
// end to end test
|
||||||
@ -215,7 +234,7 @@ func TestNatspecE2E(t *testing.T) {
|
|||||||
addr, _ := tf.ethereum.Etherbase()
|
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 HashReg contract itself
|
||||||
ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm)
|
ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm)
|
||||||
dochash := crypto.Sha3Hash([]byte(testContractInfo))
|
dochash := crypto.Sha3Hash([]byte(testContractInfo))
|
||||||
|
|
||||||
@ -223,10 +242,6 @@ func TestNatspecE2E(t *testing.T) {
|
|||||||
codeb := tf.xeth.CodeAtBytes(registrar.HashRegAddr)
|
codeb := tf.xeth.CodeAtBytes(registrar.HashRegAddr)
|
||||||
codehash := crypto.Sha3Hash(codeb)
|
codehash := crypto.Sha3Hash(codeb)
|
||||||
|
|
||||||
// use resolver to register codehash->dochash->url
|
|
||||||
// test if globalregistry works
|
|
||||||
// registrar.HashRefAddr = "0x0"
|
|
||||||
// registrar.UrlHintAddr = "0x0"
|
|
||||||
reg := registrar.New(tf.xeth)
|
reg := registrar.New(tf.xeth)
|
||||||
_, err := reg.SetHashToHash(addr, codehash, dochash)
|
_, err := reg.SetHashToHash(addr, codehash, dochash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -48,17 +48,16 @@ The Registrar uses 3 contracts on the blockchain:
|
|||||||
These contracts are (currently) not included in the genesis block.
|
These contracts are (currently) not included in the genesis block.
|
||||||
Each Set<X> needs to be called once on each blockchain/network once.
|
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
|
Contract addresses need to be set the first time any Registrar method is called
|
||||||
registrar the first time any Registrar method is called in a client session
|
in a client session.
|
||||||
|
This is done for frontier by default, otherwise the caller needs to make sure
|
||||||
So the caller needs to make sure the relevant environment initialised the desired
|
the relevant environment initialised the desired contracts
|
||||||
contracts
|
|
||||||
*/
|
*/
|
||||||
var (
|
var (
|
||||||
UrlHintAddr = "0x0"
|
// GlobalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b" // olympic
|
||||||
HashRegAddr = "0x0"
|
GlobalRegistrarAddr = "0x33990122638b9132ca29c723bdf037f1a891a70c" // frontier
|
||||||
GlobalRegistrarAddr = "0x0"
|
HashRegAddr = "0x23bf622b5a65f6060d855fca401133ded3520620" // frontier
|
||||||
// GlobalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b"
|
UrlHintAddr = "0x73ed5ef6c010727dfd2671dbb70faac19ec18626" // frontier
|
||||||
|
|
||||||
zero = regexp.MustCompile("^(0x)?0*$")
|
zero = regexp.MustCompile("^(0x)?0*$")
|
||||||
)
|
)
|
||||||
@ -113,7 +112,7 @@ func (self *Registrar) SetGlobalRegistrar(namereg string, addr common.Address) (
|
|||||||
GlobalRegistrarAddr = namereg
|
GlobalRegistrarAddr = namereg
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if GlobalRegistrarAddr == "0x0" || GlobalRegistrarAddr == "0x" {
|
if zero.MatchString(GlobalRegistrarAddr) {
|
||||||
if (addr == common.Address{}) {
|
if (addr == common.Address{}) {
|
||||||
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation not given")
|
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation not given")
|
||||||
return
|
return
|
||||||
@ -200,6 +199,9 @@ func (self *Registrar) SetUrlHint(urlhint string, addr common.Address) (txhash s
|
|||||||
// ReserveName(from, name) reserves name for the sender address in the globalRegistrar
|
// ReserveName(from, name) reserves name for the sender address in the globalRegistrar
|
||||||
// the tx needs to be mined to take effect
|
// the tx needs to be mined to take effect
|
||||||
func (self *Registrar) ReserveName(address common.Address, name string) (txh string, err error) {
|
func (self *Registrar) ReserveName(address common.Address, name string) (txh string, err error) {
|
||||||
|
if zero.MatchString(GlobalRegistrarAddr) {
|
||||||
|
return "", fmt.Errorf("GlobalRegistrar address is not set")
|
||||||
|
}
|
||||||
nameHex, extra := encodeName(name, 2)
|
nameHex, extra := encodeName(name, 2)
|
||||||
abi := reserveAbi + nameHex + extra
|
abi := reserveAbi + nameHex + extra
|
||||||
glog.V(logger.Detail).Infof("Reserve data: %s", abi)
|
glog.V(logger.Detail).Infof("Reserve data: %s", abi)
|
||||||
@ -215,6 +217,10 @@ func (self *Registrar) ReserveName(address common.Address, name string) (txh str
|
|||||||
// in the globalRegistrar using from as the sender of the transaction
|
// in the globalRegistrar using from as the sender of the transaction
|
||||||
// the tx needs to be mined to take effect
|
// 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) {
|
func (self *Registrar) SetAddressToName(from common.Address, name string, address common.Address) (txh string, err error) {
|
||||||
|
if zero.MatchString(GlobalRegistrarAddr) {
|
||||||
|
return "", fmt.Errorf("GlobalRegistrar address is not set")
|
||||||
|
}
|
||||||
|
|
||||||
nameHex, extra := encodeName(name, 6)
|
nameHex, extra := encodeName(name, 6)
|
||||||
addrHex := encodeAddress(address)
|
addrHex := encodeAddress(address)
|
||||||
|
|
||||||
@ -231,6 +237,10 @@ func (self *Registrar) SetAddressToName(from common.Address, name string, addres
|
|||||||
|
|
||||||
// NameToAddr(from, name) queries the registrar for the address on name
|
// 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) {
|
func (self *Registrar) NameToAddr(from common.Address, name string) (address common.Address, err error) {
|
||||||
|
if zero.MatchString(GlobalRegistrarAddr) {
|
||||||
|
return address, fmt.Errorf("GlobalRegistrar address is not set")
|
||||||
|
}
|
||||||
|
|
||||||
nameHex, extra := encodeName(name, 2)
|
nameHex, extra := encodeName(name, 2)
|
||||||
abi := resolveAbi + nameHex + extra
|
abi := resolveAbi + nameHex + extra
|
||||||
glog.V(logger.Detail).Infof("NameToAddr data: %s", abi)
|
glog.V(logger.Detail).Infof("NameToAddr data: %s", abi)
|
||||||
@ -249,6 +259,9 @@ func (self *Registrar) NameToAddr(from common.Address, name string) (address com
|
|||||||
|
|
||||||
// called as first step in the registration process on HashReg
|
// called as first step in the registration process on HashReg
|
||||||
func (self *Registrar) SetOwner(address common.Address) (txh string, err error) {
|
func (self *Registrar) SetOwner(address common.Address) (txh string, err error) {
|
||||||
|
if zero.MatchString(HashRegAddr) {
|
||||||
|
return "", fmt.Errorf("HashReg address is not set")
|
||||||
|
}
|
||||||
return self.backend.Transact(
|
return self.backend.Transact(
|
||||||
address.Hex(),
|
address.Hex(),
|
||||||
HashRegAddr,
|
HashRegAddr,
|
||||||
@ -261,6 +274,10 @@ func (self *Registrar) SetOwner(address common.Address) (txh string, err error)
|
|||||||
// e.g., the contract Info combined Json Doc's ContentHash
|
// e.g., the contract Info combined Json Doc's ContentHash
|
||||||
// to CodeHash of a contract or hash of a domain
|
// 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) {
|
func (self *Registrar) SetHashToHash(address common.Address, codehash, dochash common.Hash) (txh string, err error) {
|
||||||
|
if zero.MatchString(HashRegAddr) {
|
||||||
|
return "", fmt.Errorf("HashReg address is not set")
|
||||||
|
}
|
||||||
|
|
||||||
_, err = self.SetOwner(address)
|
_, err = self.SetOwner(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -284,6 +301,10 @@ func (self *Registrar) SetHashToHash(address common.Address, codehash, dochash c
|
|||||||
// FIXME: silently doing nothing if sender is not the owner
|
// FIXME: silently doing nothing if sender is not the owner
|
||||||
// note that with content addressed storage, this step is no longer necessary
|
// 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) {
|
func (self *Registrar) SetUrlToHash(address common.Address, hash common.Hash, url string) (txh string, err error) {
|
||||||
|
if zero.MatchString(UrlHintAddr) {
|
||||||
|
return "", fmt.Errorf("UrlHint address is not set")
|
||||||
|
}
|
||||||
|
|
||||||
hashHex := common.Bytes2Hex(hash[:])
|
hashHex := common.Bytes2Hex(hash[:])
|
||||||
var urlHex string
|
var urlHex string
|
||||||
urlb := []byte(url)
|
urlb := []byte(url)
|
||||||
@ -321,13 +342,17 @@ func (self *Registrar) SetUrlToHash(address common.Address, hash common.Hash, ur
|
|||||||
// resolution is costless non-transactional
|
// resolution is costless non-transactional
|
||||||
// implemented as direct retrieval from db
|
// implemented as direct retrieval from db
|
||||||
func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err error) {
|
func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err error) {
|
||||||
|
if zero.MatchString(HashRegAddr) {
|
||||||
|
return common.Hash{}, fmt.Errorf("HashReg address is not set")
|
||||||
|
}
|
||||||
|
|
||||||
// look up in hashReg
|
// look up in hashReg
|
||||||
at := HashRegAddr[2:]
|
at := HashRegAddr[2:]
|
||||||
key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:]))
|
key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:]))
|
||||||
hash := self.backend.StorageAt(at, key)
|
hash := self.backend.StorageAt(at, key)
|
||||||
|
|
||||||
if hash == "0x0" || len(hash) < 3 || (hash == common.Hash{}.Hex()) {
|
if hash == "0x0" || len(hash) < 3 || (hash == common.Hash{}.Hex()) {
|
||||||
err = fmt.Errorf("content hash not found for '%v'", khash.Hex())
|
err = fmt.Errorf("HashToHash: content hash not found for '%v'", khash.Hex())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
copy(chash[:], common.Hex2BytesFixed(hash[2:], 32))
|
copy(chash[:], common.Hex2BytesFixed(hash[2:], 32))
|
||||||
@ -339,6 +364,9 @@ func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err err
|
|||||||
// implemented as direct retrieval from db
|
// implemented as direct retrieval from db
|
||||||
// if we use content addressed storage, this step is no longer necessary
|
// if we use content addressed storage, this step is no longer necessary
|
||||||
func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) {
|
func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) {
|
||||||
|
if zero.MatchString(UrlHintAddr) {
|
||||||
|
return "", fmt.Errorf("UrlHint address is not set")
|
||||||
|
}
|
||||||
// look up in URL reg
|
// look up in URL reg
|
||||||
var str string = " "
|
var str string = " "
|
||||||
var idx uint32
|
var idx uint32
|
||||||
@ -358,7 +386,7 @@ func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(uri) == 0 {
|
if len(uri) == 0 {
|
||||||
err = fmt.Errorf("GetURLhint: URL hint not found for '%v'", chash.Hex())
|
err = fmt.Errorf("HashToUrl: URL hint not found for '%v'", chash.Hex())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -36,29 +36,31 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func NewTestBackend() *testBackend {
|
func NewTestBackend() *testBackend {
|
||||||
HashRegAddr = common.BigToAddress(common.Big0).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))
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *testBackend) initHashReg() {
|
||||||
self.contracts[HashRegAddr[2:]] = 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[HashRegAddr[2:]][key] = hash.Hex()
|
self.contracts[HashRegAddr[2:]][key] = hash.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *testBackend) initUrlHint() {
|
||||||
self.contracts[UrlHintAddr[2:]] = 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[UrlHintAddr[2:]][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[UrlHintAddr[2:]][key] = "0x0"
|
self.contracts[UrlHintAddr[2:]][key] = "0x0"
|
||||||
return self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testBackend) StorageAt(ca, sa string) (res string) {
|
func (self *testBackend) StorageAt(ca, sa string) (res string) {
|
||||||
c := self.contracts[ca]
|
c := self.contracts[ca]
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return
|
return "0x0"
|
||||||
}
|
}
|
||||||
res = c[sa]
|
res = c[sa]
|
||||||
return
|
return
|
||||||
@ -84,9 +86,31 @@ func TestSetGlobalRegistrar(t *testing.T) {
|
|||||||
func TestHashToHash(t *testing.T) {
|
func TestHashToHash(t *testing.T) {
|
||||||
b := NewTestBackend()
|
b := NewTestBackend()
|
||||||
res := New(b)
|
res := New(b)
|
||||||
// res.SetHashReg()
|
|
||||||
|
|
||||||
|
HashRegAddr = "0x0"
|
||||||
got, err := res.HashToHash(codehash)
|
got, err := res.HashToHash(codehash)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected error")
|
||||||
|
} else {
|
||||||
|
exp := "HashReg address is not set"
|
||||||
|
if err.Error() != exp {
|
||||||
|
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HashRegAddr = common.BigToAddress(common.Big1).Hex() //[2:]
|
||||||
|
got, err = res.HashToHash(codehash)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected error")
|
||||||
|
} else {
|
||||||
|
exp := "HashToHash: content hash not found for '" + codehash.Hex() + "'"
|
||||||
|
if err.Error() != exp {
|
||||||
|
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.initHashReg()
|
||||||
|
got, err = res.HashToHash(codehash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expected no error, got %v", err)
|
t.Errorf("expected no error, got %v", err)
|
||||||
} else {
|
} else {
|
||||||
@ -99,11 +123,33 @@ func TestHashToHash(t *testing.T) {
|
|||||||
func TestHashToUrl(t *testing.T) {
|
func TestHashToUrl(t *testing.T) {
|
||||||
b := NewTestBackend()
|
b := NewTestBackend()
|
||||||
res := New(b)
|
res := New(b)
|
||||||
// res.SetUrlHint()
|
|
||||||
|
|
||||||
|
UrlHintAddr = "0x0"
|
||||||
got, err := res.HashToUrl(hash)
|
got, err := res.HashToUrl(hash)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected error")
|
||||||
|
} else {
|
||||||
|
exp := "UrlHint address is not set"
|
||||||
|
if err.Error() != exp {
|
||||||
|
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UrlHintAddr = common.BigToAddress(common.Big2).Hex() //[2:]
|
||||||
|
got, err = res.HashToUrl(hash)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected error")
|
||||||
|
} else {
|
||||||
|
exp := "HashToUrl: URL hint not found for '" + hash.Hex() + "'"
|
||||||
|
if err.Error() != exp {
|
||||||
|
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.initUrlHint()
|
||||||
|
got, err = res.HashToUrl(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expected error, got %v", err)
|
t.Errorf("expected no 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)
|
||||||
|
@ -261,6 +261,9 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
|
|||||||
passBytes := []byte(password)
|
passBytes := []byte(password)
|
||||||
derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
|
derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
|
||||||
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
|
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
ethPriv := Sha3(plainText)
|
ethPriv := Sha3(plainText)
|
||||||
ecKey := ToECDSA(ethPriv)
|
ecKey := ToECDSA(ethPriv)
|
||||||
key = &Key{
|
key = &Key{
|
||||||
@ -271,7 +274,7 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
|
|||||||
derivedAddr := hex.EncodeToString(key.Address.Bytes()) // needed because .Hex() gives leading "0x"
|
derivedAddr := hex.EncodeToString(key.Address.Bytes()) // needed because .Hex() gives leading "0x"
|
||||||
expectedAddr := preSaleKeyStruct.EthAddr
|
expectedAddr := preSaleKeyStruct.EthAddr
|
||||||
if derivedAddr != expectedAddr {
|
if derivedAddr != expectedAddr {
|
||||||
err = errors.New(fmt.Sprintf("decrypted addr not equal to expected addr ", derivedAddr, expectedAddr))
|
err = fmt.Errorf("decrypted addr '%s' not equal to expected addr '%s'", derivedAddr, expectedAddr)
|
||||||
}
|
}
|
||||||
return key, err
|
return key, err
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,9 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/ethash"
|
"github.com/ethereum/ethash"
|
||||||
@ -62,6 +64,9 @@ const (
|
|||||||
var (
|
var (
|
||||||
jsonlogger = logger.NewJsonLogger()
|
jsonlogger = logger.NewJsonLogger()
|
||||||
|
|
||||||
|
datadirInUseErrNos = []uint{11, 32, 35}
|
||||||
|
portInUseErrRE = regexp.MustCompile("address already in use")
|
||||||
|
|
||||||
defaultBootNodes = []*discover.Node{
|
defaultBootNodes = []*discover.Node{
|
||||||
// ETH/DEV Go Bootnodes
|
// ETH/DEV Go Bootnodes
|
||||||
discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE
|
discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE
|
||||||
@ -282,6 +287,17 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
// Open the chain database and perform any upgrades needed
|
// Open the chain database and perform any upgrades needed
|
||||||
chainDb, err := newdb(filepath.Join(config.DataDir, "chaindata"))
|
chainDb, err := newdb(filepath.Join(config.DataDir, "chaindata"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
var ok bool
|
||||||
|
errno := uint(err.(syscall.Errno))
|
||||||
|
for _, no := range datadirInUseErrNos {
|
||||||
|
if errno == no {
|
||||||
|
ok = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
err = fmt.Errorf("%v (check if another instance of geth is already running with the same data directory '%s')", err, config.DataDir)
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("blockchain db err: %v", err)
|
return nil, fmt.Errorf("blockchain db err: %v", err)
|
||||||
}
|
}
|
||||||
if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
|
if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
|
||||||
@ -296,6 +312,16 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
|
|
||||||
dappDb, err := newdb(filepath.Join(config.DataDir, "dapp"))
|
dappDb, err := newdb(filepath.Join(config.DataDir, "dapp"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
var ok bool
|
||||||
|
for _, no := range datadirInUseErrNos {
|
||||||
|
if uint(err.(syscall.Errno)) == no {
|
||||||
|
ok = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
err = fmt.Errorf("%v (check if another instance of geth is already running with the same data directory '%s')", err, config.DataDir)
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("dapp db err: %v", err)
|
return nil, fmt.Errorf("dapp db err: %v", err)
|
||||||
}
|
}
|
||||||
if db, ok := dappDb.(*ethdb.LDBDatabase); ok {
|
if db, ok := dappDb.(*ethdb.LDBDatabase); ok {
|
||||||
@ -553,6 +579,9 @@ func (s *Ethereum) Start() error {
|
|||||||
})
|
})
|
||||||
err := s.net.Start()
|
err := s.net.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if portInUseErrRE.MatchString(err.Error()) {
|
||||||
|
err = fmt.Errorf("%v (possibly another instance of geth is using the same port)", err)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,17 +84,19 @@ type adminApi struct {
|
|||||||
ethereum *eth.Ethereum
|
ethereum *eth.Ethereum
|
||||||
codec codec.Codec
|
codec codec.Codec
|
||||||
coder codec.ApiCoder
|
coder codec.ApiCoder
|
||||||
|
docRoot string
|
||||||
ds *docserver.DocServer
|
ds *docserver.DocServer
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a new admin api instance
|
// create a new admin api instance
|
||||||
func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, codec codec.Codec) *adminApi {
|
func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, codec codec.Codec, docRoot string) *adminApi {
|
||||||
return &adminApi{
|
return &adminApi{
|
||||||
xeth: xeth,
|
xeth: xeth,
|
||||||
ethereum: ethereum,
|
ethereum: ethereum,
|
||||||
codec: codec,
|
codec: codec,
|
||||||
coder: codec.New(nil),
|
coder: codec.New(nil),
|
||||||
ds: docserver.New("/"),
|
docRoot: docRoot,
|
||||||
|
ds: docserver.New(docRoot),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +258,7 @@ func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) {
|
|||||||
CorsDomain: args.CorsDomain,
|
CorsDomain: args.CorsDomain,
|
||||||
}
|
}
|
||||||
|
|
||||||
apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.ethereum)
|
apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.ethereum, self.docRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestParseApiString(t *testing.T) {
|
func TestParseApiString(t *testing.T) {
|
||||||
apis, err := ParseApiString("", codec.JSON, nil, nil)
|
apis, err := ParseApiString("", codec.JSON, nil, nil, "")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an err from parsing empty API string but got nil")
|
t.Errorf("Expected an err from parsing empty API string but got nil")
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ func TestParseApiString(t *testing.T) {
|
|||||||
t.Errorf("Expected 0 apis from empty API string")
|
t.Errorf("Expected 0 apis from empty API string")
|
||||||
}
|
}
|
||||||
|
|
||||||
apis, err = ParseApiString("eth", codec.JSON, nil, nil)
|
apis, err = ParseApiString("eth", codec.JSON, nil, nil, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected nil err from parsing empty API string but got %v", err)
|
t.Errorf("Expected nil err from parsing empty API string but got %v", err)
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ func TestParseApiString(t *testing.T) {
|
|||||||
t.Errorf("Expected 1 apis but got %d - %v", apis, apis)
|
t.Errorf("Expected 1 apis but got %d - %v", apis, apis)
|
||||||
}
|
}
|
||||||
|
|
||||||
apis, err = ParseApiString("eth,eth", codec.JSON, nil, nil)
|
apis, err = ParseApiString("eth,eth", codec.JSON, nil, nil, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected nil err from parsing empty API string but got \"%v\"", err)
|
t.Errorf("Expected nil err from parsing empty API string but got \"%v\"", err)
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ func TestParseApiString(t *testing.T) {
|
|||||||
t.Errorf("Expected 2 apis but got %d - %v", apis, apis)
|
t.Errorf("Expected 2 apis but got %d - %v", apis, apis)
|
||||||
}
|
}
|
||||||
|
|
||||||
apis, err = ParseApiString("eth,invalid", codec.JSON, nil, nil)
|
apis, err = ParseApiString("eth,invalid", codec.JSON, nil, nil, "")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an err but got no err")
|
t.Errorf("Expected an err but got no err")
|
||||||
}
|
}
|
||||||
|
@ -98,9 +98,22 @@ func (self *personalApi) NewAccount(req *shared.Request) (interface{}, error) {
|
|||||||
if err := self.codec.Decode(req.Params, &args); err != nil {
|
if err := self.codec.Decode(req.Params, &args); err != nil {
|
||||||
return nil, shared.NewDecodeParamError(err.Error())
|
return nil, shared.NewDecodeParamError(err.Error())
|
||||||
}
|
}
|
||||||
|
var passwd string
|
||||||
|
if args.Passphrase == nil {
|
||||||
|
fe := self.xeth.Frontend()
|
||||||
|
if fe == nil {
|
||||||
|
return false, fmt.Errorf("unable to create account: unable to interact with user")
|
||||||
|
}
|
||||||
|
var ok bool
|
||||||
|
passwd, ok = fe.AskPassword()
|
||||||
|
if !ok {
|
||||||
|
return false, fmt.Errorf("unable to create account: no password given")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
passwd = *args.Passphrase
|
||||||
|
}
|
||||||
am := self.ethereum.AccountManager()
|
am := self.ethereum.AccountManager()
|
||||||
acc, err := am.NewAccount(args.Passphrase)
|
acc, err := am.NewAccount(passwd)
|
||||||
return acc.Address.Hex(), err
|
return acc.Address.Hex(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type NewAccountArgs struct {
|
type NewAccountArgs struct {
|
||||||
Passphrase string
|
Passphrase *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (args *NewAccountArgs) UnmarshalJSON(b []byte) (err error) {
|
func (args *NewAccountArgs) UnmarshalJSON(b []byte) (err error) {
|
||||||
@ -32,18 +32,17 @@ func (args *NewAccountArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
return shared.NewDecodeParamError(err.Error())
|
return shared.NewDecodeParamError(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(obj) < 1 {
|
if len(obj) >= 1 && obj[0] != nil {
|
||||||
return shared.NewInsufficientParamsError(len(obj), 1)
|
if passphrasestr, ok := obj[0].(string); ok {
|
||||||
|
args.Passphrase = &passphrasestr
|
||||||
|
} else {
|
||||||
|
return shared.NewInvalidTypeError("passphrase", "not a string")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if passhrase, ok := obj[0].(string); ok {
|
|
||||||
args.Passphrase = passhrase
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return shared.NewInvalidTypeError("passhrase", "not a string")
|
|
||||||
}
|
|
||||||
|
|
||||||
type UnlockAccountArgs struct {
|
type UnlockAccountArgs struct {
|
||||||
Address string
|
Address string
|
||||||
Passphrase *string
|
Passphrase *string
|
||||||
|
@ -33,14 +33,21 @@ var (
|
|||||||
"admin": []string{
|
"admin": []string{
|
||||||
"addPeer",
|
"addPeer",
|
||||||
"datadir",
|
"datadir",
|
||||||
|
"enableUserAgent",
|
||||||
"exportChain",
|
"exportChain",
|
||||||
"getContractInfo",
|
"getContractInfo",
|
||||||
|
"httpGet",
|
||||||
"importChain",
|
"importChain",
|
||||||
"nodeInfo",
|
"nodeInfo",
|
||||||
"peers",
|
"peers",
|
||||||
"register",
|
"register",
|
||||||
"registerUrl",
|
"registerUrl",
|
||||||
|
"saveInfo",
|
||||||
|
"setGlobalRegistrar",
|
||||||
|
"setHashReg",
|
||||||
|
"setUrlHint",
|
||||||
"setSolc",
|
"setSolc",
|
||||||
|
"sleep",
|
||||||
"sleepBlocks",
|
"sleepBlocks",
|
||||||
"startNatSpec",
|
"startNatSpec",
|
||||||
"startRPC",
|
"startRPC",
|
||||||
@ -146,7 +153,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Parse a comma separated API string to individual api's
|
// Parse a comma separated API string to individual api's
|
||||||
func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.Ethereum) ([]shared.EthereumApi, error) {
|
func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.Ethereum, docRoot string) ([]shared.EthereumApi, error) {
|
||||||
if len(strings.TrimSpace(apistr)) == 0 {
|
if len(strings.TrimSpace(apistr)) == 0 {
|
||||||
return nil, fmt.Errorf("Empty apistr provided")
|
return nil, fmt.Errorf("Empty apistr provided")
|
||||||
}
|
}
|
||||||
@ -157,7 +164,7 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
|
|||||||
for i, name := range names {
|
for i, name := range names {
|
||||||
switch strings.ToLower(strings.TrimSpace(name)) {
|
switch strings.ToLower(strings.TrimSpace(name)) {
|
||||||
case shared.AdminApiName:
|
case shared.AdminApiName:
|
||||||
apis[i] = NewAdminApi(xeth, eth, codec)
|
apis[i] = NewAdminApi(xeth, eth, codec, docRoot)
|
||||||
case shared.DebugApiName:
|
case shared.DebugApiName:
|
||||||
apis[i] = NewDebugApi(xeth, eth, codec)
|
apis[i] = NewDebugApi(xeth, eth, codec)
|
||||||
case shared.DbApiName:
|
case shared.DbApiName:
|
||||||
|
@ -158,11 +158,11 @@ func (self *Jeth) askPassword(id interface{}, jsonrpc string, args []interface{}
|
|||||||
if len(args) >= 1 {
|
if len(args) >= 1 {
|
||||||
if account, ok := args[0].(string); ok {
|
if account, ok := args[0].(string); ok {
|
||||||
fmt.Printf("Unlock account %s\n", account)
|
fmt.Printf("Unlock account %s\n", account)
|
||||||
passwd, err = utils.PromptPassword("Passphrase: ", true)
|
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
passwd, err = utils.PromptPassword("Passphrase: ", true)
|
||||||
|
|
||||||
if err = self.client.Send(shared.NewRpcResponse(id, jsonrpc, passwd, err)); err != nil {
|
if err = self.client.Send(shared.NewRpcResponse(id, jsonrpc, passwd, err)); err != nil {
|
||||||
glog.V(logger.Info).Infof("Unable to send user agent ask password response - %v\n", err)
|
glog.V(logger.Info).Infof("Unable to send user agent ask password response - %v\n", err)
|
||||||
|
@ -49,6 +49,31 @@ func (fe *RemoteFrontend) Enable() {
|
|||||||
fe.enabled = true
|
fe.enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fe *RemoteFrontend) AskPassword() (string, bool) {
|
||||||
|
if !fe.enabled {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
err := fe.send(AskPasswordMethod)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Unable to send password request to agent - %v\n", err)
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
passwdRes, err := fe.recv()
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Unable to recv password response from agent - %v\n", err)
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
if passwd, ok := passwdRes.Result.(string); ok {
|
||||||
|
return passwd, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// UnlockAccount asks the user agent for the user password and tries to unlock the account.
|
// UnlockAccount asks the user agent for the user password and tries to unlock the account.
|
||||||
// It will try 3 attempts before giving up.
|
// It will try 3 attempts before giving up.
|
||||||
func (fe *RemoteFrontend) UnlockAccount(address []byte) bool {
|
func (fe *RemoteFrontend) UnlockAccount(address []byte) bool {
|
||||||
|
@ -19,6 +19,9 @@ package xeth
|
|||||||
// Frontend should be implemented by users of XEth. Its methods are
|
// Frontend should be implemented by users of XEth. Its methods are
|
||||||
// called whenever XEth makes a decision that requires user input.
|
// called whenever XEth makes a decision that requires user input.
|
||||||
type Frontend interface {
|
type Frontend interface {
|
||||||
|
// AskPassword is called when a new account is created or updated
|
||||||
|
AskPassword() (string, bool)
|
||||||
|
|
||||||
// UnlockAccount is called when a transaction needs to be signed
|
// UnlockAccount is called when a transaction needs to be signed
|
||||||
// but the key corresponding to the transaction's sender is
|
// but the key corresponding to the transaction's sender is
|
||||||
// locked.
|
// locked.
|
||||||
@ -40,5 +43,6 @@ type Frontend interface {
|
|||||||
// transactions but cannot not unlock any keys.
|
// transactions but cannot not unlock any keys.
|
||||||
type dummyFrontend struct{}
|
type dummyFrontend struct{}
|
||||||
|
|
||||||
|
func (dummyFrontend) AskPassword() (string, bool) { return "", false }
|
||||||
func (dummyFrontend) UnlockAccount([]byte) bool { return false }
|
func (dummyFrontend) UnlockAccount([]byte) bool { return false }
|
||||||
func (dummyFrontend) ConfirmTransaction(string) bool { return true }
|
func (dummyFrontend) ConfirmTransaction(string) bool { return true }
|
||||||
|
Loading…
Reference in New Issue
Block a user