forked from cerc-io/plugeth
Merge branch 'rpcfrontier' of github.com:ethereum/go-ethereum into rpcfrontier
This commit is contained in:
commit
6bca40274f
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -17,8 +17,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/codegangsta/cli",
|
"ImportPath": "github.com/codegangsta/cli",
|
||||||
"Comment": "1.2.0-74-g50c77ec",
|
"Comment": "1.2.0-81-g3e09053",
|
||||||
"Rev": "50c77ecec0068c9aef9d90ae0fd0fdf410041da3"
|
"Rev": "3e0905345cd2c5366530dbcdce62457f2ce16e7c"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/ethereum/ethash",
|
"ImportPath": "github.com/ethereum/ethash",
|
||||||
|
31
Godeps/_workspace/src/github.com/codegangsta/cli/app.go
generated
vendored
31
Godeps/_workspace/src/github.com/codegangsta/cli/app.go
generated
vendored
@ -43,9 +43,11 @@ type App struct {
|
|||||||
CommandNotFound func(context *Context, command string)
|
CommandNotFound func(context *Context, command string)
|
||||||
// Compilation date
|
// Compilation date
|
||||||
Compiled time.Time
|
Compiled time.Time
|
||||||
// Author
|
// List of all authors who contributed
|
||||||
|
Authors []Author
|
||||||
|
// Name of Author (Note: Use App.Authors, this is deprecated)
|
||||||
Author string
|
Author string
|
||||||
// Author e-mail
|
// Email of Author (Note: Use App.Authors, this is deprecated)
|
||||||
Email string
|
Email string
|
||||||
// Writer writer to write output to
|
// Writer writer to write output to
|
||||||
Writer io.Writer
|
Writer io.Writer
|
||||||
@ -70,14 +72,19 @@ func NewApp() *App {
|
|||||||
BashComplete: DefaultAppComplete,
|
BashComplete: DefaultAppComplete,
|
||||||
Action: helpCommand.Action,
|
Action: helpCommand.Action,
|
||||||
Compiled: compileTime(),
|
Compiled: compileTime(),
|
||||||
Author: "Author",
|
Author: "Dr. James",
|
||||||
Email: "unknown@email",
|
Email: "who@gmail.com",
|
||||||
|
Authors: []Author{{"Jim", "jim@corporate.com"}, {"Hank", "hank@indiepalace.com"}},
|
||||||
Writer: os.Stdout,
|
Writer: os.Stdout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
|
// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
|
||||||
func (a *App) Run(arguments []string) (err error) {
|
func (a *App) Run(arguments []string) (err error) {
|
||||||
|
if a.Author != "" && a.Author != "" {
|
||||||
|
a.Authors = append(a.Authors, Author{a.Author, a.Email})
|
||||||
|
}
|
||||||
|
|
||||||
if HelpPrinter == nil {
|
if HelpPrinter == nil {
|
||||||
defer func() {
|
defer func() {
|
||||||
HelpPrinter = nil
|
HelpPrinter = nil
|
||||||
@ -294,3 +301,19 @@ func (a *App) appendFlag(flag Flag) {
|
|||||||
a.Flags = append(a.Flags, flag)
|
a.Flags = append(a.Flags, flag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Author represents someone who has contributed to a cli project.
|
||||||
|
type Author struct {
|
||||||
|
Name string // The Authors name
|
||||||
|
Email string // The Authors email
|
||||||
|
}
|
||||||
|
|
||||||
|
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
|
||||||
|
func (a Author) String() string {
|
||||||
|
e := ""
|
||||||
|
if a.Email != "" {
|
||||||
|
e = "<" + a.Email + "> "
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%v %v", a.Name, e)
|
||||||
|
}
|
||||||
|
3
Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go
generated
vendored
3
Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go
generated
vendored
@ -21,6 +21,9 @@ func ExampleApp() {
|
|||||||
app.Action = func(c *cli.Context) {
|
app.Action = func(c *cli.Context) {
|
||||||
fmt.Printf("Hello %v\n", c.String("name"))
|
fmt.Printf("Hello %v\n", c.String("name"))
|
||||||
}
|
}
|
||||||
|
app.Author = "Harrison"
|
||||||
|
app.Email = "harrison@lolwut.com"
|
||||||
|
app.Authors = []cli.Author{{"Oliver Allen", "oliver@toyshop.com"}}
|
||||||
app.Run(os.Args)
|
app.Run(os.Args)
|
||||||
// Output:
|
// Output:
|
||||||
// Hello Jeremy
|
// Hello Jeremy
|
||||||
|
2
Godeps/_workspace/src/github.com/codegangsta/cli/command.go
generated
vendored
2
Godeps/_workspace/src/github.com/codegangsta/cli/command.go
generated
vendored
@ -119,7 +119,7 @@ func (c Command) Run(ctx *Context) error {
|
|||||||
|
|
||||||
// Returns true if Command.Name or Command.ShortName matches given name
|
// Returns true if Command.Name or Command.ShortName matches given name
|
||||||
func (c Command) HasName(name string) bool {
|
func (c Command) HasName(name string) bool {
|
||||||
return c.Name == name || c.ShortName == name
|
return c.Name == name || (c.ShortName != "" && c.ShortName == name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Command) startApp(ctx *Context) error {
|
func (c Command) startApp(ctx *Context) error {
|
||||||
|
13
Godeps/_workspace/src/github.com/codegangsta/cli/help.go
generated
vendored
13
Godeps/_workspace/src/github.com/codegangsta/cli/help.go
generated
vendored
@ -12,11 +12,10 @@ USAGE:
|
|||||||
{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
|
{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
|
||||||
|
|
||||||
VERSION:
|
VERSION:
|
||||||
{{.Version}}{{if or .Author .Email}}
|
{{.Version}}
|
||||||
|
|
||||||
AUTHOR:{{if .Author}}
|
AUTHOR(S):
|
||||||
{{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
|
{{range .Authors}}{{ . }} {{end}}
|
||||||
{{.Email}}{{end}}{{end}}
|
|
||||||
|
|
||||||
COMMANDS:
|
COMMANDS:
|
||||||
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
|
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
|
||||||
@ -112,6 +111,12 @@ func DefaultAppComplete(c *Context) {
|
|||||||
|
|
||||||
// Prints help for the given command
|
// Prints help for the given command
|
||||||
func ShowCommandHelp(c *Context, command string) {
|
func ShowCommandHelp(c *Context, command string) {
|
||||||
|
// show the subcommand help for a command with subcommands
|
||||||
|
if command == "" {
|
||||||
|
HelpPrinter(SubcommandHelpTemplate, c.App)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, c := range c.App.Commands {
|
for _, c := range c.App.Commands {
|
||||||
if c.HasName(command) {
|
if c.HasName(command) {
|
||||||
HelpPrinter(CommandHelpTemplate, c)
|
HelpPrinter(CommandHelpTemplate, c)
|
||||||
|
@ -33,7 +33,10 @@ and accounts persistence is derived from stored keys' addresses
|
|||||||
package accounts
|
package accounts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/ecdsa"
|
||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
|
"os"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
@ -42,77 +45,117 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrLocked = errors.New("account is locked; please request passphrase")
|
var (
|
||||||
|
ErrLocked = errors.New("account is locked")
|
||||||
|
ErrNoKeys = errors.New("no keys in store")
|
||||||
|
)
|
||||||
|
|
||||||
// TODO: better name for this struct?
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Address []byte
|
Address []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccountManager struct {
|
type Manager struct {
|
||||||
keyStore crypto.KeyStore2
|
keyStore crypto.KeyStore2
|
||||||
unlockedKeys map[string]crypto.Key
|
unlocked map[string]*unlocked
|
||||||
unlockMilliseconds time.Duration
|
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAccountManager(keyStore crypto.KeyStore2, unlockMilliseconds time.Duration) AccountManager {
|
type unlocked struct {
|
||||||
keysMap := make(map[string]crypto.Key)
|
*crypto.Key
|
||||||
am := &AccountManager{
|
abort chan struct{}
|
||||||
keyStore: keyStore,
|
|
||||||
unlockedKeys: keysMap,
|
|
||||||
unlockMilliseconds: unlockMilliseconds,
|
|
||||||
}
|
|
||||||
return *am
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am AccountManager) DeleteAccount(address []byte, auth string) error {
|
func NewManager(keyStore crypto.KeyStore2) *Manager {
|
||||||
|
return &Manager{
|
||||||
|
keyStore: keyStore,
|
||||||
|
unlocked: make(map[string]*unlocked),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am *Manager) HasAccount(addr []byte) bool {
|
||||||
|
accounts, _ := am.Accounts()
|
||||||
|
for _, acct := range accounts {
|
||||||
|
if bytes.Compare(acct.Address, addr) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coinbase returns the account address that mining rewards are sent to.
|
||||||
|
func (am *Manager) Coinbase() (addr []byte, err error) {
|
||||||
|
// TODO: persist coinbase address on disk
|
||||||
|
return am.firstAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am *Manager) firstAddr() ([]byte, error) {
|
||||||
|
addrs, err := am.keyStore.GetKeyAddresses()
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil, ErrNoKeys
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(addrs) == 0 {
|
||||||
|
return nil, ErrNoKeys
|
||||||
|
}
|
||||||
|
return addrs[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am *Manager) DeleteAccount(address []byte, auth string) error {
|
||||||
return am.keyStore.DeleteKey(address, auth)
|
return am.keyStore.DeleteKey(address, auth)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *AccountManager) Sign(fromAccount *Account, toSign []byte) (signature []byte, err error) {
|
func (am *Manager) Sign(a Account, toSign []byte) (signature []byte, err error) {
|
||||||
am.mutex.RLock()
|
am.mutex.RLock()
|
||||||
unlockedKey := am.unlockedKeys[string(fromAccount.Address)]
|
unlockedKey, found := am.unlocked[string(a.Address)]
|
||||||
am.mutex.RUnlock()
|
am.mutex.RUnlock()
|
||||||
if unlockedKey.Address == nil {
|
if !found {
|
||||||
return nil, ErrLocked
|
return nil, ErrLocked
|
||||||
}
|
}
|
||||||
signature, err = crypto.Sign(toSign, unlockedKey.PrivateKey)
|
signature, err = crypto.Sign(toSign, unlockedKey.PrivateKey)
|
||||||
return signature, err
|
return signature, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *AccountManager) SignLocked(fromAccount *Account, keyAuth string, toSign []byte) (signature []byte, err error) {
|
// TimedUnlock unlocks the account with the given address.
|
||||||
key, err := am.keyStore.GetKey(fromAccount.Address, keyAuth)
|
// When timeout has passed, the account will be locked again.
|
||||||
|
func (am *Manager) TimedUnlock(addr []byte, keyAuth string, timeout time.Duration) error {
|
||||||
|
key, err := am.keyStore.GetKey(addr, keyAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
am.mutex.RLock()
|
u := am.addUnlocked(addr, key)
|
||||||
am.unlockedKeys[string(fromAccount.Address)] = *key
|
go am.dropLater(addr, u, timeout)
|
||||||
am.mutex.RUnlock()
|
return nil
|
||||||
go unlockLater(am, fromAccount.Address)
|
|
||||||
signature, err = crypto.Sign(toSign, key.PrivateKey)
|
|
||||||
return signature, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am AccountManager) NewAccount(auth string) (*Account, error) {
|
// Unlock unlocks the account with the given address. The account
|
||||||
|
// stays unlocked until the program exits or until a TimedUnlock
|
||||||
|
// timeout (started after the call to Unlock) expires.
|
||||||
|
func (am *Manager) Unlock(addr []byte, keyAuth string) error {
|
||||||
|
key, err := am.keyStore.GetKey(addr, keyAuth)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
am.addUnlocked(addr, key)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am *Manager) NewAccount(auth string) (Account, error) {
|
||||||
key, err := am.keyStore.GenerateNewKey(crand.Reader, auth)
|
key, err := am.keyStore.GenerateNewKey(crand.Reader, auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return Account{}, err
|
||||||
}
|
}
|
||||||
ua := &Account{
|
return Account{Address: key.Address}, nil
|
||||||
Address: key.Address,
|
|
||||||
}
|
|
||||||
return ua, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *AccountManager) Accounts() ([]Account, error) {
|
func (am *Manager) Accounts() ([]Account, error) {
|
||||||
addresses, err := am.keyStore.GetKeyAddresses()
|
addresses, err := am.keyStore.GetKeyAddresses()
|
||||||
if err != nil {
|
if os.IsNotExist(err) {
|
||||||
|
return nil, ErrNoKeys
|
||||||
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
accounts := make([]Account, len(addresses))
|
accounts := make([]Account, len(addresses))
|
||||||
|
|
||||||
for i, addr := range addresses {
|
for i, addr := range addresses {
|
||||||
accounts[i] = Account{
|
accounts[i] = Account{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
@ -121,12 +164,47 @@ func (am *AccountManager) Accounts() ([]Account, error) {
|
|||||||
return accounts, err
|
return accounts, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func unlockLater(am *AccountManager, addr []byte) {
|
func (am *Manager) addUnlocked(addr []byte, key *crypto.Key) *unlocked {
|
||||||
|
u := &unlocked{Key: key, abort: make(chan struct{})}
|
||||||
|
am.mutex.Lock()
|
||||||
|
prev, found := am.unlocked[string(addr)]
|
||||||
|
if found {
|
||||||
|
// terminate dropLater for this key to avoid unexpected drops.
|
||||||
|
close(prev.abort)
|
||||||
|
// the key is zeroed here instead of in dropLater because
|
||||||
|
// there might not actually be a dropLater running for this
|
||||||
|
// key, i.e. when Unlock was used.
|
||||||
|
zeroKey(prev.PrivateKey)
|
||||||
|
}
|
||||||
|
am.unlocked[string(addr)] = u
|
||||||
|
am.mutex.Unlock()
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am *Manager) dropLater(addr []byte, u *unlocked, timeout time.Duration) {
|
||||||
|
t := time.NewTimer(timeout)
|
||||||
|
defer t.Stop()
|
||||||
select {
|
select {
|
||||||
case <-time.After(time.Millisecond * am.unlockMilliseconds):
|
case <-u.abort:
|
||||||
|
// just quit
|
||||||
|
case <-t.C:
|
||||||
|
am.mutex.Lock()
|
||||||
|
// only drop if it's still the same key instance that dropLater
|
||||||
|
// was launched with. we can check that using pointer equality
|
||||||
|
// because the map stores a new pointer every time the key is
|
||||||
|
// unlocked.
|
||||||
|
if am.unlocked[string(addr)] == u {
|
||||||
|
zeroKey(u.PrivateKey)
|
||||||
|
delete(am.unlocked, string(addr))
|
||||||
|
}
|
||||||
|
am.mutex.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// zeroKey zeroes a private key in memory.
|
||||||
|
func zeroKey(k *ecdsa.PrivateKey) {
|
||||||
|
b := k.D.Bits()
|
||||||
|
for i := range b {
|
||||||
|
b[i] = 0
|
||||||
}
|
}
|
||||||
am.mutex.RLock()
|
|
||||||
// TODO: how do we know the key is actually gone from memory?
|
|
||||||
delete(am.unlockedKeys, string(addr))
|
|
||||||
am.mutex.RUnlock()
|
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,36 @@
|
|||||||
package accounts
|
package accounts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/randentropy"
|
"github.com/ethereum/go-ethereum/crypto/randentropy"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAccountManager(t *testing.T) {
|
func TestSign(t *testing.T) {
|
||||||
ks := crypto.NewKeyStorePlain(ethutil.DefaultDataDir() + "/testaccounts")
|
dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain)
|
||||||
am := NewAccountManager(ks, 100)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
am := NewManager(ks)
|
||||||
pass := "" // not used but required by API
|
pass := "" // not used but required by API
|
||||||
a1, err := am.NewAccount(pass)
|
a1, err := am.NewAccount(pass)
|
||||||
toSign := randentropy.GetEntropyCSPRNG(32)
|
toSign := randentropy.GetEntropyCSPRNG(32)
|
||||||
_, err = am.SignLocked(a1, pass, toSign)
|
am.Unlock(a1.Address, "")
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
_, err = am.Sign(a1, toSign)
|
||||||
time.Sleep(time.Millisecond * 150) // wait for locking
|
|
||||||
|
|
||||||
accounts, err := am.Accounts()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
for _, account := range accounts {
|
|
||||||
err := am.DeleteAccount(account.Address, pass)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func TestAccountManagerLocking(t *testing.T) {
|
func TestTimedUnlock(t *testing.T) {
|
||||||
ks := crypto.NewKeyStorePassphrase(ethutil.DefaultDataDir() + "/testaccounts")
|
dir, ks := tmpKeyStore(t, crypto.NewKeyStorePassphrase)
|
||||||
am := NewAccountManager(ks, 200)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
am := NewManager(ks)
|
||||||
pass := "foo"
|
pass := "foo"
|
||||||
a1, err := am.NewAccount(pass)
|
a1, err := am.NewAccount(pass)
|
||||||
toSign := randentropy.GetEntropyCSPRNG(32)
|
toSign := randentropy.GetEntropyCSPRNG(32)
|
||||||
@ -45,38 +38,32 @@ func TestAccountManagerLocking(t *testing.T) {
|
|||||||
// Signing without passphrase fails because account is locked
|
// Signing without passphrase fails because account is locked
|
||||||
_, err = am.Sign(a1, toSign)
|
_, err = am.Sign(a1, toSign)
|
||||||
if err != ErrLocked {
|
if err != ErrLocked {
|
||||||
t.Fatal(err)
|
t.Fatal("Signing should've failed with ErrLocked before unlocking, got ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signing with passphrase works
|
// Signing with passphrase works
|
||||||
_, err = am.SignLocked(a1, pass, toSign)
|
if err = am.TimedUnlock(a1.Address, pass, 100*time.Millisecond); err != nil {
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signing without passphrase works because account is temp unlocked
|
// Signing without passphrase works because account is temp unlocked
|
||||||
_, err = am.Sign(a1, toSign)
|
_, err = am.Sign(a1, toSign)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signing without passphrase fails after automatic locking
|
// Signing fails again after automatic locking
|
||||||
time.Sleep(time.Millisecond * time.Duration(250))
|
time.Sleep(150 * time.Millisecond)
|
||||||
|
|
||||||
_, err = am.Sign(a1, toSign)
|
_, err = am.Sign(a1, toSign)
|
||||||
if err != ErrLocked {
|
if err != ErrLocked {
|
||||||
t.Fatal(err)
|
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
func tmpKeyStore(t *testing.T, new func(string) crypto.KeyStore2) (string, crypto.KeyStore2) {
|
||||||
accounts, err := am.Accounts()
|
d, err := ioutil.TempDir("", "eth-keystore-test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
for _, account := range accounts {
|
return d, new(d)
|
||||||
err := am.DeleteAccount(account.Address, pass)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of go-ethereum
|
|
||||||
|
|
||||||
go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
go-ethereum is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @authors
|
|
||||||
* Gustav Simonsson <gustav.simonsson@gmail.com>
|
|
||||||
*/
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
TestFile string
|
|
||||||
)
|
|
||||||
|
|
||||||
func Init() {
|
|
||||||
flag.Usage = func() {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s <testfile>\n", os.Args[0])
|
|
||||||
flag.PrintDefaults()
|
|
||||||
}
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
TestFile = flag.Arg(0)
|
|
||||||
}
|
|
@ -25,34 +25,26 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ecdsa"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
"path"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
types "github.com/ethereum/go-ethereum/core/types"
|
types "github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
ClientIdentifier = "Ethereum(G)"
|
|
||||||
Version = "0.8.6"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Balance string
|
Balance string
|
||||||
Code string
|
Code string
|
||||||
@ -78,6 +70,7 @@ type BlockHeader struct {
|
|||||||
TransactionsTrie string
|
TransactionsTrie string
|
||||||
UncleHash string
|
UncleHash string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tx struct {
|
type Tx struct {
|
||||||
Data string
|
Data string
|
||||||
GasLimit string
|
GasLimit string
|
||||||
@ -103,108 +96,44 @@ type Test struct {
|
|||||||
Pre map[string]Account
|
Pre map[string]Account
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
Identifier string
|
|
||||||
KeyRing string
|
|
||||||
DiffTool bool
|
|
||||||
DiffType string
|
|
||||||
KeyStore string
|
|
||||||
StartRpc bool
|
|
||||||
StartWebSockets bool
|
|
||||||
RpcListenAddress string
|
|
||||||
RpcPort int
|
|
||||||
WsPort int
|
|
||||||
OutboundPort string
|
|
||||||
ShowGenesis bool
|
|
||||||
AddPeer string
|
|
||||||
MaxPeer int
|
|
||||||
GenAddr bool
|
|
||||||
BootNodes string
|
|
||||||
NodeKey *ecdsa.PrivateKey
|
|
||||||
NAT nat.Interface
|
|
||||||
SecretFile string
|
|
||||||
ExportDir string
|
|
||||||
NonInteractive bool
|
|
||||||
Datadir string
|
|
||||||
LogFile string
|
|
||||||
ConfigFile string
|
|
||||||
DebugFile string
|
|
||||||
LogLevel int
|
|
||||||
LogFormat string
|
|
||||||
Dump bool
|
|
||||||
DumpHash string
|
|
||||||
DumpNumber int
|
|
||||||
VmType int
|
|
||||||
ImportChain string
|
|
||||||
SHH bool
|
|
||||||
Dial bool
|
|
||||||
PrintVersion bool
|
|
||||||
MinerThreads int
|
|
||||||
)
|
|
||||||
|
|
||||||
// flags specific to cli client
|
|
||||||
var (
|
|
||||||
StartMining bool
|
|
||||||
StartJsConsole bool
|
|
||||||
InputFile string
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
init_vars()
|
flag.Usage = func() {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s <testfile>\n", os.Args[0])
|
||||||
Init()
|
flag.PrintDefaults()
|
||||||
|
|
||||||
if len(TestFile) < 1 {
|
|
||||||
log.Fatal("Please specify test file")
|
|
||||||
}
|
|
||||||
blocks, err := loadBlocksFromTestFile(TestFile)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
logger.AddLogSystem(logger.NewStdLogSystem(os.Stderr, log.LstdFlags, logger.DebugDetailLevel))
|
||||||
|
defer func() { logger.Flush() }()
|
||||||
|
|
||||||
defer func() {
|
if len(os.Args) < 2 {
|
||||||
logger.Flush()
|
utils.Fatalf("Please specify a test file as the first argument.")
|
||||||
}()
|
}
|
||||||
|
blocks, err := loadBlocksFromTestFile(os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Could not load blocks: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
//utils.HandleInterrupt()
|
chain := memchain()
|
||||||
|
chain.ResetWithGenesisBlock(blocks[0])
|
||||||
|
if err = chain.InsertChain(types.Blocks{blocks[1]}); err != nil {
|
||||||
|
utils.Fatalf("Error: %v", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("PASS")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
utils.InitConfig(VmType, ConfigFile, Datadir, "ethblocktest")
|
func memchain() *core.ChainManager {
|
||||||
|
blockdb, err := ethdb.NewMemDatabase()
|
||||||
ethereum, err := eth.New(ð.Config{
|
if err != nil {
|
||||||
Name: p2p.MakeName(ClientIdentifier, Version),
|
utils.Fatalf("Could not create in-memory database: %v", err)
|
||||||
KeyStore: KeyStore,
|
}
|
||||||
DataDir: Datadir,
|
statedb, err := ethdb.NewMemDatabase()
|
||||||
LogFile: LogFile,
|
if err != nil {
|
||||||
LogLevel: LogLevel,
|
utils.Fatalf("Could not create in-memory database: %v", err)
|
||||||
LogFormat: LogFormat,
|
}
|
||||||
MaxPeers: MaxPeer,
|
return core.NewChainManager(blockdb, statedb, new(event.TypeMux))
|
||||||
Port: OutboundPort,
|
|
||||||
NAT: NAT,
|
|
||||||
KeyRing: KeyRing,
|
|
||||||
Shh: true,
|
|
||||||
Dial: Dial,
|
|
||||||
BootNodes: BootNodes,
|
|
||||||
NodeKey: NodeKey,
|
|
||||||
MinerThreads: MinerThreads,
|
|
||||||
})
|
|
||||||
|
|
||||||
utils.StartEthereumForTest(ethereum)
|
|
||||||
utils.StartRpc(ethereum, RpcListenAddress, RpcPort)
|
|
||||||
|
|
||||||
ethereum.ChainManager().ResetWithGenesisBlock(blocks[0])
|
|
||||||
// bph := ethereum.ChainManager().GetBlock(blocks[1].Header().ParentHash)
|
|
||||||
// fmt.Println("bph: ", bph)
|
|
||||||
|
|
||||||
//fmt.Println("b0: ", hex.EncodeToString(ethutil.Encode(blocks[0].RlpData())))
|
|
||||||
//fmt.Println("b0: ", hex.EncodeToString(blocks[0].Hash()))
|
|
||||||
//fmt.Println("b1: ", hex.EncodeToString(ethutil.Encode(blocks[1].RlpData())))
|
|
||||||
//fmt.Println("b1: ", hex.EncodeToString(blocks[1].Hash()))
|
|
||||||
|
|
||||||
go ethereum.ChainManager().InsertChain(types.Blocks{blocks[1]})
|
|
||||||
fmt.Println("OK! ")
|
|
||||||
ethereum.WaitForShutdown()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadBlocksFromTestFile(filePath string) (blocks types.Blocks, err error) {
|
func loadBlocksFromTestFile(filePath string) (blocks types.Blocks, err error) {
|
||||||
@ -212,9 +141,8 @@ func loadBlocksFromTestFile(filePath string) (blocks types.Blocks, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bt := *new(map[string]Test)
|
bt := make(map[string]Test)
|
||||||
err = json.Unmarshal(fileContent, &bt)
|
if err = json.Unmarshal(fileContent, &bt); err != nil {
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,49 +208,6 @@ func loadBlocksFromTestFile(filePath string) (blocks types.Blocks, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_vars() {
|
|
||||||
VmType = 0
|
|
||||||
Identifier = ""
|
|
||||||
KeyRing = ""
|
|
||||||
KeyStore = "db"
|
|
||||||
RpcListenAddress = "127.0.0.1"
|
|
||||||
RpcPort = 8545
|
|
||||||
WsPort = 40404
|
|
||||||
StartRpc = true
|
|
||||||
StartWebSockets = false
|
|
||||||
NonInteractive = false
|
|
||||||
GenAddr = false
|
|
||||||
SecretFile = ""
|
|
||||||
ExportDir = ""
|
|
||||||
LogFile = ""
|
|
||||||
|
|
||||||
timeStr := strconv.FormatInt(time.Now().UnixNano(), 10)
|
|
||||||
|
|
||||||
Datadir = path.Join(ethutil.DefaultDataDir(), timeStr)
|
|
||||||
ConfigFile = path.Join(ethutil.DefaultDataDir(), timeStr, "conf.ini")
|
|
||||||
|
|
||||||
DebugFile = ""
|
|
||||||
LogLevel = 5
|
|
||||||
LogFormat = "std"
|
|
||||||
DiffTool = false
|
|
||||||
DiffType = "all"
|
|
||||||
ShowGenesis = false
|
|
||||||
ImportChain = ""
|
|
||||||
Dump = false
|
|
||||||
DumpHash = ""
|
|
||||||
DumpNumber = -1
|
|
||||||
StartMining = false
|
|
||||||
StartJsConsole = false
|
|
||||||
PrintVersion = false
|
|
||||||
MinerThreads = runtime.NumCPU()
|
|
||||||
|
|
||||||
Dial = false
|
|
||||||
OutboundPort = "30303"
|
|
||||||
BootNodes = ""
|
|
||||||
MaxPeer = 1
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func hex_decode(s string) (res []byte, err error) {
|
func hex_decode(s string) (res []byte, err error) {
|
||||||
return hex.DecodeString(strings.TrimPrefix(s, "0x"))
|
return hex.DecodeString(strings.TrimPrefix(s, "0x"))
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
@ -37,51 +35,123 @@ import (
|
|||||||
"github.com/peterh/liner"
|
"github.com/peterh/liner"
|
||||||
)
|
)
|
||||||
|
|
||||||
func execJsFile(ethereum *eth.Ethereum, filename string) {
|
type prompter interface {
|
||||||
file, err := os.Open(filename)
|
AppendHistory(string)
|
||||||
if err != nil {
|
Prompt(p string) (string, error)
|
||||||
utils.Fatalf("%v", err)
|
PasswordPrompt(p string) (string, error)
|
||||||
}
|
|
||||||
content, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("%v", err)
|
|
||||||
}
|
|
||||||
re := javascript.NewJSRE(xeth.New(ethereum, nil))
|
|
||||||
if _, err := re.Run(string(content)); err != nil {
|
|
||||||
utils.Fatalf("Javascript Error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type repl struct {
|
type dumbterm struct{ r *bufio.Reader }
|
||||||
|
|
||||||
|
func (r dumbterm) Prompt(p string) (string, error) {
|
||||||
|
fmt.Print(p)
|
||||||
|
return r.r.ReadString('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r dumbterm) PasswordPrompt(p string) (string, error) {
|
||||||
|
fmt.Println("!! Unsupported terminal, password will echo.")
|
||||||
|
fmt.Print(p)
|
||||||
|
input, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||||
|
fmt.Println()
|
||||||
|
return input, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r dumbterm) AppendHistory(string) {}
|
||||||
|
|
||||||
|
type jsre struct {
|
||||||
re *javascript.JSRE
|
re *javascript.JSRE
|
||||||
ethereum *eth.Ethereum
|
ethereum *eth.Ethereum
|
||||||
xeth *xeth.XEth
|
xeth *xeth.XEth
|
||||||
prompt string
|
ps1 string
|
||||||
lr *liner.State
|
atexit func()
|
||||||
|
|
||||||
|
prompter
|
||||||
}
|
}
|
||||||
|
|
||||||
func runREPL(ethereum *eth.Ethereum) {
|
func newJSRE(ethereum *eth.Ethereum) *jsre {
|
||||||
xeth := xeth.New(ethereum, nil)
|
js := &jsre{ethereum: ethereum, ps1: "> "}
|
||||||
repl := &repl{
|
js.xeth = xeth.New(ethereum, js)
|
||||||
re: javascript.NewJSRE(xeth),
|
js.re = javascript.NewJSRE(js.xeth)
|
||||||
xeth: xeth,
|
js.initStdFuncs()
|
||||||
ethereum: ethereum,
|
|
||||||
prompt: "> ",
|
|
||||||
}
|
|
||||||
repl.initStdFuncs()
|
|
||||||
if !liner.TerminalSupported() {
|
if !liner.TerminalSupported() {
|
||||||
repl.dumbRead()
|
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
|
||||||
} else {
|
} else {
|
||||||
lr := liner.NewLiner()
|
lr := liner.NewLiner()
|
||||||
defer lr.Close()
|
js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) })
|
||||||
lr.SetCtrlCAborts(true)
|
lr.SetCtrlCAborts(true)
|
||||||
repl.withHistory(func(hist *os.File) { lr.ReadHistory(hist) })
|
js.prompter = lr
|
||||||
repl.read(lr)
|
js.atexit = func() {
|
||||||
repl.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) })
|
js.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) })
|
||||||
|
lr.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return js
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *jsre) ConfirmTransaction(tx *types.Transaction) bool {
|
||||||
|
p := fmt.Sprintf("Confirm Transaction %v\n[y/n] ", tx)
|
||||||
|
answer, _ := self.Prompt(p)
|
||||||
|
return strings.HasPrefix(strings.Trim(answer, " "), "y")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *jsre) UnlockAccount(addr []byte) bool {
|
||||||
|
fmt.Printf("Please unlock account %x.\n", addr)
|
||||||
|
pass, err := self.PasswordPrompt("Passphrase: ")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// TODO: allow retry
|
||||||
|
if err := self.ethereum.AccountManager().Unlock(addr, pass); err != nil {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
fmt.Println("Account is now unlocked for this session.")
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *repl) withHistory(op func(*os.File)) {
|
func (self *jsre) exec(filename string) error {
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
content, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := self.re.Run(string(content)); err != nil {
|
||||||
|
return fmt.Errorf("Javascript Error: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *jsre) interactive() {
|
||||||
|
for {
|
||||||
|
input, err := self.Prompt(self.ps1)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if input == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
str += input + "\n"
|
||||||
|
self.setIndent()
|
||||||
|
if indentCount <= 0 {
|
||||||
|
if input == "exit" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
hist := str[:len(str)-1]
|
||||||
|
self.AppendHistory(hist)
|
||||||
|
self.parseInput(str)
|
||||||
|
str = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.atexit != nil {
|
||||||
|
self.atexit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *jsre) withHistory(op func(*os.File)) {
|
||||||
hist, err := os.OpenFile(path.Join(self.ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
|
hist, err := os.OpenFile(path.Join(self.ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("unable to open history file: %v\n", err)
|
fmt.Printf("unable to open history file: %v\n", err)
|
||||||
@ -91,7 +161,7 @@ func (self *repl) withHistory(op func(*os.File)) {
|
|||||||
hist.Close()
|
hist.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *repl) parseInput(code string) {
|
func (self *jsre) parseInput(code string) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
fmt.Println("[native] error", r)
|
fmt.Println("[native] error", r)
|
||||||
@ -108,79 +178,21 @@ func (self *repl) parseInput(code string) {
|
|||||||
var indentCount = 0
|
var indentCount = 0
|
||||||
var str = ""
|
var str = ""
|
||||||
|
|
||||||
func (self *repl) setIndent() {
|
func (self *jsre) setIndent() {
|
||||||
open := strings.Count(str, "{")
|
open := strings.Count(str, "{")
|
||||||
open += strings.Count(str, "(")
|
open += strings.Count(str, "(")
|
||||||
closed := strings.Count(str, "}")
|
closed := strings.Count(str, "}")
|
||||||
closed += strings.Count(str, ")")
|
closed += strings.Count(str, ")")
|
||||||
indentCount = open - closed
|
indentCount = open - closed
|
||||||
if indentCount <= 0 {
|
if indentCount <= 0 {
|
||||||
self.prompt = "> "
|
self.ps1 = "> "
|
||||||
} else {
|
} else {
|
||||||
self.prompt = strings.Join(make([]string, indentCount*2), "..")
|
self.ps1 = strings.Join(make([]string, indentCount*2), "..")
|
||||||
self.prompt += " "
|
self.ps1 += " "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *repl) read(lr *liner.State) {
|
func (self *jsre) printValue(v interface{}) {
|
||||||
for {
|
|
||||||
input, err := lr.Prompt(self.prompt)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if input == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
str += input + "\n"
|
|
||||||
self.setIndent()
|
|
||||||
if indentCount <= 0 {
|
|
||||||
if input == "exit" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
hist := str[:len(str)-1]
|
|
||||||
lr.AppendHistory(hist)
|
|
||||||
self.parseInput(str)
|
|
||||||
str = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *repl) dumbRead() {
|
|
||||||
fmt.Println("Unsupported terminal, line editing will not work.")
|
|
||||||
|
|
||||||
// process lines
|
|
||||||
readDone := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
r := bufio.NewReader(os.Stdin)
|
|
||||||
loop:
|
|
||||||
for {
|
|
||||||
fmt.Print(self.prompt)
|
|
||||||
line, err := r.ReadString('\n')
|
|
||||||
switch {
|
|
||||||
case err != nil || line == "exit":
|
|
||||||
break loop
|
|
||||||
case line == "":
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
self.parseInput(line + "\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(readDone)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// wait for Ctrl-C
|
|
||||||
sigc := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sigc, os.Interrupt, os.Kill)
|
|
||||||
defer signal.Stop(sigc)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-readDone:
|
|
||||||
case <-sigc:
|
|
||||||
os.Stdin.Close() // terminate read
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *repl) printValue(v interface{}) {
|
|
||||||
method, _ := self.re.Vm.Get("prettyPrint")
|
method, _ := self.re.Vm.Get("prettyPrint")
|
||||||
v, err := self.re.Vm.ToValue(v)
|
v, err := self.re.Vm.ToValue(v)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -191,7 +203,7 @@ func (self *repl) printValue(v interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *repl) initStdFuncs() {
|
func (self *jsre) initStdFuncs() {
|
||||||
t, _ := self.re.Vm.Get("eth")
|
t, _ := self.re.Vm.Get("eth")
|
||||||
eth := t.Object()
|
eth := t.Object()
|
||||||
eth.Set("connect", self.connect)
|
eth.Set("connect", self.connect)
|
||||||
@ -205,7 +217,7 @@ func (self *repl) initStdFuncs() {
|
|||||||
* The following methods are natively implemented javascript functions.
|
* The following methods are natively implemented javascript functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (self *repl) dump(call otto.FunctionCall) otto.Value {
|
func (self *jsre) dump(call otto.FunctionCall) otto.Value {
|
||||||
var block *types.Block
|
var block *types.Block
|
||||||
|
|
||||||
if len(call.ArgumentList) > 0 {
|
if len(call.ArgumentList) > 0 {
|
||||||
@ -236,17 +248,17 @@ func (self *repl) dump(call otto.FunctionCall) otto.Value {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *repl) stopMining(call otto.FunctionCall) otto.Value {
|
func (self *jsre) stopMining(call otto.FunctionCall) otto.Value {
|
||||||
self.xeth.Miner().Stop()
|
self.xeth.Miner().Stop()
|
||||||
return otto.TrueValue()
|
return otto.TrueValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *repl) startMining(call otto.FunctionCall) otto.Value {
|
func (self *jsre) startMining(call otto.FunctionCall) otto.Value {
|
||||||
self.xeth.Miner().Start()
|
self.xeth.Miner().Start()
|
||||||
return otto.TrueValue()
|
return otto.TrueValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *repl) connect(call otto.FunctionCall) otto.Value {
|
func (self *jsre) connect(call otto.FunctionCall) otto.Value {
|
||||||
nodeURL, err := call.Argument(0).ToString()
|
nodeURL, err := call.Argument(0).ToString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return otto.FalseValue()
|
return otto.FalseValue()
|
||||||
@ -257,7 +269,7 @@ func (self *repl) connect(call otto.FunctionCall) otto.Value {
|
|||||||
return otto.TrueValue()
|
return otto.TrueValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *repl) export(call otto.FunctionCall) otto.Value {
|
func (self *jsre) export(call otto.FunctionCall) otto.Value {
|
||||||
if len(call.ArgumentList) == 0 {
|
if len(call.ArgumentList) == 0 {
|
||||||
fmt.Println("err: require file name")
|
fmt.Println("err: require file name")
|
||||||
return otto.FalseValue()
|
return otto.FalseValue()
|
||||||
|
@ -21,19 +21,23 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
|
"github.com/peterh/liner"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -43,12 +47,10 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
clilogger = logger.NewLogger("CLI")
|
clilogger = logger.NewLogger("CLI")
|
||||||
app = cli.NewApp()
|
app = utils.NewApp(Version, "the go-ethereum command line interface")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
app.Version = Version
|
|
||||||
app.Usage = "the go-ethereum command-line client"
|
|
||||||
app.Action = run
|
app.Action = run
|
||||||
app.HideVersion = true // we have a command to print the version
|
app.HideVersion = true // we have a command to print the version
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []cli.Command{
|
||||||
@ -60,6 +62,23 @@ func init() {
|
|||||||
The output of this command is supposed to be machine-readable.
|
The output of this command is supposed to be machine-readable.
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Action: accountList,
|
||||||
|
Name: "account",
|
||||||
|
Usage: "manage accounts",
|
||||||
|
Subcommands: []cli.Command{
|
||||||
|
{
|
||||||
|
Action: accountList,
|
||||||
|
Name: "list",
|
||||||
|
Usage: "print account addresses",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Action: accountCreate,
|
||||||
|
Name: "new",
|
||||||
|
Usage: "create a new account",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Action: dump,
|
Action: dump,
|
||||||
Name: "dump",
|
Name: "dump",
|
||||||
@ -93,13 +112,10 @@ runtime will execute the file and exit.
|
|||||||
Usage: `export blockchain into file`,
|
Usage: `export blockchain into file`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
app.Author = ""
|
|
||||||
app.Email = ""
|
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
|
utils.UnlockedAccountFlag,
|
||||||
utils.BootnodesFlag,
|
utils.BootnodesFlag,
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
utils.KeyRingFlag,
|
|
||||||
utils.KeyStoreFlag,
|
|
||||||
utils.ListenPortFlag,
|
utils.ListenPortFlag,
|
||||||
utils.LogFileFlag,
|
utils.LogFileFlag,
|
||||||
utils.LogFormatFlag,
|
utils.LogFormatFlag,
|
||||||
@ -140,38 +156,100 @@ func main() {
|
|||||||
func run(ctx *cli.Context) {
|
func run(ctx *cli.Context) {
|
||||||
fmt.Printf("Welcome to the FRONTIER\n")
|
fmt.Printf("Welcome to the FRONTIER\n")
|
||||||
utils.HandleInterrupt()
|
utils.HandleInterrupt()
|
||||||
eth := utils.GetEthereum(ClientIdentifier, Version, ctx)
|
eth, err := utils.GetEthereum(ClientIdentifier, Version, ctx)
|
||||||
|
if err == accounts.ErrNoKeys {
|
||||||
|
utils.Fatalf(`No accounts configured.
|
||||||
|
Please run 'ethereum account new' to create a new account.`)
|
||||||
|
} else if err != nil {
|
||||||
|
utils.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
startEth(ctx, eth)
|
startEth(ctx, eth)
|
||||||
// this blocks the thread
|
// this blocks the thread
|
||||||
eth.WaitForShutdown()
|
eth.WaitForShutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runjs(ctx *cli.Context) {
|
func runjs(ctx *cli.Context) {
|
||||||
eth := utils.GetEthereum(ClientIdentifier, Version, ctx)
|
eth, err := utils.GetEthereum(ClientIdentifier, Version, ctx)
|
||||||
|
if err == accounts.ErrNoKeys {
|
||||||
|
utils.Fatalf(`No accounts configured.
|
||||||
|
Please run 'ethereum account new' to create a new account.`)
|
||||||
|
} else if err != nil {
|
||||||
|
utils.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
startEth(ctx, eth)
|
startEth(ctx, eth)
|
||||||
|
repl := newJSRE(eth)
|
||||||
if len(ctx.Args()) == 0 {
|
if len(ctx.Args()) == 0 {
|
||||||
runREPL(eth)
|
repl.interactive()
|
||||||
|
} else {
|
||||||
|
for _, file := range ctx.Args() {
|
||||||
|
repl.exec(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
eth.Stop()
|
eth.Stop()
|
||||||
eth.WaitForShutdown()
|
eth.WaitForShutdown()
|
||||||
} else if len(ctx.Args()) == 1 {
|
|
||||||
execJsFile(eth, ctx.Args()[0])
|
|
||||||
} else {
|
|
||||||
utils.Fatalf("This command can handle at most one argument.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
||||||
utils.StartEthereum(eth)
|
utils.StartEthereum(eth)
|
||||||
|
|
||||||
|
// Load startup keys. XXX we are going to need a different format
|
||||||
|
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
|
||||||
|
if len(account) > 0 {
|
||||||
|
split := strings.Split(account, ":")
|
||||||
|
if len(split) != 2 {
|
||||||
|
utils.Fatalf("Illegal 'unlock' format (address:password)")
|
||||||
|
}
|
||||||
|
am := utils.GetAccountManager(ctx)
|
||||||
|
// Attempt to unlock the account
|
||||||
|
err := am.Unlock(ethutil.Hex2Bytes(split[0]), split[1])
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Unlock account failed '%v'", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Start auxiliary services if enabled.
|
||||||
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
|
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
|
||||||
addr := ctx.GlobalString(utils.RPCListenAddrFlag.Name)
|
utils.StartRPC(eth, ctx)
|
||||||
port := ctx.GlobalInt(utils.RPCPortFlag.Name)
|
|
||||||
utils.StartRpc(eth, addr, port)
|
|
||||||
}
|
}
|
||||||
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
|
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
|
||||||
eth.Miner().Start()
|
eth.Miner().Start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func accountList(ctx *cli.Context) {
|
||||||
|
am := utils.GetAccountManager(ctx)
|
||||||
|
accts, err := am.Accounts()
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Could not list accounts: %v", err)
|
||||||
|
}
|
||||||
|
for _, acct := range accts {
|
||||||
|
fmt.Printf("Address: %#x\n", acct)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func accountCreate(ctx *cli.Context) {
|
||||||
|
am := utils.GetAccountManager(ctx)
|
||||||
|
fmt.Println("The new account will be encrypted with a passphrase.")
|
||||||
|
fmt.Println("Please enter a passphrase now.")
|
||||||
|
auth, err := readPassword("Passphrase: ", true)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
confirm, err := readPassword("Repeat Passphrase: ", false)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
if auth != confirm {
|
||||||
|
utils.Fatalf("Passphrases did not match.")
|
||||||
|
}
|
||||||
|
acct, err := am.NewAccount(auth)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Could not create the account: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Address: %#x\n", acct.Address)
|
||||||
|
}
|
||||||
|
|
||||||
func importchain(ctx *cli.Context) {
|
func importchain(ctx *cli.Context) {
|
||||||
if len(ctx.Args()) != 1 {
|
if len(ctx.Args()) != 1 {
|
||||||
utils.Fatalf("This command requires an argument.")
|
utils.Fatalf("This command requires an argument.")
|
||||||
@ -221,12 +299,6 @@ func dump(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hashish returns true for strings that look like hashes.
|
|
||||||
func hashish(x string) bool {
|
|
||||||
_, err := strconv.Atoi(x)
|
|
||||||
return err != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func version(c *cli.Context) {
|
func version(c *cli.Context) {
|
||||||
fmt.Printf(`%v
|
fmt.Printf(`%v
|
||||||
Version: %v
|
Version: %v
|
||||||
@ -238,3 +310,24 @@ GOPATH=%s
|
|||||||
GOROOT=%s
|
GOROOT=%s
|
||||||
`, ClientIdentifier, Version, eth.ProtocolVersion, eth.NetworkId, runtime.Version(), runtime.GOOS, os.Getenv("GOPATH"), runtime.GOROOT())
|
`, ClientIdentifier, Version, eth.ProtocolVersion, eth.NetworkId, runtime.Version(), runtime.GOOS, os.Getenv("GOPATH"), runtime.GOROOT())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hashish returns true for strings that look like hashes.
|
||||||
|
func hashish(x string) bool {
|
||||||
|
_, err := strconv.Atoi(x)
|
||||||
|
return err != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readPassword(prompt string, warnTerm bool) (string, error) {
|
||||||
|
if liner.TerminalSupported() {
|
||||||
|
lr := liner.NewLiner()
|
||||||
|
defer lr.Close()
|
||||||
|
return lr.PasswordPrompt(prompt)
|
||||||
|
}
|
||||||
|
if warnTerm {
|
||||||
|
fmt.Println("!! Unsupported terminal, password will be echoed.")
|
||||||
|
}
|
||||||
|
fmt.Print(prompt)
|
||||||
|
input, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||||
|
fmt.Println()
|
||||||
|
return input, err
|
||||||
|
}
|
||||||
|
@ -59,8 +59,6 @@ func main() {
|
|||||||
|
|
||||||
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(*loglevel)))
|
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(*loglevel)))
|
||||||
|
|
||||||
ethutil.ReadConfig("/tmp/evmtest", "/tmp/evm", "")
|
|
||||||
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
statedb := state.New(nil, db)
|
statedb := state.New(nil, db)
|
||||||
sender := statedb.NewStateObject([]byte("sender"))
|
sender := statedb.NewStateObject([]byte("sender"))
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
// deploy if not exist
|
// deploy if not exist
|
||||||
if (address == null) {
|
if (address == null) {
|
||||||
var code = "0x60056013565b61014f8061003a6000396000f35b620f42406000600033600160a060020a0316815260200190815260200160002081905550560060e060020a600035048063d0679d3414610020578063e3d670d71461003457005b61002e600435602435610049565b60006000f35b61003f600435610129565b8060005260206000f35b806000600033600160a060020a03168152602001908152602001600020541061007157610076565b610125565b806000600033600160a060020a03168152602001908152602001600020908154039081905550806000600084600160a060020a031681526020019081526020016000209081540190819055508033600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a38082600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a35b5050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056";
|
var code = "0x60056013565b61014f8061003a6000396000f35b620f42406000600033600160a060020a0316815260200190815260200160002081905550560060e060020a600035048063d0679d3414610020578063e3d670d71461003457005b61002e600435602435610049565b60006000f35b61003f600435610129565b8060005260206000f35b806000600033600160a060020a03168152602001908152602001600020541061007157610076565b610125565b806000600033600160a060020a03168152602001908152602001600020908154039081905550806000600084600160a060020a031681526020019081526020016000209081540190819055508033600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a38082600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a35b5050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056";
|
||||||
address = web3.eth.transact({data: code});
|
address = web3.eth.transact({from: eth.coinbase, data: code});
|
||||||
localStorage.setItem("address", address);
|
localStorage.setItem("address", address);
|
||||||
}
|
}
|
||||||
document.querySelector("#contract_addr").innerHTML = address;
|
document.querySelector("#contract_addr").innerHTML = address;
|
||||||
|
@ -190,6 +190,11 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Generate key"
|
||||||
|
shortcut: "Ctrl+k"
|
||||||
|
onTriggered: gui.generateKey()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu {
|
Menu {
|
||||||
|
@ -54,7 +54,6 @@ Rectangle {
|
|||||||
height: 200
|
height: 200
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
right: logLevelSlider.left
|
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
top: parent.top
|
top: parent.top
|
||||||
}
|
}
|
||||||
@ -107,46 +106,6 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
TableView {
|
|
||||||
id: logView
|
|
||||||
headerVisible: false
|
|
||||||
anchors {
|
|
||||||
right: logLevelSlider.left
|
|
||||||
left: parent.left
|
|
||||||
bottom: parent.bottom
|
|
||||||
top: parent.top
|
|
||||||
}
|
|
||||||
|
|
||||||
TableViewColumn{ role: "description" ; title: "log" }
|
|
||||||
|
|
||||||
model: logModel
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Slider {
|
|
||||||
id: logLevelSlider
|
|
||||||
value: gui.getLogLevelInt()
|
|
||||||
anchors {
|
|
||||||
right: parent.right
|
|
||||||
top: parent.top
|
|
||||||
bottom: parent.bottom
|
|
||||||
|
|
||||||
rightMargin: 5
|
|
||||||
leftMargin: 5
|
|
||||||
topMargin: 5
|
|
||||||
bottomMargin: 5
|
|
||||||
}
|
|
||||||
|
|
||||||
orientation: Qt.Vertical
|
|
||||||
maximumValue: 5
|
|
||||||
stepSize: 1
|
|
||||||
|
|
||||||
onValueChanged: {
|
|
||||||
gui.setLogLevel(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
property var logModel: ListModel {
|
property var logModel: ListModel {
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,19 +36,7 @@ type plugin struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogPrint writes to the GUI log.
|
func (gui *Gui) Transact(from, recipient, value, gas, gasPrice, d string) (string, error) {
|
||||||
func (gui *Gui) LogPrint(level logger.LogLevel, msg string) {
|
|
||||||
/*
|
|
||||||
str := strings.TrimRight(s, "\n")
|
|
||||||
lines := strings.Split(str, "\n")
|
|
||||||
|
|
||||||
view := gui.getObjectByName("infoView")
|
|
||||||
for _, line := range lines {
|
|
||||||
view.Call("addLog", line)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
func (gui *Gui) Transact(recipient, value, gas, gasPrice, d string) (string, error) {
|
|
||||||
var data string
|
var data string
|
||||||
if len(recipient) == 0 {
|
if len(recipient) == 0 {
|
||||||
code, err := ethutil.Compile(d, false)
|
code, err := ethutil.Compile(d, false)
|
||||||
@ -61,18 +48,7 @@ func (gui *Gui) Transact(recipient, value, gas, gasPrice, d string) (string, err
|
|||||||
data = ethutil.Bytes2Hex(utils.FormatTransactionData(d))
|
data = ethutil.Bytes2Hex(utils.FormatTransactionData(d))
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.xeth.Transact(recipient, value, gas, gasPrice, data)
|
return gui.xeth.Transact(from, recipient, value, gas, gasPrice, data)
|
||||||
}
|
|
||||||
|
|
||||||
// functions that allow Gui to implement interface guilogger.LogSystem
|
|
||||||
func (gui *Gui) SetLogLevel(level logger.LogLevel) {
|
|
||||||
gui.logLevel = level
|
|
||||||
gui.eth.Logger().SetLogLevel(level)
|
|
||||||
gui.config.Save("loglevel", level)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) GetLogLevel() logger.LogLevel {
|
|
||||||
return gui.logLevel
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Gui) AddPlugin(pluginPath string) {
|
func (self *Gui) AddPlugin(pluginPath string) {
|
||||||
@ -89,11 +65,6 @@ func (self *Gui) RemovePlugin(pluginPath string) {
|
|||||||
ethutil.WriteFile(self.eth.DataDir+"/plugins.json", json)
|
ethutil.WriteFile(self.eth.DataDir+"/plugins.json", json)
|
||||||
}
|
}
|
||||||
|
|
||||||
// this extra function needed to give int typecast value to gui widget
|
|
||||||
// that sets initial loglevel to default
|
|
||||||
func (gui *Gui) GetLogLevelInt() int {
|
|
||||||
return int(gui.logLevel)
|
|
||||||
}
|
|
||||||
func (self *Gui) DumpState(hash, path string) {
|
func (self *Gui) DumpState(hash, path string) {
|
||||||
var stateDump []byte
|
var stateDump []byte
|
||||||
|
|
||||||
|
@ -1,130 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of go-ethereum
|
|
||||||
|
|
||||||
go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
go-ethereum is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @authors
|
|
||||||
* Jeffrey Wilcke <i@jev.io>
|
|
||||||
*/
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
|
||||||
"github.com/ethereum/go-ethereum/vm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
Identifier string
|
|
||||||
KeyRing string
|
|
||||||
KeyStore string
|
|
||||||
StartRpc bool
|
|
||||||
RpcListenAddress string
|
|
||||||
RpcPort int
|
|
||||||
OutboundPort string
|
|
||||||
ShowGenesis bool
|
|
||||||
AddPeer string
|
|
||||||
MaxPeer int
|
|
||||||
GenAddr bool
|
|
||||||
BootNodes string
|
|
||||||
NodeKey *ecdsa.PrivateKey
|
|
||||||
NAT nat.Interface
|
|
||||||
SecretFile string
|
|
||||||
ExportDir string
|
|
||||||
NonInteractive bool
|
|
||||||
Datadir string
|
|
||||||
LogFile string
|
|
||||||
ConfigFile string
|
|
||||||
DebugFile string
|
|
||||||
LogLevel int
|
|
||||||
VmType int
|
|
||||||
MinerThreads int
|
|
||||||
)
|
|
||||||
|
|
||||||
// flags specific to gui client
|
|
||||||
var AssetPath string
|
|
||||||
var defaultConfigFile = path.Join(ethutil.DefaultDataDir(), "conf.ini")
|
|
||||||
|
|
||||||
func Init() {
|
|
||||||
// TODO: move common flag processing to cmd/utils
|
|
||||||
flag.Usage = func() {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s [options] [filename]:\noptions precedence: default < config file < environment variables < command line\n", os.Args[0])
|
|
||||||
flag.PrintDefaults()
|
|
||||||
}
|
|
||||||
|
|
||||||
flag.IntVar(&VmType, "vm", 0, "Virtual Machine type: 0-1: standard, debug")
|
|
||||||
flag.StringVar(&Identifier, "id", "", "Custom client identifier")
|
|
||||||
flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use")
|
|
||||||
flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file")
|
|
||||||
flag.StringVar(&RpcListenAddress, "rpcaddr", "127.0.0.1", "address for json-rpc server to listen on")
|
|
||||||
flag.IntVar(&RpcPort, "rpcport", 8545, "port to start json-rpc server on")
|
|
||||||
flag.BoolVar(&StartRpc, "rpc", true, "start rpc server")
|
|
||||||
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
|
|
||||||
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
|
|
||||||
flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)")
|
|
||||||
flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given")
|
|
||||||
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)")
|
|
||||||
flag.StringVar(&Datadir, "datadir", ethutil.DefaultDataDir(), "specifies the datadir to use")
|
|
||||||
flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
|
|
||||||
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
|
|
||||||
flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5 (= silent,error,warn,info,debug,debug detail)")
|
|
||||||
|
|
||||||
flag.StringVar(&AssetPath, "asset_path", ethutil.DefaultAssetPath(), "absolute path to GUI assets directory")
|
|
||||||
|
|
||||||
// Network stuff
|
|
||||||
var (
|
|
||||||
nodeKeyFile = flag.String("nodekey", "", "network private key file")
|
|
||||||
nodeKeyHex = flag.String("nodekeyhex", "", "network private key (for testing)")
|
|
||||||
natstr = flag.String("nat", "any", "port mapping mechanism (any|none|upnp|pmp|extip:<IP>)")
|
|
||||||
)
|
|
||||||
flag.StringVar(&OutboundPort, "port", "30303", "listening port")
|
|
||||||
flag.StringVar(&BootNodes, "bootnodes", "", "space-separated node URLs for discovery bootstrap")
|
|
||||||
flag.IntVar(&MaxPeer, "maxpeer", 30, "maximum desired peers")
|
|
||||||
|
|
||||||
flag.IntVar(&MinerThreads, "minerthreads", runtime.NumCPU(), "number of miner threads")
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
var err error
|
|
||||||
if NAT, err = nat.Parse(*natstr); err != nil {
|
|
||||||
log.Fatalf("-nat: %v", err)
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case *nodeKeyFile != "" && *nodeKeyHex != "":
|
|
||||||
log.Fatal("Options -nodekey and -nodekeyhex are mutually exclusive")
|
|
||||||
case *nodeKeyFile != "":
|
|
||||||
if NodeKey, err = crypto.LoadECDSA(*nodeKeyFile); err != nil {
|
|
||||||
log.Fatalf("-nodekey: %v", err)
|
|
||||||
}
|
|
||||||
case *nodeKeyHex != "":
|
|
||||||
if NodeKey, err = crypto.HexToECDSA(*nodeKeyHex); err != nil {
|
|
||||||
log.Fatalf("-nodekeyhex: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if VmType >= int(vm.MaxVmTy) {
|
|
||||||
log.Fatal("Invalid VM type ", VmType)
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,7 +23,6 @@ package main
|
|||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -70,20 +69,18 @@ type Gui struct {
|
|||||||
|
|
||||||
txDb *ethdb.LDBDatabase
|
txDb *ethdb.LDBDatabase
|
||||||
|
|
||||||
logLevel logger.LogLevel
|
|
||||||
open bool
|
open bool
|
||||||
|
|
||||||
xeth *xeth.XEth
|
xeth *xeth.XEth
|
||||||
|
|
||||||
Session string
|
Session string
|
||||||
config *ethutil.ConfigManager
|
|
||||||
|
|
||||||
plugins map[string]plugin
|
plugins map[string]plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create GUI, but doesn't start it
|
// Create GUI, but doesn't start it
|
||||||
func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, session string, logLevel int) *Gui {
|
func NewWindow(ethereum *eth.Ethereum) *Gui {
|
||||||
db, err := ethdb.NewLDBDatabase("tx_database")
|
db, err := ethdb.NewLDBDatabase(path.Join(ethereum.DataDir, "tx_database"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -92,10 +89,7 @@ func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, session st
|
|||||||
gui := &Gui{eth: ethereum,
|
gui := &Gui{eth: ethereum,
|
||||||
txDb: db,
|
txDb: db,
|
||||||
xeth: xeth,
|
xeth: xeth,
|
||||||
logLevel: logger.LogLevel(logLevel),
|
|
||||||
Session: session,
|
|
||||||
open: false,
|
open: false,
|
||||||
config: config,
|
|
||||||
plugins: make(map[string]plugin),
|
plugins: make(map[string]plugin),
|
||||||
serviceEvents: make(chan ServEv, 1),
|
serviceEvents: make(chan ServEv, 1),
|
||||||
}
|
}
|
||||||
@ -142,18 +136,12 @@ func (gui *Gui) Start(assetPath string) {
|
|||||||
gui.open = true
|
gui.open = true
|
||||||
win.Show()
|
win.Show()
|
||||||
|
|
||||||
// only add the gui guilogger after window is shown otherwise slider wont be shown
|
|
||||||
logger.AddLogSystem(gui)
|
|
||||||
win.Wait()
|
win.Wait()
|
||||||
|
|
||||||
// need to silence gui guilogger after window closed otherwise logsystem hangs (but do not save loglevel)
|
|
||||||
gui.logLevel = logger.Silence
|
|
||||||
gui.open = false
|
gui.open = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) Stop() {
|
func (gui *Gui) Stop() {
|
||||||
if gui.open {
|
if gui.open {
|
||||||
gui.logLevel = logger.Silence
|
|
||||||
gui.open = false
|
gui.open = false
|
||||||
gui.win.Hide()
|
gui.win.Hide()
|
||||||
}
|
}
|
||||||
@ -172,7 +160,11 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
|
|||||||
return gui.win, nil
|
return gui.win, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) ImportKey(filePath string) {
|
func (gui *Gui) GenerateKey() {
|
||||||
|
_, err := gui.eth.AccountManager().NewAccount("hurr")
|
||||||
|
if err != nil {
|
||||||
|
// TODO: UI feedback?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
|
func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
|
||||||
@ -191,31 +183,11 @@ func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
|
|||||||
return gui.win
|
return gui.win
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) ImportAndSetPrivKey(secret string) bool {
|
|
||||||
err := gui.eth.KeyManager().InitFromString(gui.Session, 0, secret)
|
|
||||||
if err != nil {
|
|
||||||
guilogger.Errorln("unable to import: ", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
guilogger.Errorln("successfully imported: ", err)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) CreateAndSetPrivKey() (string, string, string, string) {
|
|
||||||
err := gui.eth.KeyManager().Init(gui.Session, 0, true)
|
|
||||||
if err != nil {
|
|
||||||
guilogger.Errorln("unable to create key: ", err)
|
|
||||||
return "", "", "", ""
|
|
||||||
}
|
|
||||||
return gui.eth.KeyManager().KeyPair().AsStrings()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) setInitialChain(ancientBlocks bool) {
|
func (gui *Gui) setInitialChain(ancientBlocks bool) {
|
||||||
sBlk := gui.eth.ChainManager().LastBlockHash()
|
sBlk := gui.eth.ChainManager().LastBlockHash()
|
||||||
blk := gui.eth.ChainManager().GetBlock(sBlk)
|
blk := gui.eth.ChainManager().GetBlock(sBlk)
|
||||||
for ; blk != nil; blk = gui.eth.ChainManager().GetBlock(sBlk) {
|
for ; blk != nil; blk = gui.eth.ChainManager().GetBlock(sBlk) {
|
||||||
sBlk = blk.ParentHash()
|
sBlk = blk.ParentHash()
|
||||||
|
|
||||||
gui.processBlock(blk, true)
|
gui.processBlock(blk, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,10 +231,8 @@ func (self *Gui) loadMergedMiningOptions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) insertTransaction(window string, tx *types.Transaction) {
|
func (gui *Gui) insertTransaction(window string, tx *types.Transaction) {
|
||||||
addr := gui.address()
|
|
||||||
|
|
||||||
var inout string
|
var inout string
|
||||||
if bytes.Compare(tx.From(), addr) == 0 {
|
if gui.eth.AccountManager().HasAccount(tx.From()) {
|
||||||
inout = "send"
|
inout = "send"
|
||||||
} else {
|
} else {
|
||||||
inout = "recv"
|
inout = "recv"
|
||||||
@ -480,14 +450,6 @@ func (gui *Gui) setPeerInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) privateKey() string {
|
|
||||||
return ethutil.Bytes2Hex(gui.eth.KeyManager().PrivateKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) address() []byte {
|
|
||||||
return gui.eth.KeyManager().Address()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
func LoadExtension(path string) (uintptr, error) {
|
func LoadExtension(path string) (uintptr, error) {
|
||||||
lib, err := ffi.NewLibrary(path)
|
lib, err := ffi.NewLibrary(path)
|
||||||
|
104
cmd/mist/main.go
104
cmd/mist/main.go
@ -26,10 +26,10 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
|
||||||
"github.com/ethereum/go-ethereum/ui/qt/webengine"
|
"github.com/ethereum/go-ethereum/ui/qt/webengine"
|
||||||
"github.com/obscuren/qml"
|
"github.com/obscuren/qml"
|
||||||
)
|
)
|
||||||
@ -39,56 +39,32 @@ const (
|
|||||||
Version = "0.9.0"
|
Version = "0.9.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ethereum *eth.Ethereum
|
var (
|
||||||
var mainlogger = logger.NewLogger("MAIN")
|
app = utils.NewApp(Version, "the ether browser")
|
||||||
|
assetPathFlag = cli.StringFlag{
|
||||||
func run() error {
|
Name: "asset_path",
|
||||||
webengine.Initialize()
|
Usage: "absolute path to GUI assets directory",
|
||||||
|
Value: ethutil.DefaultAssetPath(),
|
||||||
// precedence: code-internal flag default < config file < environment variables < command line
|
|
||||||
Init() // parsing command line
|
|
||||||
|
|
||||||
tstart := time.Now()
|
|
||||||
config := utils.InitConfig(VmType, ConfigFile, Datadir, "ETH")
|
|
||||||
|
|
||||||
ethereum, err := eth.New(ð.Config{
|
|
||||||
Name: p2p.MakeName(ClientIdentifier, Version),
|
|
||||||
KeyStore: KeyStore,
|
|
||||||
DataDir: Datadir,
|
|
||||||
LogFile: LogFile,
|
|
||||||
LogLevel: LogLevel,
|
|
||||||
MaxPeers: MaxPeer,
|
|
||||||
Port: OutboundPort,
|
|
||||||
NAT: NAT,
|
|
||||||
Shh: true,
|
|
||||||
BootNodes: BootNodes,
|
|
||||||
NodeKey: NodeKey,
|
|
||||||
KeyRing: KeyRing,
|
|
||||||
Dial: true,
|
|
||||||
MinerThreads: MinerThreads,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
mainlogger.Fatalln(err)
|
|
||||||
}
|
}
|
||||||
utils.KeyTasks(ethereum.KeyManager(), KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
|
)
|
||||||
|
|
||||||
if StartRpc {
|
func init() {
|
||||||
utils.StartRpc(ethereum, RpcListenAddress, RpcPort)
|
app.Action = run
|
||||||
|
app.Flags = []cli.Flag{
|
||||||
|
assetPathFlag,
|
||||||
|
|
||||||
|
utils.BootnodesFlag,
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.ListenPortFlag,
|
||||||
|
utils.LogFileFlag,
|
||||||
|
utils.LogLevelFlag,
|
||||||
|
utils.MaxPeersFlag,
|
||||||
|
utils.MinerThreadsFlag,
|
||||||
|
utils.NATFlag,
|
||||||
|
utils.NodeKeyFileFlag,
|
||||||
|
utils.RPCListenAddrFlag,
|
||||||
|
utils.RPCPortFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
gui := NewWindow(ethereum, config, KeyRing, LogLevel)
|
|
||||||
|
|
||||||
utils.RegisterInterrupt(func(os.Signal) {
|
|
||||||
gui.Stop()
|
|
||||||
})
|
|
||||||
go utils.StartEthereum(ethereum)
|
|
||||||
|
|
||||||
fmt.Println("ETH stack took", time.Since(tstart))
|
|
||||||
|
|
||||||
// gui blocks the main thread
|
|
||||||
gui.Start(AssetPath)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -97,15 +73,16 @@ func main() {
|
|||||||
// This is a bit of a cheat, but ey!
|
// This is a bit of a cheat, but ey!
|
||||||
os.Setenv("QTWEBKIT_INSPECTOR_SERVER", "127.0.0.1:99999")
|
os.Setenv("QTWEBKIT_INSPECTOR_SERVER", "127.0.0.1:99999")
|
||||||
|
|
||||||
qml.Run(run)
|
|
||||||
|
|
||||||
var interrupted = false
|
var interrupted = false
|
||||||
utils.RegisterInterrupt(func(os.Signal) {
|
utils.RegisterInterrupt(func(os.Signal) {
|
||||||
interrupted = true
|
interrupted = true
|
||||||
})
|
})
|
||||||
|
|
||||||
utils.HandleInterrupt()
|
utils.HandleInterrupt()
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
// we need to run the interrupt callbacks in case gui is closed
|
// we need to run the interrupt callbacks in case gui is closed
|
||||||
// this skips if we got here by actual interrupt stopping the GUI
|
// this skips if we got here by actual interrupt stopping the GUI
|
||||||
if !interrupted {
|
if !interrupted {
|
||||||
@ -113,3 +90,26 @@ func main() {
|
|||||||
}
|
}
|
||||||
logger.Flush()
|
logger.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func run(ctx *cli.Context) {
|
||||||
|
tstart := time.Now()
|
||||||
|
|
||||||
|
// TODO: show qml popup instead of exiting if initialization fails.
|
||||||
|
ethereum, err := utils.GetEthereum(ClientIdentifier, Version, ctx)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
utils.StartRPC(ethereum, ctx)
|
||||||
|
go utils.StartEthereum(ethereum)
|
||||||
|
fmt.Println("initializing eth stack took", time.Since(tstart))
|
||||||
|
|
||||||
|
// Open the window
|
||||||
|
qml.Run(func() error {
|
||||||
|
webengine.Initialize()
|
||||||
|
gui := NewWindow(ethereum)
|
||||||
|
utils.RegisterInterrupt(func(os.Signal) { gui.Stop() })
|
||||||
|
// gui blocks the main thread
|
||||||
|
gui.Start(ctx.GlobalString(assetPathFlag.Name))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -128,6 +128,7 @@ func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
|
|||||||
object := mapToTxParams(params)
|
object := mapToTxParams(params)
|
||||||
|
|
||||||
return self.XEth.Transact(
|
return self.XEth.Transact(
|
||||||
|
object["from"],
|
||||||
object["to"],
|
object["to"],
|
||||||
object["value"],
|
object["value"],
|
||||||
object["gas"],
|
object["gas"],
|
||||||
|
@ -29,13 +29,10 @@ import (
|
|||||||
|
|
||||||
"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/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
rpchttp "github.com/ethereum/go-ethereum/rpc/http"
|
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var clilogger = logger.NewLogger("CLI")
|
var clilogger = logger.NewLogger("CLI")
|
||||||
@ -97,14 +94,6 @@ func initDataDir(Datadir string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitConfig(vmType int, ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager {
|
|
||||||
initDataDir(Datadir)
|
|
||||||
cfg := ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
|
|
||||||
cfg.VmType = vmType
|
|
||||||
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
func exit(err error) {
|
func exit(err error) {
|
||||||
status := 0
|
status := 0
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -142,47 +131,6 @@ func StartEthereumForTest(ethereum *eth.Ethereum) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
|
|
||||||
var err error
|
|
||||||
switch {
|
|
||||||
case GenAddr:
|
|
||||||
if NonInteractive || confirm("This action overwrites your old private key.") {
|
|
||||||
err = keyManager.Init(KeyRing, 0, true)
|
|
||||||
}
|
|
||||||
exit(err)
|
|
||||||
case len(SecretFile) > 0:
|
|
||||||
SecretFile = ethutil.ExpandHomePath(SecretFile)
|
|
||||||
|
|
||||||
if NonInteractive || confirm("This action overwrites your old private key.") {
|
|
||||||
err = keyManager.InitFromSecretsFile(KeyRing, 0, SecretFile)
|
|
||||||
}
|
|
||||||
exit(err)
|
|
||||||
case len(ExportDir) > 0:
|
|
||||||
err = keyManager.Init(KeyRing, 0, false)
|
|
||||||
if err == nil {
|
|
||||||
err = keyManager.Export(ExportDir)
|
|
||||||
}
|
|
||||||
exit(err)
|
|
||||||
default:
|
|
||||||
// Creates a keypair if none exists
|
|
||||||
err = keyManager.Init(KeyRing, 0, false)
|
|
||||||
if err != nil {
|
|
||||||
exit(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clilogger.Infof("Main address %x\n", keyManager.Address())
|
|
||||||
}
|
|
||||||
|
|
||||||
func StartRpc(ethereum *eth.Ethereum, RpcListenAddress string, RpcPort int) {
|
|
||||||
var err error
|
|
||||||
ethereum.RpcServer, err = rpchttp.NewRpcHttpServer(xeth.New(ethereum, nil), RpcListenAddress, RpcPort)
|
|
||||||
if err != nil {
|
|
||||||
clilogger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
|
|
||||||
} else {
|
|
||||||
go ethereum.RpcServer.Start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FormatTransactionData(data string) []byte {
|
func FormatTransactionData(data string) []byte {
|
||||||
d := ethutil.StringToByteFunc(data, func(s string) (ret []byte) {
|
d := ethutil.StringToByteFunc(data, func(s string) (ret []byte) {
|
||||||
slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000)
|
slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000)
|
||||||
|
@ -2,10 +2,15 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
@ -15,8 +20,48 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
|
||||||
|
|
||||||
|
VERSION:
|
||||||
|
{{.Version}}
|
||||||
|
|
||||||
|
COMMANDS:
|
||||||
|
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
|
||||||
|
{{end}}{{if .Flags}}
|
||||||
|
GLOBAL OPTIONS:
|
||||||
|
{{range .Flags}}{{.}}
|
||||||
|
{{end}}{{end}}
|
||||||
|
`
|
||||||
|
|
||||||
|
cli.CommandHelpTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} [arguments...]
|
||||||
|
{{if .Description}}{{.Description}}
|
||||||
|
{{end}}{{if .Subcommands}}
|
||||||
|
SUBCOMMANDS:
|
||||||
|
{{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
|
||||||
|
{{end}}{{end}}{{if .Flags}}
|
||||||
|
OPTIONS:
|
||||||
|
{{range .Flags}}{{.}}
|
||||||
|
{{end}}{{end}}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewApp creates an app with sane defaults.
|
||||||
|
func NewApp(version, usage string) *cli.App {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Name = path.Base(os.Args[0])
|
||||||
|
app.Author = ""
|
||||||
|
app.Authors = nil
|
||||||
|
app.Email = ""
|
||||||
|
app.Version = version
|
||||||
|
app.Usage = usage
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
// These are all the command line flags we support.
|
// These are all the command line flags we support.
|
||||||
// If you add to this list, please remember to include the
|
// If you add to this list, please remember to include the
|
||||||
// flag in the appropriate command definition.
|
// flag in the appropriate command definition.
|
||||||
@ -32,20 +77,14 @@ var (
|
|||||||
Usage: "Virtual Machine type: 0 is standard VM, 1 is debug VM",
|
Usage: "Virtual Machine type: 0 is standard VM, 1 is debug VM",
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
UnlockedAccountFlag = cli.StringFlag{
|
||||||
|
Name: "unlock",
|
||||||
|
Usage: "Unlock a given account untill this programs exits (address:password)",
|
||||||
|
}
|
||||||
VMDebugFlag = cli.BoolFlag{
|
VMDebugFlag = cli.BoolFlag{
|
||||||
Name: "vmdebug",
|
Name: "vmdebug",
|
||||||
Usage: "Virtual Machine debug output",
|
Usage: "Virtual Machine debug output",
|
||||||
}
|
}
|
||||||
KeyRingFlag = cli.StringFlag{
|
|
||||||
Name: "keyring",
|
|
||||||
Usage: "Name of keyring to be used",
|
|
||||||
Value: "",
|
|
||||||
}
|
|
||||||
KeyStoreFlag = cli.StringFlag{
|
|
||||||
Name: "keystore",
|
|
||||||
Usage: `Where to store keyrings: "db" or "file"`,
|
|
||||||
Value: "db",
|
|
||||||
}
|
|
||||||
DataDirFlag = cli.StringFlag{
|
DataDirFlag = cli.StringFlag{
|
||||||
Name: "datadir",
|
Name: "datadir",
|
||||||
Usage: "Data directory to be used",
|
Usage: "Data directory to be used",
|
||||||
@ -149,30 +188,24 @@ func GetNodeKey(ctx *cli.Context) (key *ecdsa.PrivateKey) {
|
|||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetEthereum(clientID, version string, ctx *cli.Context) *eth.Ethereum {
|
func GetEthereum(clientID, version string, ctx *cli.Context) (*eth.Ethereum, error) {
|
||||||
ethereum, err := eth.New(ð.Config{
|
return eth.New(ð.Config{
|
||||||
Name: p2p.MakeName(clientID, version),
|
Name: p2p.MakeName(clientID, version),
|
||||||
KeyStore: ctx.GlobalString(KeyStoreFlag.Name),
|
|
||||||
DataDir: ctx.GlobalString(DataDirFlag.Name),
|
DataDir: ctx.GlobalString(DataDirFlag.Name),
|
||||||
LogFile: ctx.GlobalString(LogFileFlag.Name),
|
LogFile: ctx.GlobalString(LogFileFlag.Name),
|
||||||
LogLevel: ctx.GlobalInt(LogLevelFlag.Name),
|
LogLevel: ctx.GlobalInt(LogLevelFlag.Name),
|
||||||
LogFormat: ctx.GlobalString(LogFormatFlag.Name),
|
LogFormat: ctx.GlobalString(LogFormatFlag.Name),
|
||||||
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
|
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
|
||||||
|
AccountManager: GetAccountManager(ctx),
|
||||||
VmDebug: ctx.GlobalBool(VMDebugFlag.Name),
|
VmDebug: ctx.GlobalBool(VMDebugFlag.Name),
|
||||||
|
|
||||||
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
|
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
|
||||||
Port: ctx.GlobalString(ListenPortFlag.Name),
|
Port: ctx.GlobalString(ListenPortFlag.Name),
|
||||||
NAT: GetNAT(ctx),
|
NAT: GetNAT(ctx),
|
||||||
NodeKey: GetNodeKey(ctx),
|
NodeKey: GetNodeKey(ctx),
|
||||||
KeyRing: ctx.GlobalString(KeyRingFlag.Name),
|
|
||||||
Shh: true,
|
Shh: true,
|
||||||
Dial: true,
|
Dial: true,
|
||||||
BootNodes: ctx.GlobalString(BootnodesFlag.Name),
|
BootNodes: ctx.GlobalString(BootnodesFlag.Name),
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
exit(err)
|
|
||||||
}
|
|
||||||
return ethereum
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetChain(ctx *cli.Context) (*core.ChainManager, ethutil.Database, ethutil.Database) {
|
func GetChain(ctx *cli.Context) (*core.ChainManager, ethutil.Database, ethutil.Database) {
|
||||||
@ -188,3 +221,27 @@ func GetChain(ctx *cli.Context) (*core.ChainManager, ethutil.Database, ethutil.D
|
|||||||
}
|
}
|
||||||
return core.NewChainManager(blockDb, stateDb, new(event.TypeMux)), blockDb, stateDb
|
return core.NewChainManager(blockDb, stateDb, new(event.TypeMux)), blockDb, stateDb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global account manager
|
||||||
|
var km *accounts.Manager
|
||||||
|
|
||||||
|
func GetAccountManager(ctx *cli.Context) *accounts.Manager {
|
||||||
|
dataDir := ctx.GlobalString(DataDirFlag.Name)
|
||||||
|
if km == nil {
|
||||||
|
ks := crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys"))
|
||||||
|
km = accounts.NewManager(ks)
|
||||||
|
}
|
||||||
|
return km
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartRPC(eth *eth.Ethereum, ctx *cli.Context) {
|
||||||
|
addr := ctx.GlobalString(RPCListenAddrFlag.Name)
|
||||||
|
port := ctx.GlobalInt(RPCPortFlag.Name)
|
||||||
|
dataDir := ctx.GlobalString(DataDirFlag.Name)
|
||||||
|
|
||||||
|
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
|
||||||
|
if err != nil {
|
||||||
|
Fatalf("Can't listen on %s:%d: %v", addr, port, err)
|
||||||
|
}
|
||||||
|
go http.Serve(l, rpc.JSONRPC(xeth.New(eth, nil), dataDir))
|
||||||
|
}
|
||||||
|
@ -440,12 +440,14 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
|||||||
self.setTotalDifficulty(td)
|
self.setTotalDifficulty(td)
|
||||||
self.insert(block)
|
self.insert(block)
|
||||||
|
|
||||||
|
/* XXX crashes
|
||||||
jsonlogger.LogJson(&logger.EthChainNewHead{
|
jsonlogger.LogJson(&logger.EthChainNewHead{
|
||||||
BlockHash: ethutil.Bytes2Hex(block.Hash()),
|
BlockHash: ethutil.Bytes2Hex(block.Hash()),
|
||||||
BlockNumber: block.Number(),
|
BlockNumber: block.Number(),
|
||||||
ChainHeadHash: ethutil.Bytes2Hex(cblock.Hash()),
|
ChainHeadHash: ethutil.Bytes2Hex(cblock.Hash()),
|
||||||
BlockPrevHash: ethutil.Bytes2Hex(block.ParentHash()),
|
BlockPrevHash: ethutil.Bytes2Hex(block.ParentHash()),
|
||||||
})
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
self.setTransState(state.New(block.Root(), self.stateDb))
|
self.setTransState(state.New(block.Root(), self.stateDb))
|
||||||
queue[i] = ChainEvent{block}
|
queue[i] = ChainEvent{block}
|
||||||
|
@ -12,14 +12,12 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test fork of length N starting from block i
|
// Test fork of length N starting from block i
|
||||||
|
@ -62,8 +62,6 @@ func (tm *TestManager) Db() ethutil.Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewTestManager() *TestManager {
|
func NewTestManager() *TestManager {
|
||||||
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "ETH")
|
|
||||||
|
|
||||||
db, err := ethdb.NewMemDatabase()
|
db, err := ethdb.NewMemDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Could not create mem-db, failing")
|
fmt.Println("Could not create mem-db, failing")
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
@ -14,7 +13,6 @@ type Backend interface {
|
|||||||
PeerCount() int
|
PeerCount() int
|
||||||
IsListening() bool
|
IsListening() bool
|
||||||
Peers() []*p2p.Peer
|
Peers() []*p2p.Peer
|
||||||
KeyManager() *crypto.KeyManager
|
|
||||||
BlockDb() ethutil.Database
|
BlockDb() ethutil.Database
|
||||||
StateDb() ethutil.Database
|
StateDb() ethutil.Database
|
||||||
EventMux() *event.TypeMux
|
EventMux() *event.TypeMux
|
||||||
|
@ -45,8 +45,6 @@ type StateTransition struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Message interface {
|
type Message interface {
|
||||||
Hash() []byte
|
|
||||||
|
|
||||||
From() []byte
|
From() []byte
|
||||||
To() []byte
|
To() []byte
|
||||||
|
|
||||||
@ -153,7 +151,7 @@ func (self *StateTransition) preCheck() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) TransitionState() (ret []byte, err error) {
|
func (self *StateTransition) TransitionState() (ret []byte, err error) {
|
||||||
statelogger.Debugf("(~) %x\n", self.msg.Hash())
|
// statelogger.Debugf("(~) %x\n", self.msg.Hash())
|
||||||
|
|
||||||
// XXX Transactions after this point are considered valid.
|
// XXX Transactions after this point are considered valid.
|
||||||
if err = self.preCheck(); err != nil {
|
if err = self.preCheck(); err != nil {
|
||||||
|
@ -129,6 +129,7 @@ func (tx *Transaction) sender() []byte {
|
|||||||
return crypto.Sha3(pubkey[1:])[12:]
|
return crypto.Sha3(pubkey[1:])[12:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: deprecate after new accounts & key stores are integrated
|
||||||
func (tx *Transaction) Sign(privk []byte) error {
|
func (tx *Transaction) Sign(privk []byte) error {
|
||||||
|
|
||||||
sig := tx.Signature(privk)
|
sig := tx.Signature(privk)
|
||||||
@ -140,6 +141,13 @@ func (tx *Transaction) Sign(privk []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tx *Transaction) SetSignatureValues(sig []byte) error {
|
||||||
|
tx.R = sig[:32]
|
||||||
|
tx.S = sig[32:64]
|
||||||
|
tx.V = uint64(sig[64] + 27)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *Transaction) SignECDSA(key *ecdsa.PrivateKey) error {
|
func (tx *Transaction) SignECDSA(key *ecdsa.PrivateKey) error {
|
||||||
return tx.Sign(crypto.FromECDSA(key))
|
return tx.Sign(crypto.FromECDSA(key))
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ package crypto
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
@ -87,18 +86,16 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewKey(rand io.Reader) *Key {
|
func NewKey(rand io.Reader) *Key {
|
||||||
randBytes := make([]byte, 32)
|
randBytes := make([]byte, 64)
|
||||||
_, err := rand.Read(randBytes)
|
_, err := rand.Read(randBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("key generation: could not read from random source: " + err.Error())
|
panic("key generation: could not read from random source: " + err.Error())
|
||||||
}
|
}
|
||||||
reader := bytes.NewReader(randBytes)
|
reader := bytes.NewReader(randBytes)
|
||||||
_, x, y, err := elliptic.GenerateKey(S256(), reader)
|
privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("key generation: elliptic.GenerateKey failed: " + err.Error())
|
panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
|
||||||
}
|
}
|
||||||
privateKeyMarshalled := elliptic.Marshal(S256(), x, y)
|
|
||||||
privateKeyECDSA := ToECDSA(privateKeyMarshalled)
|
|
||||||
|
|
||||||
id := uuid.NewRandom()
|
id := uuid.NewRandom()
|
||||||
key := &Key{
|
key := &Key{
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
var keylogger = logger.NewLogger("KEY")
|
|
||||||
|
|
||||||
type KeyManager struct {
|
|
||||||
keyRing *KeyRing
|
|
||||||
session string
|
|
||||||
keyStore KeyStore // interface
|
|
||||||
keyRings map[string]*KeyRing // cache
|
|
||||||
keyPair *KeyPair
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDBKeyManager(db ethutil.Database) *KeyManager {
|
|
||||||
return &KeyManager{keyStore: &DBKeyStore{db: db}, keyRings: make(map[string]*KeyRing)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFileKeyManager(basedir string) *KeyManager {
|
|
||||||
return &KeyManager{keyStore: &FileKeyStore{basedir: basedir}, keyRings: make(map[string]*KeyRing)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) KeyPair() *KeyPair {
|
|
||||||
return k.keyPair
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) KeyRing() *KeyPair {
|
|
||||||
return k.keyPair
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) PrivateKey() []byte {
|
|
||||||
return k.keyPair.PrivateKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) PublicKey() []byte {
|
|
||||||
return k.keyPair.PublicKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) Address() []byte {
|
|
||||||
return k.keyPair.Address()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) save(session string, keyRing *KeyRing) error {
|
|
||||||
err := k.keyStore.Save(session, keyRing)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
k.keyRings[session] = keyRing
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) load(session string) (*KeyRing, error) {
|
|
||||||
keyRing, found := k.keyRings[session]
|
|
||||||
if !found {
|
|
||||||
var err error
|
|
||||||
keyRing, err = k.keyStore.Load(session)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return keyRing, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cursorError(cursor int, len int) error {
|
|
||||||
return fmt.Errorf("cursor %d out of range (0..%d)", cursor, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) reset(session string, cursor int, keyRing *KeyRing) error {
|
|
||||||
if cursor >= keyRing.Len() {
|
|
||||||
return cursorError(cursor, keyRing.Len())
|
|
||||||
}
|
|
||||||
lock := &sync.Mutex{}
|
|
||||||
lock.Lock()
|
|
||||||
defer lock.Unlock()
|
|
||||||
err := k.save(session, keyRing)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
k.session = session
|
|
||||||
k.keyRing = keyRing
|
|
||||||
k.keyPair = keyRing.GetKeyPair(cursor)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) SetCursor(cursor int) error {
|
|
||||||
if cursor >= k.keyRing.Len() {
|
|
||||||
return cursorError(cursor, k.keyRing.Len())
|
|
||||||
}
|
|
||||||
k.keyPair = k.keyRing.GetKeyPair(cursor)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) Init(session string, cursor int, force bool) error {
|
|
||||||
var keyRing *KeyRing
|
|
||||||
if !force {
|
|
||||||
var err error
|
|
||||||
keyRing, err = k.load(session)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if keyRing == nil {
|
|
||||||
keyRing = NewGeneratedKeyRing(1)
|
|
||||||
keylogger.Infof("Created keypair. Private key: %x\n", keyRing.keys[0].PrivateKey)
|
|
||||||
}
|
|
||||||
return k.reset(session, cursor, keyRing)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) InitFromSecretsFile(session string, cursor int, secretsfile string) error {
|
|
||||||
keyRing, err := NewKeyRingFromFile(secretsfile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return k.reset(session, cursor, keyRing)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) InitFromString(session string, cursor int, secrets string) error {
|
|
||||||
keyRing, err := NewKeyRingFromString(secrets)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return k.reset(session, cursor, keyRing)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyManager) Export(dir string) error {
|
|
||||||
fileKeyStore := FileKeyStore{dir}
|
|
||||||
return fileKeyStore.Save(k.session, k.keyRing)
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
type KeyStore interface {
|
|
||||||
Load(string) (*KeyRing, error)
|
|
||||||
Save(string, *KeyRing) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type DBKeyStore struct {
|
|
||||||
db ethutil.Database
|
|
||||||
}
|
|
||||||
|
|
||||||
const dbKeyPrefix = "KeyRing"
|
|
||||||
|
|
||||||
func (k *DBKeyStore) dbKey(session string) []byte {
|
|
||||||
return []byte(fmt.Sprintf("%s%s", dbKeyPrefix, session))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *DBKeyStore) Save(session string, keyRing *KeyRing) error {
|
|
||||||
k.db.Put(k.dbKey(session), keyRing.RlpEncode())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *DBKeyStore) Load(session string) (*KeyRing, error) {
|
|
||||||
data, err := k.db.Get(k.dbKey(session))
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
var keyRing *KeyRing
|
|
||||||
keyRing, err = NewKeyRingFromBytes(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// if empty keyRing is found we return nil, no error
|
|
||||||
if keyRing.Len() == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return keyRing, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type FileKeyStore struct {
|
|
||||||
basedir string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *FileKeyStore) Save(session string, keyRing *KeyRing) error {
|
|
||||||
var content []byte
|
|
||||||
var err error
|
|
||||||
var privateKeys []string
|
|
||||||
var publicKeys []string
|
|
||||||
var mnemonics []string
|
|
||||||
var addresses []string
|
|
||||||
keyRing.Each(func(keyPair *KeyPair) {
|
|
||||||
privateKeys = append(privateKeys, ethutil.Bytes2Hex(keyPair.PrivateKey))
|
|
||||||
publicKeys = append(publicKeys, ethutil.Bytes2Hex(keyPair.PublicKey))
|
|
||||||
addresses = append(addresses, ethutil.Bytes2Hex(keyPair.Address()))
|
|
||||||
mnemonics = append(mnemonics, keyPair.Mnemonic())
|
|
||||||
})
|
|
||||||
|
|
||||||
basename := session
|
|
||||||
if session == "" {
|
|
||||||
basename = "default"
|
|
||||||
}
|
|
||||||
|
|
||||||
path := path.Join(k.basedir, basename)
|
|
||||||
content = []byte(strings.Join(privateKeys, "\n"))
|
|
||||||
err = ioutil.WriteFile(path+".prv", content, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
content = []byte(strings.Join(publicKeys, "\n"))
|
|
||||||
err = ioutil.WriteFile(path+".pub", content, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
content = []byte(strings.Join(addresses, "\n"))
|
|
||||||
err = ioutil.WriteFile(path+".addr", content, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
content = []byte(strings.Join(mnemonics, "\n"))
|
|
||||||
err = ioutil.WriteFile(path+".mne", content, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *FileKeyStore) Load(session string) (*KeyRing, error) {
|
|
||||||
basename := session
|
|
||||||
if session == "" {
|
|
||||||
basename = "default"
|
|
||||||
}
|
|
||||||
secfile := path.Join(k.basedir, basename+".prv")
|
|
||||||
_, err := os.Stat(secfile)
|
|
||||||
// if file is not found then we return nil, no error
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return NewKeyRingFromFile(secfile)
|
|
||||||
}
|
|
@ -1,123 +0,0 @@
|
|||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
type KeyRing struct {
|
|
||||||
keys []*KeyPair
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewKeyRing() *KeyRing {
|
|
||||||
return &KeyRing{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyRing) AddKeyPair(keyPair *KeyPair) {
|
|
||||||
k.keys = append(k.keys, keyPair)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyRing) GetKeyPair(i int) *KeyPair {
|
|
||||||
if len(k.keys) > i {
|
|
||||||
return k.keys[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyRing) Empty() bool {
|
|
||||||
return k.Len() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyRing) Len() int {
|
|
||||||
return len(k.keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyRing) Each(f func(*KeyPair)) {
|
|
||||||
for _, keyPair := range k.keys {
|
|
||||||
f(keyPair)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewGeneratedKeyRing(len int) *KeyRing {
|
|
||||||
keyRing := NewKeyRing()
|
|
||||||
for i := 0; i < len; i++ {
|
|
||||||
keyRing.AddKeyPair(GenerateNewKeyPair())
|
|
||||||
}
|
|
||||||
return keyRing
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewKeyRingFromFile(secfile string) (*KeyRing, error) {
|
|
||||||
var content []byte
|
|
||||||
var err error
|
|
||||||
content, err = ioutil.ReadFile(secfile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
keyRing, err := NewKeyRingFromString(string(content))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return keyRing, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewKeyRingFromString(content string) (*KeyRing, error) {
|
|
||||||
secretStrings := strings.Split(content, "\n")
|
|
||||||
var secrets [][]byte
|
|
||||||
for _, secretString := range secretStrings {
|
|
||||||
secret := secretString
|
|
||||||
words := strings.Split(secretString, " ")
|
|
||||||
if len(words) == 24 {
|
|
||||||
secret = MnemonicDecode(words)
|
|
||||||
} else if len(words) != 1 {
|
|
||||||
return nil, fmt.Errorf("Unrecognised key format")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(secret) != 0 {
|
|
||||||
secrets = append(secrets, ethutil.Hex2Bytes(secret))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewKeyRingFromSecrets(secrets)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewKeyRingFromSecrets(secs [][]byte) (*KeyRing, error) {
|
|
||||||
keyRing := NewKeyRing()
|
|
||||||
for _, sec := range secs {
|
|
||||||
keyPair, err := NewKeyPairFromSec(sec)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
keyRing.AddKeyPair(keyPair)
|
|
||||||
}
|
|
||||||
return keyRing, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewKeyRingFromBytes(data []byte) (*KeyRing, error) {
|
|
||||||
var secrets [][]byte
|
|
||||||
it := ethutil.NewValueFromBytes(data).NewIterator()
|
|
||||||
for it.Next() {
|
|
||||||
secret := it.Value().Bytes()
|
|
||||||
secrets = append(secrets, secret)
|
|
||||||
}
|
|
||||||
keyRing, err := NewKeyRingFromSecrets(secrets)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return keyRing, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyRing) RlpEncode() []byte {
|
|
||||||
return k.RlpValue().Encode()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KeyRing) RlpValue() *ethutil.Value {
|
|
||||||
v := ethutil.EmptyValue()
|
|
||||||
k.Each(func(keyPair *KeyPair) {
|
|
||||||
v.Append(keyPair.RlpValue())
|
|
||||||
})
|
|
||||||
return v
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
package crypto
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
// // "io/ioutil"
|
|
||||||
// "fmt"
|
|
||||||
// "os"
|
|
||||||
// "path"
|
|
||||||
// "testing"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// // test if persistence layer works
|
|
||||||
// func TestDBKeyManager(t *testing.T) {
|
|
||||||
// memdb, _ := ethdb.NewMemDatabase()
|
|
||||||
// keyManager0 := NewDBKeyManager(memdb)
|
|
||||||
// err := keyManager0.Init("", 0, false)
|
|
||||||
// if err != nil {
|
|
||||||
// t.Error("Unexpected error: ", err)
|
|
||||||
// }
|
|
||||||
// keyManager1 := NewDBKeyManager(memdb)
|
|
||||||
// err = keyManager1.Init("", 0, false)
|
|
||||||
// if err != nil {
|
|
||||||
// t.Error("Unexpected error: ", err)
|
|
||||||
// }
|
|
||||||
// if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) {
|
|
||||||
// t.Error("Expected private keys %x, %x, to be identical via db persistence", keyManager0.PrivateKey(), keyManager1.PrivateKey())
|
|
||||||
// }
|
|
||||||
// err = keyManager1.Init("", 0, true)
|
|
||||||
// if err != nil {
|
|
||||||
// t.Error("Unexpected error: ", err)
|
|
||||||
// }
|
|
||||||
// if string(keyManager0.PrivateKey()) == string(keyManager1.PrivateKey()) {
|
|
||||||
// t.Error("Expected private keys %x, %x, to be be different despite db persistence if force generate", keyManager0.PrivateKey(), keyManager1.PrivateKey())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestFileKeyManager(t *testing.T) {
|
|
||||||
// basedir0 := "/tmp/ethtest0"
|
|
||||||
// os.RemoveAll(basedir0)
|
|
||||||
// os.Mkdir(basedir0, 0777)
|
|
||||||
|
|
||||||
// keyManager0 := NewFileKeyManager(basedir0)
|
|
||||||
// err := keyManager0.Init("", 0, false)
|
|
||||||
// if err != nil {
|
|
||||||
// t.Error("Unexpected error: ", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// keyManager1 := NewFileKeyManager(basedir0)
|
|
||||||
|
|
||||||
// err = keyManager1.Init("", 0, false)
|
|
||||||
// if err != nil {
|
|
||||||
// t.Error("Unexpected error: ", err)
|
|
||||||
// }
|
|
||||||
// if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) {
|
|
||||||
// t.Error("Expected private keys %x, %x, to be identical via db persistence", keyManager0.PrivateKey(), keyManager1.PrivateKey())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// err = keyManager1.Init("", 0, true)
|
|
||||||
// if err != nil {
|
|
||||||
// t.Error("Unexpected error: ", err)
|
|
||||||
// }
|
|
||||||
// if string(keyManager0.PrivateKey()) == string(keyManager1.PrivateKey()) {
|
|
||||||
// t.Error("Expected private keys %x, %x, to be be different despite db persistence if force generate", keyManager0.PrivateKey(), keyManager1.PrivateKey())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // cursor errors
|
|
||||||
// func TestCursorErrors(t *testing.T) {
|
|
||||||
// memdb, _ := ethdb.NewMemDatabase()
|
|
||||||
// keyManager0 := NewDBKeyManager(memdb)
|
|
||||||
// err := keyManager0.Init("", 0, false)
|
|
||||||
// err = keyManager0.Init("", 1, false)
|
|
||||||
// if err == nil {
|
|
||||||
// t.Error("Expected cursor error")
|
|
||||||
// }
|
|
||||||
// err = keyManager0.SetCursor(1)
|
|
||||||
// if err == nil {
|
|
||||||
// t.Error("Expected cursor error")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestExportImport(t *testing.T) {
|
|
||||||
// memdb, _ := ethdb.NewMemDatabase()
|
|
||||||
// keyManager0 := NewDBKeyManager(memdb)
|
|
||||||
// err := keyManager0.Init("", 0, false)
|
|
||||||
// basedir0 := "/tmp/ethtest0"
|
|
||||||
// os.RemoveAll(basedir0)
|
|
||||||
// os.Mkdir(basedir0, 0777)
|
|
||||||
// keyManager0.Export(basedir0)
|
|
||||||
|
|
||||||
// keyManager1 := NewFileKeyManager(basedir0)
|
|
||||||
// err = keyManager1.Init("", 0, false)
|
|
||||||
// if err != nil {
|
|
||||||
// t.Error("Unexpected error: ", err)
|
|
||||||
// }
|
|
||||||
// fmt.Printf("keyRing: %v\n", keyManager0.KeyPair())
|
|
||||||
// fmt.Printf("keyRing: %v\n", keyManager1.KeyPair())
|
|
||||||
// if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) {
|
|
||||||
// t.Error("Expected private keys %x, %x, to be identical via export to filestore basedir", keyManager0.PrivateKey(), keyManager1.PrivateKey())
|
|
||||||
// }
|
|
||||||
// path.Join("")
|
|
||||||
|
|
||||||
// // memdb, _ = ethdb.NewMemDatabase()
|
|
||||||
// // keyManager2 := NewDBKeyManager(memdb)
|
|
||||||
// // err = keyManager2.InitFromSecretsFile("", 0, path.Join(basedir0, "default.prv"))
|
|
||||||
// // if err != nil {
|
|
||||||
// // t.Error("Unexpected error: ", err)
|
|
||||||
// // }
|
|
||||||
// // if string(keyManager0.PrivateKey()) != string(keyManager2.PrivateKey()) {
|
|
||||||
// // t.Error("Expected private keys %s, %s, to be identical via export/import prv", keyManager0.PrivateKey(), keyManager1.PrivateKey())
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // memdb, _ = ethdb.NewMemDatabase()
|
|
||||||
// // keyManager3 := NewDBKeyManager(memdb)
|
|
||||||
// // err = keyManager3.InitFromSecretsFile("", 0, path.Join(basedir0, "default.mne"))
|
|
||||||
// // if err != nil {
|
|
||||||
// // t.Error("Unexpected error: ", err)
|
|
||||||
// // }
|
|
||||||
// // if string(keyManager0.PrivateKey()) != string(keyManager3.PrivateKey()) {
|
|
||||||
// // t.Error("Expected private keys %s, %s, to be identical via export/import mnemonic file", keyManager0.PrivateKey(), keyManager1.PrivateKey())
|
|
||||||
// // }
|
|
||||||
// }
|
|
@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/ethash"
|
"github.com/ethereum/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/blockpool"
|
"github.com/ethereum/go-ethereum/blockpool"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
@ -19,13 +20,12 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
|
||||||
"github.com/ethereum/go-ethereum/vm"
|
"github.com/ethereum/go-ethereum/vm"
|
||||||
"github.com/ethereum/go-ethereum/whisper"
|
"github.com/ethereum/go-ethereum/whisper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ethlogger = logger.NewLogger("SERV")
|
servlogger = logger.NewLogger("SERV")
|
||||||
jsonlogger = logger.NewJsonLogger()
|
jsonlogger = logger.NewJsonLogger()
|
||||||
|
|
||||||
defaultBootNodes = []*discover.Node{
|
defaultBootNodes = []*discover.Node{
|
||||||
@ -38,11 +38,9 @@ var (
|
|||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Name string
|
Name string
|
||||||
KeyStore string
|
|
||||||
DataDir string
|
DataDir string
|
||||||
LogFile string
|
LogFile string
|
||||||
LogLevel int
|
LogLevel int
|
||||||
KeyRing string
|
|
||||||
LogFormat string
|
LogFormat string
|
||||||
VmDebug bool
|
VmDebug bool
|
||||||
|
|
||||||
@ -62,8 +60,7 @@ type Config struct {
|
|||||||
Dial bool
|
Dial bool
|
||||||
|
|
||||||
MinerThreads int
|
MinerThreads int
|
||||||
|
AccountManager *accounts.Manager
|
||||||
KeyManager *crypto.KeyManager
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) parseBootNodes() []*discover.Node {
|
func (cfg *Config) parseBootNodes() []*discover.Node {
|
||||||
@ -77,7 +74,7 @@ func (cfg *Config) parseBootNodes() []*discover.Node {
|
|||||||
}
|
}
|
||||||
n, err := discover.ParseNode(url)
|
n, err := discover.ParseNode(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ethlogger.Errorf("Bootstrap URL %s: %v\n", url, err)
|
servlogger.Errorf("Bootstrap URL %s: %v\n", url, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ns = append(ns, n)
|
ns = append(ns, n)
|
||||||
@ -101,7 +98,7 @@ func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) {
|
|||||||
return nil, fmt.Errorf("could not generate server key: %v", err)
|
return nil, fmt.Errorf("could not generate server key: %v", err)
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(keyfile, crypto.FromECDSA(key), 0600); err != nil {
|
if err := ioutil.WriteFile(keyfile, crypto.FromECDSA(key), 0600); err != nil {
|
||||||
ethlogger.Errorln("could not persist nodekey: ", err)
|
servlogger.Errorln("could not persist nodekey: ", err)
|
||||||
}
|
}
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
@ -120,6 +117,7 @@ type Ethereum struct {
|
|||||||
txPool *core.TxPool
|
txPool *core.TxPool
|
||||||
chainManager *core.ChainManager
|
chainManager *core.ChainManager
|
||||||
blockPool *blockpool.BlockPool
|
blockPool *blockpool.BlockPool
|
||||||
|
accountManager *accounts.Manager
|
||||||
whisper *whisper.Whisper
|
whisper *whisper.Whisper
|
||||||
|
|
||||||
net *p2p.Server
|
net *p2p.Server
|
||||||
@ -128,9 +126,6 @@ type Ethereum struct {
|
|||||||
blockSub event.Subscription
|
blockSub event.Subscription
|
||||||
miner *miner.Miner
|
miner *miner.Miner
|
||||||
|
|
||||||
RpcServer rpc.RpcServer
|
|
||||||
keyManager *crypto.KeyManager
|
|
||||||
|
|
||||||
logger logger.LogSystem
|
logger logger.LogSystem
|
||||||
|
|
||||||
Mining bool
|
Mining bool
|
||||||
@ -139,7 +134,7 @@ type Ethereum struct {
|
|||||||
|
|
||||||
func New(config *Config) (*Ethereum, error) {
|
func New(config *Config) (*Ethereum, error) {
|
||||||
// Boostrap database
|
// Boostrap database
|
||||||
ethlogger := logger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat)
|
servlogger := logger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat)
|
||||||
|
|
||||||
blockDb, err := ethdb.NewLDBDatabase(path.Join(config.DataDir, "blockchain"))
|
blockDb, err := ethdb.NewLDBDatabase(path.Join(config.DataDir, "blockchain"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -158,19 +153,6 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, path)
|
return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new keymanager
|
|
||||||
var keyManager *crypto.KeyManager
|
|
||||||
switch config.KeyStore {
|
|
||||||
case "db":
|
|
||||||
keyManager = crypto.NewDBKeyManager(blockDb)
|
|
||||||
case "file":
|
|
||||||
keyManager = crypto.NewFileKeyManager(config.DataDir)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown keystore type: %s", config.KeyStore)
|
|
||||||
}
|
|
||||||
// Initialise the keyring
|
|
||||||
keyManager.Init(config.KeyRing, 0, false)
|
|
||||||
|
|
||||||
saveProtocolVersion(blockDb)
|
saveProtocolVersion(blockDb)
|
||||||
//ethutil.Config.Db = db
|
//ethutil.Config.Db = db
|
||||||
|
|
||||||
@ -178,20 +160,24 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
shutdownChan: make(chan bool),
|
shutdownChan: make(chan bool),
|
||||||
blockDb: blockDb,
|
blockDb: blockDb,
|
||||||
stateDb: stateDb,
|
stateDb: stateDb,
|
||||||
keyManager: keyManager,
|
|
||||||
eventMux: &event.TypeMux{},
|
eventMux: &event.TypeMux{},
|
||||||
logger: ethlogger,
|
logger: servlogger,
|
||||||
|
accountManager: config.AccountManager,
|
||||||
DataDir: config.DataDir,
|
DataDir: config.DataDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cb, err := eth.accountManager.Coinbase()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.EventMux())
|
eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.EventMux())
|
||||||
pow := ethash.New(eth.chainManager)
|
pow := ethash.New(eth.chainManager)
|
||||||
|
|
||||||
eth.txPool = core.NewTxPool(eth.EventMux())
|
eth.txPool = core.NewTxPool(eth.EventMux())
|
||||||
eth.blockProcessor = core.NewBlockProcessor(stateDb, pow, eth.txPool, eth.chainManager, eth.EventMux())
|
eth.blockProcessor = core.NewBlockProcessor(stateDb, pow, eth.txPool, eth.chainManager, eth.EventMux())
|
||||||
eth.chainManager.SetProcessor(eth.blockProcessor)
|
eth.chainManager.SetProcessor(eth.blockProcessor)
|
||||||
eth.whisper = whisper.New()
|
eth.whisper = whisper.New()
|
||||||
eth.miner = miner.New(keyManager.Address(), eth, pow, config.MinerThreads)
|
eth.miner = miner.New(cb, eth, pow, config.MinerThreads)
|
||||||
|
|
||||||
hasBlock := eth.chainManager.HasBlock
|
hasBlock := eth.chainManager.HasBlock
|
||||||
insertChain := eth.chainManager.InsertChain
|
insertChain := eth.chainManager.InsertChain
|
||||||
@ -225,9 +211,9 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
return eth, nil
|
return eth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) KeyManager() *crypto.KeyManager { return s.keyManager }
|
|
||||||
func (s *Ethereum) Logger() logger.LogSystem { return s.logger }
|
func (s *Ethereum) Logger() logger.LogSystem { return s.logger }
|
||||||
func (s *Ethereum) Name() string { return s.net.Name }
|
func (s *Ethereum) Name() string { return s.net.Name }
|
||||||
|
func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager }
|
||||||
func (s *Ethereum) ChainManager() *core.ChainManager { return s.chainManager }
|
func (s *Ethereum) ChainManager() *core.ChainManager { return s.chainManager }
|
||||||
func (s *Ethereum) BlockProcessor() *core.BlockProcessor { return s.blockProcessor }
|
func (s *Ethereum) BlockProcessor() *core.BlockProcessor { return s.blockProcessor }
|
||||||
func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
|
func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
|
||||||
@ -241,7 +227,6 @@ func (s *Ethereum) IsListening() bool { return true } // Alwa
|
|||||||
func (s *Ethereum) PeerCount() int { return s.net.PeerCount() }
|
func (s *Ethereum) PeerCount() int { return s.net.PeerCount() }
|
||||||
func (s *Ethereum) Peers() []*p2p.Peer { return s.net.Peers() }
|
func (s *Ethereum) Peers() []*p2p.Peer { return s.net.Peers() }
|
||||||
func (s *Ethereum) MaxPeers() int { return s.net.MaxPeers }
|
func (s *Ethereum) MaxPeers() int { return s.net.MaxPeers }
|
||||||
func (s *Ethereum) Coinbase() []byte { return nil } // TODO
|
|
||||||
|
|
||||||
// Start the ethereum
|
// Start the ethereum
|
||||||
func (s *Ethereum) Start() error {
|
func (s *Ethereum) Start() error {
|
||||||
@ -271,7 +256,7 @@ func (s *Ethereum) Start() error {
|
|||||||
s.blockSub = s.eventMux.Subscribe(core.NewMinedBlockEvent{})
|
s.blockSub = s.eventMux.Subscribe(core.NewMinedBlockEvent{})
|
||||||
go s.blockBroadcastLoop()
|
go s.blockBroadcastLoop()
|
||||||
|
|
||||||
ethlogger.Infoln("Server started")
|
servlogger.Infoln("Server started")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,10 +288,6 @@ func (s *Ethereum) Stop() {
|
|||||||
s.txSub.Unsubscribe() // quits txBroadcastLoop
|
s.txSub.Unsubscribe() // quits txBroadcastLoop
|
||||||
s.blockSub.Unsubscribe() // quits blockBroadcastLoop
|
s.blockSub.Unsubscribe() // quits blockBroadcastLoop
|
||||||
|
|
||||||
if s.RpcServer != nil {
|
|
||||||
s.RpcServer.Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
s.txPool.Stop()
|
s.txPool.Stop()
|
||||||
s.eventMux.Stop()
|
s.eventMux.Stop()
|
||||||
s.blockPool.Stop()
|
s.blockPool.Stop()
|
||||||
@ -314,7 +295,7 @@ func (s *Ethereum) Stop() {
|
|||||||
s.whisper.Stop()
|
s.whisper.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
ethlogger.Infoln("Server stopped")
|
servlogger.Infoln("Server stopped")
|
||||||
close(s.shutdownChan)
|
close(s.shutdownChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestCompression(t *testing.T) {
|
func TestCompression(t *testing.T) {
|
||||||
ethutil.ReadConfig("", "/tmp", "")
|
|
||||||
|
|
||||||
db, err := NewLDBDatabase("testdb")
|
db, err := NewLDBDatabase("testdb")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
"github.com/obscuren/otto"
|
"github.com/obscuren/otto"
|
||||||
|
@ -70,8 +70,8 @@ func (self *JSEthereum) GetStateObject(addr string) otto.Value {
|
|||||||
return self.toVal(&JSStateObject{self.XEth.State().SafeGet(addr), self})
|
return self.toVal(&JSStateObject{self.XEth.State().SafeGet(addr), self})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *JSEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value {
|
func (self *JSEthereum) Transact(fromStr, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value {
|
||||||
r, err := self.XEth.Transact(recipient, valueStr, gasStr, gasPriceStr, dataStr)
|
r, err := self.XEth.Transact(fromStr, recipient, valueStr, gasStr, gasPriceStr, dataStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
|
||||||
|
36
rpc/api.go
36
rpc/api.go
@ -2,7 +2,9 @@ package rpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -46,8 +48,8 @@ type EthereumApi struct {
|
|||||||
// defaultBlockAge int64
|
// defaultBlockAge int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEthereumApi(eth *xeth.XEth) *EthereumApi {
|
func NewEthereumApi(eth *xeth.XEth, dataDir string) *EthereumApi {
|
||||||
db, _ := ethdb.NewLDBDatabase("dapps")
|
db, _ := ethdb.NewLDBDatabase(path.Join(dataDir, "dapps"))
|
||||||
api := &EthereumApi{
|
api := &EthereumApi{
|
||||||
eth: eth,
|
eth: eth,
|
||||||
mux: eth.Backend().EventMux(),
|
mux: eth.Backend().EventMux(),
|
||||||
@ -232,15 +234,7 @@ func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
|
func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) (err error) {
|
||||||
if args.Gas == ethutil.Big0 {
|
|
||||||
args.Gas = defaultGas
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.GasPrice == ethutil.Big0 {
|
|
||||||
args.GasPrice = defaultGasPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO if no_private_key then
|
// TODO if no_private_key then
|
||||||
//if _, exists := p.register[args.From]; exists {
|
//if _, exists := p.register[args.From]; exists {
|
||||||
// p.register[args.From] = append(p.register[args.From], args)
|
// p.register[args.From] = append(p.register[args.From], args)
|
||||||
@ -262,18 +256,28 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
|
|||||||
p.register[ags.From] = append(p.register[args.From], args)
|
p.register[ags.From] = append(p.register[args.From], args)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
result, err := p.xeth().Transact( /* TODO specify account */ args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
|
// TODO: align default values to have the same type, e.g. not depend on
|
||||||
|
// ethutil.Value conversions later on
|
||||||
|
fmt.Println("gas", args.Gas)
|
||||||
|
if args.Gas.Cmp(big.NewInt(0)) == 0 {
|
||||||
|
args.Gas = defaultGas
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.GasPrice.Cmp(big.NewInt(0)) == 0 {
|
||||||
|
args.GasPrice = defaultGasPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
*reply, err = p.xeth().Transact(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
*reply = result
|
|
||||||
//}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error {
|
func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error {
|
||||||
result, err := p.xeth().Call( /* TODO specify account */ args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
|
result, err := p.xeth().Call(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -556,7 +560,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return p.GetData(args, reply)
|
return p.GetData(args, reply)
|
||||||
case "eth_sendTransaction":
|
case "eth_sendTransaction", "eth_transact":
|
||||||
args := new(NewTxArgs)
|
args := new(NewTxArgs)
|
||||||
if err := json.Unmarshal(req.Params, &args); err != nil {
|
if err := json.Unmarshal(req.Params, &args); err != nil {
|
||||||
return err
|
return err
|
||||||
|
52
rpc/http.go
Normal file
52
rpc/http.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rpchttplogger = logger.NewLogger("RPC-HTTP")
|
||||||
|
|
||||||
|
const (
|
||||||
|
jsonrpcver = "2.0"
|
||||||
|
maxSizeReqLength = 1024 * 1024 // 1MB
|
||||||
|
)
|
||||||
|
|
||||||
|
// JSONRPC returns a handler that implements the Ethereum JSON-RPC API.
|
||||||
|
func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
|
||||||
|
var json JsonWrapper
|
||||||
|
api := NewEthereumApi(pipe, dataDir)
|
||||||
|
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
|
||||||
|
rpchttplogger.DebugDetailln("Handling request")
|
||||||
|
|
||||||
|
if req.ContentLength > maxSizeReqLength {
|
||||||
|
jsonerr := &RpcErrorObject{-32700, "Error: Request too large"}
|
||||||
|
json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reqParsed, reqerr := json.ParseRequestBody(req)
|
||||||
|
if reqerr != nil {
|
||||||
|
jsonerr := &RpcErrorObject{-32700, "Error: Could not parse request"}
|
||||||
|
json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response interface{}
|
||||||
|
reserr := api.GetRequestReply(&reqParsed, &response)
|
||||||
|
if reserr != nil {
|
||||||
|
rpchttplogger.Warnln(reserr)
|
||||||
|
jsonerr := &RpcErrorObject{-32603, reserr.Error()}
|
||||||
|
json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rpchttplogger.DebugDetailf("Generated response: %T %s", response, response)
|
||||||
|
json.Send(w, &RpcSuccessResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Result: response})
|
||||||
|
})
|
||||||
|
}
|
@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of go-ethereum
|
|
||||||
|
|
||||||
go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
go-ethereum is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package rpchttp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
|
||||||
)
|
|
||||||
|
|
||||||
var rpchttplogger = logger.NewLogger("RPC-HTTP")
|
|
||||||
var JSON rpc.JsonWrapper
|
|
||||||
|
|
||||||
const maxSizeReqLength = 1024 * 1024 // 1MB
|
|
||||||
|
|
||||||
func NewRpcHttpServer(pipe *xeth.XEth, address string, port int) (*RpcHttpServer, error) {
|
|
||||||
sport := fmt.Sprintf("%s:%d", address, port)
|
|
||||||
l, err := net.Listen("tcp", sport)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &RpcHttpServer{
|
|
||||||
listener: l,
|
|
||||||
quit: make(chan bool),
|
|
||||||
pipe: pipe,
|
|
||||||
port: port,
|
|
||||||
addr: address,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type RpcHttpServer struct {
|
|
||||||
quit chan bool
|
|
||||||
listener net.Listener
|
|
||||||
pipe *xeth.XEth
|
|
||||||
port int
|
|
||||||
addr string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RpcHttpServer) exitHandler() {
|
|
||||||
out:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-s.quit:
|
|
||||||
s.listener.Close()
|
|
||||||
break out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rpchttplogger.Infoln("Shutdown RPC-HTTP server")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RpcHttpServer) Stop() {
|
|
||||||
close(s.quit)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RpcHttpServer) Start() {
|
|
||||||
rpchttplogger.Infof("Starting RPC-HTTP server on %s:%d", s.addr, s.port)
|
|
||||||
go s.exitHandler()
|
|
||||||
|
|
||||||
api := rpc.NewEthereumApi(s.pipe)
|
|
||||||
h := s.apiHandler(api)
|
|
||||||
http.Handle("/", h)
|
|
||||||
|
|
||||||
err := http.Serve(s.listener, nil)
|
|
||||||
// FIX Complains on shutdown due to listner already being closed
|
|
||||||
if err != nil {
|
|
||||||
rpchttplogger.Errorln("Error on RPC-HTTP interface:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RpcHttpServer) apiHandler(api *rpc.EthereumApi) http.Handler {
|
|
||||||
var jsonrpcver string = "2.0"
|
|
||||||
fn := func(w http.ResponseWriter, req *http.Request) {
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
||||||
|
|
||||||
rpchttplogger.DebugDetailln("Handling request")
|
|
||||||
|
|
||||||
if req.ContentLength > maxSizeReqLength {
|
|
||||||
jsonerr := &rpc.RpcErrorObject{-32700, "Error: Request too large"}
|
|
||||||
JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
reqParsed, reqerr := JSON.ParseRequestBody(req)
|
|
||||||
if reqerr != nil {
|
|
||||||
jsonerr := &rpc.RpcErrorObject{-32700, "Error: Could not parse request"}
|
|
||||||
JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var response interface{}
|
|
||||||
reserr := api.GetRequestReply(&reqParsed, &response)
|
|
||||||
if reserr != nil {
|
|
||||||
rpchttplogger.Warnln(reserr)
|
|
||||||
jsonerr := &rpc.RpcErrorObject{-32603, reserr.Error()}
|
|
||||||
JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rpchttplogger.DebugDetailf("Generated response: %T %s", response, response)
|
|
||||||
JSON.Send(w, &rpc.RpcSuccessResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Result: response})
|
|
||||||
}
|
|
||||||
|
|
||||||
return http.HandlerFunc(fn)
|
|
||||||
}
|
|
@ -33,16 +33,16 @@ func (s *StateSuite) TestDump(c *checker.C) {
|
|||||||
// check that dump contains the state objects that are in trie
|
// check that dump contains the state objects that are in trie
|
||||||
got := string(s.state.Dump())
|
got := string(s.state.Dump())
|
||||||
want := `{
|
want := `{
|
||||||
"root": "4e3a59299745ba6752247c8b91d0f716dac9ec235861c91f5ac1894a361d87ba",
|
"root": "6e277ae8357d013e50f74eedb66a991f6922f93ae03714de58b3d0c5e9eee53f",
|
||||||
"accounts": {
|
"accounts": {
|
||||||
"0000000000000000000000000000000000000001": {
|
"1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d": {
|
||||||
"balance": "22",
|
"balance": "22",
|
||||||
"nonce": 0,
|
"nonce": 0,
|
||||||
"root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
"root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||||
"codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
"codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
||||||
"storage": {}
|
"storage": {}
|
||||||
},
|
},
|
||||||
"0000000000000000000000000000000000000102": {
|
"a17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1": {
|
||||||
"balance": "0",
|
"balance": "0",
|
||||||
"nonce": 0,
|
"nonce": 0,
|
||||||
"root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
"root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||||
@ -57,7 +57,6 @@ func (s *StateSuite) TestDump(c *checker.C) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateSuite) SetUpTest(c *checker.C) {
|
func (s *StateSuite) SetUpTest(c *checker.C) {
|
||||||
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
s.state = New(nil, db)
|
s.state = New(nil, db)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
|
||||||
logpkg "github.com/ethereum/go-ethereum/logger"
|
logpkg "github.com/ethereum/go-ethereum/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,6 +13,4 @@ var Log = logpkg.NewLogger("TEST")
|
|||||||
func init() {
|
func init() {
|
||||||
Logger = logpkg.NewStdLogSystem(os.Stdout, log.LstdFlags, logpkg.InfoLevel)
|
Logger = logpkg.NewStdLogSystem(os.Stdout, log.LstdFlags, logpkg.InfoLevel)
|
||||||
logpkg.AddLogSystem(Logger)
|
logpkg.AddLogSystem(Logger)
|
||||||
|
|
||||||
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
package ui
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/core/types"
|
|
||||||
|
|
||||||
type Interface interface {
|
|
||||||
UnlockAccount(address []byte) bool
|
|
||||||
ConfirmTransaction(tx *types.Transaction) bool
|
|
||||||
}
|
|
@ -38,11 +38,11 @@ func (self *peer) init() error {
|
|||||||
|
|
||||||
func (self *peer) start() {
|
func (self *peer) start() {
|
||||||
go self.update()
|
go self.update()
|
||||||
self.peer.Infoln("whisper started")
|
self.peer.Debugln("whisper started")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *peer) stop() {
|
func (self *peer) stop() {
|
||||||
self.peer.Infoln("whisper stopped")
|
self.peer.Debugln("whisper stopped")
|
||||||
|
|
||||||
close(self.quit)
|
close(self.quit)
|
||||||
}
|
}
|
||||||
|
163
xeth/xeth.go
163
xeth/xeth.go
@ -1,14 +1,13 @@
|
|||||||
|
// eXtended ETHereum
|
||||||
package xeth
|
package xeth
|
||||||
|
|
||||||
/*
|
|
||||||
* eXtended ETHereum
|
|
||||||
*/
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"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/crypto"
|
||||||
@ -18,7 +17,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
"github.com/ethereum/go-ethereum/ui"
|
|
||||||
"github.com/ethereum/go-ethereum/whisper"
|
"github.com/ethereum/go-ethereum/whisper"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,11 +26,11 @@ var pipelogger = logger.NewLogger("XETH")
|
|||||||
type Backend interface {
|
type Backend interface {
|
||||||
BlockProcessor() *core.BlockProcessor
|
BlockProcessor() *core.BlockProcessor
|
||||||
ChainManager() *core.ChainManager
|
ChainManager() *core.ChainManager
|
||||||
|
AccountManager() *accounts.Manager
|
||||||
TxPool() *core.TxPool
|
TxPool() *core.TxPool
|
||||||
PeerCount() int
|
PeerCount() int
|
||||||
IsListening() bool
|
IsListening() bool
|
||||||
Peers() []*p2p.Peer
|
Peers() []*p2p.Peer
|
||||||
KeyManager() *crypto.KeyManager
|
|
||||||
BlockDb() ethutil.Database
|
BlockDb() ethutil.Database
|
||||||
StateDb() ethutil.Database
|
StateDb() ethutil.Database
|
||||||
EventMux() *event.TypeMux
|
EventMux() *event.TypeMux
|
||||||
@ -40,37 +38,62 @@ type Backend interface {
|
|||||||
Miner() *miner.Miner
|
Miner() *miner.Miner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Frontend should be implemented by users of XEth. Its methods are
|
||||||
|
// called whenever XEth makes a decision that requires user input.
|
||||||
|
type Frontend interface {
|
||||||
|
// UnlockAccount is called when a transaction needs to be signed
|
||||||
|
// but the key corresponding to the transaction's sender is
|
||||||
|
// locked.
|
||||||
|
//
|
||||||
|
// It should unlock the account with the given address and return
|
||||||
|
// true if unlocking succeeded.
|
||||||
|
UnlockAccount(address []byte) bool
|
||||||
|
|
||||||
|
// This is called for all transactions inititated through
|
||||||
|
// Transact. It should prompt the user to confirm the transaction
|
||||||
|
// and return true if the transaction was acknowledged.
|
||||||
|
//
|
||||||
|
// ConfirmTransaction is not used for Call transactions
|
||||||
|
// because they cannot change any state.
|
||||||
|
ConfirmTransaction(tx *types.Transaction) bool
|
||||||
|
}
|
||||||
|
|
||||||
type XEth struct {
|
type XEth struct {
|
||||||
eth Backend
|
eth Backend
|
||||||
blockProcessor *core.BlockProcessor
|
blockProcessor *core.BlockProcessor
|
||||||
chainManager *core.ChainManager
|
chainManager *core.ChainManager
|
||||||
|
accountManager *accounts.Manager
|
||||||
state *State
|
state *State
|
||||||
whisper *Whisper
|
whisper *Whisper
|
||||||
miner *miner.Miner
|
miner *miner.Miner
|
||||||
|
|
||||||
frontend ui.Interface
|
frontend Frontend
|
||||||
}
|
}
|
||||||
|
|
||||||
type TmpFrontend struct{}
|
// dummyFrontend is a non-interactive frontend that allows all
|
||||||
|
// transactions but cannot not unlock any keys.
|
||||||
|
type dummyFrontend struct{}
|
||||||
|
|
||||||
func (TmpFrontend) UnlockAccount([]byte) bool { panic("UNLOCK ACCOUNT") }
|
func (dummyFrontend) UnlockAccount([]byte) bool { return false }
|
||||||
func (TmpFrontend) ConfirmTransaction(*types.Transaction) bool { panic("CONFIRM TRANSACTION") }
|
func (dummyFrontend) ConfirmTransaction(*types.Transaction) bool { return true }
|
||||||
|
|
||||||
func New(eth Backend, frontend ui.Interface) *XEth {
|
// New creates an XEth that uses the given frontend.
|
||||||
|
// If a nil Frontend is provided, a default frontend which
|
||||||
|
// confirms all transactions will be used.
|
||||||
|
func New(eth Backend, frontend Frontend) *XEth {
|
||||||
xeth := &XEth{
|
xeth := &XEth{
|
||||||
eth: eth,
|
eth: eth,
|
||||||
blockProcessor: eth.BlockProcessor(),
|
blockProcessor: eth.BlockProcessor(),
|
||||||
chainManager: eth.ChainManager(),
|
chainManager: eth.ChainManager(),
|
||||||
|
accountManager: eth.AccountManager(),
|
||||||
whisper: NewWhisper(eth.Whisper()),
|
whisper: NewWhisper(eth.Whisper()),
|
||||||
miner: eth.Miner(),
|
miner: eth.Miner(),
|
||||||
|
frontend: frontend,
|
||||||
}
|
}
|
||||||
|
|
||||||
if frontend == nil {
|
if frontend == nil {
|
||||||
xeth.frontend = TmpFrontend{}
|
xeth.frontend = dummyFrontend{}
|
||||||
}
|
}
|
||||||
|
|
||||||
xeth.state = NewState(xeth, xeth.chainManager.TransState())
|
xeth.state = NewState(xeth, xeth.chainManager.TransState())
|
||||||
|
|
||||||
return xeth
|
return xeth
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +158,13 @@ func (self *XEth) Block(v interface{}) *Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) Accounts() []string {
|
func (self *XEth) Accounts() []string {
|
||||||
return []string{toHex(self.eth.KeyManager().Address())}
|
// TODO: check err?
|
||||||
|
accounts, _ := self.eth.AccountManager().Accounts()
|
||||||
|
accountAddresses := make([]string, len(accounts))
|
||||||
|
for i, ac := range accounts {
|
||||||
|
accountAddresses[i] = toHex(ac.Address)
|
||||||
|
}
|
||||||
|
return accountAddresses
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) PeerCount() int {
|
func (self *XEth) PeerCount() int {
|
||||||
@ -162,7 +191,8 @@ func (self *XEth) IsListening() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) Coinbase() string {
|
func (self *XEth) Coinbase() string {
|
||||||
return toHex(self.eth.KeyManager().Address())
|
cb, _ := self.eth.AccountManager().Coinbase()
|
||||||
|
return toHex(cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) NumberToHuman(balance string) string {
|
func (self *XEth) NumberToHuman(balance string) string {
|
||||||
@ -263,7 +293,7 @@ func (self *XEth) PushTx(encodedTx string) (string, error) {
|
|||||||
return toHex(tx.Hash()), nil
|
return toHex(tx.Hash()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) Call(toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) {
|
func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) {
|
||||||
if len(gasStr) == 0 {
|
if len(gasStr) == 0 {
|
||||||
gasStr = "100000"
|
gasStr = "100000"
|
||||||
}
|
}
|
||||||
@ -271,41 +301,34 @@ func (self *XEth) Call(toStr, valueStr, gasStr, gasPriceStr, dataStr string) (st
|
|||||||
gasPriceStr = "1"
|
gasPriceStr = "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
statedb := self.State().State() //self.chainManager.TransState()
|
||||||
statedb = self.State().State() //self.chainManager.TransState()
|
msg := callmsg{
|
||||||
key = self.eth.KeyManager().KeyPair()
|
from: statedb.GetOrNewStateObject(fromHex(fromStr)),
|
||||||
from = statedb.GetOrNewStateObject(key.Address())
|
to: fromHex(toStr),
|
||||||
block = self.chainManager.CurrentBlock()
|
gas: ethutil.Big(gasStr),
|
||||||
to = statedb.GetOrNewStateObject(fromHex(toStr))
|
gasPrice: ethutil.Big(gasPriceStr),
|
||||||
data = fromHex(dataStr)
|
value: ethutil.Big(valueStr),
|
||||||
gas = ethutil.Big(gasStr)
|
data: fromHex(dataStr),
|
||||||
price = ethutil.Big(gasPriceStr)
|
}
|
||||||
value = ethutil.Big(valueStr)
|
block := self.chainManager.CurrentBlock()
|
||||||
)
|
|
||||||
|
|
||||||
msg := types.NewTransactionMessage(fromHex(toStr), value, gas, price, data)
|
|
||||||
msg.Sign(key.PrivateKey)
|
|
||||||
vmenv := core.NewEnv(statedb, self.chainManager, msg, block)
|
vmenv := core.NewEnv(statedb, self.chainManager, msg, block)
|
||||||
|
|
||||||
res, err := vmenv.Call(from, to.Address(), data, gas, price, value)
|
res, err := vmenv.Call(msg.from, msg.to, msg.data, msg.gas, msg.gasPrice, msg.value)
|
||||||
if err != nil {
|
return toHex(res), err
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return toHex(res), nil
|
func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
||||||
}
|
|
||||||
|
|
||||||
func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
|
||||||
var (
|
var (
|
||||||
|
from []byte
|
||||||
to []byte
|
to []byte
|
||||||
value = ethutil.NewValue(valueStr)
|
value = ethutil.NewValue(valueStr)
|
||||||
gas = ethutil.NewValue(gasStr)
|
gas = ethutil.NewValue(gasStr)
|
||||||
price = ethutil.NewValue(gasPriceStr)
|
price = ethutil.NewValue(gasPriceStr)
|
||||||
data []byte
|
data []byte
|
||||||
key = self.eth.KeyManager().KeyPair()
|
|
||||||
contractCreation bool
|
contractCreation bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from = fromHex(fromStr)
|
||||||
data = fromHex(codeStr)
|
data = fromHex(codeStr)
|
||||||
to = fromHex(toStr)
|
to = fromHex(toStr)
|
||||||
if len(to) == 0 {
|
if len(to) == 0 {
|
||||||
@ -319,25 +342,61 @@ func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string)
|
|||||||
tx = types.NewTransactionMessage(to, value.BigInt(), gas.BigInt(), price.BigInt(), data)
|
tx = types.NewTransactionMessage(to, value.BigInt(), gas.BigInt(), price.BigInt(), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
state := self.chainManager.TxState()
|
||||||
state := self.eth.ChainManager().TxState()
|
nonce := state.GetNonce(from)
|
||||||
if balance := state.GetBalance(key.Address()); balance.Cmp(tx.Value()) < 0 {
|
|
||||||
return "", fmt.Errorf("insufficient balance. balance=%v tx=%v", balance, tx.Value())
|
|
||||||
}
|
|
||||||
nonce := state.GetNonce(key.Address())
|
|
||||||
|
|
||||||
tx.SetNonce(nonce)
|
tx.SetNonce(nonce)
|
||||||
tx.Sign(key.PrivateKey)
|
|
||||||
|
|
||||||
err = self.eth.TxPool().Add(tx)
|
if err := self.sign(tx, from, false); err != nil {
|
||||||
if err != nil {
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
state.SetNonce(key.Address(), nonce+1)
|
if err := self.eth.TxPool().Add(tx); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
state.SetNonce(from, nonce+1)
|
||||||
|
|
||||||
|
if contractCreation {
|
||||||
|
addr := core.AddressFromMessage(tx)
|
||||||
|
pipelogger.Infof("Contract addr %x\n", addr)
|
||||||
|
}
|
||||||
|
|
||||||
if types.IsContractAddr(to) {
|
if types.IsContractAddr(to) {
|
||||||
return toHex(core.AddressFromMessage(tx)), nil
|
return toHex(core.AddressFromMessage(tx)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return toHex(tx.Hash()), nil
|
return toHex(tx.Hash()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *XEth) sign(tx *types.Transaction, from []byte, didUnlock bool) error {
|
||||||
|
sig, err := self.accountManager.Sign(accounts.Account{Address: from}, tx.Hash())
|
||||||
|
if err == accounts.ErrLocked {
|
||||||
|
if didUnlock {
|
||||||
|
return fmt.Errorf("sender account still locked after successful unlock")
|
||||||
|
}
|
||||||
|
if !self.frontend.UnlockAccount(from) {
|
||||||
|
return fmt.Errorf("could not unlock sender account")
|
||||||
|
}
|
||||||
|
// retry signing, the account should now be unlocked.
|
||||||
|
return self.sign(tx, from, true)
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tx.SetSignatureValues(sig)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// callmsg is the message type used for call transations.
|
||||||
|
type callmsg struct {
|
||||||
|
from *state.StateObject
|
||||||
|
to []byte
|
||||||
|
gas, gasPrice *big.Int
|
||||||
|
value *big.Int
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// accessor boilerplate to implement core.Message
|
||||||
|
func (m callmsg) From() []byte { return m.from.Address() }
|
||||||
|
func (m callmsg) Nonce() uint64 { return m.from.Nonce() }
|
||||||
|
func (m callmsg) To() []byte { return m.to }
|
||||||
|
func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
|
||||||
|
func (m callmsg) Gas() *big.Int { return m.gas }
|
||||||
|
func (m callmsg) Value() *big.Int { return m.value }
|
||||||
|
func (m callmsg) Data() []byte { return m.data }
|
||||||
|
Loading…
Reference in New Issue
Block a user