Merge pull request #2827 from ethereum/release/1.4

Geth 1.4.10 "Return of the ETH"
This commit is contained in:
Péter Szilágyi
2016-07-16 18:52:56 +03:00
committed by GitHub
42 changed files with 10124 additions and 138 deletions

191
README.md
View File

@ -54,6 +54,197 @@ The go-ethereum project comes with several wrappers/executables found in the `cm
| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. | | `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. |
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | | `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
## Running geth
Going through all the possible command line flags is out of scope here (please consult our
[CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)), but we've
enumerated a few common parameter combos to get you up to speed quickly on how you can run your
own Geth instance.
### Full node on the main Ethereum network
By far the most common scenario is people wanting to simply interact with the Ethereum network:
create accounts; transfer funds; deploy and interact with contracts. For this particular use-case
the user doesn't care about years-old historical data, so we can fast-sync quickly to the current
state of the network. To do so:
```
$ geth --fast --cache=512 console
```
This command will:
* Start geth in fast sync mode (`--fast`), causing it to download more data in exchange for avoiding
processing the entire history of the Ethereum network, which is very CPU intensive.
* Bump the memory allowance of the database to 512MB (`--cache=512`), which can help significantly in
sync times especially for HDD users. This flag is optional and you can set it as high or as low as
you'd like, though we'd recommend the 512MB - 2GB range.
* Start up Geth's built-in interactive [JavaScript console](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console),
(via the trailing `console` subcommand) through which you can invoke all official [`web3` methods](https://github.com/ethereum/wiki/wiki/JavaScript-API)
as well as Geth's own [management APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs).
This too is optional and if you leave it out you can always attach to an already running Geth instance
with `geth --attach`.
### Full node on the Ethereum test network
Transitioning towards developers, if you'd like to play around with creating Ethereum contracts, you
almost certainly would like to do that without any real money involved until you get the hang of the
entire system. In other words, instead of attaching to the main network, you want to join the **test**
network with your node, which is fully equivalent to the main network, but with play-Ether only.
```
$ geth --testnet --fast --cache=512 console
```
The `--fast`, `--cache` flags and `console` subcommand have the exact same meaning as above and they
are equially useful on the testnet too. Please see above for their explanations if you've skipped to
here.
Specifying the `--testnet` flag however will reconfigure your Geth instance a bit:
* Instead of using the default data directory (`~/.ethereum` on Linux for example), Geth will nest
itself one level deeper into a `testnet` subfolder (`~/.ethereum/testnet` on Linux).
* Instead of connecting the main Ethereum network, the client will connect to the test network,
which uses different P2P bootnodes, different network IDs and genesis states.
*Note: Although there are some internal protective measures to prevent transactions from crossing
over between the main network and test network (different starting nonces), you should make sure to
always use separate accounts for play-money and real-money. Unless you manually move accounts, Geth
will by default correctly separate the two networks and will not make any accounts available between
them.*
### Programatically interfacing Geth nodes
As a developer, sooner rather than later you'll want to start interacting with Geth and the Ethereum
network via your own programs and not manually through the console. To aid this, Geth has built in
support for a JSON-RPC based APIs ([standard APIs](https://github.com/ethereum/wiki/wiki/JSON-RPC) and
[Geth specific APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs)). These can be
exposed via HTTP, WebSockets and IPC (unix sockets on unix based platroms, and named pipes on Windows).
The IPC interface is enabled by default and exposes all the APIs supported by Geth, whereas the HTTP
and WS interfaces need to manually be enabled and only expose a subset of APIs due to security reasons.
These can be turned on/off and configured as you'd expect.
HTTP based JSON-RPC API options:
* `--rpc` Enable the HTTP-RPC server
* `--rpcaddr` HTTP-RPC server listening interface (default: "localhost")
* `--rpcport` HTTP-RPC server listening port (default: 8545)
* `--rpcapi` API's offered over the HTTP-RPC interface (default: "eth,net,web3")
* `--rpccorsdomain` Comma separated list of domains from which to accept cross origin requests (browser enforced)
* `--ws` Enable the WS-RPC server
* `--wsaddr` WS-RPC server listening interface (default: "localhost")
* `--wsport` WS-RPC server listening port (default: 8546)
* `--wsapi` API's offered over the WS-RPC interface (default: "eth,net,web3")
* `--wsorigins` Origins from which to accept websockets requests
* `--ipcdisable` Disable the IPC-RPC server
* `--ipcapi` API's offered over the IPC-RPC interface (default: "admin,debug,eth,miner,net,personal,shh,txpool,web3")
* `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it)
You'll need to use your own programming environments' capabilities (libraries, tools, etc) to connect
via HTTP, WS or IPC to a Geth node configured with the above flags and you'll need to speak [JSON-RPC](http://www.jsonrpc.org/specification)
on all transports. You can reuse the same connection for multiple requests!
**Note: Please understand the security implications of opening up an HTTP/WS based transport before
doing so! Hackers on the internet are actively trying to subvert Ethereum nodes with exposed APIs!
Further, all browser tabs can access locally running webservers, so malicious webpages could try to
subvert locally available APIs!**
### Operating a private network
Maintaining your own private network is more involved as a lot of configurations taken for granted in
the official networks need to be manually set up.
#### Defining the private genesis state
First, you'll need to create the genesis state of your networks, which all nodes need to be aware of
and agree upon. This consists of a small JSON file (e.g. call it `genesis.json`):
```json
{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00"
}
```
The above fields should be fine for most purposes, although we'd recommend changing the `nonce` to
some random value so you prevent unknown remote nodes from being able to connect to you. If you'd
like to pre-fund some accounts for easier testing, you can populate the `alloc` field with account
configs:
```json
"alloc": {
"0x0000000000000000000000000000000000000001": {"balance": "111111111"},
"0x0000000000000000000000000000000000000002": {"balance": "222222222"}
}
```
With the genesis state defined in the above JSON file, you'll need to initialize **every** Geth node
with it prior to starting it up to ensure all blockchain parameters are correctly set:
```
$ geth init path/to/genesis.json
```
#### Creating the rendezvous point
With all nodes that you want to run initialized to the desired genesis state, you'll need to start a
bootstrap node that others can use to find each other in your network and/or over the internet. The
clean way is to configure and run a dedicated bootnode:
```
$ bootnode --genkey=boot.key
$ bootnode --nodekey=boot.key
```
With the bootnode online, it will display an [`enode` URL](https://github.com/ethereum/wiki/wiki/enode-url-format)
that other nodes can use to connect to it and exchange peer information. Make sure to replace the
displayed IP address information (most probably `[::]`) with your externally accessible IP to get the
actual `enode` URL.
*Note: You could also use a full fledged Geth node as a bootnode, but it's the less recommended way.*
#### Starting up your member nodes
With the bootnode operational and externally reachable (you can try `telnet <ip> <port>` to ensure
it's indeed reachable), start every subsequent Geth node pointed to the bootnode for peer discovery
via the `--bootnodes` flag. It will probably also be desirable to keep the data directory of your
private network separated, so do also specify a custom `--datadir` flag.
```
$ geth --datadir=path/to/custom/data/folder --bootnodes=<bootnode-enode-url-from-above>
```
*Note: Since your network will be completely cut off from the main and test networks, you'll also
need to configure a miner to process transactions and create new blocks for you.*
#### Running a private miner
Mining on the public Ethereum network is a complex task as it's only feasible using GPUs, requiring
an OpenCL or CUDA enabled `ethminer` instance. For information on such a setup, please consult the
[EtherMining subreddit](https://www.reddit.com/r/EtherMining/) and the [Genoil miner](https://github.com/Genoil/cpp-ethereum)
repository.
In a private network setting however, a single CPU miner instance is more than enough for practical
purposes as it can produce a stable stream of blocks at the correct intervals without needing heavy
resources (consider running on a single thread, no need for multiple ones either). To start a Geth
instance for mining, run it with all your usual flags, extended by:
```
$ geth <usual-flags> --mine --minerthreads=1 --etherbase=0x0000000000000000000000000000000000000000
```
Which will start mining bocks and transactions on a single CPU thread, crediting all proceedings to
the account specified by `--etherbase`. You can further tune the mining by changing the default gas
limit blocks converge to (`--targetgaslimit`) and the price transactions are accepted at (`--gasprice`).
## Contribution ## Contribution
Thank you for considering to help out with the source code! We welcome contributions from Thank you for considering to help out with the source code! We welcome contributions from

View File

@ -1 +1 @@
1.4.9 1.4.10

View File

@ -72,7 +72,7 @@ func (b *SimulatedBackend) Commit() {
// Rollback aborts all pending transactions, reverting to the last committed state. // Rollback aborts all pending transactions, reverting to the last committed state.
func (b *SimulatedBackend) Rollback() { func (b *SimulatedBackend) Rollback() {
blocks, _ := core.GenerateChain(b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {}) blocks, _ := core.GenerateChain(nil, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
b.pendingBlock = blocks[0] b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database) b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
@ -178,7 +178,7 @@ func (b *SimulatedBackend) EstimateGasLimit(sender common.Address, contract *com
// SendTransaction implements ContractTransactor.SendTransaction, delegating the raw // SendTransaction implements ContractTransactor.SendTransaction, delegating the raw
// transaction injection to the remote node. // transaction injection to the remote node.
func (b *SimulatedBackend) SendTransaction(tx *types.Transaction) error { func (b *SimulatedBackend) SendTransaction(tx *types.Transaction) error {
blocks, _ := core.GenerateChain(b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) { blocks, _ := core.GenerateChain(nil, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
for _, tx := range b.pendingBlock.Transactions() { for _, tx := range b.pendingBlock.Transactions() {
block.AddTx(tx) block.AddTx(tx)
} }

32
circle.yml Normal file
View File

@ -0,0 +1,32 @@
machine:
services:
- docker
dependencies:
cache_directories:
- "~/.ethash" # Cache the ethash DAG generated by hive for consecutive builds
- "~/.docker" # Cache all docker images manually to avoid lengthy rebuilds
override:
# Restore all previously cached docker images
- mkdir -p ~/.docker
- for img in `ls ~/.docker`; do docker load -i ~/.docker/$img; done
# Pull in and hive, restore cached ethash DAGs and do a dry run
- go get -u github.com/karalabe/hive
- (cd ~/.go_workspace/src/github.com/karalabe/hive && mkdir -p workspace/ethash/ ~/.ethash)
- (cd ~/.go_workspace/src/github.com/karalabe/hive && cp -r ~/.ethash/. workspace/ethash/)
- (cd ~/.go_workspace/src/github.com/karalabe/hive && hive --docker-noshell --client=NONE --test=. --sim=. --loglevel=6)
# Cache all the docker images and the ethash DAGs
- for img in `docker images | grep -v "^<none>" | tail -n +2 | awk '{print $1}'`; do docker save $img > ~/.docker/`echo $img | tr '/' ':'`.tar; done
- cp -r ~/.go_workspace/src/github.com/karalabe/hive/workspace/ethash/. ~/.ethash
test:
override:
# Build Geth and move into a known folder
- make geth
- cp ./build/bin/geth $HOME/geth
# Run hive and move all generated logs into the public artifacts folder
- (cd ~/.go_workspace/src/github.com/karalabe/hive && hive --docker-noshell --client=go-ethereum:local --override=$HOME/geth --test=. --sim=.)
- cp -r ~/.go_workspace/src/github.com/karalabe/hive/workspace/logs/* $CIRCLE_ARTIFACTS

View File

@ -74,9 +74,9 @@ func runTestWithReader(test string, r io.Reader) error {
var err error var err error
switch strings.ToLower(test) { switch strings.ToLower(test) {
case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests": case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
err = tests.RunBlockTestWithReader(params.MainNetHomesteadBlock, r, skipTests) err = tests.RunBlockTestWithReader(params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, r, skipTests)
case "st", "state", "statetest", "statetests": case "st", "state", "statetest", "statetests":
rs := tests.RuleSet{HomesteadBlock: params.MainNetHomesteadBlock} rs := tests.RuleSet{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true}
err = tests.RunStateTestWithReader(rs, r, skipTests) err = tests.RunStateTestWithReader(rs, r, skipTests)
case "tx", "transactiontest", "transactiontests": case "tx", "transactiontest", "transactiontests":
err = tests.RunTransactionTestsWithReader(r, skipTests) err = tests.RunTransactionTestsWithReader(r, skipTests)

232
cmd/geth/dao_test.go Normal file
View File

@ -0,0 +1,232 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"io/ioutil"
"math/big"
"os"
"path/filepath"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
// Genesis block for nodes which don't care about the DAO fork (i.e. not configured)
var daoOldGenesis = `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"config" : {}
}`
// Genesis block for nodes which actively oppose the DAO fork
var daoNoForkGenesis = `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"config" : {
"daoForkBlock" : 314,
"daoForkSupport" : false
}
}`
// Genesis block for nodes which actively support the DAO fork
var daoProForkGenesis = `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"config" : {
"daoForkBlock" : 314,
"daoForkSupport" : true
}
}`
var daoGenesisHash = common.HexToHash("5e1fc79cb4ffa4739177b5408045cd5d51c6cf766133f23f7cd72ee1f8d790e0")
var daoGenesisForkBlock = big.NewInt(314)
// Tests that the DAO hard-fork number and the nodes support/opposition is correctly
// set in the database after various initialization procedures and invocations.
func TestDAODefaultMainnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, "", [][2]bool{{false, false}}, params.MainNetDAOForkBlock, true)
}
func TestDAOSupportMainnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, "", [][2]bool{{true, false}}, params.MainNetDAOForkBlock, true)
}
func TestDAOOpposeMainnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, "", [][2]bool{{false, true}}, params.MainNetDAOForkBlock, false)
}
func TestDAOSwitchToSupportMainnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, "", [][2]bool{{false, true}, {true, false}}, params.MainNetDAOForkBlock, true)
}
func TestDAOSwitchToOpposeMainnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, "", [][2]bool{{true, false}, {false, true}}, params.MainNetDAOForkBlock, false)
}
func TestDAODefaultTestnet(t *testing.T) {
testDAOForkBlockNewChain(t, true, "", [][2]bool{{false, false}}, params.TestNetDAOForkBlock, true)
}
func TestDAOSupportTestnet(t *testing.T) {
testDAOForkBlockNewChain(t, true, "", [][2]bool{{true, false}}, params.TestNetDAOForkBlock, true)
}
func TestDAOOpposeTestnet(t *testing.T) {
testDAOForkBlockNewChain(t, true, "", [][2]bool{{false, true}}, params.TestNetDAOForkBlock, false)
}
func TestDAOSwitchToSupportTestnet(t *testing.T) {
testDAOForkBlockNewChain(t, true, "", [][2]bool{{false, true}, {true, false}}, params.TestNetDAOForkBlock, true)
}
func TestDAOSwitchToOpposeTestnet(t *testing.T) {
testDAOForkBlockNewChain(t, true, "", [][2]bool{{true, false}, {false, true}}, params.TestNetDAOForkBlock, false)
}
func TestDAOInitOldPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{}, nil, false)
}
func TestDAODefaultOldPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{{false, false}}, params.MainNetDAOForkBlock, true)
}
func TestDAOSupportOldPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{{true, false}}, params.MainNetDAOForkBlock, true)
}
func TestDAOOpposeOldPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{{false, true}}, params.MainNetDAOForkBlock, false)
}
func TestDAOSwitchToSupportOldPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{{false, true}, {true, false}}, params.MainNetDAOForkBlock, true)
}
func TestDAOSwitchToOpposeOldPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{{true, false}, {false, true}}, params.MainNetDAOForkBlock, false)
}
func TestDAOInitNoForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{}, daoGenesisForkBlock, false)
}
func TestDAODefaultNoForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{{false, false}}, daoGenesisForkBlock, false)
}
func TestDAOSupportNoForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{{true, false}}, daoGenesisForkBlock, true)
}
func TestDAOOpposeNoForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{{false, true}}, daoGenesisForkBlock, false)
}
func TestDAOSwitchToSupportNoForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{{false, true}, {true, false}}, daoGenesisForkBlock, true)
}
func TestDAOSwitchToOpposeNoForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{{true, false}, {false, true}}, daoGenesisForkBlock, false)
}
func TestDAOInitProForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{}, daoGenesisForkBlock, true)
}
func TestDAODefaultProForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{{false, false}}, daoGenesisForkBlock, true)
}
func TestDAOSupportProForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{{true, false}}, daoGenesisForkBlock, true)
}
func TestDAOOpposeProForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{{false, true}}, daoGenesisForkBlock, false)
}
func TestDAOSwitchToSupportProForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{{false, true}, {true, false}}, daoGenesisForkBlock, true)
}
func TestDAOSwitchToOpposeProForkPrivnet(t *testing.T) {
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{{true, false}, {false, true}}, daoGenesisForkBlock, false)
}
func testDAOForkBlockNewChain(t *testing.T, testnet bool, genesis string, votes [][2]bool, expectBlock *big.Int, expectVote bool) {
// Create a temporary data directory to use and inspect later
datadir := tmpdir(t)
defer os.RemoveAll(datadir)
// Start a Geth instance with the requested flags set and immediately terminate
if genesis != "" {
json := filepath.Join(datadir, "genesis.json")
if err := ioutil.WriteFile(json, []byte(genesis), 0600); err != nil {
t.Fatalf("failed to write genesis file: %v", err)
}
runGeth(t, "--datadir", datadir, "init", json).cmd.Wait()
}
for _, vote := range votes {
args := []string{"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir}
if testnet {
args = append(args, "--testnet")
}
if vote[0] {
args = append(args, "--support-dao-fork")
}
if vote[1] {
args = append(args, "--oppose-dao-fork")
}
geth := runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...)
geth.cmd.Wait()
}
// Retrieve the DAO config flag from the database
path := filepath.Join(datadir, "chaindata")
if testnet && genesis == "" {
path = filepath.Join(datadir, "testnet", "chaindata")
}
db, err := ethdb.NewLDBDatabase(path, 0, 0)
if err != nil {
t.Fatalf("failed to open test database: %v", err)
}
defer db.Close()
genesisHash := common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
if testnet {
genesisHash = common.HexToHash("0x0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303")
}
if genesis != "" {
genesisHash = daoGenesisHash
}
config, err := core.GetChainConfig(db, genesisHash)
if err != nil {
t.Fatalf("failed to retrieve chain config: %v", err)
}
// Validate the DAO hard-fork block number against the expected value
if config.DAOForkBlock == nil {
if expectBlock != nil {
t.Errorf("dao hard-fork block mismatch: have nil, want %v", expectBlock)
}
} else if expectBlock == nil {
t.Errorf("dao hard-fork block mismatch: have %v, want nil", config.DAOForkBlock)
} else if config.DAOForkBlock.Cmp(expectBlock) != 0 {
t.Errorf("dao hard-fork block mismatch: have %v, want %v", config.DAOForkBlock, expectBlock)
}
if config.DAOForkSupport != expectVote {
t.Errorf("dao hard-fork support mismatch: have %v, want %v", config.DAOForkSupport, expectVote)
}
}

107
cmd/geth/genesis_test.go Normal file
View File

@ -0,0 +1,107 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
)
var customGenesisTests = []struct {
genesis string
query string
result string
}{
// Plain genesis file without anything extra
{
genesis: `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00"
}`,
query: "eth.getBlock(0).nonce",
result: "0x0000000000000042",
},
// Genesis file with an empty chain configuration (ensure missing fields work)
{
genesis: `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"config" : {}
}`,
query: "eth.getBlock(0).nonce",
result: "0x0000000000000042",
},
// Genesis file with specific chain configurations
{
genesis: `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"config" : {
"homesteadBlock" : 314,
"daoForkBlock" : 141,
"daoForkSupport" : true
},
}`,
query: "eth.getBlock(0).nonce",
result: "0x0000000000000042",
},
}
// Tests that initializing Geth with a custom genesis block and chain definitions
// work properly.
func TestCustomGenesis(t *testing.T) {
for i, tt := range customGenesisTests {
// Create a temporary data directory to use and inspect later
datadir := tmpdir(t)
defer os.RemoveAll(datadir)
// Initialize the data directory with the custom genesis block
json := filepath.Join(datadir, "genesis.json")
if err := ioutil.WriteFile(json, []byte(tt.genesis), 0600); err != nil {
t.Fatalf("test %d: failed to write genesis file: %v", i, err)
}
runGeth(t, "--datadir", datadir, "init", json).cmd.Wait()
// Query the custom genesis block
geth := runGeth(t, "--datadir", datadir, "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--exec", tt.query, "console")
geth.expectRegexp(tt.result)
geth.expectExit()
}
}

View File

@ -50,7 +50,7 @@ const (
clientIdentifier = "Geth" // Client identifier to advertise over the network clientIdentifier = "Geth" // Client identifier to advertise over the network
versionMajor = 1 // Major version component of the current release versionMajor = 1 // Major version component of the current release
versionMinor = 4 // Minor version component of the current release versionMinor = 4 // Minor version component of the current release
versionPatch = 9 // Patch version component of the current release versionPatch = 10 // Patch version component of the current release
versionMeta = "stable" // Version metadata to append to the version string versionMeta = "stable" // Version metadata to append to the version string
versionOracle = "0xfa7b9770ca4cb04296cac84f37736d4041251cdf" // Ethereum address of the Geth release oracle versionOracle = "0xfa7b9770ca4cb04296cac84f37736d4041251cdf" // Ethereum address of the Geth release oracle
@ -149,7 +149,6 @@ participating.
utils.IdentityFlag, utils.IdentityFlag,
utils.UnlockedAccountFlag, utils.UnlockedAccountFlag,
utils.PasswordFileFlag, utils.PasswordFileFlag,
utils.GenesisFileFlag,
utils.BootnodesFlag, utils.BootnodesFlag,
utils.DataDirFlag, utils.DataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
@ -164,6 +163,8 @@ participating.
utils.MaxPendingPeersFlag, utils.MaxPendingPeersFlag,
utils.EtherbaseFlag, utils.EtherbaseFlag,
utils.GasPriceFlag, utils.GasPriceFlag,
utils.SupportDAOFork,
utils.OpposeDAOFork,
utils.MinerThreadsFlag, utils.MinerThreadsFlag,
utils.MiningEnabledFlag, utils.MiningEnabledFlag,
utils.MiningGPUFlag, utils.MiningGPUFlag,
@ -224,12 +225,6 @@ participating.
eth.EnableBadBlockReporting = true eth.EnableBadBlockReporting = true
utils.SetupNetwork(ctx) utils.SetupNetwork(ctx)
// Deprecation warning.
if ctx.GlobalIsSet(utils.GenesisFileFlag.Name) {
common.PrintDepricationWarning("--genesis is deprecated. Switch to use 'geth init /path/to/file'")
}
return nil return nil
} }

View File

@ -68,7 +68,6 @@ var AppHelpFlagGroups = []flagGroup{
utils.OlympicFlag, utils.OlympicFlag,
utils.TestNetFlag, utils.TestNetFlag,
utils.DevModeFlag, utils.DevModeFlag,
utils.GenesisFileFlag,
utils.IdentityFlag, utils.IdentityFlag,
utils.FastSyncFlag, utils.FastSyncFlag,
utils.LightKDFFlag, utils.LightKDFFlag,

View File

@ -126,10 +126,6 @@ var (
Name: "dev", Name: "dev",
Usage: "Developer mode: pre-configured private network with several debugging flags", Usage: "Developer mode: pre-configured private network with several debugging flags",
} }
GenesisFileFlag = cli.StringFlag{
Name: "genesis",
Usage: "Insert/overwrite the genesis block (JSON format)",
}
IdentityFlag = cli.StringFlag{ IdentityFlag = cli.StringFlag{
Name: "identity", Name: "identity",
Usage: "Custom node name", Usage: "Custom node name",
@ -161,6 +157,15 @@ var (
Name: "lightkdf", Name: "lightkdf",
Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
} }
// Fork settings
SupportDAOFork = cli.BoolFlag{
Name: "support-dao-fork",
Usage: "Updates the chain rules to support the DAO hard-fork",
}
OpposeDAOFork = cli.BoolFlag{
Name: "oppose-dao-fork",
Usage: "Updates the chain rules to oppose the DAO hard-fork",
}
// Miner settings // Miner settings
// TODO: refactor CPU vs GPU mining flags // TODO: refactor CPU vs GPU mining flags
MiningEnabledFlag = cli.BoolFlag{ MiningEnabledFlag = cli.BoolFlag{
@ -534,20 +539,6 @@ func MakeWSRpcHost(ctx *cli.Context) string {
return ctx.GlobalString(WSListenAddrFlag.Name) return ctx.GlobalString(WSListenAddrFlag.Name)
} }
// MakeGenesisBlock loads up a genesis block from an input file specified in the
// command line, or returns the empty string if none set.
func MakeGenesisBlock(ctx *cli.Context) string {
genesis := ctx.GlobalString(GenesisFileFlag.Name)
if genesis == "" {
return ""
}
data, err := ioutil.ReadFile(genesis)
if err != nil {
Fatalf("Failed to load custom genesis file: %v", err)
}
return string(data)
}
// MakeDatabaseHandles raises out the number of allowed file handles per process // MakeDatabaseHandles raises out the number of allowed file handles per process
// for Geth and returns half of the allowance to assign to the database. // for Geth and returns half of the allowance to assign to the database.
func MakeDatabaseHandles() int { func MakeDatabaseHandles() int {
@ -689,7 +680,6 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
ethConf := &eth.Config{ ethConf := &eth.Config{
ChainConfig: MustMakeChainConfig(ctx), ChainConfig: MustMakeChainConfig(ctx),
Genesis: MakeGenesisBlock(ctx),
FastSync: ctx.GlobalBool(FastSyncFlag.Name), FastSync: ctx.GlobalBool(FastSyncFlag.Name),
BlockChainVersion: ctx.GlobalInt(BlockchainVersionFlag.Name), BlockChainVersion: ctx.GlobalInt(BlockchainVersionFlag.Name),
DatabaseCache: ctx.GlobalInt(CacheFlag.Name), DatabaseCache: ctx.GlobalInt(CacheFlag.Name),
@ -722,17 +712,13 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
if !ctx.GlobalIsSet(NetworkIdFlag.Name) { if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
ethConf.NetworkId = 1 ethConf.NetworkId = 1
} }
if !ctx.GlobalIsSet(GenesisFileFlag.Name) { ethConf.Genesis = core.OlympicGenesisBlock()
ethConf.Genesis = core.OlympicGenesisBlock()
}
case ctx.GlobalBool(TestNetFlag.Name): case ctx.GlobalBool(TestNetFlag.Name):
if !ctx.GlobalIsSet(NetworkIdFlag.Name) { if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
ethConf.NetworkId = 2 ethConf.NetworkId = 2
} }
if !ctx.GlobalIsSet(GenesisFileFlag.Name) { ethConf.Genesis = core.TestNetGenesisBlock()
ethConf.Genesis = core.TestNetGenesisBlock()
}
state.StartingNonce = 1048576 // (2**20) state.StartingNonce = 1048576 // (2**20)
case ctx.GlobalBool(DevModeFlag.Name): case ctx.GlobalBool(DevModeFlag.Name):
@ -747,9 +733,7 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
stackConf.ListenAddr = ":0" stackConf.ListenAddr = ":0"
} }
// Override the Ethereum protocol configs // Override the Ethereum protocol configs
if !ctx.GlobalIsSet(GenesisFileFlag.Name) { ethConf.Genesis = core.OlympicGenesisBlock()
ethConf.Genesis = core.OlympicGenesisBlock()
}
if !ctx.GlobalIsSet(GasPriceFlag.Name) { if !ctx.GlobalIsSet(GasPriceFlag.Name) {
ethConf.GasPrice = new(big.Int) ethConf.GasPrice = new(big.Int)
} }
@ -806,24 +790,62 @@ func MustMakeChainConfig(ctx *cli.Context) *core.ChainConfig {
// MustMakeChainConfigFromDb reads the chain configuration from the given database. // MustMakeChainConfigFromDb reads the chain configuration from the given database.
func MustMakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfig { func MustMakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfig {
genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0)) // If the chain is already initialized, use any existing chain configs
config := new(core.ChainConfig)
genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0))
if genesis != nil { if genesis != nil {
// Existing genesis block, use stored config if available.
storedConfig, err := core.GetChainConfig(db, genesis.Hash()) storedConfig, err := core.GetChainConfig(db, genesis.Hash())
if err == nil { switch err {
return storedConfig case nil:
} else if err != core.ChainConfigNotFoundErr { config = storedConfig
case core.ChainConfigNotFoundErr:
// No configs found, use empty, will populate below
default:
Fatalf("Could not make chain configuration: %v", err) Fatalf("Could not make chain configuration: %v", err)
} }
} }
var homesteadBlockNo *big.Int // Set any missing fields due to them being unset or system upgrade
if ctx.GlobalBool(TestNetFlag.Name) { if config.HomesteadBlock == nil {
homesteadBlockNo = params.TestNetHomesteadBlock if ctx.GlobalBool(TestNetFlag.Name) {
} else { config.HomesteadBlock = params.TestNetHomesteadBlock
homesteadBlockNo = params.MainNetHomesteadBlock } else {
config.HomesteadBlock = params.MainNetHomesteadBlock
}
} }
return &core.ChainConfig{HomesteadBlock: homesteadBlockNo} if config.DAOForkBlock == nil {
if ctx.GlobalBool(TestNetFlag.Name) {
config.DAOForkBlock = params.TestNetDAOForkBlock
} else {
config.DAOForkBlock = params.MainNetDAOForkBlock
}
config.DAOForkSupport = true
}
// Force override any existing configs if explicitly requested
switch {
case ctx.GlobalBool(SupportDAOFork.Name):
config.DAOForkSupport = true
case ctx.GlobalBool(OpposeDAOFork.Name):
config.DAOForkSupport = false
}
// Temporarilly display a proper message so the user knows which fork its on
if !ctx.GlobalBool(TestNetFlag.Name) && (genesis == nil || genesis.Hash() == common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")) {
choice := "SUPPORT"
if !config.DAOForkSupport {
choice = "OPPOSE"
}
current := fmt.Sprintf("Geth is currently configured to %s the DAO hard-fork!", choice)
howtoswap := fmt.Sprintf("You can change your choice prior to block #%v with --support-dao-fork or --oppose-dao-fork.", config.DAOForkBlock)
howtosync := fmt.Sprintf("After the hard-fork block #%v passed, changing chains requires a resync from scratch!", config.DAOForkBlock)
separator := strings.Repeat("-", len(howtoswap))
glog.V(logger.Warn).Info(separator)
glog.V(logger.Warn).Info(current)
glog.V(logger.Warn).Info(howtoswap)
glog.V(logger.Warn).Info(howtosync)
glog.V(logger.Warn).Info(separator)
}
return config
} }
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.

View File

@ -1,11 +1,11 @@
FROM alpine:3.3 FROM alpine:3.3
RUN \ RUN \
apk add --update go git make gcc musl-dev gmp-dev gmp && \ apk add --update go git make gcc musl-dev && \
git clone https://github.com/ethereum/go-ethereum && \ git clone https://github.com/ethereum/go-ethereum && \
(cd go-ethereum && make geth) && \ (cd go-ethereum && make geth) && \
cp go-ethereum/build/bin/geth /geth && \ cp go-ethereum/build/bin/geth /geth && \
apk del go git make gcc musl-dev gmp-dev && \ apk del go git make gcc musl-dev && \
rm -rf /go-ethereum && rm -rf /var/cache/apk/* rm -rf /go-ethereum && rm -rf /var/cache/apk/*
EXPOSE 8545 EXPOSE 8545

View File

@ -163,7 +163,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
// Generate a chain of b.N blocks using the supplied block // Generate a chain of b.N blocks using the supplied block
// generator function. // generator function.
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds}) genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds})
chain, _ := GenerateChain(genesis, db, b.N, gen) chain, _ := GenerateChain(nil, genesis, db, b.N, gen)
// Time the insertion of the new chain. // Time the insertion of the new chain.
// State and blocks are stored in the same DB. // State and blocks are stored in the same DB.

View File

@ -247,7 +247,8 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare
return &BlockNonceErr{header.Number, header.Hash(), header.Nonce.Uint64()} return &BlockNonceErr{header.Number, header.Hash(), header.Nonce.Uint64()}
} }
} }
return nil // If all checks passed, validate the extra-data field for hard forks
return ValidateDAOHeaderExtraData(config, header)
} }
// CalcDifficulty is the difficulty adjustment algorithm. It returns // CalcDifficulty is the difficulty adjustment algorithm. It returns

View File

@ -763,14 +763,13 @@ func (self *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err
if ptd == nil { if ptd == nil {
return NonStatTy, ParentError(block.ParentHash()) return NonStatTy, ParentError(block.ParentHash())
} }
localTd := self.GetTd(self.currentBlock.Hash())
externTd := new(big.Int).Add(block.Difficulty(), ptd)
// Make sure no inconsistent state is leaked during insertion // Make sure no inconsistent state is leaked during insertion
self.mu.Lock() self.mu.Lock()
defer self.mu.Unlock() defer self.mu.Unlock()
localTd := self.GetTd(self.currentBlock.Hash())
externTd := new(big.Int).Add(block.Difficulty(), ptd)
// If the total difficulty is higher than our known, add it to the canonical chain // If the total difficulty is higher than our known, add it to the canonical chain
// Second clause in the if statement reduces the vulnerability to selfish mining. // Second clause in the if statement reduces the vulnerability to selfish mining.
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf

View File

@ -712,7 +712,7 @@ func TestFastVsFullChains(t *testing.T) {
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
genesis = GenesisBlockForTesting(gendb, address, funds) genesis = GenesisBlockForTesting(gendb, address, funds)
) )
blocks, receipts := GenerateChain(genesis, gendb, 1024, func(i int, block *BlockGen) { blocks, receipts := GenerateChain(nil, genesis, gendb, 1024, func(i int, block *BlockGen) {
block.SetCoinbase(common.Address{0x00}) block.SetCoinbase(common.Address{0x00})
// If the block number is multiple of 3, send a few bonus transactions to the miner // If the block number is multiple of 3, send a few bonus transactions to the miner
@ -795,7 +795,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
genesis = GenesisBlockForTesting(gendb, address, funds) genesis = GenesisBlockForTesting(gendb, address, funds)
) )
height := uint64(1024) height := uint64(1024)
blocks, receipts := GenerateChain(genesis, gendb, int(height), nil) blocks, receipts := GenerateChain(nil, genesis, gendb, int(height), nil)
// Configure a subchain to roll back // Configure a subchain to roll back
remove := []common.Hash{} remove := []common.Hash{}
@ -895,7 +895,7 @@ func TestChainTxReorgs(t *testing.T) {
// - futureAdd: transaction added after the reorg has already finished // - futureAdd: transaction added after the reorg has already finished
var pastAdd, freshAdd, futureAdd *types.Transaction var pastAdd, freshAdd, futureAdd *types.Transaction
chain, _ := GenerateChain(genesis, db, 3, func(i int, gen *BlockGen) { chain, _ := GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2) pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2)
@ -920,7 +920,7 @@ func TestChainTxReorgs(t *testing.T) {
} }
// overwrite the old chain // overwrite the old chain
chain, _ = GenerateChain(genesis, db, 5, func(i int, gen *BlockGen) { chain, _ = GenerateChain(nil, genesis, db, 5, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3) pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3)
@ -990,7 +990,7 @@ func TestLogReorgs(t *testing.T) {
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux) blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
subs := evmux.Subscribe(RemovedLogsEvent{}) subs := evmux.Subscribe(RemovedLogsEvent{})
chain, _ := GenerateChain(genesis, db, 2, func(i int, gen *BlockGen) { chain, _ := GenerateChain(nil, genesis, db, 2, func(i int, gen *BlockGen) {
if i == 1 { if i == 1 {
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(key1) tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(key1)
if err != nil { if err != nil {
@ -1003,7 +1003,7 @@ func TestLogReorgs(t *testing.T) {
t.Fatalf("failed to insert chain: %v", err) t.Fatalf("failed to insert chain: %v", err)
} }
chain, _ = GenerateChain(genesis, db, 3, func(i int, gen *BlockGen) {}) chain, _ = GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {})
if _, err := blockchain.InsertChain(chain); err != nil { if _, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert forked chain: %v", err) t.Fatalf("failed to insert forked chain: %v", err)
} }
@ -1025,12 +1025,12 @@ func TestReorgSideEvent(t *testing.T) {
evmux := &event.TypeMux{} evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux) blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
chain, _ := GenerateChain(genesis, db, 3, func(i int, gen *BlockGen) {}) chain, _ := GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {})
if _, err := blockchain.InsertChain(chain); err != nil { if _, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert chain: %v", err) t.Fatalf("failed to insert chain: %v", err)
} }
replacementBlocks, _ := GenerateChain(genesis, db, 4, func(i int, gen *BlockGen) { replacementBlocks, _ := GenerateChain(nil, genesis, db, 4, func(i int, gen *BlockGen) {
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(key1) tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(key1)
if i == 2 { if i == 2 {
gen.OffsetTime(-1) gen.OffsetTime(-1)

View File

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
) )
@ -35,7 +36,11 @@ import (
// MakeChainConfig returns a new ChainConfig with the ethereum default chain settings. // MakeChainConfig returns a new ChainConfig with the ethereum default chain settings.
func MakeChainConfig() *ChainConfig { func MakeChainConfig() *ChainConfig {
return &ChainConfig{HomesteadBlock: big.NewInt(0)} return &ChainConfig{
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
}
} }
// FakePow is a non-validating proof of work implementation. // FakePow is a non-validating proof of work implementation.
@ -173,10 +178,27 @@ func (b *BlockGen) OffsetTime(seconds int64) {
// Blocks created by GenerateChain do not contain valid proof of work // Blocks created by GenerateChain do not contain valid proof of work
// values. Inserting them into BlockChain requires use of FakePow or // values. Inserting them into BlockChain requires use of FakePow or
// a similar non-validating proof of work implementation. // a similar non-validating proof of work implementation.
func GenerateChain(parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) { func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) { genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb} b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb}
// Mutate the state and block according to any hard-fork specs
if config == nil {
config = MakeChainConfig()
}
if daoBlock := config.DAOForkBlock; daoBlock != nil {
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
if h.Number.Cmp(daoBlock) >= 0 && h.Number.Cmp(limit) < 0 {
if config.DAOForkSupport {
h.Extra = common.CopyBytes(params.DAOForkBlockExtra)
}
}
}
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(h.Number) == 0 {
ApplyDAOHardFork(statedb)
}
// Execute any user modifications to the block and finalize it
if gen != nil { if gen != nil {
gen(i, b) gen(i, b)
} }
@ -261,7 +283,7 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
// makeBlockChain creates a deterministic chain of blocks rooted at parent. // makeBlockChain creates a deterministic chain of blocks rooted at parent.
func makeBlockChain(parent *types.Block, n int, db ethdb.Database, seed int) []*types.Block { func makeBlockChain(parent *types.Block, n int, db ethdb.Database, seed int) []*types.Block {
blocks, _ := GenerateChain(parent, db, n, func(i int, b *BlockGen) { blocks, _ := GenerateChain(nil, parent, db, n, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
}) })
return blocks return blocks

View File

@ -47,7 +47,7 @@ func ExampleGenerateChain() {
// This call generates a chain of 5 blocks. The function runs for // This call generates a chain of 5 blocks. The function runs for
// each block and adds different features to gen based on the // each block and adds different features to gen based on the
// block index. // block index.
chain, _ := GenerateChain(genesis, db, 5, func(i int, gen *BlockGen) { chain, _ := GenerateChain(nil, genesis, db, 5, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
// In block 1, addr1 sends addr2 some ether. // In block 1, addr1 sends addr2 some ether.

View File

@ -60,7 +60,7 @@ func TestPowVerification(t *testing.T) {
var ( var (
testdb, _ = ethdb.NewMemDatabase() testdb, _ = ethdb.NewMemDatabase()
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int)) genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
blocks, _ = GenerateChain(genesis, testdb, 8, nil) blocks, _ = GenerateChain(nil, genesis, testdb, 8, nil)
) )
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
for i, block := range blocks { for i, block := range blocks {
@ -115,7 +115,7 @@ func testPowConcurrentVerification(t *testing.T, threads int) {
var ( var (
testdb, _ = ethdb.NewMemDatabase() testdb, _ = ethdb.NewMemDatabase()
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int)) genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
blocks, _ = GenerateChain(genesis, testdb, 8, nil) blocks, _ = GenerateChain(nil, genesis, testdb, 8, nil)
) )
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
for i, block := range blocks { for i, block := range blocks {
@ -186,7 +186,7 @@ func testPowConcurrentAbortion(t *testing.T, threads int) {
var ( var (
testdb, _ = ethdb.NewMemDatabase() testdb, _ = ethdb.NewMemDatabase()
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int)) genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
blocks, _ = GenerateChain(genesis, testdb, 1024, nil) blocks, _ = GenerateChain(nil, genesis, testdb, 1024, nil)
) )
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
for i, block := range blocks { for i, block := range blocks {

View File

@ -31,16 +31,17 @@ var ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general conf
// that any network, identified by its genesis block, can have its own // that any network, identified by its genesis block, can have its own
// set of configuration options. // set of configuration options.
type ChainConfig struct { type ChainConfig struct {
HomesteadBlock *big.Int // homestead switch block HomesteadBlock *big.Int `json:"homesteadBlock"` // Homestead switch block (nil = no fork, 0 = already homestead)
DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork)
DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork
VmConfig vm.Config `json:"-"` VmConfig vm.Config `json:"-"`
} }
// IsHomestead returns whether num is either equal to the homestead block or greater. // IsHomestead returns whether num is either equal to the homestead block or greater.
func (c *ChainConfig) IsHomestead(num *big.Int) bool { func (c *ChainConfig) IsHomestead(num *big.Int) bool {
if num == nil { if c.HomesteadBlock == nil || num == nil {
return false return false
} }
return num.Cmp(c.HomesteadBlock) >= 0 return num.Cmp(c.HomesteadBlock) >= 0
} }

74
core/dao.go Normal file
View File

@ -0,0 +1,74 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"bytes"
"math/big"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
// ValidateDAOHeaderExtraData validates the extra-data field of a block header to
// ensure it conforms to DAO hard-fork rules.
//
// DAO hard-fork extension to the header validity:
// a) if the node is no-fork, do not accept blocks in the [fork, fork+10) range
// with the fork specific extra-data set
// b) if the node is pro-fork, require blocks in the specific range to have the
// unique extra-data set.
func ValidateDAOHeaderExtraData(config *ChainConfig, header *types.Header) error {
// Short circuit validation if the node doesn't care about the DAO fork
if config.DAOForkBlock == nil {
return nil
}
// Make sure the block is within the fork's modified extra-data range
limit := new(big.Int).Add(config.DAOForkBlock, params.DAOForkExtraRange)
if header.Number.Cmp(config.DAOForkBlock) < 0 || header.Number.Cmp(limit) >= 0 {
return nil
}
// Depending whether we support or oppose the fork, validate the extra-data contents
if config.DAOForkSupport {
if bytes.Compare(header.Extra, params.DAOForkBlockExtra) != 0 {
return ValidationError("DAO pro-fork bad block extra-data: 0x%x", header.Extra)
}
} else {
if bytes.Compare(header.Extra, params.DAOForkBlockExtra) == 0 {
return ValidationError("DAO no-fork bad block extra-data: 0x%x", header.Extra)
}
}
// All ok, header has the same extra-data we expect
return nil
}
// ApplyDAOHardFork modifies the state database according to the DAO hard-fork
// rules, transferring all balances of a set of DAO accounts to a single refund
// contract.
func ApplyDAOHardFork(statedb *state.StateDB) {
// Retrieve the contract to refund balances into
refund := statedb.GetOrNewStateObject(params.DAORefundContract)
// Move every DAO account and extra-balance account funds into the refund contract
for _, addr := range params.DAODrainList {
if account := statedb.GetStateObject(addr); account != nil {
refund.AddBalance(account.Balance())
account.SetBalance(new(big.Int))
}
}
}

132
core/dao_test.go Normal file
View File

@ -0,0 +1,132 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
)
// Tests that DAO-fork enabled clients can properly filter out fork-commencing
// blocks based on their extradata fields.
func TestDAOForkRangeExtradata(t *testing.T) {
forkBlock := big.NewInt(32)
// Generate a common prefix for both pro-forkers and non-forkers
db, _ := ethdb.NewMemDatabase()
genesis := WriteGenesisBlockForTesting(db)
prefix, _ := GenerateChain(nil, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
// Create the concurrent, conflicting two nodes
proDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(proDb)
proConf := &ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
proBc, _ := NewBlockChain(proDb, proConf, new(FakePow), new(event.TypeMux))
conDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(conDb)
conConf := &ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
conBc, _ := NewBlockChain(conDb, conConf, new(FakePow), new(event.TypeMux))
if _, err := proBc.InsertChain(prefix); err != nil {
t.Fatalf("pro-fork: failed to import chain prefix: %v", err)
}
if _, err := conBc.InsertChain(prefix); err != nil {
t.Fatalf("con-fork: failed to import chain prefix: %v", err)
}
// Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
// Create a pro-fork block, and try to feed into the no-fork chain
db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db)
bc, _ := NewBlockChain(db, conConf, new(FakePow), new(event.TypeMux))
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
for j := 0; j < len(blocks)/2; j++ {
blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
}
if _, err := bc.InsertChain(blocks); err != nil {
t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
}
blocks, _ = GenerateChain(proConf, conBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) {})
if _, err := conBc.InsertChain(blocks); err == nil {
t.Fatalf("contra-fork chain accepted pro-fork block: %v", blocks[0])
}
// Create a proper no-fork block for the contra-forker
blocks, _ = GenerateChain(conConf, conBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) {})
if _, err := conBc.InsertChain(blocks); err != nil {
t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err)
}
// Create a no-fork block, and try to feed into the pro-fork chain
db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db)
bc, _ = NewBlockChain(db, proConf, new(FakePow), new(event.TypeMux))
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
for j := 0; j < len(blocks)/2; j++ {
blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
}
if _, err := bc.InsertChain(blocks); err != nil {
t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
}
blocks, _ = GenerateChain(conConf, proBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) {})
if _, err := proBc.InsertChain(blocks); err == nil {
t.Fatalf("pro-fork chain accepted contra-fork block: %v", blocks[0])
}
// Create a proper pro-fork block for the pro-forker
blocks, _ = GenerateChain(proConf, proBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) {})
if _, err := proBc.InsertChain(blocks); err != nil {
t.Fatalf("pro-fork chain didn't accepted pro-fork block: %v", err)
}
}
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db)
bc, _ := NewBlockChain(db, conConf, new(FakePow), new(event.TypeMux))
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
for j := 0; j < len(blocks)/2; j++ {
blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
}
if _, err := bc.InsertChain(blocks); err != nil {
t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
}
blocks, _ = GenerateChain(proConf, conBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) {})
if _, err := conBc.InsertChain(blocks); err != nil {
t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err)
}
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db)
bc, _ = NewBlockChain(db, proConf, new(FakePow), new(event.TypeMux))
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
for j := 0; j < len(blocks)/2; j++ {
blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
}
if _, err := bc.InsertChain(blocks); err != nil {
t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
}
blocks, _ = GenerateChain(conConf, proBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) {})
if _, err := proBc.InsertChain(blocks); err != nil {
t.Fatalf("pro-fork chain didn't accept contra-fork block post-fork: %v", err)
}
}

View File

@ -561,7 +561,7 @@ func TestMipmapChain(t *testing.T) {
defer db.Close() defer db.Close()
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)}) genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)})
chain, receipts := GenerateChain(genesis, db, 1010, func(i int, gen *BlockGen) { chain, receipts := GenerateChain(nil, genesis, db, 1010, func(i int, gen *BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
case 1: case 1:

View File

@ -65,7 +65,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
allLogs vm.Logs allLogs vm.Logs
gp = new(GasPool).AddGas(block.GasLimit()) gp = new(GasPool).AddGas(block.GasLimit())
) )
// Mutate the the block and state according to any hard-fork specs
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
ApplyDAOHardFork(statedb)
}
// Iterate over and process the individual transactions
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
statedb.StartRecord(tx.Hash(), block.Hash(), i) statedb.StartRecord(tx.Hash(), block.Hash(), i)
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg) receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)

View File

@ -250,6 +250,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if config.ChainConfig == nil { if config.ChainConfig == nil {
return nil, errors.New("missing chain config") return nil, errors.New("missing chain config")
} }
core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig)
eth.chainConfig = config.ChainConfig eth.chainConfig = config.ChainConfig
eth.chainConfig.VmConfig = vm.Config{ eth.chainConfig.VmConfig = vm.Config{
EnableJit: config.EnableJit, EnableJit: config.EnableJit,

View File

@ -32,7 +32,7 @@ func TestMipmapUpgrade(t *testing.T) {
addr := common.BytesToAddress([]byte("jeff")) addr := common.BytesToAddress([]byte("jeff"))
genesis := core.WriteGenesisBlockForTesting(db) genesis := core.WriteGenesisBlockForTesting(db)
chain, receipts := core.GenerateChain(genesis, db, 10, func(i int, gen *core.BlockGen) { chain, receipts := core.GenerateChain(nil, genesis, db, 10, func(i int, gen *core.BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
case 1: case 1:

View File

@ -1859,7 +1859,7 @@ func (d *Downloader) processContent() error {
} }
if err != nil { if err != nil {
glog.V(logger.Debug).Infof("Result #%d [%x…] processing failed: %v", results[index].Header.Number, results[index].Header.Hash().Bytes()[:4], err) glog.V(logger.Debug).Infof("Result #%d [%x…] processing failed: %v", results[index].Header.Number, results[index].Header.Hash().Bytes()[:4], err)
return err return errInvalidChain
} }
// Shift the results to the next batch // Shift the results to the next batch
results = results[items:] results = results[items:]

View File

@ -55,7 +55,7 @@ func init() {
// reassembly. // reassembly.
func makeChain(n int, seed byte, parent *types.Block, parentReceipts types.Receipts, heavy bool) ([]common.Hash, map[common.Hash]*types.Header, map[common.Hash]*types.Block, map[common.Hash]types.Receipts) { func makeChain(n int, seed byte, parent *types.Block, parentReceipts types.Receipts, heavy bool) ([]common.Hash, map[common.Hash]*types.Header, map[common.Hash]*types.Block, map[common.Hash]types.Receipts) {
// Generate the block chain // Generate the block chain
blocks, receipts := core.GenerateChain(parent, testdb, n, func(i int, block *core.BlockGen) { blocks, receipts := core.GenerateChain(nil, parent, testdb, n, func(i int, block *core.BlockGen) {
block.SetCoinbase(common.Address{seed}) block.SetCoinbase(common.Address{seed})
// If a heavy chain is requested, delay blocks to raise difficulty // If a heavy chain is requested, delay blocks to raise difficulty

View File

@ -45,7 +45,7 @@ var (
// contains a transaction and every 5th an uncle to allow testing correct block // contains a transaction and every 5th an uncle to allow testing correct block
// reassembly. // reassembly.
func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) {
blocks, _ := core.GenerateChain(parent, testdb, n, func(i int, block *core.BlockGen) { blocks, _ := core.GenerateChain(nil, parent, testdb, n, func(i int, block *core.BlockGen) {
block.SetCoinbase(common.Address{seed}) block.SetCoinbase(common.Address{seed})
// If the block number is multiple of 3, send a bonus transaction to the miner // If the block number is multiple of 3, send a bonus transaction to the miner

View File

@ -57,7 +57,7 @@ func BenchmarkMipmaps(b *testing.B) {
defer db.Close() defer db.Close()
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)}) genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)})
chain, receipts := core.GenerateChain(genesis, db, 100010, func(i int, gen *core.BlockGen) { chain, receipts := core.GenerateChain(nil, genesis, db, 100010, func(i int, gen *core.BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
case 2403: case 2403:
@ -133,7 +133,7 @@ func TestFilters(t *testing.T) {
defer db.Close() defer db.Close()
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)}) genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)})
chain, receipts := core.GenerateChain(genesis, db, 1000, func(i int, gen *core.BlockGen) { chain, receipts := core.GenerateChain(nil, genesis, db, 1000, func(i int, gen *core.BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
case 1: case 1:

View File

@ -45,6 +45,10 @@ const (
estHeaderRlpSize = 500 // Approximate size of an RLP encoded block header estHeaderRlpSize = 500 // Approximate size of an RLP encoded block header
) )
var (
daoChallengeTimeout = 15 * time.Second // Time allowance for a node to reply to the DAO handshake challenge
)
// errIncompatibleConfig is returned if the requested protocols and configs are // errIncompatibleConfig is returned if the requested protocols and configs are
// not compatible (low protocol version restrictions and high requirements). // not compatible (low protocol version restrictions and high requirements).
var errIncompatibleConfig = errors.New("incompatible configuration") var errIncompatibleConfig = errors.New("incompatible configuration")
@ -62,9 +66,10 @@ type ProtocolManager struct {
fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks) fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks)
synced uint32 // Flag whether we're considered synchronised (enables transaction processing) synced uint32 // Flag whether we're considered synchronised (enables transaction processing)
txpool txPool txpool txPool
blockchain *core.BlockChain blockchain *core.BlockChain
chaindb ethdb.Database chaindb ethdb.Database
chainconfig *core.ChainConfig
downloader *downloader.Downloader downloader *downloader.Downloader
fetcher *fetcher.Fetcher fetcher *fetcher.Fetcher
@ -99,6 +104,7 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int,
txpool: txpool, txpool: txpool,
blockchain: blockchain, blockchain: blockchain,
chaindb: chaindb, chaindb: chaindb,
chainconfig: config,
peers: newPeerSet(), peers: newPeerSet(),
newPeerCh: make(chan *peer), newPeerCh: make(chan *peer),
noMorePeers: make(chan struct{}), noMorePeers: make(chan struct{}),
@ -278,6 +284,18 @@ func (pm *ProtocolManager) handle(p *peer) error {
// after this will be sent via broadcasts. // after this will be sent via broadcasts.
pm.syncTransactions(p) pm.syncTransactions(p)
// If we're DAO hard-fork aware, validate any remote peer with regard to the hard-fork
if daoBlock := pm.chainconfig.DAOForkBlock; daoBlock != nil {
// Request the peer's DAO fork header for extra-data validation
if err := p.RequestHeadersByNumber(daoBlock.Uint64(), 1, 0, false); err != nil {
return err
}
// Start a timer to disconnect if the peer doesn't reply in time
p.forkDrop = time.AfterFunc(daoChallengeTimeout, func() {
glog.V(logger.Warn).Infof("%v: timed out DAO fork-check, dropping", p)
pm.removePeer(p.id)
})
}
// main loop. handle incoming messages. // main loop. handle incoming messages.
for { for {
if err := pm.handleMsg(p); err != nil { if err := pm.handleMsg(p); err != nil {
@ -479,9 +497,43 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if err := msg.Decode(&headers); err != nil { if err := msg.Decode(&headers); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err) return errResp(ErrDecode, "msg %v: %v", msg, err)
} }
// If no headers were received, but we're expending a DAO fork check, maybe it's that
if len(headers) == 0 && p.forkDrop != nil {
// Possibly an empty reply to the fork header checks, sanity check TDs
verifyDAO := true
// If we already have a DAO header, we can check the peer's TD against it. If
// the peer's ahead of this, it too must have a reply to the DAO check
if daoHeader := pm.blockchain.GetHeaderByNumber(pm.chainconfig.DAOForkBlock.Uint64()); daoHeader != nil {
if p.Td().Cmp(pm.blockchain.GetTd(daoHeader.Hash())) >= 0 {
verifyDAO = false
}
}
// If we're seemingly on the same chain, disable the drop timer
if verifyDAO {
glog.V(logger.Debug).Infof("%v: seems to be on the same side of the DAO fork", p)
p.forkDrop.Stop()
p.forkDrop = nil
return nil
}
}
// Filter out any explicitly requested headers, deliver the rest to the downloader // Filter out any explicitly requested headers, deliver the rest to the downloader
filter := len(headers) == 1 filter := len(headers) == 1
if filter { if filter {
// If it's a potential DAO fork check, validate against the rules
if p.forkDrop != nil && pm.chainconfig.DAOForkBlock.Cmp(headers[0].Number) == 0 {
// Disable the fork drop timer
p.forkDrop.Stop()
p.forkDrop = nil
// Validate the header and either drop the peer or continue
if err := core.ValidateDAOHeaderExtraData(pm.chainconfig, headers[0]); err != nil {
glog.V(logger.Debug).Infof("%v: verified to be on the other side of the DAO fork, dropping", p)
return err
}
glog.V(logger.Debug).Infof("%v: verified to be on the same side of the DAO fork", p)
}
// Irrelevant of the fork checks, send the header to the fetcher just in case
headers = pm.fetcher.FilterHeaders(headers, time.Now()) headers = pm.fetcher.FilterHeaders(headers, time.Now())
} }
if len(headers) > 0 || !filter { if len(headers) > 0 || !filter {

View File

@ -20,6 +20,7 @@ import (
"math/big" "math/big"
"math/rand" "math/rand"
"testing" "testing"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
@ -28,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -580,3 +582,75 @@ func testGetReceipt(t *testing.T, protocol int) {
t.Errorf("receipts mismatch: %v", err) t.Errorf("receipts mismatch: %v", err)
} }
} }
// Tests that post eth protocol handshake, DAO fork-enabled clients also execute
// a DAO "challenge" verifying each others' DAO fork headers to ensure they're on
// compatible chains.
func TestDAOChallengeNoVsNo(t *testing.T) { testDAOChallenge(t, false, false, false) }
func TestDAOChallengeNoVsPro(t *testing.T) { testDAOChallenge(t, false, true, false) }
func TestDAOChallengeProVsNo(t *testing.T) { testDAOChallenge(t, true, false, false) }
func TestDAOChallengeProVsPro(t *testing.T) { testDAOChallenge(t, true, true, false) }
func TestDAOChallengeNoVsTimeout(t *testing.T) { testDAOChallenge(t, false, false, true) }
func TestDAOChallengeProVsTimeout(t *testing.T) { testDAOChallenge(t, true, true, true) }
func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool) {
// Reduce the DAO handshake challenge timeout
if timeout {
defer func(old time.Duration) { daoChallengeTimeout = old }(daoChallengeTimeout)
daoChallengeTimeout = 500 * time.Millisecond
}
// Create a DAO aware protocol manager
var (
evmux = new(event.TypeMux)
pow = new(core.FakePow)
db, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(db)
config = &core.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
blockchain, _ = core.NewBlockChain(db, config, pow, evmux)
)
pm, err := NewProtocolManager(config, false, NetworkId, evmux, new(testTxPool), pow, blockchain, db)
if err != nil {
t.Fatalf("failed to start test protocol manager: %v", err)
}
pm.Start()
defer pm.Stop()
// Connect a new peer and check that we receive the DAO challenge
peer, _ := newTestPeer("peer", eth63, pm, true)
defer peer.close()
challenge := &getBlockHeadersData{
Origin: hashOrNumber{Number: config.DAOForkBlock.Uint64()},
Amount: 1,
Skip: 0,
Reverse: false,
}
if err := p2p.ExpectMsg(peer.app, GetBlockHeadersMsg, challenge); err != nil {
t.Fatalf("challenge mismatch: %v", err)
}
// Create a block to reply to the challenge if no timeout is simualted
if !timeout {
blocks, _ := core.GenerateChain(nil, genesis, db, 1, func(i int, block *core.BlockGen) {
if remoteForked {
block.SetExtra(params.DAOForkBlockExtra)
}
})
if err := p2p.Send(peer.app, BlockHeadersMsg, []*types.Header{blocks[0].Header()}); err != nil {
t.Fatalf("failed to answer challenge: %v", err)
}
time.Sleep(100 * time.Millisecond) // Sleep to avoid the verification racing with the drops
} else {
// Otherwise wait until the test timeout passes
time.Sleep(daoChallengeTimeout + 500*time.Millisecond)
}
// Verify that depending on fork side, the remote peer is maintained or dropped
if localForked == remoteForked && !timeout {
if peers := pm.peers.Len(); peers != 1 {
t.Fatalf("peer count mismatch: have %d, want %d", peers, 1)
}
} else {
if peers := pm.peers.Len(); peers != 0 {
t.Fatalf("peer count mismatch: have %d, want %d", peers, 0)
}
}
}

View File

@ -56,7 +56,7 @@ func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core
chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux) blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux)
) )
chain, _ := core.GenerateChain(genesis, db, blocks, generator) chain, _ := core.GenerateChain(nil, genesis, db, blocks, generator)
if _, err := blockchain.InsertChain(chain); err != nil { if _, err := blockchain.InsertChain(chain); err != nil {
panic(err) panic(err)
} }

View File

@ -59,10 +59,12 @@ type peer struct {
*p2p.Peer *p2p.Peer
rw p2p.MsgReadWriter rw p2p.MsgReadWriter
version int // Protocol version negotiated version int // Protocol version negotiated
head common.Hash forkDrop *time.Timer // Timed connection dropper if forks aren't validated in time
td *big.Int
lock sync.RWMutex head common.Hash
td *big.Int
lock sync.RWMutex
knownTxs *set.Set // Set of transaction hashes known to be known by this peer knownTxs *set.Set // Set of transaction hashes known to be known by this peer
knownBlocks *set.Set // Set of block hashes known to be known by this peer knownBlocks *set.Set // Set of block hashes known to be known by this peer

View File

@ -37,10 +37,10 @@ const (
var ProtocolName = "eth" var ProtocolName = "eth"
// Supported versions of the eth protocol (first is primary). // Supported versions of the eth protocol (first is primary).
var ProtocolVersions = []uint{eth63, eth62, eth61} var ProtocolVersions = []uint{eth63, eth62}
// Number of implemented message corresponding to different protocol versions. // Number of implemented message corresponding to different protocol versions.
var ProtocolLengths = []uint64{17, 8, 9} var ProtocolLengths = []uint64{17, 8}
const ( const (
NetworkId = 1 NetworkId = 1

View File

@ -17,6 +17,7 @@
package miner package miner
import ( import (
"bytes"
"fmt" "fmt"
"math/big" "math/big"
"sync" "sync"
@ -33,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"gopkg.in/fatih/set.v0" "gopkg.in/fatih/set.v0"
) )
@ -468,7 +470,19 @@ func (self *worker) commitNewWork() {
Extra: self.extra, Extra: self.extra,
Time: big.NewInt(tstamp), Time: big.NewInt(tstamp),
} }
// If we are care about TheDAO hard-fork check whether to override the extra-data or not
if daoBlock := self.config.DAOForkBlock; daoBlock != nil {
// Check whether the block is among the fork extra-override range
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 {
// Depending whether we support or oppose the fork, override differently
if self.config.DAOForkSupport {
header.Extra = common.CopyBytes(params.DAOForkBlockExtra)
} else if bytes.Compare(header.Extra, params.DAOForkBlockExtra) == 0 {
header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data
}
}
}
previous := self.current previous := self.current
// Could potentially happen if starting to mine in an odd state. // Could potentially happen if starting to mine in an odd state.
err := self.makeCurrent(parent, header) err := self.makeCurrent(parent, header)
@ -476,7 +490,11 @@ func (self *worker) commitNewWork() {
glog.V(logger.Info).Infoln("Could not create new env for mining, retrying on next block.") glog.V(logger.Info).Infoln("Could not create new env for mining, retrying on next block.")
return return
} }
// Create the current work task and check any fork transitions needed
work := self.current work := self.current
if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 {
core.ApplyDAOHardFork(work.state)
}
/* //approach 1 /* //approach 1
transactions := self.eth.TxPool().GetTransactions() transactions := self.eth.TxPool().GetTransactions()

418
params/dao.go Normal file
View File

@ -0,0 +1,418 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package params
import (
"encoding/json"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
)
// TestNetDAOForkBlock is the block number where the DAO hard-fork commences on
// the Ethereum test network. It's enforced nil since it was decided not to do a
// testnet transition.
var TestNetDAOForkBlock *big.Int
// MainNetDAOForkBlock is the block number where the DAO hard-fork commences on
// the Ethereum main network.
var MainNetDAOForkBlock = big.NewInt(1920000)
// DAOForkBlockExtra is the block header extra-data field to set for the DAO fork
// point and a number of consecutive blocks to allow fast/light syncers to correctly
// pick the side they want ("dao-hard-fork").
var DAOForkBlockExtra = common.FromHex("0x64616f2d686172642d666f726b")
// DAOForkExtraRange is the number of consecutive blocks from the DAO fork point
// to override the extra-data in to prevent no-fork attacks.
var DAOForkExtraRange = big.NewInt(10)
// DAORefundContract is the address of the refund contract to send DAO balances to.
var DAORefundContract = common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d20bca754")
// DAODrainList is the list of accounts whose full balances will be moved into a
// refund contract at the beginning of the dao-fork block.
var DAODrainList []common.Address
func init() {
// Parse the list of DAO accounts to drain
var list []map[string]string
if err := json.Unmarshal([]byte(daoDrainListJSON), &list); err != nil {
panic(fmt.Errorf("Failed to parse DAO drain list: %v", err))
}
// Collect all the accounts that need draining
for _, dao := range list {
DAODrainList = append(DAODrainList, common.HexToAddress(dao["address"]))
DAODrainList = append(DAODrainList, common.HexToAddress(dao["extraBalanceAccount"]))
}
}
// daoDrainListJSON is the JSON encoded list of accounts whose full balances will
// be moved into a refund contract at the beginning of the dao-fork block.
const daoDrainListJSON = `
[
{
"address":"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"balance":"186cc8bfaefb7be",
"extraBalance":"0",
"extraBalanceAccount":"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"
},
{
"address":"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
"balance":"b14e8feab1ff435",
"extraBalance":"0",
"extraBalanceAccount":"0xecd135fa4f61a655311e86238c92adcd779555d2"
},
{
"address":"0x1975bd06d486162d5dc297798dfc41edd5d160a7",
"balance":"359d26614cb5070c77",
"extraBalance":"0",
"extraBalanceAccount":"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6"
},
{
"address":"0x319f70bab6845585f412ec7724b744fec6095c85",
"balance":"6e075cd846d2cb1d42",
"extraBalance":"13d34fd41b545b81",
"extraBalanceAccount":"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936"
},
{
"address":"0x5c8536898fbb74fc7445814902fd08422eac56d0",
"balance":"b1e5593558008fd78",
"extraBalance":"0",
"extraBalanceAccount":"0x6966ab0d485353095148a2155858910e0965b6f9"
},
{
"address":"0x779543a0491a837ca36ce8c635d6154e3c4911a6",
"balance":"392eaa20d1aad59a4c",
"extraBalance":"426938826a96c9",
"extraBalanceAccount":"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c"
},
{
"address":"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5",
"balance":"2875d22b29793d4ba7",
"extraBalance":"0",
"extraBalanceAccount":"0x9c50426be05db97f5d64fc54bf89eff947f0a321"
},
{
"address":"0x200450f06520bdd6c527622a273333384d870efb",
"balance":"43c341d9f96954c049",
"extraBalance":"0",
"extraBalanceAccount":"0xbe8539bfe837b67d1282b2b1d61c3f723966f049"
},
{
"address":"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb",
"balance":"75251057154d70fa816",
"extraBalance":"0",
"extraBalanceAccount":"0xf1385fb24aad0cd7432824085e42aff90886fef5"
},
{
"address":"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091",
"balance":"392409769296cf67f36",
"extraBalance":"0",
"extraBalanceAccount":"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd"
},
{
"address":"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6",
"balance":"8ac72eccbf4e8083",
"extraBalance":"0",
"extraBalanceAccount":"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7"
},
{
"address":"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5",
"balance":"82289c3bb3e8c98799",
"extraBalance":"0",
"extraBalanceAccount":"0x24c4d950dfd4dd1902bbed3508144a54542bba94"
},
{
"address":"0x9f27daea7aca0aa0446220b98d028715e3bc803d",
"balance":"56bc29049ebed40fd",
"extraBalance":"0",
"extraBalanceAccount":"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90"
},
{
"address":"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b",
"balance":"56bc7d3ff79110524",
"extraBalance":"0",
"extraBalanceAccount":"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf"
},
{
"address":"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d",
"balance":"23b651bd48cbc70cc",
"extraBalance":"0",
"extraBalanceAccount":"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6"
},
{
"address":"0x492ea3bb0f3315521c31f273e565b868fc090f17",
"balance":"13ea6d4fee651dd7c9",
"extraBalance":"0",
"extraBalanceAccount":"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00"
},
{
"address":"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416",
"balance":"35ac471a3836ae7de5a",
"extraBalance":"0",
"extraBalanceAccount":"0xceaeb481747ca6c540a000c1f3641f8cef161fa7"
},
{
"address":"0xcc34673c6c40e791051898567a1222daf90be287",
"balance":"d529c0b76b7aa0",
"extraBalance":"0",
"extraBalanceAccount":"0x579a80d909f346fbfb1189493f521d7f48d52238"
},
{
"address":"0xe308bd1ac5fda103967359b2712dd89deffb7973",
"balance":"5cd9e7df3a8e5cdd3",
"extraBalance":"0",
"extraBalanceAccount":"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c"
},
{
"address":"0xac1ecab32727358dba8962a0f3b261731aad9723",
"balance":"2c8442fe35363313b93",
"extraBalance":"0",
"extraBalanceAccount":"0x4fd6ace747f06ece9c49699c7cabc62d02211f75"
},
{
"address":"0x440c59b325d2997a134c2c7c60a8c61611212bad",
"balance":"e77583a3958130e53",
"extraBalance":"0",
"extraBalanceAccount":"0x4486a3d68fac6967006d7a517b889fd3f98c102b"
},
{
"address":"0x9c15b54878ba618f494b38f0ae7443db6af648ba",
"balance":"1f0b6ade348ca998",
"extraBalance":"0",
"extraBalanceAccount":"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f"
},
{
"address":"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241",
"balance":"61725880736659",
"extraBalance":"0",
"extraBalanceAccount":"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50"
},
{
"address":"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b",
"balance":"42948d8dc7ddbc22d",
"extraBalance":"0",
"extraBalanceAccount":"0xb9637156d330c0d605a791f1c31ba5890582fe1c"
},
{
"address":"0x6131c42fa982e56929107413a9d526fd99405560",
"balance":"7306683851d1eafbfa",
"extraBalance":"0",
"extraBalanceAccount":"0x1591fc0f688c81fbeb17f5426a162a7024d430c2"
},
{
"address":"0x542a9515200d14b68e934e9830d91645a980dd7a",
"balance":"2a8457d0d8432e21d0c",
"extraBalance":"0",
"extraBalanceAccount":"0xc4bbd073882dd2add2424cf47d35213405b01324"
},
{
"address":"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4",
"balance":"d8d7391feaeaa8cdb",
"extraBalance":"0",
"extraBalanceAccount":"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb"
},
{
"address":"0x3ba4d81db016dc2890c81f3acec2454bff5aada5",
"balance":"1",
"extraBalance":"0",
"extraBalanceAccount":"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab"
},
{
"address":"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1",
"balance":"456397665fa74041",
"extraBalance":"0",
"extraBalanceAccount":"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5"
},
{
"address":"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53",
"balance":"6324dcb7126ecbef",
"extraBalance":"0",
"extraBalanceAccount":"0x97f43a37f595ab5dd318fb46e7a155eae057317a"
},
{
"address":"0x52c5317c848ba20c7504cb2c8052abd1fde29d03",
"balance":"6c3419b0705c01cd0d",
"extraBalance":"0",
"extraBalanceAccount":"0x4863226780fe7c0356454236d3b1c8792785748d"
},
{
"address":"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479",
"balance":"456397665fa74041",
"extraBalance":"0",
"extraBalanceAccount":"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c"
},
{
"address":"0x057b56736d32b86616a10f619859c6cd6f59092a",
"balance":"232c025bb44b46",
"extraBalance":"0",
"extraBalanceAccount":"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192"
},
{
"address":"0x304a554a310c7e546dfe434669c62820b7d83490",
"balance":"3034f5ca7d45e17df199b",
"extraBalance":"f7d15162c44e97b6e",
"extraBalanceAccount":"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79"
},
{
"address":"0x4deb0033bb26bc534b197e61d19e0733e5679784",
"balance":"4417e96ed796591e09",
"extraBalance":"0",
"extraBalanceAccount":"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a"
},
{
"address":"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b",
"balance":"d3ff7771412bbcc9",
"extraBalance":"0",
"extraBalanceAccount":"0x4fa802324e929786dbda3b8820dc7834e9134a2a"
},
{
"address":"0x9da397b9e80755301a3b32173283a91c0ef6c87e",
"balance":"32ae324c233816b4c2",
"extraBalance":"0",
"extraBalanceAccount":"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6"
},
{
"address":"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9",
"balance":"1e530695b705f037c6",
"extraBalance":"0",
"extraBalanceAccount":"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f"
},
{
"address":"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76",
"balance":"68013bad5b4b1133fc5",
"extraBalance":"0",
"extraBalanceAccount":"0x12e626b0eebfe86a56d633b9864e389b45dcb260"
},
{
"address":"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7",
"balance":"456397665fa74041",
"extraBalance":"0",
"extraBalanceAccount":"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5"
},
{
"address":"0xd164b088bd9108b60d0ca3751da4bceb207b0782",
"balance":"3635ce47fabaaa336e",
"extraBalance":"0",
"extraBalanceAccount":"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b"
},
{
"address":"0x1cba23d343a983e9b5cfd19496b9a9701ada385f",
"balance":"f3abd9906c170a",
"extraBalance":"0",
"extraBalanceAccount":"0xa82f360a8d3455c5c41366975bde739c37bfeb8a"
},
{
"address":"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339",
"balance":"4c6679d9d9b95a4e08",
"extraBalance":"0",
"extraBalanceAccount":"0x005f5cee7a43331d5a3d3eec71305925a62f34b6"
},
{
"address":"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d",
"balance":"40f622936475de31849",
"extraBalance":"671e1bbabded39754",
"extraBalanceAccount":"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e"
},
{
"address":"0xbc07118b9ac290e4622f5e77a0853539789effbe",
"balance":"1316ccfa4a35db5e58f",
"extraBalance":"0",
"extraBalanceAccount":"0x47e7aa56d6bdf3f36be34619660de61275420af8"
},
{
"address":"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225",
"balance":"b3ad6bb72000bab9f",
"extraBalance":"0",
"extraBalanceAccount":"0xadf80daec7ba8dcf15392f1ac611fff65d94f880"
},
{
"address":"0x5524c55fb03cf21f549444ccbecb664d0acad706",
"balance":"16f2da372a5c8a70967",
"extraBalance":"0",
"extraBalanceAccount":"0x40b803a9abce16f50f36a77ba41180eb90023925"
},
{
"address":"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
"balance":"ea0b1bdc78f500a43",
"extraBalance":"0",
"extraBalanceAccount":"0x17802f43a0137c506ba92291391a8a8f207f487d"
},
{
"address":"0x253488078a4edf4d6f42f113d1e62836a942cf1a",
"balance":"3060e3aed135cc80",
"extraBalance":"0",
"extraBalanceAccount":"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915"
},
{
"address":"0xb136707642a4ea12fb4bae820f03d2562ebff487",
"balance":"6050bdeb3354b5c98adc3",
"extraBalance":"0",
"extraBalanceAccount":"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940"
},
{
"address":"0xf14c14075d6c4ed84b86798af0956deef67365b5",
"balance":"1d77844e94c25ba2",
"extraBalance":"0",
"extraBalanceAccount":"0xca544e5c4687d109611d0f8f928b53a25af72448"
},
{
"address":"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
"balance":"2e93a72de4fc5ec0ed",
"extraBalance":"0",
"extraBalanceAccount":"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7"
},
{
"address":"0x6d87578288b6cb5549d5076a207456a1f6a63dc0",
"balance":"1afd340799e48c18",
"extraBalance":"0",
"extraBalanceAccount":"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e"
},
{
"address":"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
"balance":"14d0944eb3be947a8",
"extraBalance":"0",
"extraBalanceAccount":"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2"
},
{
"address":"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
"balance":"6202b236a200e365eba",
"extraBalance":"11979be9020f03ec4ec",
"extraBalanceAccount":"0xd343b217de44030afaa275f54d31a9317c7f441e"
},
{
"address":"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
"balance":"7ed634ebbba531901e07",
"extraBalance":"f9c5eff28cb08720c85",
"extraBalanceAccount":"0xda2fef9e4a3230988ff17df2165440f37e8b1708"
},
{
"address":"0xf4c64518ea10f995918a454158c6b61407ea345c",
"balance":"39152e15508a96ff894a",
"extraBalance":"14041ca908bcc185c8",
"extraBalanceAccount":"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97"
},
{
"address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"balance":"1",
"extraBalance":"5553ebc",
"extraBalanceAccount":"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
}
]
`

View File

@ -19,6 +19,6 @@ package params
import "math/big" import "math/big"
var ( var (
TestNetHomesteadBlock = big.NewInt(494000) // testnet homestead block TestNetHomesteadBlock = big.NewInt(494000) // Testnet homestead block
MainNetHomesteadBlock = big.NewInt(1150000) // mainnet homestead block MainNetHomesteadBlock = big.NewInt(1150000) // Mainnet homestead block
) )

View File

@ -23,63 +23,63 @@ import (
) )
func TestBcValidBlockTests(t *testing.T) { func TestBcValidBlockTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcValidBlockTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcValidBlockTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcUncleHeaderValidityTests(t *testing.T) { func TestBcUncleHeaderValidityTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcUncleHeaderValiditiy.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcUncleHeaderValiditiy.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcUncleTests(t *testing.T) { func TestBcUncleTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcUncleTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcUncleTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcForkUncleTests(t *testing.T) { func TestBcForkUncleTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcForkUncle.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcForkUncle.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcInvalidHeaderTests(t *testing.T) { func TestBcInvalidHeaderTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcInvalidHeaderTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcInvalidHeaderTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcInvalidRLPTests(t *testing.T) { func TestBcInvalidRLPTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcInvalidRLPTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcInvalidRLPTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcRPCAPITests(t *testing.T) { func TestBcRPCAPITests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcRPC_API_Test.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcRPC_API_Test.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcForkBlockTests(t *testing.T) { func TestBcForkBlockTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcForkBlockTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcForkBlockTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcForkStress(t *testing.T) { func TestBcForkStress(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcForkStressTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcForkStressTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -89,21 +89,21 @@ func TestBcTotalDifficulty(t *testing.T) {
// skip because these will fail due to selfish mining fix // skip because these will fail due to selfish mining fix
t.Skip() t.Skip()
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcTotalDifficultyTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcTotalDifficultyTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcWallet(t *testing.T) { func TestBcWallet(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcWalletTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcWalletTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcGasPricer(t *testing.T) { func TestBcGasPricer(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcGasPricerTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcGasPricerTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -111,7 +111,7 @@ func TestBcGasPricer(t *testing.T) {
// TODO: iterate over files once we got more than a few // TODO: iterate over files once we got more than a few
func TestBcRandom(t *testing.T) { func TestBcRandom(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "RandomTests/bl201507071825GO.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "RandomTests/bl201507071825GO.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -121,14 +121,14 @@ func TestBcMultiChain(t *testing.T) {
// skip due to selfish mining // skip due to selfish mining
t.Skip() t.Skip()
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcMultiChainTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcMultiChainTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcState(t *testing.T) { func TestBcState(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), filepath.Join(blockTestDir, "bcStateTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcStateTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -136,77 +136,85 @@ func TestBcState(t *testing.T) {
// Homestead tests // Homestead tests
func TestHomesteadBcValidBlockTests(t *testing.T) { func TestHomesteadBcValidBlockTests(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcValidBlockTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcValidBlockTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcUncleHeaderValidityTests(t *testing.T) { func TestHomesteadBcUncleHeaderValidityTests(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcUncleHeaderValiditiy.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcUncleHeaderValiditiy.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcUncleTests(t *testing.T) { func TestHomesteadBcUncleTests(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcUncleTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcUncleTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcInvalidHeaderTests(t *testing.T) { func TestHomesteadBcInvalidHeaderTests(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcInvalidHeaderTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcInvalidHeaderTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcRPCAPITests(t *testing.T) { func TestHomesteadBcRPCAPITests(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcRPC_API_Test.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcRPC_API_Test.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcForkStress(t *testing.T) { func TestHomesteadBcForkStress(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcForkStressTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcForkStressTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcTotalDifficulty(t *testing.T) { func TestHomesteadBcTotalDifficulty(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcTotalDifficultyTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcTotalDifficultyTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcWallet(t *testing.T) { func TestHomesteadBcWallet(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcWalletTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcWalletTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcGasPricer(t *testing.T) { func TestHomesteadBcGasPricer(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcGasPricerTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcGasPricerTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcMultiChain(t *testing.T) { func TestHomesteadBcMultiChain(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcMultiChainTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcMultiChainTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcState(t *testing.T) { func TestHomesteadBcState(t *testing.T) {
err := RunBlockTest(big.NewInt(0), filepath.Join(blockTestDir, "Homestead", "bcStateTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcStateTest.json"), BlockSkipTests)
if err != nil {
t.Fatal(err)
}
}
// DAO hard-fork tests
func TestDAOBcTheDao(t *testing.T) {
err := RunBlockTest(big.NewInt(5), big.NewInt(8), filepath.Join(blockTestDir, "TestNetwork", "bcTheDaoTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -103,7 +103,7 @@ type btTransaction struct {
Value string Value string
} }
func RunBlockTestWithReader(homesteadBlock *big.Int, r io.Reader, skipTests []string) error { func RunBlockTestWithReader(homesteadBlock, daoForkBlock *big.Int, r io.Reader, skipTests []string) error {
btjs := make(map[string]*btJSON) btjs := make(map[string]*btJSON)
if err := readJson(r, &btjs); err != nil { if err := readJson(r, &btjs); err != nil {
return err return err
@ -114,13 +114,13 @@ func RunBlockTestWithReader(homesteadBlock *big.Int, r io.Reader, skipTests []st
return err return err
} }
if err := runBlockTests(homesteadBlock, bt, skipTests); err != nil { if err := runBlockTests(homesteadBlock, daoForkBlock, bt, skipTests); err != nil {
return err return err
} }
return nil return nil
} }
func RunBlockTest(homesteadBlock *big.Int, file string, skipTests []string) error { func RunBlockTest(homesteadBlock, daoForkBlock *big.Int, file string, skipTests []string) error {
btjs := make(map[string]*btJSON) btjs := make(map[string]*btJSON)
if err := readJsonFile(file, &btjs); err != nil { if err := readJsonFile(file, &btjs); err != nil {
return err return err
@ -130,13 +130,13 @@ func RunBlockTest(homesteadBlock *big.Int, file string, skipTests []string) erro
if err != nil { if err != nil {
return err return err
} }
if err := runBlockTests(homesteadBlock, bt, skipTests); err != nil { if err := runBlockTests(homesteadBlock, daoForkBlock, bt, skipTests); err != nil {
return err return err
} }
return nil return nil
} }
func runBlockTests(homesteadBlock *big.Int, bt map[string]*BlockTest, skipTests []string) error { func runBlockTests(homesteadBlock, daoForkBlock *big.Int, bt map[string]*BlockTest, skipTests []string) error {
skipTest := make(map[string]bool, len(skipTests)) skipTest := make(map[string]bool, len(skipTests))
for _, name := range skipTests { for _, name := range skipTests {
skipTest[name] = true skipTest[name] = true
@ -148,7 +148,7 @@ func runBlockTests(homesteadBlock *big.Int, bt map[string]*BlockTest, skipTests
continue continue
} }
// test the block // test the block
if err := runBlockTest(homesteadBlock, test); err != nil { if err := runBlockTest(homesteadBlock, daoForkBlock, test); err != nil {
return fmt.Errorf("%s: %v", name, err) return fmt.Errorf("%s: %v", name, err)
} }
glog.Infoln("Block test passed: ", name) glog.Infoln("Block test passed: ", name)
@ -157,7 +157,7 @@ func runBlockTests(homesteadBlock *big.Int, bt map[string]*BlockTest, skipTests
return nil return nil
} }
func runBlockTest(homesteadBlock *big.Int, test *BlockTest) error { func runBlockTest(homesteadBlock, daoForkBlock *big.Int, test *BlockTest) error {
// import pre accounts & construct test genesis block & state root // import pre accounts & construct test genesis block & state root
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
if _, err := test.InsertPreState(db); err != nil { if _, err := test.InsertPreState(db); err != nil {
@ -169,7 +169,7 @@ func runBlockTest(homesteadBlock *big.Int, test *BlockTest) error {
core.WriteCanonicalHash(db, test.Genesis.Hash(), test.Genesis.NumberU64()) core.WriteCanonicalHash(db, test.Genesis.Hash(), test.Genesis.NumberU64())
core.WriteHeadBlockHash(db, test.Genesis.Hash()) core.WriteHeadBlockHash(db, test.Genesis.Hash())
evmux := new(event.TypeMux) evmux := new(event.TypeMux)
config := &core.ChainConfig{HomesteadBlock: homesteadBlock} config := &core.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true}
chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux) chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux)
if err != nil { if err != nil {
return err return err

File diff suppressed because it is too large Load Diff

View File

@ -141,6 +141,8 @@ type VmTest struct {
type RuleSet struct { type RuleSet struct {
HomesteadBlock *big.Int HomesteadBlock *big.Int
DAOForkBlock *big.Int
DAOForkSupport bool
} }
func (r RuleSet) IsHomestead(n *big.Int) bool { func (r RuleSet) IsHomestead(n *big.Int) bool {

View File

@ -241,7 +241,7 @@ func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs,
caller := state.GetOrNewStateObject(from) caller := state.GetOrNewStateObject(from)
vmenv := NewEnvFromMap(RuleSet{params.MainNetHomesteadBlock}, state, env, exec) vmenv := NewEnvFromMap(RuleSet{params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, true}, state, env, exec)
vmenv.vmTest = true vmenv.vmTest = true
vmenv.skipTransfer = true vmenv.skipTransfer = true
vmenv.initial = true vmenv.initial = true