Merge branch 'release/v0.7.10'
|
@ -9,6 +9,4 @@
|
||||||
*un~
|
*un~
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*/**/.DS_Store
|
*/**/.DS_Store
|
||||||
ethereum/ethereum
|
.ethtest
|
||||||
ethereal/ethereal
|
|
||||||
|
|
||||||
|
|
25
.travis.yml
|
@ -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="
|
||||||
|
|
||||||
|
|
|
@ -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
|
8
LICENSE
|
@ -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
|
||||||
|
|
88
README.md
|
@ -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!)
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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))
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
|
@ -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()
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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]))
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
60006102ff5360003560001a60008114156103395760013560405260216040516020025990590160009052606052604051602002816060513760405160200281019050506002604051121561005957604051602002606051f35b604051602002599059016000905260a052600060c052604051602002599059016000905260e0526000610100526001610120525b604051610120511215610109576060515161012051602002606051015112156100d8576101205160200260605101516101005160200260e051015260016101005101610100526100f9565b61012051602002606051015160c05160200260a0510152600160c0510160c0525b600161012051016101205261008d565b60216020599059016000905260c051808252806020028301925050602082015990590160009052600081538151600182015260218101825160200260a0518260005b8381101561016657808301518186015260208101905061014b565b50505050825160200281019050604059905901600090526102405281610240515283602061024051015261024051905090509050905060c05160200280599059016000905281816020850151855160003060195a03f1508090509050905060a05260216020599059016000905261010051808252806020028301925050602082015990590160009052600081538151600182015260218101825160200260e0518260005b8381101561022557808301518186015260208101905061020a565b50505050825160200281019050604059905901600090526102c052816102c051528360206102c05101526102c05190509050905090506101005160200280599059016000905281816020850151855160003060195a03f1508090509050905060e05260405160200259905901600090526102e0526000610120525b610100516101205112156102d7576101205160200260e0510151610120516020026102e051015260016101205101610120526102a0565b60605151610100516020026102e05101526000610120525b60c05161012051121561032d576101205160200260a05101516101205160016101005101016020026102e051015260016101205101610120526102ef565b6040516020026102e051f35b50
|
|
@ -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)
|
||||||
|
}
|
Before Width: | Height: | Size: 1004 B After Width: | Height: | Size: 1004 B |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 905 B After Width: | Height: | Size: 905 B |
|
@ -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 = {
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
```
|
|
@ -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;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
|
@ -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>
|
|
@ -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);
|
|
@ -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;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
})();
|
|
@ -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(),
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
|
@ -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('');
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
(function() {
|
||||||
|
if (typeof(Promise) === "undefined")
|
||||||
|
window.Promise = Q.Promise;
|
||||||
|
|
||||||
|
var eth = web3.eth;
|
||||||
|
|
||||||
|
web3.setProvider(new web3.providers.QtProvider());
|
||||||
|
})()
|
|
@ -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
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 2.1 KiB |
|
@ -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)
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 932 B After Width: | Height: | Size: 932 B |
|
@ -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"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> <' + name + '> ' + coinbase; color: "#F2F2F2"}
|
Text { text: '<b>Coinbase:</b> <' + name + '> ' + 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"
|
|
@ -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
|
|
@ -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)})
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -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)
|
|
||||||
}
|
|
|
@ -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: ðvm.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(ðstate.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")
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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)
|
|
@ -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 := ðpipe.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))
|
|
@ -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()
|
||||||
}
|
}
|
|
@ -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) {}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {}
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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) {
|
|
@ -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()
|
||||||
|
}
|
|
@ -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)
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|