Merge branch 'master' into lightgolint2

This commit is contained in:
kiel barry 2018-05-07 12:09:28 -07:00 committed by GitHub
commit 2df585114b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
124 changed files with 1949 additions and 1737 deletions

View file

@ -31,7 +31,6 @@ matrix:
script: script:
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703 - unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
- brew update - brew update
- brew install caskroom/cask/brew-cask
- brew cask install osxfuse - brew cask install osxfuse
- go run build/ci.go install - go run build/ci.go install
- go run build/ci.go test -coverage $TEST_PACKAGES - go run build/ci.go test -coverage $TEST_PACKAGES

View file

@ -1 +1 @@
1.8.7 1.8.8

View file

@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -159,7 +160,7 @@ func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Addres
// TransactionReceipt returns the receipt of a transaction. // TransactionReceipt returns the receipt of a transaction.
func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
receipt, _, _, _ := core.GetReceipt(b.database, txHash) receipt, _, _, _ := rawdb.ReadReceipt(b.database, txHash)
return receipt, nil return receipt, nil
} }
@ -430,11 +431,19 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumb
} }
func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil number := rawdb.ReadHeaderNumber(fb.db, hash)
if number == nil {
return nil, nil
}
return rawdb.ReadReceipts(fb.db, hash, *number), nil
} }
func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
receipts := core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)) number := rawdb.ReadHeaderNumber(fb.db, hash)
if number == nil {
return nil, nil
}
receipts := rawdb.ReadReceipts(fb.db, hash, *number)
if receipts == nil { if receipts == nil {
return nil, nil return nil, nil
} }

View file

@ -33,15 +33,15 @@ type Event struct {
Inputs Arguments Inputs Arguments
} }
func (event Event) String() string { func (e Event) String() string {
inputs := make([]string, len(event.Inputs)) inputs := make([]string, len(e.Inputs))
for i, input := range event.Inputs { for i, input := range e.Inputs {
inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type) inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type)
if input.Indexed { if input.Indexed {
inputs[i] = fmt.Sprintf("%v indexed %v", input.Name, input.Type) inputs[i] = fmt.Sprintf("%v indexed %v", input.Name, input.Type)
} }
} }
return fmt.Sprintf("event %v(%v)", event.Name, strings.Join(inputs, ", ")) return fmt.Sprintf("e %v(%v)", e.Name, strings.Join(inputs, ", "))
} }
// Id returns the canonical representation of the event's signature used by the // Id returns the canonical representation of the event's signature used by the

View file

@ -108,9 +108,8 @@ func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) er
func (ks keyStorePassphrase) JoinPath(filename string) string { func (ks keyStorePassphrase) JoinPath(filename string) string {
if filepath.IsAbs(filename) { if filepath.IsAbs(filename) {
return filename return filename
} else {
return filepath.Join(ks.keysDirPath, filename)
} }
return filepath.Join(ks.keysDirPath, filename)
} }
// EncryptKey encrypts a key using the specified scrypt parameters into a json // EncryptKey encrypts a key using the specified scrypt parameters into a json

View file

@ -56,7 +56,6 @@ func (ks keyStorePlain) StoreKey(filename string, key *Key, auth string) error {
func (ks keyStorePlain) JoinPath(filename string) string { func (ks keyStorePlain) JoinPath(filename string) string {
if filepath.IsAbs(filename) { if filepath.IsAbs(filename) {
return filename return filename
} else { }
return filepath.Join(ks.keysDirPath, filename) return filepath.Join(ks.keysDirPath, filename)
} }
}

View file

@ -731,7 +731,7 @@ func doAndroidArchive(cmdline []string) {
// Build the Android archive and Maven resources // Build the Android archive and Maven resources
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind")) build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
build.MustRun(gomobileTool("init", "--ndk", os.Getenv("ANDROID_NDK"))) build.MustRun(gomobileTool("init", "--ndk", os.Getenv("ANDROID_NDK")))
build.MustRun(gomobileTool("bind", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile")) build.MustRun(gomobileTool("bind", "-ldflags", "-s -w", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile"))
if *local { if *local {
// If we're building locally, copy bundle to build dir and skip Maven // If we're building locally, copy bundle to build dir and skip Maven
@ -852,7 +852,7 @@ func doXCodeFramework(cmdline []string) {
// Build the iOS XCode framework // Build the iOS XCode framework
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind")) build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
build.MustRun(gomobileTool("init")) build.MustRun(gomobileTool("init"))
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile") bind := gomobileTool("bind", "-ldflags", "-s -w", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile")
if *local { if *local {
// If we're building locally, use the build folder and stop afterwards // If we're building locally, use the build folder and stop afterwards

View file

@ -12,6 +12,11 @@ synchronised with the chain or a particular Ethereum node that has no built-in (
Clef can run as a daemon on the same machine, or off a usb-stick like [usb armory](https://inversepath.com/usbarmory), Clef can run as a daemon on the same machine, or off a usb-stick like [usb armory](https://inversepath.com/usbarmory),
or a separate VM in a [QubesOS](https://www.qubes-os.org/) type os setup. or a separate VM in a [QubesOS](https://www.qubes-os.org/) type os setup.
Check out
* the [tutorial](tutorial.md) for some concrete examples on how the signer works.
* the [setup docs](docs/setup.md) for some information on how to configure it to work on QubesOS or USBArmory.
## Command line flags ## Command line flags
Clef accepts the following command line options: Clef accepts the following command line options:
@ -49,7 +54,6 @@ Example:
signer -keystore /my/keystore -chainid 4 signer -keystore /my/keystore -chainid 4
``` ```
Check out the [tutorial](tutorial.md) for some concrete examples on how the signer works.
## Security model ## Security model
@ -862,3 +866,12 @@ A UI should conform to the following rules.
along with the UI. along with the UI.
### UI Implementations
There are a couple of implementation for a UI. We'll try to keep this list up to date.
| Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters|
| ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- |
| QtSigner| https://github.com/holiman/qtsigner/| Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: | :+1: (partially)|
| GtkSigner| https://github.com/holiman/gtksigner| Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: | :x: |
| Frame | https://github.com/floating/frame/commits/go-signer| Electron-based| :x:| :x:| :x:| :x:| ?| :x: | :x: |

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -0,0 +1,23 @@
"""
This implements a dispatcher which listens to localhost:8550, and proxies
requests via qrexec to the service qubes.EthSign on a target domain
"""
import http.server
import socketserver,subprocess
PORT=8550
TARGET_DOMAIN= 'debian-work'
class Dispatcher(http.server.BaseHTTPRequestHandler):
def do_POST(self):
post_data = self.rfile.read(int(self.headers['Content-Length']))
p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE)
output = p.communicate(post_data)[0]
self.wfile.write(output)
with socketserver.TCPServer(("",PORT), Dispatcher) as httpd:
print("Serving at port", PORT)
httpd.serve_forever()

View file

@ -0,0 +1,16 @@
#!/bin/bash
SIGNER_BIN="/home/user/tools/clef/clef"
SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN"
# Start clef if not already started
if [ ! -S /home/user/.clef/clef.ipc ]; then
$SIGNER_CMD &
sleep 1
fi
# Should be started by now
if [ -S /home/user/.clef/clef.ipc ]; then
# Post incoming request to HTTP channel
curl -H "Content-Type: application/json" -X POST -d @- http://localhost:8550 2>/dev/null
fi

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

198
cmd/clef/docs/setup.md Normal file
View file

@ -0,0 +1,198 @@
# Setting up Clef
This document describes how Clef can be used in a more secure manner than executing it from your everyday laptop,
in order to ensure that the keys remain safe in the event that your computer should get compromised.
## Qubes OS
### Background
The Qubes operating system is based around virtual machines (qubes), where a set of virtual machines are configured, typically for
different purposes such as:
- personal
- Your personal email, browsing etc
- work
- Work email etc
- vault
- a VM without network access, where gpg-keys and/or keepass credentials are stored.
A couple of dedicated virtual machines handle externalities:
- sys-net provides networking to all other (network-enabled) machines
- sys-firewall handles firewall rules
- sys-usb handles USB devices, and can map usb-devices to certain qubes.
The goal of this document is to describe how we can set up clef to provide secure transaction
signing from a `vault` vm, to another networked qube which runs Dapps.
### Setup
There are two ways that this can be achieved: integrated via Qubes or integrated via networking.
#### 1. Qubes Integrated
Qubes provdes a facility for inter-qubes communication via `qrexec`. A qube can request to make a cross-qube RPC request
to another qube. The OS then asks the user if the call is permitted.
![Example](qubes/qrexec-example.png)
A policy-file can be created to allow such interaction. On the `target` domain, a service is invoked which can read the
`stdin` from the `client` qube.
This is how [Split GPG](https://www.qubes-os.org/doc/split-gpg/) is implemented. We can set up Clef the same way:
##### Server
![Clef via qrexec](qubes/clef_qubes_qrexec.png)
On the `target` qubes, we need to define the rpc service.
[qubes.Clefsign](qubes/qubes.Clefsign):
```bash
#!/bin/bash
SIGNER_BIN="/home/user/tools/clef/clef"
SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN"
# Start clef if not already started
if [ ! -S /home/user/.clef/clef.ipc ]; then
$SIGNER_CMD &
sleep 1
fi
# Should be started by now
if [ -S /home/user/.clef/clef.ipc ]; then
# Post incoming request to HTTP channel
curl -H "Content-Type: application/json" -X POST -d @- http://localhost:8550 2>/dev/null
fi
```
This RPC service is not complete (see notes about HTTP headers below), but works as a proof-of-concept.
It will forward the data received on `stdin` (forwarded by the OS) to Clef's HTTP channel.
It would have been possible to send data directly to the `/home/user/.clef/.clef.ipc`
socket via e.g `nc -U /home/user/.clef/clef.ipc`, but the reason for sending the request
data over `HTTP` instead of `IPC` is that we want the ability to forward `HTTP` headers.
To enable the service:
``` bash
sudo cp qubes.Clefsign /etc/qubes-rpc/
sudo chmod +x /etc/qubes-rpc/ qubes.Clefsign
```
This setup uses [gtksigner](https://github.com/holiman/gtksigner), which is a very minimal GTK-based UI that works well
with minimal requirements.
##### Client
On the `client` qube, we need to create a listener which will receive the request from the Dapp, and proxy it.
[qubes-client.py](qubes/client/qubes-client.py):
```python
"""
This implements a dispatcher which listens to localhost:8550, and proxies
requests via qrexec to the service qubes.EthSign on a target domain
"""
import http.server
import socketserver,subprocess
PORT=8550
TARGET_DOMAIN= 'debian-work'
class Dispatcher(http.server.BaseHTTPRequestHandler):
def do_POST(self):
post_data = self.rfile.read(int(self.headers['Content-Length']))
p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE)
output = p.communicate(post_data)[0]
self.wfile.write(output)
with socketserver.TCPServer(("",PORT), Dispatcher) as httpd:
print("Serving at port", PORT)
httpd.serve_forever()
```
#### Testing
To test the flow, if we have set up `debian-work` as the `target`, we can do
```bash
$ cat newaccnt.json
{ "id": 0, "jsonrpc": "2.0","method": "account_new","params": []}
$ cat newaccnt.json| qrexec-client-vm debian-work qubes.Clefsign
```
This should pop up first a dialog to allow the IPC call:
![one](qubes/qubes_newaccount-1.png)
Followed by a GTK-dialog to approve the operation
![two](qubes/qubes_newaccount-2.png)
To test the full flow, we use the client wrapper. Start it on the `client` qube:
```
[user@work qubes]$ python3 qubes-client.py
```
Make the request over http (`client` qube):
```
[user@work clef]$ cat newaccnt.json | curl -X POST -d @- http://localhost:8550
```
And it should show the same popups again.
##### Pros and cons
The benefits of this setup are:
- This is the qubes-os intended model for inter-qube communication,
- and thus benefits from qubes-os dialogs and policies for user approval
However, it comes with a couple of drawbacks:
- The `qubes-gpg-client` must forward the http request via RPC to the `target` qube. When doing so, the proxy
will either drop important headers, or replace them.
- The `Host` header is most likely `localhost`
- The `Origin` header must be forwarded
- Information about the remote ip must be added as a `X-Forwarded-For`. However, Clef cannot always trust an `XFF` header,
since malicious clients may lie about `XFF` in order to fool the http server into believing it comes from another address.
- Even with a policy in place to allow rpc-calls between `caller` and `target`, there will be several popups:
- One qubes-specific where the user specifies the `target` vm
- One clef-specific to approve the transaction
#### 2. Network integrated
The second way to set up Clef on a qubes system is to allow networking, and have Clef listen to a port which is accessible
form other qubes.
![Clef via http](qubes/clef_qubes_http.png)
## USBArmory
The [USB armory](https://inversepath.com/usbarmory) is an open source hardware design with an 800 Mhz ARM processor. It is a pocket-size
computer. When inserted into a laptop, it identifies itself as a USB network interface, basically adding another network
to your computer. Over this new network interface, you can SSH into the device.
Running Clef off a USB armory means that you can use the armory as a very versatile offline computer, which only
ever connects to a local network between your computer and the device itself.
Needless to say, the while this model should be fairly secure against remote attacks, an attacker with physical access
to the USB Armory would trivially be able to extract the contents of the device filesystem.

View file

@ -21,12 +21,12 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big"
"os" "os"
goruntime "runtime"
"runtime/pprof" "runtime/pprof"
"time" "time"
goruntime "runtime"
"github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -86,6 +86,7 @@ func runCmd(ctx *cli.Context) error {
chainConfig *params.ChainConfig chainConfig *params.ChainConfig
sender = common.BytesToAddress([]byte("sender")) sender = common.BytesToAddress([]byte("sender"))
receiver = common.BytesToAddress([]byte("receiver")) receiver = common.BytesToAddress([]byte("receiver"))
blockNumber uint64
) )
if ctx.GlobalBool(MachineFlag.Name) { if ctx.GlobalBool(MachineFlag.Name) {
tracer = NewJSONLogger(logconfig, os.Stdout) tracer = NewJSONLogger(logconfig, os.Stdout)
@ -101,6 +102,7 @@ func runCmd(ctx *cli.Context) error {
genesis := gen.ToBlock(db) genesis := gen.ToBlock(db)
statedb, _ = state.New(genesis.Root(), state.NewDatabase(db)) statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
chainConfig = gen.Config chainConfig = gen.Config
blockNumber = gen.Number
} else { } else {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) statedb, _ = state.New(common.Hash{}, state.NewDatabase(db))
@ -161,6 +163,7 @@ func runCmd(ctx *cli.Context) error {
GasLimit: initialGas, GasLimit: initialGas,
GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), GasPrice: utils.GlobalBig(ctx, PriceFlag.Name),
Value: utils.GlobalBig(ctx, ValueFlag.Name), Value: utils.GlobalBig(ctx, ValueFlag.Name),
BlockNumber: new(big.Int).SetUint64(blockNumber),
EVMConfig: vm.Config{ EVMConfig: vm.Config{
Tracer: tracer, Tracer: tracer,
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name),

View file

@ -24,7 +24,7 @@ import (
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -131,8 +131,8 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc
if genesis != "" { if genesis != "" {
genesisHash = daoGenesisHash genesisHash = daoGenesisHash
} }
config, err := core.GetChainConfig(db, genesisHash) config := rawdb.ReadChainConfig(db, genesisHash)
if err != nil { if config == nil {
t.Errorf("test %d: failed to retrieve chain config: %v", test, err) t.Errorf("test %d: failed to retrieve chain config: %v", test, err)
return // we want to return here, the other checks can't make it past this point (nil panic). return // we want to return here, the other checks can't make it past this point (nil panic).
} }

View file

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -271,15 +272,13 @@ func ImportPreimages(db *ethdb.LDBDatabase, fn string) error {
// Accumulate the preimages and flush when enough ws gathered // Accumulate the preimages and flush when enough ws gathered
preimages[crypto.Keccak256Hash(blob)] = common.CopyBytes(blob) preimages[crypto.Keccak256Hash(blob)] = common.CopyBytes(blob)
if len(preimages) > 1024 { if len(preimages) > 1024 {
if err := core.WritePreimages(db, 0, preimages); err != nil { rawdb.WritePreimages(db, 0, preimages)
return err
}
preimages = make(map[common.Hash][]byte) preimages = make(map[common.Hash][]byte)
} }
} }
// Flush the last batch preimage data // Flush the last batch preimage data
if len(preimages) > 0 { if len(preimages) > 0 {
return core.WritePreimages(db, 0, preimages) rawdb.WritePreimages(db, 0, preimages)
} }
return nil return nil
} }

View file

@ -158,11 +158,11 @@ var (
} }
FastSyncFlag = cli.BoolFlag{ FastSyncFlag = cli.BoolFlag{
Name: "fast", Name: "fast",
Usage: "Enable fast syncing through state downloads", Usage: "Enable fast syncing through state downloads (replaced by --syncmode)",
} }
LightModeFlag = cli.BoolFlag{ LightModeFlag = cli.BoolFlag{
Name: "light", Name: "light",
Usage: "Enable light client mode", Usage: "Enable light client mode (replaced by --syncmode)",
} }
defaultSyncMode = eth.DefaultConfig.SyncMode defaultSyncMode = eth.DefaultConfig.SyncMode
SyncModeFlag = TextMarshalerFlag{ SyncModeFlag = TextMarshalerFlag{

View file

@ -271,7 +271,9 @@ func initialize() {
if *mailServerMode { if *mailServerMode {
shh.RegisterServer(&mailServer) shh.RegisterServer(&mailServer)
mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW) if err := mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW); err != nil {
utils.Fatalf("Failed to init MailServer: %s", err)
}
} }
server = &p2p.Server{ server = &p2p.Server{

View file

@ -87,16 +87,14 @@ func Hex2BytesFixed(str string, flen int) []byte {
h, _ := hex.DecodeString(str) h, _ := hex.DecodeString(str)
if len(h) == flen { if len(h) == flen {
return h return h
} else { }
if len(h) > flen { if len(h) > flen {
return h[len(h)-flen:] return h[len(h)-flen:]
} else { }
hh := make([]byte, flen) hh := make([]byte, flen)
copy(hh[flen-len(h):flen], h[:]) copy(hh[flen-len(h):flen], h[:])
return hh return hh
} }
}
}
func RightPadBytes(slice []byte, l int) []byte { func RightPadBytes(slice []byte, l int) []byte {
if l <= len(slice) { if l <= len(slice) {

View file

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -81,7 +82,7 @@ func (r *testerChainReader) GetBlock(common.Hash, uint64) *types.Block { panic
func (r *testerChainReader) GetHeaderByHash(common.Hash) *types.Header { panic("not supported") } func (r *testerChainReader) GetHeaderByHash(common.Hash) *types.Header { panic("not supported") }
func (r *testerChainReader) GetHeaderByNumber(number uint64) *types.Header { func (r *testerChainReader) GetHeaderByNumber(number uint64) *types.Header {
if number == 0 { if number == 0 {
return core.GetHeader(r.db, core.GetCanonicalHash(r.db, 0), 0) return rawdb.ReadHeader(r.db, rawdb.ReadCanonicalHash(r.db, 0), 0)
} }
panic("not supported") panic("not supported")
} }

View file

@ -156,7 +156,7 @@ type lru struct {
futureItem interface{} futureItem interface{}
} }
// newlru create a new least-recently-used cache for ither the verification caches // newlru create a new least-recently-used cache for either the verification caches
// or the mining datasets. // or the mining datasets.
func newlru(what string, maxItems int, new func(epoch uint64) interface{}) *lru { func newlru(what string, maxItems int, new func(epoch uint64) interface{}) *lru {
if maxItems <= 0 { if maxItems <= 0 {

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -234,13 +235,15 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) {
ReceiptHash: types.EmptyRootHash, ReceiptHash: types.EmptyRootHash,
} }
hash = header.Hash() hash = header.Hash()
WriteHeader(db, header)
WriteCanonicalHash(db, hash, n) rawdb.WriteHeader(db, header)
WriteTd(db, hash, n, big.NewInt(int64(n+1))) rawdb.WriteCanonicalHash(db, hash, n)
rawdb.WriteTd(db, hash, n, big.NewInt(int64(n+1)))
if full || n == 0 { if full || n == 0 {
block := types.NewBlockWithHeader(header) block := types.NewBlockWithHeader(header)
WriteBody(db, hash, n, block.Body()) rawdb.WriteBody(db, hash, n, block.Body())
WriteBlockReceipts(db, hash, n, nil) rawdb.WriteReceipts(db, hash, n, nil)
} }
} }
} }
@ -292,11 +295,10 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
header := chain.GetHeaderByNumber(n) header := chain.GetHeaderByNumber(n)
if full { if full {
hash := header.Hash() hash := header.Hash()
GetBody(db, hash, n) rawdb.ReadBody(db, hash, n)
GetBlockReceipts(db, hash, n) rawdb.ReadReceipts(db, hash, n)
} }
} }
chain.Stop() chain.Stop()
db.Close() db.Close()
} }

View file

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -202,7 +203,7 @@ func (bc *BlockChain) getProcInterrupt() bool {
// assumes that the chain manager mutex is held. // assumes that the chain manager mutex is held.
func (bc *BlockChain) loadLastState() error { func (bc *BlockChain) loadLastState() error {
// Restore the last known head block // Restore the last known head block
head := GetHeadBlockHash(bc.db) head := rawdb.ReadHeadBlockHash(bc.db)
if head == (common.Hash{}) { if head == (common.Hash{}) {
// Corrupt or empty database, init from scratch // Corrupt or empty database, init from scratch
log.Warn("Empty database, resetting chain") log.Warn("Empty database, resetting chain")
@ -228,7 +229,7 @@ func (bc *BlockChain) loadLastState() error {
// Restore the last known head header // Restore the last known head header
currentHeader := currentBlock.Header() currentHeader := currentBlock.Header()
if head := GetHeadHeaderHash(bc.db); head != (common.Hash{}) { if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) {
if header := bc.GetHeaderByHash(head); header != nil { if header := bc.GetHeaderByHash(head); header != nil {
currentHeader = header currentHeader = header
} }
@ -237,7 +238,7 @@ func (bc *BlockChain) loadLastState() error {
// Restore the last known head fast block // Restore the last known head fast block
bc.currentFastBlock.Store(currentBlock) bc.currentFastBlock.Store(currentBlock)
if head := GetHeadFastBlockHash(bc.db); head != (common.Hash{}) { if head := rawdb.ReadHeadFastBlockHash(bc.db); head != (common.Hash{}) {
if block := bc.GetBlockByHash(head); block != nil { if block := bc.GetBlockByHash(head); block != nil {
bc.currentFastBlock.Store(block) bc.currentFastBlock.Store(block)
} }
@ -269,7 +270,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
// Rewind the header chain, deleting all block bodies until then // Rewind the header chain, deleting all block bodies until then
delFn := func(hash common.Hash, num uint64) { delFn := func(hash common.Hash, num uint64) {
DeleteBody(bc.db, hash, num) rawdb.DeleteBody(bc.db, hash, num)
} }
bc.hc.SetHead(head, delFn) bc.hc.SetHead(head, delFn)
currentHeader := bc.hc.CurrentHeader() currentHeader := bc.hc.CurrentHeader()
@ -303,12 +304,10 @@ func (bc *BlockChain) SetHead(head uint64) error {
} }
currentBlock := bc.CurrentBlock() currentBlock := bc.CurrentBlock()
currentFastBlock := bc.CurrentFastBlock() currentFastBlock := bc.CurrentFastBlock()
if err := WriteHeadBlockHash(bc.db, currentBlock.Hash()); err != nil {
log.Crit("Failed to reset head full block", "err", err) rawdb.WriteHeadBlockHash(bc.db, currentBlock.Hash())
} rawdb.WriteHeadFastBlockHash(bc.db, currentFastBlock.Hash())
if err := WriteHeadFastBlockHash(bc.db, currentFastBlock.Hash()); err != nil {
log.Crit("Failed to reset head fast block", "err", err)
}
return bc.loadLastState() return bc.loadLastState()
} }
@ -406,9 +405,8 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
if err := bc.hc.WriteTd(genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil { if err := bc.hc.WriteTd(genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil {
log.Crit("Failed to write genesis block TD", "err", err) log.Crit("Failed to write genesis block TD", "err", err)
} }
if err := WriteBlock(bc.db, genesis); err != nil { rawdb.WriteBlock(bc.db, genesis)
log.Crit("Failed to write genesis block", "err", err)
}
bc.genesisBlock = genesis bc.genesisBlock = genesis
bc.insert(bc.genesisBlock) bc.insert(bc.genesisBlock)
bc.currentBlock.Store(bc.genesisBlock) bc.currentBlock.Store(bc.genesisBlock)
@ -474,24 +472,19 @@ func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error {
// Note, this function assumes that the `mu` mutex is held! // Note, this function assumes that the `mu` mutex is held!
func (bc *BlockChain) insert(block *types.Block) { func (bc *BlockChain) insert(block *types.Block) {
// If the block is on a side chain or an unknown one, force other heads onto it too // If the block is on a side chain or an unknown one, force other heads onto it too
updateHeads := GetCanonicalHash(bc.db, block.NumberU64()) != block.Hash() updateHeads := rawdb.ReadCanonicalHash(bc.db, block.NumberU64()) != block.Hash()
// Add the block to the canonical chain number scheme and mark as the head // Add the block to the canonical chain number scheme and mark as the head
if err := WriteCanonicalHash(bc.db, block.Hash(), block.NumberU64()); err != nil { rawdb.WriteCanonicalHash(bc.db, block.Hash(), block.NumberU64())
log.Crit("Failed to insert block number", "err", err) rawdb.WriteHeadBlockHash(bc.db, block.Hash())
}
if err := WriteHeadBlockHash(bc.db, block.Hash()); err != nil {
log.Crit("Failed to insert head block hash", "err", err)
}
bc.currentBlock.Store(block) bc.currentBlock.Store(block)
// If the block is better than our head or is on a different chain, force update heads // If the block is better than our head or is on a different chain, force update heads
if updateHeads { if updateHeads {
bc.hc.SetCurrentHeader(block.Header()) bc.hc.SetCurrentHeader(block.Header())
rawdb.WriteHeadFastBlockHash(bc.db, block.Hash())
if err := WriteHeadFastBlockHash(bc.db, block.Hash()); err != nil {
log.Crit("Failed to insert head fast block hash", "err", err)
}
bc.currentFastBlock.Store(block) bc.currentFastBlock.Store(block)
} }
} }
@ -509,7 +502,11 @@ func (bc *BlockChain) GetBody(hash common.Hash) *types.Body {
body := cached.(*types.Body) body := cached.(*types.Body)
return body return body
} }
body := GetBody(bc.db, hash, bc.hc.GetBlockNumber(hash)) number := bc.hc.GetBlockNumber(hash)
if number == nil {
return nil
}
body := rawdb.ReadBody(bc.db, hash, *number)
if body == nil { if body == nil {
return nil return nil
} }
@ -525,7 +522,11 @@ func (bc *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue {
if cached, ok := bc.bodyRLPCache.Get(hash); ok { if cached, ok := bc.bodyRLPCache.Get(hash); ok {
return cached.(rlp.RawValue) return cached.(rlp.RawValue)
} }
body := GetBodyRLP(bc.db, hash, bc.hc.GetBlockNumber(hash)) number := bc.hc.GetBlockNumber(hash)
if number == nil {
return nil
}
body := rawdb.ReadBodyRLP(bc.db, hash, *number)
if len(body) == 0 { if len(body) == 0 {
return nil return nil
} }
@ -539,8 +540,7 @@ func (bc *BlockChain) HasBlock(hash common.Hash, number uint64) bool {
if bc.blockCache.Contains(hash) { if bc.blockCache.Contains(hash) {
return true return true
} }
ok, _ := bc.db.Has(blockBodyKey(hash, number)) return rawdb.HasBody(bc.db, hash, number)
return ok
} }
// HasState checks if state trie is fully present in the database or not. // HasState checks if state trie is fully present in the database or not.
@ -567,7 +567,7 @@ func (bc *BlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
if block, ok := bc.blockCache.Get(hash); ok { if block, ok := bc.blockCache.Get(hash); ok {
return block.(*types.Block) return block.(*types.Block)
} }
block := GetBlock(bc.db, hash, number) block := rawdb.ReadBlock(bc.db, hash, number)
if block == nil { if block == nil {
return nil return nil
} }
@ -578,13 +578,17 @@ func (bc *BlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
// GetBlockByHash retrieves a block from the database by hash, caching it if found. // GetBlockByHash retrieves a block from the database by hash, caching it if found.
func (bc *BlockChain) GetBlockByHash(hash common.Hash) *types.Block { func (bc *BlockChain) GetBlockByHash(hash common.Hash) *types.Block {
return bc.GetBlock(hash, bc.hc.GetBlockNumber(hash)) number := bc.hc.GetBlockNumber(hash)
if number == nil {
return nil
}
return bc.GetBlock(hash, *number)
} }
// GetBlockByNumber retrieves a block from the database by number, caching it // GetBlockByNumber retrieves a block from the database by number, caching it
// (associated with its hash) if found. // (associated with its hash) if found.
func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block { func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block {
hash := GetCanonicalHash(bc.db, number) hash := rawdb.ReadCanonicalHash(bc.db, number)
if hash == (common.Hash{}) { if hash == (common.Hash{}) {
return nil return nil
} }
@ -593,21 +597,28 @@ func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block {
// GetReceiptsByHash retrieves the receipts for all transactions in a given block. // GetReceiptsByHash retrieves the receipts for all transactions in a given block.
func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts { func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts {
return GetBlockReceipts(bc.db, hash, GetBlockNumber(bc.db, hash)) number := rawdb.ReadHeaderNumber(bc.db, hash)
if number == nil {
return nil
}
return rawdb.ReadReceipts(bc.db, hash, *number)
} }
// GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors. // GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors.
// [deprecated by eth/62] // [deprecated by eth/62]
func (bc *BlockChain) GetBlocksFromHash(hash common.Hash, n int) (blocks []*types.Block) { func (bc *BlockChain) GetBlocksFromHash(hash common.Hash, n int) (blocks []*types.Block) {
number := bc.hc.GetBlockNumber(hash) number := bc.hc.GetBlockNumber(hash)
if number == nil {
return nil
}
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
block := bc.GetBlock(hash, number) block := bc.GetBlock(hash, *number)
if block == nil { if block == nil {
break break
} }
blocks = append(blocks, block) blocks = append(blocks, block)
hash = block.ParentHash() hash = block.ParentHash()
number-- *number--
} }
return return
} }
@ -712,12 +723,12 @@ func (bc *BlockChain) Rollback(chain []common.Hash) {
if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock.Hash() == hash { if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock.Hash() == hash {
newFastBlock := bc.GetBlock(currentFastBlock.ParentHash(), currentFastBlock.NumberU64()-1) newFastBlock := bc.GetBlock(currentFastBlock.ParentHash(), currentFastBlock.NumberU64()-1)
bc.currentFastBlock.Store(newFastBlock) bc.currentFastBlock.Store(newFastBlock)
WriteHeadFastBlockHash(bc.db, newFastBlock.Hash()) rawdb.WriteHeadFastBlockHash(bc.db, newFastBlock.Hash())
} }
if currentBlock := bc.CurrentBlock(); currentBlock.Hash() == hash { if currentBlock := bc.CurrentBlock(); currentBlock.Hash() == hash {
newBlock := bc.GetBlock(currentBlock.ParentHash(), currentBlock.NumberU64()-1) newBlock := bc.GetBlock(currentBlock.ParentHash(), currentBlock.NumberU64()-1)
bc.currentBlock.Store(newBlock) bc.currentBlock.Store(newBlock)
WriteHeadBlockHash(bc.db, newBlock.Hash()) rawdb.WriteHeadBlockHash(bc.db, newBlock.Hash())
} }
} }
} }
@ -802,15 +813,10 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
return i, fmt.Errorf("failed to set receipts data: %v", err) return i, fmt.Errorf("failed to set receipts data: %v", err)
} }
// Write all the data out into the database // Write all the data out into the database
if err := WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()); err != nil { rawdb.WriteBody(batch, block.Hash(), block.NumberU64(), block.Body())
return i, fmt.Errorf("failed to write block body: %v", err) rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts)
} rawdb.WriteTxLookupEntries(batch, block)
if err := WriteBlockReceipts(batch, block.Hash(), block.NumberU64(), receipts); err != nil {
return i, fmt.Errorf("failed to write block receipts: %v", err)
}
if err := WriteTxLookupEntries(batch, block); err != nil {
return i, fmt.Errorf("failed to write lookup metadata: %v", err)
}
stats.processed++ stats.processed++
if batch.ValueSize() >= ethdb.IdealBatchSize { if batch.ValueSize() >= ethdb.IdealBatchSize {
@ -834,9 +840,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
if td := bc.GetTd(head.Hash(), head.NumberU64()); td != nil { // Rewind may have occurred, skip in that case if td := bc.GetTd(head.Hash(), head.NumberU64()); td != nil { // Rewind may have occurred, skip in that case
currentFastBlock := bc.CurrentFastBlock() currentFastBlock := bc.CurrentFastBlock()
if bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64()).Cmp(td) < 0 { if bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64()).Cmp(td) < 0 {
if err := WriteHeadFastBlockHash(bc.db, head.Hash()); err != nil { rawdb.WriteHeadFastBlockHash(bc.db, head.Hash())
log.Crit("Failed to update head fast block hash", "err", err)
}
bc.currentFastBlock.Store(head) bc.currentFastBlock.Store(head)
} }
} }
@ -864,9 +868,8 @@ func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (e
if err := bc.hc.WriteTd(block.Hash(), block.NumberU64(), td); err != nil { if err := bc.hc.WriteTd(block.Hash(), block.NumberU64(), td); err != nil {
return err return err
} }
if err := WriteBlock(bc.db, block); err != nil { rawdb.WriteBlock(bc.db, block)
return err
}
return nil return nil
} }
@ -894,9 +897,8 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
} }
// Write other block data using a batch. // Write other block data using a batch.
batch := bc.db.NewBatch() batch := bc.db.NewBatch()
if err := WriteBlock(batch, block); err != nil { rawdb.WriteBlock(batch, block)
return NonStatTy, err
}
root, err := state.Commit(bc.chainConfig.IsEIP158(block.Number())) root, err := state.Commit(bc.chainConfig.IsEIP158(block.Number()))
if err != nil { if err != nil {
return NonStatTy, err return NonStatTy, err
@ -953,9 +955,8 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
} }
} }
} }
if err := WriteBlockReceipts(batch, block.Hash(), block.NumberU64(), receipts); err != nil { rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts)
return NonStatTy, err
}
// 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
@ -972,14 +973,10 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
return NonStatTy, err return NonStatTy, err
} }
} }
// Write the positional metadata for transaction and receipt lookups // Write the positional metadata for transaction/receipt lookups and preimages
if err := WriteTxLookupEntries(batch, block); err != nil { rawdb.WriteTxLookupEntries(batch, block)
return NonStatTy, err rawdb.WritePreimages(batch, block.NumberU64(), state.Preimages())
}
// Write hash preimages
if err := WritePreimages(bc.db, block.NumberU64(), state.Preimages()); err != nil {
return NonStatTy, err
}
status = CanonStatTy status = CanonStatTy
} else { } else {
status = SideStatTy status = SideStatTy
@ -1256,9 +1253,13 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
// collectLogs collects the logs that were generated during the // collectLogs collects the logs that were generated during the
// processing of the block that corresponds with the given hash. // processing of the block that corresponds with the given hash.
// These logs are later announced as deleted. // These logs are later announced as deleted.
collectLogs = func(h common.Hash) { collectLogs = func(hash common.Hash) {
// Coalesce logs and set 'Removed'. // Coalesce logs and set 'Removed'.
receipts := GetBlockReceipts(bc.db, h, bc.hc.GetBlockNumber(h)) number := bc.hc.GetBlockNumber(hash)
if number == nil {
return
}
receipts := rawdb.ReadReceipts(bc.db, hash, *number)
for _, receipt := range receipts { for _, receipt := range receipts {
for _, log := range receipt.Logs { for _, log := range receipt.Logs {
del := *log del := *log
@ -1327,9 +1328,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
// insert the block in the canonical way, re-writing history // insert the block in the canonical way, re-writing history
bc.insert(newChain[i]) bc.insert(newChain[i])
// write lookup entries for hash based transaction/receipt searches // write lookup entries for hash based transaction/receipt searches
if err := WriteTxLookupEntries(bc.db, newChain[i]); err != nil { rawdb.WriteTxLookupEntries(bc.db, newChain[i])
return err
}
addedTxs = append(addedTxs, newChain[i].Transactions()...) addedTxs = append(addedTxs, newChain[i].Transactions()...)
} }
// calculate the difference between deleted and added transactions // calculate the difference between deleted and added transactions
@ -1337,7 +1336,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
// When transactions get deleted from the database that means the // When transactions get deleted from the database that means the
// receipts that were created in the fork must also be deleted // receipts that were created in the fork must also be deleted
for _, tx := range diff { for _, tx := range diff {
DeleteTxLookupEntry(bc.db, tx.Hash()) rawdb.DeleteTxLookupEntry(bc.db, tx.Hash())
} }
if len(deletedLogs) > 0 { if len(deletedLogs) > 0 {
go bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs}) go bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs})

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -128,8 +129,8 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
return err return err
} }
blockchain.mu.Lock() blockchain.mu.Lock()
WriteTd(blockchain.db, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash()))) rawdb.WriteTd(blockchain.db, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash())))
WriteBlock(blockchain.db, block) rawdb.WriteBlock(blockchain.db, block)
statedb.Commit(false) statedb.Commit(false)
blockchain.mu.Unlock() blockchain.mu.Unlock()
} }
@ -146,8 +147,8 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error
} }
// Manually insert the header into the database, but don't reorganise (allows subsequent testing) // Manually insert the header into the database, but don't reorganise (allows subsequent testing)
blockchain.mu.Lock() blockchain.mu.Lock()
WriteTd(blockchain.db, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, blockchain.GetTdByHash(header.ParentHash))) rawdb.WriteTd(blockchain.db, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, blockchain.GetTdByHash(header.ParentHash)))
WriteHeader(blockchain.db, header) rawdb.WriteHeader(blockchain.db, header)
blockchain.mu.Unlock() blockchain.mu.Unlock()
} }
return nil return nil
@ -173,7 +174,7 @@ func TestLastBlock(t *testing.T) {
if _, err := blockchain.InsertChain(blocks); err != nil { if _, err := blockchain.InsertChain(blocks); err != nil {
t.Fatalf("Failed to insert block: %v", err) t.Fatalf("Failed to insert block: %v", err)
} }
if blocks[len(blocks)-1].Hash() != GetHeadBlockHash(blockchain.db) { if blocks[len(blocks)-1].Hash() != rawdb.ReadHeadBlockHash(blockchain.db) {
t.Fatalf("Write/Get HeadBlockHash failed") t.Fatalf("Write/Get HeadBlockHash failed")
} }
} }
@ -639,13 +640,13 @@ func TestFastVsFullChains(t *testing.T) {
} else if types.CalcUncleHash(fblock.Uncles()) != types.CalcUncleHash(ablock.Uncles()) { } else if types.CalcUncleHash(fblock.Uncles()) != types.CalcUncleHash(ablock.Uncles()) {
t.Errorf("block #%d [%x]: uncles mismatch: have %v, want %v", num, hash, fblock.Uncles(), ablock.Uncles()) t.Errorf("block #%d [%x]: uncles mismatch: have %v, want %v", num, hash, fblock.Uncles(), ablock.Uncles())
} }
if freceipts, areceipts := GetBlockReceipts(fastDb, hash, GetBlockNumber(fastDb, hash)), GetBlockReceipts(archiveDb, hash, GetBlockNumber(archiveDb, hash)); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) { if freceipts, areceipts := rawdb.ReadReceipts(fastDb, hash, *rawdb.ReadHeaderNumber(fastDb, hash)), rawdb.ReadReceipts(archiveDb, hash, *rawdb.ReadHeaderNumber(archiveDb, hash)); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) {
t.Errorf("block #%d [%x]: receipts mismatch: have %v, want %v", num, hash, freceipts, areceipts) t.Errorf("block #%d [%x]: receipts mismatch: have %v, want %v", num, hash, freceipts, areceipts)
} }
} }
// Check that the canonical chains are the same between the databases // Check that the canonical chains are the same between the databases
for i := 0; i < len(blocks)+1; i++ { for i := 0; i < len(blocks)+1; i++ {
if fhash, ahash := GetCanonicalHash(fastDb, uint64(i)), GetCanonicalHash(archiveDb, uint64(i)); fhash != ahash { if fhash, ahash := rawdb.ReadCanonicalHash(fastDb, uint64(i)), rawdb.ReadCanonicalHash(archiveDb, uint64(i)); fhash != ahash {
t.Errorf("block #%d: canonical hash mismatch: have %v, want %v", i, fhash, ahash) t.Errorf("block #%d: canonical hash mismatch: have %v, want %v", i, fhash, ahash)
} }
} }
@ -821,28 +822,28 @@ func TestChainTxReorgs(t *testing.T) {
// removed tx // removed tx
for i, tx := range (types.Transactions{pastDrop, freshDrop}) { for i, tx := range (types.Transactions{pastDrop, freshDrop}) {
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { if txn, _, _, _ := rawdb.ReadTransaction(db, tx.Hash()); txn != nil {
t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn) t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn)
} }
if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt != nil { if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash()); rcpt != nil {
t.Errorf("drop %d: receipt %v found while shouldn't have been", i, rcpt) t.Errorf("drop %d: receipt %v found while shouldn't have been", i, rcpt)
} }
} }
// added tx // added tx
for i, tx := range (types.Transactions{pastAdd, freshAdd, futureAdd}) { for i, tx := range (types.Transactions{pastAdd, freshAdd, futureAdd}) {
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { if txn, _, _, _ := rawdb.ReadTransaction(db, tx.Hash()); txn == nil {
t.Errorf("add %d: expected tx to be found", i) t.Errorf("add %d: expected tx to be found", i)
} }
if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil { if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash()); rcpt == nil {
t.Errorf("add %d: expected receipt to be found", i) t.Errorf("add %d: expected receipt to be found", i)
} }
} }
// shared tx // shared tx
for i, tx := range (types.Transactions{postponed, swapped}) { for i, tx := range (types.Transactions{postponed, swapped}) {
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { if txn, _, _, _ := rawdb.ReadTransaction(db, tx.Hash()); txn == nil {
t.Errorf("share %d: expected tx to be found", i) t.Errorf("share %d: expected tx to be found", i)
} }
if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil { if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash()); rcpt == nil {
t.Errorf("share %d: expected receipt to be found", i) t.Errorf("share %d: expected receipt to be found", i)
} }
} }
@ -997,14 +998,14 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
// try to retrieve a block by its canonical hash and see if the block data can be retrieved. // try to retrieve a block by its canonical hash and see if the block data can be retrieved.
for { for {
ch := GetCanonicalHash(blockchain.db, block.NumberU64()) ch := rawdb.ReadCanonicalHash(blockchain.db, block.NumberU64())
if ch == (common.Hash{}) { if ch == (common.Hash{}) {
continue // busy wait for canonical hash to be written continue // busy wait for canonical hash to be written
} }
if ch != block.Hash() { if ch != block.Hash() {
t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex()) t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex())
} }
fb := GetBlock(blockchain.db, ch, block.NumberU64()) fb := rawdb.ReadBlock(blockchain.db, ch, block.NumberU64())
if fb == nil { if fb == nil {
t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex()) t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex())
} }

