mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 04:36:42 +00:00
Merge remote-tracking branch 'upstream/develop' into bzz
This commit is contained in:
commit
1f7ec3539f
213 changed files with 14373 additions and 9936 deletions
12
.mailmap
Normal file
12
.mailmap
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
Jeffrey Wilcke <jeffrey@ethereum.org>
|
||||||
|
Jeffrey Wilcke <jeffrey@ethereum.org> <geffobscura@gmail.com>
|
||||||
|
Jeffrey Wilcke <jeffrey@ethereum.org> <obscuren@obscura.com>
|
||||||
|
Jeffrey Wilcke <jeffrey@ethereum.org> <obscuren@users.noreply.github.com>
|
||||||
|
|
||||||
|
Viktor Trón <viktor.tron@gmail.com>
|
||||||
|
|
||||||
|
Joseph Goulden <joegoulden@gmail.com>
|
||||||
|
|
||||||
|
Nick Savers <nicksavers@gmail.com>
|
||||||
|
|
||||||
|
Maran Hidskes <maran.hidskes@gmail.com>
|
||||||
10
.travis.yml
10
.travis.yml
|
|
@ -1,6 +1,6 @@
|
||||||
language: go
|
language: go
|
||||||
go:
|
go:
|
||||||
- 1.3
|
- tip
|
||||||
before_install:
|
before_install:
|
||||||
- sudo add-apt-repository ppa:ubuntu-sdk-team/ppa -y
|
- sudo add-apt-repository ppa:ubuntu-sdk-team/ppa -y
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
|
|
@ -8,10 +8,10 @@ before_install:
|
||||||
install:
|
install:
|
||||||
- go get code.google.com/p/go.tools/cmd/goimports
|
- go get code.google.com/p/go.tools/cmd/goimports
|
||||||
- go get github.com/golang/lint/golint
|
- go get github.com/golang/lint/golint
|
||||||
# - go get code.google.com/p/go.tools/cmd/vet
|
# - go get golang.org/x/tools/cmd/vet
|
||||||
- go get code.google.com/p/go.tools/cmd/cover
|
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
|
||||||
- go get github.com/mattn/goveralls
|
- go get github.com/mattn/goveralls
|
||||||
- ./install_deps.sh
|
- ETH_DEPS=$(go list -f '{{.Imports}} {{.TestImports}} {{.XTestImports}}' github.com/ethereum/go-ethereum/... | sed -e 's/\[//g' | sed -e 's/\]//g' | sed -e 's/C //g'); if [ "$ETH_DEPS" ]; then go get $ETH_DEPS; fi
|
||||||
before_script:
|
before_script:
|
||||||
- gofmt -l -w .
|
- gofmt -l -w .
|
||||||
- goimports -l -w .
|
- goimports -l -w .
|
||||||
|
|
@ -19,7 +19,7 @@ before_script:
|
||||||
# - go vet ./...
|
# - go vet ./...
|
||||||
# - go test -race ./...
|
# - go test -race ./...
|
||||||
script:
|
script:
|
||||||
- ./gocoverage.sh && goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN
|
- ./gocoverage.sh
|
||||||
env:
|
env:
|
||||||
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
|
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,14 @@ RUN apt-get install -y qtbase5-private-dev qtdeclarative5-private-dev libqt5open
|
||||||
## Fetch and install serpent-go
|
## Fetch and install serpent-go
|
||||||
RUN go get -v -d github.com/ethereum/serpent-go
|
RUN go get -v -d github.com/ethereum/serpent-go
|
||||||
WORKDIR $GOPATH/src/github.com/ethereum/serpent-go
|
WORKDIR $GOPATH/src/github.com/ethereum/serpent-go
|
||||||
RUN git checkout master
|
# RUN git checkout master
|
||||||
RUN git submodule update --init
|
RUN git submodule update --init
|
||||||
RUN go install -v
|
RUN go install -v
|
||||||
|
|
||||||
# Fetch and install go-ethereum
|
# Fetch and install go-ethereum
|
||||||
RUN go get -v -d github.com/ethereum/go-ethereum/...
|
RUN go get -v -d github.com/ethereum/go-ethereum/...
|
||||||
WORKDIR $GOPATH/src/github.com/ethereum/go-ethereum
|
WORKDIR $GOPATH/src/github.com/ethereum/go-ethereum
|
||||||
RUN git checkout poc8
|
# RUN git checkout develop
|
||||||
RUN ETH_DEPS=$(go list -f '{{.Imports}} {{.TestImports}} {{.XTestImports}}' github.com/ethereum/go-ethereum/... | sed -e 's/\[//g' | sed -e 's/\]//g' | sed -e 's/C //g'); if [ "$ETH_DEPS" ]; then go get $ETH_DEPS; fi
|
RUN ETH_DEPS=$(go list -f '{{.Imports}} {{.TestImports}} {{.XTestImports}}' github.com/ethereum/go-ethereum/... | sed -e 's/\[//g' | sed -e 's/\]//g' | sed -e 's/C //g'); if [ "$ETH_DEPS" ]; then go get $ETH_DEPS; fi
|
||||||
RUN go install -v ./cmd/ethereum
|
RUN go install -v ./cmd/ethereum
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,11 @@ Ethereum
|
||||||
[](http://build.ethdev.com:8010/builders/Linux%20Go%20master%20branch/builds/-1) master [](http://build.ethdev.com:8010/builders/Linux%20Go%20master%20branch/builds/-1) master [](http://build.ethdev.com:8010/builders/Linux%20Go%20develop%20branch/builds/-1) develop
|
Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](http://build.ethdev.com:8010/builders/Linux%20Go%20develop%20branch/builds/-1) develop
|
||||||
|
[](https://coveralls.io/r/ethereum/go-ethereum?branch=tests) tests
|
||||||
|
|
||||||
Ethereum Go Client © 2014 Jeffrey Wilcke.
|
Ethereum Go Client © 2014 Jeffrey Wilcke.
|
||||||
|
|
||||||
Current state: Proof of Concept 0.7
|
Current state: Proof of Concept 0.8
|
||||||
|
|
||||||
Ethereum is currently in its testing phase.
|
Ethereum is currently in its testing phase.
|
||||||
|
|
||||||
|
|
|
||||||
BIN
_data/chain1
BIN
_data/chain1
Binary file not shown.
BIN
_data/chain2
BIN
_data/chain2
Binary file not shown.
BIN
_data/invalid1
Executable file
BIN
_data/invalid1
Executable file
Binary file not shown.
BIN
_data/valid1
Executable file
BIN
_data/valid1
Executable file
Binary file not shown.
BIN
_data/valid2
Executable file
BIN
_data/valid2
Executable file
Binary file not shown.
BIN
_data/valid3
Executable file
BIN
_data/valid3
Executable file
Binary file not shown.
BIN
_data/valid4
Executable file
BIN
_data/valid4
Executable file
Binary file not shown.
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -58,6 +61,10 @@ var (
|
||||||
DumpHash string
|
DumpHash string
|
||||||
DumpNumber int
|
DumpNumber int
|
||||||
VmType int
|
VmType int
|
||||||
|
ImportChain string
|
||||||
|
SHH bool
|
||||||
|
Dial bool
|
||||||
|
PrintVersion bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// flags specific to cli client
|
// flags specific to cli client
|
||||||
|
|
@ -87,12 +94,14 @@ func Init() {
|
||||||
flag.StringVar(&OutboundPort, "port", "30303", "listening port")
|
flag.StringVar(&OutboundPort, "port", "30303", "listening port")
|
||||||
flag.StringVar(&NatType, "nat", "", "NAT support (UPNP|PMP) (none)")
|
flag.StringVar(&NatType, "nat", "", "NAT support (UPNP|PMP) (none)")
|
||||||
flag.StringVar(&PMPGateway, "pmp", "", "Gateway IP for PMP")
|
flag.StringVar(&PMPGateway, "pmp", "", "Gateway IP for PMP")
|
||||||
flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
|
flag.IntVar(&MaxPeer, "maxpeer", 30, "maximum desired peers")
|
||||||
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
|
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
|
||||||
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
|
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
|
||||||
flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server")
|
flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server")
|
||||||
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
|
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
|
||||||
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
|
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
|
||||||
|
flag.BoolVar(&SHH, "shh", true, "whisper protocol (on)")
|
||||||
|
flag.BoolVar(&Dial, "dial", true, "dial out connections (on)")
|
||||||
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
|
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(&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(&ExportDir, "export", "", "exports the session keyring to files in the directory given")
|
||||||
|
|
@ -104,6 +113,7 @@ func Init() {
|
||||||
flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0")
|
flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0")
|
||||||
flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false")
|
flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false")
|
||||||
flag.BoolVar(&ShowGenesis, "genesis", false, "Dump the genesis block")
|
flag.BoolVar(&ShowGenesis, "genesis", false, "Dump the genesis block")
|
||||||
|
flag.StringVar(&ImportChain, "chain", "", "Imports given chain")
|
||||||
|
|
||||||
flag.BoolVar(&Dump, "dump", false, "output the ethereum state in JSON format. Sub args [number, hash]")
|
flag.BoolVar(&Dump, "dump", false, "output the ethereum state in JSON format. Sub args [number, hash]")
|
||||||
flag.StringVar(&DumpHash, "hash", "", "specify arg in hex")
|
flag.StringVar(&DumpHash, "hash", "", "specify arg in hex")
|
||||||
|
|
@ -111,6 +121,7 @@ func Init() {
|
||||||
|
|
||||||
flag.BoolVar(&StartMining, "mine", false, "start dagger mining")
|
flag.BoolVar(&StartMining, "mine", false, "start dagger mining")
|
||||||
flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console")
|
flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console")
|
||||||
|
flag.BoolVar(&PrintVersion, "version", false, "prints version number")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,42 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"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"
|
||||||
|
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ClientIdentifier = "Ethereum(G)"
|
ClientIdentifier = "Ethereum(G)"
|
||||||
Version = "0.7.9"
|
Version = "0.8.1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var clilogger = logger.NewLogger("CLI")
|
var clilogger = logger.NewLogger("CLI")
|
||||||
|
|
@ -38,40 +44,44 @@ var clilogger = logger.NewLogger("CLI")
|
||||||
func main() {
|
func main() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
logger.Flush()
|
||||||
|
}()
|
||||||
|
|
||||||
utils.HandleInterrupt()
|
utils.HandleInterrupt()
|
||||||
|
|
||||||
// precedence: code-internal flag default < config file < environment variables < command line
|
// precedence: code-internal flag default < config file < environment variables < command line
|
||||||
Init() // parsing command line
|
Init() // parsing command line
|
||||||
|
|
||||||
// If the difftool option is selected ignore all other log output
|
if PrintVersion {
|
||||||
if DiffTool || Dump {
|
printVersion()
|
||||||
LogLevel = 0
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.InitConfig(VmType, ConfigFile, Datadir, "ETH")
|
utils.InitConfig(VmType, ConfigFile, Datadir, "ETH")
|
||||||
ethutil.Config.Diff = DiffTool
|
|
||||||
ethutil.Config.DiffType = DiffType
|
|
||||||
|
|
||||||
utils.InitDataDir(Datadir)
|
ethereum, err := eth.New(ð.Config{
|
||||||
|
Name: ClientIdentifier,
|
||||||
|
Version: Version,
|
||||||
|
KeyStore: KeyStore,
|
||||||
|
DataDir: Datadir,
|
||||||
|
LogFile: LogFile,
|
||||||
|
LogLevel: LogLevel,
|
||||||
|
Identifier: Identifier,
|
||||||
|
MaxPeers: MaxPeer,
|
||||||
|
Port: OutboundPort,
|
||||||
|
NATType: PMPGateway,
|
||||||
|
PMPGateway: PMPGateway,
|
||||||
|
KeyRing: KeyRing,
|
||||||
|
Shh: SHH,
|
||||||
|
Dial: Dial,
|
||||||
|
})
|
||||||
|
|
||||||
utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile)
|
|
||||||
|
|
||||||
db := utils.NewDatabase()
|
|
||||||
err := utils.DBSanityCheck(db)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
clilogger.Fatalln(err)
|
||||||
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keyManager := utils.NewKeyManager(KeyStore, Datadir, db)
|
utils.KeyTasks(ethereum.KeyManager(), KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
|
||||||
|
|
||||||
// create, import, export keys
|
|
||||||
utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
|
|
||||||
|
|
||||||
clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier, string(keyManager.PublicKey()))
|
|
||||||
|
|
||||||
ethereum := utils.NewEthereum(db, clientIdentity, keyManager, utils.NatType(NatType, PMPGateway), OutboundPort, MaxPeer)
|
|
||||||
|
|
||||||
if Dump {
|
if Dump {
|
||||||
var block *types.Block
|
var block *types.Block
|
||||||
|
|
@ -93,30 +103,27 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// block.GetRoot() does not exist
|
|
||||||
//fmt.Printf("RLP: %x\nstate: %x\nhash: %x\n", ethutil.Rlp(block), block.GetRoot(), block.Hash())
|
|
||||||
|
|
||||||
// Leave the Println. This needs clean output for piping
|
// Leave the Println. This needs clean output for piping
|
||||||
fmt.Printf("%s\n", block.State().Dump())
|
statedb := state.New(block.Root(), ethereum.Db())
|
||||||
|
fmt.Printf("%s\n", statedb.Dump())
|
||||||
|
|
||||||
fmt.Println(block)
|
fmt.Println(block)
|
||||||
|
|
||||||
os.Exit(0)
|
return
|
||||||
}
|
|
||||||
|
|
||||||
if ShowGenesis {
|
|
||||||
utils.ShowGenesis(ethereum)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if StartMining {
|
if StartMining {
|
||||||
utils.StartMining(ethereum)
|
utils.StartMining(ethereum)
|
||||||
}
|
}
|
||||||
|
|
||||||
// better reworked as cases
|
if len(ImportChain) > 0 {
|
||||||
if StartJsConsole {
|
start := time.Now()
|
||||||
InitJsConsole(ethereum)
|
err := utils.ImportChain(ethereum, ImportChain)
|
||||||
} else if len(InputFile) > 0 {
|
if err != nil {
|
||||||
ExecJsFile(ethereum, InputFile)
|
clilogger.Infoln(err)
|
||||||
|
}
|
||||||
|
clilogger.Infoln("import done in", time.Since(start))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if StartRpc {
|
if StartRpc {
|
||||||
|
|
@ -129,7 +136,21 @@ func main() {
|
||||||
|
|
||||||
utils.StartEthereum(ethereum, UseSeed)
|
utils.StartEthereum(ethereum, UseSeed)
|
||||||
|
|
||||||
|
if StartJsConsole {
|
||||||
|
InitJsConsole(ethereum)
|
||||||
|
} else if len(InputFile) > 0 {
|
||||||
|
ExecJsFile(ethereum, InputFile)
|
||||||
|
}
|
||||||
// this blocks the thread
|
// this blocks the thread
|
||||||
ethereum.WaitForShutdown()
|
ethereum.WaitForShutdown()
|
||||||
logger.Flush()
|
}
|
||||||
|
|
||||||
|
func printVersion() {
|
||||||
|
fmt.Printf(`%v %v
|
||||||
|
PV=%d
|
||||||
|
GOOS=%s
|
||||||
|
GO=%s
|
||||||
|
GOPATH=%s
|
||||||
|
GOROOT=%s
|
||||||
|
`, ClientIdentifier, Version, eth.ProtocolVersion, runtime.GOOS, runtime.Version(), os.Getenv("GOPATH"), runtime.GOROOT())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,11 +86,6 @@ func (self *JSRepl) Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *JSRepl) parseInput(code string) {
|
func (self *JSRepl) parseInput(code string) {
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
fmt.Println("[native] error", r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
value, err := self.re.Run(code)
|
value, err := self.re.Run(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
5
cmd/ethtest/.bowerrc
Normal file
5
cmd/ethtest/.bowerrc
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"directory": "example/js/",
|
||||||
|
"cwd": "./",
|
||||||
|
"analytics": false
|
||||||
|
}
|
||||||
12
cmd/ethtest/.editorconfig
Normal file
12
cmd/ethtest/.editorconfig
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
# or operating system, you probably want to add a global ignore instead:
|
# or operating system, you probably want to add a global ignore instead:
|
||||||
# git config --global core.excludesfile ~/.gitignore_global
|
# git config --global core.excludesfile ~/.gitignore_global
|
||||||
|
|
||||||
|
*.swp
|
||||||
/tmp
|
/tmp
|
||||||
*/**/*un~
|
*/**/*un~
|
||||||
*un~
|
*un~
|
||||||
|
|
@ -11,4 +12,7 @@
|
||||||
*/**/.DS_Store
|
*/**/.DS_Store
|
||||||
ethereum/ethereum
|
ethereum/ethereum
|
||||||
ethereal/ethereal
|
ethereal/ethereal
|
||||||
|
example/js
|
||||||
|
node_modules
|
||||||
|
bower_components
|
||||||
|
npm-debug.log
|
||||||
50
cmd/ethtest/.jshintrc
Normal file
50
cmd/ethtest/.jshintrc
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"predef": [
|
||||||
|
"console",
|
||||||
|
"require",
|
||||||
|
"equal",
|
||||||
|
"test",
|
||||||
|
"testBoth",
|
||||||
|
"testWithDefault",
|
||||||
|
"raises",
|
||||||
|
"deepEqual",
|
||||||
|
"start",
|
||||||
|
"stop",
|
||||||
|
"ok",
|
||||||
|
"strictEqual",
|
||||||
|
"module",
|
||||||
|
"expect",
|
||||||
|
"reject",
|
||||||
|
"impl"
|
||||||
|
],
|
||||||
|
|
||||||
|
"esnext": true,
|
||||||
|
"proto": true,
|
||||||
|
"node" : true,
|
||||||
|
"browser" : true,
|
||||||
|
"browserify" : true,
|
||||||
|
|
||||||
|
"boss" : true,
|
||||||
|
"curly": false,
|
||||||
|
"debug": true,
|
||||||
|
"devel": true,
|
||||||
|
"eqeqeq": true,
|
||||||
|
"evil": true,
|
||||||
|
"forin": false,
|
||||||
|
"immed": false,
|
||||||
|
"laxbreak": false,
|
||||||
|
"newcap": true,
|
||||||
|
"noarg": true,
|
||||||
|
"noempty": false,
|
||||||
|
"nonew": false,
|
||||||
|
"nomen": false,
|
||||||
|
"onevar": false,
|
||||||
|
"plusplus": false,
|
||||||
|
"regexp": false,
|
||||||
|
"undef": true,
|
||||||
|
"sub": true,
|
||||||
|
"strict": false,
|
||||||
|
"white": false,
|
||||||
|
"shadow": true,
|
||||||
|
"eqnull": true
|
||||||
|
}
|
||||||
9
cmd/ethtest/.npmignore
Normal file
9
cmd/ethtest/.npmignore
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
example/js
|
||||||
|
node_modules
|
||||||
|
test
|
||||||
|
.gitignore
|
||||||
|
.editorconfig
|
||||||
|
.travis.yml
|
||||||
|
.npmignore
|
||||||
|
component.json
|
||||||
|
testling.html
|
||||||
11
cmd/ethtest/.travis.yml
Normal file
11
cmd/ethtest/.travis.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "0.11"
|
||||||
|
- "0.10"
|
||||||
|
before_script:
|
||||||
|
- npm install
|
||||||
|
- npm install jshint
|
||||||
|
script:
|
||||||
|
- "jshint *.js lib"
|
||||||
|
after_script:
|
||||||
|
- npm run-script gulp
|
||||||
|
|
@ -17,8 +17,6 @@
|
||||||
/**
|
/**
|
||||||
* @authors:
|
* @authors:
|
||||||
* Jeffrey Wilcke <i@jev.io>
|
* Jeffrey Wilcke <i@jev.io>
|
||||||
* @date 2014
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
@ -26,11 +24,13 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
"github.com/ethereum/go-ethereum/tests/helper"
|
"github.com/ethereum/go-ethereum/tests/helper"
|
||||||
|
|
@ -43,8 +43,8 @@ type Account struct {
|
||||||
Storage map[string]string
|
Storage map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func StateObjectFromAccount(addr string, account Account) *state.StateObject {
|
func StateObjectFromAccount(db ethutil.Database, addr string, account Account) *state.StateObject {
|
||||||
obj := state.NewStateObject(ethutil.Hex2Bytes(addr))
|
obj := state.NewStateObject(ethutil.Hex2Bytes(addr), db)
|
||||||
obj.SetBalance(ethutil.Big(account.Balance))
|
obj.SetBalance(ethutil.Big(account.Balance))
|
||||||
|
|
||||||
if ethutil.IsHex(account.Code) {
|
if ethutil.IsHex(account.Code) {
|
||||||
|
|
@ -66,19 +66,20 @@ type VmTest struct {
|
||||||
Pre map[string]Account
|
Pre map[string]Account
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunVmTest(js string) (failed int) {
|
func RunVmTest(r io.Reader) (failed int) {
|
||||||
tests := make(map[string]VmTest)
|
tests := make(map[string]VmTest)
|
||||||
|
|
||||||
data, _ := ioutil.ReadAll(strings.NewReader(js))
|
data, _ := ioutil.ReadAll(r)
|
||||||
err := json.Unmarshal(data, &tests)
|
err := json.Unmarshal(data, &tests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
state := state.New(helper.NewTrie())
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
state := state.New(nil, db)
|
||||||
for addr, account := range test.Pre {
|
for addr, account := range test.Pre {
|
||||||
obj := StateObjectFromAccount(addr, account)
|
obj := StateObjectFromAccount(db, addr, account)
|
||||||
state.SetStateObject(obj)
|
state.SetStateObject(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,10 +96,15 @@ func RunVmTest(js string) (failed int) {
|
||||||
failed = 1
|
failed = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
gexp := ethutil.Big(test.Gas)
|
if len(test.Gas) == 0 && err == nil {
|
||||||
if gexp.Cmp(gas) != 0 {
|
log.Printf("0 gas indicates error but no error given by VM")
|
||||||
log.Printf("%s's gas failed. Expected %v, got %v\n", name, gexp, gas)
|
|
||||||
failed = 1
|
failed = 1
|
||||||
|
} else {
|
||||||
|
gexp := ethutil.Big(test.Gas)
|
||||||
|
if gexp.Cmp(gas) != 0 {
|
||||||
|
log.Printf("%s's gas failed. Expected %v, got %v\n", name, gexp, gas)
|
||||||
|
failed = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for addr, account := range test.Post {
|
for addr, account := range test.Post {
|
||||||
|
|
@ -120,9 +126,10 @@ func RunVmTest(js string) (failed int) {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
helper.Logger.SetLogLevel(5)
|
helper.Logger.SetLogLevel(5)
|
||||||
if len(os.Args) == 1 {
|
|
||||||
log.Fatalln("no json supplied")
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Exit(RunVmTest(os.Args[1]))
|
if len(os.Args) > 1 {
|
||||||
|
os.Exit(RunVmTest(strings.NewReader(os.Args[1])))
|
||||||
|
} else {
|
||||||
|
os.Exit(RunVmTest(os.Stdin))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@
|
||||||
/**
|
/**
|
||||||
* @authors
|
* @authors
|
||||||
* Jeffrey Wilcke <i@jev.io>
|
* Jeffrey Wilcke <i@jev.io>
|
||||||
* @date 2014
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
@ -38,7 +36,6 @@ import (
|
||||||
"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/ethereum/go-ethereum/trie"
|
|
||||||
"github.com/ethereum/go-ethereum/vm"
|
"github.com/ethereum/go-ethereum/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -65,7 +62,7 @@ func main() {
|
||||||
ethutil.ReadConfig("/tmp/evmtest", "/tmp/evm", "")
|
ethutil.ReadConfig("/tmp/evmtest", "/tmp/evm", "")
|
||||||
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
statedb := state.New(trie.New(db, ""))
|
statedb := state.New(nil, db)
|
||||||
sender := statedb.NewStateObject([]byte("sender"))
|
sender := statedb.NewStateObject([]byte("sender"))
|
||||||
receiver := statedb.NewStateObject([]byte("receiver"))
|
receiver := statedb.NewStateObject([]byte("receiver"))
|
||||||
//receiver.SetCode([]byte(*code))
|
//receiver.SetCode([]byte(*code))
|
||||||
|
|
@ -133,6 +130,12 @@ func (self *VMEnv) Value() *big.Int { return self.value }
|
||||||
func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) }
|
func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) }
|
||||||
func (self *VMEnv) Depth() int { return 0 }
|
func (self *VMEnv) Depth() int { return 0 }
|
||||||
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
||||||
|
func (self *VMEnv) GetHash(n uint64) []byte {
|
||||||
|
if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 {
|
||||||
|
return self.block.Hash()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func (self *VMEnv) AddLog(log state.Log) {
|
func (self *VMEnv) AddLog(log state.Log) {
|
||||||
self.state.AddLog(log)
|
self.state.AddLog(log)
|
||||||
}
|
}
|
||||||
|
|
@ -141,24 +144,22 @@ func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *core.Execution {
|
func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *core.Execution {
|
||||||
evm := vm.New(self, vm.DebugVmTy)
|
return core.NewExecution(self, addr, data, gas, price, value)
|
||||||
|
|
||||||
return core.NewExecution(evm, addr, data, gas, price, value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Call(caller vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
func (self *VMEnv) Call(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
||||||
exe := self.vm(addr, data, gas, price, value)
|
exe := self.vm(addr, data, gas, price, value)
|
||||||
ret, err := exe.Call(addr, caller)
|
ret, err := exe.Call(addr, caller)
|
||||||
self.Gas = exe.Gas
|
self.Gas = exe.Gas
|
||||||
|
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
func (self *VMEnv) CallCode(caller vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
func (self *VMEnv) CallCode(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
||||||
exe := self.vm(caller.Address(), data, gas, price, value)
|
exe := self.vm(caller.Address(), data, gas, price, value)
|
||||||
return exe.Call(addr, caller)
|
return exe.Call(addr, caller)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Create(caller vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ClosureRef) {
|
func (self *VMEnv) Create(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) {
|
||||||
exe := self.vm(addr, data, gas, price, value)
|
exe := self.vm(addr, data, gas, price, value)
|
||||||
return exe.Create(caller)
|
return exe.Create(caller)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
# Ethereum JavaScript API
|
|
||||||
|
|
||||||
This is the Ethereum compatible JavaScript API using `Promise`s
|
|
||||||
which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec.
|
|
||||||
|
|
||||||
For an example see `index.html`.
|
|
||||||
|
|
||||||
**Please note this repo is in it's early stage.**
|
|
||||||
|
|
||||||
If you'd like to run a WebSocket ethereum node check out
|
|
||||||
[go-ethereum](https://github.com/ethereum/go-ethereum).
|
|
||||||
|
|
||||||
To install ethereum and spawn a node:
|
|
||||||
|
|
||||||
```
|
|
||||||
go get github.com/ethereum/go-ethereum/ethereum
|
|
||||||
ethereum -ws -loglevel=4
|
|
||||||
```
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
(function () {
|
|
||||||
var HttpRpcProvider = function (host) {
|
|
||||||
this.handlers = [];
|
|
||||||
this.host = host;
|
|
||||||
};
|
|
||||||
|
|
||||||
function formatJsonRpcObject(object) {
|
|
||||||
return {
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
method: object.call,
|
|
||||||
params: object.args,
|
|
||||||
id: object._id
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function formatJsonRpcMessage(message) {
|
|
||||||
var object = JSON.parse(message);
|
|
||||||
|
|
||||||
return {
|
|
||||||
_id: object.id,
|
|
||||||
data: object.result
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpRpcProvider.prototype.sendRequest = function (payload, cb) {
|
|
||||||
var data = formatJsonRpcObject(payload);
|
|
||||||
|
|
||||||
var request = new XMLHttpRequest();
|
|
||||||
request.open("POST", this.host, true);
|
|
||||||
request.send(JSON.stringify(data));
|
|
||||||
request.onreadystatechange = function () {
|
|
||||||
if (request.readyState === 4 && cb) {
|
|
||||||
cb(request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpRpcProvider.prototype.send = function (payload) {
|
|
||||||
var self = this;
|
|
||||||
this.sendRequest(payload, function (request) {
|
|
||||||
self.handlers.forEach(function (handler) {
|
|
||||||
handler.call(self, formatJsonRpcMessage(request.responseText));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpRpcProvider.prototype.poll = function (payload, id) {
|
|
||||||
var self = this;
|
|
||||||
this.sendRequest(payload, function (request) {
|
|
||||||
var parsed = JSON.parse(request.responseText);
|
|
||||||
if (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.handlers.forEach(function (handler) {
|
|
||||||
handler.call(self, {_event: payload.call, _id: id, data: parsed.result});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.defineProperty(HttpRpcProvider.prototype, "onmessage", {
|
|
||||||
set: function (handler) {
|
|
||||||
this.handlers.push(handler);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (typeof(web3) !== "undefined" && web3.providers !== undefined) {
|
|
||||||
web3.providers.HttpRpcProvider = HttpRpcProvider;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
<!doctype>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<script type="text/javascript" src="main.js"></script>
|
|
||||||
<script type="text/javascript" src="websocket.js"></script>
|
|
||||||
<script type="text/javascript" src="qt.js"></script>
|
|
||||||
<script type="text/javascript" src="httprpc.js"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
function registerName() {
|
|
||||||
var name = document.querySelector("#name").value;
|
|
||||||
name = web3.fromAscii(name);
|
|
||||||
|
|
||||||
var eth = web3.eth;
|
|
||||||
eth.transact({to: "NameReg", gas: "10000", gasPrice: eth.gasPrice, data: [web3.fromAscii("register"), name]}).then(function(tx) {
|
|
||||||
document.querySelector("#result").innerHTML = "Registered name. Please wait for the next block to come through.";
|
|
||||||
}, function(err) {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<h1>std::name_reg</h1>
|
|
||||||
<input type="text" id="name"></input>
|
|
||||||
<input type="submit" onClick="registerName();"></input>
|
|
||||||
<div id="result"></div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,432 +0,0 @@
|
||||||
(function(window) {
|
|
||||||
function isPromise(o) {
|
|
||||||
return o instanceof Promise
|
|
||||||
}
|
|
||||||
|
|
||||||
function flattenPromise (obj) {
|
|
||||||
if (obj instanceof Promise) {
|
|
||||||
return Promise.resolve(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof Array) {
|
|
||||||
return new Promise(function (resolve) {
|
|
||||||
var promises = obj.map(function (o) {
|
|
||||||
return flattenPromise(o);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(promises).then(function (res) {
|
|
||||||
for (var i = 0; i < obj.length; i++) {
|
|
||||||
obj[i] = res[i];
|
|
||||||
}
|
|
||||||
resolve(obj);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof Object) {
|
|
||||||
return new Promise(function (resolve) {
|
|
||||||
var keys = Object.keys(obj);
|
|
||||||
var promises = keys.map(function (key) {
|
|
||||||
return flattenPromise(obj[key]);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(promises).then(function (res) {
|
|
||||||
for (var i = 0; i < keys.length; i++) {
|
|
||||||
obj[keys[i]] = res[i];
|
|
||||||
}
|
|
||||||
resolve(obj);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve(obj);
|
|
||||||
};
|
|
||||||
|
|
||||||
var ethMethods = function () {
|
|
||||||
var blockCall = function (args) {
|
|
||||||
return typeof args[0] === "string" ? "blockByHash" : "blockByNumber";
|
|
||||||
};
|
|
||||||
|
|
||||||
var transactionCall = function (args) {
|
|
||||||
return typeof args[0] === "string" ? 'transactionByHash' : 'transactionByNumber';
|
|
||||||
};
|
|
||||||
|
|
||||||
var uncleCall = function (args) {
|
|
||||||
return typeof args[0] === "string" ? 'uncleByHash' : 'uncleByNumber';
|
|
||||||
};
|
|
||||||
|
|
||||||
var methods = [
|
|
||||||
{ name: 'balanceAt', call: 'balanceAt' },
|
|
||||||
{ name: 'stateAt', call: 'stateAt' },
|
|
||||||
{ name: 'countAt', call: 'countAt'},
|
|
||||||
{ name: 'codeAt', call: 'codeAt' },
|
|
||||||
{ name: 'transact', call: 'transact' },
|
|
||||||
{ name: 'call', call: 'call' },
|
|
||||||
{ name: 'block', call: blockCall },
|
|
||||||
{ name: 'transaction', call: transactionCall },
|
|
||||||
{ name: 'uncle', call: uncleCall },
|
|
||||||
{ name: 'compile', call: 'compile' }
|
|
||||||
];
|
|
||||||
return methods;
|
|
||||||
};
|
|
||||||
|
|
||||||
var ethProperties = function () {
|
|
||||||
return [
|
|
||||||
{ name: 'coinbase', getter: 'coinbase', setter: 'setCoinbase' },
|
|
||||||
{ name: 'listening', getter: 'listening', setter: 'setListening' },
|
|
||||||
{ name: 'mining', getter: 'mining', setter: 'setMining' },
|
|
||||||
{ name: 'gasPrice', getter: 'gasPrice' },
|
|
||||||
{ name: 'account', getter: 'account' },
|
|
||||||
{ name: 'accounts', getter: 'accounts' },
|
|
||||||
{ name: 'peerCount', getter: 'peerCount' },
|
|
||||||
{ name: 'defaultBlock', getter: 'defaultBlock', setter: 'setDefaultBlock' },
|
|
||||||
{ name: 'number', getter: 'number'}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
var dbMethods = function () {
|
|
||||||
return [
|
|
||||||
{ name: 'put', call: 'put' },
|
|
||||||
{ name: 'get', call: 'get' },
|
|
||||||
{ name: 'putString', call: 'putString' },
|
|
||||||
{ name: 'getString', call: 'getString' }
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
var shhMethods = function () {
|
|
||||||
return [
|
|
||||||
{ name: 'post', call: 'post' },
|
|
||||||
{ name: 'newIdentity', call: 'newIdentity' },
|
|
||||||
{ name: 'haveIdentity', call: 'haveIdentity' },
|
|
||||||
{ name: 'newGroup', call: 'newGroup' },
|
|
||||||
{ name: 'addToGroup', call: 'addToGroup' }
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
var ethWatchMethods = function () {
|
|
||||||
var newFilter = function (args) {
|
|
||||||
return typeof args[0] === 'string' ? 'newFilterString' : 'newFilter';
|
|
||||||
};
|
|
||||||
|
|
||||||
return [
|
|
||||||
{ name: 'newFilter', call: newFilter },
|
|
||||||
{ name: 'uninstallFilter', call: 'uninstallFilter' },
|
|
||||||
{ name: 'getMessages', call: 'getMessages' }
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
var shhWatchMethods = function () {
|
|
||||||
return [
|
|
||||||
{ name: 'newFilter', call: 'shhNewFilter' },
|
|
||||||
{ name: 'uninstallFilter', call: 'shhUninstallFilter' },
|
|
||||||
{ name: 'getMessage', call: 'shhGetMessages' }
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
var setupMethods = function (obj, methods) {
|
|
||||||
methods.forEach(function (method) {
|
|
||||||
obj[method.name] = function () {
|
|
||||||
return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {
|
|
||||||
var call = typeof method.call === "function" ? method.call(args) : method.call;
|
|
||||||
return {call: call, args: args};
|
|
||||||
}).then(function (request) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
web3.provider.send(request, function (result) {
|
|
||||||
//if (result || typeof result === "boolean") {
|
|
||||||
resolve(result);
|
|
||||||
return;
|
|
||||||
//}
|
|
||||||
//reject(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}).catch(function( err) {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var setupProperties = function (obj, properties) {
|
|
||||||
properties.forEach(function (property) {
|
|
||||||
var proto = {};
|
|
||||||
proto.get = function () {
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
web3.provider.send({call: property.getter}, function(result) {
|
|
||||||
resolve(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
if (property.setter) {
|
|
||||||
proto.set = function (val) {
|
|
||||||
return flattenPromise([val]).then(function (args) {
|
|
||||||
return new Promise(function (resolve) {
|
|
||||||
web3.provider.send({call: property.setter, args: args}, function (result) {
|
|
||||||
resolve(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}).catch(function (err) {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Object.defineProperty(obj, property.name, proto);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var web3 = {
|
|
||||||
_callbacks: {},
|
|
||||||
_events: {},
|
|
||||||
providers: {},
|
|
||||||
toHex: function(str) {
|
|
||||||
var hex = "";
|
|
||||||
for(var i = 0; i < str.length; i++) {
|
|
||||||
var n = str.charCodeAt(i).toString(16);
|
|
||||||
hex += n.length < 2 ? '0' + n : n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hex;
|
|
||||||
},
|
|
||||||
|
|
||||||
toAscii: function(hex) {
|
|
||||||
// Find termination
|
|
||||||
var str = "";
|
|
||||||
var i = 0, l = hex.length;
|
|
||||||
for(; i < l; i+=2) {
|
|
||||||
var code = hex.charCodeAt(i)
|
|
||||||
if(code == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
},
|
|
||||||
|
|
||||||
toDecimal: function (val) {
|
|
||||||
return parseInt(val, 16);
|
|
||||||
},
|
|
||||||
|
|
||||||
fromAscii: function(str, pad) {
|
|
||||||
pad = pad === undefined ? 32 : pad;
|
|
||||||
var hex = this.toHex(str);
|
|
||||||
while(hex.length < pad*2)
|
|
||||||
hex += "00";
|
|
||||||
return hex
|
|
||||||
},
|
|
||||||
|
|
||||||
eth: {
|
|
||||||
prototype: Object(),
|
|
||||||
watch: function (params) {
|
|
||||||
return new Filter(params, ethWatch);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
db: {
|
|
||||||
prototype: Object()
|
|
||||||
},
|
|
||||||
|
|
||||||
shh: {
|
|
||||||
prototype: Object(),
|
|
||||||
watch: function (params) {
|
|
||||||
return new Filter(params, shhWatch);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
on: function(event, id, cb) {
|
|
||||||
if(web3._events[event] === undefined) {
|
|
||||||
web3._events[event] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
web3._events[event][id] = cb;
|
|
||||||
return this
|
|
||||||
},
|
|
||||||
|
|
||||||
off: function(event, id) {
|
|
||||||
if(web3._events[event] !== undefined) {
|
|
||||||
delete web3._events[event][id];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this
|
|
||||||
},
|
|
||||||
|
|
||||||
trigger: function(event, id, data) {
|
|
||||||
var callbacks = web3._events[event];
|
|
||||||
if (!callbacks || !callbacks[id]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var cb = callbacks[id];
|
|
||||||
cb(data);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
var eth = web3.eth;
|
|
||||||
setupMethods(eth, ethMethods());
|
|
||||||
setupProperties(eth, ethProperties());
|
|
||||||
setupMethods(web3.db, dbMethods());
|
|
||||||
setupMethods(web3.shh, shhMethods());
|
|
||||||
|
|
||||||
var ethWatch = {
|
|
||||||
changed: 'changed'
|
|
||||||
};
|
|
||||||
setupMethods(ethWatch, ethWatchMethods());
|
|
||||||
var shhWatch = {
|
|
||||||
changed: 'shhChanged'
|
|
||||||
};
|
|
||||||
setupMethods(shhWatch, shhWatchMethods());
|
|
||||||
|
|
||||||
var ProviderManager = function() {
|
|
||||||
this.queued = [];
|
|
||||||
this.polls = [];
|
|
||||||
this.ready = false;
|
|
||||||
this.provider = undefined;
|
|
||||||
this.id = 1;
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
var poll = function () {
|
|
||||||
if (self.provider && self.provider.poll) {
|
|
||||||
self.polls.forEach(function (data) {
|
|
||||||
data.data._id = self.id;
|
|
||||||
self.id++;
|
|
||||||
self.provider.poll(data.data, data.id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setTimeout(poll, 12000);
|
|
||||||
};
|
|
||||||
poll();
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.send = function(data, cb) {
|
|
||||||
data._id = this.id;
|
|
||||||
if (cb) {
|
|
||||||
web3._callbacks[data._id] = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.args = data.args || [];
|
|
||||||
this.id++;
|
|
||||||
|
|
||||||
if(this.provider !== undefined) {
|
|
||||||
this.provider.send(data);
|
|
||||||
} else {
|
|
||||||
console.warn("provider is not set");
|
|
||||||
this.queued.push(data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.set = function(provider) {
|
|
||||||
if(this.provider !== undefined && this.provider.unload !== undefined) {
|
|
||||||
this.provider.unload();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.provider = provider;
|
|
||||||
this.ready = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.sendQueued = function() {
|
|
||||||
for(var i = 0; this.queued.length; i++) {
|
|
||||||
// Resend
|
|
||||||
this.send(this.queued[i]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.installed = function() {
|
|
||||||
return this.provider !== undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.startPolling = function (data, pollId) {
|
|
||||||
if (!this.provider || !this.provider.poll) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.polls.push({data: data, id: pollId});
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.stopPolling = function (pollId) {
|
|
||||||
for (var i = this.polls.length; i--;) {
|
|
||||||
var poll = this.polls[i];
|
|
||||||
if (poll.id === pollId) {
|
|
||||||
this.polls.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
web3.provider = new ProviderManager();
|
|
||||||
|
|
||||||
web3.setProvider = function(provider) {
|
|
||||||
provider.onmessage = messageHandler;
|
|
||||||
web3.provider.set(provider);
|
|
||||||
web3.provider.sendQueued();
|
|
||||||
};
|
|
||||||
|
|
||||||
var Filter = function(options, impl) {
|
|
||||||
this.impl = impl;
|
|
||||||
this.callbacks = [];
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
this.promise = impl.newFilter(options);
|
|
||||||
this.promise.then(function (id) {
|
|
||||||
self.id = id;
|
|
||||||
web3.on(impl.changed, id, self.trigger.bind(self));
|
|
||||||
web3.provider.startPolling({call: impl.changed, args: [id]}, id);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.arrived = function(callback) {
|
|
||||||
this.changed(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
Filter.prototype.changed = function(callback) {
|
|
||||||
var self = this;
|
|
||||||
this.promise.then(function(id) {
|
|
||||||
self.callbacks.push(callback);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.trigger = function(messages) {
|
|
||||||
for(var i = 0; i < this.callbacks.length; i++) {
|
|
||||||
this.callbacks[i].call(this, messages);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.uninstall = function() {
|
|
||||||
var self = this;
|
|
||||||
this.promise.then(function (id) {
|
|
||||||
self.impl.uninstallFilter(id);
|
|
||||||
web3.provider.stopPolling(id);
|
|
||||||
web3.off(impl.changed, id);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.messages = function() {
|
|
||||||
var self = this;
|
|
||||||
return this.promise.then(function (id) {
|
|
||||||
return self.impl.getMessages(id);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function messageHandler(data) {
|
|
||||||
if(data._event !== undefined) {
|
|
||||||
web3.trigger(data._event, data._id, data.data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(data._id) {
|
|
||||||
var cb = web3._callbacks[data._id];
|
|
||||||
if (cb) {
|
|
||||||
cb.call(this, data.data)
|
|
||||||
delete web3._callbacks[data._id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Install default provider
|
|
||||||
if(!web3.provider.installed()) {
|
|
||||||
var sock = new web3.WebSocket("ws://localhost:40404/eth");
|
|
||||||
|
|
||||||
web3.setProvider(sock);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
window.web3 = web3;
|
|
||||||
|
|
||||||
})(this);
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
(function() {
|
|
||||||
var QtProvider = function() {
|
|
||||||
this.handlers = [];
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
navigator.qt.onmessage = function (message) {
|
|
||||||
self.handlers.forEach(function (handler) {
|
|
||||||
handler.call(self, JSON.parse(message.data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
QtProvider.prototype.send = function(payload) {
|
|
||||||
navigator.qt.postMessage(JSON.stringify(payload));
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.defineProperty(QtProvider.prototype, "onmessage", {
|
|
||||||
set: function(handler) {
|
|
||||||
this.handlers.push(handler);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if(typeof(web3) !== "undefined" && web3.providers !== undefined) {
|
|
||||||
web3.providers.QtProvider = QtProvider;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
(function() {
|
|
||||||
var WebSocketProvider = function(host) {
|
|
||||||
// onmessage handlers
|
|
||||||
this.handlers = [];
|
|
||||||
// queue will be filled with messages if send is invoked before the ws is ready
|
|
||||||
this.queued = [];
|
|
||||||
this.ready = false;
|
|
||||||
|
|
||||||
this.ws = new WebSocket(host);
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
this.ws.onmessage = function(event) {
|
|
||||||
for(var i = 0; i < self.handlers.length; i++) {
|
|
||||||
self.handlers[i].call(self, JSON.parse(event.data), event)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.ws.onopen = function() {
|
|
||||||
self.ready = true;
|
|
||||||
|
|
||||||
for(var i = 0; i < self.queued.length; i++) {
|
|
||||||
// Resend
|
|
||||||
self.send(self.queued[i]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
WebSocketProvider.prototype.send = function(payload) {
|
|
||||||
if(this.ready) {
|
|
||||||
var data = JSON.stringify(payload);
|
|
||||||
|
|
||||||
this.ws.send(data);
|
|
||||||
} else {
|
|
||||||
this.queued.push(payload);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
WebSocketProvider.prototype.onMessage = function(handler) {
|
|
||||||
this.handlers.push(handler);
|
|
||||||
};
|
|
||||||
|
|
||||||
WebSocketProvider.prototype.unload = function() {
|
|
||||||
this.ws.close();
|
|
||||||
};
|
|
||||||
Object.defineProperty(WebSocketProvider.prototype, "onmessage", {
|
|
||||||
set: function(provider) { this.onMessage(provider); }
|
|
||||||
});
|
|
||||||
|
|
||||||
if(typeof(web3) !== "undefined" && web3.providers !== undefined) {
|
|
||||||
web3.providers.WebSocketProvider = WebSocketProvider;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
@ -1,312 +0,0 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
|
||||||
//
|
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
// Main Ethereum library
|
|
||||||
window.eth = {
|
|
||||||
prototype: Object(),
|
|
||||||
_callbacks: {},
|
|
||||||
_onCallbacks: {},
|
|
||||||
|
|
||||||
test: function() {
|
|
||||||
var t = undefined;
|
|
||||||
postData({call: "test"})
|
|
||||||
navigator.qt.onmessage = function(d) {console.log("onmessage called"); t = d; }
|
|
||||||
for(;;) {
|
|
||||||
if(t !== undefined) {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mutan: function(code, cb) {
|
|
||||||
postData({call: "mutan", args: [code]}, cb)
|
|
||||||
},
|
|
||||||
|
|
||||||
toHex: function(str) {
|
|
||||||
var hex = "";
|
|
||||||
for(var i = 0; i < str.length; i++) {
|
|
||||||
var n = str.charCodeAt(i).toString(16);
|
|
||||||
hex += n.length < 2 ? '0' + n : n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hex;
|
|
||||||
},
|
|
||||||
|
|
||||||
toAscii: function(hex) {
|
|
||||||
// Find termination
|
|
||||||
var str = "";
|
|
||||||
var i = 0, l = hex.length;
|
|
||||||
for(; i < l; i+=2) {
|
|
||||||
var code = hex.charCodeAt(i)
|
|
||||||
if(code == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
},
|
|
||||||
|
|
||||||
fromAscii: function(str, pad) {
|
|
||||||
if(pad === undefined) {
|
|
||||||
pad = 32
|
|
||||||
}
|
|
||||||
|
|
||||||
var hex = this.toHex(str);
|
|
||||||
|
|
||||||
while(hex.length < pad*2)
|
|
||||||
hex += "00";
|
|
||||||
|
|
||||||
return hex
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
// Retrieve block
|
|
||||||
//
|
|
||||||
// Either supply a number or a string. Type is determent for the lookup method
|
|
||||||
// string - Retrieves the block by looking up the hash
|
|
||||||
// number - Retrieves the block by looking up the block number
|
|
||||||
getBlock: function(numberOrHash, cb) {
|
|
||||||
var func;
|
|
||||||
if(typeof numberOrHash == "string") {
|
|
||||||
func = "getBlockByHash";
|
|
||||||
} else {
|
|
||||||
func = "getBlockByNumber";
|
|
||||||
}
|
|
||||||
postData({call: func, args: [numberOrHash]}, cb);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Create transaction
|
|
||||||
//
|
|
||||||
// Transact between two state objects
|
|
||||||
transact: function(params, cb) {
|
|
||||||
if(params === undefined) {
|
|
||||||
params = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if(params.endowment !== undefined)
|
|
||||||
params.value = params.endowment;
|
|
||||||
if(params.code !== undefined)
|
|
||||||
params.data = params.code;
|
|
||||||
|
|
||||||
// Make sure everything is string
|
|
||||||
var fields = ["to", "from", "value", "gas", "gasPrice"];
|
|
||||||
for(var i = 0; i < fields.length; i++) {
|
|
||||||
if(params[fields[i]] === undefined) {
|
|
||||||
params[fields[i]] = "";
|
|
||||||
}
|
|
||||||
params[fields[i]] = params[fields[i]].toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
var data;
|
|
||||||
if(typeof params.data === "object") {
|
|
||||||
data = "";
|
|
||||||
for(var i = 0; i < params.data.length; i++) {
|
|
||||||
data += params.data[i]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data = params.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
postData({call: "transact", args: [params.from, params.to, params.value, params.gas, params.gasPrice, "0x"+data]}, cb);
|
|
||||||
},
|
|
||||||
|
|
||||||
getMessages: function(filter, cb) {
|
|
||||||
postData({call: "messages", args: [filter]}, cb);
|
|
||||||
},
|
|
||||||
|
|
||||||
getStorageAt: function(address, storageAddress, cb) {
|
|
||||||
postData({call: "getStorage", args: [address, storageAddress]}, cb);
|
|
||||||
},
|
|
||||||
|
|
||||||
getEachStorageAt: function(address, cb){
|
|
||||||
postData({call: "getEachStorage", args: [address]}, cb);
|
|
||||||
},
|
|
||||||
|
|
||||||
getKey: function(cb) {
|
|
||||||
postData({call: "getKey"}, cb);
|
|
||||||
},
|
|
||||||
|
|
||||||
getTxCountAt: function(address, cb) {
|
|
||||||
postData({call: "getTxCountAt", args: [address]}, cb);
|
|
||||||
},
|
|
||||||
getIsMining: function(cb){
|
|
||||||
postData({call: "getIsMining"}, cb)
|
|
||||||
},
|
|
||||||
getIsListening: function(cb){
|
|
||||||
postData({call: "getIsListening"}, cb)
|
|
||||||
},
|
|
||||||
getCoinBase: function(cb){
|
|
||||||
postData({call: "getCoinBase"}, cb);
|
|
||||||
},
|
|
||||||
getPeerCount: function(cb){
|
|
||||||
postData({call: "getPeerCount"}, cb);
|
|
||||||
},
|
|
||||||
getBalanceAt: function(address, cb) {
|
|
||||||
postData({call: "getBalance", args: [address]}, cb);
|
|
||||||
},
|
|
||||||
getTransactionsFor: function(address, cb) {
|
|
||||||
postData({call: "getTransactionsFor", args: [address]}, cb);
|
|
||||||
},
|
|
||||||
|
|
||||||
getSecretToAddress: function(sec, cb) {
|
|
||||||
postData({call: "getSecretToAddress", args: [sec]}, cb);
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
watch: function(address, storageAddrOrCb, cb) {
|
|
||||||
var ev;
|
|
||||||
if(cb === undefined) {
|
|
||||||
cb = storageAddrOrCb;
|
|
||||||
storageAddrOrCb = "";
|
|
||||||
ev = "object:"+address;
|
|
||||||
} else {
|
|
||||||
ev = "storage:"+address+":"+storageAddrOrCb;
|
|
||||||
}
|
|
||||||
|
|
||||||
eth.on(ev, cb)
|
|
||||||
|
|
||||||
postData({call: "watch", args: [address, storageAddrOrCb]});
|
|
||||||
},
|
|
||||||
|
|
||||||
disconnect: function(address, storageAddrOrCb, cb) {
|
|
||||||
var ev;
|
|
||||||
if(cb === undefined) {
|
|
||||||
cb = storageAddrOrCb;
|
|
||||||
storageAddrOrCb = "";
|
|
||||||
ev = "object:"+address;
|
|
||||||
} else {
|
|
||||||
ev = "storage:"+address+":"+storageAddrOrCb;
|
|
||||||
}
|
|
||||||
|
|
||||||
eth.off(ev, cb)
|
|
||||||
|
|
||||||
postData({call: "disconnect", args: [address, storageAddrOrCb]});
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
|
|
||||||
watch: function(options) {
|
|
||||||
var filter = new Filter(options);
|
|
||||||
filter.number = newWatchNum().toString()
|
|
||||||
|
|
||||||
postData({call: "watch", args: [options, filter.number]})
|
|
||||||
|
|
||||||
return filter;
|
|
||||||
},
|
|
||||||
|
|
||||||
set: function(props) {
|
|
||||||
postData({call: "set", args: props});
|
|
||||||
},
|
|
||||||
|
|
||||||
on: function(event, cb) {
|
|
||||||
if(eth._onCallbacks[event] === undefined) {
|
|
||||||
eth._onCallbacks[event] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
eth._onCallbacks[event].push(cb);
|
|
||||||
|
|
||||||
return this
|
|
||||||
},
|
|
||||||
|
|
||||||
off: function(event, cb) {
|
|
||||||
if(eth._onCallbacks[event] !== undefined) {
|
|
||||||
var callbacks = eth._onCallbacks[event];
|
|
||||||
for(var i = 0; i < callbacks.length; i++) {
|
|
||||||
if(callbacks[i] === cb) {
|
|
||||||
delete callbacks[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this
|
|
||||||
},
|
|
||||||
|
|
||||||
trigger: function(event, data) {
|
|
||||||
var callbacks = eth._onCallbacks[event];
|
|
||||||
if(callbacks !== undefined) {
|
|
||||||
for(var i = 0; i < callbacks.length; i++) {
|
|
||||||
// Figure out whether the returned data was an array
|
|
||||||
// array means multiple return arguments (multiple params)
|
|
||||||
if(data instanceof Array) {
|
|
||||||
callbacks[i].apply(this, data);
|
|
||||||
} else {
|
|
||||||
callbacks[i].call(this, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var Filter = function(options) {
|
|
||||||
this.options = options;
|
|
||||||
};
|
|
||||||
Filter.prototype.changed = function(callback) {
|
|
||||||
// Register the watched:<number>. Qml will call the appropriate event if anything
|
|
||||||
// interesting happens in the land of Go.
|
|
||||||
eth.on("watched:"+this.number, callback)
|
|
||||||
}
|
|
||||||
Filter.prototype.getMessages = function(cb) {
|
|
||||||
return eth.getMessages(this.options, cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
var watchNum = 0;
|
|
||||||
function newWatchNum() {
|
|
||||||
return watchNum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
function postData(data, cb) {
|
|
||||||
data._seed = Math.floor(Math.random() * 1000000)
|
|
||||||
if(cb) {
|
|
||||||
eth._callbacks[data._seed] = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(data.args === undefined) {
|
|
||||||
data.args = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
navigator.qt.postMessage(JSON.stringify(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
navigator.qt.onmessage = function(ev) {
|
|
||||||
var data = JSON.parse(ev.data)
|
|
||||||
|
|
||||||
if(data._event !== undefined) {
|
|
||||||
eth.trigger(data._event, data.data);
|
|
||||||
} else {
|
|
||||||
if(data._seed) {
|
|
||||||
var cb = eth._callbacks[data._seed];
|
|
||||||
if(cb) {
|
|
||||||
cb.call(this, data.data)
|
|
||||||
|
|
||||||
// Remove the "trigger" callback
|
|
||||||
delete eth._callbacks[ev._seed];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eth.on("chain:changed", function() {
|
|
||||||
})
|
|
||||||
|
|
||||||
eth.on("messages", { /* filters */}, function(messages){
|
|
||||||
})
|
|
||||||
|
|
||||||
eth.on("pending:changed", function() {
|
|
||||||
})
|
|
||||||
|
|
||||||
5
cmd/mist/assets/ext/ethereum.js/.bowerrc
Normal file
5
cmd/mist/assets/ext/ethereum.js/.bowerrc
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"directory": "example/js/",
|
||||||
|
"cwd": "./",
|
||||||
|
"analytics": false
|
||||||
|
}
|
||||||
12
cmd/mist/assets/ext/ethereum.js/.editorconfig
Normal file
12
cmd/mist/assets/ext/ethereum.js/.editorconfig
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
18
cmd/mist/assets/ext/ethereum.js/.gitignore
vendored
Normal file
18
cmd/mist/assets/ext/ethereum.js/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
#
|
||||||
|
# If you find yourself ignoring temporary files generated by your text editor
|
||||||
|
# or operating system, you probably want to add a global ignore instead:
|
||||||
|
# git config --global core.excludesfile ~/.gitignore_global
|
||||||
|
|
||||||
|
*.swp
|
||||||
|
/tmp
|
||||||
|
*/**/*un~
|
||||||
|
*un~
|
||||||
|
.DS_Store
|
||||||
|
*/**/.DS_Store
|
||||||
|
ethereum/ethereum
|
||||||
|
ethereal/ethereal
|
||||||
|
example/js
|
||||||
|
node_modules
|
||||||
|
bower_components
|
||||||
|
npm-debug.log
|
||||||
50
cmd/mist/assets/ext/ethereum.js/.jshintrc
Normal file
50
cmd/mist/assets/ext/ethereum.js/.jshintrc
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"predef": [
|
||||||
|
"console",
|
||||||
|
"require",
|
||||||
|
"equal",
|
||||||
|
"test",
|
||||||
|
"testBoth",
|
||||||
|
"testWithDefault",
|
||||||
|
"raises",
|
||||||
|
"deepEqual",
|
||||||
|
"start",
|
||||||
|
"stop",
|
||||||
|
"ok",
|
||||||
|
"strictEqual",
|
||||||
|
"module",
|
||||||
|
"expect",
|
||||||
|
"reject",
|
||||||
|
"impl"
|
||||||
|
],
|
||||||
|
|
||||||
|
"esnext": true,
|
||||||
|
"proto": true,
|
||||||
|
"node" : true,
|
||||||
|
"browser" : true,
|
||||||
|
"browserify" : true,
|
||||||
|
|
||||||
|
"boss" : true,
|
||||||
|
"curly": false,
|
||||||
|
"debug": true,
|
||||||
|
"devel": true,
|
||||||
|
"eqeqeq": true,
|
||||||
|
"evil": true,
|
||||||
|
"forin": false,
|
||||||
|
"immed": false,
|
||||||
|
"laxbreak": false,
|
||||||
|
"newcap": true,
|
||||||
|
"noarg": true,
|
||||||
|
"noempty": false,
|
||||||
|
"nonew": false,
|
||||||
|
"nomen": false,
|
||||||
|
"onevar": false,
|
||||||
|
"plusplus": false,
|
||||||
|
"regexp": false,
|
||||||
|
"undef": true,
|
||||||
|
"sub": true,
|
||||||
|
"strict": false,
|
||||||
|
"white": false,
|
||||||
|
"shadow": true,
|
||||||
|
"eqnull": true
|
||||||
|
}
|
||||||
9
cmd/mist/assets/ext/ethereum.js/.npmignore
Normal file
9
cmd/mist/assets/ext/ethereum.js/.npmignore
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
example/js
|
||||||
|
node_modules
|
||||||
|
test
|
||||||
|
.gitignore
|
||||||
|
.editorconfig
|
||||||
|
.travis.yml
|
||||||
|
.npmignore
|
||||||
|
component.json
|
||||||
|
testling.html
|
||||||
11
cmd/mist/assets/ext/ethereum.js/.travis.yml
Normal file
11
cmd/mist/assets/ext/ethereum.js/.travis.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "0.11"
|
||||||
|
- "0.10"
|
||||||
|
before_script:
|
||||||
|
- npm install
|
||||||
|
- npm install jshint
|
||||||
|
script:
|
||||||
|
- "jshint *.js lib"
|
||||||
|
after_script:
|
||||||
|
- npm run-script gulp
|
||||||
14
cmd/mist/assets/ext/ethereum.js/LICENSE
Normal file
14
cmd/mist/assets/ext/ethereum.js/LICENSE
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
This file is part of ethereum.js.
|
||||||
|
|
||||||
|
ethereum.js is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ethereum.js is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
79
cmd/mist/assets/ext/ethereum.js/README.md
Normal file
79
cmd/mist/assets/ext/ethereum.js/README.md
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
# Ethereum JavaScript API
|
||||||
|
|
||||||
|
This is the Ethereum compatible JavaScript API using `Promise`s
|
||||||
|
which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js
|
||||||
|
|
||||||
|
[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url]
|
||||||
|
|
||||||
|
<!-- [](https://ci.testling.com/ethereum/ethereum.js) -->
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Node.js
|
||||||
|
|
||||||
|
npm install ethereum.js
|
||||||
|
|
||||||
|
### For browser
|
||||||
|
Bower
|
||||||
|
|
||||||
|
bower install ethereum.js
|
||||||
|
|
||||||
|
Component
|
||||||
|
|
||||||
|
component install ethereum/ethereum.js
|
||||||
|
|
||||||
|
* Include `ethereum.min.js` in your html file.
|
||||||
|
* Include [es6-promise](https://github.com/jakearchibald/es6-promise) or another ES6-Shim if your browser doesn't support ECMAScript 6.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Require the library:
|
||||||
|
|
||||||
|
var web3 = require('web3');
|
||||||
|
|
||||||
|
Set a provider (QtProvider, WebSocketProvider, HttpRpcProvider)
|
||||||
|
|
||||||
|
var web3.setProvider(new web3.providers.WebSocketProvider('ws://localhost:40404/eth'));
|
||||||
|
|
||||||
|
There you go, now you can use it:
|
||||||
|
|
||||||
|
```
|
||||||
|
web3.eth.coinbase.then(function(result){
|
||||||
|
console.log(result);
|
||||||
|
return web3.eth.balanceAt(result);
|
||||||
|
}).then(function(balance){
|
||||||
|
console.log(web3.toDecimal(balance));
|
||||||
|
}).catch(function(err){
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
For another example see `example/index.html`.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
* `gulp build`
|
||||||
|
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
**Please note this repo is in it's early stage.**
|
||||||
|
|
||||||
|
If you'd like to run a WebSocket ethereum node check out
|
||||||
|
[go-ethereum](https://github.com/ethereum/go-ethereum).
|
||||||
|
|
||||||
|
To install ethereum and spawn a node:
|
||||||
|
|
||||||
|
```
|
||||||
|
go get github.com/ethereum/go-ethereum/ethereum
|
||||||
|
ethereum -ws -loglevel=4
|
||||||
|
```
|
||||||
|
|
||||||
|
[npm-image]: https://badge.fury.io/js/ethereum.js.png
|
||||||
|
[npm-url]: https://npmjs.org/package/ethereum.js
|
||||||
|
[travis-image]: https://travis-ci.org/ethereum/ethereum.js.svg
|
||||||
|
[travis-url]: https://travis-ci.org/ethereum/ethereum.js
|
||||||
|
[dep-image]: https://david-dm.org/ethereum/ethereum.js.svg
|
||||||
|
[dep-url]: https://david-dm.org/ethereum/ethereum.js
|
||||||
|
[dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg
|
||||||
|
[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies
|
||||||
51
cmd/mist/assets/ext/ethereum.js/bower.json
Normal file
51
cmd/mist/assets/ext/ethereum.js/bower.json
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "ethereum.js",
|
||||||
|
"namespace": "ethereum",
|
||||||
|
"version": "0.0.3",
|
||||||
|
"description": "Ethereum Compatible JavaScript API",
|
||||||
|
"main": ["./dist/ethereum.js", "./dist/ethereum.min.js"],
|
||||||
|
"dependencies": {
|
||||||
|
"es6-promise": "#master"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/ethereum/ethereum.js.git"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/ethereum/ethereum.js",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/ethereum/ethereum.js/issues"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"ethereum",
|
||||||
|
"javascript",
|
||||||
|
"API"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Marek Kotewicz",
|
||||||
|
"email": "marek@ethdev.com",
|
||||||
|
"homepage": "https://github.com/debris"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Marian Oancea",
|
||||||
|
"email": "marian@ethdev.com",
|
||||||
|
"homepage": "https://github.com/cubedro"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0",
|
||||||
|
"ignore": [
|
||||||
|
"example",
|
||||||
|
"lib",
|
||||||
|
"node_modules",
|
||||||
|
"package.json",
|
||||||
|
".bowerrc",
|
||||||
|
".editorconfig",
|
||||||
|
".gitignore",
|
||||||
|
".jshintrc",
|
||||||
|
".npmignore",
|
||||||
|
".travis.yml",
|
||||||
|
"gulpfile.js",
|
||||||
|
"index.js",
|
||||||
|
"**/*.txt"
|
||||||
|
]
|
||||||
|
}
|
||||||
1184
cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
vendored
Normal file
1184
cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
29
cmd/mist/assets/ext/ethereum.js/dist/ethereum.js.map
vendored
Normal file
29
cmd/mist/assets/ext/ethereum.js/dist/ethereum.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
cmd/mist/assets/ext/ethereum.js/dist/ethereum.min.js
vendored
Normal file
1
cmd/mist/assets/ext/ethereum.js/dist/ethereum.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
41
cmd/mist/assets/ext/ethereum.js/example/balance.html
Normal file
41
cmd/mist/assets/ext/ethereum.js/example/balance.html
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
<!doctype>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
|
||||||
|
<script type="text/javascript" src="../dist/ethereum.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var web3 = require('web3');
|
||||||
|
web3.setProvider(new web3.providers.AutoProvider());
|
||||||
|
|
||||||
|
function watchBalance() {
|
||||||
|
var coinbase = web3.eth.coinbase;
|
||||||
|
var originalBalance = 0;
|
||||||
|
|
||||||
|
web3.eth.balanceAt(coinbase).then(function (balance) {
|
||||||
|
originalBalance = web3.toDecimal(balance);
|
||||||
|
document.getElementById('original').innerText = 'original balance: ' + originalBalance + ' watching...';
|
||||||
|
});
|
||||||
|
|
||||||
|
web3.eth.watch({altered: coinbase}).changed(function() {
|
||||||
|
web3.eth.balanceAt(coinbase).then(function (balance) {
|
||||||
|
var currentBalance = web3.toDecimal(balance);
|
||||||
|
document.getElementById("current").innerText = 'current: ' + currentBalance;
|
||||||
|
document.getElementById("diff").innerText = 'diff: ' + (currentBalance - originalBalance);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>coinbase balance</h1>
|
||||||
|
<button type="button" onClick="watchBalance();">watch balance</button>
|
||||||
|
<div></div>
|
||||||
|
<div id="original"></div>
|
||||||
|
<div id="current"></div>
|
||||||
|
<div id="diff"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
75
cmd/mist/assets/ext/ethereum.js/example/contract.html
Normal file
75
cmd/mist/assets/ext/ethereum.js/example/contract.html
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
<!doctype>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
|
||||||
|
<script type="text/javascript" src="../dist/ethereum.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var web3 = require('web3');
|
||||||
|
web3.setProvider(new web3.providers.AutoProvider());
|
||||||
|
|
||||||
|
// solidity source code
|
||||||
|
var source = "" +
|
||||||
|
"contract test {\n" +
|
||||||
|
" function multiply(uint a) returns(uint d) {\n" +
|
||||||
|
" return a * 7;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
// contract description, this will be autogenerated somehow
|
||||||
|
var desc = [{
|
||||||
|
"name": "multiply",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "a",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "d",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}];
|
||||||
|
|
||||||
|
var contract;
|
||||||
|
|
||||||
|
function createExampleContract() {
|
||||||
|
// hide create button
|
||||||
|
document.getElementById('create').style.visibility = 'hidden';
|
||||||
|
document.getElementById('source').innerText = source;
|
||||||
|
|
||||||
|
// create contract
|
||||||
|
web3.eth.transact({code: web3.eth.solidity(source)}).then(function (address) {
|
||||||
|
contract = web3.contract(address, desc);
|
||||||
|
document.getElementById('call').style.visibility = 'visible';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function callExampleContract() {
|
||||||
|
// this should be generated by ethereum
|
||||||
|
var param = parseInt(document.getElementById('value').value);
|
||||||
|
|
||||||
|
// call the contract
|
||||||
|
contract.multiply(param).call().then(function(res) {
|
||||||
|
document.getElementById('result').innerText = res[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>contract</h1>
|
||||||
|
<div id="source"></div>
|
||||||
|
<div id='create'>
|
||||||
|
<button type="button" onClick="createExampleContract();">create example contract</button>
|
||||||
|
</div>
|
||||||
|
<div id='call' style='visibility: hidden;'>
|
||||||
|
<input type="number" id="value" onkeyup='callExampleContract()'></input>
|
||||||
|
</div>
|
||||||
|
<div id="result"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
16
cmd/mist/assets/ext/ethereum.js/example/node-app.js
Normal file
16
cmd/mist/assets/ext/ethereum.js/example/node-app.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
require('es6-promise').polyfill();
|
||||||
|
|
||||||
|
var web3 = require("../index.js");
|
||||||
|
|
||||||
|
web3.setProvider(new web3.providers.HttpRpcProvider('http://localhost:8080'));
|
||||||
|
|
||||||
|
web3.eth.coinbase.then(function(result){
|
||||||
|
console.log(result);
|
||||||
|
return web3.eth.balanceAt(result);
|
||||||
|
}).then(function(balance){
|
||||||
|
console.log(web3.toDecimal(balance));
|
||||||
|
}).catch(function(err){
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
104
cmd/mist/assets/ext/ethereum.js/gulpfile.js
Normal file
104
cmd/mist/assets/ext/ethereum.js/gulpfile.js
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
var del = require('del');
|
||||||
|
var gulp = require('gulp');
|
||||||
|
var browserify = require('browserify');
|
||||||
|
var jshint = require('gulp-jshint');
|
||||||
|
var uglify = require('gulp-uglify');
|
||||||
|
var rename = require('gulp-rename');
|
||||||
|
var envify = require('envify/custom');
|
||||||
|
var unreach = require('unreachable-branch-transform');
|
||||||
|
var source = require('vinyl-source-stream');
|
||||||
|
var exorcist = require('exorcist');
|
||||||
|
var bower = require('bower');
|
||||||
|
|
||||||
|
var DEST = './dist/';
|
||||||
|
|
||||||
|
var build = function(src, dst, ugly) {
|
||||||
|
var result = browserify({
|
||||||
|
debug: true,
|
||||||
|
insert_global_vars: false,
|
||||||
|
detectGlobals: false,
|
||||||
|
bundleExternal: false
|
||||||
|
})
|
||||||
|
.require('./' + src + '.js', {expose: 'web3'})
|
||||||
|
.add('./' + src + '.js')
|
||||||
|
.transform('envify', {
|
||||||
|
NODE_ENV: 'build'
|
||||||
|
})
|
||||||
|
.transform('unreachable-branch-transform');
|
||||||
|
|
||||||
|
if (ugly) {
|
||||||
|
result = result.transform('uglifyify', {
|
||||||
|
mangle: false,
|
||||||
|
compress: {
|
||||||
|
dead_code: false,
|
||||||
|
conditionals: true,
|
||||||
|
unused: false,
|
||||||
|
hoist_funs: true,
|
||||||
|
hoist_vars: true,
|
||||||
|
negate_iife: false
|
||||||
|
},
|
||||||
|
beautify: true,
|
||||||
|
warnings: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.bundle()
|
||||||
|
.pipe(exorcist(path.join( DEST, dst + '.js.map')))
|
||||||
|
.pipe(source(dst + '.js'))
|
||||||
|
.pipe(gulp.dest( DEST ));
|
||||||
|
};
|
||||||
|
|
||||||
|
var uglifyFile = function(file) {
|
||||||
|
return gulp.src( DEST + file + '.js')
|
||||||
|
.pipe(uglify())
|
||||||
|
.pipe(rename(file + '.min.js'))
|
||||||
|
.pipe(gulp.dest( DEST ));
|
||||||
|
};
|
||||||
|
|
||||||
|
gulp.task('bower', function(cb){
|
||||||
|
bower.commands.install().on('end', function (installed){
|
||||||
|
console.log(installed);
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('clean', ['lint'], function(cb) {
|
||||||
|
del([ DEST ], cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('lint', function(){
|
||||||
|
return gulp.src(['./*.js', './lib/*.js'])
|
||||||
|
.pipe(jshint())
|
||||||
|
.pipe(jshint.reporter('default'));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('build', ['clean'], function () {
|
||||||
|
return build('index', 'ethereum', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('buildDev', ['clean'], function () {
|
||||||
|
return build('index', 'ethereum', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('uglify', ['build'], function(){
|
||||||
|
return uglifyFile('ethereum');
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('uglify', ['buildDev'], function(){
|
||||||
|
return uglifyFile('ethereum');
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('watch', function() {
|
||||||
|
gulp.watch(['./lib/*.js'], ['lint', 'prepare', 'build']);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('release', ['bower', 'lint', 'build', 'uglify']);
|
||||||
|
gulp.task('dev', ['bower', 'lint', 'buildDev', 'uglify']);
|
||||||
|
gulp.task('default', ['dev']);
|
||||||
|
|
||||||
8
cmd/mist/assets/ext/ethereum.js/index.js
Normal file
8
cmd/mist/assets/ext/ethereum.js/index.js
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
var web3 = require('./lib/web3');
|
||||||
|
web3.providers.WebSocketProvider = require('./lib/websocket');
|
||||||
|
web3.providers.HttpRpcProvider = require('./lib/httprpc');
|
||||||
|
web3.providers.QtProvider = require('./lib/qt');
|
||||||
|
web3.providers.AutoProvider = require('./lib/autoprovider');
|
||||||
|
web3.contract = require('./lib/contract');
|
||||||
|
|
||||||
|
module.exports = web3;
|
||||||
267
cmd/mist/assets/ext/ethereum.js/lib/abi.js
Normal file
267
cmd/mist/assets/ext/ethereum.js/lib/abi.js
Normal file
|
|
@ -0,0 +1,267 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethereum.js.
|
||||||
|
|
||||||
|
ethereum.js is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ethereum.js is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file abi.js
|
||||||
|
* @authors:
|
||||||
|
* Marek Kotewicz <marek@ethdev.com>
|
||||||
|
* Gav Wood <g@ethdev.com>
|
||||||
|
* @date 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: is these line is supposed to be here?
|
||||||
|
if (process.env.NODE_ENV !== 'build') {
|
||||||
|
var web3 = require('./web3'); // jshint ignore:line
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make these be actually accurate instead of falling back onto JS's doubles.
|
||||||
|
var hexToDec = function (hex) {
|
||||||
|
return parseInt(hex, 16).toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
var decToHex = function (dec) {
|
||||||
|
return parseInt(dec).toString(16);
|
||||||
|
};
|
||||||
|
|
||||||
|
var findIndex = function (array, callback) {
|
||||||
|
var end = false;
|
||||||
|
var i = 0;
|
||||||
|
for (; i < array.length && !end; i++) {
|
||||||
|
end = callback(array[i]);
|
||||||
|
}
|
||||||
|
return end ? i - 1 : -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
var findMethodIndex = function (json, methodName) {
|
||||||
|
return findIndex(json, function (method) {
|
||||||
|
return method.name === methodName;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var padLeft = function (string, chars) {
|
||||||
|
return new Array(chars - string.length + 1).join("0") + string;
|
||||||
|
};
|
||||||
|
|
||||||
|
var calcBitPadding = function (type, expected) {
|
||||||
|
var value = type.slice(expected.length);
|
||||||
|
if (value === "") {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
return parseInt(value) / 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
var calcBytePadding = function (type, expected) {
|
||||||
|
var value = type.slice(expected.length);
|
||||||
|
if (value === "") {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
return parseInt(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
var calcRealPadding = function (type, expected) {
|
||||||
|
var value = type.slice(expected.length);
|
||||||
|
if (value === "") {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
var sizes = value.split('x');
|
||||||
|
for (var padding = 0, i = 0; i < sizes; i++) {
|
||||||
|
padding += (sizes[i] / 8);
|
||||||
|
}
|
||||||
|
return padding;
|
||||||
|
};
|
||||||
|
|
||||||
|
var setupInputTypes = function () {
|
||||||
|
|
||||||
|
var prefixedType = function (prefix, calcPadding) {
|
||||||
|
return function (type, value) {
|
||||||
|
var expected = prefix;
|
||||||
|
if (type.indexOf(expected) !== 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var padding = calcPadding(type, expected);
|
||||||
|
if (typeof value === "number")
|
||||||
|
value = value.toString(16);
|
||||||
|
else if (typeof value === "string")
|
||||||
|
value = web3.toHex(value);
|
||||||
|
else if (value.indexOf('0x') === 0)
|
||||||
|
value = value.substr(2);
|
||||||
|
else
|
||||||
|
value = (+value).toString(16);
|
||||||
|
return padLeft(value, padding * 2);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var namedType = function (name, padding, formatter) {
|
||||||
|
return function (type, value) {
|
||||||
|
if (type !== name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return padLeft(formatter ? formatter(value) : value, padding * 2);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var formatBool = function (value) {
|
||||||
|
return value ? '0x1' : '0x0';
|
||||||
|
};
|
||||||
|
|
||||||
|
return [
|
||||||
|
prefixedType('uint', calcBitPadding),
|
||||||
|
prefixedType('int', calcBitPadding),
|
||||||
|
prefixedType('hash', calcBitPadding),
|
||||||
|
prefixedType('string', calcBytePadding),
|
||||||
|
prefixedType('real', calcRealPadding),
|
||||||
|
prefixedType('ureal', calcRealPadding),
|
||||||
|
namedType('address', 20),
|
||||||
|
namedType('bool', 1, formatBool),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var inputTypes = setupInputTypes();
|
||||||
|
|
||||||
|
var toAbiInput = function (json, methodName, params) {
|
||||||
|
var bytes = "";
|
||||||
|
var index = findMethodIndex(json, methodName);
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = "0x" + padLeft(index.toString(16), 2);
|
||||||
|
var method = json[index];
|
||||||
|
|
||||||
|
for (var i = 0; i < method.inputs.length; i++) {
|
||||||
|
var found = false;
|
||||||
|
for (var j = 0; j < inputTypes.length && !found; j++) {
|
||||||
|
found = inputTypes[j](method.inputs[i].type, params[i]);
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
console.error('unsupported json type: ' + method.inputs[i].type);
|
||||||
|
}
|
||||||
|
bytes += found;
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
var setupOutputTypes = function () {
|
||||||
|
|
||||||
|
var prefixedType = function (prefix, calcPadding) {
|
||||||
|
return function (type) {
|
||||||
|
var expected = prefix;
|
||||||
|
if (type.indexOf(expected) !== 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var padding = calcPadding(type, expected);
|
||||||
|
return padding * 2;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var namedType = function (name, padding) {
|
||||||
|
return function (type) {
|
||||||
|
return name === type ? padding * 2 : -1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var formatInt = function (value) {
|
||||||
|
return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
var formatHash = function (value) {
|
||||||
|
return "0x" + value;
|
||||||
|
};
|
||||||
|
|
||||||
|
var formatBool = function (value) {
|
||||||
|
return value === '1' ? true : false;
|
||||||
|
};
|
||||||
|
|
||||||
|
var formatString = function (value) {
|
||||||
|
return web3.toAscii(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return [
|
||||||
|
{ padding: prefixedType('uint', calcBitPadding), format: formatInt },
|
||||||
|
{ padding: prefixedType('int', calcBitPadding), format: formatInt },
|
||||||
|
{ padding: prefixedType('hash', calcBitPadding), format: formatHash },
|
||||||
|
{ padding: prefixedType('string', calcBytePadding), format: formatString },
|
||||||
|
{ padding: prefixedType('real', calcRealPadding), format: formatInt },
|
||||||
|
{ padding: prefixedType('ureal', calcRealPadding), format: formatInt },
|
||||||
|
{ padding: namedType('address', 20) },
|
||||||
|
{ padding: namedType('bool', 1), format: formatBool }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var outputTypes = setupOutputTypes();
|
||||||
|
|
||||||
|
var fromAbiOutput = function (json, methodName, output) {
|
||||||
|
var index = findMethodIndex(json, methodName);
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output = output.slice(2);
|
||||||
|
|
||||||
|
var result = [];
|
||||||
|
var method = json[index];
|
||||||
|
for (var i = 0; i < method.outputs.length; i++) {
|
||||||
|
var padding = -1;
|
||||||
|
for (var j = 0; j < outputTypes.length && padding === -1; j++) {
|
||||||
|
padding = outputTypes[j].padding(method.outputs[i].type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (padding === -1) {
|
||||||
|
// not found output parsing
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var res = output.slice(0, padding);
|
||||||
|
var formatter = outputTypes[j - 1].format;
|
||||||
|
result.push(formatter ? formatter(res) : ("0x" + res));
|
||||||
|
output = output.slice(padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
var inputParser = function (json) {
|
||||||
|
var parser = {};
|
||||||
|
json.forEach(function (method) {
|
||||||
|
parser[method.name] = function () {
|
||||||
|
var params = Array.prototype.slice.call(arguments);
|
||||||
|
return toAbiInput(json, method.name, params);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return parser;
|
||||||
|
};
|
||||||
|
|
||||||
|
var outputParser = function (json) {
|
||||||
|
var parser = {};
|
||||||
|
json.forEach(function (method) {
|
||||||
|
parser[method.name] = function (output) {
|
||||||
|
return fromAbiOutput(json, method.name, output);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return parser;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof(module) !== "undefined") {
|
||||||
|
module.exports = {
|
||||||
|
inputParser: inputParser,
|
||||||
|
outputParser: outputParser
|
||||||
|
};
|
||||||
|
}
|
||||||
103
cmd/mist/assets/ext/ethereum.js/lib/autoprovider.js
Normal file
103
cmd/mist/assets/ext/ethereum.js/lib/autoprovider.js
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethereum.js.
|
||||||
|
|
||||||
|
ethereum.js is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ethereum.js is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file autoprovider.js
|
||||||
|
* @authors:
|
||||||
|
* Marek Kotewicz <marek@ethdev.com>
|
||||||
|
* Marian Oancea <marian@ethdev.com>
|
||||||
|
* @date 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief if qt object is available, uses QtProvider,
|
||||||
|
* if not tries to connect over websockets
|
||||||
|
* if it fails, it uses HttpRpcProvider
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: is these line is supposed to be here?
|
||||||
|
if (process.env.NODE_ENV !== 'build') {
|
||||||
|
var WebSocket = require('ws'); // jshint ignore:line
|
||||||
|
var web3 = require('./web3'); // jshint ignore:line
|
||||||
|
}
|
||||||
|
|
||||||
|
var AutoProvider = function (userOptions) {
|
||||||
|
if (web3.haveProvider()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// before we determine what provider we are, we have to cache request
|
||||||
|
this.sendQueue = [];
|
||||||
|
this.onmessageQueue = [];
|
||||||
|
|
||||||
|
if (navigator.qt) {
|
||||||
|
this.provider = new web3.providers.QtProvider();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
userOptions = userOptions || {};
|
||||||
|
var options = {
|
||||||
|
httprpc: userOptions.httprpc || 'http://localhost:8080',
|
||||||
|
websockets: userOptions.websockets || 'ws://localhost:40404/eth'
|
||||||
|
};
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var closeWithSuccess = function (success) {
|
||||||
|
ws.close();
|
||||||
|
if (success) {
|
||||||
|
self.provider = new web3.providers.WebSocketProvider(options.websockets);
|
||||||
|
} else {
|
||||||
|
self.provider = new web3.providers.HttpRpcProvider(options.httprpc);
|
||||||
|
self.poll = self.provider.poll.bind(self.provider);
|
||||||
|
}
|
||||||
|
self.sendQueue.forEach(function (payload) {
|
||||||
|
self.provider(payload);
|
||||||
|
});
|
||||||
|
self.onmessageQueue.forEach(function (handler) {
|
||||||
|
self.provider.onmessage = handler;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var ws = new WebSocket(options.websockets);
|
||||||
|
|
||||||
|
ws.onopen = function() {
|
||||||
|
closeWithSuccess(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = function() {
|
||||||
|
closeWithSuccess(false);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
AutoProvider.prototype.send = function (payload) {
|
||||||
|
if (this.provider) {
|
||||||
|
this.provider.send(payload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.sendQueue.push(payload);
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperty(AutoProvider.prototype, 'onmessage', {
|
||||||
|
set: function (handler) {
|
||||||
|
if (this.provider) {
|
||||||
|
this.provider.onmessage = handler;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.onmessageQueue.push(handler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof(module) !== "undefined")
|
||||||
|
module.exports = AutoProvider;
|
||||||
66
cmd/mist/assets/ext/ethereum.js/lib/contract.js
Normal file
66
cmd/mist/assets/ext/ethereum.js/lib/contract.js
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethereum.js.
|
||||||
|
|
||||||
|
ethereum.js is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ethereum.js is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file contract.js
|
||||||
|
* @authors:
|
||||||
|
* Marek Kotewicz <marek@ethdev.com>
|
||||||
|
* @date 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: is these line is supposed to be here?
|
||||||
|
if (process.env.NODE_ENV !== 'build') {
|
||||||
|
var web3 = require('./web3'); // jshint ignore:line
|
||||||
|
}
|
||||||
|
|
||||||
|
var abi = require('./abi');
|
||||||
|
|
||||||
|
var contract = function (address, desc) {
|
||||||
|
var inputParser = abi.inputParser(desc);
|
||||||
|
var outputParser = abi.outputParser(desc);
|
||||||
|
|
||||||
|
var contract = {};
|
||||||
|
|
||||||
|
desc.forEach(function (method) {
|
||||||
|
contract[method.name] = function () {
|
||||||
|
var params = Array.prototype.slice.call(arguments);
|
||||||
|
var parsed = inputParser[method.name].apply(null, params);
|
||||||
|
|
||||||
|
var onSuccess = function (result) {
|
||||||
|
return outputParser[method.name](result);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
call: function (extra) {
|
||||||
|
extra = extra || {};
|
||||||
|
extra.to = address;
|
||||||
|
extra.data = parsed;
|
||||||
|
return web3.eth.call(extra).then(onSuccess);
|
||||||
|
},
|
||||||
|
transact: function (extra) {
|
||||||
|
extra = extra || {};
|
||||||
|
extra.to = address;
|
||||||
|
extra.data = parsed;
|
||||||
|
return web3.eth.transact(extra).then(onSuccess);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return contract;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof(module) !== "undefined")
|
||||||
|
module.exports = contract;
|
||||||
95
cmd/mist/assets/ext/ethereum.js/lib/httprpc.js
Normal file
95
cmd/mist/assets/ext/ethereum.js/lib/httprpc.js
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethereum.js.
|
||||||
|
|
||||||
|
ethereum.js is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ethereum.js is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file httprpc.js
|
||||||
|
* @authors:
|
||||||
|
* Marek Kotewicz <marek@ethdev.com>
|
||||||
|
* Marian Oancea <marian@ethdev.com>
|
||||||
|
* @date 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: is these line is supposed to be here?
|
||||||
|
if (process.env.NODE_ENV !== 'build') {
|
||||||
|
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
|
||||||
|
}
|
||||||
|
|
||||||
|
var HttpRpcProvider = function (host) {
|
||||||
|
this.handlers = [];
|
||||||
|
this.host = host;
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatJsonRpcObject(object) {
|
||||||
|
return {
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method: object.call,
|
||||||
|
params: object.args,
|
||||||
|
id: object._id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatJsonRpcMessage(message) {
|
||||||
|
var object = JSON.parse(message);
|
||||||
|
|
||||||
|
return {
|
||||||
|
_id: object.id,
|
||||||
|
data: object.result,
|
||||||
|
error: object.error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRpcProvider.prototype.sendRequest = function (payload, cb) {
|
||||||
|
var data = formatJsonRpcObject(payload);
|
||||||
|
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open("POST", this.host, true);
|
||||||
|
request.send(JSON.stringify(data));
|
||||||
|
request.onreadystatechange = function () {
|
||||||
|
if (request.readyState === 4 && cb) {
|
||||||
|
cb(request);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpRpcProvider.prototype.send = function (payload) {
|
||||||
|
var self = this;
|
||||||
|
this.sendRequest(payload, function (request) {
|
||||||
|
self.handlers.forEach(function (handler) {
|
||||||
|
handler.call(self, formatJsonRpcMessage(request.responseText));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpRpcProvider.prototype.poll = function (payload, id) {
|
||||||
|
var self = this;
|
||||||
|
this.sendRequest(payload, function (request) {
|
||||||
|
var parsed = JSON.parse(request.responseText);
|
||||||
|
if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.handlers.forEach(function (handler) {
|
||||||
|
handler.call(self, {_event: payload.call, _id: id, data: parsed.result});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperty(HttpRpcProvider.prototype, "onmessage", {
|
||||||
|
set: function (handler) {
|
||||||
|
this.handlers.push(handler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof(module) !== "undefined")
|
||||||
|
module.exports = HttpRpcProvider;
|
||||||
46
cmd/mist/assets/ext/ethereum.js/lib/qt.js
Normal file
46
cmd/mist/assets/ext/ethereum.js/lib/qt.js
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethereum.js.
|
||||||
|
|
||||||
|
ethereum.js is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ethereum.js is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file qt.js
|
||||||
|
* @authors:
|
||||||
|
* Jeffrey Wilcke <jeff@ethdev.com>
|
||||||
|
* Marek Kotewicz <marek@ethdev.com>
|
||||||
|
* @date 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
var QtProvider = function() {
|
||||||
|
this.handlers = [];
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
navigator.qt.onmessage = function (message) {
|
||||||
|
self.handlers.forEach(function (handler) {
|
||||||
|
handler.call(self, JSON.parse(message.data));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
QtProvider.prototype.send = function(payload) {
|
||||||
|
navigator.qt.postMessage(JSON.stringify(payload));
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperty(QtProvider.prototype, "onmessage", {
|
||||||
|
set: function(handler) {
|
||||||
|
this.handlers.push(handler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof(module) !== "undefined")
|
||||||
|
module.exports = QtProvider;
|
||||||
509
cmd/mist/assets/ext/ethereum.js/lib/web3.js
Normal file
509
cmd/mist/assets/ext/ethereum.js/lib/web3.js
Normal file
|
|
@ -0,0 +1,509 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethereum.js.
|
||||||
|
|
||||||
|
ethereum.js is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ethereum.js is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file main.js
|
||||||
|
* @authors:
|
||||||
|
* Jeffrey Wilcke <jeff@ethdev.com>
|
||||||
|
* Marek Kotewicz <marek@ethdev.com>
|
||||||
|
* Marian Oancea <marian@ethdev.com>
|
||||||
|
* Gav Wood <g@ethdev.com>
|
||||||
|
* @date 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
function flattenPromise (obj) {
|
||||||
|
if (obj instanceof Promise) {
|
||||||
|
return Promise.resolve(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj instanceof Array) {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
var promises = obj.map(function (o) {
|
||||||
|
return flattenPromise(o);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then(function (res) {
|
||||||
|
for (var i = 0; i < obj.length; i++) {
|
||||||
|
obj[i] = res[i];
|
||||||
|
}
|
||||||
|
resolve(obj);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj instanceof Object) {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
var keys = Object.keys(obj);
|
||||||
|
var promises = keys.map(function (key) {
|
||||||
|
return flattenPromise(obj[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then(function (res) {
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
obj[keys[i]] = res[i];
|
||||||
|
}
|
||||||
|
resolve(obj);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
var web3Methods = function () {
|
||||||
|
return [
|
||||||
|
{ name: 'sha3', call: 'web3_sha3' }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var ethMethods = function () {
|
||||||
|
var blockCall = function (args) {
|
||||||
|
return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber";
|
||||||
|
};
|
||||||
|
|
||||||
|
var transactionCall = function (args) {
|
||||||
|
return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber';
|
||||||
|
};
|
||||||
|
|
||||||
|
var uncleCall = function (args) {
|
||||||
|
return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber';
|
||||||
|
};
|
||||||
|
|
||||||
|
var methods = [
|
||||||
|
{ name: 'balanceAt', call: 'eth_balanceAt' },
|
||||||
|
{ name: 'stateAt', call: 'eth_stateAt' },
|
||||||
|
{ name: 'storageAt', call: 'eth_storageAt' },
|
||||||
|
{ name: 'countAt', call: 'eth_countAt'},
|
||||||
|
{ name: 'codeAt', call: 'eth_codeAt' },
|
||||||
|
{ name: 'transact', call: 'eth_transact' },
|
||||||
|
{ name: 'call', call: 'eth_call' },
|
||||||
|
{ name: 'block', call: blockCall },
|
||||||
|
{ name: 'transaction', call: transactionCall },
|
||||||
|
{ name: 'uncle', call: uncleCall },
|
||||||
|
{ name: 'compilers', call: 'eth_compilers' },
|
||||||
|
{ name: 'lll', call: 'eth_lll' },
|
||||||
|
{ name: 'solidity', call: 'eth_solidity' },
|
||||||
|
{ name: 'serpent', call: 'eth_serpent' },
|
||||||
|
{ name: 'logs', call: 'eth_logs' }
|
||||||
|
];
|
||||||
|
return methods;
|
||||||
|
};
|
||||||
|
|
||||||
|
var ethProperties = function () {
|
||||||
|
return [
|
||||||
|
{ name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },
|
||||||
|
{ name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },
|
||||||
|
{ name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },
|
||||||
|
{ name: 'gasPrice', getter: 'eth_gasPrice' },
|
||||||
|
{ name: 'account', getter: 'eth_account' },
|
||||||
|
{ name: 'accounts', getter: 'eth_accounts' },
|
||||||
|
{ name: 'peerCount', getter: 'eth_peerCount' },
|
||||||
|
{ name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },
|
||||||
|
{ name: 'number', getter: 'eth_number'}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var dbMethods = function () {
|
||||||
|
return [
|
||||||
|
{ name: 'put', call: 'db_put' },
|
||||||
|
{ name: 'get', call: 'db_get' },
|
||||||
|
{ name: 'putString', call: 'db_putString' },
|
||||||
|
{ name: 'getString', call: 'db_getString' }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var shhMethods = function () {
|
||||||
|
return [
|
||||||
|
{ name: 'post', call: 'shh_post' },
|
||||||
|
{ name: 'newIdentity', call: 'shh_newIdentity' },
|
||||||
|
{ name: 'haveIdentity', call: 'shh_haveIdentity' },
|
||||||
|
{ name: 'newGroup', call: 'shh_newGroup' },
|
||||||
|
{ name: 'addToGroup', call: 'shh_addToGroup' }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var ethWatchMethods = function () {
|
||||||
|
var newFilter = function (args) {
|
||||||
|
return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';
|
||||||
|
};
|
||||||
|
|
||||||
|
return [
|
||||||
|
{ name: 'newFilter', call: newFilter },
|
||||||
|
{ name: 'uninstallFilter', call: 'eth_uninstallFilter' },
|
||||||
|
{ name: 'getMessages', call: 'eth_filterLogs' }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var shhWatchMethods = function () {
|
||||||
|
return [
|
||||||
|
{ name: 'newFilter', call: 'shh_newFilter' },
|
||||||
|
{ name: 'uninstallFilter', call: 'shh_uninstallFilter' },
|
||||||
|
{ name: 'getMessage', call: 'shh_getMessages' }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var setupMethods = function (obj, methods) {
|
||||||
|
methods.forEach(function (method) {
|
||||||
|
obj[method.name] = function () {
|
||||||
|
return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {
|
||||||
|
var call = typeof method.call === "function" ? method.call(args) : method.call;
|
||||||
|
return {call: call, args: args};
|
||||||
|
}).then(function (request) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
web3.provider.send(request, function (err, result) {
|
||||||
|
if (!err) {
|
||||||
|
resolve(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).catch(function(err) {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var setupProperties = function (obj, properties) {
|
||||||
|
properties.forEach(function (property) {
|
||||||
|
var proto = {};
|
||||||
|
proto.get = function () {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
web3.provider.send({call: property.getter}, function(err, result) {
|
||||||
|
if (!err) {
|
||||||
|
resolve(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (property.setter) {
|
||||||
|
proto.set = function (val) {
|
||||||
|
return flattenPromise([val]).then(function (args) {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
web3.provider.send({call: property.setter, args: args}, function (err, result) {
|
||||||
|
if (!err) {
|
||||||
|
resolve(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).catch(function (err) {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Object.defineProperty(obj, property.name, proto);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: import from a dependency, don't duplicate.
|
||||||
|
var hexToDec = function (hex) {
|
||||||
|
return parseInt(hex, 16).toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
var decToHex = function (dec) {
|
||||||
|
return parseInt(dec).toString(16);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var web3 = {
|
||||||
|
_callbacks: {},
|
||||||
|
_events: {},
|
||||||
|
providers: {},
|
||||||
|
|
||||||
|
toHex: function(str) {
|
||||||
|
var hex = "";
|
||||||
|
for(var i = 0; i < str.length; i++) {
|
||||||
|
var n = str.charCodeAt(i).toString(16);
|
||||||
|
hex += n.length < 2 ? '0' + n : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
|
},
|
||||||
|
|
||||||
|
toAscii: function(hex) {
|
||||||
|
// Find termination
|
||||||
|
var str = "";
|
||||||
|
var i = 0, l = hex.length;
|
||||||
|
if (hex.substring(0, 2) === '0x')
|
||||||
|
i = 2;
|
||||||
|
for(; i < l; i+=2) {
|
||||||
|
var code = hex.charCodeAt(i);
|
||||||
|
if(code === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
},
|
||||||
|
|
||||||
|
fromAscii: function(str, pad) {
|
||||||
|
pad = pad === undefined ? 32 : pad;
|
||||||
|
var hex = this.toHex(str);
|
||||||
|
while(hex.length < pad*2)
|
||||||
|
hex += "00";
|
||||||
|
return "0x" + hex;
|
||||||
|
},
|
||||||
|
|
||||||
|
toDecimal: function (val) {
|
||||||
|
return hexToDec(val.substring(2));
|
||||||
|
},
|
||||||
|
|
||||||
|
fromDecimal: function (val) {
|
||||||
|
return "0x" + decToHex(val);
|
||||||
|
},
|
||||||
|
|
||||||
|
toEth: function(str) {
|
||||||
|
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
|
||||||
|
var unit = 0;
|
||||||
|
var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];
|
||||||
|
while (val > 3000 && unit < units.length - 1)
|
||||||
|
{
|
||||||
|
val /= 1000;
|
||||||
|
unit++;
|
||||||
|
}
|
||||||
|
var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);
|
||||||
|
var replaceFunction = function($0, $1, $2) {
|
||||||
|
return $1 + ',' + $2;
|
||||||
|
};
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
var o = s;
|
||||||
|
s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction);
|
||||||
|
if (o === s)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s + ' ' + units[unit];
|
||||||
|
},
|
||||||
|
|
||||||
|
eth: {
|
||||||
|
prototype: Object(), // jshint ignore:line
|
||||||
|
watch: function (params) {
|
||||||
|
return new Filter(params, ethWatch);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
db: {
|
||||||
|
prototype: Object() // jshint ignore:line
|
||||||
|
},
|
||||||
|
|
||||||
|
shh: {
|
||||||
|
prototype: Object(), // jshint ignore:line
|
||||||
|
watch: function (params) {
|
||||||
|
return new Filter(params, shhWatch);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
on: function(event, id, cb) {
|
||||||
|
if(web3._events[event] === undefined) {
|
||||||
|
web3._events[event] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
web3._events[event][id] = cb;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
off: function(event, id) {
|
||||||
|
if(web3._events[event] !== undefined) {
|
||||||
|
delete web3._events[event][id];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
trigger: function(event, id, data) {
|
||||||
|
var callbacks = web3._events[event];
|
||||||
|
if (!callbacks || !callbacks[id]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var cb = callbacks[id];
|
||||||
|
cb(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
setupMethods(web3, web3Methods());
|
||||||
|
setupMethods(web3.eth, ethMethods());
|
||||||
|
setupProperties(web3.eth, ethProperties());
|
||||||
|
setupMethods(web3.db, dbMethods());
|
||||||
|
setupMethods(web3.shh, shhMethods());
|
||||||
|
|
||||||
|
var ethWatch = {
|
||||||
|
changed: 'eth_changed'
|
||||||
|
};
|
||||||
|
setupMethods(ethWatch, ethWatchMethods());
|
||||||
|
var shhWatch = {
|
||||||
|
changed: 'shh_changed'
|
||||||
|
};
|
||||||
|
setupMethods(shhWatch, shhWatchMethods());
|
||||||
|
|
||||||
|
var ProviderManager = function() {
|
||||||
|
this.queued = [];
|
||||||
|
this.polls = [];
|
||||||
|
this.ready = false;
|
||||||
|
this.provider = undefined;
|
||||||
|
this.id = 1;
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var poll = function () {
|
||||||
|
if (self.provider && self.provider.poll) {
|
||||||
|
self.polls.forEach(function (data) {
|
||||||
|
data.data._id = self.id;
|
||||||
|
self.id++;
|
||||||
|
self.provider.poll(data.data, data.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setTimeout(poll, 12000);
|
||||||
|
};
|
||||||
|
poll();
|
||||||
|
};
|
||||||
|
|
||||||
|
ProviderManager.prototype.send = function(data, cb) {
|
||||||
|
data._id = this.id;
|
||||||
|
if (cb) {
|
||||||
|
web3._callbacks[data._id] = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.args = data.args || [];
|
||||||
|
this.id++;
|
||||||
|
|
||||||
|
if(this.provider !== undefined) {
|
||||||
|
this.provider.send(data);
|
||||||
|
} else {
|
||||||
|
console.warn("provider is not set");
|
||||||
|
this.queued.push(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ProviderManager.prototype.set = function(provider) {
|
||||||
|
if(this.provider !== undefined && this.provider.unload !== undefined) {
|
||||||
|
this.provider.unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.provider = provider;
|
||||||
|
this.ready = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
ProviderManager.prototype.sendQueued = function() {
|
||||||
|
for(var i = 0; this.queued.length; i++) {
|
||||||
|
// Resend
|
||||||
|
this.send(this.queued[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ProviderManager.prototype.installed = function() {
|
||||||
|
return this.provider !== undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
ProviderManager.prototype.startPolling = function (data, pollId) {
|
||||||
|
if (!this.provider || !this.provider.poll) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.polls.push({data: data, id: pollId});
|
||||||
|
};
|
||||||
|
|
||||||
|
ProviderManager.prototype.stopPolling = function (pollId) {
|
||||||
|
for (var i = this.polls.length; i--;) {
|
||||||
|
var poll = this.polls[i];
|
||||||
|
if (poll.id === pollId) {
|
||||||
|
this.polls.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
web3.provider = new ProviderManager();
|
||||||
|
|
||||||
|
web3.setProvider = function(provider) {
|
||||||
|
provider.onmessage = messageHandler;
|
||||||
|
web3.provider.set(provider);
|
||||||
|
web3.provider.sendQueued();
|
||||||
|
};
|
||||||
|
|
||||||
|
web3.haveProvider = function() {
|
||||||
|
return !!web3.provider.provider;
|
||||||
|
};
|
||||||
|
|
||||||
|
var Filter = function(options, impl) {
|
||||||
|
this.impl = impl;
|
||||||
|
this.callbacks = [];
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
this.promise = impl.newFilter(options);
|
||||||
|
this.promise.then(function (id) {
|
||||||
|
self.id = id;
|
||||||
|
web3.on(impl.changed, id, self.trigger.bind(self));
|
||||||
|
web3.provider.startPolling({call: impl.changed, args: [id]}, id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Filter.prototype.arrived = function(callback) {
|
||||||
|
this.changed(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
Filter.prototype.changed = function(callback) {
|
||||||
|
var self = this;
|
||||||
|
this.promise.then(function(id) {
|
||||||
|
self.callbacks.push(callback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Filter.prototype.trigger = function(messages) {
|
||||||
|
for(var i = 0; i < this.callbacks.length; i++) {
|
||||||
|
this.callbacks[i].call(this, messages);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Filter.prototype.uninstall = function() {
|
||||||
|
var self = this;
|
||||||
|
this.promise.then(function (id) {
|
||||||
|
self.impl.uninstallFilter(id);
|
||||||
|
web3.provider.stopPolling(id);
|
||||||
|
web3.off(impl.changed, id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Filter.prototype.messages = function() {
|
||||||
|
var self = this;
|
||||||
|
return this.promise.then(function (id) {
|
||||||
|
return self.impl.getMessages(id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Filter.prototype.logs = function () {
|
||||||
|
return this.messages();
|
||||||
|
};
|
||||||
|
|
||||||
|
function messageHandler(data) {
|
||||||
|
if(data._event !== undefined) {
|
||||||
|
web3.trigger(data._event, data._id, data.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data._id) {
|
||||||
|
var cb = web3._callbacks[data._id];
|
||||||
|
if (cb) {
|
||||||
|
cb.call(this, data.error, data.data);
|
||||||
|
delete web3._callbacks[data._id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof(module) !== "undefined")
|
||||||
|
module.exports = web3;
|
||||||
78
cmd/mist/assets/ext/ethereum.js/lib/websocket.js
Normal file
78
cmd/mist/assets/ext/ethereum.js/lib/websocket.js
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethereum.js.
|
||||||
|
|
||||||
|
ethereum.js is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ethereum.js is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file websocket.js
|
||||||
|
* @authors:
|
||||||
|
* Jeffrey Wilcke <jeff@ethdev.com>
|
||||||
|
* Marek Kotewicz <marek@ethdev.com>
|
||||||
|
* Marian Oancea <marian@ethdev.com>
|
||||||
|
* @date 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: is these line is supposed to be here?
|
||||||
|
if (process.env.NODE_ENV !== 'build') {
|
||||||
|
var WebSocket = require('ws'); // jshint ignore:line
|
||||||
|
}
|
||||||
|
|
||||||
|
var WebSocketProvider = function(host) {
|
||||||
|
// onmessage handlers
|
||||||
|
this.handlers = [];
|
||||||
|
// queue will be filled with messages if send is invoked before the ws is ready
|
||||||
|
this.queued = [];
|
||||||
|
this.ready = false;
|
||||||
|
|
||||||
|
this.ws = new WebSocket(host);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
this.ws.onmessage = function(event) {
|
||||||
|
for(var i = 0; i < self.handlers.length; i++) {
|
||||||
|
self.handlers[i].call(self, JSON.parse(event.data), event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onopen = function() {
|
||||||
|
self.ready = true;
|
||||||
|
|
||||||
|
for(var i = 0; i < self.queued.length; i++) {
|
||||||
|
// Resend
|
||||||
|
self.send(self.queued[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
WebSocketProvider.prototype.send = function(payload) {
|
||||||
|
if(this.ready) {
|
||||||
|
var data = JSON.stringify(payload);
|
||||||
|
|
||||||
|
this.ws.send(data);
|
||||||
|
} else {
|
||||||
|
this.queued.push(payload);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WebSocketProvider.prototype.onMessage = function(handler) {
|
||||||
|
this.handlers.push(handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
WebSocketProvider.prototype.unload = function() {
|
||||||
|
this.ws.close();
|
||||||
|
};
|
||||||
|
Object.defineProperty(WebSocketProvider.prototype, "onmessage", {
|
||||||
|
set: function(provider) { this.onMessage(provider); }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof(module) !== "undefined")
|
||||||
|
module.exports = WebSocketProvider;
|
||||||
67
cmd/mist/assets/ext/ethereum.js/package.json
Normal file
67
cmd/mist/assets/ext/ethereum.js/package.json
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
{
|
||||||
|
"name": "ethereum.js",
|
||||||
|
"namespace": "ethereum",
|
||||||
|
"version": "0.0.6",
|
||||||
|
"description": "Ethereum Compatible JavaScript API",
|
||||||
|
"main": "./index.js",
|
||||||
|
"directories": {
|
||||||
|
"lib": "./lib"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"es6-promise": "*",
|
||||||
|
"ws": "*",
|
||||||
|
"xmlhttprequest": "*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"bower": ">=1.3.0",
|
||||||
|
"browserify": ">=6.0",
|
||||||
|
"del": ">=0.1.1",
|
||||||
|
"envify": "^3.0.0",
|
||||||
|
"exorcist": "^0.1.6",
|
||||||
|
"gulp": ">=3.4.0",
|
||||||
|
"gulp-jshint": ">=1.5.0",
|
||||||
|
"gulp-rename": ">=1.2.0",
|
||||||
|
"gulp-uglify": ">=1.0.0",
|
||||||
|
"jshint": ">=2.5.0",
|
||||||
|
"uglifyify": "^2.6.0",
|
||||||
|
"unreachable-branch-transform": "^0.1.0",
|
||||||
|
"vinyl-source-stream": "^1.0.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "gulp",
|
||||||
|
"watch": "gulp watch",
|
||||||
|
"lint": "gulp lint"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/ethereum/ethereum.js.git"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/ethereum/ethereum.js",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/ethereum/ethereum.js/issues"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"ethereum",
|
||||||
|
"javascript",
|
||||||
|
"API"
|
||||||
|
],
|
||||||
|
"author": "ethdev.com",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jeffery Wilcke",
|
||||||
|
"email": "jeff@ethdev.com",
|
||||||
|
"url": "https://github.com/obscuren"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Marek Kotewicz",
|
||||||
|
"email": "marek@ethdev.com",
|
||||||
|
"url": "https://github.com/debris"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Marian Oancea",
|
||||||
|
"email": "marian@ethdev.com",
|
||||||
|
"url": "https://github.com/cubedro"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0"
|
||||||
|
}
|
||||||
|
|
@ -66,7 +66,11 @@ Rectangle {
|
||||||
onMessages: {
|
onMessages: {
|
||||||
// Bit of a cheat to get proper JSON
|
// Bit of a cheat to get proper JSON
|
||||||
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
|
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
|
||||||
webview.postEvent("messages", [m, id]);
|
webview.postEvent("messages", id, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onShhMessage(message, id) {
|
||||||
|
webview.postEvent("shh_changed", id, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|
@ -105,7 +109,8 @@ Rectangle {
|
||||||
leftMargin: 5
|
leftMargin: 5
|
||||||
rightMargin: 5
|
rightMargin: 5
|
||||||
}
|
}
|
||||||
text: "http://etherian.io"
|
//text: "http://etherian.io"
|
||||||
|
text: webview.url;
|
||||||
id: uriNav
|
id: uriNav
|
||||||
y: parent.height / 2 - this.height / 2
|
y: parent.height / 2 - this.height / 2
|
||||||
|
|
||||||
|
|
@ -147,6 +152,12 @@ Rectangle {
|
||||||
window.open(request.url.toString());
|
window.open(request.url.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function injectJs(js) {
|
||||||
|
webview.experimental.navigatorQtObjectEnabled = true;
|
||||||
|
webview.experimental.evaluateJavaScript(js)
|
||||||
|
webview.experimental.javascriptEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
function sendMessage(data) {
|
function sendMessage(data) {
|
||||||
webview.experimental.postMessage(JSON.stringify(data))
|
webview.experimental.postMessage(JSON.stringify(data))
|
||||||
}
|
}
|
||||||
|
|
@ -155,8 +166,7 @@ Rectangle {
|
||||||
experimental.preferences.javascriptEnabled: true
|
experimental.preferences.javascriptEnabled: true
|
||||||
experimental.preferences.navigatorQtObjectEnabled: true
|
experimental.preferences.navigatorQtObjectEnabled: true
|
||||||
experimental.preferences.developerExtrasEnabled: true
|
experimental.preferences.developerExtrasEnabled: true
|
||||||
//experimental.userScripts: ["../ext/qt_messaging_adapter.js", "../ext/q.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"]
|
experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"]
|
||||||
experimental.userScripts: ["../ext/q.js", "../ext/eth.js/main.js", "../ext/eth.js/qt.js", "../ext/setup.js"]
|
|
||||||
experimental.onMessageReceived: {
|
experimental.onMessageReceived: {
|
||||||
console.log("[onMessageReceived]: ", message.data)
|
console.log("[onMessageReceived]: ", message.data)
|
||||||
// TODO move to messaging.js
|
// TODO move to messaging.js
|
||||||
|
|
@ -164,51 +174,51 @@ Rectangle {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch(data.call) {
|
switch(data.call) {
|
||||||
case "compile":
|
case "eth_compile":
|
||||||
postData(data._id, eth.compile(data.args[0]))
|
postData(data._id, eth.compile(data.args[0]))
|
||||||
break
|
break
|
||||||
|
|
||||||
case "coinbase":
|
case "eth_coinbase":
|
||||||
postData(data._id, eth.coinBase())
|
postData(data._id, eth.coinBase())
|
||||||
|
|
||||||
case "account":
|
case "eth_account":
|
||||||
postData(data._id, eth.key().address);
|
postData(data._id, eth.key().address);
|
||||||
|
|
||||||
case "isListening":
|
case "eth_istening":
|
||||||
postData(data._id, eth.isListening())
|
postData(data._id, eth.isListening())
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case "isMining":
|
case "eth_mining":
|
||||||
postData(data._id, eth.isMining())
|
postData(data._id, eth.isMining())
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case "peerCount":
|
case "eth_peerCount":
|
||||||
postData(data._id, eth.peerCount())
|
postData(data._id, eth.peerCount())
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case "countAt":
|
case "eth_countAt":
|
||||||
require(1)
|
require(1)
|
||||||
postData(data._id, eth.txCountAt(data.args[0]))
|
postData(data._id, eth.txCountAt(data.args[0]))
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case "codeAt":
|
case "eth_codeAt":
|
||||||
require(1)
|
require(1)
|
||||||
var code = eth.codeAt(data.args[0])
|
var code = eth.codeAt(data.args[0])
|
||||||
postData(data._id, code);
|
postData(data._id, code);
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case "blockByNumber":
|
case "eth_blockByNumber":
|
||||||
require(1)
|
require(1)
|
||||||
var block = eth.blockByNumber(data.args[0])
|
var block = eth.blockByNumber(data.args[0])
|
||||||
postData(data._id, block)
|
postData(data._id, block)
|
||||||
break
|
break
|
||||||
|
|
||||||
case "blockByHash":
|
case "eth_blockByHash":
|
||||||
require(1)
|
require(1)
|
||||||
var block = eth.blockByHash(data.args[0])
|
var block = eth.blockByHash(data.args[0])
|
||||||
postData(data._id, block)
|
postData(data._id, block)
|
||||||
|
|
@ -219,8 +229,8 @@ Rectangle {
|
||||||
postData(data._id, block.transactions[data.args[1]])
|
postData(data._id, block.transactions[data.args[1]])
|
||||||
break
|
break
|
||||||
|
|
||||||
case "transactionByHash":
|
case "eth_transactionByHash":
|
||||||
case "transactionByNumber":
|
case "eth_transactionByNumber":
|
||||||
require(2)
|
require(2)
|
||||||
|
|
||||||
var block;
|
var block;
|
||||||
|
|
@ -234,8 +244,8 @@ Rectangle {
|
||||||
postData(data._id, tx)
|
postData(data._id, tx)
|
||||||
break
|
break
|
||||||
|
|
||||||
case "uncleByHash":
|
case "eth_uncleByHash":
|
||||||
case "uncleByNumber":
|
case "eth_uncleByNumber":
|
||||||
require(2)
|
require(2)
|
||||||
|
|
||||||
var block;
|
var block;
|
||||||
|
|
@ -258,7 +268,7 @@ Rectangle {
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case "stateAt":
|
case "eth_stateAt":
|
||||||
require(2);
|
require(2);
|
||||||
|
|
||||||
var storage = eth.storageAt(data.args[0], data.args[1]);
|
var storage = eth.storageAt(data.args[0], data.args[1]);
|
||||||
|
|
@ -266,55 +276,41 @@ Rectangle {
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case "call":
|
case "eth_call":
|
||||||
require(1);
|
require(1);
|
||||||
var ret = eth.call(data.args)
|
var ret = eth.call(data.args)
|
||||||
postData(data._id, ret)
|
postData(data._id, ret)
|
||||||
break
|
break
|
||||||
|
|
||||||
case "balanceAt":
|
case "eth_balanceAt":
|
||||||
require(1);
|
require(1);
|
||||||
|
|
||||||
postData(data._id, eth.balanceAt(data.args[0]));
|
postData(data._id, eth.balanceAt(data.args[0]));
|
||||||
break
|
break
|
||||||
|
|
||||||
case "watch":
|
case "eth_watch":
|
||||||
require(2)
|
require(2)
|
||||||
eth.watch(data.args[0], data.args[1])
|
eth.watch(data.args[0], data.args[1])
|
||||||
|
|
||||||
case "disconnect":
|
case "eth_disconnect":
|
||||||
require(1)
|
require(1)
|
||||||
postData(data._id, null)
|
postData(data._id, null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "messages":
|
case "eth_newFilterString":
|
||||||
require(1);
|
|
||||||
|
|
||||||
var messages = JSON.parse(eth.getMessages(data.args[0]))
|
|
||||||
postData(data._id, messages)
|
|
||||||
break
|
|
||||||
|
|
||||||
case "mutan":
|
|
||||||
require(1)
|
|
||||||
|
|
||||||
var code = eth.compileMutan(data.args[0])
|
|
||||||
postData(data._id, "0x"+code)
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "newFilterString":
|
|
||||||
require(1)
|
require(1)
|
||||||
var id = eth.newFilterString(data.args[0])
|
var id = eth.newFilterString(data.args[0])
|
||||||
postData(data._id, id);
|
postData(data._id, id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "newFilter":
|
case "eth_newFilter":
|
||||||
require(1)
|
require(1)
|
||||||
var id = eth.newFilter(data.args[0])
|
var id = eth.newFilter(data.args[0])
|
||||||
|
|
||||||
postData(data._id, id);
|
postData(data._id, id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "getMessages":
|
case "eth_messages":
|
||||||
require(1);
|
require(1);
|
||||||
|
|
||||||
var messages = eth.messages(data.args[0]);
|
var messages = eth.messages(data.args[0]);
|
||||||
|
|
@ -323,10 +319,40 @@ Rectangle {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "deleteFilter":
|
case "eth_deleteFilter":
|
||||||
require(1);
|
require(1);
|
||||||
eth.uninstallFilter(data.args[0])
|
eth.uninstallFilter(data.args[0])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case "shh_newFilter":
|
||||||
|
require(1);
|
||||||
|
var id = shh.watch(data.args[0], window);
|
||||||
|
postData(data._id, id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "shh_newIdentity":
|
||||||
|
var id = shh.newIdentity()
|
||||||
|
postData(data._id, id)
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
case "shh_post":
|
||||||
|
require(1);
|
||||||
|
|
||||||
|
var params = data.args[0];
|
||||||
|
var fields = ["payload", "to", "from"];
|
||||||
|
for(var i = 0; i < fields.length; i++) {
|
||||||
|
params[fields[i]] = params[fields[i]] || "";
|
||||||
|
}
|
||||||
|
if(typeof params.payload !== "object") { params.payload = [params.payload]; } //params.payload = params.payload.join(""); }
|
||||||
|
params.topics = params.topics || [];
|
||||||
|
params.priority = params.priority || 1000;
|
||||||
|
params.ttl = params.ttl || 100;
|
||||||
|
|
||||||
|
shh.post(params.payload, params.to, params.from, params.topics, params.priority, params.ttl);
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log(data.call + ": " + e)
|
console.log(data.call + ": " + e)
|
||||||
|
|
@ -348,8 +374,8 @@ Rectangle {
|
||||||
function postData(seed, data) {
|
function postData(seed, data) {
|
||||||
webview.experimental.postMessage(JSON.stringify({data: data, _id: seed}))
|
webview.experimental.postMessage(JSON.stringify({data: data, _id: seed}))
|
||||||
}
|
}
|
||||||
function postEvent(event, data) {
|
function postEvent(event, id, data) {
|
||||||
webview.experimental.postMessage(JSON.stringify({data: data, _event: event}))
|
webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWatchedCb(data, id) {
|
function onWatchedCb(data, id) {
|
||||||
|
|
@ -45,7 +45,7 @@ ApplicationWindow {
|
||||||
// Takes care of loading all default plugins
|
// Takes care of loading all default plugins
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
||||||
var browser = addPlugin("./webapp.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
var browser = addPlugin("./browser.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
||||||
root.browser = browser;
|
root.browser = browser;
|
||||||
addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
||||||
|
|
||||||
|
|
@ -59,8 +59,8 @@ ApplicationWindow {
|
||||||
|
|
||||||
mainSplit.setView(wallet.view, wallet.menuItem);
|
mainSplit.setView(wallet.view, wallet.menuItem);
|
||||||
|
|
||||||
// Call the ready handler
|
// Command setup
|
||||||
gui.done();
|
gui.sendCommand(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
function addViews(view, path, options) {
|
function addViews(view, path, options) {
|
||||||
|
|
@ -512,18 +512,17 @@ ApplicationWindow {
|
||||||
var section;
|
var section;
|
||||||
switch(options.section) {
|
switch(options.section) {
|
||||||
case "ethereum":
|
case "ethereum":
|
||||||
section = menuDefault;
|
section = menuDefault;
|
||||||
break;
|
break;
|
||||||
case "legacy":
|
case "legacy":
|
||||||
section = menuLegacy;
|
section = menuLegacy;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
section = menuApps;
|
section = menuApps;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var comp = menuItemTemplate.createObject(section)
|
var comp = menuItemTemplate.createObject(section)
|
||||||
|
|
||||||
comp.view = view
|
comp.view = view
|
||||||
comp.title = view.title
|
comp.title = view.title
|
||||||
|
|
||||||
|
|
@ -771,12 +770,9 @@ ApplicationWindow {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
id: peerTable
|
id: peerTable
|
||||||
model: peerModel
|
model: peerModel
|
||||||
TableViewColumn{width: 100; role: "ip" ; title: "IP" }
|
TableViewColumn{width: 200; role: "ip" ; title: "IP" }
|
||||||
TableViewColumn{width: 60; role: "port" ; title: "Port" }
|
|
||||||
TableViewColumn{width: 140; role: "lastResponse"; title: "Last event" }
|
|
||||||
TableViewColumn{width: 100; role: "latency"; title: "Latency" }
|
|
||||||
TableViewColumn{width: 260; role: "version" ; title: "Version" }
|
TableViewColumn{width: 260; role: "version" ; title: "Version" }
|
||||||
TableViewColumn{width: 80; role: "caps" ; title: "Capabilities" }
|
TableViewColumn{width: 180; role: "caps" ; title: "Capabilities" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -787,8 +783,8 @@ ApplicationWindow {
|
||||||
title: "About"
|
title: "About"
|
||||||
minimumWidth: 350
|
minimumWidth: 350
|
||||||
maximumWidth: 350
|
maximumWidth: 350
|
||||||
maximumHeight: 200
|
maximumHeight: 280
|
||||||
minimumHeight: 200
|
minimumHeight: 280
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: aboutIcon
|
id: aboutIcon
|
||||||
|
|
@ -798,7 +794,7 @@ ApplicationWindow {
|
||||||
smooth: true
|
smooth: true
|
||||||
source: "../facet.png"
|
source: "../facet.png"
|
||||||
x: 10
|
x: 10
|
||||||
y: 10
|
y: 30
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
|
@ -807,7 +803,7 @@ ApplicationWindow {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 30
|
anchors.topMargin: 30
|
||||||
font.pointSize: 12
|
font.pointSize: 12
|
||||||
text: "<h2>Mist (0.6.5)</h2><h4>Amalthea</h4><br><h3>Development</h3>Jeffrey Wilcke<br>Viktor Trón<br><h3>Building</h3>Maran Hidskes"
|
text: "<h2>Mist (0.7.10)</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Viktor Trón<br>Felix Lange<br>Taylor Gerring<br>Daniel Nagy<br><h3>UX</h3>Alex van de Sande<br>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -866,12 +862,15 @@ ApplicationWindow {
|
||||||
model: ListModel { id: pastPeers }
|
model: ListModel { id: pastPeers }
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
pastPeers.insert(0, {text: "poc-8.ethdev.com:30303"})
|
||||||
|
/*
|
||||||
var ips = eth.pastPeers()
|
var ips = eth.pastPeers()
|
||||||
for(var i = 0; i < ips.length; i++) {
|
for(var i = 0; i < ips.length; i++) {
|
||||||
pastPeers.append({text: ips.get(i)})
|
pastPeers.append({text: ips.get(i)})
|
||||||
}
|
}
|
||||||
|
|
||||||
pastPeers.insert(0, {text: "poc-7.ethdev.com:30303"})
|
pastPeers.insert(0, {text: "poc-7.ethdev.com:30303"})
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ Rectangle {
|
||||||
text: "Start"
|
text: "Start"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
eth.setGasPrice(minGasPrice.text || "10000000000000");
|
eth.setGasPrice(minGasPrice.text || "10000000000000");
|
||||||
|
eth.setExtra(blockExtra.text)
|
||||||
if (eth.toggleMining()) {
|
if (eth.toggleMining()) {
|
||||||
this.text = "Stop";
|
this.text = "Stop";
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -55,6 +56,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
id: minGasPriceRect
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 2
|
anchors.topMargin: 2
|
||||||
width: 200
|
width: 200
|
||||||
|
|
@ -65,6 +67,23 @@ Rectangle {
|
||||||
validator: RegExpValidator { regExp: /\d*/ }
|
validator: RegExpValidator { regExp: /\d*/ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 300
|
||||||
|
anchors {
|
||||||
|
left: minGasPriceRect.right
|
||||||
|
leftMargin: 5
|
||||||
|
top: parent.top
|
||||||
|
topMargin: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: blockExtra
|
||||||
|
placeholderText: "Extra"
|
||||||
|
width: parent.width
|
||||||
|
maximumLength: 1024
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setBalance() {
|
function setBalance() {
|
||||||
balance.text = "<b>Balance</b>: " + eth.numberToHuman(eth.balanceAt(eth.key().address))
|
//balance.text = "<b>Balance</b>: " + eth.numberToHuman(eth.balanceAt(eth.key().address))
|
||||||
if(menuItem)
|
if(menuItem)
|
||||||
menuItem.secondaryTitle = eth.numberToHuman(eth.balanceAt(eth.key().address))
|
menuItem.secondaryTitle = eth.numberToHuman(eth.balanceAt(eth.key().address))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,7 @@ import Ethereum 1.0
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
property var title: "Whisper"
|
property var title: "Whisper Traffic"
|
||||||
property var iconSource: "../facet.png"
|
|
||||||
property var menuItem
|
property var menuItem
|
||||||
|
|
||||||
objectName: "whisperView"
|
objectName: "whisperView"
|
||||||
|
|
@ -21,10 +20,22 @@ Rectangle {
|
||||||
identity = shh.newIdentity()
|
identity = shh.newIdentity()
|
||||||
console.log("New identity:", identity)
|
console.log("New identity:", identity)
|
||||||
|
|
||||||
var t = shh.watch({topics: ["chat"]})
|
var t = shh.watch({}, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onShhMessage(message, i) {
|
||||||
|
whisperModel.insert(0, {from: message.from, payload: eth.toAscii(message.payload)})
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
id: input
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: 20
|
||||||
|
top: parent.top
|
||||||
|
topMargin: 20
|
||||||
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: to
|
id: to
|
||||||
placeholderText: "To"
|
placeholderText: "To"
|
||||||
|
|
@ -40,8 +51,25 @@ Rectangle {
|
||||||
Button {
|
Button {
|
||||||
text: "Send"
|
text: "Send"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
shh.post(eth.toHex(data.text), "", identity, topics.text.split(","), 500, 50)
|
shh.post([eth.toHex(data.text)], "", identity, topics.text.split(","), 500, 50)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TableView {
|
||||||
|
id: txTableView
|
||||||
|
anchors {
|
||||||
|
top: input.bottom
|
||||||
|
topMargin: 10
|
||||||
|
bottom: parent.bottom
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
TableViewColumn{ id: fromRole; role: "from" ; title: "From"; width: 300 }
|
||||||
|
TableViewColumn{ role: "payload" ; title: "Payload" ; width: parent.width - fromRole.width - 2 }
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
id: whisperModel
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -26,6 +29,7 @@ import (
|
||||||
"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/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
type plugin struct {
|
type plugin struct {
|
||||||
|
|
@ -57,7 +61,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.pipe.Transact(gui.privateKey(), recipient, value, gas, gasPrice, data)
|
return gui.xeth.Transact(gui.privateKey(), recipient, value, gas, gasPrice, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) SetCustomIdentifier(customIdentifier string) {
|
func (gui *Gui) SetCustomIdentifier(customIdentifier string) {
|
||||||
|
|
@ -72,7 +76,7 @@ func (gui *Gui) GetCustomIdentifier() string {
|
||||||
// functions that allow Gui to implement interface guilogger.LogSystem
|
// functions that allow Gui to implement interface guilogger.LogSystem
|
||||||
func (gui *Gui) SetLogLevel(level logger.LogLevel) {
|
func (gui *Gui) SetLogLevel(level logger.LogLevel) {
|
||||||
gui.logLevel = level
|
gui.logLevel = level
|
||||||
gui.stdLog.SetLogLevel(level)
|
gui.eth.Logger().SetLogLevel(level)
|
||||||
gui.config.Save("loglevel", level)
|
gui.config.Save("loglevel", level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +122,7 @@ func (self *Gui) DumpState(hash, path string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
stateDump = block.State().Dump()
|
stateDump = state.New(block.Root(), self.eth.Db()).Dump()
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.OpenFile(path[7:], os.O_CREATE|os.O_RDWR, os.ModePerm)
|
file, err := os.OpenFile(path[7:], os.O_CREATE|os.O_RDWR, os.ModePerm)
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -151,7 +154,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
|
||||||
|
|
||||||
block := self.lib.eth.ChainManager().CurrentBlock()
|
block := self.lib.eth.ChainManager().CurrentBlock()
|
||||||
|
|
||||||
env := utils.NewEnv(statedb, block, account.Address(), value)
|
env := utils.NewEnv(self.lib.eth.ChainManager(), statedb, block, account.Address(), value)
|
||||||
|
|
||||||
self.Logf("callsize %d", len(script))
|
self.Logf("callsize %d", len(script))
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -309,9 +312,11 @@ func (d *Debugger) halting(pc int, op vm.OpCode, mem *vm.Memory, stack *vm.Stack
|
||||||
d.win.Root().Call("setStack", val.String())
|
d.win.Root().Call("setStack", val.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
stateObject.EachStorage(func(key string, node *ethutil.Value) {
|
it := stateObject.Trie().Iterator()
|
||||||
d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
|
for it.Next() {
|
||||||
})
|
d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", it.Key), fmt.Sprintf("% x", it.Value)})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
stackFrameAt := new(big.Int).SetBytes(mem.Get(0, 32))
|
stackFrameAt := new(big.Int).SetBytes(mem.Get(0, 32))
|
||||||
psize := mem.Len() - int(new(big.Int).SetBytes(mem.Get(0, 32)).Uint64())
|
psize := mem.Len() - int(new(big.Int).SetBytes(mem.Get(0, 32)).Uint64())
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -106,7 +109,7 @@ func Init() {
|
||||||
flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)")
|
flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)")
|
||||||
flag.StringVar(&OutboundPort, "port", "30303", "listening port")
|
flag.StringVar(&OutboundPort, "port", "30303", "listening port")
|
||||||
flag.BoolVar(&UseUPnP, "upnp", true, "enable UPnP support")
|
flag.BoolVar(&UseUPnP, "upnp", true, "enable UPnP support")
|
||||||
flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
|
flag.IntVar(&MaxPeer, "maxpeer", 30, "maximum desired peers")
|
||||||
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
|
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
|
||||||
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
|
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
|
||||||
flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server")
|
flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server")
|
||||||
|
|
|
||||||
414
cmd/mist/gui.go
414
cmd/mist/gui.go
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
@ -23,7 +26,9 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -43,49 +48,24 @@ import (
|
||||||
"gopkg.in/qml.v1"
|
"gopkg.in/qml.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
func LoadExtension(path string) (uintptr, error) {
|
|
||||||
lib, err := ffi.NewLibrary(path)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
so, err := lib.Fct("sharedObject", ffi.Pointer, nil)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr := so()
|
|
||||||
|
|
||||||
err = lib.Close()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ptr.Interface().(uintptr), nil
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
vec, errr := LoadExtension("/Users/jeffrey/Desktop/build-libqmltest-Desktop_Qt_5_2_1_clang_64bit-Debug/liblibqmltest_debug.dylib")
|
|
||||||
fmt.Printf("Fetched vec with addr: %#x\n", vec)
|
|
||||||
if errr != nil {
|
|
||||||
fmt.Println(errr)
|
|
||||||
} else {
|
|
||||||
context.SetVar("vec", (unsafe.Pointer)(vec))
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
var guilogger = logger.NewLogger("GUI")
|
var guilogger = logger.NewLogger("GUI")
|
||||||
|
|
||||||
|
type ServEv byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
setup ServEv = iota
|
||||||
|
update
|
||||||
|
)
|
||||||
|
|
||||||
type Gui struct {
|
type Gui struct {
|
||||||
// The main application window
|
// The main application window
|
||||||
win *qml.Window
|
win *qml.Window
|
||||||
// QML Engine
|
// QML Engine
|
||||||
engine *qml.Engine
|
engine *qml.Engine
|
||||||
component *qml.Common
|
component *qml.Common
|
||||||
qmlDone bool
|
|
||||||
// The ethereum interface
|
// The ethereum interface
|
||||||
eth *eth.Ethereum
|
eth *eth.Ethereum
|
||||||
|
serviceEvents chan ServEv
|
||||||
|
|
||||||
// The public Ethereum library
|
// The public Ethereum library
|
||||||
uiLib *UiLib
|
uiLib *UiLib
|
||||||
|
|
@ -96,7 +76,7 @@ type Gui struct {
|
||||||
logLevel logger.LogLevel
|
logLevel logger.LogLevel
|
||||||
open bool
|
open bool
|
||||||
|
|
||||||
pipe *xeth.JSXEth
|
xeth *xeth.JSXEth
|
||||||
|
|
||||||
Session string
|
Session string
|
||||||
clientIdentity *p2p.SimpleClientIdentity
|
clientIdentity *p2p.SimpleClientIdentity
|
||||||
|
|
@ -104,8 +84,7 @@ type Gui struct {
|
||||||
|
|
||||||
plugins map[string]plugin
|
plugins map[string]plugin
|
||||||
|
|
||||||
miner *miner.Miner
|
miner *miner.Miner
|
||||||
stdLog logger.LogSystem
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create GUI, but doesn't start it
|
// Create GUI, but doesn't start it
|
||||||
|
|
@ -115,8 +94,18 @@ func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIden
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pipe := xeth.NewJSXEth(ethereum)
|
xeth := xeth.NewJSXEth(ethereum)
|
||||||
gui := &Gui{eth: ethereum, txDb: db, pipe: pipe, logLevel: logger.LogLevel(logLevel), Session: session, open: false, clientIdentity: clientIdentity, config: config, plugins: make(map[string]plugin)}
|
gui := &Gui{eth: ethereum,
|
||||||
|
txDb: db,
|
||||||
|
xeth: xeth,
|
||||||
|
logLevel: logger.LogLevel(logLevel),
|
||||||
|
Session: session,
|
||||||
|
open: false,
|
||||||
|
clientIdentity: clientIdentity,
|
||||||
|
config: config,
|
||||||
|
plugins: make(map[string]plugin),
|
||||||
|
serviceEvents: make(chan ServEv, 1),
|
||||||
|
}
|
||||||
data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "plugins.json"))
|
data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "plugins.json"))
|
||||||
json.Unmarshal([]byte(data), &gui.plugins)
|
json.Unmarshal([]byte(data), &gui.plugins)
|
||||||
|
|
||||||
|
|
@ -128,6 +117,8 @@ func (gui *Gui) Start(assetPath string) {
|
||||||
|
|
||||||
guilogger.Infoln("Starting GUI")
|
guilogger.Infoln("Starting GUI")
|
||||||
|
|
||||||
|
go gui.service()
|
||||||
|
|
||||||
// Register ethereum functions
|
// Register ethereum functions
|
||||||
qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{
|
qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{
|
||||||
Init: func(p *xeth.JSBlock, obj qml.Object) { p.Number = 0; p.Hash = "" },
|
Init: func(p *xeth.JSBlock, obj qml.Object) { p.Number = 0; p.Hash = "" },
|
||||||
|
|
@ -147,18 +138,7 @@ func (gui *Gui) Start(assetPath string) {
|
||||||
context.SetVar("eth", gui.uiLib)
|
context.SetVar("eth", gui.uiLib)
|
||||||
context.SetVar("shh", gui.whisper)
|
context.SetVar("shh", gui.whisper)
|
||||||
|
|
||||||
// Load the main QML interface
|
win, err := gui.showWallet(context)
|
||||||
data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
|
|
||||||
|
|
||||||
var win *qml.Window
|
|
||||||
var err error
|
|
||||||
var addlog = false
|
|
||||||
if len(data) == 0 {
|
|
||||||
win, err = gui.showKeyImport(context)
|
|
||||||
} else {
|
|
||||||
win, err = gui.showWallet(context)
|
|
||||||
addlog = true
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
guilogger.Errorln("asset not found: you can set an alternative asset path on the command line using option 'asset_path'", err)
|
guilogger.Errorln("asset not found: you can set an alternative asset path on the command line using option 'asset_path'", err)
|
||||||
|
|
||||||
|
|
@ -169,9 +149,7 @@ func (gui *Gui) Start(assetPath string) {
|
||||||
win.Show()
|
win.Show()
|
||||||
|
|
||||||
// only add the gui guilogger after window is shown otherwise slider wont be shown
|
// only add the gui guilogger after window is shown otherwise slider wont be shown
|
||||||
if addlog {
|
logger.AddLogSystem(gui)
|
||||||
logger.AddLogSystem(gui)
|
|
||||||
}
|
|
||||||
win.Wait()
|
win.Wait()
|
||||||
|
|
||||||
// need to silence gui guilogger after window closed otherwise logsystem hangs (but do not save loglevel)
|
// need to silence gui guilogger after window closed otherwise logsystem hangs (but do not save loglevel)
|
||||||
|
|
@ -197,18 +175,11 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.win = gui.createWindow(component)
|
gui.createWindow(component)
|
||||||
|
|
||||||
gui.update()
|
|
||||||
|
|
||||||
return gui.win, nil
|
return gui.win, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// The done handler will be called by QML when all views have been loaded
|
|
||||||
func (gui *Gui) Done() {
|
|
||||||
gui.qmlDone = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) ImportKey(filePath string) {
|
func (gui *Gui) ImportKey(filePath string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,10 +193,8 @@ func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
|
func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
|
||||||
win := comp.CreateWindow(nil)
|
gui.win = comp.CreateWindow(nil)
|
||||||
|
gui.uiLib.win = gui.win
|
||||||
gui.win = win
|
|
||||||
gui.uiLib.win = win
|
|
||||||
|
|
||||||
return gui.win
|
return gui.win
|
||||||
}
|
}
|
||||||
|
|
@ -253,7 +222,7 @@ 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.PrevHash
|
sBlk = blk.ParentHash()
|
||||||
|
|
||||||
gui.processBlock(blk, true)
|
gui.processBlock(blk, true)
|
||||||
}
|
}
|
||||||
|
|
@ -261,43 +230,40 @@ func (gui *Gui) setInitialChain(ancientBlocks bool) {
|
||||||
|
|
||||||
func (gui *Gui) loadAddressBook() {
|
func (gui *Gui) loadAddressBook() {
|
||||||
view := gui.getObjectByName("infoView")
|
view := gui.getObjectByName("infoView")
|
||||||
nameReg := gui.pipe.World().Config().Get("NameReg")
|
nameReg := gui.xeth.World().Config().Get("NameReg")
|
||||||
if nameReg != nil {
|
if nameReg != nil {
|
||||||
nameReg.EachStorage(func(name string, value *ethutil.Value) {
|
it := nameReg.Trie().Iterator()
|
||||||
if name[0] != 0 {
|
for it.Next() {
|
||||||
value.Decode()
|
if it.Key[0] != 0 {
|
||||||
|
view.Call("addAddress", struct{ Name, Address string }{string(it.Key), ethutil.Bytes2Hex(it.Value)})
|
||||||
view.Call("addAddress", struct{ Name, Address string }{name, ethutil.Bytes2Hex(value.Bytes())})
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Gui) loadMergedMiningOptions() {
|
func (self *Gui) loadMergedMiningOptions() {
|
||||||
view := self.getObjectByName("mergedMiningModel")
|
view := self.getObjectByName("mergedMiningModel")
|
||||||
|
|
||||||
nameReg := self.pipe.World().Config().Get("MergeMining")
|
mergeMining := self.xeth.World().Config().Get("MergeMining")
|
||||||
if nameReg != nil {
|
if mergeMining != nil {
|
||||||
i := 0
|
i := 0
|
||||||
nameReg.EachStorage(func(name string, value *ethutil.Value) {
|
it := mergeMining.Trie().Iterator()
|
||||||
if name[0] != 0 {
|
for it.Next() {
|
||||||
value.Decode()
|
view.Call("addMergedMiningOption", struct {
|
||||||
|
Checked bool
|
||||||
|
Name, Address string
|
||||||
|
Id, ItemId int
|
||||||
|
}{false, string(it.Key), ethutil.Bytes2Hex(it.Value), 0, i})
|
||||||
|
|
||||||
view.Call("addMergedMiningOption", struct {
|
i++
|
||||||
Checked bool
|
|
||||||
Name, Address string
|
|
||||||
Id, ItemId int
|
|
||||||
}{false, name, ethutil.Bytes2Hex(value.Bytes()), 0, i})
|
|
||||||
|
|
||||||
i++
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) insertTransaction(window string, tx *types.Transaction) {
|
func (gui *Gui) insertTransaction(window string, tx *types.Transaction) {
|
||||||
pipe := xeth.New(gui.eth)
|
nameReg := gui.xeth.World().Config().Get("NameReg")
|
||||||
nameReg := pipe.World().Config().Get("NameReg")
|
|
||||||
addr := gui.address()
|
addr := gui.address()
|
||||||
|
|
||||||
var inout string
|
var inout string
|
||||||
|
|
@ -308,7 +274,7 @@ func (gui *Gui) insertTransaction(window string, tx *types.Transaction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ptx = xeth.NewJSTx(tx, pipe.World().State())
|
ptx = xeth.NewJSTx(tx)
|
||||||
send = nameReg.Storage(tx.From())
|
send = nameReg.Storage(tx.From())
|
||||||
rec = nameReg.Storage(tx.To())
|
rec = nameReg.Storage(tx.To())
|
||||||
s, r string
|
s, r string
|
||||||
|
|
@ -354,7 +320,7 @@ func (gui *Gui) readPreviousTransactions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) processBlock(block *types.Block, initial bool) {
|
func (gui *Gui) processBlock(block *types.Block, initial bool) {
|
||||||
name := strings.Trim(gui.pipe.World().Config().Get("NameReg").Storage(block.Coinbase).Str(), "\x00")
|
name := strings.Trim(gui.xeth.World().Config().Get("NameReg").Storage(block.Coinbase()).Str(), "\x00")
|
||||||
b := xeth.NewJSBlock(block)
|
b := xeth.NewJSBlock(block)
|
||||||
b.Name = name
|
b.Name = name
|
||||||
|
|
||||||
|
|
@ -381,11 +347,48 @@ func (self *Gui) getObjectByName(objectName string) qml.Object {
|
||||||
return self.win.Root().ObjectByName(objectName)
|
return self.win.Root().ObjectByName(objectName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple go routine function that updates the list of peers in the GUI
|
func loadJavascriptAssets(gui *Gui) (jsfiles string) {
|
||||||
func (gui *Gui) update() {
|
for _, fn := range []string{"ext/q.js", "ext/eth.js/main.js", "ext/eth.js/qt.js", "ext/setup.js"} {
|
||||||
// We have to wait for qml to be done loading all the windows.
|
f, err := os.Open(gui.uiLib.AssetPath(fn))
|
||||||
for !gui.qmlDone {
|
if err != nil {
|
||||||
time.Sleep(300 * time.Millisecond)
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
jsfiles += string(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) SendCommand(cmd ServEv) {
|
||||||
|
gui.serviceEvents <- cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) service() {
|
||||||
|
for ev := range gui.serviceEvents {
|
||||||
|
switch ev {
|
||||||
|
case setup:
|
||||||
|
go gui.setup()
|
||||||
|
case update:
|
||||||
|
go gui.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) setup() {
|
||||||
|
for gui.win == nil {
|
||||||
|
time.Sleep(time.Millisecond * 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, plugin := range gui.plugins {
|
||||||
|
guilogger.Infoln("Loading plugin ", plugin.Name)
|
||||||
|
gui.win.Root().Call("addPlugin", plugin.Path, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -395,14 +398,21 @@ func (gui *Gui) update() {
|
||||||
gui.setPeerInfo()
|
gui.setPeerInfo()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
gui.whisper.SetView(gui.win.Root().ObjectByName("whisperView"))
|
// Inject javascript files each time navigation is requested.
|
||||||
|
// Unfortunately webview.experimental.userScripts injects _after_
|
||||||
|
// the page has loaded which kind of renders it useless...
|
||||||
|
//jsfiles := loadJavascriptAssets(gui)
|
||||||
|
gui.getObjectByName("webView").On("navigationRequested", func() {
|
||||||
|
//gui.getObjectByName("webView").Call("injectJs", jsfiles)
|
||||||
|
})
|
||||||
|
|
||||||
for _, plugin := range gui.plugins {
|
gui.whisper.SetView(gui.getObjectByName("whisperView"))
|
||||||
guilogger.Infoln("Loading plugin ", plugin.Name)
|
|
||||||
|
|
||||||
gui.win.Root().Call("addPlugin", plugin.Path, "")
|
gui.SendCommand(update)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simple go routine function that updates the list of peers in the GUI
|
||||||
|
func (gui *Gui) update() {
|
||||||
peerUpdateTicker := time.NewTicker(5 * time.Second)
|
peerUpdateTicker := time.NewTicker(5 * time.Second)
|
||||||
generalUpdateTicker := time.NewTicker(500 * time.Millisecond)
|
generalUpdateTicker := time.NewTicker(500 * time.Millisecond)
|
||||||
statsUpdateTicker := time.NewTicker(5 * time.Second)
|
statsUpdateTicker := time.NewTicker(5 * time.Second)
|
||||||
|
|
@ -421,77 +431,75 @@ func (gui *Gui) update() {
|
||||||
core.TxPostEvent{},
|
core.TxPostEvent{},
|
||||||
)
|
)
|
||||||
|
|
||||||
go func() {
|
defer events.Unsubscribe()
|
||||||
defer events.Unsubscribe()
|
for {
|
||||||
for {
|
select {
|
||||||
select {
|
case ev, isopen := <-events.Chan():
|
||||||
case ev, isopen := <-events.Chan():
|
if !isopen {
|
||||||
if !isopen {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
switch ev := ev.(type) {
|
|
||||||
case core.NewBlockEvent:
|
|
||||||
gui.processBlock(ev.Block, false)
|
|
||||||
if bytes.Compare(ev.Block.Coinbase, gui.address()) == 0 {
|
|
||||||
gui.setWalletValue(gui.eth.ChainManager().State().GetBalance(gui.address()), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
case core.TxPreEvent:
|
|
||||||
tx := ev.Tx
|
|
||||||
|
|
||||||
tstate := gui.eth.ChainManager().TransState()
|
|
||||||
cstate := gui.eth.ChainManager().State()
|
|
||||||
|
|
||||||
taccount := tstate.GetAccount(gui.address())
|
|
||||||
caccount := cstate.GetAccount(gui.address())
|
|
||||||
unconfirmedFunds := new(big.Int).Sub(taccount.Balance(), caccount.Balance())
|
|
||||||
|
|
||||||
gui.setWalletValue(taccount.Balance(), unconfirmedFunds)
|
|
||||||
gui.insertTransaction("pre", tx)
|
|
||||||
|
|
||||||
case core.TxPostEvent:
|
|
||||||
tx := ev.Tx
|
|
||||||
object := state.GetAccount(gui.address())
|
|
||||||
|
|
||||||
if bytes.Compare(tx.From(), gui.address()) == 0 {
|
|
||||||
object.SubAmount(tx.Value())
|
|
||||||
|
|
||||||
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
|
|
||||||
} else if bytes.Compare(tx.To(), gui.address()) == 0 {
|
|
||||||
object.AddAmount(tx.Value())
|
|
||||||
|
|
||||||
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.setWalletValue(object.Balance(), nil)
|
|
||||||
state.UpdateStateObject(object)
|
|
||||||
}
|
|
||||||
|
|
||||||
case <-peerUpdateTicker.C:
|
|
||||||
gui.setPeerInfo()
|
|
||||||
case <-generalUpdateTicker.C:
|
|
||||||
statusText := "#" + gui.eth.ChainManager().CurrentBlock().Number.String()
|
|
||||||
lastBlockLabel.Set("text", statusText)
|
|
||||||
miningLabel.Set("text", "Mining @ "+strconv.FormatInt(gui.uiLib.miner.GetPow().GetHashrate(), 10)+"Khash")
|
|
||||||
|
|
||||||
/*
|
|
||||||
blockLength := gui.eth.BlockPool().BlocksProcessed
|
|
||||||
chainLength := gui.eth.BlockPool().ChainLength
|
|
||||||
|
|
||||||
var (
|
|
||||||
pct float64 = 1.0 / float64(chainLength) * float64(blockLength)
|
|
||||||
dlWidget = gui.win.Root().ObjectByName("downloadIndicator")
|
|
||||||
dlLabel = gui.win.Root().ObjectByName("downloadLabel")
|
|
||||||
)
|
|
||||||
dlWidget.Set("value", pct)
|
|
||||||
dlLabel.Set("text", fmt.Sprintf("%d / %d", blockLength, chainLength))
|
|
||||||
*/
|
|
||||||
|
|
||||||
case <-statsUpdateTicker.C:
|
|
||||||
gui.setStatsPane()
|
|
||||||
}
|
}
|
||||||
|
switch ev := ev.(type) {
|
||||||
|
case core.NewBlockEvent:
|
||||||
|
gui.processBlock(ev.Block, false)
|
||||||
|
if bytes.Compare(ev.Block.Coinbase(), gui.address()) == 0 {
|
||||||
|
gui.setWalletValue(gui.eth.ChainManager().State().GetBalance(gui.address()), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
case core.TxPreEvent:
|
||||||
|
tx := ev.Tx
|
||||||
|
|
||||||
|
tstate := gui.eth.ChainManager().TransState()
|
||||||
|
cstate := gui.eth.ChainManager().State()
|
||||||
|
|
||||||
|
taccount := tstate.GetAccount(gui.address())
|
||||||
|
caccount := cstate.GetAccount(gui.address())
|
||||||
|
unconfirmedFunds := new(big.Int).Sub(taccount.Balance(), caccount.Balance())
|
||||||
|
|
||||||
|
gui.setWalletValue(taccount.Balance(), unconfirmedFunds)
|
||||||
|
gui.insertTransaction("pre", tx)
|
||||||
|
|
||||||
|
case core.TxPostEvent:
|
||||||
|
tx := ev.Tx
|
||||||
|
object := state.GetAccount(gui.address())
|
||||||
|
|
||||||
|
if bytes.Compare(tx.From(), gui.address()) == 0 {
|
||||||
|
object.SubAmount(tx.Value())
|
||||||
|
|
||||||
|
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
|
||||||
|
} else if bytes.Compare(tx.To(), gui.address()) == 0 {
|
||||||
|
object.AddAmount(tx.Value())
|
||||||
|
|
||||||
|
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
|
||||||
|
}
|
||||||
|
|
||||||
|
gui.setWalletValue(object.Balance(), nil)
|
||||||
|
state.UpdateStateObject(object)
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-peerUpdateTicker.C:
|
||||||
|
gui.setPeerInfo()
|
||||||
|
case <-generalUpdateTicker.C:
|
||||||
|
statusText := "#" + gui.eth.ChainManager().CurrentBlock().Number().String()
|
||||||
|
lastBlockLabel.Set("text", statusText)
|
||||||
|
miningLabel.Set("text", "Mining @ "+strconv.FormatInt(gui.uiLib.miner.GetPow().GetHashrate(), 10)+"Khash")
|
||||||
|
|
||||||
|
/*
|
||||||
|
blockLength := gui.eth.BlockPool().BlocksProcessed
|
||||||
|
chainLength := gui.eth.BlockPool().ChainLength
|
||||||
|
|
||||||
|
var (
|
||||||
|
pct float64 = 1.0 / float64(chainLength) * float64(blockLength)
|
||||||
|
dlWidget = gui.win.Root().ObjectByName("downloadIndicator")
|
||||||
|
dlLabel = gui.win.Root().ObjectByName("downloadLabel")
|
||||||
|
)
|
||||||
|
dlWidget.Set("value", pct)
|
||||||
|
dlLabel.Set("text", fmt.Sprintf("%d / %d", blockLength, chainLength))
|
||||||
|
*/
|
||||||
|
|
||||||
|
case <-statsUpdateTicker.C:
|
||||||
|
gui.setStatsPane()
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) setStatsPane() {
|
func (gui *Gui) setStatsPane() {
|
||||||
|
|
@ -523,7 +531,7 @@ NumGC: %d
|
||||||
func (gui *Gui) setPeerInfo() {
|
func (gui *Gui) setPeerInfo() {
|
||||||
gui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", gui.eth.PeerCount(), gui.eth.MaxPeers))
|
gui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", gui.eth.PeerCount(), gui.eth.MaxPeers))
|
||||||
gui.win.Root().Call("resetPeers")
|
gui.win.Root().Call("resetPeers")
|
||||||
for _, peer := range gui.pipe.Peers() {
|
for _, peer := range gui.xeth.Peers() {
|
||||||
gui.win.Root().Call("addPeer", peer)
|
gui.win.Root().Call("addPeer", peer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -535,3 +543,35 @@ func (gui *Gui) privateKey() string {
|
||||||
func (gui *Gui) address() []byte {
|
func (gui *Gui) address() []byte {
|
||||||
return gui.eth.KeyManager().Address()
|
return gui.eth.KeyManager().Address()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func LoadExtension(path string) (uintptr, error) {
|
||||||
|
lib, err := ffi.NewLibrary(path)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
so, err := lib.Fct("sharedObject", ffi.Pointer, nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr := so()
|
||||||
|
|
||||||
|
err = lib.Close()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr.Interface().(uintptr), nil
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
vec, errr := LoadExtension("/Users/jeffrey/Desktop/build-libqmltest-Desktop_Qt_5_2_1_clang_64bit-Debug/liblibqmltest_debug.dylib")
|
||||||
|
fmt.Printf("Fetched vec with addr: %#x\n", vec)
|
||||||
|
if errr != nil {
|
||||||
|
fmt.Println(errr)
|
||||||
|
} else {
|
||||||
|
context.SetVar("vec", (unsafe.Pointer)(vec))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -139,7 +142,7 @@ func (app *HtmlApplication) Window() *qml.Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *HtmlApplication) NewBlock(block *types.Block) {
|
func (app *HtmlApplication) NewBlock(block *types.Block) {
|
||||||
b := &xeth.JSBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())}
|
b := &xeth.JSBlock{Number: int(block.NumberU64()), Hash: ethutil.Bytes2Hex(block.Hash())}
|
||||||
app.webView.Call("onNewBlockCb", b)
|
app.webView.Call("onNewBlockCb", b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -26,15 +29,17 @@ import (
|
||||||
"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/eth"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"gopkg.in/qml.v1"
|
"gopkg.in/qml.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ClientIdentifier = "Mist"
|
ClientIdentifier = "Mist"
|
||||||
Version = "0.7.9"
|
Version = "0.8.1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ethereum *eth.Ethereum
|
var ethereum *eth.Ethereum
|
||||||
|
var mainlogger = logger.NewLogger("MAIN")
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
// precedence: code-internal flag default < config file < environment variables < command line
|
// precedence: code-internal flag default < config file < environment variables < command line
|
||||||
|
|
@ -43,27 +48,25 @@ func run() error {
|
||||||
tstart := time.Now()
|
tstart := time.Now()
|
||||||
config := utils.InitConfig(VmType, ConfigFile, Datadir, "ETH")
|
config := utils.InitConfig(VmType, ConfigFile, Datadir, "ETH")
|
||||||
|
|
||||||
utils.InitDataDir(Datadir)
|
ethereum, err := eth.New(ð.Config{
|
||||||
|
Name: ClientIdentifier,
|
||||||
stdLog := utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile)
|
Version: Version,
|
||||||
|
KeyStore: KeyStore,
|
||||||
db := utils.NewDatabase()
|
DataDir: Datadir,
|
||||||
err := utils.DBSanityCheck(db)
|
LogFile: LogFile,
|
||||||
|
LogLevel: LogLevel,
|
||||||
|
Identifier: Identifier,
|
||||||
|
MaxPeers: MaxPeer,
|
||||||
|
Port: OutboundPort,
|
||||||
|
NATType: PMPGateway,
|
||||||
|
PMPGateway: PMPGateway,
|
||||||
|
KeyRing: KeyRing,
|
||||||
|
Dial: true,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorWindow(err)
|
mainlogger.Fatalln(err)
|
||||||
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
keyManager := utils.NewKeyManager(KeyStore, Datadir, db)
|
|
||||||
|
|
||||||
// create, import, export keys
|
|
||||||
utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
|
|
||||||
clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier, string(keyManager.PublicKey()))
|
|
||||||
ethereum := utils.NewEthereum(db, clientIdentity, keyManager, utils.NatType(NatType, PMPGateway), OutboundPort, MaxPeer)
|
|
||||||
|
|
||||||
if ShowGenesis {
|
|
||||||
utils.ShowGenesis(ethereum)
|
|
||||||
}
|
}
|
||||||
|
utils.KeyTasks(ethereum.KeyManager(), KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
|
||||||
|
|
||||||
if StartRpc {
|
if StartRpc {
|
||||||
utils.StartRpc(ethereum, RpcPort)
|
utils.StartRpc(ethereum, RpcPort)
|
||||||
|
|
@ -73,8 +76,7 @@ func run() error {
|
||||||
utils.StartWebSockets(ethereum)
|
utils.StartWebSockets(ethereum)
|
||||||
}
|
}
|
||||||
|
|
||||||
gui := NewWindow(ethereum, config, clientIdentity, KeyRing, LogLevel)
|
gui := NewWindow(ethereum, config, ethereum.ClientIdentity().(*p2p.SimpleClientIdentity), KeyRing, LogLevel)
|
||||||
gui.stdLog = stdLog
|
|
||||||
|
|
||||||
utils.RegisterInterrupt(func(os.Signal) {
|
utils.RegisterInterrupt(func(os.Signal) {
|
||||||
gui.Stop()
|
gui.Stop()
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU General Public
|
go-ethereum is free software: you can redistribute it and/or modify
|
||||||
// License as published by the Free Software Foundation; either
|
it under the terms of the GNU General Public License as published by
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
//
|
(at your option) any later version.
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
go-ethereum is distributed in the hope that it will be useful,
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// General Public License for more details.
|
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 this library; if not, write to the Free Software
|
You should have received a copy of the GNU General Public License
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
// MA 02110-1301 USA
|
*/
|
||||||
|
/**
|
||||||
|
* @authors
|
||||||
|
* Jeffrey Wilcke <i@jev.io>
|
||||||
|
*/
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
@ -66,7 +70,7 @@ func (app *QmlApplication) NewWatcher(quitChan chan bool) {
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
func (app *QmlApplication) NewBlock(block *types.Block) {
|
func (app *QmlApplication) NewBlock(block *types.Block) {
|
||||||
pblock := &xeth.JSBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())}
|
pblock := &xeth.JSBlock{Number: int(block.NumberU64()), Hash: ethutil.Bytes2Hex(block.Hash())}
|
||||||
app.win.Call("onNewBlockCb", pblock)
|
app.win.Call("onNewBlockCb", pblock)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
/*
|
||||||
//
|
This file is part of go-ethereum
|
||||||
// This library 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 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
// MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -195,7 +198,9 @@ func (ui *UiLib) Connect(button qml.Object) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ui *UiLib) ConnectToPeer(addr string) {
|
func (ui *UiLib) ConnectToPeer(addr string) {
|
||||||
ui.eth.SuggestPeer(addr)
|
if err := ui.eth.SuggestPeer(addr); err != nil {
|
||||||
|
guilogger.Infoln(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ui *UiLib) AssetPath(p string) string {
|
func (ui *UiLib) AssetPath(p string) string {
|
||||||
|
|
@ -225,6 +230,87 @@ func (self *UiLib) StartDebugger() {
|
||||||
dbWindow.Show()
|
dbWindow.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
|
||||||
|
object := mapToTxParams(params)
|
||||||
|
|
||||||
|
return self.JSXEth.Transact(
|
||||||
|
object["from"],
|
||||||
|
object["to"],
|
||||||
|
object["value"],
|
||||||
|
object["gas"],
|
||||||
|
object["gasPrice"],
|
||||||
|
object["data"],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *UiLib) Compile(code string) (string, error) {
|
||||||
|
bcode, err := ethutil.Compile(code, false)
|
||||||
|
if err != nil {
|
||||||
|
return err.Error(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ethutil.Bytes2Hex(bcode), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *UiLib) Call(params map[string]interface{}) (string, error) {
|
||||||
|
object := mapToTxParams(params)
|
||||||
|
|
||||||
|
return self.JSXEth.Execute(
|
||||||
|
object["to"],
|
||||||
|
object["value"],
|
||||||
|
object["gas"],
|
||||||
|
object["gasPrice"],
|
||||||
|
object["data"],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *UiLib) AddLocalTransaction(to, data, gas, gasPrice, value string) int {
|
||||||
|
return self.miner.AddLocalTx(&miner.LocalTx{
|
||||||
|
To: ethutil.Hex2Bytes(to),
|
||||||
|
Data: ethutil.Hex2Bytes(data),
|
||||||
|
Gas: gas,
|
||||||
|
GasPrice: gasPrice,
|
||||||
|
Value: value,
|
||||||
|
}) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *UiLib) RemoveLocalTransaction(id int) {
|
||||||
|
self.miner.RemoveLocalTx(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *UiLib) SetGasPrice(price string) {
|
||||||
|
self.miner.MinAcceptedGasPrice = ethutil.Big(price)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *UiLib) SetExtra(extra string) {
|
||||||
|
self.miner.Extra = extra
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *UiLib) ToggleMining() bool {
|
||||||
|
if !self.miner.Mining() {
|
||||||
|
self.miner.Start()
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
self.miner.Stop()
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *UiLib) ToHex(data string) string {
|
||||||
|
return "0x" + ethutil.Bytes2Hex([]byte(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *UiLib) ToAscii(data string) string {
|
||||||
|
start := 0
|
||||||
|
if len(data) > 1 && data[0:2] == "0x" {
|
||||||
|
start = 2
|
||||||
|
}
|
||||||
|
return string(ethutil.Hex2Bytes(data[start:]))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ethereum filter methods
|
||||||
func (self *UiLib) NewFilter(object map[string]interface{}) (id int) {
|
func (self *UiLib) NewFilter(object map[string]interface{}) (id int) {
|
||||||
filter := qt.NewFilterFromMap(object, self.eth)
|
filter := qt.NewFilterFromMap(object, self.eth)
|
||||||
filter.MessageCallback = func(messages state.Messages) {
|
filter.MessageCallback = func(messages state.Messages) {
|
||||||
|
|
@ -312,80 +398,3 @@ func mapToTxParams(object map[string]interface{}) map[string]string {
|
||||||
|
|
||||||
return conv
|
return conv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
|
|
||||||
object := mapToTxParams(params)
|
|
||||||
|
|
||||||
return self.JSXEth.Transact(
|
|
||||||
object["from"],
|
|
||||||
object["to"],
|
|
||||||
object["value"],
|
|
||||||
object["gas"],
|
|
||||||
object["gasPrice"],
|
|
||||||
object["data"],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *UiLib) Compile(code string) (string, error) {
|
|
||||||
bcode, err := ethutil.Compile(code, false)
|
|
||||||
if err != nil {
|
|
||||||
return err.Error(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ethutil.Bytes2Hex(bcode), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *UiLib) Call(params map[string]interface{}) (string, error) {
|
|
||||||
object := mapToTxParams(params)
|
|
||||||
|
|
||||||
return self.JSXEth.Execute(
|
|
||||||
object["to"],
|
|
||||||
object["value"],
|
|
||||||
object["gas"],
|
|
||||||
object["gasPrice"],
|
|
||||||
object["data"],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *UiLib) AddLocalTransaction(to, data, gas, gasPrice, value string) int {
|
|
||||||
return self.miner.AddLocalTx(&miner.LocalTx{
|
|
||||||
To: ethutil.Hex2Bytes(to),
|
|
||||||
Data: ethutil.Hex2Bytes(data),
|
|
||||||
Gas: gas,
|
|
||||||
GasPrice: gasPrice,
|
|
||||||
Value: value,
|
|
||||||
}) - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *UiLib) RemoveLocalTransaction(id int) {
|
|
||||||
self.miner.RemoveLocalTx(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *UiLib) SetGasPrice(price string) {
|
|
||||||
self.miner.MinAcceptedGasPrice = ethutil.Big(price)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *UiLib) ToggleMining() bool {
|
|
||||||
if !self.miner.Mining() {
|
|
||||||
self.miner.Start()
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
self.miner.Stop()
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *UiLib) ToHex(data string) string {
|
|
||||||
return "0x" + ethutil.Bytes2Hex([]byte(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// XXX Refactor me & MOVE
|
|
||||||
func (self *Ethereum) InstallFilter(filter *core.Filter) (id int) {
|
|
||||||
return self.filterManager.InstallFilter(filter)
|
|
||||||
}
|
|
||||||
func (self *Ethereum) UninstallFilter(id int) { self.filterManager.UninstallFilter(id) }
|
|
||||||
func (self *Ethereum) GetFilter(id int) *core.Filter { return self.filterManager.GetFilter(id) }
|
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,25 @@
|
||||||
|
/*
|
||||||
|
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 main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"fmt"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -12,29 +27,32 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
natType = flag.String("nat", "", "NAT traversal implementation")
|
||||||
|
pmpGateway = flag.String("gateway", "", "gateway address for NAT-PMP")
|
||||||
|
listenAddr = flag.String("addr", ":30301", "listen address")
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
nat, err := p2p.ParseNAT(*natType, *pmpGateway)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("invalid nat:", err)
|
||||||
|
}
|
||||||
|
|
||||||
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel))
|
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel))
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
marshaled := elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y)
|
marshaled := elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y)
|
||||||
|
|
||||||
srv := p2p.Server{
|
srv := p2p.Server{
|
||||||
MaxPeers: 10,
|
MaxPeers: 100,
|
||||||
Identity: p2p.NewSimpleClientIdentity("Ethereum(G)", "0.1", "Peer Server Two", string(marshaled)),
|
Identity: p2p.NewSimpleClientIdentity("Ethereum(G)", "0.1", "Peer Server Two", marshaled),
|
||||||
ListenAddr: ":30301",
|
ListenAddr: *listenAddr,
|
||||||
NAT: p2p.UPNP(),
|
NAT: nat,
|
||||||
|
NoDial: true,
|
||||||
}
|
}
|
||||||
if err := srv.Start(); err != nil {
|
if err := srv.Start(); err != nil {
|
||||||
fmt.Println("could not start server:", err)
|
log.Fatal("could not start server:", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add seed peers
|
|
||||||
seed, err := net.ResolveTCPAddr("tcp", "poc-7.ethdev.com:30300")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("couldn't resolve:", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
srv.SuggestPeer(seed.IP, seed.Port, nil)
|
|
||||||
|
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
148
cmd/rlpdump/main.go
Normal file
148
cmd/rlpdump/main.go
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
* Felix Lange <felix@ethdev.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// rlpdump is a pretty-printer for RLP data.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
hexMode = flag.String("hex", "", "dump given hex data")
|
||||||
|
noASCII = flag.Bool("noascii", false, "don't print ASCII strings readably")
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.Usage = func() {
|
||||||
|
fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[-noascii] [-hex <data>] [filename]")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
fmt.Fprintln(os.Stderr, `
|
||||||
|
Dumps RLP data from the given file in readable form.
|
||||||
|
If the filename is omitted, data is read from stdin.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
var r io.Reader
|
||||||
|
switch {
|
||||||
|
case *hexMode != "":
|
||||||
|
data, err := hex.DecodeString(*hexMode)
|
||||||
|
if err != nil {
|
||||||
|
die(err)
|
||||||
|
}
|
||||||
|
r = bytes.NewReader(data)
|
||||||
|
|
||||||
|
case flag.NArg() == 0:
|
||||||
|
r = os.Stdin
|
||||||
|
|
||||||
|
case flag.NArg() == 1:
|
||||||
|
fd, err := os.Open(flag.Arg(0))
|
||||||
|
if err != nil {
|
||||||
|
die(err)
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
r = fd
|
||||||
|
|
||||||
|
default:
|
||||||
|
fmt.Fprintln(os.Stderr, "Error: too many arguments")
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := rlp.NewStream(r)
|
||||||
|
for {
|
||||||
|
if err := dump(s, 0); err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
die(err)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dump(s *rlp.Stream, depth int) error {
|
||||||
|
kind, size, err := s.Kind()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch kind {
|
||||||
|
case rlp.Byte, rlp.String:
|
||||||
|
str, err := s.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(str) == 0 || !*noASCII && isASCII(str) {
|
||||||
|
fmt.Printf("%s%q", ws(depth), str)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s%x", ws(depth), str)
|
||||||
|
}
|
||||||
|
case rlp.List:
|
||||||
|
s.List()
|
||||||
|
defer s.ListEnd()
|
||||||
|
if size == 0 {
|
||||||
|
fmt.Print(ws(depth) + "[]")
|
||||||
|
} else {
|
||||||
|
fmt.Println(ws(depth) + "[")
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
if i > 0 {
|
||||||
|
fmt.Print(",\n")
|
||||||
|
}
|
||||||
|
if err := dump(s, depth+1); err == rlp.EOL {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Print(ws(depth) + "]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isASCII(b []byte) bool {
|
||||||
|
for _, c := range b {
|
||||||
|
if c < 32 || c > 126 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func ws(n int) string {
|
||||||
|
return strings.Repeat(" ", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func die(args ...interface{}) {
|
||||||
|
fmt.Fprintln(os.Stderr, args...)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
156
cmd/utils/cmd.go
156
cmd/utils/cmd.go
|
|
@ -1,10 +1,28 @@
|
||||||
|
/*
|
||||||
|
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>
|
||||||
|
* Viktor Tron <viktor@ethdev.com>
|
||||||
|
*/
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path"
|
"path"
|
||||||
|
|
@ -13,14 +31,15 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"bitbucket.org/kardianos/osext"
|
"bitbucket.org/kardianos/osext"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"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/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/ethereum/go-ethereum/state"
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -50,15 +69,8 @@ func RunInterruptCallbacks(sig os.Signal) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AbsolutePath(Datadir string, filename string) string {
|
|
||||||
if path.IsAbs(filename) {
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
return path.Join(Datadir, filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func openLogFile(Datadir string, filename string) *os.File {
|
func openLogFile(Datadir string, filename string) *os.File {
|
||||||
path := AbsolutePath(Datadir, filename)
|
path := ethutil.AbsolutePath(Datadir, filename)
|
||||||
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("error opening log file '%s': %v", filename, err))
|
panic(fmt.Sprintf("error opening log file '%s': %v", filename, err))
|
||||||
|
|
@ -74,23 +86,13 @@ func confirm(message string) bool {
|
||||||
if r == "n" || r == "y" {
|
if r == "n" || r == "y" {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Yes or no?", r)
|
fmt.Printf("Yes or no? (%s)", r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r == "y"
|
return r == "y"
|
||||||
}
|
}
|
||||||
|
|
||||||
func DBSanityCheck(db ethutil.Database) error {
|
func initDataDir(Datadir string) {
|
||||||
d, _ := db.Get([]byte("ProtocolVersion"))
|
|
||||||
protov := ethutil.NewValue(d).Uint()
|
|
||||||
if protov != eth.ProtocolVersion && protov != 0 {
|
|
||||||
return fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, eth.ProtocolVersion, ethutil.Config.ExecPath+"/database")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitDataDir(Datadir string) {
|
|
||||||
_, err := os.Stat(Datadir)
|
_, err := os.Stat(Datadir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
|
@ -100,26 +102,8 @@ func InitDataDir(Datadir string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) logger.LogSystem {
|
|
||||||
var writer io.Writer
|
|
||||||
if LogFile == "" {
|
|
||||||
writer = os.Stdout
|
|
||||||
} else {
|
|
||||||
writer = openLogFile(Datadir, LogFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
sys := logger.NewStdLogSystem(writer, log.LstdFlags, logger.LogLevel(LogLevel))
|
|
||||||
logger.AddLogSystem(sys)
|
|
||||||
if DebugFile != "" {
|
|
||||||
writer = openLogFile(Datadir, DebugFile)
|
|
||||||
logger.AddLogSystem(logger.NewStdLogSystem(writer, log.LstdFlags, logger.DebugLevel))
|
|
||||||
}
|
|
||||||
|
|
||||||
return sys
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitConfig(vmType int, ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager {
|
func InitConfig(vmType int, ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager {
|
||||||
InitDataDir(Datadir)
|
initDataDir(Datadir)
|
||||||
cfg := ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
|
cfg := ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
|
||||||
cfg.VmType = vmType
|
cfg.VmType = vmType
|
||||||
|
|
||||||
|
|
@ -136,70 +120,19 @@ func exit(err error) {
|
||||||
os.Exit(status)
|
os.Exit(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDatabase() ethutil.Database {
|
func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
|
||||||
db, err := ethdb.NewLDBDatabase("database")
|
clilogger.Infof("Starting %s", ethereum.ClientIdentity())
|
||||||
|
err := ethereum.Start(UseSeed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
exit(err)
|
||||||
}
|
}
|
||||||
return db
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewClientIdentity(clientIdentifier, version, customIdentifier string, pubkey string) *p2p.SimpleClientIdentity {
|
|
||||||
return p2p.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier, pubkey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NatType(natType string, gateway string) (nat p2p.NAT) {
|
|
||||||
switch natType {
|
|
||||||
case "UPNP":
|
|
||||||
nat = p2p.UPNP()
|
|
||||||
case "PMP":
|
|
||||||
ip := net.ParseIP(gateway)
|
|
||||||
if ip == nil {
|
|
||||||
clilogger.Fatalf("cannot resolve PMP gateway IP %s", gateway)
|
|
||||||
}
|
|
||||||
nat = p2p.PMP(ip)
|
|
||||||
case "":
|
|
||||||
default:
|
|
||||||
clilogger.Fatalf("unrecognised NAT type '%s'", natType)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEthereum(db ethutil.Database, clientIdentity p2p.ClientIdentity, keyManager *crypto.KeyManager, nat p2p.NAT, OutboundPort string, MaxPeer int) *eth.Ethereum {
|
|
||||||
ethereum, err := eth.New(db, clientIdentity, keyManager, nat, OutboundPort, MaxPeer)
|
|
||||||
if err != nil {
|
|
||||||
clilogger.Fatalln("eth start err:", err)
|
|
||||||
}
|
|
||||||
return ethereum
|
|
||||||
}
|
|
||||||
|
|
||||||
func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
|
|
||||||
clilogger.Infof("Starting %s", ethereum.ClientIdentity())
|
|
||||||
ethereum.Start(UseSeed)
|
|
||||||
RegisterInterrupt(func(sig os.Signal) {
|
RegisterInterrupt(func(sig os.Signal) {
|
||||||
ethereum.Stop()
|
ethereum.Stop()
|
||||||
logger.Flush()
|
logger.Flush()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShowGenesis(ethereum *eth.Ethereum) {
|
|
||||||
clilogger.Infoln(ethereum.ChainManager().Genesis())
|
|
||||||
exit(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *crypto.KeyManager {
|
|
||||||
var keyManager *crypto.KeyManager
|
|
||||||
switch {
|
|
||||||
case KeyStore == "db":
|
|
||||||
keyManager = crypto.NewDBKeyManager(db)
|
|
||||||
case KeyStore == "file":
|
|
||||||
keyManager = crypto.NewFileKeyManager(Datadir)
|
|
||||||
default:
|
|
||||||
exit(fmt.Errorf("unknown keystore type: %s", KeyStore))
|
|
||||||
}
|
|
||||||
return keyManager
|
|
||||||
}
|
|
||||||
|
|
||||||
func DefaultAssetPath() string {
|
func DefaultAssetPath() string {
|
||||||
var assetPath string
|
var assetPath string
|
||||||
// If the current working directory is the go-ethereum dir
|
// If the current working directory is the go-ethereum dir
|
||||||
|
|
@ -325,9 +258,10 @@ func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
|
||||||
return fmt.Errorf("unknown block %x", hash)
|
return fmt.Errorf("unknown block %x", hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
parent := ethereum.ChainManager().GetBlock(block.PrevHash)
|
parent := ethereum.ChainManager().GetBlock(block.ParentHash())
|
||||||
|
|
||||||
_, err := ethereum.BlockManager().TransitionState(parent.State(), parent, block)
|
statedb := state.New(parent.Root(), ethereum.Db())
|
||||||
|
_, err := ethereum.BlockProcessor().TransitionState(statedb, parent, block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -335,3 +269,25 @@ func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ImportChain(ethereum *eth.Ethereum, fn string) error {
|
||||||
|
clilogger.Infof("importing chain '%s'\n", fn)
|
||||||
|
fh, err := os.OpenFile(fn, os.O_RDONLY, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
var chain types.Blocks
|
||||||
|
if err := rlp.Decode(fh, &chain); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ethereum.ChainManager().Reset()
|
||||||
|
if err := ethereum.ChainManager().InsertChain(chain); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
clilogger.Infof("imported %d blocks\n", len(chain))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,23 @@
|
||||||
|
/*
|
||||||
|
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 utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -10,6 +30,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type VMEnv struct {
|
type VMEnv struct {
|
||||||
|
chain *core.ChainManager
|
||||||
state *state.StateDB
|
state *state.StateDB
|
||||||
block *types.Block
|
block *types.Block
|
||||||
|
|
||||||
|
|
@ -20,8 +41,9 @@ type VMEnv struct {
|
||||||
Gas *big.Int
|
Gas *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnv(state *state.StateDB, block *types.Block, transactor []byte, value *big.Int) *VMEnv {
|
func NewEnv(chain *core.ChainManager, state *state.StateDB, block *types.Block, transactor []byte, value *big.Int) *VMEnv {
|
||||||
return &VMEnv{
|
return &VMEnv{
|
||||||
|
chain: chain,
|
||||||
state: state,
|
state: state,
|
||||||
block: block,
|
block: block,
|
||||||
transactor: transactor,
|
transactor: transactor,
|
||||||
|
|
@ -30,17 +52,23 @@ func NewEnv(state *state.StateDB, block *types.Block, transactor []byte, value *
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Origin() []byte { return self.transactor }
|
func (self *VMEnv) Origin() []byte { return self.transactor }
|
||||||
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number }
|
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() }
|
||||||
func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash }
|
func (self *VMEnv) PrevHash() []byte { return self.block.ParentHash() }
|
||||||
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase }
|
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() }
|
||||||
func (self *VMEnv) Time() int64 { return self.block.Time }
|
func (self *VMEnv) Time() int64 { return self.block.Time() }
|
||||||
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty }
|
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() }
|
||||||
func (self *VMEnv) BlockHash() []byte { return self.block.Hash() }
|
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
|
||||||
func (self *VMEnv) Value() *big.Int { return self.value }
|
func (self *VMEnv) Value() *big.Int { return self.value }
|
||||||
func (self *VMEnv) State() *state.StateDB { return self.state }
|
func (self *VMEnv) State() *state.StateDB { return self.state }
|
||||||
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit }
|
|
||||||
func (self *VMEnv) Depth() int { return self.depth }
|
func (self *VMEnv) Depth() int { return self.depth }
|
||||||
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
||||||
|
func (self *VMEnv) GetHash(n uint64) []byte {
|
||||||
|
if block := self.chain.GetBlockByNumber(n); block != nil {
|
||||||
|
return block.Hash()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func (self *VMEnv) AddLog(log state.Log) {
|
func (self *VMEnv) AddLog(log state.Log) {
|
||||||
self.state.AddLog(log)
|
self.state.AddLog(log)
|
||||||
}
|
}
|
||||||
|
|
@ -52,19 +80,19 @@ func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *core.Execu
|
||||||
return core.NewExecution(self, addr, data, gas, price, value)
|
return core.NewExecution(self, addr, data, gas, price, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Call(caller vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
func (self *VMEnv) Call(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
||||||
exe := self.vm(addr, data, gas, price, value)
|
exe := self.vm(addr, data, gas, price, value)
|
||||||
ret, err := exe.Call(addr, caller)
|
ret, err := exe.Call(addr, caller)
|
||||||
self.Gas = exe.Gas
|
self.Gas = exe.Gas
|
||||||
|
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
func (self *VMEnv) CallCode(caller vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
func (self *VMEnv) CallCode(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
||||||
exe := self.vm(caller.Address(), data, gas, price, value)
|
exe := self.vm(caller.Address(), data, gas, price, value)
|
||||||
return exe.Call(addr, caller)
|
return exe.Call(addr, caller)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Create(caller vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ClosureRef) {
|
func (self *VMEnv) Create(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) {
|
||||||
exe := self.vm(addr, data, gas, price, value)
|
exe := self.vm(addr, data, gas, price, value)
|
||||||
return exe.Create(caller)
|
return exe.Create(caller)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,35 @@
|
||||||
|
/*
|
||||||
|
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 utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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/websocket"
|
"github.com/ethereum/go-ethereum/websocket"
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var wslogger = logger.NewLogger("WS")
|
||||||
|
|
||||||
func args(v ...interface{}) []interface{} {
|
func args(v ...interface{}) []interface{} {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
@ -30,73 +53,73 @@ func (self *WebSocketServer) Serv() {
|
||||||
data := ethutil.NewValue(msg.Args)
|
data := ethutil.NewValue(msg.Args)
|
||||||
bcode, err := ethutil.Compile(data.Get(0).Str(), false)
|
bcode, err := ethutil.Compile(data.Get(0).Str(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Write(args(nil, err.Error()), msg.Seed)
|
c.Write(args(nil, err.Error()), msg.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
code := ethutil.Bytes2Hex(bcode)
|
code := ethutil.Bytes2Hex(bcode)
|
||||||
c.Write(args(code, nil), msg.Seed)
|
c.Write(args(code, nil), msg.Id)
|
||||||
case "getBlockByNumber":
|
case "eth_blockByNumber":
|
||||||
args := msg.Arguments()
|
args := msg.Arguments()
|
||||||
|
|
||||||
block := pipe.BlockByNumber(int32(args.Get(0).Uint()))
|
block := pipe.BlockByNumber(int32(args.Get(0).Uint()))
|
||||||
c.Write(block, msg.Seed)
|
c.Write(block, msg.Id)
|
||||||
|
|
||||||
case "getKey":
|
case "eth_blockByHash":
|
||||||
c.Write(pipe.Key().PrivateKey, msg.Seed)
|
args := msg.Arguments()
|
||||||
case "transact":
|
|
||||||
|
c.Write(pipe.BlockByHash(args.Get(0).Str()), msg.Id)
|
||||||
|
|
||||||
|
case "eth_transact":
|
||||||
if mp, ok := msg.Args[0].(map[string]interface{}); ok {
|
if mp, ok := msg.Args[0].(map[string]interface{}); ok {
|
||||||
object := mapToTxParams(mp)
|
object := mapToTxParams(mp)
|
||||||
c.Write(
|
c.Write(
|
||||||
args(pipe.Transact(object["from"], object["to"], object["value"], object["gas"], object["gasPrice"], object["data"])),
|
args(pipe.Transact(pipe.Key().PrivateKey, object["to"], object["value"], object["gas"], object["gasPrice"], object["data"])),
|
||||||
msg.Seed,
|
msg.Id,
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
case "getCoinBase":
|
case "eth_gasPrice":
|
||||||
c.Write(pipe.CoinBase(), msg.Seed)
|
c.Write("10000000000000", msg.Id)
|
||||||
|
case "eth_coinbase":
|
||||||
|
c.Write(pipe.CoinBase(), msg.Id)
|
||||||
|
|
||||||
case "getIsListening":
|
case "eth_listening":
|
||||||
c.Write(pipe.IsListening(), msg.Seed)
|
c.Write(pipe.IsListening(), msg.Id)
|
||||||
|
|
||||||
case "getIsMining":
|
case "eth_mining":
|
||||||
c.Write(pipe.IsMining(), msg.Seed)
|
c.Write(pipe.IsMining(), msg.Id)
|
||||||
|
|
||||||
case "getPeerCoint":
|
case "eth_peerCount":
|
||||||
c.Write(pipe.PeerCount(), msg.Seed)
|
c.Write(pipe.PeerCount(), msg.Id)
|
||||||
|
|
||||||
case "getCountAt":
|
case "eth_countAt":
|
||||||
args := msg.Arguments()
|
args := msg.Arguments()
|
||||||
|
|
||||||
c.Write(pipe.TxCountAt(args.Get(0).Str()), msg.Seed)
|
c.Write(pipe.TxCountAt(args.Get(0).Str()), msg.Id)
|
||||||
|
|
||||||
case "getCodeAt":
|
case "eth_codeAt":
|
||||||
args := msg.Arguments()
|
args := msg.Arguments()
|
||||||
|
|
||||||
c.Write(len(pipe.CodeAt(args.Get(0).Str())), msg.Seed)
|
c.Write(len(pipe.CodeAt(args.Get(0).Str())), msg.Id)
|
||||||
|
|
||||||
case "getBlockByHash":
|
case "eth_storageAt":
|
||||||
args := msg.Arguments()
|
args := msg.Arguments()
|
||||||
|
|
||||||
c.Write(pipe.BlockByHash(args.Get(0).Str()), msg.Seed)
|
c.Write(pipe.StorageAt(args.Get(0).Str(), args.Get(1).Str()), msg.Id)
|
||||||
|
|
||||||
case "getStorageAt":
|
case "eth_balanceAt":
|
||||||
args := msg.Arguments()
|
args := msg.Arguments()
|
||||||
|
|
||||||
c.Write(pipe.StorageAt(args.Get(0).Str(), args.Get(1).Str()), msg.Seed)
|
c.Write(pipe.BalanceAt(args.Get(0).Str()), msg.Id)
|
||||||
|
|
||||||
case "getBalanceAt":
|
case "eth_secretToAddress":
|
||||||
args := msg.Arguments()
|
args := msg.Arguments()
|
||||||
|
|
||||||
c.Write(pipe.BalanceAt(args.Get(0).Str()), msg.Seed)
|
c.Write(pipe.SecretToAddress(args.Get(0).Str()), msg.Id)
|
||||||
|
|
||||||
case "getSecretToAddress":
|
case "eth_newFilter":
|
||||||
args := msg.Arguments()
|
case "eth_newFilterString":
|
||||||
|
case "eth_messages":
|
||||||
c.Write(pipe.SecretToAddress(args.Get(0).Str()), msg.Seed)
|
|
||||||
|
|
||||||
case "newFilter":
|
|
||||||
case "newFilterString":
|
|
||||||
case "messages":
|
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,6 +129,8 @@ func (self *WebSocketServer) Serv() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartWebSockets(eth *eth.Ethereum) {
|
func StartWebSockets(eth *eth.Ethereum) {
|
||||||
|
wslogger.Infoln("Starting WebSockets")
|
||||||
|
|
||||||
sock := NewWebSocketServer(eth)
|
sock := NewWebSocketServer(eth)
|
||||||
go sock.Serv()
|
go sock.Serv()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"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"
|
||||||
|
|
@ -17,24 +16,13 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"github.com/ethereum/go-ethereum/pow/ezp"
|
"github.com/ethereum/go-ethereum/pow/ezp"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
|
"gopkg.in/fatih/set.v0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var statelogger = logger.NewLogger("BLOCK")
|
var statelogger = logger.NewLogger("BLOCK")
|
||||||
|
|
||||||
type Peer interface {
|
|
||||||
Inbound() bool
|
|
||||||
LastSend() time.Time
|
|
||||||
LastPong() int64
|
|
||||||
Host() []byte
|
|
||||||
Port() uint16
|
|
||||||
Version() string
|
|
||||||
PingTime() string
|
|
||||||
Connected() *int32
|
|
||||||
Caps() *ethutil.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
type EthManager interface {
|
type EthManager interface {
|
||||||
BlockManager() *BlockManager
|
BlockProcessor() *BlockProcessor
|
||||||
ChainManager() *ChainManager
|
ChainManager() *ChainManager
|
||||||
TxPool() *TxPool
|
TxPool() *TxPool
|
||||||
PeerCount() int
|
PeerCount() int
|
||||||
|
|
@ -47,7 +35,8 @@ type EthManager interface {
|
||||||
EventMux() *event.TypeMux
|
EventMux() *event.TypeMux
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockManager struct {
|
type BlockProcessor struct {
|
||||||
|
db ethutil.Database
|
||||||
// Mutex for locking the block processor. Blocks can only be handled one at a time
|
// Mutex for locking the block processor. Blocks can only be handled one at a time
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
// Canonical block chain
|
// Canonical block chain
|
||||||
|
|
@ -69,8 +58,9 @@ type BlockManager struct {
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockManager(txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockManager {
|
func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
|
||||||
sm := &BlockManager{
|
sm := &BlockProcessor{
|
||||||
|
db: db,
|
||||||
mem: make(map[string]*big.Int),
|
mem: make(map[string]*big.Int),
|
||||||
Pow: ezp.New(),
|
Pow: ezp.New(),
|
||||||
bc: chainManager,
|
bc: chainManager,
|
||||||
|
|
@ -81,11 +71,11 @@ func NewBlockManager(txpool *TxPool, chainManager *ChainManager, eventMux *event
|
||||||
return sm
|
return sm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *BlockManager) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) {
|
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) {
|
||||||
coinbase := statedb.GetOrNewStateObject(block.Coinbase)
|
coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase)
|
||||||
coinbase.SetGasPool(block.CalcGasLimit(parent))
|
coinbase.SetGasPool(CalcGasLimit(parent, block))
|
||||||
|
|
||||||
// Process the transactions on to current block
|
// Process the transactions on to parent state
|
||||||
receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false)
|
receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -94,7 +84,7 @@ func (sm *BlockManager) TransitionState(statedb *state.StateDB, parent, block *t
|
||||||
return receipts, nil
|
return receipts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BlockManager) ApplyTransactions(coinbase *state.StateObject, state *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
|
func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
|
||||||
var (
|
var (
|
||||||
receipts types.Receipts
|
receipts types.Receipts
|
||||||
handled, unhandled types.Transactions
|
handled, unhandled types.Transactions
|
||||||
|
|
@ -112,7 +102,7 @@ done:
|
||||||
txGas := new(big.Int).Set(tx.Gas())
|
txGas := new(big.Int).Set(tx.Gas())
|
||||||
|
|
||||||
cb := state.GetStateObject(coinbase.Address())
|
cb := state.GetStateObject(coinbase.Address())
|
||||||
st := NewStateTransition(cb, tx, state, block)
|
st := NewStateTransition(NewEnv(state, self.bc, tx, block), tx, cb)
|
||||||
_, err = st.TransitionState()
|
_, err = st.TransitionState()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -127,7 +117,6 @@ done:
|
||||||
statelogger.Infoln(err)
|
statelogger.Infoln(err)
|
||||||
erroneous = append(erroneous, tx)
|
erroneous = append(erroneous, tx)
|
||||||
err = nil
|
err = nil
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,6 +130,7 @@ done:
|
||||||
receipt := types.NewReceipt(state.Root(), cumulative)
|
receipt := types.NewReceipt(state.Root(), cumulative)
|
||||||
receipt.SetLogs(state.Logs())
|
receipt.SetLogs(state.Logs())
|
||||||
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
||||||
|
chainlogger.Debugln(receipt)
|
||||||
|
|
||||||
// Notify all subscribers
|
// Notify all subscribers
|
||||||
if !transientProcess {
|
if !transientProcess {
|
||||||
|
|
@ -156,38 +146,34 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
block.Reward = cumulativeSum
|
block.Reward = cumulativeSum
|
||||||
block.GasUsed = totalUsedGas
|
block.Header().GasUsed = totalUsedGas
|
||||||
|
|
||||||
return receipts, handled, unhandled, erroneous, err
|
return receipts, handled, unhandled, erroneous, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *BlockManager) Process(block *types.Block) (td *big.Int, msgs state.Messages, err error) {
|
func (sm *BlockProcessor) Process(block *types.Block) (td *big.Int, msgs state.Messages, err error) {
|
||||||
// Processing a blocks may never happen simultaneously
|
// Processing a blocks may never happen simultaneously
|
||||||
sm.mutex.Lock()
|
sm.mutex.Lock()
|
||||||
defer sm.mutex.Unlock()
|
defer sm.mutex.Unlock()
|
||||||
|
|
||||||
if sm.bc.HasBlock(block.Hash()) {
|
header := block.Header()
|
||||||
return nil, nil, &KnownBlockError{block.Number, block.Hash()}
|
if sm.bc.HasBlock(header.Hash()) {
|
||||||
|
return nil, nil, &KnownBlockError{header.Number, header.Hash()}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !sm.bc.HasBlock(block.PrevHash) {
|
if !sm.bc.HasBlock(header.ParentHash) {
|
||||||
return nil, nil, ParentError(block.PrevHash)
|
return nil, nil, ParentError(header.ParentHash)
|
||||||
}
|
}
|
||||||
parent := sm.bc.GetBlock(block.PrevHash)
|
parent := sm.bc.GetBlock(header.ParentHash)
|
||||||
|
|
||||||
return sm.ProcessWithParent(block, parent)
|
return sm.ProcessWithParent(block, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.Int, messages state.Messages, err error) {
|
func (sm *BlockProcessor) ProcessWithParent(block, parent *types.Block) (td *big.Int, messages state.Messages, err error) {
|
||||||
sm.lastAttemptedBlock = block
|
sm.lastAttemptedBlock = block
|
||||||
|
|
||||||
state := parent.State().Copy()
|
state := state.New(parent.Root(), sm.db)
|
||||||
|
//state := state.New(parent.Trie().Copy())
|
||||||
// Defer the Undo on the Trie. If the block processing happened
|
|
||||||
// we don't want to undo but since undo only happens on dirty
|
|
||||||
// nodes this won't happen because Commit would have been called
|
|
||||||
// before that.
|
|
||||||
defer state.Reset()
|
|
||||||
|
|
||||||
// Block validation
|
// Block validation
|
||||||
if err = sm.ValidateBlock(block, parent); err != nil {
|
if err = sm.ValidateBlock(block, parent); err != nil {
|
||||||
|
|
@ -199,21 +185,24 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header := block.Header()
|
||||||
|
|
||||||
rbloom := types.CreateBloom(receipts)
|
rbloom := types.CreateBloom(receipts)
|
||||||
if bytes.Compare(rbloom, block.LogsBloom) != 0 {
|
if bytes.Compare(rbloom, header.Bloom) != 0 {
|
||||||
err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
|
err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
txSha := types.DeriveSha(block.Transactions())
|
txSha := types.DeriveSha(block.Transactions())
|
||||||
if bytes.Compare(txSha, block.TxSha) != 0 {
|
if bytes.Compare(txSha, header.TxHash) != 0 {
|
||||||
err = fmt.Errorf("validating transaction root. received=%x got=%x", block.TxSha, txSha)
|
err = fmt.Errorf("validating transaction root. received=%x got=%x", header.TxHash, txSha)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
receiptSha := types.DeriveSha(receipts)
|
receiptSha := types.DeriveSha(receipts)
|
||||||
if bytes.Compare(receiptSha, block.ReceiptSha) != 0 {
|
if bytes.Compare(receiptSha, header.ReceiptHash) != 0 {
|
||||||
err = fmt.Errorf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha)
|
fmt.Println("receipts", receipts)
|
||||||
|
err = fmt.Errorf("validating receipt root. received=%x got=%x", header.ReceiptHash, receiptSha)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,8 +212,8 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
|
||||||
|
|
||||||
state.Update(ethutil.Big0)
|
state.Update(ethutil.Big0)
|
||||||
|
|
||||||
if !block.State().Cmp(state) {
|
if !bytes.Equal(header.Root, state.Root()) {
|
||||||
err = fmt.Errorf("invalid merkle root. received=%x got=%x", block.Root(), state.Root())
|
err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,10 +222,12 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
|
||||||
// Sync the current block's state to the database and cancelling out the deferred Undo
|
// Sync the current block's state to the database and cancelling out the deferred Undo
|
||||||
state.Sync()
|
state.Sync()
|
||||||
|
|
||||||
|
state.Manifest().SetHash(block.Hash())
|
||||||
|
|
||||||
messages := state.Manifest().Messages
|
messages := state.Manifest().Messages
|
||||||
state.Manifest().Reset()
|
state.Manifest().Reset()
|
||||||
|
|
||||||
chainlogger.Infof("Processed block #%d (%x...)\n", block.Number, block.Hash()[0:4])
|
chainlogger.Infof("processed block #%d (%x...)\n", header.Number, block.Hash()[0:4])
|
||||||
|
|
||||||
sm.txpool.RemoveSet(block.Transactions())
|
sm.txpool.RemoveSet(block.Transactions())
|
||||||
|
|
||||||
|
|
@ -246,16 +237,16 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) {
|
func (sm *BlockProcessor) CalculateTD(block *types.Block) (*big.Int, bool) {
|
||||||
uncleDiff := new(big.Int)
|
uncleDiff := new(big.Int)
|
||||||
for _, uncle := range block.Uncles {
|
for _, uncle := range block.Uncles() {
|
||||||
uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
|
uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
|
// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
|
||||||
td := new(big.Int)
|
td := new(big.Int)
|
||||||
td = td.Add(sm.bc.Td(), uncleDiff)
|
td = td.Add(sm.bc.Td(), uncleDiff)
|
||||||
td = td.Add(td, block.Difficulty)
|
td = td.Add(td, block.Header().Difficulty)
|
||||||
|
|
||||||
// The new TD will only be accepted if the new difficulty is
|
// The new TD will only be accepted if the new difficulty is
|
||||||
// is greater than the previous.
|
// is greater than the previous.
|
||||||
|
|
@ -269,15 +260,20 @@ func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) {
|
||||||
// Validates the current block. Returns an error if the block was invalid,
|
// Validates the current block. Returns an error if the block was invalid,
|
||||||
// an uncle or anything that isn't on the current block chain.
|
// an uncle or anything that isn't on the current block chain.
|
||||||
// Validation validates easy over difficult (dagger takes longer time = difficult)
|
// Validation validates easy over difficult (dagger takes longer time = difficult)
|
||||||
func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error {
|
func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
|
||||||
expd := CalcDifficulty(block, parent)
|
if len(block.Header().Extra) > 1024 {
|
||||||
if expd.Cmp(block.Difficulty) < 0 {
|
return fmt.Errorf("Block extra data too long (%d)", len(block.Header().Extra))
|
||||||
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
diff := block.Time - parent.Time
|
expd := CalcDifficulty(block, parent)
|
||||||
|
if expd.Cmp(block.Header().Difficulty) < 0 {
|
||||||
|
fmt.Println("parent\n", parent)
|
||||||
|
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd)
|
||||||
|
}
|
||||||
|
|
||||||
|
diff := block.Header().Time - parent.Header().Time
|
||||||
if diff < 0 {
|
if diff < 0 {
|
||||||
return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock().Time)
|
return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Header().Time, sm.bc.CurrentBlock().Header().Time)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX
|
/* XXX
|
||||||
|
|
@ -289,37 +285,47 @@ func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error {
|
||||||
|
|
||||||
// Verify the nonce of the block. Return an error if it's not valid
|
// Verify the nonce of the block. Return an error if it's not valid
|
||||||
if !sm.Pow.Verify(block /*block.HashNoNonce(), block.Difficulty, block.Nonce*/) {
|
if !sm.Pow.Verify(block /*block.HashNoNonce(), block.Difficulty, block.Nonce*/) {
|
||||||
return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce))
|
return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Header().Nonce))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent *types.Block) error {
|
func (sm *BlockProcessor) AccumelateRewards(statedb *state.StateDB, block, parent *types.Block) error {
|
||||||
reward := new(big.Int).Set(BlockReward)
|
reward := new(big.Int).Set(BlockReward)
|
||||||
|
|
||||||
knownUncles := ethutil.Set(parent.Uncles)
|
ancestors := set.New()
|
||||||
nonces := ethutil.NewSet(block.Nonce)
|
for _, ancestor := range sm.bc.GetAncestors(block, 6) {
|
||||||
for _, uncle := range block.Uncles {
|
ancestors.Add(string(ancestor.Hash()))
|
||||||
if nonces.Include(uncle.Nonce) {
|
}
|
||||||
|
|
||||||
|
uncles := set.New()
|
||||||
|
uncles.Add(string(block.Hash()))
|
||||||
|
for _, uncle := range block.Uncles() {
|
||||||
|
if uncles.Has(string(uncle.Hash())) {
|
||||||
// Error not unique
|
// Error not unique
|
||||||
return UncleError("Uncle not unique")
|
return UncleError("Uncle not unique")
|
||||||
}
|
}
|
||||||
|
uncles.Add(string(uncle.Hash()))
|
||||||
|
|
||||||
uncleParent := sm.bc.GetBlock(uncle.PrevHash)
|
if !ancestors.Has(uncle.ParentHash) {
|
||||||
if uncleParent == nil {
|
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
||||||
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.PrevHash[0:4]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 {
|
/*
|
||||||
return UncleError("Uncle too old")
|
uncleParent := sm.bc.GetBlock(uncle.ParentHash)
|
||||||
}
|
if uncleParent == nil {
|
||||||
|
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
||||||
|
}
|
||||||
|
|
||||||
if knownUncles.Include(uncle.Hash()) {
|
if uncleParent.Number().Cmp(new(big.Int).Sub(parent.Number(), big.NewInt(6))) < 0 {
|
||||||
return UncleError("Uncle in chain")
|
return UncleError("Uncle too old")
|
||||||
}
|
}
|
||||||
|
|
||||||
nonces.Insert(uncle.Nonce)
|
if knownUncles.Has(string(uncle.Hash())) {
|
||||||
|
return UncleError("Uncle in chain")
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
r := new(big.Int)
|
r := new(big.Int)
|
||||||
r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
|
r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
|
||||||
|
|
@ -331,31 +337,32 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the account associated with the coinbase
|
// Get the account associated with the coinbase
|
||||||
account := statedb.GetAccount(block.Coinbase)
|
account := statedb.GetAccount(block.Header().Coinbase)
|
||||||
// Reward amount of ether to the coinbase address
|
// Reward amount of ether to the coinbase address
|
||||||
account.AddAmount(reward)
|
account.AddAmount(reward)
|
||||||
|
|
||||||
statedb.Manifest().AddMessage(&state.Message{
|
statedb.Manifest().AddMessage(&state.Message{
|
||||||
To: block.Coinbase,
|
To: block.Header().Coinbase,
|
||||||
Input: nil,
|
Input: nil,
|
||||||
Origin: nil,
|
Origin: nil,
|
||||||
Block: block.Hash(), Timestamp: block.Time, Coinbase: block.Coinbase, Number: block.Number,
|
Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number,
|
||||||
Value: new(big.Int).Add(reward, block.Reward),
|
Value: new(big.Int).Add(reward, block.Reward),
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *BlockManager) GetMessages(block *types.Block) (messages []*state.Message, err error) {
|
func (sm *BlockProcessor) GetMessages(block *types.Block) (messages []*state.Message, err error) {
|
||||||
if !sm.bc.HasBlock(block.PrevHash) {
|
if !sm.bc.HasBlock(block.Header().ParentHash) {
|
||||||
return nil, ParentError(block.PrevHash)
|
return nil, ParentError(block.Header().ParentHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
sm.lastAttemptedBlock = block
|
sm.lastAttemptedBlock = block
|
||||||
|
|
||||||
var (
|
var (
|
||||||
parent = sm.bc.GetBlock(block.PrevHash)
|
parent = sm.bc.GetBlock(block.Header().ParentHash)
|
||||||
state = parent.State().Copy()
|
//state = state.New(parent.Trie().Copy())
|
||||||
|
state = state.New(parent.Root(), sm.db)
|
||||||
)
|
)
|
||||||
|
|
||||||
defer state.Reset()
|
defer state.Reset()
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
@ -9,44 +10,52 @@ import (
|
||||||
"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/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
var chainlogger = logger.NewLogger("CHAIN")
|
var chainlogger = logger.NewLogger("CHAIN")
|
||||||
|
|
||||||
func AddTestNetFunds(block *types.Block) {
|
type StateQuery interface {
|
||||||
for _, addr := range []string{
|
GetAccount(addr []byte) *state.StateObject
|
||||||
"51ba59315b3a95761d0863b05ccc7a7f54703d99",
|
|
||||||
"e4157b34ea9615cfbde6b4fda419828124b70c78",
|
|
||||||
"b9c015918bdaba24b4ff057a92a3873d6eb201be",
|
|
||||||
"6c386a4b26f73c802f34673f7248bb118f97424a",
|
|
||||||
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826",
|
|
||||||
"2ef47100e0787b915105fd5e3f4ff6752079d5cb",
|
|
||||||
"e6716f9544a56c530d868e4bfbacb172315bdead",
|
|
||||||
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4",
|
|
||||||
} {
|
|
||||||
codedAddr := ethutil.Hex2Bytes(addr)
|
|
||||||
account := block.State().GetAccount(codedAddr)
|
|
||||||
account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200)
|
|
||||||
block.State().UpdateStateObject(account)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CalcDifficulty(block, parent *types.Block) *big.Int {
|
func CalcDifficulty(block, parent *types.Block) *big.Int {
|
||||||
diff := new(big.Int)
|
diff := new(big.Int)
|
||||||
|
|
||||||
adjust := new(big.Int).Rsh(parent.Difficulty, 10)
|
bh, ph := block.Header(), parent.Header()
|
||||||
if block.Time >= parent.Time+5 {
|
adjust := new(big.Int).Rsh(ph.Difficulty, 10)
|
||||||
diff.Sub(parent.Difficulty, adjust)
|
if bh.Time >= ph.Time+13 {
|
||||||
|
diff.Sub(ph.Difficulty, adjust)
|
||||||
} else {
|
} else {
|
||||||
diff.Add(parent.Difficulty, adjust)
|
diff.Add(ph.Difficulty, adjust)
|
||||||
}
|
}
|
||||||
|
|
||||||
return diff
|
return diff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CalcGasLimit(parent, block *types.Block) *big.Int {
|
||||||
|
if block.Number().Cmp(big.NewInt(0)) == 0 {
|
||||||
|
return ethutil.BigPow(10, 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024
|
||||||
|
|
||||||
|
previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit())
|
||||||
|
current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed()), big.NewRat(6, 5))
|
||||||
|
curInt := new(big.Int).Div(current.Num(), current.Denom())
|
||||||
|
|
||||||
|
result := new(big.Int).Add(previous, curInt)
|
||||||
|
result.Div(result, big.NewInt(1024))
|
||||||
|
|
||||||
|
min := big.NewInt(125000)
|
||||||
|
|
||||||
|
return ethutil.BigMax(min, result)
|
||||||
|
}
|
||||||
|
|
||||||
type ChainManager struct {
|
type ChainManager struct {
|
||||||
//eth EthManager
|
//eth EthManager
|
||||||
|
db ethutil.Database
|
||||||
processor types.BlockProcessor
|
processor types.BlockProcessor
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
genesisBlock *types.Block
|
genesisBlock *types.Block
|
||||||
|
|
@ -88,13 +97,9 @@ func (self *ChainManager) CurrentBlock() *types.Block {
|
||||||
return self.currentBlock
|
return self.currentBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChainManager(mux *event.TypeMux) *ChainManager {
|
func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
|
||||||
bc := &ChainManager{}
|
bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
|
||||||
bc.genesisBlock = types.NewBlockFromBytes(ethutil.Encode(Genesis))
|
|
||||||
bc.eventMux = mux
|
|
||||||
|
|
||||||
bc.setLastBlock()
|
bc.setLastBlock()
|
||||||
|
|
||||||
bc.transState = bc.State().Copy()
|
bc.transState = bc.State().Copy()
|
||||||
|
|
||||||
return bc
|
return bc
|
||||||
|
|
@ -112,7 +117,7 @@ func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ChainManager) State() *state.StateDB {
|
func (self *ChainManager) State() *state.StateDB {
|
||||||
return self.CurrentBlock().State()
|
return state.New(self.CurrentBlock().Root(), self.db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ChainManager) TransState() *state.StateDB {
|
func (self *ChainManager) TransState() *state.StateDB {
|
||||||
|
|
@ -120,23 +125,21 @@ func (self *ChainManager) TransState() *state.StateDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *ChainManager) setLastBlock() {
|
func (bc *ChainManager) setLastBlock() {
|
||||||
data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
|
data, _ := bc.db.Get([]byte("LastBlock"))
|
||||||
if len(data) != 0 {
|
if len(data) != 0 {
|
||||||
// Prep genesis
|
var block types.Block
|
||||||
AddTestNetFunds(bc.genesisBlock)
|
rlp.Decode(bytes.NewReader(data), &block)
|
||||||
|
bc.currentBlock = &block
|
||||||
block := types.NewBlockFromBytes(data)
|
|
||||||
bc.currentBlock = block
|
|
||||||
bc.lastBlockHash = block.Hash()
|
bc.lastBlockHash = block.Hash()
|
||||||
bc.lastBlockNumber = block.Number.Uint64()
|
bc.lastBlockNumber = block.Header().Number.Uint64()
|
||||||
|
|
||||||
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
|
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
|
||||||
bc.td = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
|
bc.td = ethutil.BigD(bc.db.LastKnownTD())
|
||||||
} else {
|
} else {
|
||||||
bc.Reset()
|
bc.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
chainlogger.Infof("Last block (#%d) %x\n", bc.lastBlockNumber, bc.currentBlock.Hash())
|
chainlogger.Infof("Last block (#%d) %x TD=%v\n", bc.lastBlockNumber, bc.currentBlock.Hash(), bc.td)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block creation & chain handling
|
// Block creation & chain handling
|
||||||
|
|
@ -144,27 +147,28 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
|
||||||
bc.mu.RLock()
|
bc.mu.RLock()
|
||||||
defer bc.mu.RUnlock()
|
defer bc.mu.RUnlock()
|
||||||
|
|
||||||
var root interface{}
|
var root []byte
|
||||||
hash := ZeroHash256
|
parentHash := ZeroHash256
|
||||||
|
|
||||||
if bc.CurrentBlock != nil {
|
if bc.CurrentBlock != nil {
|
||||||
root = bc.currentBlock.Root()
|
root = bc.currentBlock.Header().Root
|
||||||
hash = bc.lastBlockHash
|
parentHash = bc.lastBlockHash
|
||||||
}
|
}
|
||||||
|
|
||||||
block := types.CreateBlock(
|
block := types.NewBlock(
|
||||||
root,
|
parentHash,
|
||||||
hash,
|
|
||||||
coinbase,
|
coinbase,
|
||||||
|
root,
|
||||||
ethutil.BigPow(2, 32),
|
ethutil.BigPow(2, 32),
|
||||||
nil,
|
nil,
|
||||||
"")
|
"")
|
||||||
|
|
||||||
parent := bc.currentBlock
|
parent := bc.currentBlock
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
block.Difficulty = CalcDifficulty(block, parent)
|
header := block.Header()
|
||||||
block.Number = new(big.Int).Add(bc.currentBlock.Number, ethutil.Big1)
|
header.Difficulty = CalcDifficulty(block, parent)
|
||||||
block.GasLimit = block.CalcGasLimit(bc.currentBlock)
|
header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
|
||||||
|
header.GasLimit = CalcGasLimit(parent, block)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,37 +179,35 @@ func (bc *ChainManager) Reset() {
|
||||||
bc.mu.Lock()
|
bc.mu.Lock()
|
||||||
defer bc.mu.Unlock()
|
defer bc.mu.Unlock()
|
||||||
|
|
||||||
AddTestNetFunds(bc.genesisBlock)
|
for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
|
||||||
|
bc.db.Delete(block.Hash())
|
||||||
|
}
|
||||||
|
|
||||||
bc.genesisBlock.Trie().Sync()
|
|
||||||
// Prepare the genesis block
|
// Prepare the genesis block
|
||||||
bc.write(bc.genesisBlock)
|
bc.write(bc.genesisBlock)
|
||||||
bc.insert(bc.genesisBlock)
|
bc.insert(bc.genesisBlock)
|
||||||
bc.currentBlock = bc.genesisBlock
|
bc.currentBlock = bc.genesisBlock
|
||||||
|
|
||||||
bc.setTotalDifficulty(ethutil.Big("0"))
|
bc.setTotalDifficulty(ethutil.Big("0"))
|
||||||
|
|
||||||
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
|
|
||||||
bc.td = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ChainManager) Export() []byte {
|
func (self *ChainManager) Export() []byte {
|
||||||
self.mu.RLock()
|
self.mu.RLock()
|
||||||
defer self.mu.RUnlock()
|
defer self.mu.RUnlock()
|
||||||
|
|
||||||
chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Number)
|
chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number)
|
||||||
|
|
||||||
blocks := make([]*types.Block, int(self.currentBlock.Number.Int64())+1)
|
blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1)
|
||||||
for block := self.currentBlock; block != nil; block = self.GetBlock(block.PrevHash) {
|
for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) {
|
||||||
blocks[block.Number.Int64()] = block
|
blocks[block.NumberU64()] = block
|
||||||
}
|
}
|
||||||
|
|
||||||
return ethutil.Encode(blocks)
|
return ethutil.Encode(blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *ChainManager) insert(block *types.Block) {
|
func (bc *ChainManager) insert(block *types.Block) {
|
||||||
encodedBlock := block.RlpEncode()
|
encodedBlock := ethutil.Encode(block)
|
||||||
ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
|
bc.db.Put([]byte("LastBlock"), encodedBlock)
|
||||||
bc.currentBlock = block
|
bc.currentBlock = block
|
||||||
bc.lastBlockHash = block.Hash()
|
bc.lastBlockHash = block.Hash()
|
||||||
}
|
}
|
||||||
|
|
@ -213,8 +215,8 @@ func (bc *ChainManager) insert(block *types.Block) {
|
||||||
func (bc *ChainManager) write(block *types.Block) {
|
func (bc *ChainManager) write(block *types.Block) {
|
||||||
bc.writeBlockInfo(block)
|
bc.writeBlockInfo(block)
|
||||||
|
|
||||||
encodedBlock := block.RlpEncode()
|
encodedBlock := ethutil.Encode(block.RlpDataForStorage())
|
||||||
ethutil.Config.Db.Put(block.Hash(), encodedBlock)
|
bc.db.Put(block.Hash(), encodedBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
|
|
@ -224,7 +226,7 @@ func (bc *ChainManager) Genesis() *types.Block {
|
||||||
|
|
||||||
// Block fetching methods
|
// Block fetching methods
|
||||||
func (bc *ChainManager) HasBlock(hash []byte) bool {
|
func (bc *ChainManager) HasBlock(hash []byte) bool {
|
||||||
data, _ := ethutil.Config.Db.Get(hash)
|
data, _ := bc.db.Get(hash)
|
||||||
return len(data) != 0
|
return len(data) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,85 +238,98 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain
|
||||||
|
|
||||||
// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
|
// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
|
||||||
for i := uint64(0); i < max; i++ {
|
for i := uint64(0); i < max; i++ {
|
||||||
|
block = self.GetBlock(block.Header().ParentHash)
|
||||||
chain = append(chain, block.Hash())
|
chain = append(chain, block.Hash())
|
||||||
|
if block.Header().Number.Cmp(ethutil.Big0) <= 0 {
|
||||||
if block.Number.Cmp(ethutil.Big0) <= 0 {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
block = self.GetBlock(block.PrevHash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ChainManager) GetBlock(hash []byte) *types.Block {
|
func (self *ChainManager) GetBlock(hash []byte) *types.Block {
|
||||||
data, _ := ethutil.Config.Db.Get(hash)
|
data, _ := self.db.Get(hash)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
var block types.Block
|
||||||
|
if err := rlp.Decode(bytes.NewReader(data), &block); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return types.NewBlockFromBytes(data)
|
return &block
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) {
|
||||||
|
for i := 0; block != nil && i < length; i++ {
|
||||||
|
uncles = append(uncles, block.Uncles()...)
|
||||||
|
block = self.GetBlock(block.ParentHash())
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ChainManager) GetAncestors(block *types.Block, length int) (blocks []*types.Block) {
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
block = self.GetBlock(block.ParentHash())
|
||||||
|
if block == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks = append(blocks, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
|
func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
|
||||||
self.mu.RLock()
|
self.mu.RLock()
|
||||||
defer self.mu.RUnlock()
|
defer self.mu.RUnlock()
|
||||||
|
|
||||||
block := self.currentBlock
|
var block *types.Block
|
||||||
for ; block != nil; block = self.GetBlock(block.PrevHash) {
|
|
||||||
if block.Number.Uint64() == num {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if block != nil && block.Number.Uint64() == 0 && num != 0 {
|
if num <= self.currentBlock.Number().Uint64() {
|
||||||
return nil
|
block = self.currentBlock
|
||||||
|
for ; block != nil; block = self.GetBlock(block.Header().ParentHash) {
|
||||||
|
if block.Header().Number.Uint64() == num {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
|
func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
|
||||||
ethutil.Config.Db.Put([]byte("LTD"), td.Bytes())
|
bc.db.Put([]byte("LTD"), td.Bytes())
|
||||||
bc.td = td
|
bc.td = td
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
|
func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
|
||||||
parent := self.GetBlock(block.PrevHash)
|
parent := self.GetBlock(block.Header().ParentHash)
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash)
|
return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.Header().ParentHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
parentTd := parent.BlockInfo().TD
|
parentTd := parent.Td
|
||||||
|
|
||||||
uncleDiff := new(big.Int)
|
uncleDiff := new(big.Int)
|
||||||
for _, uncle := range block.Uncles {
|
for _, uncle := range block.Uncles() {
|
||||||
uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
|
uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
|
||||||
}
|
}
|
||||||
|
|
||||||
td := new(big.Int)
|
td := new(big.Int)
|
||||||
td = td.Add(parentTd, uncleDiff)
|
td = td.Add(parentTd, uncleDiff)
|
||||||
td = td.Add(td, block.Difficulty)
|
td = td.Add(td, block.Header().Difficulty)
|
||||||
|
|
||||||
return td, nil
|
return td, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *ChainManager) BlockInfo(block *types.Block) types.BlockInfo {
|
|
||||||
bi := types.BlockInfo{}
|
|
||||||
data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
|
|
||||||
bi.RlpDecode(data)
|
|
||||||
|
|
||||||
return bi
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unexported method for writing extra non-essential block info to the db
|
// Unexported method for writing extra non-essential block info to the db
|
||||||
func (bc *ChainManager) writeBlockInfo(block *types.Block) {
|
func (bc *ChainManager) writeBlockInfo(block *types.Block) {
|
||||||
bc.lastBlockNumber++
|
bc.lastBlockNumber++
|
||||||
bi := types.BlockInfo{Number: bc.lastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash, TD: bc.td}
|
|
||||||
|
|
||||||
// For now we use the block hash with the words "info" appended as key
|
|
||||||
ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *ChainManager) Stop() {
|
func (bc *ChainManager) Stop() {
|
||||||
|
|
@ -331,24 +346,26 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
chainlogger.Infof("block #%v process failed (%x)\n", block.Number, block.Hash()[:4])
|
h := block.Header()
|
||||||
|
chainlogger.Infof("block #%v process failed (%x)\n", h.Number, h.Hash()[:4])
|
||||||
chainlogger.Infoln(block)
|
chainlogger.Infoln(block)
|
||||||
chainlogger.Infoln(err)
|
chainlogger.Infoln(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
block.Td = td
|
||||||
|
|
||||||
self.mu.Lock()
|
self.mu.Lock()
|
||||||
{
|
{
|
||||||
|
|
||||||
self.write(block)
|
self.write(block)
|
||||||
|
cblock := self.currentBlock
|
||||||
if td.Cmp(self.td) > 0 {
|
if td.Cmp(self.td) > 0 {
|
||||||
if block.Number.Cmp(new(big.Int).Add(self.currentBlock.Number, ethutil.Big1)) < 0 {
|
if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 {
|
||||||
chainlogger.Infof("Split detected. New head #%v (%x), was #%v (%x)\n", block.Number, block.Hash()[:4], self.currentBlock.Number, self.currentBlock.Hash()[:4])
|
chainlogger.Infof("Split detected. New head #%v (%x), was #%v (%x)\n", block.Header().Number, block.Hash()[:4], cblock.Header().Number, cblock.Hash()[:4])
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setTotalDifficulty(td)
|
self.setTotalDifficulty(td)
|
||||||
self.insert(block)
|
self.insert(block)
|
||||||
self.transState = self.currentBlock.State().Copy()
|
self.transState = state.New(cblock.Root(), self.db) //state.New(cblock.Trie().Copy())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -360,3 +377,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Satisfy state query interface
|
||||||
|
func (self *ChainManager) GetAccount(addr []byte) *state.StateObject {
|
||||||
|
return self.State().GetAccount(addr)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,39 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"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/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
//logpkg "github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
//var Logger logpkg.LogSystem
|
|
||||||
//var Log = logpkg.NewLogger("TEST")
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
//Logger = logpkg.NewStdLogSystem(os.Stdout, log.LstdFlags, logpkg.InfoLevel)
|
|
||||||
//logpkg.AddLogSystem(Logger)
|
|
||||||
|
|
||||||
ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH")
|
ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH")
|
||||||
|
|
||||||
db, err := ethdb.NewMemDatabase()
|
|
||||||
if err != nil {
|
|
||||||
panic("Could not create mem-db, failing")
|
|
||||||
}
|
|
||||||
ethutil.Config.Db = db
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadChain(fn string, t *testing.T) types.Blocks {
|
func loadChain(fn string, t *testing.T) (types.Blocks, error) {
|
||||||
c1, err := ethutil.ReadAllFile(path.Join("..", "_data", fn))
|
fh, err := os.OpenFile(path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "_data", fn), os.O_RDONLY, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
return nil, err
|
||||||
t.FailNow()
|
|
||||||
}
|
}
|
||||||
value := ethutil.NewValueFromBytes([]byte(c1))
|
defer fh.Close()
|
||||||
blocks := make(types.Blocks, value.Len())
|
|
||||||
it := value.NewIterator()
|
var chain types.Blocks
|
||||||
for it.Next() {
|
if err := rlp.Decode(fh, &chain); err != nil {
|
||||||
blocks[it.Idx()] = types.NewBlockFromRlpValue(it.Value())
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return blocks
|
return chain, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *testing.T) {
|
func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *testing.T) {
|
||||||
|
|
@ -56,12 +46,24 @@ func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChainInsertions(t *testing.T) {
|
func TestChainInsertions(t *testing.T) {
|
||||||
chain1 := loadChain("chain1", t)
|
db, _ := ethdb.NewMemDatabase()
|
||||||
chain2 := loadChain("chain2", t)
|
|
||||||
|
chain1, err := loadChain("valid1", t)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
chain2, err := loadChain("valid2", t)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
var eventMux event.TypeMux
|
var eventMux event.TypeMux
|
||||||
chainMan := NewChainManager(&eventMux)
|
chainMan := NewChainManager(db, &eventMux)
|
||||||
txPool := NewTxPool(chainMan, nil, &eventMux)
|
txPool := NewTxPool(&eventMux)
|
||||||
blockMan := NewBlockManager(txPool, chainMan, &eventMux)
|
blockMan := NewBlockProcessor(db, txPool, chainMan, &eventMux)
|
||||||
chainMan.SetProcessor(blockMan)
|
chainMan.SetProcessor(blockMan)
|
||||||
|
|
||||||
const max = 2
|
const max = 2
|
||||||
|
|
@ -73,5 +75,56 @@ func TestChainInsertions(t *testing.T) {
|
||||||
for i := 0; i < max; i++ {
|
for i := 0; i < max; i++ {
|
||||||
<-done
|
<-done
|
||||||
}
|
}
|
||||||
fmt.Println(chainMan.CurrentBlock())
|
|
||||||
|
if bytes.Equal(chain2[len(chain2)-1].Hash(), chainMan.CurrentBlock().Hash()) {
|
||||||
|
t.Error("chain2 is canonical and shouldn't be")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(chain1[len(chain1)-1].Hash(), chainMan.CurrentBlock().Hash()) {
|
||||||
|
t.Error("chain1 isn't canonical and should be")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChainMultipleInsertions(t *testing.T) {
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
|
||||||
|
const max = 4
|
||||||
|
chains := make([]types.Blocks, max)
|
||||||
|
var longest int
|
||||||
|
for i := 0; i < max; i++ {
|
||||||
|
var err error
|
||||||
|
name := "valid" + strconv.Itoa(i+1)
|
||||||
|
chains[i], err = loadChain(name, t)
|
||||||
|
if len(chains[i]) >= len(chains[longest]) {
|
||||||
|
longest = i
|
||||||
|
}
|
||||||
|
fmt.Println("loaded", name, "with a length of", len(chains[i]))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var eventMux event.TypeMux
|
||||||
|
chainMan := NewChainManager(db, &eventMux)
|
||||||
|
txPool := NewTxPool(&eventMux)
|
||||||
|
blockMan := NewBlockProcessor(db, txPool, chainMan, &eventMux)
|
||||||
|
chainMan.SetProcessor(blockMan)
|
||||||
|
done := make(chan bool, max)
|
||||||
|
for i, chain := range chains {
|
||||||
|
// XXX the go routine would otherwise reference the same (chain[3]) variable and fail
|
||||||
|
i := i
|
||||||
|
chain := chain
|
||||||
|
go func() {
|
||||||
|
insertChain(done, chainMan, chain, t)
|
||||||
|
fmt.Println(i, "done")
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < max; i++ {
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(chains[longest][len(chains[longest])-1].Hash(), chainMan.CurrentBlock().Hash()) {
|
||||||
|
t.Error("Invalid canonical chain")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,42 +3,41 @@ package core
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
"github.com/ethereum/go-ethereum/vm"
|
"github.com/ethereum/go-ethereum/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Execution struct {
|
type Execution struct {
|
||||||
vm vm.VirtualMachine
|
env vm.Environment
|
||||||
address, input []byte
|
address, input []byte
|
||||||
Gas, price, value *big.Int
|
Gas, price, value *big.Int
|
||||||
object *state.StateObject
|
|
||||||
SkipTransfer bool
|
SkipTransfer bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExecution(env vm.Environment, address, input []byte, gas, gasPrice, value *big.Int) *Execution {
|
func NewExecution(env vm.Environment, address, input []byte, gas, gasPrice, value *big.Int) *Execution {
|
||||||
evm := vm.New(env, vm.DebugVmTy)
|
return &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value}
|
||||||
|
|
||||||
return &Execution{vm: evm, address: address, input: input, Gas: gas, price: gasPrice, value: value}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Execution) Addr() []byte {
|
func (self *Execution) Addr() []byte {
|
||||||
return self.address
|
return self.address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Execution) Call(codeAddr []byte, caller vm.ClosureRef) ([]byte, error) {
|
func (self *Execution) Call(codeAddr []byte, caller vm.ContextRef) ([]byte, error) {
|
||||||
// Retrieve the executing code
|
// Retrieve the executing code
|
||||||
code := self.vm.Env().State().GetCode(codeAddr)
|
code := self.env.State().GetCode(codeAddr)
|
||||||
|
|
||||||
return self.exec(code, codeAddr, caller)
|
return self.exec(code, codeAddr, caller)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Execution) exec(code, contextAddr []byte, caller vm.ClosureRef) (ret []byte, err error) {
|
func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret []byte, err error) {
|
||||||
env := self.vm.Env()
|
env := self.env
|
||||||
chainlogger.Debugf("pre state %x\n", env.State().Root())
|
evm := vm.New(env, vm.DebugVmTy)
|
||||||
|
|
||||||
|
if env.Depth() == vm.MaxCallDepth {
|
||||||
|
caller.ReturnGas(self.Gas, self.price)
|
||||||
|
|
||||||
if self.vm.Env().Depth() == vm.MaxCallDepth {
|
|
||||||
// Consume all gas (by not returning it) and return a depth error
|
|
||||||
return nil, vm.DepthError{}
|
return nil, vm.DepthError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,22 +54,19 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ClosureRef) (ret
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot := env.State().Copy()
|
snapshot := env.State().Copy()
|
||||||
defer func() {
|
start := time.Now()
|
||||||
if /*vm.IsDepthErr(err) ||*/ vm.IsOOGErr(err) {
|
ret, err = evm.Run(to, caller, code, self.value, self.Gas, self.price, self.input)
|
||||||
env.State().Set(snapshot)
|
if err != nil {
|
||||||
}
|
env.State().Set(snapshot)
|
||||||
chainlogger.Debugf("post state %x\n", env.State().Root())
|
}
|
||||||
}()
|
chainlogger.Debugf("vm took %v\n", time.Since(start))
|
||||||
|
|
||||||
self.object = to
|
|
||||||
ret, err = self.vm.Run(to, caller, code, self.value, self.Gas, self.price, self.input)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Execution) Create(caller vm.ClosureRef) (ret []byte, err error, account *state.StateObject) {
|
func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, account *state.StateObject) {
|
||||||
ret, err = self.exec(self.input, nil, caller)
|
ret, err = self.exec(self.input, nil, caller)
|
||||||
account = self.vm.Env().State().GetStateObject(self.address)
|
account = self.env.State().GetStateObject(self.address)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,13 +76,14 @@ func (self *Filter) SetSkip(skip int) {
|
||||||
|
|
||||||
// Run filters messages with the current parameters set
|
// Run filters messages with the current parameters set
|
||||||
func (self *Filter) Find() []*state.Message {
|
func (self *Filter) Find() []*state.Message {
|
||||||
|
earliestBlock := self.eth.ChainManager().CurrentBlock()
|
||||||
var earliestBlockNo uint64 = uint64(self.earliest)
|
var earliestBlockNo uint64 = uint64(self.earliest)
|
||||||
if self.earliest == -1 {
|
if self.earliest == -1 {
|
||||||
earliestBlockNo = self.eth.ChainManager().CurrentBlock().Number.Uint64()
|
earliestBlockNo = earliestBlock.NumberU64()
|
||||||
}
|
}
|
||||||
var latestBlockNo uint64 = uint64(self.latest)
|
var latestBlockNo uint64 = uint64(self.latest)
|
||||||
if self.latest == -1 {
|
if self.latest == -1 {
|
||||||
latestBlockNo = self.eth.ChainManager().CurrentBlock().Number.Uint64()
|
latestBlockNo = earliestBlock.NumberU64()
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -93,7 +94,7 @@ func (self *Filter) Find() []*state.Message {
|
||||||
for i := 0; !quit && block != nil; i++ {
|
for i := 0; !quit && block != nil; i++ {
|
||||||
// Quit on latest
|
// Quit on latest
|
||||||
switch {
|
switch {
|
||||||
case block.Number.Uint64() == earliestBlockNo, block.Number.Uint64() == 0:
|
case block.NumberU64() == earliestBlockNo, block.NumberU64() == 0:
|
||||||
quit = true
|
quit = true
|
||||||
case self.max <= len(messages):
|
case self.max <= len(messages):
|
||||||
break
|
break
|
||||||
|
|
@ -103,7 +104,7 @@ func (self *Filter) Find() []*state.Message {
|
||||||
// current parameters
|
// current parameters
|
||||||
if self.bloomFilter(block) {
|
if self.bloomFilter(block) {
|
||||||
// Get the messages of the block
|
// Get the messages of the block
|
||||||
msgs, err := self.eth.BlockManager().GetMessages(block)
|
msgs, err := self.eth.BlockProcessor().GetMessages(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
chainlogger.Warnln("err: filter get messages ", err)
|
chainlogger.Warnln("err: filter get messages ", err)
|
||||||
|
|
||||||
|
|
@ -113,7 +114,7 @@ func (self *Filter) Find() []*state.Message {
|
||||||
messages = append(messages, self.FilterMessages(msgs)...)
|
messages = append(messages, self.FilterMessages(msgs)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
block = self.eth.ChainManager().GetBlock(block.PrevHash)
|
block = self.eth.ChainManager().GetBlock(block.ParentHash())
|
||||||
}
|
}
|
||||||
|
|
||||||
skip := int(math.Min(float64(len(messages)), float64(self.skip)))
|
skip := int(math.Min(float64(len(messages)), float64(self.skip)))
|
||||||
|
|
@ -176,7 +177,7 @@ func (self *Filter) bloomFilter(block *types.Block) bool {
|
||||||
var fromIncluded, toIncluded bool
|
var fromIncluded, toIncluded bool
|
||||||
if len(self.from) > 0 {
|
if len(self.from) > 0 {
|
||||||
for _, from := range self.from {
|
for _, from := range self.from {
|
||||||
if types.BloomLookup(block.LogsBloom, from) || bytes.Equal(block.Coinbase, from) {
|
if types.BloomLookup(block.Bloom(), from) || bytes.Equal(block.Coinbase(), from) {
|
||||||
fromIncluded = true
|
fromIncluded = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +188,7 @@ func (self *Filter) bloomFilter(block *types.Block) bool {
|
||||||
|
|
||||||
if len(self.to) > 0 {
|
if len(self.to) > 0 {
|
||||||
for _, to := range self.to {
|
for _, to := range self.to {
|
||||||
if types.BloomLookup(block.LogsBloom, ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) || bytes.Equal(block.Coinbase, to) {
|
if types.BloomLookup(block.Bloom(), ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) || bytes.Equal(block.Coinbase(), to) {
|
||||||
toIncluded = true
|
toIncluded = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@ package core
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
|
"github.com/ethereum/go-ethereum/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -17,36 +19,37 @@ var ZeroHash512 = make([]byte, 64)
|
||||||
var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{}))
|
var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{}))
|
||||||
var EmptyListRoot = crypto.Sha3(ethutil.Encode(""))
|
var EmptyListRoot = crypto.Sha3(ethutil.Encode(""))
|
||||||
|
|
||||||
var GenesisHeader = []interface{}{
|
func GenesisBlock(db ethutil.Database) *types.Block {
|
||||||
// Previous hash (none)
|
genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, big.NewInt(131072), crypto.Sha3(big.NewInt(42).Bytes()), "")
|
||||||
ZeroHash256,
|
genesis.Header().Number = ethutil.Big0
|
||||||
// Empty uncles
|
genesis.Header().GasLimit = big.NewInt(1000000)
|
||||||
EmptyShaList,
|
genesis.Header().GasUsed = ethutil.Big0
|
||||||
// Coinbase
|
genesis.Header().Time = 0
|
||||||
ZeroHash160,
|
genesis.Td = ethutil.Big0
|
||||||
// Root state
|
|
||||||
EmptyShaList,
|
|
||||||
// tx root
|
|
||||||
EmptyListRoot,
|
|
||||||
// receipt root
|
|
||||||
EmptyListRoot,
|
|
||||||
// bloom
|
|
||||||
ZeroHash512,
|
|
||||||
// Difficulty
|
|
||||||
//ethutil.BigPow(2, 22),
|
|
||||||
big.NewInt(131072),
|
|
||||||
// Number
|
|
||||||
ethutil.Big0,
|
|
||||||
// Block upper gas bound
|
|
||||||
big.NewInt(1000000),
|
|
||||||
// Block gas used
|
|
||||||
ethutil.Big0,
|
|
||||||
// Time
|
|
||||||
ethutil.Big0,
|
|
||||||
// Extra
|
|
||||||
nil,
|
|
||||||
// Nonce
|
|
||||||
crypto.Sha3(big.NewInt(42).Bytes()),
|
|
||||||
}
|
|
||||||
|
|
||||||
var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}}
|
genesis.SetUncles([]*types.Header{})
|
||||||
|
genesis.SetTransactions(types.Transactions{})
|
||||||
|
genesis.SetReceipts(types.Receipts{})
|
||||||
|
|
||||||
|
statedb := state.New(genesis.Root(), db)
|
||||||
|
//statedb := state.New(genesis.Trie())
|
||||||
|
for _, addr := range []string{
|
||||||
|
"51ba59315b3a95761d0863b05ccc7a7f54703d99",
|
||||||
|
"e4157b34ea9615cfbde6b4fda419828124b70c78",
|
||||||
|
"b9c015918bdaba24b4ff057a92a3873d6eb201be",
|
||||||
|
"6c386a4b26f73c802f34673f7248bb118f97424a",
|
||||||
|
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826",
|
||||||
|
"2ef47100e0787b915105fd5e3f4ff6752079d5cb",
|
||||||
|
"e6716f9544a56c530d868e4bfbacb172315bdead",
|
||||||
|
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4",
|
||||||
|
} {
|
||||||
|
codedAddr := ethutil.Hex2Bytes(addr)
|
||||||
|
account := statedb.GetAccount(codedAddr)
|
||||||
|
account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200)
|
||||||
|
statedb.UpdateStateObject(account)
|
||||||
|
}
|
||||||
|
statedb.Sync()
|
||||||
|
genesis.Header().Root = statedb.Root()
|
||||||
|
|
||||||
|
return genesis
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"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/wire"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Implement our EthTest Manager
|
// Implement our EthTest Manager
|
||||||
|
|
@ -54,11 +54,11 @@ func (tm *TestManager) TxPool() *TxPool {
|
||||||
func (tm *TestManager) EventMux() *event.TypeMux {
|
func (tm *TestManager) EventMux() *event.TypeMux {
|
||||||
return tm.eventMux
|
return tm.eventMux
|
||||||
}
|
}
|
||||||
func (tm *TestManager) Broadcast(msgType wire.MsgType, data []interface{}) {
|
func (tm *TestManager) Broadcast(msgType p2p.Msg, data []interface{}) {
|
||||||
fmt.Println("Broadcast not implemented")
|
fmt.Println("Broadcast not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *TestManager) ClientIdentity() wire.ClientIdentity {
|
func (tm *TestManager) ClientIdentity() p2p.ClientIdentity {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (tm *TestManager) KeyManager() *crypto.KeyManager {
|
func (tm *TestManager) KeyManager() *crypto.KeyManager {
|
||||||
|
|
@ -77,7 +77,6 @@ func NewTestManager() *TestManager {
|
||||||
fmt.Println("Could not create mem-db, failing")
|
fmt.Println("Could not create mem-db, failing")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ethutil.Config.Db = db
|
|
||||||
|
|
||||||
testManager := &TestManager{}
|
testManager := &TestManager{}
|
||||||
testManager.eventMux = new(event.TypeMux)
|
testManager.eventMux = new(event.TypeMux)
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/state"
|
||||||
|
|
@ -28,18 +27,17 @@ import (
|
||||||
* 6) Derive new state root
|
* 6) Derive new state root
|
||||||
*/
|
*/
|
||||||
type StateTransition struct {
|
type StateTransition struct {
|
||||||
coinbase, receiver []byte
|
coinbase []byte
|
||||||
msg Message
|
msg Message
|
||||||
gas, gasPrice *big.Int
|
gas, gasPrice *big.Int
|
||||||
initialGas *big.Int
|
initialGas *big.Int
|
||||||
value *big.Int
|
value *big.Int
|
||||||
data []byte
|
data []byte
|
||||||
state *state.StateDB
|
state *state.StateDB
|
||||||
block *types.Block
|
|
||||||
|
|
||||||
cb, rec, sen *state.StateObject
|
cb, rec, sen *state.StateObject
|
||||||
|
|
||||||
Env vm.Environment
|
env vm.Environment
|
||||||
}
|
}
|
||||||
|
|
||||||
type Message interface {
|
type Message interface {
|
||||||
|
|
@ -69,16 +67,19 @@ func MessageGasValue(msg Message) *big.Int {
|
||||||
return new(big.Int).Mul(msg.Gas(), msg.GasPrice())
|
return new(big.Int).Mul(msg.Gas(), msg.GasPrice())
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateTransition(coinbase *state.StateObject, msg Message, state *state.StateDB, block *types.Block) *StateTransition {
|
func NewStateTransition(env vm.Environment, msg Message, coinbase *state.StateObject) *StateTransition {
|
||||||
return &StateTransition{coinbase.Address(), msg.To(), msg, new(big.Int), new(big.Int).Set(msg.GasPrice()), new(big.Int), msg.Value(), msg.Data(), state, block, coinbase, nil, nil, nil}
|
return &StateTransition{
|
||||||
}
|
coinbase: coinbase.Address(),
|
||||||
|
env: env,
|
||||||
func (self *StateTransition) VmEnv() vm.Environment {
|
msg: msg,
|
||||||
if self.Env == nil {
|
gas: new(big.Int),
|
||||||
self.Env = NewEnv(self.state, self.msg, self.block)
|
gasPrice: new(big.Int).Set(msg.GasPrice()),
|
||||||
|
initialGas: new(big.Int),
|
||||||
|
value: msg.Value(),
|
||||||
|
data: msg.Data(),
|
||||||
|
state: env.State(),
|
||||||
|
cb: coinbase,
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.Env
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) Coinbase() *state.StateObject {
|
func (self *StateTransition) Coinbase() *state.StateObject {
|
||||||
|
|
@ -112,7 +113,7 @@ func (self *StateTransition) BuyGas() error {
|
||||||
|
|
||||||
sender := self.From()
|
sender := self.From()
|
||||||
if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 {
|
if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 {
|
||||||
return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", MessageGasValue(self.msg), sender.Balance())
|
return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address()[:4], MessageGasValue(self.msg), sender.Balance())
|
||||||
}
|
}
|
||||||
|
|
||||||
coinbase := self.Coinbase()
|
coinbase := self.Coinbase()
|
||||||
|
|
@ -183,18 +184,25 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
vmenv := self.VmEnv()
|
vmenv := self.env
|
||||||
var ref vm.ClosureRef
|
var ref vm.ContextRef
|
||||||
if MessageCreatesContract(msg) {
|
if MessageCreatesContract(msg) {
|
||||||
self.rec = MakeContract(msg, self.state)
|
contract := MakeContract(msg, self.state)
|
||||||
|
ret, err, ref = vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
|
||||||
ret, err, ref = vmenv.Create(sender, self.rec.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
|
if err == nil {
|
||||||
ref.SetCode(ret)
|
dataGas := big.NewInt(int64(len(ret)))
|
||||||
|
dataGas.Mul(dataGas, vm.GasCreateByte)
|
||||||
|
if err = self.UseGas(dataGas); err == nil {
|
||||||
|
//self.state.SetCode(ref.Address(), ret)
|
||||||
|
ref.SetCode(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ret, err = vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
|
ret, err = vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statelogger.Debugln(err)
|
self.UseGas(self.gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
@ -211,20 +219,19 @@ func MakeContract(msg Message, state *state.StateDB) *state.StateObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) RefundGas() {
|
func (self *StateTransition) RefundGas() {
|
||||||
coinbaseSub := new(big.Int).Set(self.gas)
|
|
||||||
uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2)
|
|
||||||
for addr, ref := range self.state.Refunds() {
|
|
||||||
refund := ethutil.BigMin(uhalf, ref)
|
|
||||||
coinbaseSub.Add(self.gas, refund)
|
|
||||||
self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice()))
|
|
||||||
}
|
|
||||||
|
|
||||||
coinbase, sender := self.Coinbase(), self.From()
|
coinbase, sender := self.Coinbase(), self.From()
|
||||||
coinbase.RefundGas(coinbaseSub, self.msg.GasPrice())
|
|
||||||
|
|
||||||
// Return remaining gas
|
// Return remaining gas
|
||||||
remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice())
|
remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice())
|
||||||
sender.AddAmount(remaining)
|
sender.AddAmount(remaining)
|
||||||
|
|
||||||
|
uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2)
|
||||||
|
for addr, ref := range self.state.Refunds() {
|
||||||
|
refund := ethutil.BigMin(uhalf, ref)
|
||||||
|
self.gas.Add(self.gas, refund)
|
||||||
|
self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice()))
|
||||||
|
}
|
||||||
|
|
||||||
|
coinbase.RefundGas(self.gas, self.msg.GasPrice())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) GasUsed() *big.Int {
|
func (self *StateTransition) GasUsed() *big.Int {
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,12 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"container/list"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"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/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var txplogger = logger.NewLogger("TXP")
|
var txplogger = logger.NewLogger("TXP")
|
||||||
|
|
@ -26,101 +22,59 @@ const (
|
||||||
minGasPrice = 1000000
|
minGasPrice = 1000000
|
||||||
)
|
)
|
||||||
|
|
||||||
var MinGasPrice = big.NewInt(10000000000000)
|
|
||||||
|
|
||||||
func EachTx(pool *list.List, it func(*types.Transaction, *list.Element) bool) {
|
|
||||||
for e := pool.Front(); e != nil; e = e.Next() {
|
|
||||||
if it(e.Value.(*types.Transaction), e) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FindTx(pool *list.List, finder func(*types.Transaction, *list.Element) bool) *types.Transaction {
|
|
||||||
for e := pool.Front(); e != nil; e = e.Next() {
|
|
||||||
if tx, ok := e.Value.(*types.Transaction); ok {
|
|
||||||
if finder(tx, e) {
|
|
||||||
return tx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type TxProcessor interface {
|
type TxProcessor interface {
|
||||||
ProcessTransaction(tx *types.Transaction)
|
ProcessTransaction(tx *types.Transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The tx pool a thread safe transaction pool handler. In order to
|
// The tx pool a thread safe transaction pool handler. In order to
|
||||||
// guarantee a non blocking pool we use a queue channel which can be
|
// guarantee a non blocking pool we use a queue channel which can be
|
||||||
// independently read without needing access to the actual pool. If the
|
// independently read without needing access to the actual pool.
|
||||||
// pool is being drained or synced for whatever reason the transactions
|
|
||||||
// will simple queue up and handled when the mutex is freed.
|
|
||||||
type TxPool struct {
|
type TxPool struct {
|
||||||
// The mutex for accessing the Tx pool.
|
|
||||||
mutex sync.Mutex
|
|
||||||
// Queueing channel for reading and writing incoming
|
// Queueing channel for reading and writing incoming
|
||||||
// transactions to
|
// transactions to
|
||||||
queueChan chan *types.Transaction
|
queueChan chan *types.Transaction
|
||||||
// Quiting channel
|
// Quiting channel
|
||||||
quit chan bool
|
quit chan bool
|
||||||
// The actual pool
|
// The actual pool
|
||||||
pool *list.List
|
//pool *list.List
|
||||||
|
txs map[string]*types.Transaction
|
||||||
|
|
||||||
SecondaryProcessor TxProcessor
|
SecondaryProcessor TxProcessor
|
||||||
|
|
||||||
subscribers []chan TxMsg
|
subscribers []chan TxMsg
|
||||||
|
|
||||||
chainManager *ChainManager
|
eventMux *event.TypeMux
|
||||||
eventMux *event.TypeMux
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTxPool(chainManager *ChainManager, eventMux *event.TypeMux) *TxPool {
|
func NewTxPool(eventMux *event.TypeMux) *TxPool {
|
||||||
return &TxPool{
|
return &TxPool{
|
||||||
pool: list.New(),
|
txs: make(map[string]*types.Transaction),
|
||||||
queueChan: make(chan *types.Transaction, txPoolQueueSize),
|
queueChan: make(chan *types.Transaction, txPoolQueueSize),
|
||||||
quit: make(chan bool),
|
quit: make(chan bool),
|
||||||
chainManager: chainManager,
|
eventMux: eventMux,
|
||||||
eventMux: eventMux,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocking function. Don't use directly. Use QueueTransaction instead
|
|
||||||
func (pool *TxPool) addTransaction(tx *types.Transaction) {
|
|
||||||
pool.mutex.Lock()
|
|
||||||
defer pool.mutex.Unlock()
|
|
||||||
|
|
||||||
pool.pool.PushBack(tx)
|
|
||||||
|
|
||||||
// Broadcast the transaction to the rest of the peers
|
|
||||||
pool.eventMux.Post(TxPreEvent{tx})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
|
func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
|
||||||
// Get the last block so we can retrieve the sender and receiver from
|
|
||||||
// the merkle trie
|
|
||||||
block := pool.chainManager.CurrentBlock
|
|
||||||
// Something has gone horribly wrong if this happens
|
|
||||||
if block == nil {
|
|
||||||
return fmt.Errorf("No last block on the block chain")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(tx.To()) != 0 && len(tx.To()) != 20 {
|
if len(tx.To()) != 0 && len(tx.To()) != 20 {
|
||||||
return fmt.Errorf("Invalid recipient. len = %d", len(tx.To()))
|
return fmt.Errorf("Invalid recipient. len = %d", len(tx.To()))
|
||||||
}
|
}
|
||||||
|
|
||||||
v, _, _ := tx.Curve()
|
v, _, _ := tx.Curve()
|
||||||
if v > 28 || v < 27 {
|
if v > 28 || v < 27 {
|
||||||
return fmt.Errorf("tx.v != (28 || 27)")
|
return fmt.Errorf("tx.v != (28 || 27) => %v", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX this kind of validation needs to happen elsewhere in the gui when sending txs.
|
||||||
|
Other clients should do their own validation. Value transfer could throw error
|
||||||
|
but doesn't necessarily invalidate the tx. Gas can still be payed for and miner
|
||||||
|
can still be rewarded for their inclusion and processing.
|
||||||
// Get the sender
|
// Get the sender
|
||||||
senderAddr := tx.From()
|
senderAddr := tx.From()
|
||||||
if senderAddr == nil {
|
if senderAddr == nil {
|
||||||
return fmt.Errorf("invalid sender")
|
return fmt.Errorf("invalid sender")
|
||||||
}
|
}
|
||||||
sender := pool.chainManager.State().GetAccount(senderAddr)
|
sender := pool.stateQuery.GetAccount(senderAddr)
|
||||||
|
|
||||||
totAmount := new(big.Int).Set(tx.Value())
|
totAmount := new(big.Int).Set(tx.Value())
|
||||||
// Make sure there's enough in the sender's account. Having insufficient
|
// Make sure there's enough in the sender's account. Having insufficient
|
||||||
|
|
@ -128,21 +82,18 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
|
||||||
if sender.Balance().Cmp(totAmount) < 0 {
|
if sender.Balance().Cmp(totAmount) < 0 {
|
||||||
return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.From())
|
return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.From())
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// Increment the nonce making each tx valid only once to prevent replay
|
|
||||||
// attacks
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TxPool) Add(tx *types.Transaction) error {
|
func (self *TxPool) addTx(tx *types.Transaction) {
|
||||||
hash := tx.Hash()
|
self.txs[string(tx.Hash())] = tx
|
||||||
foundTx := FindTx(self.pool, func(tx *types.Transaction, e *list.Element) bool {
|
}
|
||||||
return bytes.Compare(tx.Hash(), hash) == 0
|
|
||||||
})
|
|
||||||
|
|
||||||
if foundTx != nil {
|
func (self *TxPool) Add(tx *types.Transaction) error {
|
||||||
return fmt.Errorf("Known transaction (%x)", hash[0:4])
|
if self.txs[string(tx.Hash())] != nil {
|
||||||
|
return fmt.Errorf("Known transaction (%x)", tx.Hash()[0:4])
|
||||||
}
|
}
|
||||||
|
|
||||||
err := self.ValidateTransaction(tx)
|
err := self.ValidateTransaction(tx)
|
||||||
|
|
@ -150,9 +101,16 @@ func (self *TxPool) Add(tx *types.Transaction) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addTransaction(tx)
|
self.addTx(tx)
|
||||||
|
|
||||||
txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.From()[:4], tx.To()[:4], tx.Value, tx.Hash())
|
var to string
|
||||||
|
if len(tx.To()) > 0 {
|
||||||
|
to = ethutil.Bytes2Hex(tx.To()[:4])
|
||||||
|
} else {
|
||||||
|
to = "[NEW_CONTRACT]"
|
||||||
|
}
|
||||||
|
|
||||||
|
txplogger.Debugf("(t) %x => %s (%v) %x\n", tx.From()[:4], to, tx.Value, tx.Hash())
|
||||||
|
|
||||||
// Notify the subscribers
|
// Notify the subscribers
|
||||||
go self.eventMux.Post(TxPreEvent{tx})
|
go self.eventMux.Post(TxPreEvent{tx})
|
||||||
|
|
@ -161,7 +119,7 @@ func (self *TxPool) Add(tx *types.Transaction) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TxPool) Size() int {
|
func (self *TxPool) Size() int {
|
||||||
return self.pool.Len()
|
return len(self.txs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TxPool) AddTransactions(txs []*types.Transaction) {
|
func (self *TxPool) AddTransactions(txs []*types.Transaction) {
|
||||||
|
|
@ -174,64 +132,45 @@ func (self *TxPool) AddTransactions(txs []*types.Transaction) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *TxPool) GetTransactions() []*types.Transaction {
|
func (self *TxPool) GetTransactions() (txs types.Transactions) {
|
||||||
pool.mutex.Lock()
|
txs = make(types.Transactions, self.Size())
|
||||||
defer pool.mutex.Unlock()
|
|
||||||
|
|
||||||
txList := make([]*types.Transaction, pool.pool.Len())
|
|
||||||
i := 0
|
i := 0
|
||||||
for e := pool.pool.Front(); e != nil; e = e.Next() {
|
for _, tx := range self.txs {
|
||||||
tx := e.Value.(*types.Transaction)
|
txs[i] = tx
|
||||||
|
|
||||||
txList[i] = tx
|
|
||||||
|
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
return txList
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *TxPool) RemoveInvalid(state *state.StateDB) {
|
func (pool *TxPool) RemoveInvalid(query StateQuery) {
|
||||||
pool.mutex.Lock()
|
var removedTxs types.Transactions
|
||||||
defer pool.mutex.Unlock()
|
for _, tx := range pool.txs {
|
||||||
|
sender := query.GetAccount(tx.From())
|
||||||
for e := pool.pool.Front(); e != nil; e = e.Next() {
|
|
||||||
tx := e.Value.(*types.Transaction)
|
|
||||||
sender := state.GetAccount(tx.From())
|
|
||||||
err := pool.ValidateTransaction(tx)
|
err := pool.ValidateTransaction(tx)
|
||||||
|
fmt.Println(err, sender.Nonce, tx.Nonce())
|
||||||
if err != nil || sender.Nonce >= tx.Nonce() {
|
if err != nil || sender.Nonce >= tx.Nonce() {
|
||||||
pool.pool.Remove(e)
|
removedTxs = append(removedTxs, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pool.RemoveSet(removedTxs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TxPool) RemoveSet(txs types.Transactions) {
|
func (self *TxPool) RemoveSet(txs types.Transactions) {
|
||||||
self.mutex.Lock()
|
|
||||||
defer self.mutex.Unlock()
|
|
||||||
|
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
EachTx(self.pool, func(t *types.Transaction, element *list.Element) bool {
|
delete(self.txs, string(tx.Hash()))
|
||||||
if t == tx {
|
|
||||||
self.pool.Remove(element)
|
|
||||||
return true // To stop the loop
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *TxPool) Flush() []*types.Transaction {
|
func (pool *TxPool) Flush() []*types.Transaction {
|
||||||
txList := pool.GetTransactions()
|
txList := pool.GetTransactions()
|
||||||
|
pool.txs = make(map[string]*types.Transaction)
|
||||||
// Recreate a new list all together
|
|
||||||
// XXX Is this the fastest way?
|
|
||||||
pool.pool = list.New()
|
|
||||||
|
|
||||||
return txList
|
return txList
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *TxPool) Start() {
|
func (pool *TxPool) Start() {
|
||||||
//go pool.queueHandler()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *TxPool) Stop() {
|
func (pool *TxPool) Stop() {
|
||||||
|
|
|
||||||
87
core/transaction_pool_test.go
Normal file
87
core/transaction_pool_test.go
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/state"
|
||||||
|
)
|
||||||
|
|
||||||
|
// State query interface
|
||||||
|
type stateQuery struct{ db ethutil.Database }
|
||||||
|
|
||||||
|
func SQ() stateQuery {
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
return stateQuery{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self stateQuery) GetAccount(addr []byte) *state.StateObject {
|
||||||
|
return state.NewStateObject(addr, self.db)
|
||||||
|
}
|
||||||
|
|
||||||
|
func transaction() *types.Transaction {
|
||||||
|
return types.NewTransactionMessage(make([]byte, 20), ethutil.Big0, ethutil.Big0, ethutil.Big0, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() (*TxPool, *ecdsa.PrivateKey) {
|
||||||
|
var m event.TypeMux
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
return NewTxPool(&m), key
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTxAdding(t *testing.T) {
|
||||||
|
pool, key := setup()
|
||||||
|
tx1 := transaction()
|
||||||
|
tx1.SignECDSA(key)
|
||||||
|
err := pool.Add(tx1)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pool.Add(tx1)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("added tx twice")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddInvalidTx(t *testing.T) {
|
||||||
|
pool, _ := setup()
|
||||||
|
tx1 := transaction()
|
||||||
|
err := pool.Add(tx1)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveSet(t *testing.T) {
|
||||||
|
pool, _ := setup()
|
||||||
|
tx1 := transaction()
|
||||||
|
pool.addTx(tx1)
|
||||||
|
pool.RemoveSet(types.Transactions{tx1})
|
||||||
|
if pool.Size() > 0 {
|
||||||
|
t.Error("expected pool size to be 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveInvalid(t *testing.T) {
|
||||||
|
pool, key := setup()
|
||||||
|
tx1 := transaction()
|
||||||
|
pool.addTx(tx1)
|
||||||
|
pool.RemoveInvalid(SQ())
|
||||||
|
if pool.Size() > 0 {
|
||||||
|
t.Error("expected pool size to be 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
tx1.SetNonce(1)
|
||||||
|
tx1.SignECDSA(key)
|
||||||
|
pool.addTx(tx1)
|
||||||
|
pool.RemoveInvalid(SQ())
|
||||||
|
if pool.Size() != 1 {
|
||||||
|
t.Error("expected pool size to be 1, is", pool.Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,41 +9,233 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/state"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type BlockInfo struct {
|
type Header struct {
|
||||||
Number uint64
|
// Hash to the previous block
|
||||||
Hash []byte
|
ParentHash ethutil.Bytes
|
||||||
Parent []byte
|
// Uncles of this block
|
||||||
TD *big.Int
|
UncleHash []byte
|
||||||
|
// The coin base address
|
||||||
|
Coinbase []byte
|
||||||
|
// Block Trie state
|
||||||
|
Root []byte
|
||||||
|
// Tx sha
|
||||||
|
TxHash []byte
|
||||||
|
// Receipt sha
|
||||||
|
ReceiptHash []byte
|
||||||
|
// Bloom
|
||||||
|
Bloom []byte
|
||||||
|
// Difficulty for the current block
|
||||||
|
Difficulty *big.Int
|
||||||
|
// The block number
|
||||||
|
Number *big.Int
|
||||||
|
// Gas limit
|
||||||
|
GasLimit *big.Int
|
||||||
|
// Gas used
|
||||||
|
GasUsed *big.Int
|
||||||
|
// Creation time
|
||||||
|
Time uint64
|
||||||
|
// Extra data
|
||||||
|
Extra string
|
||||||
|
// Block Nonce for verification
|
||||||
|
Nonce ethutil.Bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bi *BlockInfo) RlpDecode(data []byte) {
|
func (self *Header) rlpData(withNonce bool) []interface{} {
|
||||||
decoder := ethutil.NewValueFromBytes(data)
|
fields := []interface{}{self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra}
|
||||||
|
if withNonce {
|
||||||
|
fields = append(fields, self.Nonce)
|
||||||
|
}
|
||||||
|
|
||||||
bi.Number = decoder.Get(0).Uint()
|
return fields
|
||||||
bi.Hash = decoder.Get(1).Bytes()
|
|
||||||
bi.Parent = decoder.Get(2).Bytes()
|
|
||||||
bi.TD = decoder.Get(3).BigInt()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bi *BlockInfo) RlpEncode() []byte {
|
func (self *Header) RlpData() interface{} {
|
||||||
return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent, bi.TD})
|
return self.rlpData(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Header) Hash() []byte {
|
||||||
|
return crypto.Sha3(ethutil.Encode(self.rlpData(true)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Header) HashNoNonce() []byte {
|
||||||
|
return crypto.Sha3(ethutil.Encode(self.rlpData(false)))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Block struct {
|
||||||
|
// Preset Hash for mock
|
||||||
|
HeaderHash []byte
|
||||||
|
ParentHeaderHash []byte
|
||||||
|
header *Header
|
||||||
|
uncles []*Header
|
||||||
|
transactions Transactions
|
||||||
|
Td *big.Int
|
||||||
|
|
||||||
|
receipts Receipts
|
||||||
|
Reward *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.Int, nonce []byte, extra string) *Block {
|
||||||
|
header := &Header{
|
||||||
|
Root: root,
|
||||||
|
ParentHash: parentHash,
|
||||||
|
Coinbase: coinbase,
|
||||||
|
Difficulty: difficulty,
|
||||||
|
Nonce: nonce,
|
||||||
|
Time: uint64(time.Now().Unix()),
|
||||||
|
Extra: extra,
|
||||||
|
GasUsed: new(big.Int),
|
||||||
|
GasLimit: new(big.Int),
|
||||||
|
}
|
||||||
|
|
||||||
|
block := &Block{header: header, Reward: new(big.Int)}
|
||||||
|
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBlockWithHeader(header *Header) *Block {
|
||||||
|
return &Block{header: header}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) DecodeRLP(s *rlp.Stream) error {
|
||||||
|
var extblock struct {
|
||||||
|
Header *Header
|
||||||
|
Txs []*Transaction
|
||||||
|
Uncles []*Header
|
||||||
|
TD *big.Int // optional
|
||||||
|
}
|
||||||
|
if err := s.Decode(&extblock); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
self.header = extblock.Header
|
||||||
|
self.uncles = extblock.Uncles
|
||||||
|
self.transactions = extblock.Txs
|
||||||
|
self.Td = extblock.TD
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) Header() *Header {
|
||||||
|
return self.header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) Uncles() []*Header {
|
||||||
|
return self.uncles
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) SetUncles(uncleHeaders []*Header) {
|
||||||
|
self.uncles = uncleHeaders
|
||||||
|
self.header.UncleHash = crypto.Sha3(ethutil.Encode(uncleHeaders))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) Transactions() Transactions {
|
||||||
|
return self.transactions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) Transaction(hash []byte) *Transaction {
|
||||||
|
for _, transaction := range self.transactions {
|
||||||
|
if bytes.Equal(hash, transaction.Hash()) {
|
||||||
|
return transaction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) SetTransactions(transactions Transactions) {
|
||||||
|
self.transactions = transactions
|
||||||
|
self.header.TxHash = DeriveSha(transactions)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) Receipts() Receipts {
|
||||||
|
return self.receipts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) SetReceipts(receipts Receipts) {
|
||||||
|
self.receipts = receipts
|
||||||
|
self.header.ReceiptHash = DeriveSha(receipts)
|
||||||
|
self.header.Bloom = CreateBloom(receipts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) RlpData() interface{} {
|
||||||
|
return []interface{}{self.header, self.transactions, self.uncles}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) RlpDataForStorage() interface{} {
|
||||||
|
return []interface{}{self.header, self.transactions, self.uncles, self.Td /* TODO receipts */}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header accessors (add as you need them)
|
||||||
|
func (self *Block) Number() *big.Int { return self.header.Number }
|
||||||
|
func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() }
|
||||||
|
func (self *Block) Bloom() []byte { return self.header.Bloom }
|
||||||
|
func (self *Block) Coinbase() []byte { return self.header.Coinbase }
|
||||||
|
func (self *Block) Time() int64 { return int64(self.header.Time) }
|
||||||
|
func (self *Block) GasLimit() *big.Int { return self.header.GasLimit }
|
||||||
|
func (self *Block) GasUsed() *big.Int { return self.header.GasUsed }
|
||||||
|
|
||||||
|
//func (self *Block) Trie() *ptrie.Trie { return ptrie.New(self.header.Root, ethutil.Config.Db) }
|
||||||
|
//func (self *Block) State() *state.StateDB { return state.New(self.Trie()) }
|
||||||
|
func (self *Block) Root() []byte { return self.header.Root }
|
||||||
|
func (self *Block) SetRoot(root []byte) { self.header.Root = root }
|
||||||
|
func (self *Block) Size() ethutil.StorageSize { return ethutil.StorageSize(len(ethutil.Encode(self))) }
|
||||||
|
|
||||||
|
// Implement pow.Block
|
||||||
|
func (self *Block) Difficulty() *big.Int { return self.header.Difficulty }
|
||||||
|
func (self *Block) N() []byte { return self.header.Nonce }
|
||||||
|
func (self *Block) HashNoNonce() []byte { return self.header.HashNoNonce() }
|
||||||
|
|
||||||
|
func (self *Block) Hash() []byte {
|
||||||
|
if self.HeaderHash != nil {
|
||||||
|
return self.HeaderHash
|
||||||
|
} else {
|
||||||
|
return self.header.Hash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) ParentHash() []byte {
|
||||||
|
if self.ParentHeaderHash != nil {
|
||||||
|
return self.ParentHeaderHash
|
||||||
|
} else {
|
||||||
|
return self.header.ParentHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Block) String() string {
|
||||||
|
return fmt.Sprintf(`BLOCK(%x): Size: %v TD: %v {
|
||||||
|
Header:
|
||||||
|
[
|
||||||
|
%v
|
||||||
|
]
|
||||||
|
Transactions:
|
||||||
|
%v
|
||||||
|
Uncles:
|
||||||
|
%v
|
||||||
|
}
|
||||||
|
`, self.header.Hash(), self.Size(), self.Td, self.header, self.transactions, self.uncles)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Header) String() string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
ParentHash: %x
|
||||||
|
UncleHash: %x
|
||||||
|
Coinbase: %x
|
||||||
|
Root: %x
|
||||||
|
TxSha %x
|
||||||
|
ReceiptSha: %x
|
||||||
|
Bloom: %x
|
||||||
|
Difficulty: %v
|
||||||
|
Number: %v
|
||||||
|
GasLimit: %v
|
||||||
|
GasUsed: %v
|
||||||
|
Time: %v
|
||||||
|
Extra: %v
|
||||||
|
Nonce: %x
|
||||||
|
`, self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.Nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Blocks []*Block
|
type Blocks []*Block
|
||||||
|
|
||||||
func (self Blocks) AsSet() ethutil.UniqueSet {
|
|
||||||
set := make(ethutil.UniqueSet)
|
|
||||||
for _, block := range self {
|
|
||||||
set.Insert(block.Hash())
|
|
||||||
}
|
|
||||||
|
|
||||||
return set
|
|
||||||
}
|
|
||||||
|
|
||||||
type BlockBy func(b1, b2 *Block) bool
|
type BlockBy func(b1, b2 *Block) bool
|
||||||
|
|
||||||
func (self BlockBy) Sort(blocks Blocks) {
|
func (self BlockBy) Sort(blocks Blocks) {
|
||||||
|
|
@ -65,352 +257,4 @@ func (self blockSorter) Swap(i, j int) {
|
||||||
}
|
}
|
||||||
func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) }
|
func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) }
|
||||||
|
|
||||||
func Number(b1, b2 *Block) bool { return b1.Number.Cmp(b2.Number) < 0 }
|
func Number(b1, b2 *Block) bool { return b1.Header().Number.Cmp(b2.Header().Number) < 0 }
|
||||||
|
|
||||||
type Block struct {
|
|
||||||
// Hash to the previous block
|
|
||||||
PrevHash ethutil.Bytes
|
|
||||||
// Uncles of this block
|
|
||||||
Uncles Blocks
|
|
||||||
UncleSha []byte
|
|
||||||
// The coin base address
|
|
||||||
Coinbase []byte
|
|
||||||
// Block Trie state
|
|
||||||
//state *ethutil.Trie
|
|
||||||
state *state.StateDB
|
|
||||||
// Difficulty for the current block
|
|
||||||
Difficulty *big.Int
|
|
||||||
// Creation time
|
|
||||||
Time int64
|
|
||||||
// The block number
|
|
||||||
Number *big.Int
|
|
||||||
// Gas limit
|
|
||||||
GasLimit *big.Int
|
|
||||||
// Gas used
|
|
||||||
GasUsed *big.Int
|
|
||||||
// Extra data
|
|
||||||
Extra string
|
|
||||||
// Block Nonce for verification
|
|
||||||
Nonce ethutil.Bytes
|
|
||||||
// List of transactions and/or contracts
|
|
||||||
transactions Transactions
|
|
||||||
receipts Receipts
|
|
||||||
TxSha, ReceiptSha []byte
|
|
||||||
LogsBloom []byte
|
|
||||||
|
|
||||||
Reward *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBlockFromBytes(raw []byte) *Block {
|
|
||||||
block := &Block{}
|
|
||||||
block.RlpDecode(raw)
|
|
||||||
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
|
|
||||||
// New block takes a raw encoded string
|
|
||||||
func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block {
|
|
||||||
block := &Block{}
|
|
||||||
block.RlpValueDecode(rlpValue)
|
|
||||||
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateBlock(root interface{},
|
|
||||||
prevHash []byte,
|
|
||||||
base []byte,
|
|
||||||
Difficulty *big.Int,
|
|
||||||
Nonce []byte,
|
|
||||||
extra string) *Block {
|
|
||||||
|
|
||||||
block := &Block{
|
|
||||||
PrevHash: prevHash,
|
|
||||||
Coinbase: base,
|
|
||||||
Difficulty: Difficulty,
|
|
||||||
Nonce: Nonce,
|
|
||||||
Time: time.Now().Unix(),
|
|
||||||
Extra: extra,
|
|
||||||
UncleSha: nil,
|
|
||||||
GasUsed: new(big.Int),
|
|
||||||
GasLimit: new(big.Int),
|
|
||||||
}
|
|
||||||
block.SetUncles([]*Block{})
|
|
||||||
|
|
||||||
block.state = state.New(trie.New(ethutil.Config.Db, root))
|
|
||||||
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a hash of the block
|
|
||||||
func (block *Block) Hash() ethutil.Bytes {
|
|
||||||
return crypto.Sha3(ethutil.NewValue(block.header()).Encode())
|
|
||||||
//return crypto.Sha3(block.Value().Encode())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) HashNoNonce() []byte {
|
|
||||||
return crypto.Sha3(ethutil.Encode(block.miningHeader()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) State() *state.StateDB {
|
|
||||||
return block.state
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) Transactions() Transactions {
|
|
||||||
return block.transactions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) CalcGasLimit(parent *Block) *big.Int {
|
|
||||||
if block.Number.Cmp(big.NewInt(0)) == 0 {
|
|
||||||
return ethutil.BigPow(10, 6)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024
|
|
||||||
|
|
||||||
previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit)
|
|
||||||
current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed), big.NewRat(6, 5))
|
|
||||||
curInt := new(big.Int).Div(current.Num(), current.Denom())
|
|
||||||
|
|
||||||
result := new(big.Int).Add(previous, curInt)
|
|
||||||
result.Div(result, big.NewInt(1024))
|
|
||||||
|
|
||||||
min := big.NewInt(125000)
|
|
||||||
|
|
||||||
return ethutil.BigMax(min, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) BlockInfo() BlockInfo {
|
|
||||||
bi := BlockInfo{}
|
|
||||||
data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
|
|
||||||
bi.RlpDecode(data)
|
|
||||||
|
|
||||||
return bi
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Block) GetTransaction(hash []byte) *Transaction {
|
|
||||||
for _, tx := range self.transactions {
|
|
||||||
if bytes.Compare(tx.Hash(), hash) == 0 {
|
|
||||||
return tx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync the block's state and contract respectively
|
|
||||||
func (block *Block) Sync() {
|
|
||||||
block.state.Sync()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) Undo() {
|
|
||||||
// Sync the block state itself
|
|
||||||
block.state.Reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
/////// Block Encoding
|
|
||||||
func (block *Block) rlpReceipts() interface{} {
|
|
||||||
// Marshal the transactions of this block
|
|
||||||
encR := make([]interface{}, len(block.receipts))
|
|
||||||
for i, r := range block.receipts {
|
|
||||||
// Cast it to a string (safe)
|
|
||||||
encR[i] = r.RlpData()
|
|
||||||
}
|
|
||||||
|
|
||||||
return encR
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) rlpUncles() interface{} {
|
|
||||||
// Marshal the transactions of this block
|
|
||||||
uncles := make([]interface{}, len(block.Uncles))
|
|
||||||
for i, uncle := range block.Uncles {
|
|
||||||
// Cast it to a string (safe)
|
|
||||||
uncles[i] = uncle.header()
|
|
||||||
}
|
|
||||||
|
|
||||||
return uncles
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) SetUncles(uncles []*Block) {
|
|
||||||
block.Uncles = uncles
|
|
||||||
block.UncleSha = crypto.Sha3(ethutil.Encode(block.rlpUncles()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Block) SetReceipts(receipts Receipts) {
|
|
||||||
self.receipts = receipts
|
|
||||||
self.ReceiptSha = DeriveSha(receipts)
|
|
||||||
self.LogsBloom = CreateBloom(receipts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Block) SetTransactions(txs Transactions) {
|
|
||||||
self.transactions = txs
|
|
||||||
self.TxSha = DeriveSha(txs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) Value() *ethutil.Value {
|
|
||||||
return ethutil.NewValue([]interface{}{block.header(), block.transactions, block.rlpUncles()})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) RlpEncode() []byte {
|
|
||||||
// Encode a slice interface which contains the header and the list of
|
|
||||||
// transactions.
|
|
||||||
return block.Value().Encode()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) RlpDecode(data []byte) {
|
|
||||||
rlpValue := ethutil.NewValueFromBytes(data)
|
|
||||||
block.RlpValueDecode(rlpValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
|
|
||||||
block.setHeader(decoder.Get(0))
|
|
||||||
|
|
||||||
// Tx list might be empty if this is an uncle. Uncles only have their
|
|
||||||
// header set.
|
|
||||||
if decoder.Get(1).IsNil() == false { // Yes explicitness
|
|
||||||
//receipts := decoder.Get(1)
|
|
||||||
//block.receipts = make([]*Receipt, receipts.Len())
|
|
||||||
txs := decoder.Get(1)
|
|
||||||
block.transactions = make(Transactions, txs.Len())
|
|
||||||
for i := 0; i < txs.Len(); i++ {
|
|
||||||
block.transactions[i] = NewTransactionFromValue(txs.Get(i))
|
|
||||||
//receipt := NewRecieptFromValue(receipts.Get(i))
|
|
||||||
//block.transactions[i] = receipt.Tx
|
|
||||||
//block.receipts[i] = receipt
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if decoder.Get(2).IsNil() == false { // Yes explicitness
|
|
||||||
uncles := decoder.Get(2)
|
|
||||||
block.Uncles = make([]*Block, uncles.Len())
|
|
||||||
for i := 0; i < uncles.Len(); i++ {
|
|
||||||
block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Block) setHeader(header *ethutil.Value) {
|
|
||||||
self.PrevHash = header.Get(0).Bytes()
|
|
||||||
self.UncleSha = header.Get(1).Bytes()
|
|
||||||
self.Coinbase = header.Get(2).Bytes()
|
|
||||||
self.state = state.New(trie.New(ethutil.Config.Db, header.Get(3).Val))
|
|
||||||
self.TxSha = header.Get(4).Bytes()
|
|
||||||
self.ReceiptSha = header.Get(5).Bytes()
|
|
||||||
self.LogsBloom = header.Get(6).Bytes()
|
|
||||||
self.Difficulty = header.Get(7).BigInt()
|
|
||||||
self.Number = header.Get(8).BigInt()
|
|
||||||
self.GasLimit = header.Get(9).BigInt()
|
|
||||||
self.GasUsed = header.Get(10).BigInt()
|
|
||||||
self.Time = int64(header.Get(11).BigInt().Uint64())
|
|
||||||
self.Extra = header.Get(12).Str()
|
|
||||||
self.Nonce = header.Get(13).Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUncleBlockFromValue(header *ethutil.Value) *Block {
|
|
||||||
block := &Block{}
|
|
||||||
block.setHeader(header)
|
|
||||||
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) Trie() *trie.Trie {
|
|
||||||
return block.state.Trie
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) Root() interface{} {
|
|
||||||
return block.state.Root()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) Diff() *big.Int {
|
|
||||||
return block.Difficulty
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Block) Receipts() []*Receipt {
|
|
||||||
return self.receipts
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) miningHeader() []interface{} {
|
|
||||||
return []interface{}{
|
|
||||||
// Sha of the previous block
|
|
||||||
block.PrevHash,
|
|
||||||
// Sha of uncles
|
|
||||||
block.UncleSha,
|
|
||||||
// Coinbase address
|
|
||||||
block.Coinbase,
|
|
||||||
// root state
|
|
||||||
block.Root(),
|
|
||||||
// tx root
|
|
||||||
block.TxSha,
|
|
||||||
// Sha of tx
|
|
||||||
block.ReceiptSha,
|
|
||||||
// Bloom
|
|
||||||
block.LogsBloom,
|
|
||||||
// Current block Difficulty
|
|
||||||
block.Difficulty,
|
|
||||||
// The block number
|
|
||||||
block.Number,
|
|
||||||
// Block upper gas bound
|
|
||||||
block.GasLimit,
|
|
||||||
// Block gas used
|
|
||||||
block.GasUsed,
|
|
||||||
// Time the block was found?
|
|
||||||
block.Time,
|
|
||||||
// Extra data
|
|
||||||
block.Extra,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) header() []interface{} {
|
|
||||||
return append(block.miningHeader(), block.Nonce)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) String() string {
|
|
||||||
return fmt.Sprintf(`
|
|
||||||
BLOCK(%x): Size: %v
|
|
||||||
PrevHash: %x
|
|
||||||
UncleSha: %x
|
|
||||||
Coinbase: %x
|
|
||||||
Root: %x
|
|
||||||
TxSha %x
|
|
||||||
ReceiptSha: %x
|
|
||||||
Bloom: %x
|
|
||||||
Difficulty: %v
|
|
||||||
Number: %v
|
|
||||||
MaxLimit: %v
|
|
||||||
GasUsed: %v
|
|
||||||
Time: %v
|
|
||||||
Extra: %v
|
|
||||||
Nonce: %x
|
|
||||||
NumTx: %v
|
|
||||||
`,
|
|
||||||
block.Hash(),
|
|
||||||
block.Size(),
|
|
||||||
block.PrevHash,
|
|
||||||
block.UncleSha,
|
|
||||||
block.Coinbase,
|
|
||||||
block.Root(),
|
|
||||||
block.TxSha,
|
|
||||||
block.ReceiptSha,
|
|
||||||
block.LogsBloom,
|
|
||||||
block.Difficulty,
|
|
||||||
block.Number,
|
|
||||||
block.GasLimit,
|
|
||||||
block.GasUsed,
|
|
||||||
block.Time,
|
|
||||||
block.Extra,
|
|
||||||
block.Nonce,
|
|
||||||
len(block.transactions),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Block) Size() ethutil.StorageSize {
|
|
||||||
return ethutil.StorageSize(len(self.RlpEncode()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement RlpEncodable
|
|
||||||
func (self *Block) RlpData() interface{} {
|
|
||||||
return []interface{}{self.header(), self.transactions, self.rlpUncles()}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement pow.Block
|
|
||||||
func (self *Block) N() []byte { return self.Nonce }
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
@ -11,10 +12,11 @@ type DerivableList interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeriveSha(list DerivableList) []byte {
|
func DeriveSha(list DerivableList) []byte {
|
||||||
trie := trie.New(ethutil.Config.Db, "")
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
trie := trie.New(nil, db)
|
||||||
for i := 0; i < list.Len(); i++ {
|
for i := 0; i < list.Len(); i++ {
|
||||||
trie.Update(string(ethutil.NewValue(i).Encode()), string(list.GetRlp(i)))
|
trie.Update(ethutil.Encode(i), list.GetRlp(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
return trie.GetRoot()
|
return trie.Root()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/ecdsa"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/obscuren/secp256k1-go"
|
"github.com/obscuren/secp256k1-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -14,22 +17,22 @@ func IsContractAddr(addr []byte) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Transaction struct {
|
type Transaction struct {
|
||||||
nonce uint64
|
AccountNonce uint64
|
||||||
recipient []byte
|
Price *big.Int
|
||||||
value *big.Int
|
GasLimit *big.Int
|
||||||
gas *big.Int
|
Recipient []byte
|
||||||
gasPrice *big.Int
|
Amount *big.Int
|
||||||
data []byte
|
Payload []byte
|
||||||
v byte
|
V uint64
|
||||||
r, s []byte
|
R, S []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction {
|
func NewContractCreationTx(Amount, gasAmount, price *big.Int, data []byte) *Transaction {
|
||||||
return &Transaction{recipient: nil, value: value, gas: gas, gasPrice: gasPrice, data: script}
|
return NewTransactionMessage(nil, Amount, gasAmount, price, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction {
|
func NewTransactionMessage(to []byte, Amount, gasAmount, price *big.Int, data []byte) *Transaction {
|
||||||
return &Transaction{recipient: to, value: value, gasPrice: gasPrice, gas: gas, data: data}
|
return &Transaction{Recipient: to, Amount: Amount, Price: price, GasLimit: gasAmount, Payload: data}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransactionFromBytes(data []byte) *Transaction {
|
func NewTransactionFromBytes(data []byte) *Transaction {
|
||||||
|
|
@ -39,7 +42,7 @@ func NewTransactionFromBytes(data []byte) *Transaction {
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransactionFromValue(val *ethutil.Value) *Transaction {
|
func NewTransactionFromAmount(val *ethutil.Value) *Transaction {
|
||||||
tx := &Transaction{}
|
tx := &Transaction{}
|
||||||
tx.RlpValueDecode(val)
|
tx.RlpValueDecode(val)
|
||||||
|
|
||||||
|
|
@ -47,33 +50,33 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) Hash() []byte {
|
func (tx *Transaction) Hash() []byte {
|
||||||
data := []interface{}{tx.Nonce, tx.gasPrice, tx.gas, tx.recipient, tx.Value, tx.Data}
|
data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}
|
||||||
|
|
||||||
return crypto.Sha3(ethutil.NewValue(data).Encode())
|
return crypto.Sha3(ethutil.Encode(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Transaction) Data() []byte {
|
func (self *Transaction) Data() []byte {
|
||||||
return self.data
|
return self.Payload
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Transaction) Gas() *big.Int {
|
func (self *Transaction) Gas() *big.Int {
|
||||||
return self.gas
|
return self.GasLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Transaction) GasPrice() *big.Int {
|
func (self *Transaction) GasPrice() *big.Int {
|
||||||
return self.gasPrice
|
return self.Price
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Transaction) Value() *big.Int {
|
func (self *Transaction) Value() *big.Int {
|
||||||
return self.value
|
return self.Amount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Transaction) Nonce() uint64 {
|
func (self *Transaction) Nonce() uint64 {
|
||||||
return self.nonce
|
return self.AccountNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Transaction) SetNonce(nonce uint64) {
|
func (self *Transaction) SetNonce(AccountNonce uint64) {
|
||||||
self.nonce = nonce
|
self.AccountNonce = AccountNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Transaction) From() []byte {
|
func (self *Transaction) From() []byte {
|
||||||
|
|
@ -81,13 +84,13 @@ func (self *Transaction) From() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Transaction) To() []byte {
|
func (self *Transaction) To() []byte {
|
||||||
return self.recipient
|
return self.Recipient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) Curve() (v byte, r []byte, s []byte) {
|
func (tx *Transaction) Curve() (v byte, r []byte, s []byte) {
|
||||||
v = tx.v
|
v = byte(tx.V)
|
||||||
r = ethutil.LeftPadBytes(tx.r, 32)
|
r = ethutil.LeftPadBytes(tx.R, 32)
|
||||||
s = ethutil.LeftPadBytes(tx.s, 32)
|
s = ethutil.LeftPadBytes(tx.S, 32)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -108,8 +111,8 @@ func (tx *Transaction) PublicKey() []byte {
|
||||||
sig := append(r, s...)
|
sig := append(r, s...)
|
||||||
sig = append(sig, v-27)
|
sig = append(sig, v-27)
|
||||||
|
|
||||||
pubkey := crypto.Ecrecover(append(hash, sig...))
|
//pubkey := crypto.Ecrecover(append(hash, sig...))
|
||||||
//pubkey, _ := secp256k1.RecoverPubkey(hash, sig)
|
pubkey, _ := secp256k1.RecoverPubkey(hash, sig)
|
||||||
|
|
||||||
return pubkey
|
return pubkey
|
||||||
}
|
}
|
||||||
|
|
@ -130,44 +133,41 @@ func (tx *Transaction) Sign(privk []byte) error {
|
||||||
|
|
||||||
sig := tx.Signature(privk)
|
sig := tx.Signature(privk)
|
||||||
|
|
||||||
tx.r = sig[:32]
|
tx.R = sig[:32]
|
||||||
tx.s = sig[32:64]
|
tx.S = sig[32:64]
|
||||||
tx.v = sig[64] + 27
|
tx.V = uint64(sig[64] + 27)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) RlpData() interface{} {
|
func (tx *Transaction) SignECDSA(key *ecdsa.PrivateKey) error {
|
||||||
data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.recipient, tx.Value, tx.Data}
|
return tx.Sign(crypto.FromECDSA(key))
|
||||||
|
|
||||||
// TODO Remove prefixing zero's
|
|
||||||
|
|
||||||
return append(data, tx.v, new(big.Int).SetBytes(tx.r).Bytes(), new(big.Int).SetBytes(tx.s).Bytes())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) RlpValue() *ethutil.Value {
|
func (tx *Transaction) RlpData() interface{} {
|
||||||
return ethutil.NewValue(tx.RlpData())
|
data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}
|
||||||
|
|
||||||
|
return append(data, tx.V, new(big.Int).SetBytes(tx.R).Bytes(), new(big.Int).SetBytes(tx.S).Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) RlpEncode() []byte {
|
func (tx *Transaction) RlpEncode() []byte {
|
||||||
return tx.RlpValue().Encode()
|
return ethutil.Encode(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) RlpDecode(data []byte) {
|
func (tx *Transaction) RlpDecode(data []byte) {
|
||||||
tx.RlpValueDecode(ethutil.NewValueFromBytes(data))
|
rlp.Decode(bytes.NewReader(data), tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
|
func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
|
||||||
tx.nonce = decoder.Get(0).Uint()
|
tx.AccountNonce = decoder.Get(0).Uint()
|
||||||
tx.gasPrice = decoder.Get(1).BigInt()
|
tx.Price = decoder.Get(1).BigInt()
|
||||||
tx.gas = decoder.Get(2).BigInt()
|
tx.GasLimit = decoder.Get(2).BigInt()
|
||||||
tx.recipient = decoder.Get(3).Bytes()
|
tx.Recipient = decoder.Get(3).Bytes()
|
||||||
tx.value = decoder.Get(4).BigInt()
|
tx.Amount = decoder.Get(4).BigInt()
|
||||||
tx.data = decoder.Get(5).Bytes()
|
tx.Payload = decoder.Get(5).Bytes()
|
||||||
tx.v = byte(decoder.Get(6).Uint())
|
tx.V = decoder.Get(6).Uint()
|
||||||
|
tx.R = decoder.Get(7).Bytes()
|
||||||
tx.r = decoder.Get(7).Bytes()
|
tx.S = decoder.Get(8).Bytes()
|
||||||
tx.s = decoder.Get(8).Bytes()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) String() string {
|
func (tx *Transaction) String() string {
|
||||||
|
|
@ -178,25 +178,28 @@ func (tx *Transaction) String() string {
|
||||||
To: %x
|
To: %x
|
||||||
Nonce: %v
|
Nonce: %v
|
||||||
GasPrice: %v
|
GasPrice: %v
|
||||||
Gas: %v
|
GasLimit %v
|
||||||
Value: %v
|
Value: %v
|
||||||
Data: 0x%x
|
Data: 0x%x
|
||||||
V: 0x%x
|
V: 0x%x
|
||||||
R: 0x%x
|
R: 0x%x
|
||||||
S: 0x%x
|
S: 0x%x
|
||||||
`,
|
Hex: %x
|
||||||
|
`,
|
||||||
tx.Hash(),
|
tx.Hash(),
|
||||||
len(tx.recipient) == 0,
|
len(tx.Recipient) == 0,
|
||||||
tx.From(),
|
tx.From(),
|
||||||
tx.recipient,
|
tx.To(),
|
||||||
tx.nonce,
|
tx.AccountNonce,
|
||||||
tx.gasPrice,
|
tx.Price,
|
||||||
tx.gas,
|
tx.GasLimit,
|
||||||
tx.Value,
|
tx.Amount,
|
||||||
tx.Data,
|
tx.Payload,
|
||||||
tx.v,
|
tx.V,
|
||||||
tx.r,
|
tx.R,
|
||||||
tx.s)
|
tx.S,
|
||||||
|
ethutil.Encode(tx),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transaction slice type for basic sorting
|
// Transaction slice type for basic sorting
|
||||||
|
|
@ -219,5 +222,5 @@ func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) }
|
||||||
type TxByNonce struct{ Transactions }
|
type TxByNonce struct{ Transactions }
|
||||||
|
|
||||||
func (s TxByNonce) Less(i, j int) bool {
|
func (s TxByNonce) Less(i, j int) bool {
|
||||||
return s.Transactions[i].nonce < s.Transactions[j].nonce
|
return s.Transactions[i].AccountNonce < s.Transactions[j].AccountNonce
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,12 @@ type VMEnv struct {
|
||||||
block *types.Block
|
block *types.Block
|
||||||
msg Message
|
msg Message
|
||||||
depth int
|
depth int
|
||||||
|
chain *ChainManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv {
|
func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types.Block) *VMEnv {
|
||||||
return &VMEnv{
|
return &VMEnv{
|
||||||
|
chain: chain,
|
||||||
state: state,
|
state: state,
|
||||||
block: block,
|
block: block,
|
||||||
msg: msg,
|
msg: msg,
|
||||||
|
|
@ -24,17 +26,22 @@ func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Origin() []byte { return self.msg.From() }
|
func (self *VMEnv) Origin() []byte { return self.msg.From() }
|
||||||
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number }
|
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() }
|
||||||
func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash }
|
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() }
|
||||||
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase }
|
func (self *VMEnv) Time() int64 { return self.block.Time() }
|
||||||
func (self *VMEnv) Time() int64 { return self.block.Time }
|
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() }
|
||||||
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty }
|
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
|
||||||
func (self *VMEnv) BlockHash() []byte { return self.block.Hash() }
|
|
||||||
func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
|
func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
|
||||||
func (self *VMEnv) State() *state.StateDB { return self.state }
|
func (self *VMEnv) State() *state.StateDB { return self.state }
|
||||||
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit }
|
|
||||||
func (self *VMEnv) Depth() int { return self.depth }
|
func (self *VMEnv) Depth() int { return self.depth }
|
||||||
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
||||||
|
func (self *VMEnv) GetHash(n uint64) []byte {
|
||||||
|
if block := self.chain.GetBlockByNumber(n); block != nil {
|
||||||
|
return block.Hash()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func (self *VMEnv) AddLog(log state.Log) {
|
func (self *VMEnv) AddLog(log state.Log) {
|
||||||
self.state.AddLog(log)
|
self.state.AddLog(log)
|
||||||
}
|
}
|
||||||
|
|
@ -46,16 +53,16 @@ func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *Execution
|
||||||
return NewExecution(self, addr, data, gas, price, value)
|
return NewExecution(self, addr, data, gas, price, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Call(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
func (self *VMEnv) Call(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
||||||
exe := self.vm(addr, data, gas, price, value)
|
exe := self.vm(addr, data, gas, price, value)
|
||||||
return exe.Call(addr, me)
|
return exe.Call(addr, me)
|
||||||
}
|
}
|
||||||
func (self *VMEnv) CallCode(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
func (self *VMEnv) CallCode(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
||||||
exe := self.vm(me.Address(), data, gas, price, value)
|
exe := self.vm(me.Address(), data, gas, price, value)
|
||||||
return exe.Call(addr, me)
|
return exe.Call(addr, me)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Create(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ClosureRef) {
|
func (self *VMEnv) Create(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) {
|
||||||
exe := self.vm(addr, data, gas, price, value)
|
exe := self.vm(addr, data, gas, price, value)
|
||||||
return exe.Create(me)
|
return exe.Create(me)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
149
eth/backend.go
149
eth/backend.go
|
|
@ -1,11 +1,13 @@
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"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/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/ethutil"
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
ethlogger "github.com/ethereum/go-ethereum/logger"
|
ethlogger "github.com/ethereum/go-ethereum/logger"
|
||||||
|
|
@ -16,9 +18,30 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
seedNodeAddress = "poc-7.ethdev.com:30300"
|
seedNodeAddress = "poc-8.ethdev.com:30303"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
Identifier string
|
||||||
|
KeyStore string
|
||||||
|
DataDir string
|
||||||
|
LogFile string
|
||||||
|
LogLevel int
|
||||||
|
KeyRing string
|
||||||
|
|
||||||
|
MaxPeers int
|
||||||
|
Port string
|
||||||
|
NATType string
|
||||||
|
PMPGateway string
|
||||||
|
|
||||||
|
Shh bool
|
||||||
|
Dial bool
|
||||||
|
|
||||||
|
KeyManager *crypto.KeyManager
|
||||||
|
}
|
||||||
|
|
||||||
var logger = ethlogger.NewLogger("SERV")
|
var logger = ethlogger.NewLogger("SERV")
|
||||||
|
|
||||||
type Ethereum struct {
|
type Ethereum struct {
|
||||||
|
|
@ -32,13 +55,13 @@ type Ethereum struct {
|
||||||
|
|
||||||
//*** SERVICES ***
|
//*** SERVICES ***
|
||||||
// State manager for processing new blocks and managing the over all states
|
// State manager for processing new blocks and managing the over all states
|
||||||
blockManager *core.BlockManager
|
blockProcessor *core.BlockProcessor
|
||||||
txPool *core.TxPool
|
txPool *core.TxPool
|
||||||
chainManager *core.ChainManager
|
chainManager *core.ChainManager
|
||||||
blockPool *BlockPool
|
blockPool *BlockPool
|
||||||
whisper *whisper.Whisper
|
whisper *whisper.Whisper
|
||||||
|
|
||||||
server *p2p.Server
|
net *p2p.Server
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
txSub event.Subscription
|
txSub event.Subscription
|
||||||
blockSub event.Subscription
|
blockSub event.Subscription
|
||||||
|
|
@ -47,6 +70,7 @@ type Ethereum struct {
|
||||||
keyManager *crypto.KeyManager
|
keyManager *crypto.KeyManager
|
||||||
|
|
||||||
clientIdentity p2p.ClientIdentity
|
clientIdentity p2p.ClientIdentity
|
||||||
|
logger ethlogger.LogSystem
|
||||||
|
|
||||||
synclock sync.Mutex
|
synclock sync.Mutex
|
||||||
syncGroup sync.WaitGroup
|
syncGroup sync.WaitGroup
|
||||||
|
|
@ -54,47 +78,82 @@ type Ethereum struct {
|
||||||
Mining bool
|
Mining bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(db ethutil.Database, identity p2p.ClientIdentity, keyManager *crypto.KeyManager, nat p2p.NAT, port string, maxPeers int) (*Ethereum, error) {
|
func New(config *Config) (*Ethereum, error) {
|
||||||
|
// Boostrap database
|
||||||
|
logger := ethlogger.New(config.DataDir, config.LogFile, config.LogLevel)
|
||||||
|
db, err := ethdb.NewLDBDatabase("blockchain")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform database sanity checks
|
||||||
|
d, _ := db.Get([]byte("ProtocolVersion"))
|
||||||
|
protov := ethutil.NewValue(d).Uint()
|
||||||
|
if protov != ProtocolVersion && protov != 0 {
|
||||||
|
return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, ethutil.Config.ExecPath+"/database")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new keymanager
|
||||||
|
var keyManager *crypto.KeyManager
|
||||||
|
switch config.KeyStore {
|
||||||
|
case "db":
|
||||||
|
keyManager = crypto.NewDBKeyManager(db)
|
||||||
|
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)
|
||||||
|
|
||||||
|
// Create a new client id for this instance. This will help identifying the node on the network
|
||||||
|
clientId := p2p.NewSimpleClientIdentity(config.Name, config.Version, config.Identifier, keyManager.PublicKey())
|
||||||
|
|
||||||
saveProtocolVersion(db)
|
saveProtocolVersion(db)
|
||||||
ethutil.Config.Db = db
|
//ethutil.Config.Db = db
|
||||||
|
|
||||||
eth := &Ethereum{
|
eth := &Ethereum{
|
||||||
shutdownChan: make(chan bool),
|
shutdownChan: make(chan bool),
|
||||||
quit: make(chan bool),
|
quit: make(chan bool),
|
||||||
db: db,
|
db: db,
|
||||||
keyManager: keyManager,
|
keyManager: keyManager,
|
||||||
clientIdentity: identity,
|
clientIdentity: clientId,
|
||||||
blacklist: p2p.NewBlacklist(),
|
blacklist: p2p.NewBlacklist(),
|
||||||
eventMux: &event.TypeMux{},
|
eventMux: &event.TypeMux{},
|
||||||
|
logger: logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
eth.chainManager = core.NewChainManager(eth.EventMux())
|
eth.chainManager = core.NewChainManager(db, eth.EventMux())
|
||||||
eth.txPool = core.NewTxPool(eth.chainManager, eth.EventMux())
|
eth.txPool = core.NewTxPool(eth.EventMux())
|
||||||
eth.blockManager = core.NewBlockManager(eth.txPool, eth.chainManager, eth.EventMux())
|
eth.blockProcessor = core.NewBlockProcessor(db, eth.txPool, eth.chainManager, eth.EventMux())
|
||||||
eth.chainManager.SetProcessor(eth.blockManager)
|
eth.chainManager.SetProcessor(eth.blockProcessor)
|
||||||
eth.whisper = whisper.New()
|
eth.whisper = whisper.New()
|
||||||
|
|
||||||
hasBlock := eth.chainManager.HasBlock
|
hasBlock := eth.chainManager.HasBlock
|
||||||
insertChain := eth.chainManager.InsertChain
|
insertChain := eth.chainManager.InsertChain
|
||||||
eth.blockPool = NewBlockPool(hasBlock, insertChain, ezp.Verify)
|
eth.blockPool = NewBlockPool(hasBlock, insertChain, ezp.Verify)
|
||||||
|
|
||||||
// Start services
|
|
||||||
eth.txPool.Start()
|
|
||||||
|
|
||||||
ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool)
|
ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool)
|
||||||
protocols := []p2p.Protocol{ethProto, eth.whisper.Protocol()}
|
protocols := []p2p.Protocol{ethProto, eth.whisper.Protocol()}
|
||||||
|
|
||||||
server := &p2p.Server{
|
nat, err := p2p.ParseNAT(config.NATType, config.PMPGateway)
|
||||||
Identity: identity,
|
if err != nil {
|
||||||
MaxPeers: maxPeers,
|
return nil, err
|
||||||
Protocols: protocols,
|
}
|
||||||
ListenAddr: ":" + port,
|
fmt.Println(nat)
|
||||||
Blacklist: eth.blacklist,
|
|
||||||
NAT: nat,
|
eth.net = &p2p.Server{
|
||||||
|
Identity: clientId,
|
||||||
|
MaxPeers: config.MaxPeers,
|
||||||
|
Protocols: protocols,
|
||||||
|
Blacklist: eth.blacklist,
|
||||||
|
NAT: p2p.UPNP(),
|
||||||
|
NoDial: !config.Dial,
|
||||||
}
|
}
|
||||||
|
|
||||||
eth.server = server
|
if len(config.Port) > 0 {
|
||||||
|
eth.net.ListenAddr = ":" + config.Port
|
||||||
|
}
|
||||||
|
|
||||||
return eth, nil
|
return eth, nil
|
||||||
}
|
}
|
||||||
|
|
@ -103,6 +162,10 @@ func (s *Ethereum) KeyManager() *crypto.KeyManager {
|
||||||
return s.keyManager
|
return s.keyManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Ethereum) Logger() ethlogger.LogSystem {
|
||||||
|
return s.logger
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Ethereum) ClientIdentity() p2p.ClientIdentity {
|
func (s *Ethereum) ClientIdentity() p2p.ClientIdentity {
|
||||||
return s.clientIdentity
|
return s.clientIdentity
|
||||||
}
|
}
|
||||||
|
|
@ -111,8 +174,8 @@ func (s *Ethereum) ChainManager() *core.ChainManager {
|
||||||
return s.chainManager
|
return s.chainManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) BlockManager() *core.BlockManager {
|
func (s *Ethereum) BlockProcessor() *core.BlockProcessor {
|
||||||
return s.blockManager
|
return s.blockProcessor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) TxPool() *core.TxPool {
|
func (s *Ethereum) TxPool() *core.TxPool {
|
||||||
|
|
@ -144,25 +207,31 @@ func (s *Ethereum) IsListening() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) PeerCount() int {
|
func (s *Ethereum) PeerCount() int {
|
||||||
return s.server.PeerCount()
|
return s.net.PeerCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) Peers() []*p2p.Peer {
|
func (s *Ethereum) Peers() []*p2p.Peer {
|
||||||
return s.server.Peers()
|
return s.net.Peers()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) MaxPeers() int {
|
func (s *Ethereum) MaxPeers() int {
|
||||||
return s.server.MaxPeers
|
return s.net.MaxPeers
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the ethereum
|
// Start the ethereum
|
||||||
func (s *Ethereum) Start(seed bool) error {
|
func (s *Ethereum) Start(seed bool) error {
|
||||||
err := s.server.Start()
|
err := s.net.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start services
|
||||||
|
s.txPool.Start()
|
||||||
s.blockPool.Start()
|
s.blockPool.Start()
|
||||||
s.whisper.Start()
|
|
||||||
|
if s.whisper != nil {
|
||||||
|
s.whisper.Start()
|
||||||
|
}
|
||||||
|
|
||||||
// broadcast transactions
|
// broadcast transactions
|
||||||
s.txSub = s.eventMux.Subscribe(core.TxPreEvent{})
|
s.txSub = s.eventMux.Subscribe(core.TxPreEvent{})
|
||||||
|
|
@ -191,7 +260,7 @@ func (self *Ethereum) SuggestPeer(addr string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
self.server.SuggestPeer(netaddr.IP, netaddr.Port, nil)
|
self.net.SuggestPeer(netaddr.IP, netaddr.Port, nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,7 +279,9 @@ func (s *Ethereum) Stop() {
|
||||||
s.txPool.Stop()
|
s.txPool.Stop()
|
||||||
s.eventMux.Stop()
|
s.eventMux.Stop()
|
||||||
s.blockPool.Stop()
|
s.blockPool.Stop()
|
||||||
s.whisper.Stop()
|
if s.whisper != nil {
|
||||||
|
s.whisper.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
logger.Infoln("Server stopped")
|
logger.Infoln("Server stopped")
|
||||||
close(s.shutdownChan)
|
close(s.shutdownChan)
|
||||||
|
|
@ -227,15 +298,17 @@ func (self *Ethereum) txBroadcastLoop() {
|
||||||
// automatically stops if unsubscribe
|
// automatically stops if unsubscribe
|
||||||
for obj := range self.txSub.Chan() {
|
for obj := range self.txSub.Chan() {
|
||||||
event := obj.(core.TxPreEvent)
|
event := obj.(core.TxPreEvent)
|
||||||
self.server.Broadcast("eth", TxMsg, []interface{}{event.Tx.RlpData()})
|
self.net.Broadcast("eth", TxMsg, event.Tx.RlpData())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Ethereum) blockBroadcastLoop() {
|
func (self *Ethereum) blockBroadcastLoop() {
|
||||||
// automatically stops if unsubscribe
|
// automatically stops if unsubscribe
|
||||||
for obj := range self.txSub.Chan() {
|
for obj := range self.blockSub.Chan() {
|
||||||
event := obj.(core.NewMinedBlockEvent)
|
switch ev := obj.(type) {
|
||||||
self.server.Broadcast("eth", NewBlockMsg, event.Block.Value().Val)
|
case core.NewMinedBlockEvent:
|
||||||
|
self.net.Broadcast("eth", NewBlockMsg, ev.Block.RlpData(), ev.Block.Td)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
1684
eth/block_pool.go
1684
eth/block_pool.go
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
13
eth/error.go
13
eth/error.go
|
|
@ -16,6 +16,7 @@ const (
|
||||||
ErrInvalidBlock
|
ErrInvalidBlock
|
||||||
ErrInvalidPoW
|
ErrInvalidPoW
|
||||||
ErrUnrequestedBlock
|
ErrUnrequestedBlock
|
||||||
|
ErrInsufficientChainInfo
|
||||||
)
|
)
|
||||||
|
|
||||||
var errorToString = map[int]string{
|
var errorToString = map[int]string{
|
||||||
|
|
@ -30,6 +31,7 @@ var errorToString = map[int]string{
|
||||||
ErrInvalidBlock: "Invalid block",
|
ErrInvalidBlock: "Invalid block",
|
||||||
ErrInvalidPoW: "Invalid PoW",
|
ErrInvalidPoW: "Invalid PoW",
|
||||||
ErrUnrequestedBlock: "Unrequested block",
|
ErrUnrequestedBlock: "Unrequested block",
|
||||||
|
ErrInsufficientChainInfo: "Insufficient chain info",
|
||||||
}
|
}
|
||||||
|
|
||||||
type protocolError struct {
|
type protocolError struct {
|
||||||
|
|
@ -52,18 +54,17 @@ func ProtocolError(code int, format string, params ...interface{}) (err *protoco
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self protocolError) Error() (message string) {
|
func (self protocolError) Error() (message string) {
|
||||||
message = self.message
|
if len(message) == 0 {
|
||||||
if message == "" {
|
var ok bool
|
||||||
message, ok := errorToString[self.Code]
|
self.message, ok = errorToString[self.Code]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("invalid error code")
|
panic("invalid error code")
|
||||||
}
|
}
|
||||||
if self.format != "" {
|
if self.format != "" {
|
||||||
message += ": " + fmt.Sprintf(self.format, self.params...)
|
self.message += ": " + fmt.Sprintf(self.format, self.params...)
|
||||||
}
|
}
|
||||||
self.message = message
|
|
||||||
}
|
}
|
||||||
return
|
return self.message
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *protocolError) Fatal() bool {
|
func (self *protocolError) Fatal() bool {
|
||||||
|
|
|
||||||
121
eth/protocol.go
121
eth/protocol.go
|
|
@ -3,7 +3,7 @@ package eth
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
@ -13,7 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProtocolVersion = 49
|
ProtocolVersion = 51
|
||||||
NetworkId = 0
|
NetworkId = 0
|
||||||
ProtocolLength = uint64(8)
|
ProtocolLength = uint64(8)
|
||||||
ProtocolMaxMsgSize = 10 * 1024 * 1024
|
ProtocolMaxMsgSize = 10 * 1024 * 1024
|
||||||
|
|
@ -67,6 +67,8 @@ type newBlockMsgData struct {
|
||||||
TD *big.Int
|
TD *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const maxHashes = 255
|
||||||
|
|
||||||
type getBlockHashesMsgData struct {
|
type getBlockHashesMsgData struct {
|
||||||
Hash []byte
|
Hash []byte
|
||||||
Amount uint64
|
Amount uint64
|
||||||
|
|
@ -95,14 +97,13 @@ func runEthProtocol(txPool txPool, chainManager chainManager, blockPool blockPoo
|
||||||
blockPool: blockPool,
|
blockPool: blockPool,
|
||||||
rw: rw,
|
rw: rw,
|
||||||
peer: peer,
|
peer: peer,
|
||||||
id: (string)(peer.Identity().Pubkey()),
|
id: fmt.Sprintf("%x", peer.Identity().Pubkey()[:8]),
|
||||||
}
|
}
|
||||||
err = self.handleStatus()
|
err = self.handleStatus()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for {
|
for {
|
||||||
err = self.handle()
|
err = self.handle()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
self.blockPool.RemovePeer(self.id)
|
self.blockPool.RemovePeer(self.id)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -117,112 +118,118 @@ func (self *ethProtocol) handle() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if msg.Size > ProtocolMaxMsgSize {
|
if msg.Size > ProtocolMaxMsgSize {
|
||||||
return ProtocolError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
|
return self.protoError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
|
||||||
}
|
}
|
||||||
// make sure that the payload has been fully consumed
|
// make sure that the payload has been fully consumed
|
||||||
defer msg.Discard()
|
defer msg.Discard()
|
||||||
|
|
||||||
switch msg.Code {
|
switch msg.Code {
|
||||||
|
case GetTxMsg: // ignore
|
||||||
case StatusMsg:
|
case StatusMsg:
|
||||||
return ProtocolError(ErrExtraStatusMsg, "")
|
return self.protoError(ErrExtraStatusMsg, "")
|
||||||
|
|
||||||
case TxMsg:
|
case TxMsg:
|
||||||
// TODO: rework using lazy RLP stream
|
// TODO: rework using lazy RLP stream
|
||||||
var txs []*types.Transaction
|
var txs []*types.Transaction
|
||||||
if err := msg.Decode(&txs); err != nil {
|
if err := msg.Decode(&txs); err != nil {
|
||||||
return ProtocolError(ErrDecode, "%v", err)
|
return self.protoError(ErrDecode, "msg %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
self.txPool.AddTransactions(txs)
|
self.txPool.AddTransactions(txs)
|
||||||
|
|
||||||
case GetBlockHashesMsg:
|
case GetBlockHashesMsg:
|
||||||
var request getBlockHashesMsgData
|
var request getBlockHashesMsgData
|
||||||
if err := msg.Decode(&request); err != nil {
|
if err := msg.Decode(&request); err != nil {
|
||||||
return ProtocolError(ErrDecode, "%v", err)
|
return self.protoError(ErrDecode, "->msg %v: %v", msg, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//request.Amount = uint64(math.Min(float64(maxHashes), float64(request.Amount)))
|
||||||
|
if request.Amount > maxHashes {
|
||||||
|
request.Amount = maxHashes
|
||||||
}
|
}
|
||||||
hashes := self.chainManager.GetBlockHashesFromHash(request.Hash, request.Amount)
|
hashes := self.chainManager.GetBlockHashesFromHash(request.Hash, request.Amount)
|
||||||
return self.rw.EncodeMsg(BlockHashesMsg, ethutil.ByteSliceToInterface(hashes)...)
|
return p2p.EncodeMsg(self.rw, BlockHashesMsg, ethutil.ByteSliceToInterface(hashes)...)
|
||||||
|
|
||||||
case BlockHashesMsg:
|
case BlockHashesMsg:
|
||||||
// TODO: redo using lazy decode , this way very inefficient on known chains
|
// TODO: redo using lazy decode , this way very inefficient on known chains
|
||||||
msgStream := rlp.NewListStream(msg.Payload, uint64(msg.Size))
|
msgStream := rlp.NewStream(msg.Payload)
|
||||||
var err error
|
var err error
|
||||||
|
var i int
|
||||||
|
|
||||||
iter := func() (hash []byte, ok bool) {
|
iter := func() (hash []byte, ok bool) {
|
||||||
hash, err = msgStream.Bytes()
|
hash, err = msgStream.Bytes()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
i++
|
||||||
ok = true
|
ok = true
|
||||||
|
} else {
|
||||||
|
if err != io.EOF {
|
||||||
|
self.protoError(ErrDecode, "msg %v: after %v hashes : %v", msg, i, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.blockPool.AddBlockHashes(iter, self.id)
|
self.blockPool.AddBlockHashes(iter, self.id)
|
||||||
if err != nil && err != rlp.EOL {
|
|
||||||
return ProtocolError(ErrDecode, "%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case GetBlocksMsg:
|
case GetBlocksMsg:
|
||||||
var blockHashes [][]byte
|
msgStream := rlp.NewStream(msg.Payload)
|
||||||
if err := msg.Decode(&blockHashes); err != nil {
|
|
||||||
return ProtocolError(ErrDecode, "%v", err)
|
|
||||||
}
|
|
||||||
max := int(math.Min(float64(len(blockHashes)), blockHashesBatchSize))
|
|
||||||
var blocks []interface{}
|
var blocks []interface{}
|
||||||
for i, hash := range blockHashes {
|
var i int
|
||||||
if i >= max {
|
for {
|
||||||
break
|
i++
|
||||||
|
var hash []byte
|
||||||
|
if err := msgStream.Decode(&hash); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
return self.protoError(ErrDecode, "msg %v: %v", msg, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
block := self.chainManager.GetBlock(hash)
|
block := self.chainManager.GetBlock(hash)
|
||||||
if block != nil {
|
if block != nil {
|
||||||
blocks = append(blocks, block.Value().Raw())
|
blocks = append(blocks, block)
|
||||||
|
}
|
||||||
|
if i == blockHashesBatchSize {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self.rw.EncodeMsg(BlocksMsg, blocks...)
|
return p2p.EncodeMsg(self.rw, BlocksMsg, blocks...)
|
||||||
|
|
||||||
case BlocksMsg:
|
case BlocksMsg:
|
||||||
msgStream := rlp.NewListStream(msg.Payload, uint64(msg.Size))
|
msgStream := rlp.NewStream(msg.Payload)
|
||||||
for {
|
for {
|
||||||
var block *types.Block
|
var block types.Block
|
||||||
if err := msgStream.Decode(&block); err != nil {
|
if err := msgStream.Decode(&block); err != nil {
|
||||||
if err == rlp.EOL {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
return ProtocolError(ErrDecode, "%v", err)
|
return self.protoError(ErrDecode, "msg %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.blockPool.AddBlock(block, self.id)
|
self.blockPool.AddBlock(&block, self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
case NewBlockMsg:
|
case NewBlockMsg:
|
||||||
var request newBlockMsgData
|
var request newBlockMsgData
|
||||||
if err := msg.Decode(&request); err != nil {
|
if err := msg.Decode(&request); err != nil {
|
||||||
return ProtocolError(ErrDecode, "%v", err)
|
return self.protoError(ErrDecode, "msg %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
hash := request.Block.Hash()
|
hash := request.Block.Hash()
|
||||||
// to simplify backend interface adding a new block
|
// to simplify backend interface adding a new block
|
||||||
// uses AddPeer followed by AddHashes, AddBlock only if peer is the best peer
|
// uses AddPeer followed by AddHashes, AddBlock only if peer is the best peer
|
||||||
// (or selected as new best peer)
|
// (or selected as new best peer)
|
||||||
if self.blockPool.AddPeer(request.TD, hash, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect) {
|
if self.blockPool.AddPeer(request.TD, hash, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect) {
|
||||||
called := true
|
|
||||||
iter := func() (hash []byte, ok bool) {
|
|
||||||
if called {
|
|
||||||
called = false
|
|
||||||
return hash, true
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.blockPool.AddBlockHashes(iter, self.id)
|
|
||||||
self.blockPool.AddBlock(request.Block, self.id)
|
self.blockPool.AddBlock(request.Block, self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ProtocolError(ErrInvalidMsgCode, "%v", msg.Code)
|
return self.protoError(ErrInvalidMsgCode, "%v", msg.Code)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type statusMsgData struct {
|
type statusMsgData struct {
|
||||||
ProtocolVersion uint
|
ProtocolVersion uint32
|
||||||
NetworkId uint
|
NetworkId uint32
|
||||||
TD *big.Int
|
TD *big.Int
|
||||||
CurrentBlock []byte
|
CurrentBlock []byte
|
||||||
GenesisBlock []byte
|
GenesisBlock []byte
|
||||||
|
|
@ -253,56 +260,56 @@ func (self *ethProtocol) handleStatus() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.Code != StatusMsg {
|
if msg.Code != StatusMsg {
|
||||||
return ProtocolError(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg)
|
return self.protoError(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.Size > ProtocolMaxMsgSize {
|
if msg.Size > ProtocolMaxMsgSize {
|
||||||
return ProtocolError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
|
return self.protoError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
var status statusMsgData
|
var status statusMsgData
|
||||||
if err := msg.Decode(&status); err != nil {
|
if err := msg.Decode(&status); err != nil {
|
||||||
return ProtocolError(ErrDecode, "%v", err)
|
return self.protoError(ErrDecode, "msg %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, genesisBlock := self.chainManager.Status()
|
_, _, genesisBlock := self.chainManager.Status()
|
||||||
|
|
||||||
if bytes.Compare(status.GenesisBlock, genesisBlock) != 0 {
|
if bytes.Compare(status.GenesisBlock, genesisBlock) != 0 {
|
||||||
return ProtocolError(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, genesisBlock)
|
return self.protoError(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, genesisBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
if status.NetworkId != NetworkId {
|
if status.NetworkId != NetworkId {
|
||||||
return ProtocolError(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, NetworkId)
|
return self.protoError(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, NetworkId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ProtocolVersion != status.ProtocolVersion {
|
if ProtocolVersion != status.ProtocolVersion {
|
||||||
return ProtocolError(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, ProtocolVersion)
|
return self.protoError(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, ProtocolVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.peer.Infof("Peer is [eth] capable (%d/%d). TD=%v H=%x\n", status.ProtocolVersion, status.NetworkId, status.TD, status.CurrentBlock[:4])
|
self.peer.Infof("Peer is [eth] capable (%d/%d). TD=%v H=%x\n", status.ProtocolVersion, status.NetworkId, status.TD, status.CurrentBlock[:4])
|
||||||
|
|
||||||
//self.blockPool.AddPeer(status.TD, status.CurrentBlock, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect)
|
self.blockPool.AddPeer(status.TD, status.CurrentBlock, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect)
|
||||||
self.peer.Infoln("AddPeer(IGNORED)")
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ethProtocol) requestBlockHashes(from []byte) error {
|
func (self *ethProtocol) requestBlockHashes(from []byte) error {
|
||||||
self.peer.Debugf("fetching hashes (%d) %x...\n", blockHashesBatchSize, from[0:4])
|
self.peer.Debugf("fetching hashes (%d) %x...\n", blockHashesBatchSize, from[0:4])
|
||||||
return self.rw.EncodeMsg(GetBlockHashesMsg, from, blockHashesBatchSize)
|
return p2p.EncodeMsg(self.rw, GetBlockHashesMsg, interface{}(from), uint64(blockHashesBatchSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ethProtocol) requestBlocks(hashes [][]byte) error {
|
func (self *ethProtocol) requestBlocks(hashes [][]byte) error {
|
||||||
self.peer.Debugf("fetching %v blocks", len(hashes))
|
self.peer.Debugf("fetching %v blocks", len(hashes))
|
||||||
return self.rw.EncodeMsg(GetBlocksMsg, ethutil.ByteSliceToInterface(hashes))
|
return p2p.EncodeMsg(self.rw, GetBlocksMsg, ethutil.ByteSliceToInterface(hashes)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ethProtocol) protoError(code int, format string, params ...interface{}) (err *protocolError) {
|
func (self *ethProtocol) protoError(code int, format string, params ...interface{}) (err *protocolError) {
|
||||||
err = ProtocolError(code, format, params...)
|
err = ProtocolError(code, format, params...)
|
||||||
if err.Fatal() {
|
if err.Fatal() {
|
||||||
self.peer.Errorln(err)
|
self.peer.Errorln("err %v", err)
|
||||||
|
// disconnect
|
||||||
} else {
|
} else {
|
||||||
self.peer.Debugln(err)
|
self.peer.Debugf("fyi %v", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -310,10 +317,10 @@ func (self *ethProtocol) protoError(code int, format string, params ...interface
|
||||||
func (self *ethProtocol) protoErrorDisconnect(code int, format string, params ...interface{}) {
|
func (self *ethProtocol) protoErrorDisconnect(code int, format string, params ...interface{}) {
|
||||||
err := ProtocolError(code, format, params...)
|
err := ProtocolError(code, format, params...)
|
||||||
if err.Fatal() {
|
if err.Fatal() {
|
||||||
self.peer.Errorln(err)
|
self.peer.Errorln("err %v", err)
|
||||||
// disconnect
|
// disconnect
|
||||||
} else {
|
} else {
|
||||||
self.peer.Debugln(err)
|
self.peer.Debugf("fyi %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,46 @@
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"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"
|
||||||
|
"github.com/ethereum/go-ethereum/ethutil"
|
||||||
|
ethlogger "github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var sys = ethlogger.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlogger.LogLevel(ethlogger.DebugDetailLevel))
|
||||||
|
|
||||||
type testMsgReadWriter struct {
|
type testMsgReadWriter struct {
|
||||||
in chan p2p.Msg
|
in chan p2p.Msg
|
||||||
out chan p2p.Msg
|
out []p2p.Msg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testMsgReadWriter) In(msg p2p.Msg) {
|
func (self *testMsgReadWriter) In(msg p2p.Msg) {
|
||||||
self.in <- msg
|
self.in <- msg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testMsgReadWriter) Out(msg p2p.Msg) {
|
func (self *testMsgReadWriter) Out() (msg p2p.Msg, ok bool) {
|
||||||
self.in <- msg
|
if len(self.out) > 0 {
|
||||||
|
msg = self.out[0]
|
||||||
|
self.out = self.out[1:]
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testMsgReadWriter) WriteMsg(msg p2p.Msg) error {
|
func (self *testMsgReadWriter) WriteMsg(msg p2p.Msg) error {
|
||||||
self.out <- msg
|
self.out = append(self.out, msg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testMsgReadWriter) EncodeMsg(code uint64, data ...interface{}) error {
|
|
||||||
return self.WriteMsg(p2p.NewMsg(code, data))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *testMsgReadWriter) ReadMsg() (p2p.Msg, error) {
|
func (self *testMsgReadWriter) ReadMsg() (p2p.Msg, error) {
|
||||||
msg, ok := <-self.in
|
msg, ok := <-self.in
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -40,145 +49,83 @@ func (self *testMsgReadWriter) ReadMsg() (p2p.Msg, error) {
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func errorCheck(t *testing.T, expCode int, err error) {
|
type testTxPool struct {
|
||||||
perr, ok := err.(*protocolError)
|
|
||||||
if ok && perr != nil {
|
|
||||||
if code := perr.Code; code != expCode {
|
|
||||||
ok = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("expected error code %v, got %v", ErrNoStatusMsg, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestBackend struct {
|
|
||||||
getTransactions func() []*types.Transaction
|
getTransactions func() []*types.Transaction
|
||||||
addTransactions func(txs []*types.Transaction)
|
addTransactions func(txs []*types.Transaction)
|
||||||
getBlockHashes func(hash []byte, amount uint32) (hashes [][]byte)
|
|
||||||
addBlockHashes func(next func() ([]byte, bool), peerId string)
|
|
||||||
getBlock func(hash []byte) *types.Block
|
|
||||||
addBlock func(block *types.Block, peerId string) (err error)
|
|
||||||
addPeer func(td *big.Int, currentBlock []byte, peerId string, requestHashes func([]byte) error, requestBlocks func([][]byte) error, invalidBlock func(error)) (best bool)
|
|
||||||
removePeer func(peerId string)
|
|
||||||
status func() (td *big.Int, currentBlock []byte, genesisBlock []byte)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TestBackend) GetTransactions() (txs []*types.Transaction) {
|
type testChainManager struct {
|
||||||
if self.getTransactions != nil {
|
getBlockHashes func(hash []byte, amount uint64) (hashes [][]byte)
|
||||||
txs = self.getTransactions()
|
getBlock func(hash []byte) *types.Block
|
||||||
}
|
status func() (td *big.Int, currentBlock []byte, genesisBlock []byte)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TestBackend) AddTransactions(txs []*types.Transaction) {
|
type testBlockPool struct {
|
||||||
|
addBlockHashes func(next func() ([]byte, bool), peerId string)
|
||||||
|
addBlock func(block *types.Block, peerId string) (err error)
|
||||||
|
addPeer func(td *big.Int, currentBlock []byte, peerId string, requestHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(int, string, ...interface{})) (best bool)
|
||||||
|
removePeer func(peerId string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (self *testTxPool) GetTransactions() (txs []*types.Transaction) {
|
||||||
|
// if self.getTransactions != nil {
|
||||||
|
// txs = self.getTransactions()
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (self *testTxPool) AddTransactions(txs []*types.Transaction) {
|
||||||
if self.addTransactions != nil {
|
if self.addTransactions != nil {
|
||||||
self.addTransactions(txs)
|
self.addTransactions(txs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TestBackend) GetBlockHashes(hash []byte, amount uint32) (hashes [][]byte) {
|
func (self *testChainManager) GetBlockHashesFromHash(hash []byte, amount uint64) (hashes [][]byte) {
|
||||||
if self.getBlockHashes != nil {
|
if self.getBlockHashes != nil {
|
||||||
hashes = self.getBlockHashes(hash, amount)
|
hashes = self.getBlockHashes(hash, amount)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
func (self *testChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) {
|
||||||
<<<<<<< HEAD
|
|
||||||
func (self *TestBackend) AddBlockHashes(next func() ([]byte, bool), peerId string) {
|
|
||||||
if self.addBlockHashes != nil {
|
|
||||||
self.addBlockHashes(next, peerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
=======
|
|
||||||
func (self *TestBackend) AddHash(hash []byte, peer *p2p.Peer) (more bool) {
|
|
||||||
if self.addHash != nil {
|
|
||||||
more = self.addHash(hash, peer)
|
|
||||||
=======
|
|
||||||
func (self *TestBackend) AddBlockHashes(next func() ([]byte, bool), peerId string) {
|
|
||||||
if self.addBlockHashes != nil {
|
|
||||||
self.addBlockHashes(next, peerId)
|
|
||||||
>>>>>>> eth protocol changes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<<<<<<< HEAD
|
|
||||||
>>>>>>> initial commit for eth-p2p integration
|
|
||||||
=======
|
|
||||||
|
|
||||||
>>>>>>> eth protocol changes
|
|
||||||
func (self *TestBackend) GetBlock(hash []byte) (block *types.Block) {
|
|
||||||
if self.getBlock != nil {
|
|
||||||
block = self.getBlock(hash)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
func (self *TestBackend) AddBlock(block *types.Block, peerId string) (err error) {
|
|
||||||
if self.addBlock != nil {
|
|
||||||
err = self.addBlock(block, peerId)
|
|
||||||
=======
|
|
||||||
func (self *TestBackend) AddBlock(td *big.Int, block *types.Block, peer *p2p.Peer) (fetchHashes bool, err error) {
|
|
||||||
if self.addBlock != nil {
|
|
||||||
fetchHashes, err = self.addBlock(td, block, peer)
|
|
||||||
>>>>>>> initial commit for eth-p2p integration
|
|
||||||
=======
|
|
||||||
func (self *TestBackend) AddBlock(block *types.Block, peerId string) (err error) {
|
|
||||||
if self.addBlock != nil {
|
|
||||||
err = self.addBlock(block, peerId)
|
|
||||||
>>>>>>> eth protocol changes
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
func (self *TestBackend) AddPeer(td *big.Int, currentBlock []byte, peerId string, requestBlockHashes func([]byte) error, requestBlocks func([][]byte) error, invalidBlock func(error)) (best bool) {
|
|
||||||
if self.addPeer != nil {
|
|
||||||
best = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, invalidBlock)
|
|
||||||
=======
|
|
||||||
func (self *TestBackend) AddPeer(td *big.Int, currentBlock []byte, peer *p2p.Peer) (fetchHashes bool) {
|
|
||||||
if self.addPeer != nil {
|
|
||||||
fetchHashes = self.addPeer(td, currentBlock, peer)
|
|
||||||
>>>>>>> initial commit for eth-p2p integration
|
|
||||||
=======
|
|
||||||
func (self *TestBackend) AddPeer(td *big.Int, currentBlock []byte, peerId string, requestBlockHashes func([]byte) error, requestBlocks func([][]byte) error, invalidBlock func(error)) (best bool) {
|
|
||||||
if self.addPeer != nil {
|
|
||||||
best = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, invalidBlock)
|
|
||||||
>>>>>>> eth protocol changes
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
>>>>>>> eth protocol changes
|
|
||||||
func (self *TestBackend) RemovePeer(peerId string) {
|
|
||||||
if self.removePeer != nil {
|
|
||||||
self.removePeer(peerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
>>>>>>> initial commit for eth-p2p integration
|
|
||||||
=======
|
|
||||||
>>>>>>> eth protocol changes
|
|
||||||
func (self *TestBackend) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) {
|
|
||||||
if self.status != nil {
|
if self.status != nil {
|
||||||
td, currentBlock, genesisBlock = self.status()
|
td, currentBlock, genesisBlock = self.status()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
func (self *testChainManager) GetBlock(hash []byte) (block *types.Block) {
|
||||||
<<<<<<< HEAD
|
if self.getBlock != nil {
|
||||||
=======
|
block = self.getBlock(hash)
|
||||||
>>>>>>> eth protocol changes
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *testBlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) {
|
||||||
|
if self.addBlockHashes != nil {
|
||||||
|
self.addBlockHashes(next, peerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *testBlockPool) AddBlock(block *types.Block, peerId string) {
|
||||||
|
if self.addBlock != nil {
|
||||||
|
self.addBlock(block, peerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *testBlockPool) AddPeer(td *big.Int, currentBlock []byte, peerId string, requestBlockHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(int, string, ...interface{})) (best bool) {
|
||||||
|
if self.addPeer != nil {
|
||||||
|
best = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, peerError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *testBlockPool) RemovePeer(peerId string) {
|
||||||
|
if self.removePeer != nil {
|
||||||
|
self.removePeer(peerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: refactor this into p2p/client_identity
|
// TODO: refactor this into p2p/client_identity
|
||||||
type peerId struct {
|
type peerId struct {
|
||||||
pubkey []byte
|
pubkey []byte
|
||||||
|
|
@ -201,32 +148,119 @@ func testPeer() *p2p.Peer {
|
||||||
return p2p.NewPeer(&peerId{}, []p2p.Cap{})
|
return p2p.NewPeer(&peerId{}, []p2p.Cap{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestErrNoStatusMsg(t *testing.T) {
|
type ethProtocolTester struct {
|
||||||
<<<<<<< HEAD
|
quit chan error
|
||||||
=======
|
rw *testMsgReadWriter // p2p.MsgReadWriter
|
||||||
func TestEth(t *testing.T) {
|
txPool *testTxPool // txPool
|
||||||
>>>>>>> initial commit for eth-p2p integration
|
chainManager *testChainManager // chainManager
|
||||||
=======
|
blockPool *testBlockPool // blockPool
|
||||||
>>>>>>> eth protocol changes
|
t *testing.T
|
||||||
quit := make(chan bool)
|
}
|
||||||
rw := &testMsgReadWriter{make(chan p2p.Msg, 10), make(chan p2p.Msg, 10)}
|
|
||||||
testBackend := &TestBackend{}
|
func newEth(t *testing.T) *ethProtocolTester {
|
||||||
var err error
|
return ðProtocolTester{
|
||||||
go func() {
|
quit: make(chan error),
|
||||||
<<<<<<< HEAD
|
rw: &testMsgReadWriter{in: make(chan p2p.Msg, 10)},
|
||||||
<<<<<<< HEAD
|
txPool: &testTxPool{},
|
||||||
err = runEthProtocol(testBackend, testPeer(), rw)
|
chainManager: &testChainManager{},
|
||||||
=======
|
blockPool: &testBlockPool{},
|
||||||
err = runEthProtocol(testBackend, nil, rw)
|
t: t,
|
||||||
>>>>>>> initial commit for eth-p2p integration
|
}
|
||||||
=======
|
}
|
||||||
err = runEthProtocol(testBackend, testPeer(), rw)
|
|
||||||
>>>>>>> eth protocol changes
|
func (self *ethProtocolTester) reset() {
|
||||||
close(quit)
|
self.rw = &testMsgReadWriter{in: make(chan p2p.Msg, 10)}
|
||||||
}()
|
self.quit = make(chan error)
|
||||||
statusMsg := p2p.NewMsg(4)
|
}
|
||||||
rw.In(statusMsg)
|
|
||||||
<-quit
|
func (self *ethProtocolTester) checkError(expCode int, delay time.Duration) (err error) {
|
||||||
errorCheck(t, ErrNoStatusMsg, err)
|
var timer = time.After(delay)
|
||||||
// read(t, remote, []byte("hello, world"), nil)
|
select {
|
||||||
|
case err = <-self.quit:
|
||||||
|
case <-timer:
|
||||||
|
self.t.Errorf("no error after %v, expected %v", delay, expCode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
perr, ok := err.(*protocolError)
|
||||||
|
if ok && perr != nil {
|
||||||
|
if code := perr.Code; code != expCode {
|
||||||
|
self.t.Errorf("expected protocol error (code %v), got %v (%v)", expCode, code, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.t.Errorf("expected protocol error (code %v), got %v", expCode, err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ethProtocolTester) In(msg p2p.Msg) {
|
||||||
|
self.rw.In(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ethProtocolTester) Out() (p2p.Msg, bool) {
|
||||||
|
return self.rw.Out()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ethProtocolTester) checkMsg(i int, code uint64, val interface{}) (msg p2p.Msg) {
|
||||||
|
if i >= len(self.rw.out) {
|
||||||
|
self.t.Errorf("expected at least %v msgs, got %v", i, len(self.rw.out))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg = self.rw.out[i]
|
||||||
|
if msg.Code != code {
|
||||||
|
self.t.Errorf("expected msg code %v, got %v", code, msg.Code)
|
||||||
|
}
|
||||||
|
if val != nil {
|
||||||
|
if err := msg.Decode(val); err != nil {
|
||||||
|
self.t.Errorf("rlp encoding error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ethProtocolTester) run() {
|
||||||
|
err := runEthProtocol(self.txPool, self.chainManager, self.blockPool, testPeer(), self.rw)
|
||||||
|
self.quit <- err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStatusMsgErrors(t *testing.T) {
|
||||||
|
logInit()
|
||||||
|
eth := newEth(t)
|
||||||
|
td := ethutil.Big1
|
||||||
|
currentBlock := []byte{1}
|
||||||
|
genesis := []byte{2}
|
||||||
|
eth.chainManager.status = func() (*big.Int, []byte, []byte) { return td, currentBlock, genesis }
|
||||||
|
go eth.run()
|
||||||
|
statusMsg := p2p.NewMsg(4)
|
||||||
|
eth.In(statusMsg)
|
||||||
|
delay := 1 * time.Second
|
||||||
|
eth.checkError(ErrNoStatusMsg, delay)
|
||||||
|
var status statusMsgData
|
||||||
|
eth.checkMsg(0, StatusMsg, &status) // first outgoing msg should be StatusMsg
|
||||||
|
if status.TD.Cmp(td) != 0 ||
|
||||||
|
status.ProtocolVersion != ProtocolVersion ||
|
||||||
|
status.NetworkId != NetworkId ||
|
||||||
|
status.TD.Cmp(td) != 0 ||
|
||||||
|
bytes.Compare(status.CurrentBlock, currentBlock) != 0 ||
|
||||||
|
bytes.Compare(status.GenesisBlock, genesis) != 0 {
|
||||||
|
t.Errorf("incorrect outgoing status")
|
||||||
|
}
|
||||||
|
|
||||||
|
eth.reset()
|
||||||
|
go eth.run()
|
||||||
|
statusMsg = p2p.NewMsg(0, uint32(48), uint32(0), td, currentBlock, genesis)
|
||||||
|
eth.In(statusMsg)
|
||||||
|
eth.checkError(ErrProtocolVersionMismatch, delay)
|
||||||
|
|
||||||
|
eth.reset()
|
||||||
|
go eth.run()
|
||||||
|
statusMsg = p2p.NewMsg(0, uint32(49), uint32(1), td, currentBlock, genesis)
|
||||||
|
eth.In(statusMsg)
|
||||||
|
eth.checkError(ErrNetworkIdMismatch, delay)
|
||||||
|
|
||||||
|
eth.reset()
|
||||||
|
go eth.run()
|
||||||
|
statusMsg = p2p.NewMsg(0, uint32(49), uint32(0), td, currentBlock, []byte{3})
|
||||||
|
eth.In(statusMsg)
|
||||||
|
eth.checkError(ErrGenesisBlockMismatch, delay)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
27
eth/test/README.md
Normal file
27
eth/test/README.md
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
= Integration tests for eth protocol and blockpool
|
||||||
|
|
||||||
|
This is a simple suite of tests to fire up a local test node with peers to test blockchain synchronisation and download.
|
||||||
|
The scripts call ethereum (assumed to be compiled in go-ethereum root).
|
||||||
|
|
||||||
|
To run a test:
|
||||||
|
|
||||||
|
. run.sh 00 02
|
||||||
|
|
||||||
|
Without arguments, all tests are run.
|
||||||
|
|
||||||
|
Peers are launched with preloaded imported chains. In order to prevent them from synchronizing with each other they are set with `-dial=false` and `-maxpeer 1` options. They log into `/tmp/eth.test/nodes/XX` where XX is the last two digits of their port.
|
||||||
|
|
||||||
|
Chains to import can be bootstrapped by letting nodes mine for some time. This is done with
|
||||||
|
|
||||||
|
. bootstrap.sh
|
||||||
|
|
||||||
|
Only the relative timing and forks matter so they should work if the bootstrap script is rerun.
|
||||||
|
The reference blockchain of tests are soft links to these import chains and check at the end of a test run.
|
||||||
|
|
||||||
|
Connecting to peers and exporting blockchain is scripted with JS files executed by the JSRE, see `tests/XX.sh`.
|
||||||
|
|
||||||
|
Each test is set with a timeout. This may vary on different computers so adjust sensibly.
|
||||||
|
If you kill a test before it completes, do not forget to kill all the background processes, since they will impact the result. Use:
|
||||||
|
|
||||||
|
killall ethereum
|
||||||
|
|
||||||
9
eth/test/bootstrap.sh
Normal file
9
eth/test/bootstrap.sh
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# bootstrap chains - used to regenerate tests/chains/*.chain
|
||||||
|
|
||||||
|
mkdir -p chains
|
||||||
|
bash ./mine.sh 00 10
|
||||||
|
bash ./mine.sh 01 5 00
|
||||||
|
bash ./mine.sh 02 10 00
|
||||||
|
bash ./mine.sh 03 5 02
|
||||||
|
bash ./mine.sh 04 10 02
|
||||||
BIN
eth/test/chains/00.chain
Executable file
BIN
eth/test/chains/00.chain
Executable file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue