Merge branch 'release/v0.7.10'

This commit is contained in:
obscuren 2014-12-20 02:34:12 +01:00
commit 3983dd2428
344 changed files with 67744 additions and 1446 deletions

4
.gitignore vendored
View File

@ -9,6 +9,4 @@
*un~ *un~
.DS_Store .DS_Store
*/**/.DS_Store */**/.DS_Store
ethereum/ethereum .ethtest
ethereal/ethereal

View File

@ -1,4 +1,25 @@
before_install: sudo apt-get install libgmp3-dev
language: go language: go
go: go:
- 1.2 - 1.3
before_install:
- sudo add-apt-repository ppa:ubuntu-sdk-team/ppa -y
- sudo apt-get update -qq
- sudo apt-get install -yqq libgmp3-dev qtbase5-private-dev qtdeclarative5-private-dev libqt5opengl5-dev libreadline6-dev
install:
- go get code.google.com/p/go.tools/cmd/goimports
- go get github.com/golang/lint/golint
# - go get code.google.com/p/go.tools/cmd/vet
- go get code.google.com/p/go.tools/cmd/cover
- go get github.com/mattn/goveralls
- ./install_deps.sh
before_script:
- gofmt -l -w .
- goimports -l -w .
- golint .
# - go vet ./...
# - go test -race ./...
script:
- ./gocoverage.sh && goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN
env:
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="

41
Dockerfile Normal file
View File

@ -0,0 +1,41 @@
FROM ubuntu:14.04
## Environment setup
ENV HOME /root
ENV GOPATH /root/go
ENV PATH /go/bin:/root/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
RUN mkdir -p /root/go
ENV DEBIAN_FRONTEND noninteractive
## Install base dependencies
RUN apt-get update && apt-get upgrade -y
RUN apt-get install -y git mercurial build-essential software-properties-common pkg-config libgmp3-dev libreadline6-dev libpcre3-dev libpcre++-dev
## Build and install Go
RUN hg clone -u release https://code.google.com/p/go
RUN cd go && hg update go1.4
RUN cd go/src && ./all.bash && go version
## Install GUI dependencies
RUN add-apt-repository ppa:ubuntu-sdk-team/ppa -y
RUN apt-get update -y
RUN apt-get install -y qtbase5-private-dev qtdeclarative5-private-dev libqt5opengl5-dev
## Fetch and install serpent-go
RUN go get -v -d github.com/ethereum/serpent-go
WORKDIR $GOPATH/src/github.com/ethereum/serpent-go
RUN git checkout master
RUN git submodule update --init
RUN go install -v
# Fetch and install go-ethereum
RUN go get -v -d github.com/ethereum/go-ethereum/...
WORKDIR $GOPATH/src/github.com/ethereum/go-ethereum
RUN git checkout poc8
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 JSON RPC
ENTRYPOINT ["ethereum", "-rpc=true", "-rpcport=8080"]
EXPOSE 8080

View File

@ -1,16 +1,16 @@
Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved. Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. 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, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU Lesser General Public
along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA MA 02110-1301 USA

View File