View file

@ -24,6 +24,7 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
@ -206,7 +207,7 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainE
// TODO(karalabe): This operation is expensive and might block, causing the event system to // TODO(karalabe): This operation is expensive and might block, causing the event system to
// potentially also lock up. We need to do with on a different thread somehow. // potentially also lock up. We need to do with on a different thread somehow.
if h := FindCommonAncestor(c.chainDb, prevHeader, header); h != nil { if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, header); h != nil {
c.newHead(h.Number.Uint64(), true) c.newHead(h.Number.Uint64(), true)
} }
} }
@ -349,11 +350,11 @@ func (c *ChainIndexer) processSection(section uint64, lastHead common.Hash) (com
} }
for number := section * c.sectionSize; number < (section+1)*c.sectionSize; number++ { for number := section * c.sectionSize; number < (section+1)*c.sectionSize; number++ {
hash := GetCanonicalHash(c.chainDb, number) hash := rawdb.ReadCanonicalHash(c.chainDb, number)
if hash == (common.Hash{}) { if hash == (common.Hash{}) {
return common.Hash{}, fmt.Errorf("canonical block #%d unknown", number) return common.Hash{}, fmt.Errorf("canonical block #%d unknown", number)
} }
header := GetHeader(c.chainDb, hash, number) header := rawdb.ReadHeader(c.chainDb, hash, number)
if header == nil { if header == nil {
return common.Hash{}, fmt.Errorf("block #%d [%x…] not found", number, hash[:4]) return common.Hash{}, fmt.Errorf("block #%d [%x…] not found", number, hash[:4])
} else if header.ParentHash != lastHead { } else if header.ParentHash != lastHead {

View file

@ -24,6 +24,7 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
) )
@ -92,10 +93,10 @@ func testChainIndexer(t *testing.T, count int) {
inject := func(number uint64) { inject := func(number uint64) {
header := &types.Header{Number: big.NewInt(int64(number)), Extra: big.NewInt(rand.Int63()).Bytes()} header := &types.Header{Number: big.NewInt(int64(number)), Extra: big.NewInt(rand.Int63()).Bytes()}
if number > 0 { if number > 0 {
header.ParentHash = GetCanonicalHash(db, number-1) header.ParentHash = rawdb.ReadCanonicalHash(db, number-1)
} }
WriteHeader(db, header) rawdb.WriteHeader(db, header)
WriteCanonicalHash(db, header.Hash(), number) rawdb.WriteCanonicalHash(db, header.Hash(), number)
} }
// Start indexer with an already existing chain // Start indexer with an already existing chain
for i := uint64(0); i <= 100; i++ { for i := uint64(0); i <= 100; i++ {

View file

@ -1,652 +0,0 @@
// Copyright 2015 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"
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
// DatabaseReader wraps the Get method of a backing data store.
type DatabaseReader interface {
Get(key []byte) (value []byte, err error)
}
// DatabaseDeleter wraps the Delete method of a backing data store.
type DatabaseDeleter interface {
Delete(key []byte) error
}
var (
headHeaderKey = []byte("LastHeader")
headBlockKey = []byte("LastBlock")
headFastKey = []byte("LastFast")
trieSyncKey = []byte("TrieSync")
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`).
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
tdSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td
numSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hash
blockHashPrefix = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian)
bodyPrefix = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
lookupPrefix = []byte("l") // lookupPrefix + hash -> transaction/receipt lookup metadata
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
preimagePrefix = "secure-key-" // preimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db
// Chain index prefixes (use `i` + single byte to avoid mixing data types).
BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress
// used by old db, now only used for conversion
oldReceiptsPrefix = []byte("receipts-")
oldTxMetaSuffix = []byte{0x01}
ErrChainConfigNotFound = errors.New("ChainConfig not found") // general config not found error
preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil)
preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil)
)
// TxLookupEntry is a positional metadata to help looking up the data content of
// a transaction or receipt given only its hash.
type TxLookupEntry struct {
BlockHash common.Hash
BlockIndex uint64
Index uint64
}
// encodeBlockNumber encodes a block number as big endian uint64
func encodeBlockNumber(number uint64) []byte {
enc := make([]byte, 8)
binary.BigEndian.PutUint64(enc, number)
return enc
}
// GetCanonicalHash retrieves a hash assigned to a canonical block number.
func GetCanonicalHash(db DatabaseReader, number uint64) common.Hash {
data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...))
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// missingNumber is returned by GetBlockNumber if no header with the
// given block hash has been stored in the database
const missingNumber = uint64(0xffffffffffffffff)
// GetBlockNumber returns the block number assigned to a block hash
// if the corresponding header is present in the database
func GetBlockNumber(db DatabaseReader, hash common.Hash) uint64 {
data, _ := db.Get(append(blockHashPrefix, hash.Bytes()...))
if len(data) != 8 {
return missingNumber
}
return binary.BigEndian.Uint64(data)
}
// GetHeadHeaderHash retrieves the hash of the current canonical head block's
// header. The difference between this and GetHeadBlockHash is that whereas the
// last block hash is only updated upon a full block import, the last header
// hash is updated already at header import, allowing head tracking for the
// light synchronization mechanism.
func GetHeadHeaderHash(db DatabaseReader) common.Hash {
data, _ := db.Get(headHeaderKey)
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// GetHeadBlockHash retrieves the hash of the current canonical head block.
func GetHeadBlockHash(db DatabaseReader) common.Hash {
data, _ := db.Get(headBlockKey)
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// GetHeadFastBlockHash retrieves the hash of the current canonical head block during
// fast synchronization. The difference between this and GetHeadBlockHash is that
// whereas the last block hash is only updated upon a full block import, the last
// fast hash is updated when importing pre-processed blocks.
func GetHeadFastBlockHash(db DatabaseReader) common.Hash {
data, _ := db.Get(headFastKey)
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// GetTrieSyncProgress retrieves the number of tries nodes fast synced to allow
// reportinc correct numbers across restarts.
func GetTrieSyncProgress(db DatabaseReader) uint64 {
data, _ := db.Get(trieSyncKey)
if len(data) == 0 {
return 0
}
return new(big.Int).SetBytes(data).Uint64()
}
// GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil
// if the header's not found.
func GetHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
data, _ := db.Get(headerKey(hash, number))
return data
}
// GetHeader retrieves the block header corresponding to the hash, nil if none
// found.
func GetHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Header {
data := GetHeaderRLP(db, hash, number)
if len(data) == 0 {
return nil
}
header := new(types.Header)
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
log.Error("Invalid block header RLP", "hash", hash, "err", err)
return nil
}
return header
}
// GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
func GetBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
data, _ := db.Get(blockBodyKey(hash, number))
return data
}
func headerKey(hash common.Hash, number uint64) []byte {
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
}
func blockBodyKey(hash common.Hash, number uint64) []byte {
return append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
}
// GetBody retrieves the block body (transactons, uncles) corresponding to the
// hash, nil if none found.
func GetBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body {
data := GetBodyRLP(db, hash, number)
if len(data) == 0 {
return nil
}
body := new(types.Body)
if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
log.Error("Invalid block body RLP", "hash", hash, "err", err)
return nil
}
return body
}
// GetTd retrieves a block's total difficulty corresponding to the hash, nil if
// none found.
func GetTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int {
data, _ := db.Get(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash[:]...), tdSuffix...))
if len(data) == 0 {
return nil
}
td := new(big.Int)
if err := rlp.Decode(bytes.NewReader(data), td); err != nil {
log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err)
return nil
}
return td
}
// GetBlock retrieves an entire block corresponding to the hash, assembling it
// back from the stored header and body. If either the header or body could not
// be retrieved nil is returned.
//
// Note, due to concurrent download of header and block body the header and thus
// canonical hash can be stored in the database but the body data not (yet).
func GetBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block {
// Retrieve the block header and body contents
header := GetHeader(db, hash, number)
if header == nil {
return nil
}
body := GetBody(db, hash, number)
if body == nil {
return nil
}
// Reassemble the block and return
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles)
}
// GetBlockReceipts retrieves the receipts generated by the transactions included
// in a block given by its hash.
func GetBlockReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
data, _ := db.Get(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash[:]...))
if len(data) == 0 {
return nil
}
storageReceipts := []*types.ReceiptForStorage{}
if err := rlp.DecodeBytes(data, &storageReceipts); err != nil {
log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
return nil
}
receipts := make(types.Receipts, len(storageReceipts))
for i, receipt := range storageReceipts {
receipts[i] = (*types.Receipt)(receipt)
}
return receipts
}
// GetTxLookupEntry retrieves the positional metadata associated with a transaction
// hash to allow retrieving the transaction or receipt by hash.
func GetTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) {
// Load the positional metadata from disk and bail if it fails
data, _ := db.Get(append(lookupPrefix, hash.Bytes()...))
if len(data) == 0 {
return common.Hash{}, 0, 0
}
// Parse and return the contents of the lookup entry
var entry TxLookupEntry
if err := rlp.DecodeBytes(data, &entry); err != nil {
log.Error("Invalid lookup entry RLP", "hash", hash, "err", err)
return common.Hash{}, 0, 0
}
return entry.BlockHash, entry.BlockIndex, entry.Index
}
// GetTransaction retrieves a specific transaction from the database, along with
// its added positional metadata.
func GetTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
// Retrieve the lookup metadata and resolve the transaction from the body
blockHash, blockNumber, txIndex := GetTxLookupEntry(db, hash)
if blockHash != (common.Hash{}) {
body := GetBody(db, blockHash, blockNumber)
if body == nil || len(body.Transactions) <= int(txIndex) {
log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash, "index", txIndex)
return nil, common.Hash{}, 0, 0
}
return body.Transactions[txIndex], blockHash, blockNumber, txIndex
}
// Old transaction representation, load the transaction and it's metadata separately
data, _ := db.Get(hash.Bytes())
if len(data) == 0 {
return nil, common.Hash{}, 0, 0
}
var tx types.Transaction
if err := rlp.DecodeBytes(data, &tx); err != nil {
return nil, common.Hash{}, 0, 0
}
// Retrieve the blockchain positional metadata
data, _ = db.Get(append(hash.Bytes(), oldTxMetaSuffix...))
if len(data) == 0 {
return nil, common.Hash{}, 0, 0
}
var entry TxLookupEntry
if err := rlp.DecodeBytes(data, &entry); err != nil {
return nil, common.Hash{}, 0, 0
}
return &tx, entry.BlockHash, entry.BlockIndex, entry.Index
}
// GetReceipt retrieves a specific transaction receipt from the database, along with
// its added positional metadata.
func GetReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) {
// Retrieve the lookup metadata and resolve the receipt from the receipts
blockHash, blockNumber, receiptIndex := GetTxLookupEntry(db, hash)
if blockHash != (common.Hash{}) {
receipts := GetBlockReceipts(db, blockHash, blockNumber)
if len(receipts) <= int(receiptIndex) {
log.Error("Receipt refereced missing", "number", blockNumber, "hash", blockHash, "index", receiptIndex)
return nil, common.Hash{}, 0, 0
}
return receipts[receiptIndex], blockHash, blockNumber, receiptIndex
}
// Old receipt representation, load the receipt and set an unknown metadata
data, _ := db.Get(append(oldReceiptsPrefix, hash[:]...))
if len(data) == 0 {
return nil, common.Hash{}, 0, 0
}
var receipt types.ReceiptForStorage
err := rlp.DecodeBytes(data, &receipt)
if err != nil {
log.Error("Invalid receipt RLP", "hash", hash, "err", err)
}
return (*types.Receipt)(&receipt), common.Hash{}, 0, 0
}
// GetBloomBits retrieves the compressed bloom bit vector belonging to the given
// section and bit index from the.
func GetBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) {
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...)
binary.BigEndian.PutUint16(key[1:], uint16(bit))
binary.BigEndian.PutUint64(key[3:], section)
return db.Get(key)
}
// WriteCanonicalHash stores the canonical hash for the given block number.
func WriteCanonicalHash(db ethdb.Putter, hash common.Hash, number uint64) error {
key := append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...)
if err := db.Put(key, hash.Bytes()); err != nil {
log.Crit("Failed to store number to hash mapping", "err", err)
}
return nil
}
// WriteHeadHeaderHash stores the head header's hash.
func WriteHeadHeaderHash(db ethdb.Putter, hash common.Hash) error {
if err := db.Put(headHeaderKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last header's hash", "err", err)
}
return nil
}
// WriteHeadBlockHash stores the head block's hash.
func WriteHeadBlockHash(db ethdb.Putter, hash common.Hash) error {
if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last block's hash", "err", err)
}
return nil
}
// WriteHeadFastBlockHash stores the fast head block's hash.
func WriteHeadFastBlockHash(db ethdb.Putter, hash common.Hash) error {
if err := db.Put(headFastKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last fast block's hash", "err", err)
}
return nil
}
// WriteTrieSyncProgress stores the fast sync trie process counter to support
// retrieving it across restarts.
func WriteTrieSyncProgress(db ethdb.Putter, count uint64) error {
if err := db.Put(trieSyncKey, new(big.Int).SetUint64(count).Bytes()); err != nil {
log.Crit("Failed to store fast sync trie progress", "err", err)
}
return nil
}
// WriteHeader serializes a block header into the database.
func WriteHeader(db ethdb.Putter, header *types.Header) error {
data, err := rlp.EncodeToBytes(header)
if err != nil {
return err
}
hash := header.Hash().Bytes()
num := header.Number.Uint64()
encNum := encodeBlockNumber(num)
key := append(blockHashPrefix, hash...)
if err := db.Put(key, encNum); err != nil {
log.Crit("Failed to store hash to number mapping", "err", err)
}
key = append(append(headerPrefix, encNum...), hash...)
if err := db.Put(key, data); err != nil {
log.Crit("Failed to store header", "err", err)
}
return nil
}
// WriteBody serializes the body of a block into the database.
func WriteBody(db ethdb.Putter, hash common.Hash, number uint64, body *types.Body) error {
data, err := rlp.EncodeToBytes(body)
if err != nil {
return err
}
return WriteBodyRLP(db, hash, number, data)
}
// WriteBodyRLP writes a serialized body of a block into the database.
func WriteBodyRLP(db ethdb.Putter, hash common.Hash, number uint64, rlp rlp.RawValue) error {
key := append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
if err := db.Put(key, rlp); err != nil {
log.Crit("Failed to store block body", "err", err)
}
return nil
}
// WriteTd serializes the total difficulty of a block into the database.
func WriteTd(db ethdb.Putter, hash common.Hash, number uint64, td *big.Int) error {
data, err := rlp.EncodeToBytes(td)
if err != nil {
return err
}
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), tdSuffix...)
if err := db.Put(key, data); err != nil {
log.Crit("Failed to store block total difficulty", "err", err)
}
return nil
}
// WriteBlock serializes a block into the database, header and body separately.
func WriteBlock(db ethdb.Putter, block *types.Block) error {
// Store the body first to retain database consistency
if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil {
return err
}
// Store the header too, signaling full block ownership
if err := WriteHeader(db, block.Header()); err != nil {
return err
}
return nil
}
// WriteBlockReceipts stores all the transaction receipts belonging to a block
// as a single receipt slice. This is used during chain reorganisations for
// rescheduling dropped transactions.
func WriteBlockReceipts(db ethdb.Putter, hash common.Hash, number uint64, receipts types.Receipts) error {
// Convert the receipts into their storage form and serialize them
storageReceipts := make([]*types.ReceiptForStorage, len(receipts))
for i, receipt := range receipts {
storageReceipts[i] = (*types.ReceiptForStorage)(receipt)
}
bytes, err := rlp.EncodeToBytes(storageReceipts)
if err != nil {
return err
}
// Store the flattened receipt slice
key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
if err := db.Put(key, bytes); err != nil {
log.Crit("Failed to store block receipts", "err", err)
}
return nil
}
// WriteTxLookupEntries stores a positional metadata for every transaction from
// a block, enabling hash based transaction and receipt lookups.
func WriteTxLookupEntries(db ethdb.Putter, block *types.Block) error {
// Iterate over each transaction and encode its metadata
for i, tx := range block.Transactions() {
entry := TxLookupEntry{
BlockHash: block.Hash(),
BlockIndex: block.NumberU64(),
Index: uint64(i),
}
data, err := rlp.EncodeToBytes(entry)
if err != nil {
return err
}
if err := db.Put(append(lookupPrefix, tx.Hash().Bytes()...), data); err != nil {
return err
}
}
return nil
}
// WriteBloomBits writes the compressed bloom bits vector belonging to the given
// section and bit index.
func WriteBloomBits(db ethdb.Putter, bit uint, section uint64, head common.Hash, bits []byte) {
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...)
binary.BigEndian.PutUint16(key[1:], uint16(bit))
binary.BigEndian.PutUint64(key[3:], section)
if err := db.Put(key, bits); err != nil {
log.Crit("Failed to store bloom bits", "err", err)
}
}
// DeleteCanonicalHash removes the number to hash canonical mapping.
func DeleteCanonicalHash(db DatabaseDeleter, number uint64) {
db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...))
}
// DeleteHeader removes all block header data associated with a hash.
func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) {
db.Delete(append(blockHashPrefix, hash.Bytes()...))
db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
}
// DeleteBody removes all block body data associated with a hash.
func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) {
db.Delete(append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
}
// DeleteTd removes all block total difficulty data associated with a hash.
func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
db.Delete(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), tdSuffix...))
}
// DeleteBlock removes all block data associated with a hash.
func DeleteBlock(db DatabaseDeleter, hash common.Hash, number uint64) {
DeleteBlockReceipts(db, hash, number)
DeleteHeader(db, hash, number)
DeleteBody(db, hash, number)
DeleteTd(db, hash, number)
}
// DeleteBlockReceipts removes all receipt data associated with a block hash.
func DeleteBlockReceipts(db DatabaseDeleter, hash common.Hash, number uint64) {
db.Delete(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
}
// DeleteTxLookupEntry removes all transaction data associated with a hash.
func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) {
db.Delete(append(lookupPrefix, hash.Bytes()...))
}
// PreimageTable returns a Database instance with the key prefix for preimage entries.
func PreimageTable(db ethdb.Database) ethdb.Database {
return ethdb.NewTable(db, preimagePrefix)
}
// WritePreimages writes the provided set of preimages to the database. `number` is the
// current block number, and is used for debug messages only.
func WritePreimages(db ethdb.Database, number uint64, preimages map[common.Hash][]byte) error {
table := PreimageTable(db)
batch := table.NewBatch()
hitCount := 0
for hash, preimage := range preimages {
if _, err := table.Get(hash.Bytes()); err != nil {
batch.Put(hash.Bytes(), preimage)
hitCount++
}
}
preimageCounter.Inc(int64(len(preimages)))
preimageHitCounter.Inc(int64(hitCount))
if hitCount > 0 {
if err := batch.Write(); err != nil {
return fmt.Errorf("preimage write fail for block %d: %v", number, err)
}
}
return nil
}
// GetBlockChainVersion reads the version number from db.
func GetBlockChainVersion(db DatabaseReader) int {
var vsn uint
enc, _ := db.Get([]byte("BlockchainVersion"))
rlp.DecodeBytes(enc, &vsn)
return int(vsn)
}
// WriteBlockChainVersion writes vsn as the version number to db.
func WriteBlockChainVersion(db ethdb.Putter, vsn int) {
enc, _ := rlp.EncodeToBytes(uint(vsn))
db.Put([]byte("BlockchainVersion"), enc)
}
// WriteChainConfig writes the chain config settings to the database.
func WriteChainConfig(db ethdb.Putter, hash common.Hash, cfg *params.ChainConfig) error {
// short circuit and ignore if nil config. GetChainConfig
// will return a default.
if cfg == nil {
return nil
}
jsonChainConfig, err := json.Marshal(cfg)
if err != nil {
return err
}
return db.Put(append(configPrefix, hash[:]...), jsonChainConfig)
}
// GetChainConfig will fetch the network settings based on the given hash.
func GetChainConfig(db DatabaseReader, hash common.Hash) (*params.ChainConfig, error) {
jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...))
if len(jsonChainConfig) == 0 {
return nil, ErrChainConfigNotFound
}
var config params.ChainConfig
if err := json.Unmarshal(jsonChainConfig, &config); err != nil {
return nil, err
}
return &config, nil
}
// FindCommonAncestor returns the last common ancestor of two block headers
func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header {
for bn := b.Number.Uint64(); a.Number.Uint64() > bn; {
a = GetHeader(db, a.ParentHash, a.Number.Uint64()-1)
if a == nil {
return nil
}
}
for an := a.Number.Uint64(); an < b.Number.Uint64(); {
b = GetHeader(db, b.ParentHash, b.Number.Uint64()-1)
if b == nil {
return nil
}
}
for a.Hash() != b.Hash() {
a = GetHeader(db, a.ParentHash, a.Number.Uint64()-1)
if a == nil {
return nil
}
b = GetHeader(db, b.ParentHash, b.Number.Uint64()-1)
if b == nil {
return nil
}
}
return a
}

View file

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -155,7 +156,7 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig
} }
// Just commit the new block if there is no stored genesis block. // Just commit the new block if there is no stored genesis block.
stored := GetCanonicalHash(db, 0) stored := rawdb.ReadCanonicalHash(db, 0)
if (stored == common.Hash{}) { if (stored == common.Hash{}) {
if genesis == nil { if genesis == nil {
log.Info("Writing default main-net genesis block") log.Info("Writing default main-net genesis block")
@ -177,14 +178,11 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig
// Get the existing chain configuration. // Get the existing chain configuration.
newcfg := genesis.configOrDefault(stored) newcfg := genesis.configOrDefault(stored)
storedcfg, err := GetChainConfig(db, stored) storedcfg := rawdb.ReadChainConfig(db, stored)
if err != nil { if storedcfg == nil {
if err == ErrChainConfigNotFound {
// This case happens if a genesis write was interrupted.
log.Warn("Found genesis block without chain config") log.Warn("Found genesis block without chain config")
err = WriteChainConfig(db, stored, newcfg) rawdb.WriteChainConfig(db, stored, newcfg)
} return newcfg, stored, nil
return newcfg, stored, err
} }
// Special case: don't change the existing config of a non-mainnet chain if no new // Special case: don't change the existing config of a non-mainnet chain if no new
// config is supplied. These chains would get AllProtocolChanges (and a compat error) // config is supplied. These chains would get AllProtocolChanges (and a compat error)
@ -195,15 +193,16 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig
// Check config compatibility and write the config. Compatibility errors // Check config compatibility and write the config. Compatibility errors
// are returned to the caller unless we're already at block zero. // are returned to the caller unless we're already at block zero.
height := GetBlockNumber(db, GetHeadHeaderHash(db)) height := rawdb.ReadHeaderNumber(db, rawdb.ReadHeadHeaderHash(db))
if height == missingNumber { if height == nil {
return newcfg, stored, fmt.Errorf("missing block number for head header hash") return newcfg, stored, fmt.Errorf("missing block number for head header hash")
} }
compatErr := storedcfg.CheckCompatible(newcfg, height) compatErr := storedcfg.CheckCompatible(newcfg, *height)
if compatErr != nil && height != 0 && compatErr.RewindTo != 0 { if compatErr != nil && *height != 0 && compatErr.RewindTo != 0 {
return newcfg, stored, compatErr return newcfg, stored, compatErr
} }
return newcfg, stored, WriteChainConfig(db, stored, newcfg) rawdb.WriteChainConfig(db, stored, newcfg)
return newcfg, stored, nil
} }
func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
@ -267,29 +266,19 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
if block.Number().Sign() != 0 { if block.Number().Sign() != 0 {
return nil, fmt.Errorf("can't commit genesis block with number > 0") return nil, fmt.Errorf("can't commit genesis block with number > 0")
} }
if err := WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty); err != nil { rawdb.WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty)
return nil, err rawdb.WriteBlock(db, block)
} rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
if err := WriteBlock(db, block); err != nil { rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64())
return nil, err rawdb.WriteHeadBlockHash(db, block.Hash())
} rawdb.WriteHeadHeaderHash(db, block.Hash())
if err := WriteBlockReceipts(db, block.Hash(), block.NumberU64(), nil); err != nil {
return nil, err
}
if err := WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil {
return nil, err
}
if err := WriteHeadBlockHash(db, block.Hash()); err != nil {
return nil, err
}
if err := WriteHeadHeaderHash(db, block.Hash()); err != nil {
return nil, err
}
config := g.Config config := g.Config
if config == nil { if config == nil {
config = params.AllEthashProtocolChanges config = params.AllEthashProtocolChanges
} }
return block, WriteChainConfig(db, block.Hash(), config) rawdb.WriteChainConfig(db, block.Hash(), config)
return block, nil
} }
// MustCommit writes the genesis block and state to db, panicking on error. // MustCommit writes the genesis block and state to db, panicking on error.

View file

@ -24,6 +24,7 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb"
"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/params" "github.com/ethereum/go-ethereum/params"
@ -154,7 +155,7 @@ func TestSetupGenesis(t *testing.T) {
t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex()) t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
} else if err == nil { } else if err == nil {
// Check database content. // Check database content.
stored := GetBlock(db, test.wantHash, 0) stored := rawdb.ReadBlock(db, test.wantHash, 0)
if stored.Hash() != test.wantHash { if stored.Hash() != test.wantHash {
t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash) t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
} }

View file

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -97,7 +98,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
} }
hc.currentHeader.Store(hc.genesisHeader) hc.currentHeader.Store(hc.genesisHeader)
if head := GetHeadBlockHash(chainDb); head != (common.Hash{}) { if head := rawdb.ReadHeadBlockHash(chainDb); head != (common.Hash{}) {
if chead := hc.GetHeaderByHash(head); chead != nil { if chead := hc.GetHeaderByHash(head); chead != nil {
hc.currentHeader.Store(chead) hc.currentHeader.Store(chead)
} }
@ -109,13 +110,14 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
// GetBlockNumber retrieves the block number belonging to the given hash // GetBlockNumber retrieves the block number belonging to the given hash
// from the cache or database // from the cache or database
func (hc *HeaderChain) GetBlockNumber(hash common.Hash) uint64 { func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 {
if cached, ok := hc.numberCache.Get(hash); ok { if cached, ok := hc.numberCache.Get(hash); ok {
return cached.(uint64) number := cached.(uint64)
return &number
} }
number := GetBlockNumber(hc.chainDb, hash) number := rawdb.ReadHeaderNumber(hc.chainDb, hash)
if number != missingNumber { if number != nil {
hc.numberCache.Add(hash, number) hc.numberCache.Add(hash, *number)
} }
return number return number
} }
@ -147,20 +149,19 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
if err := hc.WriteTd(hash, number, externTd); err != nil { if err := hc.WriteTd(hash, number, externTd); err != nil {
log.Crit("Failed to write header total difficulty", "err", err) log.Crit("Failed to write header total difficulty", "err", err)
} }
if err := WriteHeader(hc.chainDb, header); err != nil { rawdb.WriteHeader(hc.chainDb, header)
log.Crit("Failed to write header content", "err", err)
}
// 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
if externTd.Cmp(localTd) > 0 || (externTd.Cmp(localTd) == 0 && mrand.Float64() < 0.5) { if externTd.Cmp(localTd) > 0 || (externTd.Cmp(localTd) == 0 && mrand.Float64() < 0.5) {
// Delete any canonical number assignments above the new head // Delete any canonical number assignments above the new head
for i := number + 1; ; i++ { for i := number + 1; ; i++ {
hash := GetCanonicalHash(hc.chainDb, i) hash := rawdb.ReadCanonicalHash(hc.chainDb, i)
if hash == (common.Hash{}) { if hash == (common.Hash{}) {
break break
} }
DeleteCanonicalHash(hc.chainDb, i) rawdb.DeleteCanonicalHash(hc.chainDb, i)
} }
// Overwrite any stale canonical number assignments // Overwrite any stale canonical number assignments
var ( var (
@ -168,20 +169,17 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
headNumber = header.Number.Uint64() - 1 headNumber = header.Number.Uint64() - 1
headHeader = hc.GetHeader(headHash, headNumber) headHeader = hc.GetHeader(headHash, headNumber)
) )
for GetCanonicalHash(hc.chainDb, headNumber) != headHash { for rawdb.ReadCanonicalHash(hc.chainDb, headNumber) != headHash {
WriteCanonicalHash(hc.chainDb, headHash, headNumber) rawdb.WriteCanonicalHash(hc.chainDb, headHash, headNumber)
headHash = headHeader.ParentHash headHash = headHeader.ParentHash
headNumber = headHeader.Number.Uint64() - 1 headNumber = headHeader.Number.Uint64() - 1
headHeader = hc.GetHeader(headHash, headNumber) headHeader = hc.GetHeader(headHash, headNumber)
} }
// Extend the canonical chain with the new header // Extend the canonical chain with the new header
if err := WriteCanonicalHash(hc.chainDb, hash, number); err != nil { rawdb.WriteCanonicalHash(hc.chainDb, hash, number)
log.Crit("Failed to insert header number", "err", err) rawdb.WriteHeadHeaderHash(hc.chainDb, hash)
}
if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil {
log.Crit("Failed to insert head header hash", "err", err)
}
hc.currentHeaderHash = hash hc.currentHeaderHash = hash
hc.currentHeader.Store(types.CopyHeader(header)) hc.currentHeader.Store(types.CopyHeader(header))
@ -316,7 +314,7 @@ func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int {
if cached, ok := hc.tdCache.Get(hash); ok { if cached, ok := hc.tdCache.Get(hash); ok {
return cached.(*big.Int) return cached.(*big.Int)
} }
td := GetTd(hc.chainDb, hash, number) td := rawdb.ReadTd(hc.chainDb, hash, number)
if td == nil { if td == nil {
return nil return nil
} }
@ -328,15 +326,17 @@ func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int {
// GetTdByHash retrieves a block's total difficulty in the canonical chain from the // GetTdByHash retrieves a block's total difficulty in the canonical chain from the
// database by hash, caching it if found. // database by hash, caching it if found.
func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int { func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int {
return hc.GetTd(hash, hc.GetBlockNumber(hash)) number := hc.GetBlockNumber(hash)
if number == nil {
return nil
}
return hc.GetTd(hash, *number)
} }
// WriteTd stores a block's total difficulty into the database, also caching it // WriteTd stores a block's total difficulty into the database, also caching it
// along the way. // along the way.
func (hc *HeaderChain) WriteTd(hash common.Hash, number uint64, td *big.Int) error { func (hc *HeaderChain) WriteTd(hash common.Hash, number uint64, td *big.Int) error {
if err := WriteTd(hc.chainDb, hash, number, td); err != nil { rawdb.WriteTd(hc.chainDb, hash, number, td)
return err
}
hc.tdCache.Add(hash, new(big.Int).Set(td)) hc.tdCache.Add(hash, new(big.Int).Set(td))
return nil return nil
} }
@ -348,7 +348,7 @@ func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header
if header, ok := hc.headerCache.Get(hash); ok { if header, ok := hc.headerCache.Get(hash); ok {
return header.(*types.Header) return header.(*types.Header)
} }
header := GetHeader(hc.chainDb, hash, number) header := rawdb.ReadHeader(hc.chainDb, hash, number)
if header == nil { if header == nil {
return nil return nil
} }
@ -360,7 +360,11 @@ func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header
// GetHeaderByHash retrieves a block header from the database by hash, caching it if // GetHeaderByHash retrieves a block header from the database by hash, caching it if
// found. // found.
func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header { func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header {
return hc.GetHeader(hash, hc.GetBlockNumber(hash)) number := hc.GetBlockNumber(hash)
if number == nil {
return nil
}
return hc.GetHeader(hash, *number)
} }
// HasHeader checks if a block header is present in the database or not. // HasHeader checks if a block header is present in the database or not.
@ -368,14 +372,13 @@ func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool {
if hc.numberCache.Contains(hash) || hc.headerCache.Contains(hash) { if hc.numberCache.Contains(hash) || hc.headerCache.Contains(hash) {
return true return true
} }
ok, _ := hc.chainDb.Has(headerKey(hash, number)) return rawdb.HasHeader(hc.chainDb, hash, number)
return ok
} }
// GetHeaderByNumber retrieves a block header from the database by number, // GetHeaderByNumber retrieves a block header from the database by number,
// caching it (associated with its hash) if found. // caching it (associated with its hash) if found.
func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header { func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
hash := GetCanonicalHash(hc.chainDb, number) hash := rawdb.ReadCanonicalHash(hc.chainDb, number)
if hash == (common.Hash{}) { if hash == (common.Hash{}) {
return nil return nil
} }
@ -390,9 +393,8 @@ func (hc *HeaderChain) CurrentHeader() *types.Header {
// SetCurrentHeader sets the current head header of the canonical chain. // SetCurrentHeader sets the current head header of the canonical chain.
func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
if err := WriteHeadHeaderHash(hc.chainDb, head.Hash()); err != nil { rawdb.WriteHeadHeaderHash(hc.chainDb, head.Hash())
log.Crit("Failed to insert head header hash", "err", err)
}
hc.currentHeader.Store(head) hc.currentHeader.Store(head)
hc.currentHeaderHash = head.Hash() hc.currentHeaderHash = head.Hash()
} }
@ -416,13 +418,14 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
if delFn != nil { if delFn != nil {
delFn(hash, num) delFn(hash, num)
} }
DeleteHeader(hc.chainDb, hash, num) rawdb.DeleteHeader(hc.chainDb, hash, num)
DeleteTd(hc.chainDb, hash, num) rawdb.DeleteTd(hc.chainDb, hash, num)
hc.currentHeader.Store(hc.GetHeader(hdr.ParentHash, hdr.Number.Uint64()-1)) hc.currentHeader.Store(hc.GetHeader(hdr.ParentHash, hdr.Number.Uint64()-1))
} }
// Roll back the canonical chain numbering // Roll back the canonical chain numbering
for i := height; i > head; i-- { for i := height; i > head; i-- {
DeleteCanonicalHash(hc.chainDb, i) rawdb.DeleteCanonicalHash(hc.chainDb, i)
} }
// Clear out any stale content from the caches // Clear out any stale content from the caches
hc.headerCache.Purge() hc.headerCache.Purge()
@ -434,9 +437,7 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
} }
hc.currentHeaderHash = hc.CurrentHeader().Hash() hc.currentHeaderHash = hc.CurrentHeader().Hash()
if err := WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash); err != nil { rawdb.WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash)
log.Crit("Failed to reset head header hash", "err", err)
}
} }
// SetGenesis sets a new genesis block header for the chain // SetGenesis sets a new genesis block header for the chain

View file

@ -0,0 +1,381 @@
// Copyright 2018 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 rawdb
import (
"bytes"
"encoding/binary"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
// ReadCanonicalHash retrieves the hash assigned to a canonical block number.
func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash {
data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...))
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// WriteCanonicalHash stores the hash assigned to a canonical block number.
func WriteCanonicalHash(db DatabaseWriter, hash common.Hash, number uint64) {
key := append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)
if err := db.Put(key, hash.Bytes()); err != nil {
log.Crit("Failed to store number to hash mapping", "err", err)
}
}
// DeleteCanonicalHash removes the number to hash canonical mapping.
func DeleteCanonicalHash(db DatabaseDeleter, number uint64) {
if err := db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)); err != nil {
log.Crit("Failed to delete number to hash mapping", "err", err)
}
}
// ReadHeaderNumber returns the header number assigned to a hash.
func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 {
data, _ := db.Get(append(headerNumberPrefix, hash.Bytes()...))
if len(data) != 8 {
return nil
}
number := binary.BigEndian.Uint64(data)
return &number
}
// ReadHeadHeaderHash retrieves the hash of the current canonical head header.
func ReadHeadHeaderHash(db DatabaseReader) common.Hash {
data, _ := db.Get(headHeaderKey)
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// WriteHeadHeaderHash stores the hash of the current canonical head header.
func WriteHeadHeaderHash(db DatabaseWriter, hash common.Hash) {
if err := db.Put(headHeaderKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last header's hash", "err", err)
}
}
// ReadHeadBlockHash retrieves the hash of the current canonical head block.
func ReadHeadBlockHash(db DatabaseReader) common.Hash {
data, _ := db.Get(headBlockKey)
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// WriteHeadBlockHash stores the head block's hash.
func WriteHeadBlockHash(db DatabaseWriter, hash common.Hash) {
if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last block's hash", "err", err)
}
}
// ReadHeadFastBlockHash retrieves the hash of the current fast-sync head block.
func ReadHeadFastBlockHash(db DatabaseReader) common.Hash {
data, _ := db.Get(headFastBlockKey)
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// WriteHeadFastBlockHash stores the hash of the current fast-sync head block.
func WriteHeadFastBlockHash(db DatabaseWriter, hash common.Hash) {
if err := db.Put(headFastBlockKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last fast block's hash", "err", err)
}
}
// ReadFastTrieProgress retrieves the number of tries nodes fast synced to allow
// reporting correct numbers across restarts.
func ReadFastTrieProgress(db DatabaseReader) uint64 {
data, _ := db.Get(fastTrieProgressKey)
if len(data) == 0 {
return 0
}
return new(big.Int).SetBytes(data).Uint64()
}
// WriteFastTrieProgress stores the fast sync trie process counter to support
// retrieving it across restarts.
func WriteFastTrieProgress(db DatabaseWriter, count uint64) {
if err := db.Put(fastTrieProgressKey, new(big.Int).SetUint64(count).Bytes()); err != nil {
log.Crit("Failed to store fast sync trie progress", "err", err)
}
}
// ReadHeaderRLP retrieves a block header in its raw RLP database encoding.
func ReadHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
return data
}
// HasHeader verifies the existence of a block header corresponding to the hash.
func HasHeader(db DatabaseReader, hash common.Hash, number uint64) bool {
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
if has, err := db.Has(key); !has || err != nil {
return false
}
return true
}
// ReadHeader retrieves the block header corresponding to the hash.
func ReadHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Header {
data := ReadHeaderRLP(db, hash, number)
if len(data) == 0 {
return nil
}
header := new(types.Header)
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
log.Error("Invalid block header RLP", "hash", hash, "err", err)
return nil
}
return header
}
// WriteHeader stores a block header into the database and also stores the hash-
// to-number mapping.
func WriteHeader(db DatabaseWriter, header *types.Header) {
// Write the hash -> number mapping
var (
hash = header.Hash().Bytes()
number = header.Number.Uint64()
encoded = encodeBlockNumber(number)
)
key := append(headerNumberPrefix, hash...)
if err := db.Put(key, encoded); err != nil {
log.Crit("Failed to store hash to number mapping", "err", err)
}
// Write the encoded header
data, err := rlp.EncodeToBytes(header)
if err != nil {
log.Crit("Failed to RLP encode header", "err", err)
}
key = append(append(headerPrefix, encoded...), hash...)
if err := db.Put(key, data); err != nil {
log.Crit("Failed to store header", "err", err)
}
}
// DeleteHeader removes all block header data associated with a hash.
func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) {
if err := db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)); err != nil {
log.Crit("Failed to delete header", "err", err)
}
if err := db.Delete(append(headerNumberPrefix, hash.Bytes()...)); err != nil {
log.Crit("Failed to delete hash to number mapping", "err", err)
}
}
// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
func ReadBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
data, _ := db.Get(append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
return data
}
// WriteBodyRLP stores an RLP encoded block body into the database.
func WriteBodyRLP(db DatabaseWriter, hash common.Hash, number uint64, rlp rlp.RawValue) {
key := append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
if err := db.Put(key, rlp); err != nil {
log.Crit("Failed to store block body", "err", err)
}
}
// HasBody verifies the existence of a block body corresponding to the hash.
func HasBody(db DatabaseReader, hash common.Hash, number uint64) bool {
key := append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
if has, err := db.Has(key); !has || err != nil {
return false
}
return true
}
// ReadBody retrieves the block body corresponding to the hash.
func ReadBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body {
data := ReadBodyRLP(db, hash, number)
if len(data) == 0 {
return nil
}
body := new(types.Body)
if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
log.Error("Invalid block body RLP", "hash", hash, "err", err)
return nil
}
return body
}
// WriteBody storea a block body into the database.
func WriteBody(db DatabaseWriter, hash common.Hash, number uint64, body *types.Body) {
data, err := rlp.EncodeToBytes(body)
if err != nil {
log.Crit("Failed to RLP encode body", "err", err)
}
WriteBodyRLP(db, hash, number, data)
}
// DeleteBody removes all block body data associated with a hash.
func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) {
if err := db.Delete(append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)); err != nil {
log.Crit("Failed to delete block body", "err", err)
}
}
// ReadTd retrieves a block's total difficulty corresponding to the hash.
func ReadTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int {
data, _ := db.Get(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash[:]...), headerTDSuffix...))
if len(data) == 0 {
return nil
}
td := new(big.Int)
if err := rlp.Decode(bytes.NewReader(data), td); err != nil {
log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err)
return nil
}
return td
}
// WriteTd stores the total difficulty of a block into the database.
func WriteTd(db DatabaseWriter, hash common.Hash, number uint64, td *big.Int) {
data, err := rlp.EncodeToBytes(td)
if err != nil {
log.Crit("Failed to RLP encode block total difficulty", "err", err)
}
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), headerTDSuffix...)
if err := db.Put(key, data); err != nil {
log.Crit("Failed to store block total difficulty", "err", err)
}
}
// DeleteTd removes all block total difficulty data associated with a hash.
func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
if err := db.Delete(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), headerTDSuffix...)); err != nil {
log.Crit("Failed to delete block total difficulty", "err", err)
}
}
// ReadReceipts retrieves all the transaction receipts belonging to a block.
func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
// Retrieve the flattened receipt slice
data, _ := db.Get(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash[:]...))
if len(data) == 0 {
return nil
}
// Convert the revceipts from their storage form to their internal representation
storageReceipts := []*types.ReceiptForStorage{}
if err := rlp.DecodeBytes(data, &storageReceipts); err != nil {
log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
return nil
}
receipts := make(types.Receipts, len(storageReceipts))
for i, receipt := range storageReceipts {
receipts[i] = (*types.Receipt)(receipt)
}
return receipts
}
// WriteReceipts stores all the transaction receipts belonging to a block.
func WriteReceipts(db DatabaseWriter, hash common.Hash, number uint64, receipts types.Receipts) {
// Convert the receipts into their storage form and serialize them
storageReceipts := make([]*types.ReceiptForStorage, len(receipts))
for i, receipt := range receipts {
storageReceipts[i] = (*types.ReceiptForStorage)(receipt)
}
bytes, err := rlp.EncodeToBytes(storageReceipts)
if err != nil {
log.Crit("Failed to encode block receipts", "err", err)
}
// Store the flattened receipt slice
key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
if err := db.Put(key, bytes); err != nil {
log.Crit("Failed to store block receipts", "err", err)
}
}
// DeleteReceipts removes all receipt data associated with a block hash.
func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) {
if err := db.Delete(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)); err != nil {
log.Crit("Failed to delete block receipts", "err", err)
}
}
// ReadBlock retrieves an entire block corresponding to the hash, assembling it
// back from the stored header and body. If either the header or body could not
// be retrieved nil is returned.
//
// Note, due to concurrent download of header and block body the header and thus
// canonical hash can be stored in the database but the body data not (yet).
func ReadBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block {
header := ReadHeader(db, hash, number)
if header == nil {
return nil
}
body := ReadBody(db, hash, number)
if body == nil {
return nil
}
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles)
}
// WriteBlock serializes a block into the database, header and body separately.
func WriteBlock(db DatabaseWriter, block *types.Block) {
WriteBody(db, block.Hash(), block.NumberU64(), block.Body())
WriteHeader(db, block.Header())
}
// DeleteBlock removes all block data associated with a hash.
func DeleteBlock(db DatabaseDeleter, hash common.Hash, number uint64) {
DeleteReceipts(db, hash, number)
DeleteHeader(db, hash, number)
DeleteBody(db, hash, number)
DeleteTd(db, hash, number)
}
// FindCommonAncestor returns the last common ancestor of two block headers
func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header {
for bn := b.Number.Uint64(); a.Number.Uint64() > bn; {
a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1)
if a == nil {
return nil
}
}
for an := a.Number.Uint64(); an < b.Number.Uint64(); {
b = ReadHeader(db, b.ParentHash, b.Number.Uint64()-1)
if b == nil {
return nil
}
}
for a.Hash() != b.Hash() {
a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1)
if a == nil {
return nil
}
b = ReadHeader(db, b.ParentHash, b.Number.Uint64()-1)
if b == nil {
return nil
}
}
return a
}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The go-ethereum Authors // Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package rawdb
import ( import (
"bytes" "bytes"
@ -34,19 +34,17 @@ func TestHeaderStorage(t *testing.T) {
// Create a test header to move around the database and make sure it's really new // Create a test header to move around the database and make sure it's really new
header := &types.Header{Number: big.NewInt(42), Extra: []byte("test header")} header := &types.Header{Number: big.NewInt(42), Extra: []byte("test header")}
if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry != nil {
t.Fatalf("Non existent header returned: %v", entry) t.Fatalf("Non existent header returned: %v", entry)
} }
// Write and verify the header in the database // Write and verify the header in the database
if err := WriteHeader(db, header); err != nil { WriteHeader(db, header)
t.Fatalf("Failed to write header into database: %v", err) if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry == nil {
}
if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry == nil {
t.Fatalf("Stored header not found") t.Fatalf("Stored header not found")
} else if entry.Hash() != header.Hash() { } else if entry.Hash() != header.Hash() {
t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header) t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header)
} }
if entry := GetHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil { if entry := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil {
t.Fatalf("Stored header RLP not found") t.Fatalf("Stored header RLP not found")
} else { } else {
hasher := sha3.NewKeccak256() hasher := sha3.NewKeccak256()
@ -58,7 +56,7 @@ func TestHeaderStorage(t *testing.T) {
} }
// Delete the header and verify the execution // Delete the header and verify the execution
DeleteHeader(db, header.Hash(), header.Number.Uint64()) DeleteHeader(db, header.Hash(), header.Number.Uint64())
if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry != nil {
t.Fatalf("Deleted header returned: %v", entry) t.Fatalf("Deleted header returned: %v", entry)
} }
} }
@ -74,19 +72,17 @@ func TestBodyStorage(t *testing.T) {
rlp.Encode(hasher, body) rlp.Encode(hasher, body)
hash := common.BytesToHash(hasher.Sum(nil)) hash := common.BytesToHash(hasher.Sum(nil))
if entry := GetBody(db, hash, 0); entry != nil { if entry := ReadBody(db, hash, 0); entry != nil {
t.Fatalf("Non existent body returned: %v", entry) t.Fatalf("Non existent body returned: %v", entry)
} }
// Write and verify the body in the database // Write and verify the body in the database
if err := WriteBody(db, hash, 0, body); err != nil { WriteBody(db, hash, 0, body)
t.Fatalf("Failed to write body into database: %v", err) if entry := ReadBody(db, hash, 0); entry == nil {
}
if entry := GetBody(db, hash, 0); entry == nil {
t.Fatalf("Stored body not found") t.Fatalf("Stored body not found")
} else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(types.Transactions(body.Transactions)) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) { } else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(types.Transactions(body.Transactions)) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) {
t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body) t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body)
} }
if entry := GetBodyRLP(db, hash, 0); entry == nil { if entry := ReadBodyRLP(db, hash, 0); entry == nil {
t.Fatalf("Stored body RLP not found") t.Fatalf("Stored body RLP not found")
} else { } else {
hasher := sha3.NewKeccak256() hasher := sha3.NewKeccak256()
@ -98,7 +94,7 @@ func TestBodyStorage(t *testing.T) {
} }
// Delete the body and verify the execution // Delete the body and verify the execution
DeleteBody(db, hash, 0) DeleteBody(db, hash, 0)
if entry := GetBody(db, hash, 0); entry != nil { if entry := ReadBody(db, hash, 0); entry != nil {
t.Fatalf("Deleted body returned: %v", entry) t.Fatalf("Deleted body returned: %v", entry)
} }
} }
@ -114,43 +110,41 @@ func TestBlockStorage(t *testing.T) {
TxHash: types.EmptyRootHash, TxHash: types.EmptyRootHash,
ReceiptHash: types.EmptyRootHash, ReceiptHash: types.EmptyRootHash,
}) })
if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil { if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Non existent block returned: %v", entry) t.Fatalf("Non existent block returned: %v", entry)
} }
if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry != nil { if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Non existent header returned: %v", entry) t.Fatalf("Non existent header returned: %v", entry)
} }
if entry := GetBody(db, block.Hash(), block.NumberU64()); entry != nil { if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Non existent body returned: %v", entry) t.Fatalf("Non existent body returned: %v", entry)
} }
// Write and verify the block in the database // Write and verify the block in the database
if err := WriteBlock(db, block); err != nil { WriteBlock(db, block)
t.Fatalf("Failed to write block into database: %v", err) if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry == nil {
}
if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry == nil {
t.Fatalf("Stored block not found") t.Fatalf("Stored block not found")
} else if entry.Hash() != block.Hash() { } else if entry.Hash() != block.Hash() {
t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block)
} }
if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry == nil { if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry == nil {
t.Fatalf("Stored header not found") t.Fatalf("Stored header not found")
} else if entry.Hash() != block.Header().Hash() { } else if entry.Hash() != block.Header().Hash() {
t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header()) t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header())
} }
if entry := GetBody(db, block.Hash(), block.NumberU64()); entry == nil { if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry == nil {
t.Fatalf("Stored body not found") t.Fatalf("Stored body not found")
} else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(block.Transactions()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) { } else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(block.Transactions()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) {
t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body()) t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body())
} }
// Delete the block and verify the execution // Delete the block and verify the execution
DeleteBlock(db, block.Hash(), block.NumberU64()) DeleteBlock(db, block.Hash(), block.NumberU64())
if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil { if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Deleted block returned: %v", entry) t.Fatalf("Deleted block returned: %v", entry)
} }
if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry != nil { if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Deleted header returned: %v", entry) t.Fatalf("Deleted header returned: %v", entry)
} }
if entry := GetBody(db, block.Hash(), block.NumberU64()); entry != nil { if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Deleted body returned: %v", entry) t.Fatalf("Deleted body returned: %v", entry)
} }
} }
@ -165,31 +159,24 @@ func TestPartialBlockStorage(t *testing.T) {
ReceiptHash: types.EmptyRootHash, ReceiptHash: types.EmptyRootHash,
}) })
// Store a header and check that it's not recognized as a block // Store a header and check that it's not recognized as a block
if err := WriteHeader(db, block.Header()); err != nil { WriteHeader(db, block.Header())
t.Fatalf("Failed to write header into database: %v", err) if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil {
}
if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Non existent block returned: %v", entry) t.Fatalf("Non existent block returned: %v", entry)
} }
DeleteHeader(db, block.Hash(), block.NumberU64()) DeleteHeader(db, block.Hash(), block.NumberU64())
// Store a body and check that it's not recognized as a block // Store a body and check that it's not recognized as a block
if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil { WriteBody(db, block.Hash(), block.NumberU64(), block.Body())
t.Fatalf("Failed to write body into database: %v", err) if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil {
}
if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Non existent block returned: %v", entry) t.Fatalf("Non existent block returned: %v", entry)
} }
DeleteBody(db, block.Hash(), block.NumberU64()) DeleteBody(db, block.Hash(), block.NumberU64())
// Store a header and a body separately and check reassembly // Store a header and a body separately and check reassembly
if err := WriteHeader(db, block.Header()); err != nil { WriteHeader(db, block.Header())
t.Fatalf("Failed to write header into database: %v", err) WriteBody(db, block.Hash(), block.NumberU64(), block.Body())
}
if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil { if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry == nil {
t.Fatalf("Failed to write body into database: %v", err)
}
if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry == nil {
t.Fatalf("Stored block not found") t.Fatalf("Stored block not found")
} else if entry.Hash() != block.Hash() { } else if entry.Hash() != block.Hash() {
t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block)
@ -202,21 +189,19 @@ func TestTdStorage(t *testing.T) {
// Create a test TD to move around the database and make sure it's really new // Create a test TD to move around the database and make sure it's really new
hash, td := common.Hash{}, big.NewInt(314) hash, td := common.Hash{}, big.NewInt(314)
if entry := GetTd(db, hash, 0); entry != nil { if entry := ReadTd(db, hash, 0); entry != nil {
t.Fatalf("Non existent TD returned: %v", entry) t.Fatalf("Non existent TD returned: %v", entry)
} }
// Write and verify the TD in the database // Write and verify the TD in the database
if err := WriteTd(db, hash, 0, td); err != nil { WriteTd(db, hash, 0, td)
t.Fatalf("Failed to write TD into database: %v", err) if entry := ReadTd(db, hash, 0); entry == nil {
}
if entry := GetTd(db, hash, 0); entry == nil {
t.Fatalf("Stored TD not found") t.Fatalf("Stored TD not found")
} else if entry.Cmp(td) != 0 { } else if entry.Cmp(td) != 0 {
t.Fatalf("Retrieved TD mismatch: have %v, want %v", entry, td) t.Fatalf("Retrieved TD mismatch: have %v, want %v", entry, td)
} }
// Delete the TD and verify the execution // Delete the TD and verify the execution
DeleteTd(db, hash, 0) DeleteTd(db, hash, 0)
if entry := GetTd(db, hash, 0); entry != nil { if entry := ReadTd(db, hash, 0); entry != nil {
t.Fatalf("Deleted TD returned: %v", entry) t.Fatalf("Deleted TD returned: %v", entry)
} }
} }
@ -227,21 +212,19 @@ func TestCanonicalMappingStorage(t *testing.T) {
// Create a test canonical number and assinged hash to move around // Create a test canonical number and assinged hash to move around
hash, number := common.Hash{0: 0xff}, uint64(314) hash, number := common.Hash{0: 0xff}, uint64(314)
if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) { if entry := ReadCanonicalHash(db, number); entry != (common.Hash{}) {
t.Fatalf("Non existent canonical mapping returned: %v", entry) t.Fatalf("Non existent canonical mapping returned: %v", entry)
} }
// Write and verify the TD in the database // Write and verify the TD in the database
if err := WriteCanonicalHash(db, hash, number); err != nil { WriteCanonicalHash(db, hash, number)
t.Fatalf("Failed to write canonical mapping into database: %v", err) if entry := ReadCanonicalHash(db, number); entry == (common.Hash{}) {
}
if entry := GetCanonicalHash(db, number); entry == (common.Hash{}) {
t.Fatalf("Stored canonical mapping not found") t.Fatalf("Stored canonical mapping not found")
} else if entry != hash { } else if entry != hash {
t.Fatalf("Retrieved canonical mapping mismatch: have %v, want %v", entry, hash) t.Fatalf("Retrieved canonical mapping mismatch: have %v, want %v", entry, hash)
} }
// Delete the TD and verify the execution // Delete the TD and verify the execution
DeleteCanonicalHash(db, number) DeleteCanonicalHash(db, number)
if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) { if entry := ReadCanonicalHash(db, number); entry != (common.Hash{}) {
t.Fatalf("Deleted canonical mapping returned: %v", entry) t.Fatalf("Deleted canonical mapping returned: %v", entry)
} }
} }
@ -255,82 +238,32 @@ func TestHeadStorage(t *testing.T) {
blockFast := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block fast")}) blockFast := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block fast")})
// Check that no head entries are in a pristine database // Check that no head entries are in a pristine database
if entry := GetHeadHeaderHash(db); entry != (common.Hash{}) { if entry := ReadHeadHeaderHash(db); entry != (common.Hash{}) {
t.Fatalf("Non head header entry returned: %v", entry) t.Fatalf("Non head header entry returned: %v", entry)
} }
if entry := GetHeadBlockHash(db); entry != (common.Hash{}) { if entry := ReadHeadBlockHash(db); entry != (common.Hash{}) {
t.Fatalf("Non head block entry returned: %v", entry) t.Fatalf("Non head block entry returned: %v", entry)
} }
if entry := GetHeadFastBlockHash(db); entry != (common.Hash{}) { if entry := ReadHeadFastBlockHash(db); entry != (common.Hash{}) {
t.Fatalf("Non fast head block entry returned: %v", entry) t.Fatalf("Non fast head block entry returned: %v", entry)
} }
// Assign separate entries for the head header and block // Assign separate entries for the head header and block
if err := WriteHeadHeaderHash(db, blockHead.Hash()); err != nil { WriteHeadHeaderHash(db, blockHead.Hash())
t.Fatalf("Failed to write head header hash: %v", err) WriteHeadBlockHash(db, blockFull.Hash())
} WriteHeadFastBlockHash(db, blockFast.Hash())
if err := WriteHeadBlockHash(db, blockFull.Hash()); err != nil {
t.Fatalf("Failed to write head block hash: %v", err)
}
if err := WriteHeadFastBlockHash(db, blockFast.Hash()); err != nil {
t.Fatalf("Failed to write fast head block hash: %v", err)
}
// Check that both heads are present, and different (i.e. two heads maintained) // Check that both heads are present, and different (i.e. two heads maintained)
if entry := GetHeadHeaderHash(db); entry != blockHead.Hash() { if entry := ReadHeadHeaderHash(db); entry != blockHead.Hash() {
t.Fatalf("Head header hash mismatch: have %v, want %v", entry, blockHead.Hash()) t.Fatalf("Head header hash mismatch: have %v, want %v", entry, blockHead.Hash())
} }
if entry := GetHeadBlockHash(db); entry != blockFull.Hash() { if entry := ReadHeadBlockHash(db); entry != blockFull.Hash() {
t.Fatalf("Head block hash mismatch: have %v, want %v", entry, blockFull.Hash()) t.Fatalf("Head block hash mismatch: have %v, want %v", entry, blockFull.Hash())
} }
if entry := GetHeadFastBlockHash(db); entry != blockFast.Hash() { if entry := ReadHeadFastBlockHash(db); entry != blockFast.Hash() {
t.Fatalf("Fast head block hash mismatch: have %v, want %v", entry, blockFast.Hash()) t.Fatalf("Fast head block hash mismatch: have %v, want %v", entry, blockFast.Hash())
} }
} }
// Tests that positional lookup metadata can be stored and retrieved.
func TestLookupStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22})
tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33})
txs := []*types.Transaction{tx1, tx2, tx3}
block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil)
// Check that no transactions entries are in a pristine database
for i, tx := range txs {
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {
t.Fatalf("tx #%d [%x]: non existent transaction returned: %v", i, tx.Hash(), txn)
}
}
// Insert all the transactions into the database, and verify contents
if err := WriteBlock(db, block); err != nil {
t.Fatalf("failed to write block contents: %v", err)
}
if err := WriteTxLookupEntries(db, block); err != nil {
t.Fatalf("failed to write transactions: %v", err)
}
for i, tx := range txs {
if txn, hash, number, index := GetTransaction(db, tx.Hash()); txn == nil {
t.Fatalf("tx #%d [%x]: transaction not found", i, tx.Hash())
} else {
if hash != block.Hash() || number != block.NumberU64() || index != uint64(i) {
t.Fatalf("tx #%d [%x]: positional metadata mismatch: have %x/%d/%d, want %x/%v/%v", i, tx.Hash(), hash, number, index, block.Hash(), block.NumberU64(), i)
}
if tx.Hash() != txn.Hash() {
t.Fatalf("tx #%d [%x]: transaction mismatch: have %v, want %v", i, tx.Hash(), txn, tx)
}
}
}
// Delete the transactions and check purge
for i, tx := range txs {
DeleteTxLookupEntry(db, tx.Hash())
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {
t.Fatalf("tx #%d [%x]: deleted transaction returned: %v", i, tx.Hash(), txn)
}
}
}
// Tests that receipts associated with a single block can be stored and retrieved. // Tests that receipts associated with a single block can be stored and retrieved.
func TestBlockReceiptStorage(t *testing.T) { func TestBlockReceiptStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
@ -361,14 +294,12 @@ func TestBlockReceiptStorage(t *testing.T) {
// Check that no receipt entries are in a pristine database // Check that no receipt entries are in a pristine database
hash := common.BytesToHash([]byte{0x03, 0x14}) hash := common.BytesToHash([]byte{0x03, 0x14})
if rs := GetBlockReceipts(db, hash, 0); len(rs) != 0 { if rs := ReadReceipts(db, hash, 0); len(rs) != 0 {
t.Fatalf("non existent receipts returned: %v", rs) t.Fatalf("non existent receipts returned: %v", rs)
} }
// Insert the receipt slice into the database and check presence // Insert the receipt slice into the database and check presence
if err := WriteBlockReceipts(db, hash, 0, receipts); err != nil { WriteReceipts(db, hash, 0, receipts)
t.Fatalf("failed to write block receipts: %v", err) if rs := ReadReceipts(db, hash, 0); len(rs) == 0 {
}
if rs := GetBlockReceipts(db, hash, 0); len(rs) == 0 {
t.Fatalf("no receipts returned") t.Fatalf("no receipts returned")
} else { } else {
for i := 0; i < len(receipts); i++ { for i := 0; i < len(receipts); i++ {
@ -381,8 +312,8 @@ func TestBlockReceiptStorage(t *testing.T) {
} }
} }
// Delete the receipt slice and check purge // Delete the receipt slice and check purge
DeleteBlockReceipts(db, hash, 0) DeleteReceipts(db, hash, 0)
if rs := GetBlockReceipts(db, hash, 0); len(rs) != 0 { if rs := ReadReceipts(db, hash, 0); len(rs) != 0 {
t.Fatalf("deleted receipts returned: %v", rs) t.Fatalf("deleted receipts returned: %v", rs)
} }
} }

View file

@ -0,0 +1,119 @@
// Copyright 2018 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 rawdb
import (
"encoding/binary"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
// ReadTxLookupEntry retrieves the positional metadata associated with a transaction
// hash to allow retrieving the transaction or receipt by hash.
func ReadTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) {
data, _ := db.Get(append(txLookupPrefix, hash.Bytes()...))
if len(data) == 0 {
return common.Hash{}, 0, 0
}
var entry TxLookupEntry
if err := rlp.DecodeBytes(data, &entry); err != nil {
log.Error("Invalid transaction lookup entry RLP", "hash", hash, "err", err)
return common.Hash{}, 0, 0
}
return entry.BlockHash, entry.BlockIndex, entry.Index
}
// WriteTxLookupEntries stores a positional metadata for every transaction from
// a block, enabling hash based transaction and receipt lookups.
func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
for i, tx := range block.Transactions() {
entry := TxLookupEntry{
BlockHash: block.Hash(),
BlockIndex: block.NumberU64(),
Index: uint64(i),
}
data, err := rlp.EncodeToBytes(entry)
if err != nil {
log.Crit("Failed to encode transaction lookup entry", "err", err)
}
if err := db.Put(append(txLookupPrefix, tx.Hash().Bytes()...), data); err != nil {
log.Crit("Failed to store transaction lookup entry", "err", err)
}
}
}
// DeleteTxLookupEntry removes all transaction data associated with a hash.
func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) {
db.Delete(append(txLookupPrefix, hash.Bytes()...))
}
// ReadTransaction retrieves a specific transaction from the database, along with
// its added positional metadata.
func ReadTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
blockHash, blockNumber, txIndex := ReadTxLookupEntry(db, hash)
if blockHash == (common.Hash{}) {
return nil, common.Hash{}, 0, 0
}
body := ReadBody(db, blockHash, blockNumber)
if body == nil || len(body.Transactions) <= int(txIndex) {
log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash, "index", txIndex)
return nil, common.Hash{}, 0, 0
}
return body.Transactions[txIndex], blockHash, blockNumber, txIndex
}
// ReadReceipt retrieves a specific transaction receipt from the database, along with
// its added positional metadata.
func ReadReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) {
blockHash, blockNumber, receiptIndex := ReadTxLookupEntry(db, hash)
if blockHash == (common.Hash{}) {
return nil, common.Hash{}, 0, 0
}
receipts := ReadReceipts(db, blockHash, blockNumber)
if len(receipts) <= int(receiptIndex) {
log.Error("Receipt refereced missing", "number", blockNumber, "hash", blockHash, "index", receiptIndex)
return nil, common.Hash{}, 0, 0
}
return receipts[receiptIndex], blockHash, blockNumber, receiptIndex
}
// ReadBloomBits retrieves the compressed bloom bit vector belonging to the given
// section and bit index from the.
func ReadBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) {
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...)
binary.BigEndian.PutUint16(key[1:], uint16(bit))
binary.BigEndian.PutUint64(key[3:], section)
return db.Get(key)
}
// WriteBloomBits stores the compressed bloom bits vector belonging to the given
// section and bit index.
func WriteBloomBits(db DatabaseWriter, bit uint, section uint64, head common.Hash, bits []byte) {
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...)
binary.BigEndian.PutUint16(key[1:], uint16(bit))
binary.BigEndian.PutUint64(key[3:], section)
if err := db.Put(key, bits); err != nil {
log.Crit("Failed to store bloom bits", "err", err)
}
}

View file

@ -0,0 +1,68 @@
// Copyright 2018 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 rawdb
import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
)
// Tests that positional lookup metadata can be stored and retrieved.
func TestLookupStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22})
tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33})
txs := []*types.Transaction{tx1, tx2, tx3}
block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil)
// Check that no transactions entries are in a pristine database
for i, tx := range txs {
if txn, _, _, _ := ReadTransaction(db, tx.Hash()); txn != nil {
t.Fatalf("tx #%d [%x]: non existent transaction returned: %v", i, tx.Hash(), txn)
}
}
// Insert all the transactions into the database, and verify contents
WriteBlock(db, block)
WriteTxLookupEntries(db, block)
for i, tx := range txs {
if txn, hash, number, index := ReadTransaction(db, tx.Hash()); txn == nil {
t.Fatalf("tx #%d [%x]: transaction not found", i, tx.Hash())
} else {
if hash != block.Hash() || number != block.NumberU64() || index != uint64(i) {
t.Fatalf("tx #%d [%x]: positional metadata mismatch: have %x/%d/%d, want %x/%v/%v", i, tx.Hash(), hash, number, index, block.Hash(), block.NumberU64(), i)
}
if tx.Hash() != txn.Hash() {
t.Fatalf("tx #%d [%x]: transaction mismatch: have %v, want %v", i, tx.Hash(), txn, tx)
}
}
}
// Delete the transactions and check purge
for i, tx := range txs {
DeleteTxLookupEntry(db, tx.Hash())
if txn, _, _, _ := ReadTransaction(db, tx.Hash()); txn != nil {
t.Fatalf("tx #%d [%x]: deleted transaction returned: %v", i, tx.Hash(), txn)
}
}
}

View file

@ -0,0 +1,90 @@
// Copyright 2018 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 rawdb
import (
"encoding/json"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
// ReadDatabaseVersion retrieves the version number of the database.
func ReadDatabaseVersion(db DatabaseReader) int {
var version int
enc, _ := db.Get(databaseVerisionKey)
rlp.DecodeBytes(enc, &version)
return version
}
// WriteDatabaseVersion stores the version number of the database
func WriteDatabaseVersion(db DatabaseWriter, version int) {
enc, _ := rlp.EncodeToBytes(version)
if err := db.Put(databaseVerisionKey, enc); err != nil {
log.Crit("Failed to store the database version", "err", err)
}
}
// ReadChainConfig retrieves the consensus settings based on the given genesis hash.
func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig {
data, _ := db.Get(append(configPrefix, hash[:]...))
if len(data) == 0 {
return nil
}
var config params.ChainConfig
if err := json.Unmarshal(data, &config); err != nil {
log.Error("Invalid chain config JSON", "hash", hash, "err", err)
return nil
}
return &config
}
// WriteChainConfig writes the chain config settings to the database.
func WriteChainConfig(db DatabaseWriter, hash common.Hash, cfg *params.ChainConfig) {
if cfg == nil {
return
}
data, err := json.Marshal(cfg)
if err != nil {
log.Crit("Failed to JSON encode chain config", "err", err)
}
if err := db.Put(append(configPrefix, hash[:]...), data); err != nil {
log.Crit("Failed to store chain config", "err", err)
}
}
// ReadPreimage retrieves a single preimage of the provided hash.
func ReadPreimage(db DatabaseReader, hash common.Hash) []byte {
data, _ := db.Get(append(preimagePrefix, hash.Bytes()...))
return data
}
// WritePreimages writes the provided set of preimages to the database. `number` is the
// current block number, and is used for debug messages only.
func WritePreimages(db DatabaseWriter, number uint64, preimages map[common.Hash][]byte) {
for hash, preimage := range preimages {
if err := db.Put(append(preimagePrefix, hash.Bytes()...), preimage); err != nil {
log.Crit("Failed to store trie preimage", "err", err)
}
}
preimageCounter.Inc(int64(len(preimages)))
preimageHitCounter.Inc(int64(len(preimages)))
}

33
core/rawdb/interfaces.go Normal file
View file

@ -0,0 +1,33 @@
// Copyright 2018 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 rawdb
// DatabaseReader wraps the Has and Get method of a backing data store.
type DatabaseReader interface {
Has(key []byte) (bool, error)
Get(key []byte) ([]byte, error)
}
// DatabaseWriter wraps the Put method of a backing data store.
type DatabaseWriter interface {
Put(key []byte, value []byte) error
}
// DatabaseDeleter wraps the Delete method of a backing data store.
type DatabaseDeleter interface {
Delete(key []byte) error
}

79
core/rawdb/schema.go Normal file
View file

@ -0,0 +1,79 @@
// Copyright 2018 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 rawdb contains a collection of low level database accessors.
package rawdb
import (
"encoding/binary"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/metrics"
)
// The fields below define the low level database schema prefixing.
var (
// databaseVerisionKey tracks the current database version.
databaseVerisionKey = []byte("DatabaseVersion")
// headHeaderKey tracks the latest know header's hash.
headHeaderKey = []byte("LastHeader")
// headBlockKey tracks the latest know full block's hash.
headBlockKey = []byte("LastBlock")
// headFastBlockKey tracks the latest known incomplete block's hash duirng fast sync.
headFastBlockKey = []byte("LastFast")
// fastTrieProgressKey tracks the number of trie entries imported during fast sync.
fastTrieProgressKey = []byte("TrieSync")
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes).
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
headerTDSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td
headerHashSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + headerHashSuffix -> hash
headerNumberPrefix = []byte("H") // headerNumberPrefix + hash -> num (uint64 big endian)
blockBodyPrefix = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db
// Chain index prefixes (use `i` + single byte to avoid mixing data types).
BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress
preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil)
preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil)
)
// TxLookupEntry is a positional metadata to help looking up the data content of
// a transaction or receipt given only its hash.
type TxLookupEntry struct {
BlockHash common.Hash
BlockIndex uint64
Index uint64
}
// encodeBlockNumber encodes a block number as big endian uint64
func encodeBlockNumber(number uint64) []byte {
enc := make([]byte, 8)
binary.BigEndian.PutUint64(enc, number)
return enc
}

View file

@ -178,9 +178,7 @@ func (self *stateObject) GetState(db Database, key common.Hash) common.Hash {
} }
value.SetBytes(content) value.SetBytes(content)
} }
if (value != common.Hash{}) {
self.cachedStorage[key] = value self.cachedStorage[key] = value
}
return value return value
} }
@ -197,7 +195,6 @@ func (self *stateObject) SetState(db Database, key, value common.Hash) {
func (self *stateObject) setState(key, value common.Hash) { func (self *stateObject) setState(key, value common.Hash) {
self.cachedStorage[key] = value self.cachedStorage[key] = value
self.dirtyStorage[key] = value self.dirtyStorage[key] = value
} }
// updateTrie writes cached storage modifications into the object's storage trie. // updateTrie writes cached storage modifications into the object's storage trie.

View file

@ -572,27 +572,6 @@ func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) {
self.txIndex = ti self.txIndex = ti
} }
// DeleteSuicides flags the suicided objects for deletion so that it
// won't be referenced again when called / queried up on.
//
// DeleteSuicides should not be used for consensus related updates
// under any circumstances.
func (s *StateDB) DeleteSuicides() {
// Reset refund so that any used-gas calculations can use this method.
s.clearJournalAndRefund()
for addr := range s.stateObjectsDirty {
stateObject := s.stateObjects[addr]
// If the object has been removed by a suicide
// flag the object as deleted.
if stateObject.suicided {
stateObject.deleted = true
}
delete(s.stateObjectsDirty, addr)
}
}
func (s *StateDB) clearJournalAndRefund() { func (s *StateDB) clearJournalAndRefund() {
s.journal = newJournal() s.journal = newJournal()
s.validRevisions = s.validRevisions[:0] s.validRevisions = s.validRevisions[:0]

View file

@ -618,7 +618,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
// If the transaction pool is full, discard underpriced transactions // If the transaction pool is full, discard underpriced transactions
if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue { if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue {
// If the new transaction is underpriced, don't accept it // If the new transaction is underpriced, don't accept it
if pool.priced.Underpriced(tx, pool.locals) { if !local && pool.priced.Underpriced(tx, pool.locals) {
log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice()) log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice())
underpricedTxCounter.Inc(1) underpricedTxCounter.Inc(1)
return false, ErrUnderpriced return false, ErrUnderpriced

View file

@ -1346,7 +1346,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
defer sub.Unsubscribe() defer sub.Unsubscribe()
// Create a number of test accounts and fund them // Create a number of test accounts and fund them
keys := make([]*ecdsa.PrivateKey, 3) keys := make([]*ecdsa.PrivateKey, 4)
for i := 0; i < len(keys); i++ { for i := 0; i < len(keys); i++ {
keys[i], _ = crypto.GenerateKey() keys[i], _ = crypto.GenerateKey()
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
@ -1406,18 +1406,22 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Ensure that adding local transactions can push out even higher priced ones // Ensure that adding local transactions can push out even higher priced ones
tx := pricedTransaction(1, 100000, big.NewInt(0), keys[2]) ltx = pricedTransaction(1, 100000, big.NewInt(0), keys[2])
if err := pool.AddLocal(tx); err != nil { if err := pool.AddLocal(ltx); err != nil {
t.Fatalf("failed to add underpriced local transaction: %v", err) t.Fatalf("failed to append underpriced local transaction: %v", err)
}
ltx = pricedTransaction(0, 100000, big.NewInt(0), keys[3])
if err := pool.AddLocal(ltx); err != nil {
t.Fatalf("failed to add new underpriced local transaction: %v", err)
} }
pending, queued = pool.Stats() pending, queued = pool.Stats()
if pending != 2 { if pending != 3 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
} }
if queued != 2 { if queued != 1 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
} }
if err := validateEvents(events, 1); err != nil { if err := validateEvents(events, 2); err != nil {
t.Fatalf("local event firing failed: %v", err) t.Fatalf("local event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validateTxPoolInternals(pool); err != nil {

View file

@ -139,15 +139,15 @@ func (c *Contract) Value() *big.Int {
} }
// SetCode sets the code to the contract // SetCode sets the code to the contract
func (self *Contract) SetCode(hash common.Hash, code []byte) { func (c *Contract) SetCode(hash common.Hash, code []byte) {
self.Code = code c.Code = code
self.CodeHash = hash c.CodeHash = hash
} }
// SetCallCode sets the code of the contract and address of the backing data // SetCallCode sets the code of the contract and address of the backing data
// object // object
func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) {
self.Code = code c.Code = code
self.CodeHash = hash c.CodeHash = hash
self.CodeAddr = addr c.CodeAddr = addr
} }

View file

@ -160,6 +160,11 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
precompiles = PrecompiledContractsByzantium precompiles = PrecompiledContractsByzantium
} }
if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
// Calling a non existing account, don't do antything, but ping the tracer
if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil)
}
return nil, gas, nil return nil, gas, nil
} }
evm.StateDB.CreateAccount(addr) evm.StateDB.CreateAccount(addr)

View file

@ -31,9 +31,9 @@ import (
type Storage map[common.Hash]common.Hash type Storage map[common.Hash]common.Hash
func (self Storage) Copy() Storage { func (s Storage) Copy() Storage {
cpy := make(Storage) cpy := make(Storage)
for key, value := range self { for key, value := range s {
cpy[key] = value cpy[key] = value
} }

View file

@ -51,14 +51,14 @@ func (m *Memory) Resize(size uint64) {
} }
// Get returns offset + size as a new slice // Get returns offset + size as a new slice
func (self *Memory) Get(offset, size int64) (cpy []byte) { func (m *Memory) Get(offset, size int64) (cpy []byte) {
if size == 0 { if size == 0 {
return nil return nil
} }
if len(self.store) > int(offset) { if len(m.store) > int(offset) {
cpy = make([]byte, size) cpy = make([]byte, size)
copy(cpy, self.store[offset:offset+size]) copy(cpy, m.store[offset:offset+size])
return return
} }
@ -67,13 +67,13 @@ func (self *Memory) Get(offset, size int64) (cpy []byte) {
} }
// GetPtr returns the offset + size // GetPtr returns the offset + size
func (self *Memory) GetPtr(offset, size int64) []byte { func (m *Memory) GetPtr(offset, size int64) []byte {
if size == 0 { if size == 0 {
return nil return nil
} }
if len(self.store) > int(offset) { if len(m.store) > int(offset) {
return self.store[offset : offset+size] return m.store[offset : offset+size]
} }
return nil return nil

View file

@ -375,10 +375,10 @@ var opCodeToString = map[OpCode]string{
SWAP: "SWAP", SWAP: "SWAP",
} }
func (o OpCode) String() string { func (op OpCode) String() string {
str := opCodeToString[o] str := opCodeToString[op]
if len(str) == 0 { if len(str) == 0 {
return fmt.Sprintf("Missing opcode 0x%x", int(o)) return fmt.Sprintf("Missing opcode 0x%x", int(op))
} }
return str return str

View file

@ -19,6 +19,7 @@ package eth
import ( import (
"compress/gzip" "compress/gzip"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
@ -28,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -343,8 +345,10 @@ func NewPrivateDebugAPI(config *params.ChainConfig, eth *Ethereum) *PrivateDebug
// Preimage is a debug API function that returns the preimage for a sha3 hash, if known. // Preimage is a debug API function that returns the preimage for a sha3 hash, if known.
func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
db := core.PreimageTable(api.eth.ChainDb()) if preimage := rawdb.ReadPreimage(api.eth.ChainDb(), hash); preimage != nil {
return db.Get(hash.Bytes()) return preimage, nil
}
return nil, errors.New("unknown preimage")
} }
// GetBadBLocks returns a list of the last 'bad blocks' that the client has seen on the network // GetBadBLocks returns a list of the last 'bad blocks' that the client has seen on the network

View file

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -96,16 +97,23 @@ func (b *EthApiBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.
return stateDb, header, err return stateDb, header, err
} }
func (b *EthApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) { func (b *EthApiBackend) GetBlock(ctx context.Context, hash common.Hash) (*types.Block, error) {
return b.eth.blockchain.GetBlockByHash(blockHash), nil return b.eth.blockchain.GetBlockByHash(hash), nil
} }
func (b *EthApiBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) { func (b *EthApiBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
return core.GetBlockReceipts(b.eth.chainDb, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)), nil if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil {
return rawdb.ReadReceipts(b.eth.chainDb, hash, *number), nil
}
return nil, nil
} }
func (b *EthApiBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) { func (b *EthApiBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
receipts := core.GetBlockReceipts(b.eth.chainDb, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)) number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash)
if number == nil {
return nil, nil
}
receipts := rawdb.ReadReceipts(b.eth.chainDb, hash, *number)
if receipts == nil { if receipts == nil {
return nil, nil return nil, nil
} }

View file

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -201,7 +202,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
break break
} }
task.statedb.DeleteSuicides() task.statedb.Finalise(true)
task.results[i] = &txTraceResult{Result: res} task.results[i] = &txTraceResult{Result: res}
} }
// Stream the result back to the user or abort on teardown // Stream the result back to the user or abort on teardown
@ -533,7 +534,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
// and returns them as a JSON object. // and returns them as a JSON object.
func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
// Retrieve the transaction and assemble its EVM context // Retrieve the transaction and assemble its EVM context
tx, blockHash, _, index := core.GetTransaction(api.eth.ChainDb(), hash) tx, blockHash, _, index := rawdb.ReadTransaction(api.eth.ChainDb(), hash)
if tx == nil { if tx == nil {
return nil, fmt.Errorf("transaction %x not found", hash) return nil, fmt.Errorf("transaction %x not found", hash)
} }
@ -640,7 +641,8 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
} }
statedb.DeleteSuicides() // Ensure any modifications are committed to the state
statedb.Finalise(true)
} }
return nil, vm.Context{}, nil, fmt.Errorf("tx index %d out of range for block %x", txIndex, blockHash) return nil, vm.Context{}, nil, fmt.Errorf("tx index %d out of range for block %x", txIndex, blockHash)
} }

View file

@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
@ -64,7 +65,6 @@ type Ethereum struct {
// Channel for shutting down the service // Channel for shutting down the service
shutdownChan chan bool // Channel for shutting down the Ethereum shutdownChan chan bool // Channel for shutting down the Ethereum
stopDbUpgrade func() error // stop chain db sequential key upgrade
// Handlers // Handlers
txPool *core.TxPool txPool *core.TxPool
@ -112,7 +112,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
stopDbUpgrade := upgradeDeduplicateData(chainDb)
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
return nil, genesisErr return nil, genesisErr
@ -127,7 +126,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
accountManager: ctx.AccountManager, accountManager: ctx.AccountManager,
engine: CreateConsensusEngine(ctx, &config.Ethash, chainConfig, chainDb), engine: CreateConsensusEngine(ctx, &config.Ethash, chainConfig, chainDb),
shutdownChan: make(chan bool), shutdownChan: make(chan bool),
stopDbUpgrade: stopDbUpgrade,
networkId: config.NetworkId, networkId: config.NetworkId,
gasPrice: config.GasPrice, gasPrice: config.GasPrice,
etherbase: config.Etherbase, etherbase: config.Etherbase,
@ -138,11 +136,11 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId) log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId)
if !config.SkipBcVersionCheck { if !config.SkipBcVersionCheck {
bcVersion := core.GetBlockChainVersion(chainDb) bcVersion := rawdb.ReadDatabaseVersion(chainDb)
if bcVersion != core.BlockChainVersion && bcVersion != 0 { if bcVersion != core.BlockChainVersion && bcVersion != 0 {
return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, core.BlockChainVersion) return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, core.BlockChainVersion)
} }
core.WriteBlockChainVersion(chainDb, core.BlockChainVersion) rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion)
} }
var ( var (
vmConfig = vm.Config{EnablePreimageRecording: config.EnablePreimageRecording} vmConfig = vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
@ -156,7 +154,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if compat, ok := genesisErr.(*params.ConfigCompatError); ok { if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
log.Warn("Rewinding chain to upgrade configuration", "err", compat) log.Warn("Rewinding chain to upgrade configuration", "err", compat)
eth.blockchain.SetHead(compat.RewindTo) eth.blockchain.SetHead(compat.RewindTo)
core.WriteChainConfig(chainDb, genesisHash, chainConfig) rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig)
} }
eth.bloomIndexer.Start(eth.blockchain) eth.bloomIndexer.Start(eth.blockchain)
@ -325,13 +323,13 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) {
return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") return common.Address{}, fmt.Errorf("etherbase must be explicitly specified")
} }
// set in js console via admin interface or wrapper from cli flags // SetEtherbase sets the mining reward address.
func (self *Ethereum) SetEtherbase(etherbase common.Address) { func (s *Ethereum) SetEtherbase(etherbase common.Address) {
self.lock.Lock() s.lock.Lock()
self.etherbase = etherbase s.etherbase = etherbase
self.lock.Unlock() s.lock.Unlock()
self.miner.SetEtherbase(etherbase) s.miner.SetEtherbase(etherbase)
} }
func (s *Ethereum) StartMining(local bool) error { func (s *Ethereum) StartMining(local bool) error {
@ -411,9 +409,6 @@ func (s *Ethereum) Start(srvr *p2p.Server) error {
// Stop implements node.Service, terminating all internal goroutines used by the // Stop implements node.Service, terminating all internal goroutines used by the
// Ethereum protocol. // Ethereum protocol.
func (s *Ethereum) Stop() error { func (s *Ethereum) Stop() error {
if s.stopDbUpgrade != nil {
s.stopDbUpgrade()
}
s.bloomIndexer.Close() s.bloomIndexer.Close()
s.blockchain.Stop() s.blockchain.Stop()
s.protocolManager.Stop() s.protocolManager.Stop()

View file

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common/bitutil" "github.com/ethereum/go-ethereum/common/bitutil"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -60,8 +61,8 @@ func (eth *Ethereum) startBloomHandlers() {
task := <-request task := <-request
task.Bitsets = make([][]byte, len(task.Sections)) task.Bitsets = make([][]byte, len(task.Sections))
for i, section := range task.Sections { for i, section := range task.Sections {
head := core.GetCanonicalHash(eth.chainDb, (section+1)*params.BloomBitsBlocks-1) head := rawdb.ReadCanonicalHash(eth.chainDb, (section+1)*params.BloomBitsBlocks-1)
if compVector, err := core.GetBloomBits(eth.chainDb, task.Bit, section, head); err == nil { if compVector, err := rawdb.ReadBloomBits(eth.chainDb, task.Bit, section, head); err == nil {
if blob, err := bitutil.DecompressBytes(compVector, int(params.BloomBitsBlocks)/8); err == nil { if blob, err := bitutil.DecompressBytes(compVector, int(params.BloomBitsBlocks)/8); err == nil {
task.Bitsets[i] = blob task.Bitsets[i] = blob
} else { } else {
@ -107,7 +108,7 @@ func NewBloomIndexer(db ethdb.Database, size uint64) *core.ChainIndexer {
db: db, db: db,
size: size, size: size,
} }
table := ethdb.NewTable(db, string(core.BloomBitsIndexPrefix)) table := ethdb.NewTable(db, string(rawdb.BloomBitsIndexPrefix))
return core.NewChainIndexer(db, table, backend, size, bloomConfirms, bloomThrottling, "bloombits") return core.NewChainIndexer(db, table, backend, size, bloomConfirms, bloomThrottling, "bloombits")
} }
@ -137,7 +138,7 @@ func (b *BloomIndexer) Commit() error {
if err != nil { if err != nil {
return err return err
} }
core.WriteBloomBits(batch, uint(i), b.section, b.head, bitutil.CompressBytes(bits)) rawdb.WriteBloomBits(batch, uint(i), b.section, b.head, bitutil.CompressBytes(bits))
} }
return batch.Write() return batch.Write()
} }

View file

@ -1,135 +0,0 @@
// 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 eth implements the Ethereum protocol.
package eth
import (
"bytes"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
var deduplicateData = []byte("dbUpgrade_20170714deduplicateData")
// upgradeDeduplicateData checks the chain database version and
// starts a background process to make upgrades if necessary.
// Returns a stop function that blocks until the process has
// been safely stopped.
func upgradeDeduplicateData(db ethdb.Database) func() error {
// If the database is already converted or empty, bail out
data, _ := db.Get(deduplicateData)
if len(data) > 0 && data[0] == 42 {
return nil
}
if data, _ := db.Get([]byte("LastHeader")); len(data) == 0 {
db.Put(deduplicateData, []byte{42})
return nil
}
// Start the deduplication upgrade on a new goroutine
log.Warn("Upgrading database to use lookup entries")
stop := make(chan chan error)
go func() {
// Create an iterator to read the entire database and covert old lookup entires
it := db.(*ethdb.LDBDatabase).NewIterator()
defer func() {
if it != nil {
it.Release()
}
}()
var (
converted uint64
failed error
)
for failed == nil && it.Next() {
// Skip any entries that don't look like old transaction meta entries (<hash>0x01)
key := it.Key()
if len(key) != common.HashLength+1 || key[common.HashLength] != 0x01 {
continue
}
// Skip any entries that don't contain metadata (name clash between <hash>0x01 and <some-prefix><hash>)
var meta struct {
BlockHash common.Hash
BlockIndex uint64
Index uint64
}
if err := rlp.DecodeBytes(it.Value(), &meta); err != nil {
continue
}
// Skip any already upgraded entries (clash due to <hash> ending with 0x01 (old suffix))
hash := key[:common.HashLength]
if hash[0] == byte('l') {
// Potential clash, the "old" `hash` must point to a live transaction.
if tx, _, _, _ := core.GetTransaction(db, common.BytesToHash(hash)); tx == nil || !bytes.Equal(tx.Hash().Bytes(), hash) {
continue
}
}
// Convert the old metadata to a new lookup entry, delete duplicate data
if failed = db.Put(append([]byte("l"), hash...), it.Value()); failed == nil { // Write the new lookup entry
if failed = db.Delete(hash); failed == nil { // Delete the duplicate transaction data
if failed = db.Delete(append([]byte("receipts-"), hash...)); failed == nil { // Delete the duplicate receipt data
if failed = db.Delete(key); failed != nil { // Delete the old transaction metadata
break
}
}
}
}
// Bump the conversion counter, and recreate the iterator occasionally to
// avoid too high memory consumption.
converted++
if converted%100000 == 0 {
it.Release()
it = db.(*ethdb.LDBDatabase).NewIterator()
it.Seek(key)
log.Info("Deduplicating database entries", "deduped", converted)
}
// Check for termination, or continue after a bit of a timeout
select {
case errc := <-stop:
errc <- nil
return
case <-time.After(time.Microsecond * 100):
}
}
// Upgrade finished, mark a such and terminate
if failed == nil {
log.Info("Database deduplication successful", "deduped", converted)
db.Put(deduplicateData, []byte{42})
} else {
log.Error("Database deduplication failed", "deduped", converted, "err", failed)
}
it.Release()
it = nil
errc := <-stop
errc <- failed
}()
// Assembly the cancellation callback
return func() error {
errc := make(chan error)
stop <- errc
return <-errc
}
}

View file

@ -27,7 +27,7 @@ import (
ethereum "github.com/ethereum/go-ethereum" ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
@ -224,7 +224,7 @@ func New(mode SyncMode, stateDb ethdb.Database, mux *event.TypeMux, chain BlockC
stateCh: make(chan dataPack), stateCh: make(chan dataPack),
stateSyncStart: make(chan *stateSync), stateSyncStart: make(chan *stateSync),
syncStatsState: stateSyncStats{ syncStatsState: stateSyncStats{
processed: core.GetTrieSyncProgress(stateDb), processed: rawdb.ReadFastTrieProgress(stateDb),
}, },
trackStateReq: make(chan *stateReq), trackStateReq: make(chan *stateReq),
} }

View file

@ -21,6 +21,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
) )
@ -126,7 +127,7 @@ func (p *FakePeer) RequestBodies(hashes []common.Hash) error {
uncles [][]*types.Header uncles [][]*types.Header
) )
for _, hash := range hashes { for _, hash := range hashes {
block := core.GetBlock(p.db, hash, p.hc.GetBlockNumber(hash)) block := rawdb.ReadBlock(p.db, hash, *p.hc.GetBlockNumber(hash))
txs = append(txs, block.Transactions()) txs = append(txs, block.Transactions())
uncles = append(uncles, block.Uncles()) uncles = append(uncles, block.Uncles())
@ -140,7 +141,7 @@ func (p *FakePeer) RequestBodies(hashes []common.Hash) error {
func (p *FakePeer) RequestReceipts(hashes []common.Hash) error { func (p *FakePeer) RequestReceipts(hashes []common.Hash) error {
var receipts [][]*types.Receipt var receipts [][]*types.Receipt
for _, hash := range hashes { for _, hash := range hashes {
receipts = append(receipts, core.GetBlockReceipts(p.db, hash, p.hc.GetBlockNumber(hash))) receipts = append(receipts, rawdb.ReadReceipts(p.db, hash, *p.hc.GetBlockNumber(hash)))
} }
p.dl.DeliverReceipts(p.id, receipts) p.dl.DeliverReceipts(p.id, receipts)
return nil return nil

View file

@ -23,7 +23,7 @@ import (
"time" "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/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -476,6 +476,6 @@ func (s *stateSync) updateStats(written, duplicate, unexpected int, duration tim
log.Info("Imported new state entries", "count", written, "elapsed", common.PrettyDuration(duration), "processed", s.d.syncStatsState.processed, "pending", s.d.syncStatsState.pending, "retry", len(s.tasks), "duplicate", s.d.syncStatsState.duplicate, "unexpected", s.d.syncStatsState.unexpected) log.Info("Imported new state entries", "count", written, "elapsed", common.PrettyDuration(duration), "processed", s.d.syncStatsState.processed, "pending", s.d.syncStatsState.pending, "retry", len(s.tasks), "duplicate", s.d.syncStatsState.duplicate, "unexpected", s.d.syncStatsState.unexpected)
} }
if written > 0 { if written > 0 {
core.WriteTrieSyncProgress(s.d.stateDB, s.d.syncStatsState.processed) rawdb.WriteFastTrieProgress(s.d.stateDB, s.d.syncStatsState.processed)
} }
} }

View file

@ -25,8 +25,8 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/bitutil" "github.com/ethereum/go-ethereum/common/bitutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
@ -71,20 +71,20 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
if err != nil { if err != nil {
b.Fatalf("error opening database at %v: %v", benchDataDir, err) b.Fatalf("error opening database at %v: %v", benchDataDir, err)
} }
head := core.GetHeadBlockHash(db) head := rawdb.ReadHeadBlockHash(db)
if head == (common.Hash{}) { if head == (common.Hash{}) {
b.Fatalf("chain data not found at %v", benchDataDir) b.Fatalf("chain data not found at %v", benchDataDir)
} }
clearBloomBits(db) clearBloomBits(db)
fmt.Println("Generating bloombits data...") fmt.Println("Generating bloombits data...")
headNum := core.GetBlockNumber(db, head) headNum := rawdb.ReadHeaderNumber(db, head)
if headNum < sectionSize+512 { if headNum == nil || *headNum < sectionSize+512 {
b.Fatalf("not enough blocks for running a benchmark") b.Fatalf("not enough blocks for running a benchmark")
} }
start := time.Now() start := time.Now()
cnt := (headNum - 512) / sectionSize cnt := (*headNum - 512) / sectionSize
var dataSize, compSize uint64 var dataSize, compSize uint64
for sectionIdx := uint64(0); sectionIdx < cnt; sectionIdx++ { for sectionIdx := uint64(0); sectionIdx < cnt; sectionIdx++ {
bc, err := bloombits.NewGenerator(uint(sectionSize)) bc, err := bloombits.NewGenerator(uint(sectionSize))
@ -93,14 +93,14 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
} }
var header *types.Header var header *types.Header
for i := sectionIdx * sectionSize; i < (sectionIdx+1)*sectionSize; i++ { for i := sectionIdx * sectionSize; i < (sectionIdx+1)*sectionSize; i++ {
hash := core.GetCanonicalHash(db, i) hash := rawdb.ReadCanonicalHash(db, i)
header = core.GetHeader(db, hash, i) header = rawdb.ReadHeader(db, hash, i)
if header == nil { if header == nil {
b.Fatalf("Error creating bloomBits data") b.Fatalf("Error creating bloomBits data")
} }
bc.AddBloom(uint(i-sectionIdx*sectionSize), header.Bloom) bc.AddBloom(uint(i-sectionIdx*sectionSize), header.Bloom)
} }
sectionHead := core.GetCanonicalHash(db, (sectionIdx+1)*sectionSize-1) sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*sectionSize-1)
for i := 0; i < types.BloomBitLength; i++ { for i := 0; i < types.BloomBitLength; i++ {
data, err := bc.Bitset(uint(i)) data, err := bc.Bitset(uint(i))
if err != nil { if err != nil {
@ -109,7 +109,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
comp := bitutil.CompressBytes(data) comp := bitutil.CompressBytes(data)
dataSize += uint64(len(data)) dataSize += uint64(len(data))
compSize += uint64(len(comp)) compSize += uint64(len(comp))
core.WriteBloomBits(db, uint(i), sectionIdx, sectionHead, comp) rawdb.WriteBloomBits(db, uint(i), sectionIdx, sectionHead, comp)
} }
//if sectionIdx%50 == 0 { //if sectionIdx%50 == 0 {
// fmt.Println(" section", sectionIdx, "/", cnt) // fmt.Println(" section", sectionIdx, "/", cnt)
@ -180,11 +180,11 @@ func BenchmarkNoBloomBits(b *testing.B) {
if err != nil { if err != nil {
b.Fatalf("error opening database at %v: %v", benchDataDir, err) b.Fatalf("error opening database at %v: %v", benchDataDir, err)
} }
head := core.GetHeadBlockHash(db) head := rawdb.ReadHeadBlockHash(db)
if head == (common.Hash{}) { if head == (common.Hash{}) {
b.Fatalf("chain data not found at %v", benchDataDir) b.Fatalf("chain data not found at %v", benchDataDir)
} }
headNum := core.GetBlockNumber(db, head) headNum := rawdb.ReadHeaderNumber(db, head)
clearBloomBits(db) clearBloomBits(db)
@ -192,10 +192,10 @@ func BenchmarkNoBloomBits(b *testing.B) {
start := time.Now() start := time.Now()
mux := new(event.TypeMux) mux := new(event.TypeMux)
backend := &testBackend{mux, db, 0, new(event.Feed), new(event.Feed), new(event.Feed), new(event.Feed)} backend := &testBackend{mux, db, 0, new(event.Feed), new(event.Feed), new(event.Feed), new(event.Feed)}
filter := New(backend, 0, int64(headNum), []common.Address{{}}, nil) filter := New(backend, 0, int64(*headNum), []common.Address{{}}, nil)
filter.Logs(context.Background()) filter.Logs(context.Background())
d := time.Since(start) d := time.Since(start)
fmt.Println("Finished running filter benchmarks") fmt.Println("Finished running filter benchmarks")
fmt.Println(" ", d, "total ", d*time.Duration(1000000)/time.Duration(headNum+1), "per million blocks") fmt.Println(" ", d, "total ", d*time.Duration(1000000)/time.Duration(*headNum+1), "per million blocks")
db.Close() db.Close()
} }

View file

@ -28,6 +28,7 @@ import (
ethereum "github.com/ethereum/go-ethereum" ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
@ -348,11 +349,11 @@ func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func
for oldh.Hash() != newh.Hash() { for oldh.Hash() != newh.Hash() {
if oldh.Number.Uint64() >= newh.Number.Uint64() { if oldh.Number.Uint64() >= newh.Number.Uint64() {
oldHeaders = append(oldHeaders, oldh) oldHeaders = append(oldHeaders, oldh)
oldh = core.GetHeader(es.backend.ChainDb(), oldh.ParentHash, oldh.Number.Uint64()-1) oldh = rawdb.ReadHeader(es.backend.ChainDb(), oldh.ParentHash, oldh.Number.Uint64()-1)
} }
if oldh.Number.Uint64() < newh.Number.Uint64() { if oldh.Number.Uint64() < newh.Number.Uint64() {
newHeaders = append(newHeaders, newh) newHeaders = append(newHeaders, newh)
newh = core.GetHeader(es.backend.ChainDb(), newh.ParentHash, newh.Number.Uint64()-1) newh = rawdb.ReadHeader(es.backend.ChainDb(), newh.ParentHash, newh.Number.Uint64()-1)
if newh == nil { if newh == nil {
// happens when CHT syncing, nothing to do // happens when CHT syncing, nothing to do
newh = oldh newh = oldh

View file

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
@ -56,26 +57,37 @@ func (b *testBackend) EventMux() *event.TypeMux {
} }
func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
var hash common.Hash var (
var num uint64 hash common.Hash
num uint64
)
if blockNr == rpc.LatestBlockNumber { if blockNr == rpc.LatestBlockNumber {
hash = core.GetHeadBlockHash(b.db) hash = rawdb.ReadHeadBlockHash(b.db)
num = core.GetBlockNumber(b.db, hash) number := rawdb.ReadHeaderNumber(b.db, hash)
if number == nil {
return nil, nil
}
num = *number
} else { } else {
num = uint64(blockNr) num = uint64(blockNr)
hash = core.GetCanonicalHash(b.db, num) hash = rawdb.ReadCanonicalHash(b.db, num)
} }
return core.GetHeader(b.db, hash, num), nil return rawdb.ReadHeader(b.db, hash, num), nil
} }
func (b *testBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) { func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
number := core.GetBlockNumber(b.db, blockHash) if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil {
return core.GetBlockReceipts(b.db, blockHash, number), nil return rawdb.ReadReceipts(b.db, hash, *number), nil
}
return nil, nil
} }
func (b *testBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) { func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
number := core.GetBlockNumber(b.db, blockHash) number := rawdb.ReadHeaderNumber(b.db, hash)
receipts := core.GetBlockReceipts(b.db, blockHash, number) if number == nil {
return nil, nil
}
receipts := rawdb.ReadReceipts(b.db, hash, *number)
logs := make([][]*types.Log, len(receipts)) logs := make([][]*types.Log, len(receipts))
for i, receipt := range receipts { for i, receipt := range receipts {
@ -121,8 +133,8 @@ func (b *testBackend) ServiceFilter(ctx context.Context, session *bloombits.Matc
task.Bitsets = make([][]byte, len(task.Sections)) task.Bitsets = make([][]byte, len(task.Sections))
for i, section := range task.Sections { for i, section := range task.Sections {
if rand.Int()%4 != 0 { // Handle occasional missing deliveries if rand.Int()%4 != 0 { // Handle occasional missing deliveries
head := core.GetCanonicalHash(b.db, (section+1)*params.BloomBitsBlocks-1) head := rawdb.ReadCanonicalHash(b.db, (section+1)*params.BloomBitsBlocks-1)
task.Bitsets[i], _ = core.GetBloomBits(b.db, task.Bit, section, head) task.Bitsets[i], _ = rawdb.ReadBloomBits(b.db, task.Bit, section, head)
} }
} }
request <- task request <- task

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -84,16 +85,10 @@ func BenchmarkFilters(b *testing.B) {
} }
}) })
for i, block := range chain { for i, block := range chain {
core.WriteBlock(db, block) rawdb.WriteBlock(db, block)
if err := core.WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil { rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64())
b.Fatalf("failed to insert block number: %v", err) rawdb.WriteHeadBlockHash(db, block.Hash())
} rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
if err := core.WriteHeadBlockHash(db, block.Hash()); err != nil {
b.Fatalf("failed to insert block number: %v", err)
}
if err := core.WriteBlockReceipts(db, block.Hash(), block.NumberU64(), receipts[i]); err != nil {
b.Fatal("error writing block receipts:", err)
}
} }
b.ResetTimer() b.ResetTimer()
@ -174,16 +169,10 @@ func TestFilters(t *testing.T) {
} }
}) })
for i, block := range chain { for i, block := range chain {
core.WriteBlock(db, block) rawdb.WriteBlock(db, block)
if err := core.WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil { rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64())
t.Fatalf("failed to insert block number: %v", err) rawdb.WriteHeadBlockHash(db, block.Hash())
} rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
if err := core.WriteHeadBlockHash(db, block.Hash()); err != nil {
t.Fatalf("failed to insert block number: %v", err)
}
if err := core.WriteBlockReceipts(db, block.Hash(), block.NumberU64(), receipts[i]); err != nil {
t.Fatal("error writing block receipts:", err)
}
} }
filter := New(backend, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) filter := New(backend, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})

View file

@ -725,25 +725,25 @@ func (pm *ProtocolManager) BroadcastTx(hash common.Hash, tx *types.Transaction)
} }
// Mined broadcast loop // Mined broadcast loop
func (self *ProtocolManager) minedBroadcastLoop() { func (pm *ProtocolManager) minedBroadcastLoop() {
// automatically stops if unsubscribe // automatically stops if unsubscribe
for obj := range self.minedBlockSub.Chan() { for obj := range pm.minedBlockSub.Chan() {
switch ev := obj.Data.(type) { switch ev := obj.Data.(type) {
case core.NewMinedBlockEvent: case core.NewMinedBlockEvent:
self.BroadcastBlock(ev.Block, true) // First propagate block to peers pm.BroadcastBlock(ev.Block, true) // First propagate block to peers
self.BroadcastBlock(ev.Block, false) // Only then announce to the rest pm.BroadcastBlock(ev.Block, false) // Only then announce to the rest
} }
} }
} }
func (self *ProtocolManager) txBroadcastLoop() { func (pm *ProtocolManager) txBroadcastLoop() {
for { for {
select { select {
case event := <-self.txCh: case event := <-pm.txCh:
self.BroadcastTx(event.Tx.Hash(), event.Tx) pm.BroadcastTx(event.Tx.Hash(), event.Tx)
// Err() channel will be closed when unsubscribing. // Err() channel will be closed when unsubscribing.
case <-self.txSub.Err(): case <-pm.txSub.Err():
return return
} }
} }
@ -760,13 +760,13 @@ type NodeInfo struct {
} }
// NodeInfo retrieves some protocol metadata about the running host node. // NodeInfo retrieves some protocol metadata about the running host node.
func (self *ProtocolManager) NodeInfo() *NodeInfo { func (pm *ProtocolManager) NodeInfo() *NodeInfo {
currentBlock := self.blockchain.CurrentBlock() currentBlock := pm.blockchain.CurrentBlock()
return &NodeInfo{ return &NodeInfo{
Network: self.networkId, Network: pm.networkId,
Difficulty: self.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()), Difficulty: pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()),
Genesis: self.blockchain.Genesis().Hash(), Genesis: pm.blockchain.Genesis().Hash(),
Config: self.blockchain.Config(), Config: pm.blockchain.Config(),
Head: currentBlock.Hash(), Head: currentBlock.Hash(),
} }
} }

View file

@ -45,37 +45,37 @@ func New() *Filters {
} }
} }
func (self *Filters) Start() { func (f *Filters) Start() {
go self.loop() go f.loop()
} }
func (self *Filters) Stop() { func (f *Filters) Stop() {
close(self.quit) close(f.quit)
} }
func (self *Filters) Notify(filter Filter, data interface{}) { func (f *Filters) Notify(filter Filter, data interface{}) {
self.ch <- FilterEvent{filter, data} f.ch <- FilterEvent{filter, data}
} }
func (self *Filters) Install(watcher Filter) int { func (f *Filters) Install(watcher Filter) int {
self.watchers[self.id] = watcher f.watchers[f.id] = watcher
self.id++ f.id++
return self.id - 1 return f.id - 1
} }
func (self *Filters) Uninstall(id int) { func (f *Filters) Uninstall(id int) {
delete(self.watchers, id) delete(f.watchers, id)
} }
func (self *Filters) loop() { func (f *Filters) loop() {
out: out:
for { for {
select { select {
case <-self.quit: case <-f.quit:
break out break out
case event := <-self.ch: case event := <-f.ch:
for _, watcher := range self.watchers { for _, watcher := range f.watchers {
if reflect.TypeOf(watcher) == reflect.TypeOf(event.filter) { if reflect.TypeOf(watcher) == reflect.TypeOf(event.filter) {
if watcher.Compare(event.filter) { if watcher.Compare(event.filter) {
watcher.Trigger(event.data) watcher.Trigger(event.data)
@ -86,10 +86,10 @@ out:
} }
} }
func (self *Filters) Match(a, b Filter) bool { func (f *Filters) Match(a, b Filter) bool {
return reflect.TypeOf(a) == reflect.TypeOf(b) && a.Compare(b) return reflect.TypeOf(a) == reflect.TypeOf(b) && a.Compare(b)
} }
func (self *Filters) Get(i int) Filter { func (f *Filters) Get(i int) Filter {
return self.watchers[i] return f.watchers[i]
} }

View file

@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -1006,7 +1007,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr
// GetTransactionByHash returns the transaction for the given hash // GetTransactionByHash returns the transaction for the given hash
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction { func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction {
// Try to return an already finalized transaction // Try to return an already finalized transaction
if tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash); tx != nil { if tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash); tx != nil {
return newRPCTransaction(tx, blockHash, blockNumber, index) return newRPCTransaction(tx, blockHash, blockNumber, index)
} }
// No finalized transaction, try to retrieve it from the pool // No finalized transaction, try to retrieve it from the pool
@ -1022,7 +1023,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,
var tx *types.Transaction var tx *types.Transaction
// Retrieve a finalized transaction, or a pooled otherwise // Retrieve a finalized transaction, or a pooled otherwise
if tx, _, _, _ = core.GetTransaction(s.b.ChainDb(), hash); tx == nil { if tx, _, _, _ = rawdb.ReadTransaction(s.b.ChainDb(), hash); tx == nil {
if tx = s.b.GetPoolTransaction(hash); tx == nil { if tx = s.b.GetPoolTransaction(hash); tx == nil {
// Transaction not found anywhere, abort // Transaction not found anywhere, abort
return nil, nil return nil, nil
@ -1034,7 +1035,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,
// GetTransactionReceipt returns the transaction receipt for the given transaction hash. // GetTransactionReceipt returns the transaction receipt for the given transaction hash.
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash) tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash)
if tx == nil { if tx == nil {
return nil, nil return nil, nil
} }

View file

@ -102,8 +102,8 @@ func randomSource() *rand.Rand {
// call the functions of the otto vm directly to circumvent the queue. These // call the functions of the otto vm directly to circumvent the queue. These
// functions should be used if and only if running a routine that was already // functions should be used if and only if running a routine that was already
// called from JS through an RPC call. // called from JS through an RPC call.
func (self *JSRE) runEventLoop() { func (re *JSRE) runEventLoop() {
defer close(self.closed) defer close(re.closed)
vm := otto.New() vm := otto.New()
r := randomSource() r := randomSource()
@ -202,14 +202,14 @@ loop:
break loop break loop
} }
} }
case req := <-self.evalQueue: case req := <-re.evalQueue:
// run the code, send the result back // run the code, send the result back
req.fn(vm) req.fn(vm)
close(req.done) close(req.done)
if waitForCallbacks && (len(registry) == 0) { if waitForCallbacks && (len(registry) == 0) {
break loop break loop
} }
case waitForCallbacks = <-self.stopEventLoop: case waitForCallbacks = <-re.stopEventLoop:
if !waitForCallbacks || (len(registry) == 0) { if !waitForCallbacks || (len(registry) == 0) {
break loop break loop
} }
@ -223,31 +223,31 @@ loop:
} }
// Do executes the given function on the JS event loop. // Do executes the given function on the JS event loop.
func (self *JSRE) Do(fn func(*otto.Otto)) { func (re *JSRE) Do(fn func(*otto.Otto)) {
done := make(chan bool) done := make(chan bool)
req := &evalReq{fn, done} req := &evalReq{fn, done}
self.evalQueue <- req re.evalQueue <- req
<-done <-done
} }
// stops the event loop before exit, optionally waits for all timers to expire // stops the event loop before exit, optionally waits for all timers to expire
func (self *JSRE) Stop(waitForCallbacks bool) { func (re *JSRE) Stop(waitForCallbacks bool) {
select { select {
case <-self.closed: case <-re.closed:
case self.stopEventLoop <- waitForCallbacks: case re.stopEventLoop <- waitForCallbacks:
<-self.closed <-re.closed
} }
} }
// Exec(file) loads and runs the contents of a file // Exec(file) loads and runs the contents of a file
// if a relative path is given, the jsre's assetPath is used // if a relative path is given, the jsre's assetPath is used
func (self *JSRE) Exec(file string) error { func (re *JSRE) Exec(file string) error {
code, err := ioutil.ReadFile(common.AbsolutePath(self.assetPath, file)) code, err := ioutil.ReadFile(common.AbsolutePath(re.assetPath, file))
if err != nil { if err != nil {
return err return err
} }
var script *otto.Script var script *otto.Script
self.Do(func(vm *otto.Otto) { re.Do(func(vm *otto.Otto) {
script, err = vm.Compile(file, code) script, err = vm.Compile(file, code)
if err != nil { if err != nil {
return return
@ -259,36 +259,36 @@ func (self *JSRE) Exec(file string) error {
// Bind assigns value v to a variable in the JS environment // Bind assigns value v to a variable in the JS environment
// This method is deprecated, use Set. // This method is deprecated, use Set.
func (self *JSRE) Bind(name string, v interface{}) error { func (re *JSRE) Bind(name string, v interface{}) error {
return self.Set(name, v) return re.Set(name, v)
} }
// Run runs a piece of JS code. // Run runs a piece of JS code.
func (self *JSRE) Run(code string) (v otto.Value, err error) { func (re *JSRE) Run(code string) (v otto.Value, err error) {
self.Do(func(vm *otto.Otto) { v, err = vm.Run(code) }) re.Do(func(vm *otto.Otto) { v, err = vm.Run(code) })
return v, err return v, err
} }
// Get returns the value of a variable in the JS environment. // Get returns the value of a variable in the JS environment.
func (self *JSRE) Get(ns string) (v otto.Value, err error) { func (re *JSRE) Get(ns string) (v otto.Value, err error) {
self.Do(func(vm *otto.Otto) { v, err = vm.Get(ns) }) re.Do(func(vm *otto.Otto) { v, err = vm.Get(ns) })
return v, err return v, err
} }
// Set assigns value v to a variable in the JS environment. // Set assigns value v to a variable in the JS environment.
func (self *JSRE) Set(ns string, v interface{}) (err error) { func (re *JSRE) Set(ns string, v interface{}) (err error) {
self.Do(func(vm *otto.Otto) { err = vm.Set(ns, v) }) re.Do(func(vm *otto.Otto) { err = vm.Set(ns, v) })
return err return err
} }
// loadScript executes a JS script from inside the currently executing JS code. // loadScript executes a JS script from inside the currently executing JS code.
func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value { func (re *JSRE) loadScript(call otto.FunctionCall) otto.Value {
file, err := call.Argument(0).ToString() file, err := call.Argument(0).ToString()
if err != nil { if err != nil {
// TODO: throw exception // TODO: throw exception
return otto.FalseValue() return otto.FalseValue()
} }
file = common.AbsolutePath(self.assetPath, file) file = common.AbsolutePath(re.assetPath, file)
source, err := ioutil.ReadFile(file) source, err := ioutil.ReadFile(file)
if err != nil { if err != nil {
// TODO: throw exception // TODO: throw exception
@ -305,10 +305,10 @@ func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value {
// Evaluate executes code and pretty prints the result to the specified output // Evaluate executes code and pretty prints the result to the specified output
// stream. // stream.
func (self *JSRE) Evaluate(code string, w io.Writer) error { func (re *JSRE) Evaluate(code string, w io.Writer) error {
var fail error var fail error
self.Do(func(vm *otto.Otto) { re.Do(func(vm *otto.Otto) {
val, err := vm.Run(code) val, err := vm.Run(code)
if err != nil { if err != nil {
prettyError(vm, err, w) prettyError(vm, err, w)
@ -321,8 +321,8 @@ func (self *JSRE) Evaluate(code string, w io.Writer) error {
} }
// Compile compiles and then runs a piece of JS code. // Compile compiles and then runs a piece of JS code.
func (self *JSRE) Compile(filename string, src interface{}) (err error) { func (re *JSRE) Compile(filename string, src interface{}) (err error) {
self.Do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) }) re.Do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) })
return err return err
} }

View file

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -83,16 +84,22 @@ func (b *LesApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*t
return b.eth.blockchain.GetBlockByHash(ctx, blockHash) return b.eth.blockchain.GetBlockByHash(ctx, blockHash)
} }
func (b *LesApiBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) { func (b *LesApiBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
return light.GetBlockReceipts(ctx, b.eth.odr, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)) if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil {
return light.GetBlockReceipts(ctx, b.eth.odr, hash, *number)
}
return nil, nil
} }
func (b *LesApiBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) { func (b *LesApiBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
return light.GetBlockLogs(ctx, b.eth.odr, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)) if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil {
return light.GetBlockLogs(ctx, b.eth.odr, hash, *number)
}
return nil, nil
} }
func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int { func (b *LesApiBackend) GetTd(hash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(blockHash) return b.eth.blockchain.GetTdByHash(hash)
} }
func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) { func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {

View file

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
@ -122,7 +123,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
if compat, ok := genesisErr.(*params.ConfigCompatError); ok { if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
log.Warn("Rewinding chain to upgrade configuration", "err", compat) log.Warn("Rewinding chain to upgrade configuration", "err", compat)
leth.blockchain.SetHead(compat.RewindTo) leth.blockchain.SetHead(compat.RewindTo)
core.WriteChainConfig(chainDb, genesisHash, chainConfig) rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig)
} }
leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay)

View file

@ -97,9 +97,8 @@ func (p *testDistPeer) waitBefore(cost uint64) (time.Duration, float64) {
p.lock.RUnlock() p.lock.RUnlock()
if sumCost < testDistBufLimit { if sumCost < testDistBufLimit {
return 0, float64(testDistBufLimit-sumCost) / float64(testDistBufLimit) return 0, float64(testDistBufLimit-sumCost) / float64(testDistBufLimit)
} else {
return time.Duration(sumCost - testDistBufLimit), 0
} }
return time.Duration(sumCost - testDistBufLimit), 0
} }
func (p *testDistPeer) canQueue() bool { func (p *testDistPeer) canQueue() bool {

View file

@ -25,7 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -280,7 +280,7 @@ func (f *lightFetcher) announce(p *peer, head *announceData) {
// if one of root's children is canonical, keep it, delete other branches and root itself // if one of root's children is canonical, keep it, delete other branches and root itself
var newRoot *fetcherTreeNode var newRoot *fetcherTreeNode
for i, nn := range fp.root.children { for i, nn := range fp.root.children {
if core.GetCanonicalHash(f.pm.chainDb, nn.number) == nn.hash { if rawdb.ReadCanonicalHash(f.pm.chainDb, nn.number) == nn.hash {
fp.root.children = append(fp.root.children[:i], fp.root.children[i+1:]...) fp.root.children = append(fp.root.children[:i], fp.root.children[i+1:]...)
nn.parent = nil nn.parent = nil
newRoot = nn newRoot = nn
@ -363,7 +363,7 @@ func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64) bo
// //
// when syncing, just check if it is part of the known chain, there is nothing better we // when syncing, just check if it is part of the known chain, there is nothing better we
// can do since we do not know the most recent block hash yet // can do since we do not know the most recent block hash yet
return core.GetCanonicalHash(f.pm.chainDb, fp.root.number) == fp.root.hash && core.GetCanonicalHash(f.pm.chainDb, number) == hash return rawdb.ReadCanonicalHash(f.pm.chainDb, fp.root.number) == fp.root.hash && rawdb.ReadCanonicalHash(f.pm.chainDb, number) == hash
} }
// requestAmount calculates the amount of headers to be downloaded starting // requestAmount calculates the amount of headers to be downloaded starting

View file

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
@ -528,11 +529,13 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
break break
} }
// Retrieve the requested block body, stopping if enough was found // Retrieve the requested block body, stopping if enough was found
if data := core.GetBodyRLP(pm.chainDb, hash, core.GetBlockNumber(pm.chainDb, hash)); len(data) != 0 { if number := rawdb.ReadHeaderNumber(pm.chainDb, hash); number != nil {
if data := rawdb.ReadBodyRLP(pm.chainDb, hash, *number); len(data) != 0 {
bodies = append(bodies, data) bodies = append(bodies, data)
bytes += len(data) bytes += len(data)
} }
} }
}
bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost)
pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost)
return p.SendBlockBodiesRLP(req.ReqID, bv, bodies) return p.SendBlockBodiesRLP(req.ReqID, bv, bodies)
@ -579,7 +582,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
} }
for _, req := range req.Reqs { for _, req := range req.Reqs {
// Retrieve the requested state entry, stopping if enough was found // Retrieve the requested state entry, stopping if enough was found
if header := core.GetHeader(pm.chainDb, req.BHash, core.GetBlockNumber(pm.chainDb, req.BHash)); header != nil { if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
statedb, err := pm.blockchain.State() statedb, err := pm.blockchain.State()
if err != nil { if err != nil {
continue continue
@ -596,6 +600,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
} }
} }
} }
}
bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost)
pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost)
return p.SendCode(req.ReqID, bv, data) return p.SendCode(req.ReqID, bv, data)
@ -645,7 +650,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
break break
} }
// Retrieve the requested block's receipts, skipping if unknown to us // Retrieve the requested block's receipts, skipping if unknown to us
results := core.GetBlockReceipts(pm.chainDb, hash, core.GetBlockNumber(pm.chainDb, hash)) var results types.Receipts
if number := rawdb.ReadHeaderNumber(pm.chainDb, hash); number != nil {
results = rawdb.ReadReceipts(pm.chainDb, hash, *number)
}
if results == nil { if results == nil {
if header := pm.blockchain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { if header := pm.blockchain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash {
continue continue
@ -705,7 +713,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
} }
for _, req := range req.Reqs { for _, req := range req.Reqs {
// Retrieve the requested state entry, stopping if enough was found // Retrieve the requested state entry, stopping if enough was found
if header := core.GetHeader(pm.chainDb, req.BHash, core.GetBlockNumber(pm.chainDb, req.BHash)); header != nil { if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
statedb, err := pm.blockchain.State() statedb, err := pm.blockchain.State()
if err != nil { if err != nil {
continue continue
@ -731,6 +740,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
} }
} }
} }
}
bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost)
pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost)
return p.SendProofs(req.ReqID, bv, proofs) return p.SendProofs(req.ReqID, bv, proofs)
@ -763,11 +773,13 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if statedb == nil || req.BHash != lastBHash { if statedb == nil || req.BHash != lastBHash {
statedb, root, lastBHash = nil, common.Hash{}, req.BHash statedb, root, lastBHash = nil, common.Hash{}, req.BHash
if header := core.GetHeader(pm.chainDb, req.BHash, core.GetBlockNumber(pm.chainDb, req.BHash)); header != nil { if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
statedb, _ = pm.blockchain.State() statedb, _ = pm.blockchain.State()
root = header.Root root = header.Root
} }
} }
}
if statedb == nil { if statedb == nil {
continue continue
} }
@ -859,7 +871,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
trieDb := trie.NewDatabase(ethdb.NewTable(pm.chainDb, light.ChtTablePrefix)) trieDb := trie.NewDatabase(ethdb.NewTable(pm.chainDb, light.ChtTablePrefix))
for _, req := range req.Reqs { for _, req := range req.Reqs {
if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil { if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil {
sectionHead := core.GetCanonicalHash(pm.chainDb, req.ChtNum*light.CHTFrequencyServer-1) sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, req.ChtNum*light.CHTFrequencyServer-1)
if root := light.GetChtRoot(pm.chainDb, req.ChtNum-1, sectionHead); root != (common.Hash{}) { if root := light.GetChtRoot(pm.chainDb, req.ChtNum-1, sectionHead); root != (common.Hash{}) {
trie, err := trie.New(root, trieDb) trie, err := trie.New(root, trieDb)
if err != nil { if err != nil {
@ -1114,10 +1126,10 @@ func (pm *ProtocolManager) getAccount(statedb *state.StateDB, root, hash common.
func (pm *ProtocolManager) getHelperTrie(id uint, idx uint64) (common.Hash, string) { func (pm *ProtocolManager) getHelperTrie(id uint, idx uint64) (common.Hash, string) {
switch id { switch id {
case htCanonical: case htCanonical:
sectionHead := core.GetCanonicalHash(pm.chainDb, (idx+1)*light.CHTFrequencyClient-1) sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, (idx+1)*light.CHTFrequencyClient-1)
return light.GetChtV2Root(pm.chainDb, idx, sectionHead), light.ChtTablePrefix return light.GetChtV2Root(pm.chainDb, idx, sectionHead), light.ChtTablePrefix
case htBloomBits: case htBloomBits:
sectionHead := core.GetCanonicalHash(pm.chainDb, (idx+1)*light.BloomTrieFrequency-1) sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, (idx+1)*light.BloomTrieFrequency-1)
return light.GetBloomTrieRoot(pm.chainDb, idx, sectionHead), light.BloomTrieTablePrefix return light.GetBloomTrieRoot(pm.chainDb, idx, sectionHead), light.BloomTrieTablePrefix
} }
return common.Hash{}, "" return common.Hash{}, ""
@ -1128,8 +1140,8 @@ func (pm *ProtocolManager) getHelperTrieAuxData(req HelperTrieReq) []byte {
switch { switch {
case req.Type == htCanonical && req.AuxReq == auxHeader && len(req.Key) == 8: case req.Type == htCanonical && req.AuxReq == auxHeader && len(req.Key) == 8:
blockNum := binary.BigEndian.Uint64(req.Key) blockNum := binary.BigEndian.Uint64(req.Key)
hash := core.GetCanonicalHash(pm.chainDb, blockNum) hash := rawdb.ReadCanonicalHash(pm.chainDb, blockNum)
return core.GetHeaderRLP(pm.chainDb, hash, blockNum) return rawdb.ReadHeaderRLP(pm.chainDb, hash, blockNum)
} }
return nil return nil
} }
@ -1142,9 +1154,9 @@ func (pm *ProtocolManager) txStatus(hashes []common.Hash) []txStatus {
// If the transaction is unknown to the pool, try looking it up locally // If the transaction is unknown to the pool, try looking it up locally
if stat == core.TxStatusUnknown { if stat == core.TxStatusUnknown {
if block, number, index := core.GetTxLookupEntry(pm.chainDb, hashes[i]); block != (common.Hash{}) { if block, number, index := rawdb.ReadTxLookupEntry(pm.chainDb, hashes[i]); block != (common.Hash{}) {
stats[i].Status = core.TxStatusIncluded stats[i].Status = core.TxStatusIncluded
stats[i].Lookup = &core.TxLookupEntry{BlockHash: block, BlockIndex: number, Index: index} stats[i].Lookup = &rawdb.TxLookupEntry{BlockHash: block, BlockIndex: number, Index: index}
} }
} }
} }

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
@ -304,7 +305,7 @@ func testGetReceipt(t *testing.T, protocol int) {
block := bc.GetBlockByNumber(i) block := bc.GetBlockByNumber(i)
hashes = append(hashes, block.Hash()) hashes = append(hashes, block.Hash())
receipts = append(receipts, core.GetBlockReceipts(db, block.Hash(), block.NumberU64())) receipts = append(receipts, rawdb.ReadReceipts(db, block.Hash(), block.NumberU64()))
} }
// Send the hash request and verify the response // Send the hash request and verify the response
cost := peer.GetRequestCost(GetReceiptsMsg, len(hashes)) cost := peer.GetRequestCost(GetReceiptsMsg, len(hashes))
@ -555,9 +556,9 @@ func TestTransactionStatusLes2(t *testing.T) {
} }
// check if their status is included now // check if their status is included now
block1hash := core.GetCanonicalHash(db, 1) block1hash := rawdb.ReadCanonicalHash(db, 1)
test(tx1, false, txStatus{Status: core.TxStatusIncluded, Lookup: &core.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}}) test(tx1, false, txStatus{Status: core.TxStatusIncluded, Lookup: &rawdb.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}})
test(tx2, false, txStatus{Status: core.TxStatusIncluded, Lookup: &core.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}}) test(tx2, false, txStatus{Status: core.TxStatusIncluded, Lookup: &rawdb.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}})
// create a reorg that rolls them back // create a reorg that rolls them back
gchain, _ = core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), db, 2, func(i int, block *core.BlockGen) {}) gchain, _ = core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), db, 2, func(i int, block *core.BlockGen) {})

View file

@ -24,7 +24,7 @@ import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -110,7 +110,7 @@ func (r *BlockRequest) Validate(db ethdb.Database, msg *Msg) error {
body := bodies[0] body := bodies[0]
// Retrieve our stored header and validate block content against it // Retrieve our stored header and validate block content against it
header := core.GetHeader(db, r.Hash, r.Number) header := rawdb.ReadHeader(db, r.Hash, r.Number)
if header == nil { if header == nil {
return errHeaderUnavailable return errHeaderUnavailable
} }
@ -166,7 +166,7 @@ func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error {
receipt := receipts[0] receipt := receipts[0]
// Retrieve our stored header and validate receipt content against it // Retrieve our stored header and validate receipt content against it
header := core.GetHeader(db, r.Hash, r.Number) header := rawdb.ReadHeader(db, r.Hash, r.Number)
if header == nil { if header == nil {
return errHeaderUnavailable return errHeaderUnavailable
} }

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -63,9 +64,13 @@ func TestOdrGetReceiptsLes2(t *testing.T) { testOdr(t, 2, 1, odrGetReceipts) }
func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
var receipts types.Receipts var receipts types.Receipts
if bc != nil { if bc != nil {
receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash)) if number := rawdb.ReadHeaderNumber(db, bhash); number != nil {
receipts = rawdb.ReadReceipts(db, bhash, *number)
}
} else { } else {
receipts, _ = light.GetBlockReceipts(ctx, lc.Odr(), bhash, core.GetBlockNumber(db, bhash)) if number := rawdb.ReadHeaderNumber(db, bhash); number != nil {
receipts, _ = light.GetBlockReceipts(ctx, lc.Odr(), bhash, *number)
}
} }
if receipts == nil { if receipts == nil {
return nil return nil
@ -178,7 +183,7 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
test := func(expFail uint64) { test := func(expFail uint64) {
for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ { for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ {
bhash := core.GetCanonicalHash(db, i) bhash := rawdb.ReadCanonicalHash(db, i)
b1 := fn(light.NoOdr, db, pm.chainConfig, pm.blockchain.(*core.BlockChain), nil, bhash) b1 := fn(light.NoOdr, db, pm.chainConfig, pm.blockchain.(*core.BlockChain), nil, bhash)
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)

View file

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
@ -160,9 +161,8 @@ func (a *announceData) checkSignature(pubKey *ecdsa.PublicKey) error {
pbytes := elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y) pbytes := elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y)
if bytes.Equal(pbytes, recPubkey) { if bytes.Equal(pbytes, recPubkey) {
return nil return nil
} else {
return errors.New("Wrong signature")
} }
return errors.New("Wrong signature")
} }
type blockInfo struct { type blockInfo struct {
@ -224,6 +224,6 @@ type proofsData [][]rlp.RawValue
type txStatus struct { type txStatus struct {
Status core.TxStatus Status core.TxStatus
Lookup *core.TxLookupEntry `rlp:"nil"` Lookup *rawdb.TxLookupEntry `rlp:"nil"`
Error string Error string
} }

View file

@ -118,7 +118,7 @@ func (n *wrsNode) insert(item wrsItem, weight int64) int {
if n.level == 0 { if n.level == 0 {
n.items[branch] = item n.items[branch] = item
return branch return branch
} else { }
var subNode *wrsNode var subNode *wrsNode
if n.items[branch] == nil { if n.items[branch] == nil {
subNode = &wrsNode{maxItems: n.maxItems / wrsBranches, level: n.level - 1} subNode = &wrsNode{maxItems: n.maxItems / wrsBranches, level: n.level - 1}
@ -129,7 +129,6 @@ func (n *wrsNode) insert(item wrsItem, weight int64) int {
subIdx := subNode.insert(item, weight) subIdx := subNode.insert(item, weight)
return subNode.maxItems*branch + subIdx return subNode.maxItems*branch + subIdx
} }
}
// setWeight updates the weight of a certain item (which should exist) and returns // setWeight updates the weight of a certain item (which should exist) and returns
// the change of the last weight value stored in the tree // the change of the last weight value stored in the tree
@ -162,12 +161,10 @@ func (n *wrsNode) choose(val int64) (wrsItem, int64) {
if val < w { if val < w {
if n.level == 0 { if n.level == 0 {
return n.items[i].(wrsItem), n.weights[i] return n.items[i].(wrsItem), n.weights[i]
} else { }
return n.items[i].(*wrsNode).choose(val) return n.items[i].(*wrsNode).choose(val)
} }
} else {
val -= w val -= w
} }
}
panic(nil) panic(nil)
} }

View file

@ -22,7 +22,7 @@ import (
"time" "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/rawdb"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -58,15 +58,22 @@ func TestTrieEntryAccessLes1(t *testing.T) { testAccess(t, 1, tfTrieEntryAccess)
func TestTrieEntryAccessLes2(t *testing.T) { testAccess(t, 2, tfTrieEntryAccess) } func TestTrieEntryAccessLes2(t *testing.T) { testAccess(t, 2, tfTrieEntryAccess) }
func tfTrieEntryAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest { func tfTrieEntryAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest {
return &light.TrieRequest{Id: light.StateTrieID(core.GetHeader(db, bhash, core.GetBlockNumber(db, bhash))), Key: testBankSecureTrieKey} if number := rawdb.ReadHeaderNumber(db, bhash); number != nil {
return &light.TrieRequest{Id: light.StateTrieID(rawdb.ReadHeader(db, bhash, *number)), Key: testBankSecureTrieKey}
}
return nil
} }
func TestCodeAccessLes1(t *testing.T) { testAccess(t, 1, tfCodeAccess) } func TestCodeAccessLes1(t *testing.T) { testAccess(t, 1, tfCodeAccess) }
func TestCodeAccessLes2(t *testing.T) { testAccess(t, 2, tfCodeAccess) } func TestCodeAccessLes2(t *testing.T) { testAccess(t, 2, tfCodeAccess) }
func tfCodeAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest { func tfCodeAccess(db ethdb.Database, bhash common.Hash, num uint64) light.OdrRequest {
header := core.GetHeader(db, bhash, core.GetBlockNumber(db, bhash)) number := rawdb.ReadHeaderNumber(db, bhash)
if number != nil {
return nil
}
header := rawdb.ReadHeader(db, bhash, *number)
if header.Number.Uint64() < testContractDeployed { if header.Number.Uint64() < testContractDeployed {
return nil return nil
} }
@ -99,7 +106,7 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) {
test := func(expFail uint64) { test := func(expFail uint64) {
for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ { for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ {
bhash := core.GetCanonicalHash(db, i) bhash := rawdb.ReadCanonicalHash(db, i)
if req := fn(ldb, bhash, i); req != nil { if req := fn(ldb, bhash, i); req != nil {
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
defer cancel() defer cancel()

View file

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -329,11 +330,11 @@ func (pm *ProtocolManager) blockLoop() {
header := ev.Block.Header() header := ev.Block.Header()
hash := header.Hash() hash := header.Hash()
number := header.Number.Uint64() number := header.Number.Uint64()
td := core.GetTd(pm.chainDb, hash, number) td := rawdb.ReadTd(pm.chainDb, hash, number)
if td != nil && td.Cmp(lastBroadcastTd) > 0 { if td != nil && td.Cmp(lastBroadcastTd) > 0 {
var reorg uint64 var reorg uint64
if lastHead != nil { if lastHead != nil {
reorg = lastHead.Number.Uint64() - core.FindCommonAncestor(pm.chainDb, header, lastHead).Number.Uint64() reorg = lastHead.Number.Uint64() - rawdb.FindCommonAncestor(pm.chainDb, header, lastHead).Number.Uint64()
} }
lastHead = header lastHead = header
lastBroadcastTd = td lastBroadcastTd = td

View file

@ -601,9 +601,8 @@ func (e *discoveredEntry) Weight() int64 {
t := time.Duration(mclock.Now() - e.lastDiscovered) t := time.Duration(mclock.Now() - e.lastDiscovered)
if t <= discoverExpireStart { if t <= discoverExpireStart {
return 1000000000 return 1000000000
} else {
return int64(1000000000 * math.Exp(-float64(t-discoverExpireStart)/float64(discoverExpireConst)))
} }
return int64(1000000000 * math.Exp(-float64(t-discoverExpireStart)/float64(discoverExpireConst)))
} }
// knownEntry implements wrsItem // knownEntry implements wrsItem

View file

@ -20,7 +20,7 @@ import (
"context" "context"
"time" "time"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/light"
) )
@ -56,7 +56,7 @@ func (pm *ProtocolManager) syncer() {
func (pm *ProtocolManager) needToSync(peerHead blockInfo) bool { func (pm *ProtocolManager) needToSync(peerHead blockInfo) bool {
head := pm.blockchain.CurrentHeader() head := pm.blockchain.CurrentHeader()
currentTd := core.GetTd(pm.chainDb, head.Hash(), head.Number.Uint64()) currentTd := rawdb.ReadTd(pm.chainDb, head.Hash(), head.Number.Uint64())
return currentTd != nil && peerHead.Td.Cmp(currentTd) > 0 return currentTd != nil && peerHead.Td.Cmp(currentTd) > 0
} }

View file

@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -189,12 +190,9 @@ func (bc *LightChain) ResetWithGenesisBlock(genesis *types.Block) {
defer bc.mu.Unlock() defer bc.mu.Unlock()
// Prepare the genesis block and reinitialise the chain // Prepare the genesis block and reinitialise the chain
if err := core.WriteTd(bc.chainDb, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil { rawdb.WriteTd(bc.chainDb, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty())
log.Crit("Failed to write genesis block TD", "err", err) rawdb.WriteBlock(bc.chainDb, genesis)
}
if err := core.WriteBlock(bc.chainDb, genesis); err != nil {
log.Crit("Failed to write genesis block", "err", err)
}
bc.genesisBlock = genesis bc.genesisBlock = genesis
bc.hc.SetGenesis(bc.genesisBlock.Header()) bc.hc.SetGenesis(bc.genesisBlock.Header())
bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) bc.hc.SetCurrentHeader(bc.genesisBlock.Header())
@ -274,7 +272,11 @@ func (bc *LightChain) GetBlock(ctx context.Context, hash common.Hash, number uin
// GetBlockByHash retrieves a block from the database or ODR service by hash, // GetBlockByHash retrieves a block from the database or ODR service by hash,
// caching it if found. // caching it if found.
func (bc *LightChain) GetBlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { func (bc *LightChain) GetBlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
return bc.GetBlock(ctx, hash, bc.hc.GetBlockNumber(hash)) number := bc.hc.GetBlockNumber(hash)
if number == nil {
return nil, errors.New("unknown block")
}
return bc.GetBlock(ctx, hash, *number)
} }
// GetBlockByNumber retrieves a block from the database or ODR service by // GetBlockByNumber retrieves a block from the database or ODR service by

View file

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -122,8 +123,8 @@ func testHeaderChainImport(chain []*types.Header, lightchain *LightChain) error
} }
// Manually insert the header into the database, but don't reorganize (allows subsequent testing) // Manually insert the header into the database, but don't reorganize (allows subsequent testing)
lightchain.mu.Lock() lightchain.mu.Lock()
core.WriteTd(lightchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, lightchain.GetTdByHash(header.ParentHash))) rawdb.WriteTd(lightchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, lightchain.GetTdByHash(header.ParentHash)))
core.WriteHeader(lightchain.chainDb, header) rawdb.WriteHeader(lightchain.chainDb, header)
lightchain.mu.Unlock() lightchain.mu.Unlock()
} }
return nil return nil

View file

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
) )
@ -112,7 +113,7 @@ type BlockRequest struct {
// StoreResult stores the retrieved data in local database // StoreResult stores the retrieved data in local database
func (req *BlockRequest) StoreResult(db ethdb.Database) { func (req *BlockRequest) StoreResult(db ethdb.Database) {
core.WriteBodyRLP(db, req.Hash, req.Number, req.Rlp) rawdb.WriteBodyRLP(db, req.Hash, req.Number, req.Rlp)
} }
// ReceiptsRequest is the ODR request type for retrieving block bodies // ReceiptsRequest is the ODR request type for retrieving block bodies
@ -125,7 +126,7 @@ type ReceiptsRequest struct {
// StoreResult stores the retrieved data in local database // StoreResult stores the retrieved data in local database
func (req *ReceiptsRequest) StoreResult(db ethdb.Database) { func (req *ReceiptsRequest) StoreResult(db ethdb.Database) {
core.WriteBlockReceipts(db, req.Hash, req.Number, req.Receipts) rawdb.WriteReceipts(db, req.Hash, req.Number, req.Receipts)
} }
// ChtRequest is the ODR request type for state/storage trie entries // ChtRequest is the ODR request type for state/storage trie entries
@ -140,11 +141,11 @@ type ChtRequest struct {
// StoreResult stores the retrieved data in local database // StoreResult stores the retrieved data in local database
func (req *ChtRequest) StoreResult(db ethdb.Database) { func (req *ChtRequest) StoreResult(db ethdb.Database) {
// if there is a canonical hash, there is a header too
core.WriteHeader(db, req.Header)
hash, num := req.Header.Hash(), req.Header.Number.Uint64() hash, num := req.Header.Hash(), req.Header.Number.Uint64()
core.WriteTd(db, hash, num, req.Td)
core.WriteCanonicalHash(db, hash, num) rawdb.WriteHeader(db, req.Header)
rawdb.WriteTd(db, hash, num, req.Td)
rawdb.WriteCanonicalHash(db, hash, num)
} }
// BloomRequest is the ODR request type for retrieving bloom filters from a CHT structure // BloomRequest is the ODR request type for retrieving bloom filters from a CHT structure
@ -161,11 +162,11 @@ type BloomRequest struct {
// StoreResult stores the retrieved data in local database // StoreResult stores the retrieved data in local database
func (req *BloomRequest) StoreResult(db ethdb.Database) { func (req *BloomRequest) StoreResult(db ethdb.Database) {
for i, sectionIdx := range req.SectionIdxList { for i, sectionIdx := range req.SectionIdxList {
sectionHead := core.GetCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1) sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1)
// if we don't have the canonical hash stored for this section head number, we'll still store it under // if we don't have the canonical hash stored for this section head number, we'll still store it under
// a key with a zero sectionHead. GetBloomBits will look there too if we still don't have the canonical // a key with a zero sectionHead. GetBloomBits will look there too if we still don't have the canonical
// hash. In the unlikely case we've retrieved the section head hash since then, we'll just retrieve the // hash. In the unlikely case we've retrieved the section head hash since then, we'll just retrieve the
// bit vector again from the network. // bit vector again from the network.
core.WriteBloomBits(db, req.BitIdx, sectionIdx, sectionHead, req.BloomBits[i]) rawdb.WriteBloomBits(db, req.BitIdx, sectionIdx, sectionHead, req.BloomBits[i])
} }
} }

View file

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -70,9 +71,15 @@ func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error {
} }
switch req := req.(type) { switch req := req.(type) {
case *BlockRequest: case *BlockRequest:
req.Rlp = core.GetBodyRLP(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash)) number := rawdb.ReadHeaderNumber(odr.sdb, req.Hash)
if number != nil {
req.Rlp = rawdb.ReadBodyRLP(odr.sdb, req.Hash, *number)
}
case *ReceiptsRequest: case *ReceiptsRequest:
req.Receipts = core.GetBlockReceipts(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash)) number := rawdb.ReadHeaderNumber(odr.sdb, req.Hash)
if number != nil {
req.Receipts = rawdb.ReadReceipts(odr.sdb, req.Hash, *number)
}
case *TrieRequest: case *TrieRequest:
t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb)) t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb))
nodes := NewNodeSet() nodes := NewNodeSet()
@ -108,9 +115,15 @@ func TestOdrGetReceiptsLes1(t *testing.T) { testChainOdr(t, 1, odrGetReceipts) }
func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
var receipts types.Receipts var receipts types.Receipts
if bc != nil { if bc != nil {
receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash)) number := rawdb.ReadHeaderNumber(db, bhash)
if number != nil {
receipts = rawdb.ReadReceipts(db, bhash, *number)
}
} else { } else {
receipts, _ = GetBlockReceipts(ctx, lc.Odr(), bhash, core.GetBlockNumber(db, bhash)) number := rawdb.ReadHeaderNumber(db, bhash)
if number != nil {
receipts, _ = GetBlockReceipts(ctx, lc.Odr(), bhash, *number)
}
} }
if receipts == nil { if receipts == nil {
return nil, nil return nil, nil
@ -260,7 +273,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) {
test := func(expFail int) { test := func(expFail int) {
for i := uint64(0); i <= blockchain.CurrentHeader().Number.Uint64(); i++ { for i := uint64(0); i <= blockchain.CurrentHeader().Number.Uint64(); i++ {
bhash := core.GetCanonicalHash(sdb, i) bhash := rawdb.ReadCanonicalHash(sdb, i)
b1, err := fn(NoOdr, sdb, blockchain, nil, bhash) b1, err := fn(NoOdr, sdb, blockchain, nil, bhash)
if err != nil { if err != nil {
t.Fatalf("error in full-node test for block %d: %v", i, err) t.Fatalf("error in full-node test for block %d: %v", i, err)

View file

@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
@ -31,10 +32,10 @@ var sha3_nil = crypto.Keccak256Hash(nil)
func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) { func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) {
db := odr.Database() db := odr.Database()
hash := core.GetCanonicalHash(db, number) hash := rawdb.ReadCanonicalHash(db, number)
if (hash != common.Hash{}) { if (hash != common.Hash{}) {
// if there is a canonical hash, there is a header too // if there is a canonical hash, there is a header too
header := core.GetHeader(db, hash, number) header := rawdb.ReadHeader(db, hash, number)
if header == nil { if header == nil {
panic("Canonical hash present but header not found") panic("Canonical hash present but header not found")
} }
@ -47,14 +48,14 @@ func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*typ
) )
if odr.ChtIndexer() != nil { if odr.ChtIndexer() != nil {
chtCount, sectionHeadNum, sectionHead = odr.ChtIndexer().Sections() chtCount, sectionHeadNum, sectionHead = odr.ChtIndexer().Sections()
canonicalHash := core.GetCanonicalHash(db, sectionHeadNum) canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum)
// if the CHT was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too // if the CHT was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too
for chtCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { for chtCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) {
chtCount-- chtCount--
if chtCount > 0 { if chtCount > 0 {
sectionHeadNum = chtCount*CHTFrequencyClient - 1 sectionHeadNum = chtCount*CHTFrequencyClient - 1
sectionHead = odr.ChtIndexer().SectionHead(chtCount - 1) sectionHead = odr.ChtIndexer().SectionHead(chtCount - 1)
canonicalHash = core.GetCanonicalHash(db, sectionHeadNum) canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum)
} }
} }
} }
@ -69,7 +70,7 @@ func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*typ
} }
func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) { func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) {
hash := core.GetCanonicalHash(odr.Database(), number) hash := rawdb.ReadCanonicalHash(odr.Database(), number)
if (hash != common.Hash{}) { if (hash != common.Hash{}) {
return hash, nil return hash, nil
} }
@ -82,7 +83,7 @@ func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (commo
// GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) { func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) {
if data := core.GetBodyRLP(odr.Database(), hash, number); data != nil { if data := rawdb.ReadBodyRLP(odr.Database(), hash, number); data != nil {
return data, nil return data, nil
} }
r := &BlockRequest{Hash: hash, Number: number} r := &BlockRequest{Hash: hash, Number: number}
@ -111,7 +112,7 @@ func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint6
// back from the stored header and body. // back from the stored header and body.
func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) { func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) {
// Retrieve the block header and body contents // Retrieve the block header and body contents
header := core.GetHeader(odr.Database(), hash, number) header := rawdb.ReadHeader(odr.Database(), hash, number)
if header == nil { if header == nil {
return nil, ErrNoHeader return nil, ErrNoHeader
} }
@ -127,7 +128,7 @@ func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint
// in a block given by its hash. // in a block given by its hash.
func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) { func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) {
// Retrieve the potentially incomplete receipts from disk or network // Retrieve the potentially incomplete receipts from disk or network
receipts := core.GetBlockReceipts(odr.Database(), hash, number) receipts := rawdb.ReadReceipts(odr.Database(), hash, number)
if receipts == nil { if receipts == nil {
r := &ReceiptsRequest{Hash: hash, Number: number} r := &ReceiptsRequest{Hash: hash, Number: number}
if err := odr.Retrieve(ctx, r); err != nil { if err := odr.Retrieve(ctx, r); err != nil {
@ -141,13 +142,13 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num
if err != nil { if err != nil {
return nil, err return nil, err
} }
genesis := core.GetCanonicalHash(odr.Database(), 0) genesis := rawdb.ReadCanonicalHash(odr.Database(), 0)
config, _ := core.GetChainConfig(odr.Database(), genesis) config := rawdb.ReadChainConfig(odr.Database(), genesis)
if err := core.SetReceiptsData(config, block, receipts); err != nil { if err := core.SetReceiptsData(config, block, receipts); err != nil {
return nil, err return nil, err
} }
core.WriteBlockReceipts(odr.Database(), hash, number, receipts) rawdb.WriteReceipts(odr.Database(), hash, number, receipts)
} }
return receipts, nil return receipts, nil
} }
@ -156,7 +157,7 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num
// block given by its hash. // block given by its hash.
func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) { func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) {
// Retrieve the potentially incomplete receipts from disk or network // Retrieve the potentially incomplete receipts from disk or network
receipts := core.GetBlockReceipts(odr.Database(), hash, number) receipts := rawdb.ReadReceipts(odr.Database(), hash, number)
if receipts == nil { if receipts == nil {
r := &ReceiptsRequest{Hash: hash, Number: number} r := &ReceiptsRequest{Hash: hash, Number: number}
if err := odr.Retrieve(ctx, r); err != nil { if err := odr.Retrieve(ctx, r); err != nil {
@ -187,24 +188,24 @@ func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxLi
) )
if odr.BloomTrieIndexer() != nil { if odr.BloomTrieIndexer() != nil {
bloomTrieCount, sectionHeadNum, sectionHead = odr.BloomTrieIndexer().Sections() bloomTrieCount, sectionHeadNum, sectionHead = odr.BloomTrieIndexer().Sections()
canonicalHash := core.GetCanonicalHash(db, sectionHeadNum) canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum)
// if the BloomTrie was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too // if the BloomTrie was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too
for bloomTrieCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { for bloomTrieCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) {
bloomTrieCount-- bloomTrieCount--
if bloomTrieCount > 0 { if bloomTrieCount > 0 {
sectionHeadNum = bloomTrieCount*BloomTrieFrequency - 1 sectionHeadNum = bloomTrieCount*BloomTrieFrequency - 1
sectionHead = odr.BloomTrieIndexer().SectionHead(bloomTrieCount - 1) sectionHead = odr.BloomTrieIndexer().SectionHead(bloomTrieCount - 1)
canonicalHash = core.GetCanonicalHash(db, sectionHeadNum) canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum)
} }
} }
} }
for i, sectionIdx := range sectionIdxList { for i, sectionIdx := range sectionIdxList {
sectionHead := core.GetCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1) sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1)
// if we don't have the canonical hash stored for this section head number, we'll still look for // if we don't have the canonical hash stored for this section head number, we'll still look for
// an entry with a zero sectionHead (we store it with zero section head too if we don't know it // an entry with a zero sectionHead (we store it with zero section head too if we don't know it
// at the time of the retrieval) // at the time of the retrieval)
bloomBits, err := core.GetBloomBits(db, bitIdx, sectionIdx, sectionHead) bloomBits, err := rawdb.ReadBloomBits(db, bitIdx, sectionIdx, sectionHead)
if err == nil { if err == nil {
result[i] = bloomBits result[i] = bloomBits
} else { } else {

View file

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/bitutil" "github.com/ethereum/go-ethereum/common/bitutil"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -161,7 +162,7 @@ func (c *ChtIndexerBackend) Process(header *types.Header) {
hash, num := header.Hash(), header.Number.Uint64() hash, num := header.Hash(), header.Number.Uint64()
c.lastHash = hash c.lastHash = hash
td := core.GetTd(c.diskdb, hash, num) td := rawdb.ReadTd(c.diskdb, hash, num)
if td == nil { if td == nil {
panic(nil) panic(nil)
} }
@ -272,7 +273,7 @@ func (b *BloomTrieIndexerBackend) Commit() error {
binary.BigEndian.PutUint64(encKey[2:10], b.section) binary.BigEndian.PutUint64(encKey[2:10], b.section)
var decomp []byte var decomp []byte
for j := uint64(0); j < b.bloomTrieRatio; j++ { for j := uint64(0); j < b.bloomTrieRatio; j++ {
data, err := core.GetBloomBits(b.diskdb, i, b.section*b.bloomTrieRatio+j, b.sectionHeads[j]) data, err := rawdb.ReadBloomBits(b.diskdb, i, b.section*b.bloomTrieRatio+j, b.sectionHeads[j])
if err != nil { if err != nil {
return err return err
} }

View file

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -183,9 +184,8 @@ func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, number
if _, err := GetBlockReceipts(ctx, pool.odr, hash, number); err != nil { // ODR caches, ignore results if _, err := GetBlockReceipts(ctx, pool.odr, hash, number); err != nil { // ODR caches, ignore results
return err return err
} }
if err := core.WriteTxLookupEntries(pool.chainDb, block); err != nil { rawdb.WriteTxLookupEntries(pool.chainDb, block)
return err
}
// Update the transaction pool's state // Update the transaction pool's state
for _, tx := range list { for _, tx := range list {
delete(pool.pending, tx.Hash()) delete(pool.pending, tx.Hash())
@ -202,7 +202,7 @@ func (pool *TxPool) rollbackTxs(hash common.Hash, txc txStateChanges) {
if list, ok := pool.mined[hash]; ok { if list, ok := pool.mined[hash]; ok {
for _, tx := range list { for _, tx := range list {
txHash := tx.Hash() txHash := tx.Hash()
core.DeleteTxLookupEntry(pool.chainDb, txHash) rawdb.DeleteTxLookupEntry(pool.chainDb, txHash)
pool.pending[txHash] = tx pool.pending[txHash] = tx
txc.setState(txHash, false) txc.setState(txHash, false)
} }
@ -258,7 +258,7 @@ func (pool *TxPool) reorgOnNewHead(ctx context.Context, newHeader *types.Header)
idx2 := idx - txPermanent idx2 := idx - txPermanent
if len(pool.mined) > 0 { if len(pool.mined) > 0 {
for i := pool.clearIdx; i < idx2; i++ { for i := pool.clearIdx; i < idx2; i++ {
hash := core.GetCanonicalHash(pool.chainDb, i) hash := rawdb.ReadCanonicalHash(pool.chainDb, i)
if list, ok := pool.mined[hash]; ok { if list, ok := pool.mined[hash]; ok {
hashes := make([]common.Hash, len(list)) hashes := make([]common.Hash, len(list))
for i, tx := range list { for i, tx := range list {

View file

@ -234,9 +234,8 @@ func FailoverHandler(hs ...Handler) Handler {
err = h.Log(r) err = h.Log(r)
if err == nil { if err == nil {
return nil return nil
} else {
r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err)
} }
r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err)
} }
return err return err
@ -320,14 +319,13 @@ func evaluateLazy(lz Lazy) (interface{}, error) {
results := value.Call([]reflect.Value{}) results := value.Call([]reflect.Value{})
if len(results) == 1 { if len(results) == 1 {
return results[0].Interface(), nil return results[0].Interface(), nil
} else { }
values := make([]interface{}, len(results)) values := make([]interface{}, len(results))
for i, v := range results { for i, v := range results {
values[i] = v.Interface() values[i] = v.Interface()
} }
return values, nil return values, nil
} }
}
// DiscardHandler reports success for all writes but does nothing. // DiscardHandler reports success for all writes but does nothing.
// It is useful for dynamically disabling logging at runtime via // It is useful for dynamically disabling logging at runtime via

View file

@ -65,7 +65,7 @@ type Batch struct {
Source string `json:"source"` Source string `json:"source"`
} }
func (self *LibratoClient) PostMetrics(batch Batch) (err error) { func (c *LibratoClient) PostMetrics(batch Batch) (err error) {
var ( var (
js []byte js []byte
req *http.Request req *http.Request
@ -85,7 +85,7 @@ func (self *LibratoClient) PostMetrics(batch Batch) (err error) {
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(self.Email, self.Token) req.SetBasicAuth(c.Email, c.Token)
if resp, err = http.DefaultClient.Do(req); err != nil { if resp, err = http.DefaultClient.Do(req); err != nil {
return return

View file

@ -40,14 +40,14 @@ func Librato(r metrics.Registry, d time.Duration, e string, t string, s string,
NewReporter(r, d, e, t, s, p, u).Run() NewReporter(r, d, e, t, s, p, u).Run()
} }
func (self *Reporter) Run() { func (rep *Reporter) Run() {
log.Printf("WARNING: This client has been DEPRECATED! It has been moved to https://github.com/mihasya/go-metrics-librato and will be removed from rcrowley/go-metrics on August 5th 2015") log.Printf("WARNING: This client has been DEPRECATED! It has been moved to https://github.com/mihasya/go-metrics-librato and will be removed from rcrowley/go-metrics on August 5th 2015")
ticker := time.Tick(self.Interval) ticker := time.Tick(rep.Interval)
metricsApi := &LibratoClient{self.Email, self.Token} metricsApi := &LibratoClient{rep.Email, rep.Token}
for now := range ticker { for now := range ticker {
var metrics Batch var metrics Batch
var err error var err error
if metrics, err = self.BuildRequest(now, self.Registry); err != nil { if metrics, err = rep.BuildRequest(now, rep.Registry); err != nil {
log.Printf("ERROR constructing librato request body %s", err) log.Printf("ERROR constructing librato request body %s", err)
continue continue
} }
@ -79,21 +79,21 @@ func sumSquaresTimer(t metrics.Timer) float64 {
return sumSquares return sumSquares
} }
func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot Batch, err error) { func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot Batch, err error) {
snapshot = Batch{ snapshot = Batch{
// coerce timestamps to a stepping fn so that they line up in Librato graphs // coerce timestamps to a stepping fn so that they line up in Librato graphs
MeasureTime: (now.Unix() / self.intervalSec) * self.intervalSec, MeasureTime: (now.Unix() / rep.intervalSec) * rep.intervalSec,
Source: self.Source, Source: rep.Source,
} }
snapshot.Gauges = make([]Measurement, 0) snapshot.Gauges = make([]Measurement, 0)
snapshot.Counters = make([]Measurement, 0) snapshot.Counters = make([]Measurement, 0)
histogramGaugeCount := 1 + len(self.Percentiles) histogramGaugeCount := 1 + len(rep.Percentiles)
r.Each(func(name string, metric interface{}) { r.Each(func(name string, metric interface{}) {
if self.Namespace != "" { if rep.Namespace != "" {
name = fmt.Sprintf("%s.%s", self.Namespace, name) name = fmt.Sprintf("%s.%s", rep.Namespace, name)
} }
measurement := Measurement{} measurement := Measurement{}
measurement[Period] = self.Interval.Seconds() measurement[Period] = rep.Interval.Seconds()
switch m := metric.(type) { switch m := metric.(type) {
case metrics.Counter: case metrics.Counter:
if m.Count() > 0 { if m.Count() > 0 {
@ -125,7 +125,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
measurement[Sum] = float64(s.Sum()) measurement[Sum] = float64(s.Sum())
measurement[SumSquares] = sumSquares(s) measurement[SumSquares] = sumSquares(s)
gauges[0] = measurement gauges[0] = measurement
for i, p := range self.Percentiles { for i, p := range rep.Percentiles {
gauges[i+1] = Measurement{ gauges[i+1] = Measurement{
Name: fmt.Sprintf("%s.%.2f", measurement[Name], p), Name: fmt.Sprintf("%s.%.2f", measurement[Name], p),
Value: s.Percentile(p), Value: s.Percentile(p),
@ -142,7 +142,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
Measurement{ Measurement{
Name: fmt.Sprintf("%s.%s", name, "1min"), Name: fmt.Sprintf("%s.%s", name, "1min"),
Value: m.Rate1(), Value: m.Rate1(),
Period: int64(self.Interval.Seconds()), Period: int64(rep.Interval.Seconds()),
Attributes: map[string]interface{}{ Attributes: map[string]interface{}{
DisplayUnitsLong: Operations, DisplayUnitsLong: Operations,
DisplayUnitsShort: OperationsShort, DisplayUnitsShort: OperationsShort,
@ -152,7 +152,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
Measurement{ Measurement{
Name: fmt.Sprintf("%s.%s", name, "5min"), Name: fmt.Sprintf("%s.%s", name, "5min"),
Value: m.Rate5(), Value: m.Rate5(),
Period: int64(self.Interval.Seconds()), Period: int64(rep.Interval.Seconds()),
Attributes: map[string]interface{}{ Attributes: map[string]interface{}{
DisplayUnitsLong: Operations, DisplayUnitsLong: Operations,
DisplayUnitsShort: OperationsShort, DisplayUnitsShort: OperationsShort,
@ -162,7 +162,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
Measurement{ Measurement{
Name: fmt.Sprintf("%s.%s", name, "15min"), Name: fmt.Sprintf("%s.%s", name, "15min"),
Value: m.Rate15(), Value: m.Rate15(),
Period: int64(self.Interval.Seconds()), Period: int64(rep.Interval.Seconds()),
Attributes: map[string]interface{}{ Attributes: map[string]interface{}{
DisplayUnitsLong: Operations, DisplayUnitsLong: Operations,
DisplayUnitsShort: OperationsShort, DisplayUnitsShort: OperationsShort,
@ -184,15 +184,15 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
Max: float64(m.Max()), Max: float64(m.Max()),
Min: float64(m.Min()), Min: float64(m.Min()),
SumSquares: sumSquaresTimer(m), SumSquares: sumSquaresTimer(m),
Period: int64(self.Interval.Seconds()), Period: int64(rep.Interval.Seconds()),
Attributes: self.TimerAttributes, Attributes: rep.TimerAttributes,
} }
for i, p := range self.Percentiles { for i, p := range rep.Percentiles {
gauges[i+1] = Measurement{ gauges[i+1] = Measurement{
Name: fmt.Sprintf("%s.timer.%2.0f", name, p*100), Name: fmt.Sprintf("%s.timer.%2.0f", name, p*100),
Value: m.Percentile(p), Value: m.Percentile(p),
Period: int64(self.Interval.Seconds()), Period: int64(rep.Interval.Seconds()),
Attributes: self.TimerAttributes, Attributes: rep.TimerAttributes,
} }
} }
snapshot.Gauges = append(snapshot.Gauges, gauges...) snapshot.Gauges = append(snapshot.Gauges, gauges...)
@ -200,7 +200,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
Measurement{ Measurement{
Name: fmt.Sprintf("%s.%s", name, "rate.1min"), Name: fmt.Sprintf("%s.%s", name, "rate.1min"),
Value: m.Rate1(), Value: m.Rate1(),
Period: int64(self.Interval.Seconds()), Period: int64(rep.Interval.Seconds()),
Attributes: map[string]interface{}{ Attributes: map[string]interface{}{
DisplayUnitsLong: Operations, DisplayUnitsLong: Operations,
DisplayUnitsShort: OperationsShort, DisplayUnitsShort: OperationsShort,
@ -210,7 +210,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
Measurement{ Measurement{
Name: fmt.Sprintf("%s.%s", name, "rate.5min"), Name: fmt.Sprintf("%s.%s", name, "rate.5min"),
Value: m.Rate5(), Value: m.Rate5(),
Period: int64(self.Interval.Seconds()), Period: int64(rep.Interval.Seconds()),
Attributes: map[string]interface{}{ Attributes: map[string]interface{}{
DisplayUnitsLong: Operations, DisplayUnitsLong: Operations,
DisplayUnitsShort: OperationsShort, DisplayUnitsShort: OperationsShort,
@ -220,7 +220,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
Measurement{ Measurement{
Name: fmt.Sprintf("%s.%s", name, "rate.15min"), Name: fmt.Sprintf("%s.%s", name, "rate.15min"),
Value: m.Rate15(), Value: m.Rate15(),
Period: int64(self.Interval.Seconds()), Period: int64(rep.Interval.Seconds()),
Attributes: map[string]interface{}{ Attributes: map[string]interface{}{
DisplayUnitsLong: Operations, DisplayUnitsLong: Operations,
DisplayUnitsShort: OperationsShort, DisplayUnitsShort: OperationsShort,

View file

@ -329,6 +329,7 @@ func (r *Receipt) EncodeJSON() (string, error) {
return string(data), err return string(data), err
} }
func (r *Receipt) GetStatus() int { return int(r.receipt.Status) }
func (r *Receipt) GetPostState() []byte { return r.receipt.PostState } func (r *Receipt) GetPostState() []byte { return r.receipt.PostState }
func (r *Receipt) GetCumulativeGasUsed() int64 { return int64(r.receipt.CumulativeGasUsed) } func (r *Receipt) GetCumulativeGasUsed() int64 { return int64(r.receipt.CumulativeGasUsed) }
func (r *Receipt) GetBloom() *Bloom { return &Bloom{r.receipt.Bloom} } func (r *Receipt) GetBloom() *Bloom { return &Bloom{r.receipt.Bloom} }

View file

@ -229,7 +229,7 @@ func ExpectMsg(r MsgReader, code uint64, content interface{}) error {
} }
if content == nil { if content == nil {
return msg.Discard() return msg.Discard()
} else { }
contentEnc, err := rlp.EncodeToBytes(content) contentEnc, err := rlp.EncodeToBytes(content)
if err != nil { if err != nil {
panic("content encode error: " + err.Error()) panic("content encode error: " + err.Error())
@ -244,7 +244,6 @@ func ExpectMsg(r MsgReader, code uint64, content interface{}) error {
if !bytes.Equal(actualContent, contentEnc) { if !bytes.Equal(actualContent, contentEnc) {
return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc) return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc)
} }
}
return nil return nil
} }

View file

@ -738,7 +738,6 @@ func (self *Network) executeNodeEvent(e *Event) error {
func (self *Network) executeConnEvent(e *Event) error { func (self *Network) executeConnEvent(e *Event) error {
if e.Conn.Up { if e.Conn.Up {
return self.Connect(e.Conn.One, e.Conn.Other) return self.Connect(e.Conn.One, e.Conn.Other)
} else { }
return self.Disconnect(e.Conn.One, e.Conn.Other) return self.Disconnect(e.Conn.One, e.Conn.Other)
} }
}

View file

@ -23,7 +23,7 @@ import (
const ( const (
VersionMajor = 1 // Major version component of the current release VersionMajor = 1 // Major version component of the current release
VersionMinor = 8 // Minor version component of the current release VersionMinor = 8 // Minor version component of the current release
VersionPatch = 7 // Patch version component of the current release VersionPatch = 8 // Patch version component of the current release
VersionMeta = "unstable" // Version metadata to append to the version string VersionMeta = "unstable" // Version metadata to append to the version string
) )

View file

@ -191,7 +191,7 @@ func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer codec.Close() defer codec.Close()
w.Header().Set("content-type", contentType) w.Header().Set("content-type", contentType)
srv.ServeSingleRequest(codec, OptionMethodInvocation, ctx) srv.ServeSingleRequest(ctx, codec, OptionMethodInvocation)
} }
// validateRequest returns a non-zero response code and error message if the // validateRequest returns a non-zero response code and error message if the

View file

@ -21,7 +21,7 @@ import (
"net" "net"
) )
// NewInProcClient attaches an in-process connection to the given RPC server. // DialInProc attaches an in-process connection to the given RPC server.
func DialInProc(handler *Server) *Client { func DialInProc(handler *Server) *Client {
initctx := context.Background() initctx := context.Background()
c, _ := newClient(initctx, func(context.Context) (net.Conn, error) { c, _ := newClient(initctx, func(context.Context) (net.Conn, error) {

View file

@ -125,7 +125,7 @@ func (s *Server) RegisterName(name string, rcvr interface{}) error {
// If singleShot is true it will process a single request, otherwise it will handle // If singleShot is true it will process a single request, otherwise it will handle
// requests until the codec returns an error when reading a request (in most cases // requests until the codec returns an error when reading a request (in most cases
// an EOF). It executes requests in parallel when singleShot is false. // an EOF). It executes requests in parallel when singleShot is false.
func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecOption, ctx context.Context) error { func (s *Server) serveRequest(ctx context.Context, codec ServerCodec, singleShot bool, options CodecOption) error {
var pend sync.WaitGroup var pend sync.WaitGroup
defer func() { defer func() {
@ -216,14 +216,14 @@ func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecO
// stopped. In either case the codec is closed. // stopped. In either case the codec is closed.
func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) {
defer codec.Close() defer codec.Close()
s.serveRequest(codec, false, options, context.Background()) s.serveRequest(context.Background(), codec, false, options)
} }
// ServeSingleRequest reads and processes a single RPC request from the given codec. It will not // ServeSingleRequest reads and processes a single RPC request from the given codec. It will not
// close the codec unless a non-recoverable error has occurred. Note, this method will return after // close the codec unless a non-recoverable error has occurred. Note, this method will return after
// a single request has been processed! // a single request has been processed!
func (s *Server) ServeSingleRequest(codec ServerCodec, options CodecOption, ctx context.Context) { func (s *Server) ServeSingleRequest(ctx context.Context, codec ServerCodec, options CodecOption) {
s.serveRequest(codec, true, options, ctx) s.serveRequest(ctx, codec, true, options)
} }
// Stop will stop reading new requests, wait for stopPendingRequestTimeout to allow pending requests to finish, // Stop will stop reading new requests, wait for stopPendingRequestTimeout to allow pending requests to finish,

View file

@ -94,14 +94,13 @@ func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) {
for n, argument := range method.Inputs { for n, argument := range method.Inputs {
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to decode argument %d (signature %v): %v", n, method.Sig(), err) return nil, fmt.Errorf("Failed to decode argument %d (signature %v): %v", n, method.Sig(), err)
} else { }
decodedArg := decodedArgument{ decodedArg := decodedArgument{
soltype: argument, soltype: argument,
value: v[n], value: v[n],
} }
decoded.inputs = append(decoded.inputs, decodedArg) decoded.inputs = append(decoded.inputs, decodedArg)
} }
}
// We're finished decoding the data. At this point, we encode the decoded data to see if it matches with the // We're finished decoding the data. At this point, we encode the decoded data to see if it matches with the
// original data. If we didn't do that, it would e.g. be possible to stuff extra data into the arguments, which // original data. If we didn't do that, it would e.g. be possible to stuff extra data into the arguments, which
@ -240,7 +239,7 @@ func (db *AbiDb) saveCustomAbi(selector, signature string) error {
return err return err
} }
// Adds a signature to the database, if custom database saving is enabled. // AddSignature to the database, if custom database saving is enabled.
// OBS: This method does _not_ validate the correctness of the data, // OBS: This method does _not_ validate the correctness of the data,
// it is assumed that the caller has already done so // it is assumed that the caller has already done so
func (db *AbiDb) AddSignature(selector string, data []byte) error { func (db *AbiDb) AddSignature(selector string, data []byte) error {

View file

@ -474,7 +474,7 @@ func (api *SignerAPI) Export(ctx context.Context, addr common.Address) (json.Raw
return ioutil.ReadFile(wallet.URL().Path) return ioutil.ReadFile(wallet.URL().Path)
} }
// Imports tries to import the given keyJSON in the local keystore. The keyJSON data is expected to be // Import tries to import the given keyJSON in the local keystore. The keyJSON data is expected to be
// in web3 keystore format. It will decrypt the keyJSON with the given passphrase and on successful // in web3 keystore format. It will decrypt the keyJSON with the given passphrase and on successful
// decryption it will encrypt the key with the given newPassphrase and store it in the keystore. // decryption it will encrypt the key with the given newPassphrase and store it in the keystore.
func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) { func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) {

View file

@ -13,6 +13,7 @@
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package core package core
import ( import (

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