@ -1,4 +1,8 @@
[![Bugs](https://badge.waffle.io/ethereum/go-ethereum.png?label=bug&title=Bugs)](https://waffle.io/ethereum/go-ethereum)
[![Stories in Ready](https://badge.waffle.io/ethereum/go-ethereum.png?label=ready&title=Ready)](https://waffle.io/ethereum/go-ethereum) [![Stories in Ready](https://badge.waffle.io/ethereum/go-ethereum.png?label=ready&title=Ready)](https://waffle.io/ethereum/go-ethereum)
[![Stories in
Progress](https://badge.waffle.io/ethereum/go-ethereum.svg?label=in%20progress&title=In Progress)](http://waffle.io/ethereum/go-ethereum)
Ethereum Ethereum
======== ========
@ -8,38 +12,64 @@ Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20
Ethereum Go Client © 2014 Jeffrey Wilcke. Ethereum Go Client © 2014 Jeffrey Wilcke.
Current state: Proof of Concept 0.6.7. Current state: Proof of Concept 0.7
For the development package please see the [eth-go package](https://github.com/ethereum/eth-go). Ethereum is currently in its testing phase.
Build Build
======= =====
To build Ethereal (GUI): To build Mist (GUI):
`go get github.com/ethereum/go-ethereum/ethereal` `go get github.com/ethereum/go-ethereum/cmd/mist`
To build the node (CLI): To build the node (CLI):
`go get github.com/ethereum/go-ethereum/ethereum` `go get github.com/ethereum/go-ethereum/cmd/ethereum`
For further, detailed, build instruction please see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)) For further, detailed, build instruction please see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go))
Automated (dev) builds
======================
* [[OS X](http://build.ethdev.com/builds/OSX%20Go%20develop%20branch/latest/app/)]
* [Windows] Coming soon™
* [Linux] Coming soon™
Binaries
========
Go Ethereum comes with several binaries found in
[cmd](https://github.com/ethereum/go-ethereum/tree/master/cmd):
* `mist` Official Ethereum Browser
* `ethereum` Ethereum CLI
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suit:
`ethtest "`cat myfile.json`"`.
* `evm` is a generic Ethereum Virtual Machine: `evm -code 60ff60ff -gas
10000 -price 0 -dump`. See `-h` for a detailed description.
General command line options General command line options
==================== ============================
``` ```
Shared between ethereum and ethereal == Shared between ethereum and Mist ==
= Settings
-id Set the custom identifier of the client (shows up on other clients) -id Set the custom identifier of the client (shows up on other clients)
-port Port on which the server will accept incomming connections -port Port on which the server will accept incomming connections
-upnp Enable UPnP -upnp Enable UPnP
-maxpeer Desired amount of peers -maxpeer Desired amount of peers
-rpc Start JSON RPC -rpc Start JSON RPC
-dir Data directory used to store configs and databases -dir Data directory used to store configs and databases
-import Import a private key
-genaddr Generates a new address and private key (destructive action) = Utility
-h This -h This
-import Import a private key
-genaddr Generates a new address and private key (destructive action)
-dump Dump a specific state of a block to stdout given the -number or -hash
-difftool Supress all output and prints VM output to stdout
-diff vm=only vm output, all=all output including state storage
Ethereum only Ethereum only
ethereum [options] [filename] ethereum [options] [filename]
@ -47,31 +77,34 @@ ethereum [options] [filename]
filename Load the given file and interpret as JavaScript filename Load the given file and interpret as JavaScript
-m Start mining blocks -m Start mining blocks
Etheral only == Mist only ==
-asset_path absolute path to GUI assets directory -asset_path absolute path to GUI assets directory
``` ```
Contribution Contribution
============ ============
If you would like to contribute to Ethereum Go, please fork, fix, commit and If you'd like to contribute to Ethereum please fork, fix, commit and
send a pull request to the main repository. Commits which do not comply with the coding standards explained below send a pull request. Commits who do not comply with the coding standards
will be ignored. If you send a pull request, make sure that you are ignored (use gofmt!). If you send pull requests make absolute sure that you
commit to the `develop` branch and that you do not merge to `master`. commit on the `develop` branch and that you do not merge to master.
Commits that are directly based off of the `master` branch instead of the `develop` branch will be ignored. Commits that are directly based on master are simply ignored.
To make this process simpler try following the [git flow](http://nvie.com/posts/a-successful-git-branching-model/) branching model, as it sets this process up and streamlines work flow. To make life easier try [git flow](http://nvie.com/posts/a-successful-git-branching-model/) it sets
this all up and streamlines your work flow.
Coding standards Coding standards
================ ================
Code should be formatted according to the [Go Formatting Sources should be formatted according to the [Go Formatting
Style](http://golang.org/doc/effective_go.html#formatting). Style](http://golang.org/doc/effective_go.html#formatting).
Unless struct fields are supposed to be directly accessible, provide Unless structs fields are supposed to be directly accesible, provide
getters and hide the fields through Go's exporting facility. Getters and hide the fields through Go's exporting facility.
Make comments in your code meaningful and only use them when necessary. Describe in detail what your code is trying to achieve. For example, this would be redundant and unnecessary commenting: When you comment put meaningfull comments. Describe in detail what you
want to achieve.
*wrong* *wrong*
@ -82,7 +115,12 @@ if x > y {
} }
``` ```
Everyone reading the source code should know what this code snippet was meant to achieve, and so those are **not** meaningful comments. Everyone reading the source probably know what you wanted to achieve
with above code. Those are **not** meaningful comments.
While this project is constantly tested and run, code tests should be written regardless. There is not time to evaluate every person's code specifically, so it is expected of you to write tests for the code so that it does not have to be tested manually. In fact, contributing by simply writing tests is perfectly fine! While the project isn't 100% tested I want you to write tests non the
less. I haven't got time to evaluate everyone's code in detail so I
expect you to write tests for me so I don't have to test your code
manually. (If you want to contribute by just writing tests that's fine
too!)

BIN
_data/chain1 Executable file

Binary file not shown.

BIN
_data/chain2 Executable file

Binary file not shown.

351
block_pool.go Normal file
View File

@ -0,0 +1,351 @@
package eth
import (
"bytes"
"container/list"
"fmt"
"math"
"math/big"
"sync"
"time"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/wire"
)
var poollogger = logger.NewLogger("BPOOL")
type block struct {
from *Peer
peer *Peer
block *types.Block
reqAt time.Time
requested int
}
type BlockPool struct {
mut sync.Mutex
eth *Ethereum
hashes [][]byte
pool map[string]*block
td *big.Int
quit chan bool
fetchingHashes bool
downloadStartedAt time.Time
ChainLength, BlocksProcessed int
peer *Peer
}
func NewBlockPool(eth *Ethereum) *BlockPool {
return &BlockPool{
eth: eth,
pool: make(map[string]*block),
td: ethutil.Big0,
quit: make(chan bool),
}
}
func (self *BlockPool) Len() int {
return len(self.hashes)
}
func (self *BlockPool) Reset() {
self.pool = make(map[string]*block)
self.hashes = nil
}
func (self *BlockPool) HasLatestHash() bool {
self.mut.Lock()
defer self.mut.Unlock()
return self.pool[string(self.eth.ChainManager().CurrentBlock().Hash())] != nil
}
func (self *BlockPool) HasCommonHash(hash []byte) bool {
return self.eth.ChainManager().GetBlock(hash) != nil
}
func (self *BlockPool) Blocks() (blocks types.Blocks) {
for _, item := range self.pool {
if item.block != nil {
blocks = append(blocks, item.block)
}
}
return
}
func (self *BlockPool) FetchHashes(peer *Peer) bool {
highestTd := self.eth.HighestTDPeer()
if (self.peer == nil && peer.td.Cmp(highestTd) >= 0) || (self.peer != nil && peer.td.Cmp(self.peer.td) > 0) || self.peer == peer {
if self.peer != peer {
poollogger.Infof("Found better suitable peer (%v vs %v)\n", self.td, peer.td)
if self.peer != nil {
self.peer.doneFetchingHashes = true
}
}
self.peer = peer
self.td = peer.td
if !self.HasLatestHash() {
self.fetchHashes()
}
return true
}
return false
}
func (self *BlockPool) fetchHashes() {
peer := self.peer
peer.doneFetchingHashes = false
const amount = 256
peerlogger.Debugf("Fetching hashes (%d) %x...\n", amount, peer.lastReceivedHash[0:4])
peer.QueueMessage(wire.NewMessage(wire.MsgGetBlockHashesTy, []interface{}{peer.lastReceivedHash, uint32(amount)}))
}
func (self *BlockPool) AddHash(hash []byte, peer *Peer) {
self.mut.Lock()
defer self.mut.Unlock()
if self.pool[string(hash)] == nil {
self.pool[string(hash)] = &block{peer, nil, nil, time.Now(), 0}
self.hashes = append([][]byte{hash}, self.hashes...)
}
}
func (self *BlockPool) Add(b *types.Block, peer *Peer) {
self.addBlock(b, peer, false)
}
func (self *BlockPool) AddNew(b *types.Block, peer *Peer) {
self.addBlock(b, peer, true)
}
func (self *BlockPool) addBlock(b *types.Block, peer *Peer, newBlock bool) {
self.mut.Lock()
defer self.mut.Unlock()
hash := string(b.Hash())
if self.pool[hash] == nil && !self.eth.ChainManager().HasBlock(b.Hash()) {
poollogger.Infof("Got unrequested block (%x...)\n", hash[0:4])
self.hashes = append(self.hashes, b.Hash())
self.pool[hash] = &block{peer, peer, b, time.Now(), 0}
// The following is only performed on an unrequested new block
if newBlock {
fmt.Println("1.", !self.eth.ChainManager().HasBlock(b.PrevHash), ethutil.Bytes2Hex(b.Hash()[0:4]), ethutil.Bytes2Hex(b.PrevHash[0:4]))
fmt.Println("2.", self.pool[string(b.PrevHash)] == nil)
fmt.Println("3.", !self.fetchingHashes)
if !self.eth.ChainManager().HasBlock(b.PrevHash) /*&& self.pool[string(b.PrevHash)] == nil*/ && !self.fetchingHashes {
poollogger.Infof("Unknown chain, requesting (%x...)\n", b.PrevHash[0:4])
peer.QueueMessage(wire.NewMessage(wire.MsgGetBlockHashesTy, []interface{}{b.Hash(), uint32(256)}))
}
}
} else if self.pool[hash] != nil {
self.pool[hash].block = b
}
self.BlocksProcessed++
}
func (self *BlockPool) Remove(hash []byte) {
self.mut.Lock()
defer self.mut.Unlock()
self.hashes = ethutil.DeleteFromByteSlice(self.hashes, hash)
delete(self.pool, string(hash))
}
func (self *BlockPool) DistributeHashes() {
self.mut.Lock()
defer self.mut.Unlock()
var (
peerLen = self.eth.peers.Len()
amount = 256 * peerLen
dist = make(map[*Peer][][]byte)
)
num := int(math.Min(float64(amount), float64(len(self.pool))))
for i, j := 0, 0; i < len(self.hashes) && j < num; i++ {
hash := self.hashes[i]
item := self.pool[string(hash)]
if item != nil && item.block == nil {
var peer *Peer
lastFetchFailed := time.Since(item.reqAt) > 5*time.Second
// Handle failed requests
if lastFetchFailed && item.requested > 5 && item.peer != nil {
if item.requested < 100 {
// Select peer the hash was retrieved off
peer = item.from
} else {
// Remove it
self.hashes = ethutil.DeleteFromByteSlice(self.hashes, hash)
delete(self.pool, string(hash))
}
} else if lastFetchFailed || item.peer == nil {
// Find a suitable, available peer
eachPeer(self.eth.peers, func(p *Peer, v *list.Element) {
if peer == nil && len(dist[p]) < amount/peerLen && p.statusKnown {
peer = p
}
})
}
if peer != nil {
item.reqAt = time.Now()
item.peer = peer
item.requested++
dist[peer] = append(dist[peer], hash)
}
}
}
for peer, hashes := range dist {
peer.FetchBlocks(hashes)
}
if len(dist) > 0 {
self.downloadStartedAt = time.Now()
}
}
func (self *BlockPool) Start() {
go self.downloadThread()
go self.chainThread()
}
func (self *BlockPool) Stop() {
close(self.quit)
}
func (self *BlockPool) downloadThread() {
serviceTimer := time.NewTicker(100 * time.Millisecond)
out:
for {
select {
case <-self.quit:
break out
case <-serviceTimer.C:
// Check if we're catching up. If not distribute the hashes to
// the peers and download the blockchain
self.fetchingHashes = false
eachPeer(self.eth.peers, func(p *Peer, v *list.Element) {
if p.statusKnown && p.FetchingHashes() {
self.fetchingHashes = true
}
})
if len(self.hashes) > 0 {
self.DistributeHashes()
}
if self.ChainLength < len(self.hashes) {
self.ChainLength = len(self.hashes)
}
if self.peer != nil &&
!self.peer.doneFetchingHashes &&
time.Since(self.peer.lastHashAt) > 10*time.Second &&
time.Since(self.peer.lastHashRequestedAt) > 5*time.Second {
self.fetchHashes()
}
/*
if !self.fetchingHashes {
blocks := self.Blocks()
chain.BlockBy(chain.Number).Sort(blocks)
if len(blocks) > 0 {
if !self.eth.ChainManager().HasBlock(b.PrevHash) && self.pool[string(b.PrevHash)] == nil && !self.fetchingHashes {
}
}
}
*/
}
}
}
func (self *BlockPool) chainThread() {
procTimer := time.NewTicker(500 * time.Millisecond)
out:
for {
select {
case <-self.quit:
break out
case <-procTimer.C:
blocks := self.Blocks()
types.BlockBy(types.Number).Sort(blocks)
// Find common block
for i, block := range blocks {
if self.eth.ChainManager().HasBlock(block.PrevHash) {
blocks = blocks[i:]
break
}
}
if len(blocks) > 0 {
if self.eth.ChainManager().HasBlock(blocks[0].PrevHash) {
for i, block := range blocks[1:] {
// NOTE: The Ith element in this loop refers to the previous block in
// outer "blocks"
if bytes.Compare(block.PrevHash, blocks[i].Hash()) != 0 {
blocks = blocks[:i]
break
}
}
} else {
blocks = nil
}
}
if len(blocks) > 0 {
chainman := self.eth.ChainManager()
err := chainman.InsertChain(blocks)
if err != nil {
poollogger.Debugln(err)
self.Reset()
if self.peer != nil && self.peer.conn != nil {
poollogger.Debugf("Punishing peer for supplying bad chain (%v)\n", self.peer.conn.RemoteAddr())
}
// This peer gave us bad hashes and made us fetch a bad chain, therefor he shall be punished.
self.eth.BlacklistPeer(self.peer)
self.peer.StopWithReason(DiscBadPeer)
self.td = ethutil.Big0
self.peer = nil
}
for _, block := range blocks {
self.Remove(block.Hash())
}
}
}
}
}

16
cmd/LICENSE Normal file
View File

@ -0,0 +1,16 @@
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

52
cmd/ethereum/cmd.go Normal file
View File

@ -0,0 +1,52 @@
// 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
package main
import (
"io/ioutil"
"os"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/cmd/ethereum/repl"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/javascript"
)
func InitJsConsole(ethereum *eth.Ethereum) {
repl := ethrepl.NewJSRepl(ethereum)
go repl.Start()
utils.RegisterInterrupt(func(os.Signal) {
repl.Stop()
})
}
func ExecJsFile(ethereum *eth.Ethereum, InputFile string) {
file, err := os.Open(InputFile)
if err != nil {
clilogger.Fatalln(err)
}
content, err := ioutil.ReadAll(file)
if err != nil {
clilogger.Fatalln(err)
}
re := javascript.NewJSRE(ethereum)
utils.RegisterInterrupt(func(os.Signal) {
re.Stop()
})
re.Run(string(content))
}

View File

@ -1,13 +1,32 @@
// 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
package main package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"log"
"os" "os"
"os/user" "os/user"
"path" "path"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/vm"
) )
var ( var (
@ -37,6 +56,7 @@ var (
Dump bool Dump bool
DumpHash string DumpHash string
DumpNumber int DumpNumber int
VmType int
) )
// flags specific to cli client // flags specific to cli client
@ -59,12 +79,13 @@ func Init() {
flag.PrintDefaults() flag.PrintDefaults()
} }
flag.IntVar(&VmType, "vm", 0, "Virtual Machine type: 0-1: standard, debug")
flag.StringVar(&Identifier, "id", "", "Custom client identifier") flag.StringVar(&Identifier, "id", "", "Custom client identifier")
flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use") flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use")
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", false, "enable UPnP support") flag.BoolVar(&UseUPnP, "upnp", false, "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")
@ -77,7 +98,7 @@ func Init() {
flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use") flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use")
flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file") flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
flag.IntVar(&LogLevel, "loglevel", int(ethlog.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
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")
@ -91,5 +112,9 @@ func Init() {
flag.Parse() flag.Parse()
if VmType >= int(vm.MaxVmTy) {
log.Fatal("Invalid VM type ", VmType)
}
InputFile = flag.Arg(0) InputFile = flag.Arg(0)
} }

View File

@ -1,3 +1,20 @@
// 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
package main package main
import ( import (
@ -5,18 +22,18 @@ import (
"os" "os"
"runtime" "runtime"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/logger"
) )
const ( const (
ClientIdentifier = "Ethereum(G)" ClientIdentifier = "Ethereum(G)"
Version = "0.6.7" Version = "0.7.10"
) )
var logger = ethlog.NewLogger("CLI") var clilogger = logger.NewLogger("CLI")
func main() { func main() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
@ -31,7 +48,7 @@ func main() {
LogLevel = 0 LogLevel = 0
} }
utils.InitConfig(ConfigFile, Datadir, "ETH") utils.InitConfig(VmType, ConfigFile, Datadir, "ETH")
ethutil.Config.Diff = DiffTool ethutil.Config.Diff = DiffTool
ethutil.Config.DiffType = DiffType ethutil.Config.DiffType = DiffType
@ -42,7 +59,7 @@ func main() {
db := utils.NewDatabase() db := utils.NewDatabase()
err := utils.DBSanityCheck(db) err := utils.DBSanityCheck(db)
if err != nil { if err != nil {
logger.Errorln(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
@ -57,14 +74,14 @@ func main() {
ethereum := utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer) ethereum := utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer)
if Dump { if Dump {
var block *ethchain.Block var block *types.Block
if len(DumpHash) == 0 && DumpNumber == -1 { if len(DumpHash) == 0 && DumpNumber == -1 {
block = ethereum.BlockChain().CurrentBlock block = ethereum.ChainManager().CurrentBlock()
} else if len(DumpHash) > 0 { } else if len(DumpHash) > 0 {
block = ethereum.BlockChain().GetBlock(ethutil.Hex2Bytes(DumpHash)) block = ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(DumpHash))
} else { } else {
block = ethereum.BlockChain().GetBlockByNumber(uint64(DumpNumber)) block = ethereum.ChainManager().GetBlockByNumber(uint64(DumpNumber))
} }
if block == nil { if block == nil {
@ -76,11 +93,14 @@ func main() {
os.Exit(1) os.Exit(1)
} }
fmt.Printf("RLP: %x\nstate: %x\nhash: %x\n", ethutil.Rlp(block), block.GetRoot(), block.Hash()) // 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()) fmt.Printf("%s\n", block.State().Dump())
fmt.Println(block)
os.Exit(0) os.Exit(0)
} }
@ -111,5 +131,5 @@ func main() {
// this blocks the thread // this blocks the thread
ethereum.WaitForShutdown() ethereum.WaitForShutdown()
ethlog.Flush() logger.Flush()
} }

View File

@ -0,0 +1,97 @@
// 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
/* Inspired by https://github.com/xuyu/logging/blob/master/colorful_win.go */
package ethrepl
import (
"syscall"
"unsafe"
)
type color uint16
const (
green = color(0x0002)
red = color(0x0004)
yellow = color(0x000E)
)
const (
mask = uint16(yellow | green | red)
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetStdHandle = kernel32.NewProc("GetStdHandle")
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
hStdout uintptr
initScreenInfo *consoleScreenBufferInfo
)
func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
ret, _, _ := procSetConsoleTextAttribute.Call(hConsoleOutput, uintptr(wAttributes))
return ret != 0
}
type coord struct {
X, Y int16
}
type smallRect struct {
Left, Top, Right, Bottom int16
}
type consoleScreenBufferInfo struct {
DwSize coord
DwCursorPosition coord
WAttributes uint16
SrWindow smallRect
DwMaximumWindowSize coord
}
func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
var csbi consoleScreenBufferInfo
ret, _, _ := procGetConsoleScreenBufferInfo.Call(hConsoleOutput, uintptr(unsafe.Pointer(&csbi)))
if ret == 0 {
return nil
}
return &csbi
}
const (
stdOutputHandle = uint32(-11 & 0xFFFFFFFF)
)
func init() {
hStdout, _, _ = procGetStdHandle.Call(uintptr(stdOutputHandle))
initScreenInfo = getConsoleScreenBufferInfo(hStdout)
}
func resetColorful() {
if initScreenInfo == nil {
return
}
setConsoleTextAttribute(hStdout, initScreenInfo.WAttributes)
}
func changeColor(c color) {
attr := uint16(0) & ^mask | uint16(c)
setConsoleTextAttribute(hStdout, attr)
}

View File

@ -1,3 +1,20 @@
// 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
package ethrepl package ethrepl
import ( import (
@ -7,13 +24,13 @@ import (
"os" "os"
"path" "path"
"github.com/ethereum/eth-go" "github.com/ethereum/go-ethereum"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/javascript" "github.com/ethereum/go-ethereum/javascript"
"github.com/ethereum/go-ethereum/logger"
) )
var logger = ethlog.NewLogger("REPL") var repllogger = logger.NewLogger("REPL")
type Repl interface { type Repl interface {
Start() Start()
@ -42,7 +59,7 @@ func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
func (self *JSRepl) Start() { func (self *JSRepl) Start() {
if !self.running { if !self.running {
self.running = true self.running = true
logger.Infoln("init JS Console") repllogger.Infoln("init JS Console")
reader := bufio.NewReader(self.history) reader := bufio.NewReader(self.history)
for { for {
line, err := reader.ReadString('\n') line, err := reader.ReadString('\n')
@ -63,7 +80,7 @@ func (self *JSRepl) Stop() {
if self.running { if self.running {
self.running = false self.running = false
self.re.Stop() self.re.Stop()
logger.Infoln("exit JS Console") repllogger.Infoln("exit JS Console")
self.history.Close() self.history.Close()
} }
} }

View File

@ -1,3 +1,20 @@
// 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
package ethrepl package ethrepl
// #cgo darwin CFLAGS: -I/usr/local/opt/readline/include // #cgo darwin CFLAGS: -I/usr/local/opt/readline/include
@ -9,6 +26,7 @@ package ethrepl
// #include <readline/history.h> // #include <readline/history.h>
import "C" import "C"
import ( import (
"fmt"
"os" "os"
"os/signal" "os/signal"
"strings" "strings"
@ -118,6 +136,9 @@ func (self *JSRepl) PrintValue(v interface{}) {
method, _ := self.re.Vm.Get("prettyPrint") method, _ := self.re.Vm.Get("prettyPrint")
v, err := self.re.Vm.ToValue(v) v, err := self.re.Vm.ToValue(v)
if err == nil { if err == nil {
method.Call(method, v) val, err := method.Call(method, v)
if err == nil {
fmt.Printf("%v", val)
}
} }
} }

View File

@ -0,0 +1,92 @@
// 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
package ethrepl
import (
"bufio"
"fmt"
"os"
"strings"
)
func (self *JSRepl) read() {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Printf(self.prompt)
str, _, err := reader.ReadLine()
if err != nil {
fmt.Println("Error reading input", err)
} else {
if string(str) == "exit" {
self.Stop()
break
} else {
self.parseInput(string(str))
}
}
}
}
func addHistory(s string) {
}
func printColored(outputVal string) {
for outputVal != "" {
codePart := ""
if strings.HasPrefix(outputVal, "\033[32m") {
codePart = "\033[32m"
changeColor(2)
}
if strings.HasPrefix(outputVal, "\033[1m\033[30m") {
codePart = "\033[1m\033[30m"
changeColor(8)
}
if strings.HasPrefix(outputVal, "\033[31m") {
codePart = "\033[31m"
changeColor(red)
}
if strings.HasPrefix(outputVal, "\033[35m") {
codePart = "\033[35m"
changeColor(5)
}
if strings.HasPrefix(outputVal, "\033[0m") {
codePart = "\033[0m"
resetColorful()
}
textPart := outputVal[len(codePart):len(outputVal)]
index := strings.Index(textPart, "\033")
if index == -1 {
outputVal = ""
} else {
outputVal = textPart[index:len(textPart)]
textPart = textPart[0:index]
}
fmt.Printf("%v", textPart)
}
}
func (self *JSRepl) PrintValue(v interface{}) {
method, _ := self.re.Vm.Get("prettyPrint")
v, err := self.re.Vm.ToValue(v)
if err == nil {
val, err := method.Call(method, v)
if err == nil {
printColored(fmt.Sprintf("%v", val))
}
}
}

128
cmd/ethtest/main.go Normal file
View File

@ -0,0 +1,128 @@
/*
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>
* @date 2014
*
*/
package main
import (
"bytes"
"encoding/json"
"io/ioutil"
"log"
"os"
"strings"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/tests/helper"
)
type Account struct {
Balance string
Code string
Nonce string
Storage map[string]string
}
func StateObjectFromAccount(addr string, account Account) *state.StateObject {
obj := state.NewStateObject(ethutil.Hex2Bytes(addr))
obj.SetBalance(ethutil.Big(account.Balance))
if ethutil.IsHex(account.Code) {
account.Code = account.Code[2:]
}
obj.Code = ethutil.Hex2Bytes(account.Code)
obj.Nonce = ethutil.Big(account.Nonce).Uint64()
return obj
}
type VmTest struct {
Callcreates interface{}
Env map[string]string
Exec map[string]string
Gas string
Out string
Post map[string]Account
Pre map[string]Account
}
func RunVmTest(js string) (failed int) {
tests := make(map[string]VmTest)
data, _ := ioutil.ReadAll(strings.NewReader(js))
err := json.Unmarshal(data, &tests)
if err != nil {
log.Fatalln(err)
}
for name, test := range tests {
state := state.New(helper.NewTrie())
for addr, account := range test.Pre {
obj := StateObjectFromAccount(addr, account)
state.SetStateObject(obj)
}
ret, _, gas, err := helper.RunVm(state, test.Env, test.Exec)
// When an error is returned it doesn't always mean the tests fails.
// Have to come up with some conditional failing mechanism.
if err != nil {
log.Println(err)
}
rexp := helper.FromHex(test.Out)
if bytes.Compare(rexp, ret) != 0 {
log.Printf("%s's return failed. Expected %x, got %x\n", name, rexp, ret)
failed = 1
}
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 {
obj := state.GetStateObject(helper.FromHex(addr))
for addr, value := range account.Storage {
v := obj.GetState(helper.FromHex(addr)).Bytes()
vexp := helper.FromHex(value)
if bytes.Compare(v, vexp) != 0 {
log.Printf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address()[0:4], addr, vexp, v, ethutil.BigD(vexp), ethutil.BigD(v))
failed = 1
}
}
}
}
return
}
func main() {
helper.Logger.SetLogLevel(5)
if len(os.Args) == 1 {
log.Fatalln("no json supplied")
}
os.Exit(RunVmTest(os.Args[1]))
}

1
cmd/evm/code.txt Normal file
View File

@ -0,0 +1 @@
60006102ff5360003560001a60008114156103395760013560405260216040516020025990590160009052606052604051602002816060513760405160200281019050506002604051121561005957604051602002606051f35b604051602002599059016000905260a052600060c052604051602002599059016000905260e0526000610100526001610120525b604051610120511215610109576060515161012051602002606051015112156100d8576101205160200260605101516101005160200260e051015260016101005101610100526100f9565b61012051602002606051015160c05160200260a0510152600160c0510160c0525b600161012051016101205261008d565b60216020599059016000905260c051808252806020028301925050602082015990590160009052600081538151600182015260218101825160200260a0518260005b8381101561016657808301518186015260208101905061014b565b50505050825160200281019050604059905901600090526102405281610240515283602061024051015261024051905090509050905060c05160200280599059016000905281816020850151855160003060195a03f1508090509050905060a05260216020599059016000905261010051808252806020028301925050602082015990590160009052600081538151600182015260218101825160200260e0518260005b8381101561022557808301518186015260208101905061020a565b50505050825160200281019050604059905901600090526102c052816102c051528360206102c05101526102c05190509050905090506101005160200280599059016000905281816020850151855160003060195a03f1508090509050905060e05260405160200259905901600090526102e0526000610120525b610100516101205112156102d7576101205160200260e0510151610120516020026102e051015260016101205101610120526102a0565b60605151610100516020026102e05101526000610120525b60c05161012051121561032d576101205160200260a05101516101205160016101005101016020026102e051015260016101205101610120526102ef565b6040516020026102e051f35b50

1
cmd/evm/input.txt Normal file

File diff suppressed because one or more lines are too long

164
cmd/evm/main.go Normal file
View File

@ -0,0 +1,164 @@
/*
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>
* @date 2014
*
*/
package main
import (
"flag"
"fmt"
"log"
"math/big"
"os"
"runtime"
"time"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/vm"
)
var (
code = flag.String("code", "", "evm code")
loglevel = flag.Int("log", 4, "log level")
gas = flag.String("gas", "1000000000", "gas amount")
price = flag.String("price", "0", "gas price")
value = flag.String("value", "0", "tx value")
dump = flag.Bool("dump", false, "dump state after run")
data = flag.String("data", "", "data")
)
func perr(v ...interface{}) {
fmt.Println(v...)
//os.Exit(1)
}
func main() {
flag.Parse()
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(*loglevel)))
ethutil.ReadConfig("/tmp/evmtest", "/tmp/evm", "")
db, _ := ethdb.NewMemDatabase()
statedb := state.New(trie.New(db, ""))
sender := statedb.NewStateObject([]byte("sender"))
receiver := statedb.NewStateObject([]byte("receiver"))
//receiver.SetCode([]byte(*code))
receiver.SetCode(ethutil.Hex2Bytes(*code))
vmenv := NewEnv(statedb, []byte("evmuser"), ethutil.Big(*value))
tstart := time.Now()
ret, e := vmenv.Call(sender, receiver.Address(), ethutil.Hex2Bytes(*data), ethutil.Big(*gas), ethutil.Big(*price), ethutil.Big(*value))
logger.Flush()
if e != nil {
perr(e)
}
if *dump {
fmt.Println(string(statedb.Dump()))
}
var mem runtime.MemStats
runtime.ReadMemStats(&mem)
fmt.Printf("vm took %v\n", time.Since(tstart))
fmt.Printf(`alloc: %d
tot alloc: %d
no. malloc: %d
heap alloc: %d
heap objs: %d
num gc: %d
`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC)
fmt.Printf("%x\n", ret)
}
type VMEnv struct {
state *state.StateDB
block *types.Block
transactor []byte
value *big.Int
depth int
Gas *big.Int
time int64
}
func NewEnv(state *state.StateDB, transactor []byte, value *big.Int) *VMEnv {
return &VMEnv{
state: state,
transactor: transactor,
value: value,
time: time.Now().Unix(),
}
}
func (self *VMEnv) State() *state.StateDB { return self.state }
func (self *VMEnv) Origin() []byte { return self.transactor }
func (self *VMEnv) BlockNumber() *big.Int { return ethutil.Big0 }
func (self *VMEnv) PrevHash() []byte { return make([]byte, 32) }
func (self *VMEnv) Coinbase() []byte { return self.transactor }
func (self *VMEnv) Time() int64 { return self.time }
func (self *VMEnv) Difficulty() *big.Int { return ethutil.Big1 }
func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) }
func (self *VMEnv) Value() *big.Int { return self.value }
func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) }
func (self *VMEnv) Depth() int { return 0 }
func (self *VMEnv) SetDepth(i int) { self.depth = i }
func (self *VMEnv) AddLog(log state.Log) {
self.state.AddLog(log)
}
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
return vm.Transfer(from, to, amount)
}
func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *core.Execution {
evm := vm.New(self, vm.DebugVmTy)
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) {
exe := self.vm(addr, data, gas, price, value)
ret, err := exe.Call(addr, caller)
self.Gas = exe.Gas
return ret, err
}
func (self *VMEnv) CallCode(caller vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
exe := self.vm(caller.Address(), data, gas, price, value)
return exe.Call(addr, caller)
}
func (self *VMEnv) Create(caller vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ClosureRef) {
exe := self.vm(addr, data, gas, price, value)
return exe.Create(caller)
}

View File

Before

Width:  |  Height:  |  Size: 1004 B

After

Width:  |  Height:  |  Size: 1004 B

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 905 B

After

Width:  |  Height:  |  Size: 905 B

View File

@ -1,3 +1,20 @@
// 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
var bigInt = (function () { var bigInt = (function () {
var base = 10000000, logBase = 7; var base = 10000000, logBase = 7;
var sign = { var sign = {

14
cmd/mist/assets/ext/eth.js/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
# 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
/tmp
*/**/*un~
*un~
.DS_Store
*/**/.DS_Store
ethereum/ethereum
ethereal/ethereal

View File

@ -0,0 +1,18 @@
# 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
```

View File

@ -0,0 +1,70 @@
(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;
}
})();

View File

@ -0,0 +1,33 @@
<!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>

View File

@ -0,0 +1,432 @@
(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);

View File

@ -0,0 +1,27 @@
(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;
}
})();

View File

@ -0,0 +1,51 @@
(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;
}
})();

View File

@ -1,3 +1,20 @@
// 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 // Main Ethereum library
window.eth = { window.eth = {
prototype: Object(), prototype: Object(),

View File

@ -1,3 +1,20 @@
// 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
var ethx = { var ethx = {
prototype: Object, prototype: Object,

View File

@ -1,3 +1,20 @@
// 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
// The magic return variable. The magic return variable will be set during the execution of the QML call. // The magic return variable. The magic return variable will be set during the execution of the QML call.
(function(window) { (function(window) {
var Promise = window.Promise; var Promise = window.Promise;

View File

@ -0,0 +1,30 @@
// 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
// this function is included locally, but you can also include separately via a header definition
function request(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = (function(req) {
return function() {
if(req.readyState === 4) {
callback(req);
}
}
})(xhr);
xhr.open('GET', url, true);
xhr.send('');
}

View File

@ -0,0 +1,30 @@
// 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
function HandleMessage(data) {
var message;
try { message = JSON.parse(data) } catch(e) {};
if(message) {
switch(message.type) {
case "coinbase":
return eth.coinBase();
case "block":
return eth.blockByNumber(0);
}
}
}

View File

@ -0,0 +1,38 @@
// 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
window._messagingAdapter = function(data) {
navigator.qt.postMessage(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];
}
}
}
}

View File

@ -0,0 +1,8 @@
(function() {
if (typeof(Promise) === "undefined")
window.Promise = Q.Promise;
var eth = web3.eth;
web3.setProvider(new web3.providers.QtProvider());
})()

View File

@ -1,3 +1,20 @@
// 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
String.prototype.pad = function(l, r) { String.prototype.pad = function(l, r) {
if (r === undefined) { if (r === undefined) {
r = l r = l

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
cmd/mist/assets/miner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,3 +1,20 @@
// 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
// Helper function for generating pseudo callbacks and sending data to the QML part of the application // Helper function for generating pseudo callbacks and sending data to the QML part of the application
function postData(data, cb) { function postData(data, cb) {
data._seed = Math.floor(Math.random() * 1000000) data._seed = Math.floor(Math.random() * 1000000)

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 932 B

After

Width:  |  Height:  |  Size: 932 B

View File

@ -12,7 +12,6 @@ import "../ext/http.js" as Http
ApplicationWindow { ApplicationWindow {
id: root id: root
property alias miningButtonText: miningButton.text
property var ethx : Eth.ethx property var ethx : Eth.ethx
property var browser property var browser
@ -48,12 +47,12 @@ ApplicationWindow {
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("./webapp.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/transaction.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
addPlugin("./views/chain.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/chain.qml", {noAdd: true, close: false, section: "legacy"});
addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"});
addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"});
addPlugin("./views/javascript.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"});
addPlugin("./views/jeffcoin/jeffcoin.qml", {noAdd: true, close: false, section: "apps"}) addPlugin("./views/jeffcoin/jeffcoin.qml", {noAdd: true, close: false, section: "apps"})
@ -253,29 +252,18 @@ ApplicationWindow {
} }
statusBar: StatusBar { statusBar: StatusBar {
height: 32 //height: 32
id: statusBar id: statusBar
RowLayout { Label {
Button { //y: 6
id: miningButton id: walletValueLabel
text: "Start Mining"
onClicked: {
gui.toggleMining()
}
}
RowLayout { font.pixelSize: 10
Label { styleColor: "#797979"
id: walletValueLabel
font.pixelSize: 10
styleColor: "#797979"
}
}
} }
Label { Label {
y: 6 //y: 6
objectName: "miningLabel" objectName: "miningLabel"
visible: true visible: true
font.pixelSize: 10 font.pixelSize: 10
@ -284,7 +272,7 @@ ApplicationWindow {
} }
Label { Label {
y: 6 //y: 6
id: lastBlockLabel id: lastBlockLabel
objectName: "lastBlockLabel" objectName: "lastBlockLabel"
visible: true visible: true
@ -298,14 +286,14 @@ ApplicationWindow {
id: downloadIndicator id: downloadIndicator
value: 0 value: 0
objectName: "downloadIndicator" objectName: "downloadIndicator"
y: 3 y: -4
x: statusBar.width / 2 - this.width / 2 x: statusBar.width / 2 - this.width / 2
width: 160 width: 160
} }
Label { Label {
objectName: "downloadLabel" objectName: "downloadLabel"
y: 7 //y: 7
anchors.left: downloadIndicator.right anchors.left: downloadIndicator.right
anchors.leftMargin: 5 anchors.leftMargin: 5
font.pixelSize: 10 font.pixelSize: 10
@ -315,7 +303,7 @@ ApplicationWindow {
RowLayout { RowLayout {
id: peerGroup id: peerGroup
y: 7 //y: 7
anchors.right: parent.right anchors.right: parent.right
MouseArea { MouseArea {
onDoubleClicked: peerWindow.visible = true onDoubleClicked: peerWindow.visible = true
@ -324,14 +312,9 @@ ApplicationWindow {
Label { Label {
id: peerLabel id: peerLabel
font.pixelSize: 8 font.pixelSize: 10
text: "0 / 0" text: "0 / 0"
} }
Image {
id: peerImage
width: 10; height: 10
source: "../network.png"
}
} }
} }
@ -363,12 +346,7 @@ ApplicationWindow {
view.visible = false view.visible = false
view.anchors.fill = mainView view.anchors.fill = mainView
if( !view.hasOwnProperty("iconSource") ) { var menuItem = menu.createMenuItem(view, options);
console.log("Could not load plugin. Property 'iconSourc' not found on view.");
return;
}
var menuItem = menu.createMenuItem(view.iconSource, view, options);
if( view.hasOwnProperty("menuItem") ) { if( view.hasOwnProperty("menuItem") ) {
view.menuItem = menuItem; view.menuItem = menuItem;
} }
@ -525,7 +503,7 @@ ApplicationWindow {
} }
} }
function createMenuItem(icon, view, options) { function createMenuItem(view, options) {
if(options === undefined) { if(options === undefined) {
options = {}; options = {};
} }
@ -547,7 +525,10 @@ ApplicationWindow {
comp.view = view comp.view = view
comp.title = view.title comp.title = view.title
comp.icon = view.iconSource
if(view.hasOwnProperty("iconSource")) {
comp.icon = view.iconSource;
}
comp.closable = options.close; comp.closable = options.close;
return comp return comp
@ -805,8 +786,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
@ -816,7 +797,7 @@ ApplicationWindow {
smooth: true smooth: true
source: "../facet.png" source: "../facet.png"
x: 10 x: 10
y: 10 y: 30
} }
Text { Text {
@ -825,7 +806,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>"
} }
} }
@ -889,7 +870,7 @@ ApplicationWindow {
pastPeers.append({text: ips.get(i)}) pastPeers.append({text: ips.get(i)})
} }
pastPeers.insert(0, {text: "poc-6.ethdev.com:30303"}) pastPeers.insert(0, {text: "poc-7.ethdev.com:30303"})
} }
} }

View File

@ -8,8 +8,7 @@ import Ethereum 1.0
Rectangle { Rectangle {
id: root id: root
property var title: "Network" property var title: "Block Chain"
property var iconSource: "../net.png"
property var menuItem property var menuItem
objectName: "chainView" objectName: "chainView"
@ -64,12 +63,12 @@ Rectangle {
Menu { Menu {
id: contextMenu id: contextMenu
property var row; property var row
MenuItem { MenuItem {
text: "Details" text: "Details"
onTriggered: { onTriggered: {
popup.visible = true popup.visible = true
popup.setDetails(blockModel.get(this.row)) popup.setDetails(blockModel.get(contextMenu.row))
} }
} }
@ -78,7 +77,7 @@ Rectangle {
MenuItem { MenuItem {
text: "Copy" text: "Copy"
onTriggered: { onTriggered: {
copyToClipboard(blockModel.get(this.row).hash) copyToClipboard(blockModel.get(contextMenu.row).hash)
} }
} }
@ -86,7 +85,7 @@ Rectangle {
text: "Dump State" text: "Dump State"
onTriggered: { onTriggered: {
generalFileDialog.show(false, function(path) { generalFileDialog.show(false, function(path) {
var hash = blockModel.get(this.row).hash; var hash = blockModel.get(contextMenu.row).hash;
gui.dumpState(hash, path); gui.dumpState(hash, path);
}); });
@ -102,22 +101,18 @@ Rectangle {
initial = false initial = false
} }
/*
var txs = JSON.parse(block.transactions);
if(txs != null){
amount = txs.length
}
*/
var txs = block.transactions;
var amount = block.transactions.length; var amount = block.transactions.length;
var txs = [];
for(var i = 0; i < block.transactions.length; i++) {
var tx = JSON.parse(block.transactions.getAsJson(i));
txs.push(tx);
}
if(initial){ if(initial){
blockModel.append({size: block.size, number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) blockModel.append({raw: block.raw, bloom: block.bloom, size: block.size, number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
} else { } else {
blockModel.insert(0, {size: block.size, number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)}) blockModel.insert(0, {bloom: block.bloom, size: block.size, number: block.number, name: block.name, gasLimit: block.gasLimit, gasUsed: block.gasUsed, coinbase: block.coinbase, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
} }
//root.secondary.text = "#" + block.number;
} }
Window { Window {
@ -141,6 +136,7 @@ Rectangle {
Text { text: '<h3>Block details</h3>'; color: "#F2F2F2"} Text { text: '<h3>Block details</h3>'; color: "#F2F2F2"}
Text { text: '<b>Block number:</b> ' + number + " (Size: " + size + ")"; color: "#F2F2F2"} Text { text: '<b>Block number:</b> ' + number + " (Size: " + size + ")"; color: "#F2F2F2"}
Text { text: '<b>Hash:</b> ' + hash; color: "#F2F2F2"} Text { text: '<b>Hash:</b> ' + hash; color: "#F2F2F2"}
Text { text: '<b>Bloom:</b> ' + bloom; color: "#F2F2F2"}
Text { text: '<b>Coinbase:</b> &lt;' + name + '&gt; ' + coinbase; color: "#F2F2F2"} Text { text: '<b>Coinbase:</b> &lt;' + name + '&gt; ' + coinbase; color: "#F2F2F2"}
Text { text: '<b>Block found at:</b> ' + prettyTime; color: "#F2F2F2"} Text { text: '<b>Block found at:</b> ' + prettyTime; color: "#F2F2F2"}
Text { text: '<b>Gas used:</b> ' + gasUsed + " / " + gasLimit; color: "#F2F2F2"} Text { text: '<b>Gas used:</b> ' + gasUsed + " / " + gasLimit; color: "#F2F2F2"}
@ -215,7 +211,7 @@ Rectangle {
anchors.topMargin: 10 anchors.topMargin: 10
text: "Debug contract" text: "Debug contract"
onClicked: { onClicked: {
if(tx.createsContract){ if(tx && tx.createsContract){
eth.startDbWithCode(tx.rawData) eth.startDbWithCode(tx.rawData)
}else { }else {
eth.startDbWithContractAndData(tx.address, tx.rawData) eth.startDbWithContractAndData(tx.address, tx.rawData)
@ -227,11 +223,17 @@ Rectangle {
text: "Contract" text: "Contract"
anchors.top: contractLabel.bottom anchors.top: contractLabel.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: popup.bottom anchors.right: parent.right
wrapMode: Text.Wrap wrapMode: Text.Wrap
width: parent.width - 30
height: 80 height: 80
anchors.leftMargin: 10 }
TextArea {
id: dumpData
anchors.top: contractData.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 300
} }
} }
property var transactionModel: ListModel { property var transactionModel: ListModel {
@ -240,19 +242,20 @@ Rectangle {
property var singleBlock: ListModel { property var singleBlock: ListModel {
id: singleBlock id: singleBlock
} }
function setDetails(block){ function setDetails(bl){
singleBlock.set(0,block) singleBlock.set(0, bl)
popup.height = 300 popup.height = 300
transactionModel.clear() transactionModel.clear()
if(block.txs !== undefined){ if(bl.txs !== undefined){
for(var i = 0; i < block.txs.length; i++) { for(var i = 0; i < bl.txs.count; i++) {
transactionModel.insert(0, block.txs.get(i)) transactionModel.insert(0, bl.txs.get(i))
} }
if(block.txs.length > 0 && block.txs.get(0).data){ if(bl.txs.count > 0 && bl.txs.get(0).data){
popup.showContractData(block.txs.get(0)) popup.showContractData(bl.txs.get(0))
} }
} }
txView.forceActiveFocus() txView.forceActiveFocus()
dumpData.text = bl.raw;
} }
} }
} }

View File

@ -7,7 +7,6 @@ import QtQuick.Controls.Styles 1.1
import Ethereum 1.0 import Ethereum 1.0
Rectangle { Rectangle {
property var iconSource: "../tx.png"
property var title: "Transactions" property var title: "Transactions"
property var menuItem property var menuItem

View File

@ -7,8 +7,7 @@ import QtQuick.Controls.Styles 1.1
import Ethereum 1.0 import Ethereum 1.0
Rectangle { Rectangle {
property var title: "Information" property var title: "Debug Info"
property var iconSource: "../heart.png"
property var menuItem property var menuItem
objectName: "infoView" objectName: "infoView"

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -0,0 +1,254 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Dialogs 1.0;
import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import Ethereum 1.0
Rectangle {
id: root
property var title: "Miner"
property var iconSource: "../miner.png"
property var menuItem
color: "#00000000"
ColumnLayout {
spacing: 10
anchors.fill: parent
Rectangle {
id: mainPane
color: "#00000000"
anchors {
top: parent.top
bottom: localTxPane.top
left: parent.left
right: parent.right
}
Rectangle {
id: menu
height: 25
anchors {
left: parent.left
}
RowLayout {
id: tools
anchors {
left: parent.left
right: parent.right
}
Button {
text: "Start"
onClicked: {
eth.setGasPrice(minGasPrice.text || "10000000000000");
if (eth.toggleMining()) {
this.text = "Stop";
} else {
this.text = "Start";
}
}
}
Rectangle {
anchors.top: parent.top
anchors.topMargin: 2
width: 200
TextField {
id: minGasPrice
placeholderText: "Min Gas: 10000000000000"
width: 200
validator: RegExpValidator { regExp: /\d*/ }
}
}
}
}
Column {
anchors {
left: parent.left
right: parent.right
top: menu.bottom
topMargin: 5
}
Text {
text: "<b>Merged mining options</b>"
}
TableView {
id: mergedMiningTable
height: 300
anchors {
left: parent.left
right: parent.right
}
Component {
id: checkBoxDelegate
Item {
id: test
CheckBox {
anchors.fill: parent
checked: styleData.value
onClicked: {
var model = mergedMiningModel.get(styleData.row)
if (this.checked) {
model.id = txModel.createLocalTx(model.address, "0", "5000", "0", "")
} else {
txModel.removeWithId(model.id);
model.id = 0;
}
}
}
}
}
TableViewColumn{ role: "checked" ; title: "" ; width: 40 ; delegate: checkBoxDelegate }
TableViewColumn{ role: "name" ; title: "Name" ; width: 480 }
model: ListModel {
objectName: "mergedMiningModel"
id: mergedMiningModel
function addMergedMiningOption(model) {
this.append(model);
}
}
Component.onCompleted: {
/*
// XXX Temp. replace with above eventually
var tmpItems = ["JEVCoin", "Some coin", "Other coin", "Etc coin"];
var address = "e6716f9544a56c530d868e4bfbacb172315bdead";
for (var i = 0; i < tmpItems.length; i++) {
mergedMiningModel.append({checked: false, name: tmpItems[i], address: address, id: 0, itemId: i});
}
*/
}
}
}
}
Rectangle {
id: localTxPane
color: "#ececec"
border.color: "#cccccc"
border.width: 1
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: 300
ColumnLayout {
spacing: 10
anchors.fill: parent
RowLayout {
id: newLocalTx
anchors {
left: parent.left
leftMargin: 5
top: parent.top
topMargin: 5
bottomMargin: 5
}
Text {
text: "Local tx"
}
Rectangle {
width: 250
color: "#00000000"
anchors.top: parent.top
anchors.topMargin: 2
TextField {
id: to
placeholderText: "To"
width: 250
validator: RegExpValidator { regExp: /[abcdefABCDEF1234567890]*/ }
}
}
TextField {
property var defaultGas: "5000"
id: gas
placeholderText: "Gas"
text: defaultGas
validator: RegExpValidator { regExp: /\d*/ }
}
TextField {
id: gasPrice
placeholderText: "Price"
validator: RegExpValidator { regExp: /\d*/ }
}
TextField {
id: value
placeholderText: "Amount"
text: "0"
validator: RegExpValidator { regExp: /\d*/ }
}
TextField {
id: data
placeholderText: "Data"
validator: RegExpValidator { regExp: /[abcdefABCDEF1234567890]*/ }
}
Button {
text: "Create"
onClicked: {
if (to.text.length == 40 && gasPrice.text.length != 0 && value.text.length != 0 && gas.text.length != 0) {
txModel.createLocalTx(to.text, gasPrice.text, gas.text, value.text, data.text);
to.text = ""; gasPrice.text = "";
gas.text = gas.defaultGas;
value.text = "0"
}
}
}
}
TableView {
id: txTableView
anchors {
top: newLocalTx.bottom
topMargin: 5
left: parent.left
right: parent.right
bottom: parent.bottom
}
TableViewColumn{ role: "to" ; title: "To" ; width: 480 }
TableViewColumn{ role: "gas" ; title: "Gas" ; width: 100 }
TableViewColumn{ role: "gasPrice" ; title: "Gas Price" ; width: 100 }
TableViewColumn{ role: "value" ; title: "Amount" ; width: 100 }
TableViewColumn{ role: "data" ; title: "Data" ; width: 100 }
model: ListModel {
id: txModel
Component.onCompleted: {
}
function removeWithId(id) {
for (var i = 0; i < this.count; i++) {
if (txModel.get(i).id == id) {
this.remove(i);
eth.removeLocalTransaction(id)
break;
}
}
}
function createLocalTx(to, gasPrice, gas, value, data) {
var id = eth.addLocalTransaction(to, data, gas, gasPrice, value)
txModel.insert(0, {to: to, gas: gas, gasPrice: gasPrice, value: value, data: data, id: id});
return id
}
}
}
}
}
}
}

View File

@ -8,7 +8,6 @@ import Ethereum 1.0
Rectangle { Rectangle {
property var title: "Pending Transactions" property var title: "Pending Transactions"
property var iconSource: "../tx.png"
property var menuItem property var menuItem
objectName: "pendingTxView" objectName: "pendingTxView"

View File

@ -7,8 +7,7 @@ import QtQuick.Controls.Styles 1.1
import Ethereum 1.0 import Ethereum 1.0
Rectangle { Rectangle {
property var iconSource: "../new.png" property var title: "New Transaction"
property var title: "New transaction"
property var menuItem property var menuItem
objectName: "newTxView" objectName: "newTxView"
@ -115,7 +114,7 @@ Rectangle {
width: 50 width: 50
validator: RegExpValidator { regExp: /\d*/ } validator: RegExpValidator { regExp: /\d*/ }
placeholderText: "Gas" placeholderText: "Gas"
text: "500" text: "5000"
} }
Label { Label {
id: atLabel id: atLabel

View File

@ -16,7 +16,13 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
function onReady() { function onReady() {
menuItem.secondaryTitle = eth.numberToHuman(eth.balanceAt(eth.key().address)) setBalance()
}
function setBalance() {
balance.text = "<b>Balance</b>: " + eth.numberToHuman(eth.balanceAt(eth.key().address))
if(menuItem)
menuItem.secondaryTitle = eth.numberToHuman(eth.balanceAt(eth.key().address))
} }
ListModel { ListModel {
@ -39,7 +45,6 @@ Rectangle {
Text { Text {
id: balance id: balance
text: "<b>Balance</b>: " + eth.numberToHuman(eth.balanceAt(eth.key().address))
font.pixelSize: 24 font.pixelSize: 24
anchors { anchors {
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter
@ -126,7 +131,6 @@ Rectangle {
var value = txValue.text + denomModel.get(valueDenom.currentIndex).zeros; var value = txValue.text + denomModel.get(valueDenom.currentIndex).zeros;
var gasPrice = "10000000000000" var gasPrice = "10000000000000"
var res = eth.transact({from: eth.key().privateKey, to: txTo.text, value: value, gas: "500", gasPrice: gasPrice}) var res = eth.transact({from: eth.key().privateKey, to: txTo.text, value: value, gas: "500", gasPrice: gasPrice})
console.log(res)
} }
} }
} }
@ -144,24 +148,35 @@ Rectangle {
id: txTableView id: txTableView
anchors.fill : parent anchors.fill : parent
TableViewColumn{ role: "num" ; title: "#" ; width: 30 } TableViewColumn{ role: "num" ; title: "#" ; width: 30 }
TableViewColumn{ role: "from" ; title: "From" ; width: 280 } TableViewColumn{ role: "from" ; title: "From" ; width: 340 }
TableViewColumn{ role: "to" ; title: "To" ; width: 280 } TableViewColumn{ role: "to" ; title: "To" ; width: 340 }
TableViewColumn{ role: "value" ; title: "Amount" ; width: 100 } TableViewColumn{ role: "value" ; title: "Amount" ; width: 100 }
model: ListModel { model: ListModel {
id: txModel id: txModel
Component.onCompleted: { Component.onCompleted: {
var filter = ethx.watch({latest: -1, from: eth.key().address}); var me = eth.key().address;
filter.changed(addTxs) var filterTo = ethx.watch({latest: -1, to: me});
var filterFrom = ethx.watch({latest: -1, from: me});
filterTo.changed(addTxs)
filterFrom.changed(addTxs)
addTxs(filter.messages()) addTxs(filterTo.messages())
addTxs(filterFrom.messages())
} }
function addTxs(messages) { function addTxs(messages) {
setBalance()
for(var i = 0; i < messages.length; i++) { for(var i = 0; i < messages.length; i++) {
var message = messages.get(i); var message = messages.get(i);
var to = eth.lookupName(message.to); var to = eth.lookupName(message.to);
var from = eth.lookupName(message.from); var from;
if(message.from.length == 0) {
from = "- MINED -";
} else {
from = eth.lookupName(message.from);
}
txModel.insert(0, {num: txModel.count, from: from, to: to, value: eth.numberToHuman(message.value)}) txModel.insert(0, {num: txModel.count, from: from, to: to, value: eth.numberToHuman(message.value)})
} }
} }

View File

@ -0,0 +1,413 @@
import QtQuick 2.0
import QtWebKit 3.0
import QtWebKit.experimental 1.0
import QtQuick.Controls 1.0;
import QtQuick.Controls.Styles 1.0
import QtQuick.Layouts 1.0;
import QtQuick.Window 2.1;
import Ethereum 1.0
Rectangle {
id: window
property var title: "Browser"
property var iconSource: "../browser.png"
property var menuItem
property alias url: webview.url
property alias webView: webview
property var cleanPath: false
property var open: function(url) {
if(!window.cleanPath) {
var uri = url;
if(!/.*\:\/\/.*/.test(uri)) {
uri = "http://" + uri;
}
var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/
if(reg.test(uri)) {
uri.replace(reg, function(match, pre, domain, path) {
uri = pre;
var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4));
var ip = [];
for(var i = 0, l = lookup.length; i < l; i++) {
ip.push(lookup.charCodeAt(i))
}
if(ip.length != 0) {
uri += lookup;
} else {
uri += domain;
}
uri += path;
});
}
window.cleanPath = true;
webview.url = uri;
//uriNav.text = uri.text.replace(/(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.\w{2,3})(.*)/, "$1$2<span style='color:#CCC'>$3</span>");
uriNav.text = uri;
} else {
// Prevent inf loop.
window.cleanPath = false;
}
}
Component.onCompleted: {
webview.url = "http://etherian.io"
}
signal messages(var messages, int id);
onMessages: {
// Bit of a cheat to get proper JSON
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
webview.postEvent("messages", [m, id]);
}
Item {
objectName: "root"
id: root
anchors.fill: parent
state: "inspectorShown"
RowLayout {
id: navBar
height: 40
anchors {
left: parent.left
right: parent.right
leftMargin: 7
}
Button {
id: back
onClicked: {
webview.goBack()
}
style: ButtonStyle {
background: Image {
source: "../back.png"
width: 30
height: 30
}
}
}
TextField {
anchors {
left: back.right
right: toggleInspector.left
leftMargin: 5
rightMargin: 5
}
text: "http://etherian.io"
id: uriNav
y: parent.height / 2 - this.height / 2
Keys.onReturnPressed: {
webview.url = this.text;
}
}
Button {
id: toggleInspector
anchors {
right: parent.right
}
iconSource: "../bug.png"
onClicked: {
if(inspector.visible == true){
inspector.visible = false
}else{
inspector.visible = true
inspector.url = webview.experimental.remoteInspectorUrl
}
}
}
}
WebView {
objectName: "webView"
id: webview
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
top: navBar.bottom
}
//property var cleanPath: false
onNavigationRequested: {
window.open(request.url.toString());
}
function sendMessage(data) {
webview.experimental.postMessage(JSON.stringify(data))
}
experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: 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/eth.js/main.js", "../ext/eth.js/qt.js", "../ext/setup.js"]
experimental.onMessageReceived: {
console.log("[onMessageReceived]: ", message.data)
// TODO move to messaging.js
var data = JSON.parse(message.data)
try {
switch(data.call) {
case "compile":
postData(data._id, eth.compile(data.args[0]))
break
case "coinbase":
postData(data._id, eth.coinBase())
case "account":
postData(data._id, eth.key().address);
case "isListening":
postData(data._id, eth.isListening())
break
case "isMining":
postData(data._id, eth.isMining())
break
case "peerCount":
postData(data._id, eth.peerCount())
break
case "countAt":
require(1)
postData(data._id, eth.txCountAt(data.args[0]))
break
case "codeAt":
require(1)
var code = eth.codeAt(data.args[0])
postData(data._id, code);
break
case "blockByNumber":
require(1)
var block = eth.blockByNumber(data.args[0])
postData(data._id, block)
break
case "blockByHash":
require(1)
var block = eth.blockByHash(data.args[0])
postData(data._id, block)
break
require(2)
var block = eth.blockByHash(data.args[0])
postData(data._id, block.transactions[data.args[1]])
break
case "transactionByHash":
case "transactionByNumber":
require(2)
var block;
if (data.call === "transactionByHash")
block = eth.blockByHash(data.args[0])
else
block = eth.blockByNumber(data.args[0])
var tx = block.transactions.get(data.args[1])
postData(data._id, tx)
break
case "uncleByHash":
case "uncleByNumber":
require(2)
var block;
if (data.call === "uncleByHash")
block = eth.blockByHash(data.args[0])
else
block = eth.blockByNumber(data.args[0])
var uncle = block.uncles.get(data.args[1])
postData(data._id, uncle)
break
case "transact":
require(5)
var tx = eth.transact(data.args)
postData(data._id, tx)
break
case "stateAt":
require(2);
var storage = eth.storageAt(data.args[0], data.args[1]);
postData(data._id, storage)
break
case "call":
require(1);
var ret = eth.call(data.args)
postData(data._id, ret)
break
case "balanceAt":
require(1);
postData(data._id, eth.balanceAt(data.args[0]));
break
case "watch":
require(2)
eth.watch(data.args[0], data.args[1])
case "disconnect":
require(1)
postData(data._id, null)
break;
case "messages":
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)
var id = eth.newFilterString(data.args[0])
postData(data._id, id);
break;
case "newFilter":
require(1)
var id = eth.newFilter(data.args[0])
postData(data._id, id);
break;
case "getMessages":
require(1);
var messages = eth.messages(data.args[0]);
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
postData(data._id, m);
break;
case "deleteFilter":
require(1);
eth.uninstallFilter(data.args[0])
break;
}
} catch(e) {
console.log(data.call + ": " + e)
postData(data._id, null);
}
}
function post(seed, data) {
postData(data._id, data)
}
function require(args, num) {
if(args.length < num) {
throw("required argument count of "+num+" got "+args.length);
}
}
function postData(seed, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _id: seed}))
}
function postEvent(event, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _event: event}))
}
function onWatchedCb(data, id) {
var messages = JSON.parse(data)
postEvent("watched:"+id, messages)
}
function onNewBlockCb(block) {
postEvent("block:new", block)
}
function onObjectChangeCb(stateObject) {
postEvent("object:"+stateObject.address(), stateObject)
}
function onStorageChangeCb(storageObject) {
var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
postEvent(ev, [storageObject.address, storageObject.value])
}
}
Rectangle {
id: sizeGrip
color: "gray"
visible: false
height: 10
anchors {
left: root.left
right: root.right
}
y: Math.round(root.height * 2 / 3)
MouseArea {
anchors.fill: parent
drag.target: sizeGrip
drag.minimumY: 0
drag.maximumY: root.height
drag.axis: Drag.YAxis
}
}
WebView {
id: inspector
visible: false
anchors {
left: root.left
right: root.right
top: sizeGrip.bottom
bottom: root.bottom
}
}
states: [
State {
name: "inspectorShown"
PropertyChanges {
target: inspector
}
}
]
}
}

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,16 +1,31 @@
// 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
package main package main
import ( import (
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"strconv" "strconv"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/utils"
) )
type plugin struct { type plugin struct {
@ -18,16 +33,8 @@ type plugin struct {
Path string `json:"path"` Path string `json:"path"`
} }
func (gui *Gui) Println(v ...interface{}) { // LogPrint writes to the GUI log.
gui.printLog(fmt.Sprintln(v...)) func (gui *Gui) LogPrint(level logger.LogLevel, msg string) {
}
func (gui *Gui) Printf(format string, v ...interface{}) {
gui.printLog(fmt.Sprintf(format, v...))
}
// Print function that logs directly to the GUI
func (gui *Gui) printLog(s string) {
/* /*
str := strings.TrimRight(s, "\n") str := strings.TrimRight(s, "\n")
lines := strings.Split(str, "\n") lines := strings.Split(str, "\n")
@ -38,12 +45,12 @@ func (gui *Gui) printLog(s string) {
} }
*/ */
} }
func (gui *Gui) Transact(recipient, value, gas, gasPrice, d string) (*ethpipe.JSReceipt, error) { func (gui *Gui) Transact(recipient, value, gas, gasPrice, d string) (string, error) {
var data string var data string
if len(recipient) == 0 { if len(recipient) == 0 {
code, err := ethutil.Compile(d, false) code, err := ethutil.Compile(d, false)
if err != nil { if err != nil {
return nil, err return "", err
} }
data = ethutil.Bytes2Hex(code) data = ethutil.Bytes2Hex(code)
} else { } else {
@ -62,18 +69,14 @@ func (gui *Gui) GetCustomIdentifier() string {
return gui.clientIdentity.GetCustomIdentifier() return gui.clientIdentity.GetCustomIdentifier()
} }
func (gui *Gui) ToggleTurboMining() { // functions that allow Gui to implement interface guilogger.LogSystem
gui.miner.ToggleTurbo() func (gui *Gui) SetLogLevel(level logger.LogLevel) {
}
// functions that allow Gui to implement interface ethlog.LogSystem
func (gui *Gui) SetLogLevel(level ethlog.LogLevel) {
gui.logLevel = level gui.logLevel = level
gui.stdLog.SetLogLevel(level) gui.stdLog.SetLogLevel(level)
gui.config.Save("loglevel", level) gui.config.Save("loglevel", level)
} }
func (gui *Gui) GetLogLevel() ethlog.LogLevel { func (gui *Gui) GetLogLevel() logger.LogLevel {
return gui.logLevel return gui.logLevel
} }
@ -100,18 +103,18 @@ func (self *Gui) DumpState(hash, path string) {
var stateDump []byte var stateDump []byte
if len(hash) == 0 { if len(hash) == 0 {
stateDump = self.eth.StateManager().CurrentState().Dump() stateDump = self.eth.ChainManager().State().Dump()
} else { } else {
var block *ethchain.Block var block *types.Block
if hash[0] == '#' { if hash[0] == '#' {
i, _ := strconv.Atoi(hash[1:]) i, _ := strconv.Atoi(hash[1:])
block = self.eth.BlockChain().GetBlockByNumber(uint64(i)) block = self.eth.ChainManager().GetBlockByNumber(uint64(i))
} else { } else {
block = self.eth.BlockChain().GetBlock(ethutil.Hex2Bytes(hash)) block = self.eth.ChainManager().GetBlock(ethutil.Hex2Bytes(hash))
} }
if block == nil { if block == nil {
logger.Infof("block err: not found %s\n", hash) guilogger.Infof("block err: not found %s\n", hash)
return return
} }
@ -120,29 +123,12 @@ func (self *Gui) DumpState(hash, path string) {
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)
if err != nil { if err != nil {
logger.Infoln("dump err: ", err) guilogger.Infoln("dump err: ", err)
return return
} }
defer file.Close() defer file.Close()
logger.Infof("dumped state (%s) to %s\n", hash, path) guilogger.Infof("dumped state (%s) to %s\n", hash, path)
file.Write(stateDump) file.Write(stateDump)
} }
func (gui *Gui) ToggleMining() {
var txt string
if gui.eth.Mining {
utils.StopMining(gui.eth)
txt = "Start mining"
gui.getObjectByName("miningLabel").Set("visible", false)
} else {
utils.StartMining(gui.eth)
gui.miner = utils.GetMiner()
txt = "Stop mining"
gui.getObjectByName("miningLabel").Set("visible", true)
}
gui.win.Root().Set("miningButtonText", txt)
}

View File

@ -1,3 +1,20 @@
// 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
package main package main
import ( import (
@ -7,11 +24,11 @@ import (
"strings" "strings"
"unicode" "unicode"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/eth-go/ethstate" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/eth-go/ethvm" "github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/vm"
"gopkg.in/qml.v1" "gopkg.in/qml.v1"
) )
@ -20,10 +37,10 @@ type DebuggerWindow struct {
engine *qml.Engine engine *qml.Engine
lib *UiLib lib *UiLib
vm *ethvm.Vm vm *vm.DebugVm
Db *Debugger Db *Debugger
state *ethstate.State state *state.StateDB
} }
func NewDebuggerWindow(lib *UiLib) *DebuggerWindow { func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
@ -37,7 +54,7 @@ func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
win := component.CreateWindow(nil) win := component.CreateWindow(nil)
w := &DebuggerWindow{engine: engine, win: win, lib: lib, vm: &ethvm.Vm{}} w := &DebuggerWindow{engine: engine, win: win, lib: lib, vm: &vm.DebugVm{}}
w.Db = NewDebugger(w) w.Db = NewDebugger(w)
return w return w
@ -64,7 +81,7 @@ func (self *DebuggerWindow) SetData(data string) {
func (self *DebuggerWindow) SetAsm(data []byte) { func (self *DebuggerWindow) SetAsm(data []byte) {
self.win.Root().Call("clearAsm") self.win.Root().Call("clearAsm")
dis := ethchain.Disassemble(data) dis := core.Disassemble(data)
for _, str := range dis { for _, str := range dis {
self.win.Root().Call("setAsm", str) self.win.Root().Call("setAsm", str)
} }
@ -124,28 +141,24 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
keyPair = self.lib.eth.KeyManager().KeyPair() keyPair = self.lib.eth.KeyManager().KeyPair()
) )
state := self.lib.eth.StateManager().TransState() statedb := self.lib.eth.ChainManager().TransState()
account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address()) account := self.lib.eth.ChainManager().TransState().GetAccount(keyPair.Address())
contract := ethstate.NewStateObject([]byte{0}) contract := statedb.NewStateObject([]byte{0})
contract.Balance = value contract.SetCode(script)
contract.SetBalance(value)
self.SetAsm(script) self.SetAsm(script)
block := self.lib.eth.BlockChain().CurrentBlock block := self.lib.eth.ChainManager().CurrentBlock()
callerClosure := ethvm.NewClosure(&ethstate.Message{}, account, contract, script, gas, gasPrice) env := utils.NewEnv(statedb, block, account.Address(), value)
env := utils.NewEnv(state, block, account.Address(), value)
vm := ethvm.New(env)
vm.Verbose = true
vm.Dbg = self.Db
self.vm = vm
self.Db.done = false
self.Logf("callsize %d", len(script)) self.Logf("callsize %d", len(script))
go func() { go func() {
ret, g, err := callerClosure.Call(vm, data) ret, err := env.Call(account, contract.Address(), data, gas, gasPrice, ethutil.Big0)
tot := new(big.Int).Mul(g, gasPrice) //ret, g, err := callerClosure.Call(evm, data)
self.Logf("gas usage %v total price = %v (%v)", g, tot, ethutil.CurrencyToString(tot)) tot := new(big.Int).Mul(env.Gas, gasPrice)
self.Logf("gas usage %v total price = %v (%v)", env.Gas, tot, ethutil.CurrencyToString(tot))
if err != nil { if err != nil {
self.Logln("exited with errors:", err) self.Logln("exited with errors:", err)
} else { } else {
@ -156,7 +169,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
} }
} }
state.Reset() statedb.Reset()
if !self.Db.interrupt { if !self.Db.interrupt {
self.Db.done = true self.Db.done = true
@ -251,13 +264,13 @@ type storeVal struct {
Key, Value string Key, Value string
} }
func (self *Debugger) BreakHook(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool { func (self *Debugger) BreakHook(pc int, op vm.OpCode, mem *vm.Memory, stack *vm.Stack, stateObject *state.StateObject) bool {
self.main.Logln("break on instr:", pc) self.main.Logln("break on instr:", pc)
return self.halting(pc, op, mem, stack, stateObject) return self.halting(pc, op, mem, stack, stateObject)
} }
func (self *Debugger) StepHook(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool { func (self *Debugger) StepHook(pc int, op vm.OpCode, mem *vm.Memory, stack *vm.Stack, stateObject *state.StateObject) bool {
return self.halting(pc, op, mem, stack, stateObject) return self.halting(pc, op, mem, stack, stateObject)
} }
@ -269,7 +282,7 @@ func (self *Debugger) BreakPoints() []int64 {
return self.breakPoints return self.breakPoints
} }
func (d *Debugger) halting(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool { func (d *Debugger) halting(pc int, op vm.OpCode, mem *vm.Memory, stack *vm.Stack, stateObject *state.StateObject) bool {
d.win.Root().Call("setInstruction", pc) d.win.Root().Call("setInstruction", pc)
d.win.Root().Call("clearMem") d.win.Root().Call("clearMem")
d.win.Root().Call("clearStack") d.win.Root().Call("clearStack")

53
cmd/mist/errors.go Normal file
View File

@ -0,0 +1,53 @@
// 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
package main
import (
"fmt"
"os"
"gopkg.in/qml.v1"
)
func ErrorWindow(err error) {
engine := qml.NewEngine()
component, e := engine.LoadString("local", qmlErr)
if e != nil {
fmt.Println("err:", err)
os.Exit(1)
}
win := component.CreateWindow(nil)
win.Root().ObjectByName("label").Set("text", err.Error())
win.Show()
win.Wait()
}
const qmlErr = `
import QtQuick 2.0; import QtQuick.Controls 1.0;
ApplicationWindow {
width: 600; height: 150;
flags: Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint
title: "Error"
Text {
x: parent.width / 2 - this.width / 2;
y: parent.height / 2 - this.height / 2;
objectName: "label";
}
}
`

143
cmd/mist/ext_app.go Normal file
View File

@ -0,0 +1,143 @@
// 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
package main
import (
"encoding/json"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/javascript"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/ui/qt"
"github.com/ethereum/go-ethereum/xeth"
"gopkg.in/qml.v1"
)
type AppContainer interface {
Create() error
Destroy()
Window() *qml.Window
Engine() *qml.Engine
NewBlock(*types.Block)
NewWatcher(chan bool)
Messages(state.Messages, string)
Post(string, int)
}
type ExtApplication struct {
*xeth.JSXEth
eth core.EthManager
events event.Subscription
watcherQuitChan chan bool
filters map[string]*core.Filter
container AppContainer
lib *UiLib
}
func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication {
return &ExtApplication{
JSXEth: xeth.NewJSXEth(lib.eth),
eth: lib.eth,
watcherQuitChan: make(chan bool),
filters: make(map[string]*core.Filter),
container: container,
lib: lib,
}
}
func (app *ExtApplication) run() {
// Set the "eth" api on to the containers context
context := app.container.Engine().Context()
context.SetVar("eth", app)
context.SetVar("ui", app.lib)
err := app.container.Create()
if err != nil {
guilogger.Errorln(err)
return
}
// Subscribe to events
mux := app.lib.eth.EventMux()
app.events = mux.Subscribe(core.NewBlockEvent{}, state.Messages(nil))
// Call the main loop
go app.mainLoop()
app.container.NewWatcher(app.watcherQuitChan)
win := app.container.Window()
win.Show()
win.Wait()
app.stop()
}
func (app *ExtApplication) stop() {
app.events.Unsubscribe()
// Kill the main loop
app.watcherQuitChan <- true
app.container.Destroy()
}
func (app *ExtApplication) mainLoop() {
for ev := range app.events.Chan() {
switch ev := ev.(type) {
case core.NewBlockEvent:
app.container.NewBlock(ev.Block)
case state.Messages:
for id, filter := range app.filters {
msgs := filter.FilterMessages(ev)
if len(msgs) > 0 {
app.container.Messages(msgs, id)
}
}
}
}
}
func (self *ExtApplication) Watch(filterOptions map[string]interface{}, identifier string) {
self.filters[identifier] = qt.NewFilterFromMap(filterOptions, self.eth)
}
func (self *ExtApplication) GetMessages(object map[string]interface{}) string {
filter := qt.NewFilterFromMap(object, self.eth)
messages := filter.Find()
var msgs []javascript.JSMessage
for _, m := range messages {
msgs = append(msgs, javascript.NewJSMessage(m))
}
b, err := json.Marshal(msgs)
if err != nil {
return "{\"error\":" + err.Error() + "}"
}
return string(b)
}

View File

@ -1,8 +1,26 @@
// 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
package main package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"log"
"os" "os"
"os/user" "os/user"
"path" "path"
@ -10,29 +28,34 @@ import (
"runtime" "runtime"
"bitbucket.org/kardianos/osext" "bitbucket.org/kardianos/osext"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/vm"
) )
var Identifier string var (
var KeyRing string Identifier string
var KeyStore string KeyRing string
var StartRpc bool KeyStore string
var RpcPort int StartRpc bool
var UseUPnP bool StartWebSockets bool
var OutboundPort string RpcPort int
var ShowGenesis bool UseUPnP bool
var AddPeer string OutboundPort string
var MaxPeer int ShowGenesis bool
var GenAddr bool AddPeer string
var UseSeed bool MaxPeer int
var SecretFile string GenAddr bool
var ExportDir string UseSeed bool
var NonInteractive bool SecretFile string
var Datadir string ExportDir string
var LogFile string NonInteractive bool
var ConfigFile string Datadir string
var DebugFile string LogFile string
var LogLevel int ConfigFile string
DebugFile string
LogLevel int
VmType int
)
// flags specific to gui client // flags specific to gui client
var AssetPath string var AssetPath string
@ -44,7 +67,7 @@ func defaultAssetPath() string {
// assume a debug build and use the source directory as // assume a debug build and use the source directory as
// asset directory. // asset directory.
pwd, _ := os.Getwd() pwd, _ := os.Getwd()
if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "mist") { if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist") {
assetPath = path.Join(pwd, "assets") assetPath = path.Join(pwd, "assets")
} else { } else {
switch runtime.GOOS { switch runtime.GOOS {
@ -75,14 +98,16 @@ func Init() {
flag.PrintDefaults() flag.PrintDefaults()
} }
flag.IntVar(&VmType, "vm", 0, "Virtual Machine type: 0-1: standard, debug")
flag.StringVar(&Identifier, "id", "", "Custom client identifier") flag.StringVar(&Identifier, "id", "", "Custom client identifier")
flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use") flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use")
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(&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(&GenAddr, "genaddr", false, "create a new priv/pub key") flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
@ -92,9 +117,13 @@ func Init() {
flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use") flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use")
flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file") flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
flag.IntVar(&LogLevel, "loglevel", int(ethlog.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
flag.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory") flag.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory")
flag.Parse() flag.Parse()
if VmType >= int(vm.MaxVmTy) {
log.Fatal("Invalid VM type ", VmType)
}
} }

View File

@ -1,3 +1,20 @@
// 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
package main package main
import "C" import "C"
@ -13,15 +30,15 @@ import (
"strings" "strings"
"time" "time"
"github.com/ethereum/eth-go" "github.com/ethereum/go-ethereum"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/eth-go/ethdb" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/eth-go/ethminer" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/eth-go/ethreact" "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/go-ethereum/wire"
"github.com/ethereum/eth-go/ethwire" "github.com/ethereum/go-ethereum/xeth"
"gopkg.in/qml.v1" "gopkg.in/qml.v1"
) )
@ -47,8 +64,17 @@ func LoadExtension(path string) (uintptr, error) {
return ptr.Interface().(uintptr), nil 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 logger = ethlog.NewLogger("GUI") var guilogger = logger.NewLogger("GUI")
type Gui struct { type Gui struct {
// The main application window // The main application window
@ -65,30 +91,30 @@ type Gui struct {
txDb *ethdb.LDBDatabase txDb *ethdb.LDBDatabase
logLevel ethlog.LogLevel logLevel logger.LogLevel
open bool open bool
pipe *ethpipe.JSPipe pipe *xeth.JSXEth
Session string Session string
clientIdentity *ethwire.SimpleClientIdentity clientIdentity *wire.SimpleClientIdentity
config *ethutil.ConfigManager config *ethutil.ConfigManager
plugins map[string]plugin plugins map[string]plugin
miner *ethminer.Miner miner *miner.Miner
stdLog ethlog.LogSystem stdLog logger.LogSystem
} }
// Create GUI, but doesn't start it // Create GUI, but doesn't start it
func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIdentity *ethwire.SimpleClientIdentity, session string, logLevel int) *Gui { func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIdentity *wire.SimpleClientIdentity, session string, logLevel int) *Gui {
db, err := ethdb.NewLDBDatabase("tx_database") db, err := ethdb.NewLDBDatabase("tx_database")
if err != nil { if err != nil {
panic(err) panic(err)
} }
pipe := ethpipe.NewJSPipe(ethereum) pipe := xeth.NewJSXEth(ethereum)
gui := &Gui{eth: ethereum, txDb: db, pipe: pipe, logLevel: ethlog.LogLevel(logLevel), Session: session, open: false, clientIdentity: clientIdentity, config: config, plugins: make(map[string]plugin)} 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)}
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)
@ -96,16 +122,17 @@ func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIden
} }
func (gui *Gui) Start(assetPath string) { func (gui *Gui) Start(assetPath string) {
defer gui.txDb.Close() defer gui.txDb.Close()
guilogger.Infoln("Starting GUI")
// Register ethereum functions // Register ethereum functions
qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{ qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{
Init: func(p *ethpipe.JSBlock, obj qml.Object) { p.Number = 0; p.Hash = "" }, Init: func(p *xeth.JSBlock, obj qml.Object) { p.Number = 0; p.Hash = "" },
}, { }, {
Init: func(p *ethpipe.JSTransaction, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" }, Init: func(p *xeth.JSTransaction, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" },
}, { }, {
Init: func(p *ethpipe.KeyVal, obj qml.Object) { p.Key = ""; p.Value = "" }, Init: func(p *xeth.KeyVal, obj qml.Object) { p.Key = ""; p.Value = "" },
}}) }})
// Create a new QML engine // Create a new QML engine
gui.engine = qml.NewEngine() gui.engine = qml.NewEngine()
@ -116,16 +143,6 @@ func (gui *Gui) Start(assetPath string) {
context.SetVar("gui", gui) context.SetVar("gui", gui)
context.SetVar("eth", gui.uiLib) context.SetVar("eth", gui.uiLib)
/*
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))
}
*/
// Load the main QML interface // Load the main QML interface
data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
@ -139,36 +156,35 @@ func (gui *Gui) Start(assetPath string) {
addlog = true addlog = true
} }
if err != nil { if err != nil {
logger.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)
panic(err) panic(err)
} }
logger.Infoln("Starting GUI")
gui.open = true gui.open = true
win.Show() win.Show()
// only add the gui logger 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 { if addlog {
ethlog.AddLogSystem(gui) logger.AddLogSystem(gui)
} }
win.Wait() win.Wait()
// need to silence gui logger 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)
gui.logLevel = ethlog.Silence gui.logLevel = logger.Silence
gui.open = false gui.open = false
} }
func (gui *Gui) Stop() { func (gui *Gui) Stop() {
if gui.open { if gui.open {
gui.logLevel = ethlog.Silence gui.logLevel = logger.Silence
gui.open = false gui.open = false
gui.win.Hide() gui.win.Hide()
} }
gui.uiLib.jsEngine.Stop() gui.uiLib.jsEngine.Stop()
logger.Infoln("Stopped") guilogger.Infoln("Stopped")
} }
func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) { func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
@ -213,51 +229,34 @@ func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
func (gui *Gui) ImportAndSetPrivKey(secret string) bool { func (gui *Gui) ImportAndSetPrivKey(secret string) bool {
err := gui.eth.KeyManager().InitFromString(gui.Session, 0, secret) err := gui.eth.KeyManager().InitFromString(gui.Session, 0, secret)
if err != nil { if err != nil {
logger.Errorln("unable to import: ", err) guilogger.Errorln("unable to import: ", err)
return false return false
} }
logger.Errorln("successfully imported: ", err) guilogger.Errorln("successfully imported: ", err)
return true return true
} }
func (gui *Gui) CreateAndSetPrivKey() (string, string, string, string) { func (gui *Gui) CreateAndSetPrivKey() (string, string, string, string) {
err := gui.eth.KeyManager().Init(gui.Session, 0, true) err := gui.eth.KeyManager().Init(gui.Session, 0, true)
if err != nil { if err != nil {
logger.Errorln("unable to create key: ", err) guilogger.Errorln("unable to create key: ", err)
return "", "", "", "" return "", "", "", ""
} }
return gui.eth.KeyManager().KeyPair().AsStrings() return gui.eth.KeyManager().KeyPair().AsStrings()
} }
func (gui *Gui) setInitialBlockChain() { func (gui *Gui) setInitialChain(ancientBlocks bool) {
sBlk := gui.eth.BlockChain().LastBlockHash sBlk := gui.eth.ChainManager().LastBlockHash()
blk := gui.eth.BlockChain().GetBlock(sBlk) blk := gui.eth.ChainManager().GetBlock(sBlk)
for ; blk != nil; blk = gui.eth.BlockChain().GetBlock(sBlk) { for ; blk != nil; blk = gui.eth.ChainManager().GetBlock(sBlk) {
sBlk = blk.PrevHash sBlk = blk.PrevHash
addr := gui.address()
// Loop through all transactions to see if we missed any while being offline
for _, tx := range blk.Transactions() {
if bytes.Compare(tx.Sender(), addr) == 0 || bytes.Compare(tx.Recipient, addr) == 0 {
if ok, _ := gui.txDb.Get(tx.Hash()); ok == nil {
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
}
}
}
gui.processBlock(blk, true) gui.processBlock(blk, true)
} }
} }
type address struct {
Name, Address string
}
func (gui *Gui) loadAddressBook() { func (gui *Gui) loadAddressBook() {
view := gui.getObjectByName("infoView") view := gui.getObjectByName("infoView")
view.Call("clearAddress")
nameReg := gui.pipe.World().Config().Get("NameReg") nameReg := gui.pipe.World().Config().Get("NameReg")
if nameReg != nil { if nameReg != nil {
nameReg.EachStorage(func(name string, value *ethutil.Value) { nameReg.EachStorage(func(name string, value *ethutil.Value) {
@ -270,8 +269,30 @@ func (gui *Gui) loadAddressBook() {
} }
} }
func (gui *Gui) insertTransaction(window string, tx *ethchain.Transaction) { func (self *Gui) loadMergedMiningOptions() {
pipe := ethpipe.New(gui.eth) view := self.getObjectByName("mergedMiningModel")
nameReg := self.pipe.World().Config().Get("MergeMining")
if nameReg != nil {
i := 0
nameReg.EachStorage(func(name string, value *ethutil.Value) {
if name[0] != 0 {
value.Decode()
view.Call("addMergedMiningOption", struct {
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) {
pipe := xeth.New(gui.eth)
nameReg := pipe.World().Config().Get("NameReg") nameReg := pipe.World().Config().Get("NameReg")
addr := gui.address() addr := gui.address()
@ -283,14 +304,14 @@ func (gui *Gui) insertTransaction(window string, tx *ethchain.Transaction) {
} }
var ( var (
ptx = ethpipe.NewJSTx(tx, pipe.World().State()) ptx = xeth.NewJSTx(tx, pipe.World().State())
send = nameReg.Storage(tx.Sender()) send = nameReg.Storage(tx.From())
rec = nameReg.Storage(tx.Recipient) rec = nameReg.Storage(tx.To())
s, r string s, r string
) )
if tx.CreatesContract() { if core.MessageCreatesContract(tx) {
rec = nameReg.Storage(tx.CreationAddress(pipe.World().State())) rec = nameReg.Storage(core.AddressFromMessage(tx))
} }
if send.Len() != 0 { if send.Len() != 0 {
@ -301,10 +322,10 @@ func (gui *Gui) insertTransaction(window string, tx *ethchain.Transaction) {
if rec.Len() != 0 { if rec.Len() != 0 {
r = strings.Trim(rec.Str(), "\x00") r = strings.Trim(rec.Str(), "\x00")
} else { } else {
if tx.CreatesContract() { if core.MessageCreatesContract(tx) {
r = ethutil.Bytes2Hex(tx.CreationAddress(pipe.World().State())) r = ethutil.Bytes2Hex(core.AddressFromMessage(tx))
} else { } else {
r = ethutil.Bytes2Hex(tx.Recipient) r = ethutil.Bytes2Hex(tx.To())
} }
} }
ptx.Sender = s ptx.Sender = s
@ -318,9 +339,9 @@ func (gui *Gui) insertTransaction(window string, tx *ethchain.Transaction) {
} }
func (gui *Gui) readPreviousTransactions() { func (gui *Gui) readPreviousTransactions() {
it := gui.txDb.Db().NewIterator(nil, nil) it := gui.txDb.NewIterator()
for it.Next() { for it.Next() {
tx := ethchain.NewTransactionFromBytes(it.Value()) tx := types.NewTransactionFromBytes(it.Value())
gui.insertTransaction("post", tx) gui.insertTransaction("post", tx)
@ -328,9 +349,9 @@ func (gui *Gui) readPreviousTransactions() {
it.Release() it.Release()
} }
func (gui *Gui) processBlock(block *ethchain.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.pipe.World().Config().Get("NameReg").Storage(block.Coinbase).Str(), "\x00")
b := ethpipe.NewJSBlock(block) b := xeth.NewJSBlock(block)
b.Name = name b.Name = name
gui.getObjectByName("chainView").Call("addBlock", b, initial) gui.getObjectByName("chainView").Call("addBlock", b, initial)
@ -360,106 +381,96 @@ func (self *Gui) getObjectByName(objectName string) qml.Object {
func (gui *Gui) update() { func (gui *Gui) update() {
// We have to wait for qml to be done loading all the windows. // We have to wait for qml to be done loading all the windows.
for !gui.qmlDone { for !gui.qmlDone {
time.Sleep(500 * time.Millisecond) time.Sleep(300 * time.Millisecond)
} }
go func() { go func() {
go gui.setInitialBlockChain() go gui.setInitialChain(false)
gui.loadAddressBook() gui.loadAddressBook()
gui.loadMergedMiningOptions()
gui.setPeerInfo() gui.setPeerInfo()
gui.readPreviousTransactions()
}() }()
for _, plugin := range gui.plugins { for _, plugin := range gui.plugins {
logger.Infoln("Loading plugin ", plugin.Name) guilogger.Infoln("Loading plugin ", plugin.Name)
gui.win.Root().Call("addPlugin", plugin.Path, "") gui.win.Root().Call("addPlugin", plugin.Path, "")
} }
var (
blockChan = make(chan ethreact.Event, 100)
txChan = make(chan ethreact.Event, 100)
objectChan = make(chan ethreact.Event, 100)
peerChan = make(chan ethreact.Event, 100)
chainSyncChan = make(chan ethreact.Event, 100)
miningChan = make(chan ethreact.Event, 100)
)
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)
state := gui.eth.StateManager().TransState() state := gui.eth.ChainManager().TransState()
unconfirmedFunds := new(big.Int) gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Balance())))
gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Balance)))
lastBlockLabel := gui.getObjectByName("lastBlockLabel") lastBlockLabel := gui.getObjectByName("lastBlockLabel")
miningLabel := gui.getObjectByName("miningLabel") miningLabel := gui.getObjectByName("miningLabel")
events := gui.eth.EventMux().Subscribe(
eth.ChainSyncEvent{},
eth.PeerListEvent{},
core.NewBlockEvent{},
core.TxPreEvent{},
core.TxPostEvent{},
)
go func() { go func() {
defer events.Unsubscribe()
for { for {
select { select {
case b := <-blockChan: case ev, isopen := <-events.Chan():
block := b.Resource.(*ethchain.Block) if !isopen {
gui.processBlock(block, false) return
if bytes.Compare(block.Coinbase, gui.address()) == 0 {
gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.address()).Balance, nil)
} }
case txMsg := <-txChan: switch ev := ev.(type) {
tx := txMsg.Resource.(*ethchain.Transaction) case core.NewBlockEvent:
gui.processBlock(ev.Block, false)
if txMsg.Name == "newTx:pre" { if bytes.Compare(ev.Block.Coinbase, gui.address()) == 0 {
object := state.GetAccount(gui.address()) gui.setWalletValue(gui.eth.ChainManager().State().GetBalance(gui.address()), nil)
if bytes.Compare(tx.Sender(), gui.address()) == 0 {
unconfirmedFunds.Sub(unconfirmedFunds, tx.Value)
} else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
unconfirmedFunds.Add(unconfirmedFunds, tx.Value)
} }
gui.setWalletValue(object.Balance, unconfirmedFunds) 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) gui.insertTransaction("pre", tx)
} else {
case core.TxPostEvent:
tx := ev.Tx
object := state.GetAccount(gui.address()) object := state.GetAccount(gui.address())
if bytes.Compare(tx.Sender(), gui.address()) == 0 { if bytes.Compare(tx.Sender(), gui.address()) == 0 {
object.SubAmount(tx.Value) object.SubAmount(tx.Value())
//gui.getObjectByName("transactionView").Call("addTx", ethpipe.NewJSTx(tx), "send")
gui.txDb.Put(tx.Hash(), tx.RlpEncode()) gui.txDb.Put(tx.Hash(), tx.RlpEncode())
} else if bytes.Compare(tx.Recipient, gui.address()) == 0 { } else if bytes.Compare(tx.To(), gui.address()) == 0 {
object.AddAmount(tx.Value) object.AddAmount(tx.Value())
//gui.getObjectByName("transactionView").Call("addTx", ethpipe.NewJSTx(tx), "recv")
gui.txDb.Put(tx.Hash(), tx.RlpEncode()) gui.txDb.Put(tx.Hash(), tx.RlpEncode())
} }
gui.setWalletValue(object.Balance, nil) gui.setWalletValue(object.Balance(), nil)
state.UpdateStateObject(object) state.UpdateStateObject(object)
case eth.PeerListEvent:
gui.setPeerInfo()
} }
case <-objectChan:
gui.loadAddressBook()
case <-peerChan:
gui.setPeerInfo()
case <-peerUpdateTicker.C: case <-peerUpdateTicker.C:
gui.setPeerInfo() gui.setPeerInfo()
case msg := <-miningChan:
if msg.Name == "miner:start" {
gui.miner = msg.Resource.(*ethminer.Miner)
} else {
gui.miner = nil
}
case <-generalUpdateTicker.C: case <-generalUpdateTicker.C:
statusText := "#" + gui.eth.BlockChain().CurrentBlock.Number.String() statusText := "#" + gui.eth.ChainManager().CurrentBlock().Number.String()
lastBlockLabel.Set("text", statusText) lastBlockLabel.Set("text", statusText)
miningLabel.Set("text", "Mining @ "+strconv.FormatInt(gui.uiLib.miner.GetPow().GetHashrate(), 10)+"Khash")
if gui.miner != nil {
pow := gui.miner.GetPow()
miningLabel.Set("text", "Mining @ "+strconv.FormatInt(pow.GetHashrate(), 10)+"Khash")
}
blockLength := gui.eth.BlockPool().BlocksProcessed blockLength := gui.eth.BlockPool().BlocksProcessed
chainLength := gui.eth.BlockPool().ChainLength chainLength := gui.eth.BlockPool().ChainLength
@ -469,7 +480,6 @@ func (gui *Gui) update() {
dlWidget = gui.win.Root().ObjectByName("downloadIndicator") dlWidget = gui.win.Root().ObjectByName("downloadIndicator")
dlLabel = gui.win.Root().ObjectByName("downloadLabel") dlLabel = gui.win.Root().ObjectByName("downloadLabel")
) )
dlWidget.Set("value", pct) dlWidget.Set("value", pct)
dlLabel.Set("text", fmt.Sprintf("%d / %d", blockLength, chainLength)) dlLabel.Set("text", fmt.Sprintf("%d / %d", blockLength, chainLength))
@ -478,20 +488,6 @@ func (gui *Gui) update() {
} }
} }
}() }()
reactor := gui.eth.Reactor()
reactor.Subscribe("newBlock", blockChan)
reactor.Subscribe("newTx:pre", txChan)
reactor.Subscribe("newTx:post", txChan)
reactor.Subscribe("chainSync", chainSyncChan)
reactor.Subscribe("miner:start", miningChan)
reactor.Subscribe("miner:stop", miningChan)
nameReg := gui.pipe.World().Config().Get("NameReg")
reactor.Subscribe("object:"+string(nameReg.Address()), objectChan)
reactor.Subscribe("peerList", peerChan)
} }
func (gui *Gui) setStatsPane() { func (gui *Gui) setStatsPane() {
@ -499,7 +495,7 @@ func (gui *Gui) setStatsPane() {
runtime.ReadMemStats(&memStats) runtime.ReadMemStats(&memStats)
statsPane := gui.getObjectByName("statsPane") statsPane := gui.getObjectByName("statsPane")
statsPane.Set("text", fmt.Sprintf(`###### Mist 0.6.8 (%s) ####### statsPane.Set("text", fmt.Sprintf(`###### Mist %s (%s) #######
eth %d (p2p = %d) eth %d (p2p = %d)
@ -512,7 +508,7 @@ Heap Alloc: %d
CGNext: %x CGNext: %x
NumGC: %d NumGC: %d
`, runtime.Version(), `, Version, runtime.Version(),
eth.ProtocolVersion, eth.P2PVersion, eth.ProtocolVersion, eth.P2PVersion,
runtime.NumCPU, runtime.NumGoroutine(), runtime.NumCgoCall(), runtime.NumCPU, runtime.NumGoroutine(), runtime.NumCgoCall(),
memStats.Alloc, memStats.HeapAlloc, memStats.Alloc, memStats.HeapAlloc,
@ -522,7 +518,6 @@ 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.pipe.Peers() {
gui.win.Root().Call("addPeer", peer) gui.win.Root().Call("addPeer", peer)

View File

@ -1,3 +1,20 @@
// 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
package main package main
import ( import (
@ -10,11 +27,11 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/javascript" "github.com/ethereum/go-ethereum/javascript"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/xeth"
"github.com/howeyc/fsnotify" "github.com/howeyc/fsnotify"
"gopkg.in/qml.v1" "gopkg.in/qml.v1"
) )
@ -81,12 +98,12 @@ func (app *HtmlApplication) NewWatcher(quitChan chan bool) {
app.watcher, err = fsnotify.NewWatcher() app.watcher, err = fsnotify.NewWatcher()
if err != nil { if err != nil {
logger.Infoln("Could not create new auto-reload watcher:", err) guilogger.Infoln("Could not create new auto-reload watcher:", err)
return return
} }
err = app.watcher.Watch(app.RootFolder()) err = app.watcher.Watch(app.RootFolder())
if err != nil { if err != nil {
logger.Infoln("Could not start auto-reload watcher:", err) guilogger.Infoln("Could not start auto-reload watcher:", err)
return return
} }
for _, folder := range app.RecursiveFolders() { for _, folder := range app.RecursiveFolders() {
@ -102,11 +119,11 @@ func (app *HtmlApplication) NewWatcher(quitChan chan bool) {
app.watcher.Close() app.watcher.Close()
break out break out
case <-app.watcher.Event: case <-app.watcher.Event:
//logger.Debugln("Got event:", ev) //guilogger.Debugln("Got event:", ev)
app.webView.Call("reload") app.webView.Call("reload")
case err := <-app.watcher.Error: case err := <-app.watcher.Error:
// TODO: Do something here // TODO: Do something here
logger.Infoln("Watcher error:", err) guilogger.Infoln("Watcher error:", err)
} }
} }
}() }()
@ -121,12 +138,12 @@ func (app *HtmlApplication) Window() *qml.Window {
return app.win return app.win
} }
func (app *HtmlApplication) NewBlock(block *ethchain.Block) { func (app *HtmlApplication) NewBlock(block *types.Block) {
b := &ethpipe.JSBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())} b := &xeth.JSBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())}
app.webView.Call("onNewBlockCb", b) app.webView.Call("onNewBlockCb", b)
} }
func (self *HtmlApplication) Messages(messages ethstate.Messages, id string) { func (self *HtmlApplication) Messages(messages state.Messages, id string) {
var msgs []javascript.JSMessage var msgs []javascript.JSMessage
for _, m := range messages { for _, m := range messages {
msgs = append(msgs, javascript.NewJSMessage(m)) msgs = append(msgs, javascript.NewJSMessage(m))

View File

@ -1,18 +1,37 @@
// 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
package main package main
import ( import (
"fmt"
"os" "os"
"runtime" "runtime"
"time"
"github.com/ethereum/eth-go" "github.com/ethereum/go-ethereum"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/utils" "github.com/ethereum/go-ethereum/logger"
"gopkg.in/qml.v1" "gopkg.in/qml.v1"
) )
const ( const (
ClientIdentifier = "Mist" ClientIdentifier = "Mist"
Version = "0.6.7" Version = "0.7.10"
) )
var ethereum *eth.Ethereum var ethereum *eth.Ethereum
@ -21,7 +40,8 @@ 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
Init() // parsing command line Init() // parsing command line
config := utils.InitConfig(ConfigFile, Datadir, "ETH") tstart := time.Now()
config := utils.InitConfig(VmType, ConfigFile, Datadir, "ETH")
utils.InitDataDir(Datadir) utils.InitDataDir(Datadir)
@ -34,14 +54,11 @@ func run() error {
os.Exit(1) os.Exit(1)
} }
keyManager := utils.NewKeyManager(KeyStore, Datadir, db) keyManager := utils.NewKeyManager(KeyStore, Datadir, db)
// create, import, export keys // create, import, export keys
utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive) utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier) clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier)
ethereum = utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer) ethereum = utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer)
if ShowGenesis { if ShowGenesis {
@ -58,7 +75,10 @@ func run() error {
utils.RegisterInterrupt(func(os.Signal) { utils.RegisterInterrupt(func(os.Signal) {
gui.Stop() gui.Stop()
}) })
utils.StartEthereum(ethereum, UseSeed) go utils.StartEthereum(ethereum, UseSeed)
fmt.Println("ETH stack took", time.Since(tstart))
// gui blocks the main thread // gui blocks the main thread
gui.Start(AssetPath) gui.Start(AssetPath)
@ -80,6 +100,10 @@ func main() {
utils.HandleInterrupt() utils.HandleInterrupt()
if StartWebSockets {
utils.StartWebSockets(ethereum)
}
// we need to run the interrupt callbacks in case gui is closed // we need to run the interrupt callbacks in case gui is closed
// this skips if we got here by actual interrupt stopping the GUI // this skips if we got here by actual interrupt stopping the GUI
if !interrupted { if !interrupted {
@ -87,5 +111,5 @@ func main() {
} }
// this blocks the thread // this blocks the thread
ethereum.WaitForShutdown() ethereum.WaitForShutdown()
ethlog.Flush() logger.Flush()
} }

85
cmd/mist/qml_container.go Normal file
View File

@ -0,0 +1,85 @@
// 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
package main
import (
"fmt"
"runtime"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/xeth"
"gopkg.in/qml.v1"
)
type QmlApplication struct {
win *qml.Window
engine *qml.Engine
lib *UiLib
path string
}
func NewQmlApplication(path string, lib *UiLib) *QmlApplication {
engine := qml.NewEngine()
return &QmlApplication{engine: engine, path: path, lib: lib}
}
func (app *QmlApplication) Create() error {
path := string(app.path)
// For some reason for windows we get /c:/path/to/something, windows doesn't like the first slash but is fine with the others so we are removing it
if app.path[0] == '/' && runtime.GOOS == "windows" {
path = app.path[1:]
}
component, err := app.engine.LoadFile(path)
if err != nil {
guilogger.Warnln(err)
}
app.win = component.CreateWindow(nil)
return nil
}
func (app *QmlApplication) Destroy() {
app.engine.Destroy()
}
func (app *QmlApplication) NewWatcher(quitChan chan bool) {
}
// Events
func (app *QmlApplication) NewBlock(block *types.Block) {
pblock := &xeth.JSBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())}
app.win.Call("onNewBlockCb", pblock)
}
func (self *QmlApplication) Messages(msgs state.Messages, id string) {
fmt.Println("IMPLEMENT QML APPLICATION MESSAGES METHOD")
}
// Getters
func (app *QmlApplication) Engine() *qml.Engine {
return app.engine
}
func (app *QmlApplication) Window() *qml.Window {
return app.win
}
func (app *QmlApplication) Post(data string, s int) {}

View File

@ -1,3 +1,20 @@
// 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
package main package main
import ( import (
@ -7,13 +24,16 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/ethereum/eth-go" "github.com/ethereum/go-ethereum"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/eth-go/ethstate" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/javascript" "github.com/ethereum/go-ethereum/javascript"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/ui/qt"
"github.com/ethereum/go-ethereum/xeth"
"gopkg.in/qml.v1" "gopkg.in/qml.v1"
) )
@ -24,7 +44,7 @@ type memAddr struct {
// UI Library that has some basic functionality exposed // UI Library that has some basic functionality exposed
type UiLib struct { type UiLib struct {
*ethpipe.JSPipe *xeth.JSXEth
engine *qml.Engine engine *qml.Engine
eth *eth.Ethereum eth *eth.Ethereum
connected bool connected bool
@ -37,21 +57,26 @@ type UiLib struct {
jsEngine *javascript.JSRE jsEngine *javascript.JSRE
filterCallbacks map[int][]int filterCallbacks map[int][]int
miner *miner.Miner
} }
func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib { func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
return &UiLib{JSPipe: ethpipe.NewJSPipe(eth), engine: engine, eth: eth, assetPath: assetPath, jsEngine: javascript.NewJSRE(eth), filterCallbacks: make(map[int][]int)} //, filters: make(map[int]*ethpipe.JSFilter)} lib := &UiLib{JSXEth: xeth.NewJSXEth(eth), engine: engine, eth: eth, assetPath: assetPath, jsEngine: javascript.NewJSRE(eth), filterCallbacks: make(map[int][]int)} //, filters: make(map[int]*xeth.JSFilter)}
lib.miner = miner.New(eth.KeyManager().Address(), eth)
return lib
} }
func (self *UiLib) Notef(args []interface{}) { func (self *UiLib) Notef(args []interface{}) {
logger.Infoln(args...) guilogger.Infoln(args...)
} }
func (self *UiLib) LookupDomain(domain string) string { func (self *UiLib) LookupDomain(domain string) string {
world := self.World() world := self.World()
if len(domain) > 32 { if len(domain) > 32 {
domain = string(ethcrypto.Sha3Bin([]byte(domain))) domain = string(crypto.Sha3([]byte(domain)))
} }
data := world.Config().Get("DnsReg").StorageString(domain).Bytes() data := world.Config().Get("DnsReg").StorageString(domain).Bytes()
@ -102,8 +127,11 @@ func (self *UiLib) PastPeers() *ethutil.List {
} }
func (self *UiLib) ImportTx(rlpTx string) { func (self *UiLib) ImportTx(rlpTx string) {
tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx)) tx := types.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx))
self.eth.TxPool().QueueTransaction(tx) err := self.eth.TxPool().Add(tx)
if err != nil {
guilogger.Infoln("import tx failed ", err)
}
} }
func (self *UiLib) EvalJavascriptFile(path string) { func (self *UiLib) EvalJavascriptFile(path string) {
@ -140,7 +168,7 @@ func (ui *UiLib) OpenBrowser() {
func (ui *UiLib) Muted(content string) { func (ui *UiLib) Muted(content string) {
component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml")) component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
if err != nil { if err != nil {
logger.Debugln(err) guilogger.Debugln(err)
return return
} }
@ -172,7 +200,7 @@ func (ui *UiLib) AssetPath(p string) string {
func (self *UiLib) StartDbWithContractAndData(contractHash, data string) { func (self *UiLib) StartDbWithContractAndData(contractHash, data string) {
dbWindow := NewDebuggerWindow(self) dbWindow := NewDebuggerWindow(self)
object := self.eth.StateManager().CurrentState().GetStateObject(ethutil.Hex2Bytes(contractHash)) object := self.eth.ChainManager().State().GetStateObject(ethutil.Hex2Bytes(contractHash))
if len(object.Code) > 0 { if len(object.Code) > 0 {
dbWindow.SetCode("0x" + ethutil.Bytes2Hex(object.Code)) dbWindow.SetCode("0x" + ethutil.Bytes2Hex(object.Code))
} }
@ -193,28 +221,32 @@ func (self *UiLib) StartDebugger() {
dbWindow.Show() dbWindow.Show()
} }
func (self *UiLib) NewFilter(object map[string]interface{}) int { func (self *UiLib) NewFilter(object map[string]interface{}) (id int) {
filter, id := self.eth.InstallFilter(object) filter := qt.NewFilterFromMap(object, self.eth)
filter.MessageCallback = func(messages ethstate.Messages) { filter.MessageCallback = func(messages state.Messages) {
self.win.Root().Call("invokeFilterCallback", ethpipe.ToJSMessages(messages), id) self.win.Root().Call("invokeFilterCallback", xeth.ToJSMessages(messages), id)
} }
id = self.eth.InstallFilter(filter)
return id return id
} }
func (self *UiLib) NewFilterString(typ string) int { func (self *UiLib) NewFilterString(typ string) (id int) {
filter, id := self.eth.InstallFilter(nil) filter := core.NewFilter(self.eth)
filter.BlockCallback = func(block *ethchain.Block) { filter.BlockCallback = func(block *types.Block) {
self.win.Root().Call("invokeFilterCallback", "{}", id) if self.win != nil && self.win.Root() != nil {
self.win.Root().Call("invokeFilterCallback", "{}", id)
} else {
fmt.Println("QML is lagging")
}
} }
id = self.eth.InstallFilter(filter)
return id return id
} }
func (self *UiLib) Messages(id int) *ethutil.List { func (self *UiLib) Messages(id int) *ethutil.List {
filter := self.eth.GetFilter(id) filter := self.eth.GetFilter(id)
if filter != nil { if filter != nil {
messages := ethpipe.ToJSMessages(filter.Find()) messages := xeth.ToJSMessages(filter.Find())
return messages return messages
} }
@ -277,10 +309,10 @@ func mapToTxParams(object map[string]interface{}) map[string]string {
return conv return conv
} }
func (self *UiLib) Transact(params map[string]interface{}) (*ethpipe.JSReceipt, error) { func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
object := mapToTxParams(params) object := mapToTxParams(params)
return self.JSPipe.Transact( return self.JSXEth.Transact(
object["from"], object["from"],
object["to"], object["to"],
object["value"], object["value"],
@ -302,7 +334,7 @@ func (self *UiLib) Compile(code string) (string, error) {
func (self *UiLib) Call(params map[string]interface{}) (string, error) { func (self *UiLib) Call(params map[string]interface{}) (string, error) {
object := mapToTxParams(params) object := mapToTxParams(params)
return self.JSPipe.Execute( return self.JSXEth.Execute(
object["to"], object["to"],
object["value"], object["value"],
object["gas"], object["gas"],
@ -310,3 +342,33 @@ func (self *UiLib) Call(params map[string]interface{}) (string, error) {
object["data"], 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
}
}

40
cmd/peerserver/main.go Normal file
View File

@ -0,0 +1,40 @@
package main
import (
"crypto/elliptic"
"fmt"
"log"
"net"
"os"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p"
)
func main() {
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel))
key, _ := crypto.GenerateKey()
marshaled := elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y)
srv := p2p.Server{
MaxPeers: 10,
Identity: p2p.NewSimpleClientIdentity("Ethereum(G)", "0.1", "Peer Server Two", string(marshaled)),
ListenAddr: ":30301",
NAT: p2p.UPNP(),
}
if err := srv.Start(); err != nil {
fmt.Println("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 {}
}

View File

@ -13,18 +13,18 @@ import (
"time" "time"
"bitbucket.org/kardianos/osext" "bitbucket.org/kardianos/osext"
"github.com/ethereum/eth-go" "github.com/ethereum/go-ethereum"
"github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/eth-go/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/eth-go/ethminer" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/eth-go/ethrpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/go-ethereum/wire"
"github.com/ethereum/eth-go/ethwire" "github.com/ethereum/go-ethereum/xeth"
) )
var logger = ethlog.NewLogger("CLI") var clilogger = logger.NewLogger("CLI")
var interruptCallbacks = []func(os.Signal){} var interruptCallbacks = []func(os.Signal){}
// Register interrupt handlers callbacks // Register interrupt handlers callbacks
@ -38,7 +38,7 @@ func HandleInterrupt() {
go func() { go func() {
signal.Notify(c, os.Interrupt) signal.Notify(c, os.Interrupt)
for sig := range c { for sig := range c {
logger.Errorf("Shutting down (%v) ... \n", sig) clilogger.Errorf("Shutting down (%v) ... \n", sig)
RunInterruptCallbacks(sig) RunInterruptCallbacks(sig)
} }
}() }()
@ -100,7 +100,7 @@ func InitDataDir(Datadir string) {
} }
} }
func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) ethlog.LogSystem { func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) logger.LogSystem {
var writer io.Writer var writer io.Writer
if LogFile == "" { if LogFile == "" {
writer = os.Stdout writer = os.Stdout
@ -108,28 +108,31 @@ func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string)
writer = openLogFile(Datadir, LogFile) writer = openLogFile(Datadir, LogFile)
} }
sys := ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.LogLevel(LogLevel)) sys := logger.NewStdLogSystem(writer, log.LstdFlags, logger.LogLevel(LogLevel))
ethlog.AddLogSystem(sys) logger.AddLogSystem(sys)
if DebugFile != "" { if DebugFile != "" {
writer = openLogFile(Datadir, DebugFile) writer = openLogFile(Datadir, DebugFile)
ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.DebugLevel)) logger.AddLogSystem(logger.NewStdLogSystem(writer, log.LstdFlags, logger.DebugLevel))
} }
return sys return sys
} }
func InitConfig(ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager { func InitConfig(vmType int, ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager {
InitDataDir(Datadir) InitDataDir(Datadir)
return ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix) cfg := ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
cfg.VmType = vmType
return cfg
} }
func exit(err error) { func exit(err error) {
status := 0 status := 0
if err != nil { if err != nil {
logger.Errorln("Fatal: ", err) clilogger.Errorln("Fatal: ", err)
status = 1 status = 1
} }
ethlog.Flush() logger.Flush()
os.Exit(status) os.Exit(status)
} }
@ -141,15 +144,14 @@ func NewDatabase() ethutil.Database {
return db return db
} }
func NewClientIdentity(clientIdentifier, version, customIdentifier string) *ethwire.SimpleClientIdentity { func NewClientIdentity(clientIdentifier, version, customIdentifier string) *wire.SimpleClientIdentity {
logger.Infoln("identity created") return wire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier)
return ethwire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier)
} }
func NewEthereum(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, usePnp bool, OutboundPort string, MaxPeer int) *eth.Ethereum { func NewEthereum(db ethutil.Database, clientIdentity wire.ClientIdentity, keyManager *crypto.KeyManager, usePnp bool, OutboundPort string, MaxPeer int) *eth.Ethereum {
ethereum, err := eth.New(db, clientIdentity, keyManager, eth.CapDefault, usePnp) ethereum, err := eth.New(db, clientIdentity, keyManager, eth.CapDefault, usePnp)
if err != nil { if err != nil {
logger.Fatalln("eth start err:", err) clilogger.Fatalln("eth start err:", err)
} }
ethereum.Port = OutboundPort ethereum.Port = OutboundPort
ethereum.MaxPeers = MaxPeer ethereum.MaxPeers = MaxPeer
@ -157,26 +159,26 @@ func NewEthereum(db ethutil.Database, clientIdentity ethwire.ClientIdentity, key
} }
func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) { func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
logger.Infof("Starting %s", ethereum.ClientIdentity()) clilogger.Infof("Starting %s", ethereum.ClientIdentity())
ethereum.Start(UseSeed) ethereum.Start(UseSeed)
RegisterInterrupt(func(sig os.Signal) { RegisterInterrupt(func(sig os.Signal) {
ethereum.Stop() ethereum.Stop()
ethlog.Flush() logger.Flush()
}) })
} }
func ShowGenesis(ethereum *eth.Ethereum) { func ShowGenesis(ethereum *eth.Ethereum) {
logger.Infoln(ethereum.BlockChain().Genesis()) clilogger.Infoln(ethereum.ChainManager().Genesis())
exit(nil) exit(nil)
} }
func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *ethcrypto.KeyManager { func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *crypto.KeyManager {
var keyManager *ethcrypto.KeyManager var keyManager *crypto.KeyManager
switch { switch {
case KeyStore == "db": case KeyStore == "db":
keyManager = ethcrypto.NewDBKeyManager(db) keyManager = crypto.NewDBKeyManager(db)
case KeyStore == "file": case KeyStore == "file":
keyManager = ethcrypto.NewFileKeyManager(Datadir) keyManager = crypto.NewFileKeyManager(Datadir)
default: default:
exit(fmt.Errorf("unknown keystore type: %s", KeyStore)) exit(fmt.Errorf("unknown keystore type: %s", KeyStore))
} }
@ -189,7 +191,7 @@ func DefaultAssetPath() string {
// assume a debug build and use the source directory as // assume a debug build and use the source directory as
// asset directory. // asset directory.
pwd, _ := os.Getwd() pwd, _ := os.Getwd()
if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "mist") { if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist") {
assetPath = path.Join(pwd, "assets") assetPath = path.Join(pwd, "assets")
} else { } else {
switch runtime.GOOS { switch runtime.GOOS {
@ -208,7 +210,7 @@ func DefaultAssetPath() string {
return assetPath return assetPath
} }
func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) { func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
var err error var err error
switch { switch {
@ -237,22 +239,23 @@ func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, Se
exit(err) exit(err)
} }
} }
clilogger.Infof("Main address %x\n", keyManager.Address())
} }
func StartRpc(ethereum *eth.Ethereum, RpcPort int) { func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
var err error var err error
ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpipe.NewJSPipe(ethereum), RpcPort) ethereum.RpcServer, err = rpc.NewJsonRpcServer(xeth.NewJSXEth(ethereum), RpcPort)
if err != nil { if err != nil {
logger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err) clilogger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
} else { } else {
go ethereum.RpcServer.Start() go ethereum.RpcServer.Start()
} }
} }
var miner *ethminer.Miner var gminer *miner.Miner
func GetMiner() *ethminer.Miner { func GetMiner() *miner.Miner {
return miner return gminer
} }
func StartMining(ethereum *eth.Ethereum) bool { func StartMining(ethereum *eth.Ethereum) bool {
@ -261,16 +264,16 @@ func StartMining(ethereum *eth.Ethereum) bool {
addr := ethereum.KeyManager().Address() addr := ethereum.KeyManager().Address()
go func() { go func() {
logger.Infoln("Start mining") clilogger.Infoln("Start mining")
if miner == nil { if gminer == nil {
miner = ethminer.NewDefaultMiner(addr, ethereum) gminer = miner.New(addr, ethereum)
} }
// Give it some time to connect with peers // Give it some time to connect with peers
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
for !ethereum.IsUpToDate() { for !ethereum.IsUpToDate() {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
} }
miner.Start() gminer.Start()
}() }()
RegisterInterrupt(func(os.Signal) { RegisterInterrupt(func(os.Signal) {
StopMining(ethereum) StopMining(ethereum)
@ -294,9 +297,9 @@ func FormatTransactionData(data string) []byte {
} }
func StopMining(ethereum *eth.Ethereum) bool { func StopMining(ethereum *eth.Ethereum) bool {
if ethereum.Mining && miner != nil { if ethereum.Mining && gminer != nil {
miner.Stop() gminer.Stop()
logger.Infoln("Stopped mining") clilogger.Infoln("Stopped mining")
ethereum.Mining = false ethereum.Mining = false
return true return true
@ -307,14 +310,14 @@ func StopMining(ethereum *eth.Ethereum) bool {
// Replay block // Replay block
func BlockDo(ethereum *eth.Ethereum, hash []byte) error { func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
block := ethereum.BlockChain().GetBlock(hash) block := ethereum.ChainManager().GetBlock(hash)
if block == nil { if block == nil {
return fmt.Errorf("unknown block %x", hash) return fmt.Errorf("unknown block %x", hash)
} }
parent := ethereum.BlockChain().GetBlock(block.PrevHash) parent := ethereum.ChainManager().GetBlock(block.PrevHash)
_, err := ethereum.StateManager().ApplyDiff(parent.State(), parent, block) _, err := ethereum.BlockManager().TransitionState(parent.State(), parent, block)
if err != nil { if err != nil {
return err return err
} }

70
cmd/utils/vm_env.go Normal file
View File

@ -0,0 +1,70 @@
package utils
import (
"math/big"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/vm"
)
type VMEnv struct {
state *state.StateDB
block *types.Block
transactor []byte
value *big.Int
depth int
Gas *big.Int
}
func NewEnv(state *state.StateDB, block *types.Block, transactor []byte, value *big.Int) *VMEnv {
return &VMEnv{
state: state,
block: block,
transactor: transactor,
value: value,
}
}
func (self *VMEnv) Origin() []byte { return self.transactor }
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) Time() int64 { return self.block.Time }
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty }
func (self *VMEnv) BlockHash() []byte { return self.block.Hash() }
func (self *VMEnv) Value() *big.Int { return self.value }
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) SetDepth(i int) { self.depth = i }
func (self *VMEnv) AddLog(log state.Log) {
self.state.AddLog(log)
}
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
return vm.Transfer(from, to, amount)
}
func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *core.Execution {
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) {
exe := self.vm(addr, data, gas, price, value)
ret, err := exe.Call(addr, caller)
self.Gas = exe.Gas
return ret, err
}
func (self *VMEnv) CallCode(caller vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
exe := self.vm(caller.Address(), data, gas, price, value)
return exe.Call(addr, caller)
}
func (self *VMEnv) Create(caller vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ClosureRef) {
exe := self.vm(addr, data, gas, price, value)
return exe.Create(caller)
}

View File

@ -1,10 +1,10 @@
package utils package utils
import ( import (
"github.com/ethereum/eth-go" "github.com/ethereum/go-ethereum"
"github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/go-ethereum/websocket"
"github.com/ethereum/eth-go/websocket" "github.com/ethereum/go-ethereum/xeth"
) )
func args(v ...interface{}) []interface{} { func args(v ...interface{}) []interface{} {
@ -21,7 +21,7 @@ func NewWebSocketServer(eth *eth.Ethereum) *WebSocketServer {
} }
func (self *WebSocketServer) Serv() { func (self *WebSocketServer) Serv() {
pipe := ethpipe.NewJSPipe(self.ethereum) pipe := xeth.NewJSXEth(self.ethereum)
wsServ := websocket.NewServer("/eth", ":40404") wsServ := websocket.NewServer("/eth", ":40404")
wsServ.MessageFunc(func(c *websocket.Client, msg *websocket.Message) { wsServ.MessageFunc(func(c *websocket.Client, msg *websocket.Message) {

View File

@ -0,0 +1,84 @@
package rle
import (
"bytes"
"errors"
"github.com/ethereum/go-ethereum/crypto"
)
const (
token byte = 0xfe
emptyShaToken = 0xfd
emptyListShaToken = 0xfe
tokenToken = 0xff
)
var empty = crypto.Sha3([]byte(""))
var emptyList = crypto.Sha3([]byte{0x80})
func Decompress(dat []byte) ([]byte, error) {
buf := new(bytes.Buffer)
for i := 0; i < len(dat); i++ {
if dat[i] == token {
if i+1 < len(dat) {
switch dat[i+1] {
case emptyShaToken:
buf.Write(empty)
case emptyListShaToken:
buf.Write(emptyList)
case tokenToken:
buf.WriteByte(token)
default:
buf.Write(make([]byte, int(dat[i+1]-2)))
}
i++
} else {
return nil, errors.New("error reading bytes. token encountered without proceeding bytes")
}
} else {
buf.WriteByte(dat[i])
}
}
return buf.Bytes(), nil
}
func compressChunk(dat []byte) (ret []byte, n int) {
switch {
case dat[0] == token:
return []byte{token, tokenToken}, 1
case len(dat) > 1 && dat[0] == 0x0 && dat[1] == 0x0:
j := 0
for j <= 254 && j < len(dat) {
if dat[j] != 0 {
break
}
j++
}
return []byte{token, byte(j + 2)}, j
case len(dat) >= 32:
if dat[0] == empty[0] && bytes.Compare(dat[:32], empty) == 0 {
return []byte{token, emptyShaToken}, 32
} else if dat[0] == emptyList[0] && bytes.Compare(dat[:32], emptyList) == 0 {
return []byte{token, emptyListShaToken}, 32
}
fallthrough
default:
return dat[:1], 1
}
}
func Compress(dat []byte) []byte {
buf := new(bytes.Buffer)
i := 0
for i < len(dat) {
b, n := compressChunk(dat[i:])
buf.Write(b)
i += n
}
return buf.Bytes()
}

View File

@ -0,0 +1,118 @@
package rle
import (
"testing"
checker "gopkg.in/check.v1"
)
func Test(t *testing.T) { checker.TestingT(t) }
type CompressionRleSuite struct{}
var _ = checker.Suite(&CompressionRleSuite{})
func (s *CompressionRleSuite) TestDecompressSimple(c *checker.C) {
exp := []byte{0xc5, 0xd2, 0x46, 0x1, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x3, 0xc0, 0xe5, 0x0, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x4, 0x5d, 0x85, 0xa4, 0x70}
res, err := Decompress([]byte{token, 0xfd})
c.Assert(err, checker.IsNil)
c.Assert(res, checker.DeepEquals, exp)
// if bytes.Compare(res, exp) != 0 {
// t.Error("empty sha3", res)
// }
exp = []byte{0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0, 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x1, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21}
res, err = Decompress([]byte{token, 0xfe})
c.Assert(err, checker.IsNil)
c.Assert(res, checker.DeepEquals, exp)
// if bytes.Compare(res, exp) != 0 {
// t.Error("0x80 sha3", res)
// }
res, err = Decompress([]byte{token, 0xff})
c.Assert(err, checker.IsNil)
c.Assert(res, checker.DeepEquals, []byte{token})
// if bytes.Compare(res, []byte{token}) != 0 {
// t.Error("token", res)
// }
res, err = Decompress([]byte{token, 12})
c.Assert(err, checker.IsNil)
c.Assert(res, checker.DeepEquals, make([]byte, 10))
// if bytes.Compare(res, make([]byte, 10)) != 0 {
// t.Error("10 * zero", res)
// }
}
// func TestDecompressMulti(t *testing.T) {
// res, err := Decompress([]byte{token, 0xfd, token, 0xfe, token, 12})
// if err != nil {
// t.Error(err)
// }
// var exp []byte
// exp = append(exp, crypto.Sha3([]byte(""))...)
// exp = append(exp, crypto.Sha3([]byte{0x80})...)
// exp = append(exp, make([]byte, 10)...)
// if bytes.Compare(res, res) != 0 {
// t.Error("Expected", exp, "result", res)
// }
// }
// func TestCompressSimple(t *testing.T) {
// res := Compress([]byte{0, 0, 0, 0, 0})
// if bytes.Compare(res, []byte{token, 7}) != 0 {
// t.Error("5 * zero", res)
// }
// res = Compress(crypto.Sha3([]byte("")))
// if bytes.Compare(res, []byte{token, emptyShaToken}) != 0 {
// t.Error("empty sha", res)
// }
// res = Compress(crypto.Sha3([]byte{0x80}))
// if bytes.Compare(res, []byte{token, emptyListShaToken}) != 0 {
// t.Error("empty list sha", res)
// }
// res = Compress([]byte{token})
// if bytes.Compare(res, []byte{token, tokenToken}) != 0 {
// t.Error("token", res)
// }
// }
// func TestCompressMulti(t *testing.T) {
// in := []byte{0, 0, 0, 0, 0}
// in = append(in, crypto.Sha3([]byte(""))...)
// in = append(in, crypto.Sha3([]byte{0x80})...)
// in = append(in, token)
// res := Compress(in)
// exp := []byte{token, 7, token, emptyShaToken, token, emptyListShaToken, token, tokenToken}
// if bytes.Compare(res, exp) != 0 {
// t.Error("expected", exp, "got", res)
// }
// }
// func TestCompressDecompress(t *testing.T) {
// var in []byte
// for i := 0; i < 20; i++ {
// in = append(in, []byte{0, 0, 0, 0, 0}...)
// in = append(in, crypto.Sha3([]byte(""))...)
// in = append(in, crypto.Sha3([]byte{0x80})...)
// in = append(in, []byte{123, 2, 19, 89, 245, 254, 255, token, 98, 233}...)
// in = append(in, token)
// }
// c := Compress(in)
// d, err := Decompress(c)
// if err != nil {
// t.Error(err)
// }
// if bytes.Compare(d, in) != 0 {
// t.Error("multi failed\n", d, "\n", in)
// }
// }

12
core/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
# 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
/tmp
*/**/*un~
*un~
.DS_Store
*/**/.DS_Store

50
core/asm.go Normal file
View File

@ -0,0 +1,50 @@
package core
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/vm"
)
func Disassemble(script []byte) (asm []string) {
pc := new(big.Int)
for {
if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 {
return
}
// Get the memory location of pc
val := script[pc.Int64()]
// Get the opcode (it must be an opcode!)
op := vm.OpCode(val)
asm = append(asm, fmt.Sprintf("%04v: %v", pc, op))
switch op {
case vm.PUSH1, vm.PUSH2, vm.PUSH3, vm.PUSH4, vm.PUSH5, vm.PUSH6, vm.PUSH7, vm.PUSH8,
vm.PUSH9, vm.PUSH10, vm.PUSH11, vm.PUSH12, vm.PUSH13, vm.PUSH14, vm.PUSH15,
vm.PUSH16, vm.PUSH17, vm.PUSH18, vm.PUSH19, vm.PUSH20, vm.PUSH21, vm.PUSH22,
vm.PUSH23, vm.PUSH24, vm.PUSH25, vm.PUSH26, vm.PUSH27, vm.PUSH28, vm.PUSH29,
vm.PUSH30, vm.PUSH31, vm.PUSH32:
pc.Add(pc, ethutil.Big1)
a := int64(op) - int64(vm.PUSH1) + 1
if int(pc.Int64()+a) > len(script) {
return
}
data := script[pc.Int64() : pc.Int64()+a]
if len(data) == 0 {
data = []byte{0}
}
asm = append(asm, fmt.Sprintf("%04v: 0x%x", pc, data))
pc.Add(pc, big.NewInt(a-1))
}
pc.Add(pc, ethutil.Big1)
}
return asm
}

371
core/block_manager.go Normal file
View File

@ -0,0 +1,371 @@
package core
import (
"bytes"
"container/list"
"errors"
"fmt"
"math/big"
"sync"
"time"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/pow/ezp"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/wire"
)
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 {
BlockManager() *BlockManager
ChainManager() *ChainManager
TxPool() *TxPool
Broadcast(msgType wire.MsgType, data []interface{})
PeerCount() int
IsMining() bool
IsListening() bool
Peers() *list.List
KeyManager() *crypto.KeyManager
ClientIdentity() wire.ClientIdentity
Db() ethutil.Database
EventMux() *event.TypeMux
}
type BlockManager struct {
// Mutex for locking the block processor. Blocks can only be handled one at a time
mutex sync.Mutex
// Canonical block chain
bc *ChainManager
// non-persistent key/value memory storage
mem map[string]*big.Int
// Proof of work used for validating
Pow pow.PoW
txpool *TxPool
// The last attempted block is mainly used for debugging purposes
// This does not have to be a valid block and will be set during
// 'Process' & canonical validation.
lastAttemptedBlock *types.Block
events event.Subscription
eventMux *event.TypeMux
}
func NewBlockManager(txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockManager {
sm := &BlockManager{
mem: make(map[string]*big.Int),
Pow: ezp.New(),
bc: chainManager,
eventMux: eventMux,
txpool: txpool,
}
return sm
}
func (sm *BlockManager) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) {
coinbase := statedb.GetOrNewStateObject(block.Coinbase)
coinbase.SetGasPool(block.CalcGasLimit(parent))
// Process the transactions on to current block
receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false)
if err != nil {
return nil, err
}
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) {
var (
receipts types.Receipts
handled, unhandled types.Transactions
erroneous types.Transactions
totalUsedGas = big.NewInt(0)
err error
cumulativeSum = new(big.Int)
)
done:
for i, tx := range txs {
// If we are mining this block and validating we want to set the logs back to 0
state.EmptyLogs()
txGas := new(big.Int).Set(tx.Gas())
cb := state.GetStateObject(coinbase.Address())
st := NewStateTransition(cb, tx, state, block)
_, err = st.TransitionState()
if err != nil {
switch {
case IsNonceErr(err):
err = nil // ignore error
continue
case IsGasLimitErr(err):
unhandled = txs[i:]
break done
default:
statelogger.Infoln(err)
erroneous = append(erroneous, tx)
err = nil
}
}
txGas.Sub(txGas, st.gas)
cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice()))
// Update the state with pending changes
state.Update(txGas)
cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas))
receipt := types.NewReceipt(state.Root(), cumulative)
receipt.SetLogs(state.Logs())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
chainlogger.Debugln(receipt)
// Notify all subscribers
if !transientProcess {
go self.eventMux.Post(TxPostEvent{tx})
}
receipts = append(receipts, receipt)
handled = append(handled, tx)
if ethutil.Config.Diff && ethutil.Config.DiffType == "all" {
state.CreateOutputForDiff()
}
}
block.Reward = cumulativeSum
block.GasUsed = totalUsedGas
return receipts, handled, unhandled, erroneous, err
}
func (sm *BlockManager) Process(block *types.Block) (td *big.Int, msgs state.Messages, err error) {
// Processing a blocks may never happen simultaneously
sm.mutex.Lock()
defer sm.mutex.Unlock()
if sm.bc.HasBlock(block.Hash()) {
return nil, nil, &KnownBlockError{block.Number, block.Hash()}
}
if !sm.bc.HasBlock(block.PrevHash) {
return nil, nil, ParentError(block.PrevHash)
}
parent := sm.bc.GetBlock(block.PrevHash)
return sm.ProcessWithParent(block, parent)
}
func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.Int, messages state.Messages, err error) {
sm.lastAttemptedBlock = block
state := parent.State().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
if err = sm.ValidateBlock(block, parent); err != nil {
return
}
receipts, err := sm.TransitionState(state, parent, block)
if err != nil {
return
}
rbloom := types.CreateBloom(receipts)
if bytes.Compare(rbloom, block.LogsBloom) != 0 {
err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
return
}
txSha := types.DeriveSha(block.Transactions())
if bytes.Compare(txSha, block.TxSha) != 0 {
err = fmt.Errorf("validating transaction root. received=%x got=%x", block.TxSha, txSha)
return
}
receiptSha := types.DeriveSha(receipts)
if bytes.Compare(receiptSha, block.ReceiptSha) != 0 {
//chainlogger.Debugf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha)
fmt.Printf("%x\n", ethutil.Encode(receipts))
err = fmt.Errorf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha)
return
}
if err = sm.AccumelateRewards(state, block, parent); err != nil {
return
}
state.Update(ethutil.Big0)
if !block.State().Cmp(state) {
err = fmt.Errorf("invalid merkle root. received=%x got=%x", block.Root(), state.Root())
return
}
// Calculate the new total difficulty and sync back to the db
if td, ok := sm.CalculateTD(block); ok {
// Sync the current block's state to the database and cancelling out the deferred Undo
state.Sync()
messages := state.Manifest().Messages
state.Manifest().Reset()
chainlogger.Infof("Processed block #%d (%x...)\n", block.Number, block.Hash()[0:4])
sm.txpool.RemoveSet(block.Transactions())
return td, messages, nil
} else {
return nil, nil, errors.New("total diff failed")
}
}
func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) {
uncleDiff := new(big.Int)
for _, uncle := range block.Uncles {
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 := new(big.Int)
td = td.Add(sm.bc.Td(), uncleDiff)
td = td.Add(td, block.Difficulty)
// The new TD will only be accepted if the new difficulty is
// is greater than the previous.
if td.Cmp(sm.bc.Td()) > 0 {
return td, true
}
return nil, false
}
// Validates the current block. Returns an error if the block was invalid,
// an uncle or anything that isn't on the current block chain.
// Validation validates easy over difficult (dagger takes longer time = difficult)
func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error {
expd := CalcDifficulty(block, parent)
if expd.Cmp(block.Difficulty) < 0 {
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
}
diff := block.Time - parent.Time
if diff < 0 {
return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock().Time)
}
/* XXX
// New blocks must be within the 15 minute range of the last block.
if diff > int64(15*time.Minute) {
return ValidationError("Block is too far in the future of last block (> 15 minutes)")
}
*/
// 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*/) {
return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce))
}
return nil
}
func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent *types.Block) error {
reward := new(big.Int).Set(BlockReward)
knownUncles := ethutil.Set(parent.Uncles)
nonces := ethutil.NewSet(block.Nonce)
for _, uncle := range block.Uncles {
if nonces.Include(uncle.Nonce) {
// Error not unique
return UncleError("Uncle not unique")
}
uncleParent := sm.bc.GetBlock(uncle.PrevHash)
if uncleParent == nil {
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")
}
if knownUncles.Include(uncle.Hash()) {
return UncleError("Uncle in chain")
}
nonces.Insert(uncle.Nonce)
r := new(big.Int)
r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
uncleAccount := statedb.GetAccount(uncle.Coinbase)
uncleAccount.AddAmount(r)
reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
}
// Get the account associated with the coinbase
account := statedb.GetAccount(block.Coinbase)
// Reward amount of ether to the coinbase address
account.AddAmount(reward)
statedb.Manifest().AddMessage(&state.Message{
To: block.Coinbase,
Input: nil,
Origin: nil,
Block: block.Hash(), Timestamp: block.Time, Coinbase: block.Coinbase, Number: block.Number,
Value: new(big.Int).Add(reward, block.Reward),
})
return nil
}
func (sm *BlockManager) GetMessages(block *types.Block) (messages []*state.Message, err error) {
if !sm.bc.HasBlock(block.PrevHash) {
return nil, ParentError(block.PrevHash)
}
sm.lastAttemptedBlock = block
var (
parent = sm.bc.GetBlock(block.PrevHash)
state = parent.State().Copy()
)
defer state.Reset()
sm.TransitionState(state, parent, block)
sm.AccumelateRewards(state, block, parent)
return state.Manifest().Messages, nil
}

355
core/chain_manager.go Normal file
View File

@ -0,0 +1,355 @@
package core
import (
"fmt"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/state"
)
var chainlogger = logger.NewLogger("CHAIN")
func AddTestNetFunds(block *types.Block) {
for _, addr := range []string{
"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 {
diff := new(big.Int)
adjust := new(big.Int).Rsh(parent.Difficulty, 10)
if block.Time >= parent.Time+5 {
diff.Sub(parent.Difficulty, adjust)
} else {
diff.Add(parent.Difficulty, adjust)
}
return diff
}
type ChainManager struct {
//eth EthManager
processor types.BlockProcessor
eventMux *event.TypeMux
genesisBlock *types.Block
// Last known total difficulty
mu sync.RWMutex
td *big.Int
lastBlockNumber uint64
currentBlock *types.Block
lastBlockHash []byte
transState *state.StateDB
}
func (self *ChainManager) Td() *big.Int {
self.mu.RLock()
defer self.mu.RUnlock()
return self.td
}
func (self *ChainManager) LastBlockNumber() uint64 {
self.mu.RLock()
defer self.mu.RUnlock()
return self.lastBlockNumber
}
func (self *ChainManager) LastBlockHash() []byte {
self.mu.RLock()
defer self.mu.RUnlock()
return self.lastBlockHash
}
func (self *ChainManager) CurrentBlock() *types.Block {
self.mu.RLock()
defer self.mu.RUnlock()
return self.currentBlock
}
func NewChainManager(mux *event.TypeMux) *ChainManager {
bc := &ChainManager{}
bc.genesisBlock = types.NewBlockFromBytes(ethutil.Encode(Genesis))
bc.eventMux = mux
bc.setLastBlock()
bc.transState = bc.State().Copy()
return bc
}
func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
self.processor = proc
}
func (self *ChainManager) State() *state.StateDB {
return self.CurrentBlock().State()
}
func (self *ChainManager) TransState() *state.StateDB {
return self.transState
}
func (bc *ChainManager) setLastBlock() {
data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
if len(data) != 0 {
// Prep genesis
AddTestNetFunds(bc.genesisBlock)
block := types.NewBlockFromBytes(data)
bc.currentBlock = block
bc.lastBlockHash = block.Hash()
bc.lastBlockNumber = block.Number.Uint64()
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc.td = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
} else {
bc.Reset()
}
chainlogger.Infof("Last block (#%d) %x\n", bc.lastBlockNumber, bc.currentBlock.Hash())
}
// Block creation & chain handling
func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
bc.mu.RLock()
defer bc.mu.RUnlock()
var root interface{}
hash := ZeroHash256
if bc.CurrentBlock != nil {
root = bc.currentBlock.Root()
hash = bc.lastBlockHash
}
block := types.CreateBlock(
root,
hash,
coinbase,
ethutil.BigPow(2, 32),
nil,
"")
parent := bc.currentBlock
if parent != nil {
block.Difficulty = CalcDifficulty(block, parent)
block.Number = new(big.Int).Add(bc.currentBlock.Number, ethutil.Big1)
block.GasLimit = block.CalcGasLimit(bc.currentBlock)
}
return block
}
func (bc *ChainManager) Reset() {
bc.mu.Lock()
defer bc.mu.Unlock()
AddTestNetFunds(bc.genesisBlock)
bc.genesisBlock.Trie().Sync()
// Prepare the genesis block
bc.write(bc.genesisBlock)
bc.insert(bc.genesisBlock)
bc.currentBlock = bc.genesisBlock
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 {
self.mu.RLock()
defer self.mu.RUnlock()
chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Number)
blocks := make([]*types.Block, int(self.currentBlock.Number.Int64())+1)
for block := self.currentBlock; block != nil; block = self.GetBlock(block.PrevHash) {
blocks[block.Number.Int64()] = block
}
return ethutil.Encode(blocks)
}
func (bc *ChainManager) insert(block *types.Block) {
encodedBlock := block.RlpEncode()
ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
bc.currentBlock = block
bc.lastBlockHash = block.Hash()
}
func (bc *ChainManager) write(block *types.Block) {
bc.writeBlockInfo(block)
encodedBlock := block.RlpEncode()
ethutil.Config.Db.Put(block.Hash(), encodedBlock)
}
// Accessors
func (bc *ChainManager) Genesis() *types.Block {
return bc.genesisBlock
}
// Block fetching methods
func (bc *ChainManager) HasBlock(hash []byte) bool {
data, _ := ethutil.Config.Db.Get(hash)
return len(data) != 0
}
func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) {
block := self.GetBlock(hash)
if block == nil {
return
}
// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
for i := uint64(0); i < max; i++ {
chain = append(chain, block.Hash())
if block.Number.Cmp(ethutil.Big0) <= 0 {
break
}
block = self.GetBlock(block.PrevHash)
}
return
}
func (self *ChainManager) GetBlock(hash []byte) *types.Block {
data, _ := ethutil.Config.Db.Get(hash)
if len(data) == 0 {
return nil
}
return types.NewBlockFromBytes(data)
}
func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
self.mu.RLock()
defer self.mu.RUnlock()
block := self.currentBlock
for ; block != nil; block = self.GetBlock(block.PrevHash) {
if block.Number.Uint64() == num {
break
}
}
if block != nil && block.Number.Uint64() == 0 && num != 0 {
return nil
}
return block
}
func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
ethutil.Config.Db.Put([]byte("LTD"), td.Bytes())
bc.td = td
}
func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
parent := self.GetBlock(block.PrevHash)
if parent == nil {
return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash)
}
parentTd := parent.BlockInfo().TD
uncleDiff := new(big.Int)
for _, uncle := range block.Uncles {
uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
}
td := new(big.Int)
td = td.Add(parentTd, uncleDiff)
td = td.Add(td, block.Difficulty)
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
func (bc *ChainManager) writeBlockInfo(block *types.Block) {
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() {
if bc.CurrentBlock != nil {
chainlogger.Infoln("Stopped")
}
}
func (self *ChainManager) InsertChain(chain types.Blocks) error {
for _, block := range chain {
td, messages, err := self.processor.Process(block)
if err != nil {
if IsKnownBlockErr(err) {
continue
}
chainlogger.Infof("block #%v process failed (%x)\n", block.Number, block.Hash()[:4])
chainlogger.Infoln(block)
chainlogger.Infoln(err)
return err
}
self.mu.Lock()
{
self.write(block)
if td.Cmp(self.td) > 0 {
if block.Number.Cmp(new(big.Int).Add(self.currentBlock.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])
}
self.setTotalDifficulty(td)
self.insert(block)
self.transState = self.currentBlock.State().Copy()
}
}
self.mu.Unlock()
self.eventMux.Post(NewBlockEvent{block})
self.eventMux.Post(messages)
}
return nil
}

Some files were not shown because too many files have changed in this diff Show More