Merge branch 'master' into coreAssorted

This commit is contained in:
kiel barry 2018-05-29 14:40:55 -07:00 committed by GitHub
commit 7f3841fd4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
156 changed files with 2232 additions and 1528 deletions

View file

@ -126,7 +126,7 @@ matrix:
# This builder does the Android Maven and Azure uploads # This builder does the Android Maven and Azure uploads
- os: linux - os: linux
dist: precise # Needed for the android tools dist: trusty
addons: addons:
apt: apt:
packages: packages:
@ -146,16 +146,16 @@ matrix:
git: git:
submodules: false # avoid cloning ethereum/tests submodules: false # avoid cloning ethereum/tests
before_install: before_install:
- curl https://storage.googleapis.com/golang/go1.10.1.linux-amd64.tar.gz | tar -xz - curl https://storage.googleapis.com/golang/go1.10.2.linux-amd64.tar.gz | tar -xz
- export PATH=`pwd`/go/bin:$PATH - export PATH=`pwd`/go/bin:$PATH
- export GOROOT=`pwd`/go - export GOROOT=`pwd`/go
- export GOPATH=$HOME/go - export GOPATH=$HOME/go
script: script:
# Build the Android archive and upload it to Maven Central and Azure # Build the Android archive and upload it to Maven Central and Azure
- curl https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip -o android-ndk-r15c.zip - curl https://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip -o android-ndk-r16b.zip
- unzip -q android-ndk-r15c.zip && rm android-ndk-r15c.zip - unzip -q android-ndk-r16b.zip && rm android-ndk-r16b.zip
- mv android-ndk-r15c $HOME - mv android-ndk-r16b $HOME
- export ANDROID_NDK=$HOME/android-ndk-r15c - export ANDROID_NDK=$HOME/android-ndk-r16b
- mkdir -p $GOPATH/src/github.com/ethereum - mkdir -p $GOPATH/src/github.com/ethereum
- ln -s `pwd` $GOPATH/src/github.com/ethereum - ln -s `pwd` $GOPATH/src/github.com/ethereum

View file

@ -1 +1 @@
1.8.8 1.8.10

View file

@ -111,9 +111,14 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
if err := requireUnpackKind(value, typ, kind, arguments); err != nil { if err := requireUnpackKind(value, typ, kind, arguments); err != nil {
return err return err
} }
// If the output interface is a struct, make sure names don't collide
// If the interface is a struct, get of abi->struct_field mapping
var abi2struct map[string]string
if kind == reflect.Struct { if kind == reflect.Struct {
if err := requireUniqueStructFieldNames(arguments); err != nil { var err error
abi2struct, err = mapAbiToStructFields(arguments, value)
if err != nil {
return err return err
} }
} }
@ -123,10 +128,11 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
switch kind { switch kind {
case reflect.Struct: case reflect.Struct:
err := unpackStruct(value, reflectValue, arg) if structField, ok := abi2struct[arg.Name]; ok {
if err != nil { if err := set(value.FieldByName(structField), reflectValue, arg); err != nil {
return err return err
} }
}
case reflect.Slice, reflect.Array: case reflect.Slice, reflect.Array:
if value.Len() < i { if value.Len() < i {
return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len()) return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len())
@ -151,17 +157,22 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interf
if len(marshalledValues) != 1 { if len(marshalledValues) != 1 {
return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues)) return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues))
} }
elem := reflect.ValueOf(v).Elem() elem := reflect.ValueOf(v).Elem()
kind := elem.Kind() kind := elem.Kind()
reflectValue := reflect.ValueOf(marshalledValues[0]) reflectValue := reflect.ValueOf(marshalledValues[0])
var abi2struct map[string]string
if kind == reflect.Struct { if kind == reflect.Struct {
//make sure names don't collide var err error
if err := requireUniqueStructFieldNames(arguments); err != nil { if abi2struct, err = mapAbiToStructFields(arguments, elem); err != nil {
return err return err
} }
arg := arguments.NonIndexed()[0]
return unpackStruct(elem, reflectValue, arguments[0]) if structField, ok := abi2struct[arg.Name]; ok {
return set(elem.FieldByName(structField), reflectValue, arg)
}
return nil
} }
return set(elem, reflectValue, arguments.NonIndexed()[0]) return set(elem, reflectValue, arguments.NonIndexed()[0])
@ -277,18 +288,3 @@ func capitalise(input string) string {
} }
return strings.ToUpper(input[:1]) + input[1:] return strings.ToUpper(input[:1]) + input[1:]
} }
//unpackStruct extracts each argument into its corresponding struct field
func unpackStruct(value, reflectValue reflect.Value, arg Argument) error {
name := capitalise(arg.Name)
typ := value.Type()
for j := 0; j < typ.NumField(); j++ {
// TODO read tags: `abi:"fieldName"`
if typ.Field(j).Name == name {
if err := set(value.Field(j), reflectValue, arg); err != nil {
return err
}
}
}
return nil
}

View file

@ -66,7 +66,7 @@ type SimulatedBackend struct {
// NewSimulatedBackend creates a new binding backend using a simulated blockchain // NewSimulatedBackend creates a new binding backend using a simulated blockchain
// for testing purposes. // for testing purposes.
func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend { func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
database, _ := ethdb.NewMemDatabase() database := ethdb.NewMemDatabase()
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, Alloc: alloc} genesis := core.Genesis{Config: params.AllEthashProtocolChanges, Alloc: alloc}
genesis.MustCommit(database) genesis.MustCommit(database)
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}) blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{})
@ -454,7 +454,7 @@ func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*ty
return logs, nil return logs, nil
} }
func (fb *filterBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { func (fb *filterBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return event.NewSubscription(func(quit <-chan struct{}) error { return event.NewSubscription(func(quit <-chan struct{}) error {
<-quit <-quit
return nil return nil

View file

@ -58,12 +58,28 @@ var jsonEventPledge = []byte(`{
"type": "event" "type": "event"
}`) }`)
var jsonEventMixedCase = []byte(`{
"anonymous": false,
"inputs": [{
"indexed": false, "name": "value", "type": "uint256"
}, {
"indexed": false, "name": "_value", "type": "uint256"
}, {
"indexed": false, "name": "Value", "type": "uint256"
}],
"name": "MixedCase",
"type": "event"
}`)
// 1000000 // 1000000
var transferData1 = "00000000000000000000000000000000000000000000000000000000000f4240" var transferData1 = "00000000000000000000000000000000000000000000000000000000000f4240"
// "0x00Ce0d46d924CC8437c806721496599FC3FFA268", 2218516807680, "usd" // "0x00Ce0d46d924CC8437c806721496599FC3FFA268", 2218516807680, "usd"
var pledgeData1 = "00000000000000000000000000ce0d46d924cc8437c806721496599fc3ffa2680000000000000000000000000000000000000000000000000000020489e800007573640000000000000000000000000000000000000000000000000000000000" var pledgeData1 = "00000000000000000000000000ce0d46d924cc8437c806721496599fc3ffa2680000000000000000000000000000000000000000000000000000020489e800007573640000000000000000000000000000000000000000000000000000000000"
// 1000000,2218516807680,1000001
var mixedCaseData1 = "00000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000020489e8000000000000000000000000000000000000000000000000000000000000000f4241"
func TestEventId(t *testing.T) { func TestEventId(t *testing.T) {
var table = []struct { var table = []struct {
definition string definition string
@ -121,6 +137,27 @@ func TestEventTupleUnpack(t *testing.T) {
Value *big.Int Value *big.Int
} }
type EventTransferWithTag struct {
// this is valid because `value` is not exportable,
// so value is only unmarshalled into `Value1`.
value *big.Int
Value1 *big.Int `abi:"value"`
}
type BadEventTransferWithSameFieldAndTag struct {
Value *big.Int
Value1 *big.Int `abi:"value"`
}
type BadEventTransferWithDuplicatedTag struct {
Value1 *big.Int `abi:"value"`
Value2 *big.Int `abi:"value"`
}
type BadEventTransferWithEmptyTag struct {
Value *big.Int `abi:""`
}
type EventPledge struct { type EventPledge struct {
Who common.Address Who common.Address
Wad *big.Int Wad *big.Int
@ -133,9 +170,16 @@ func TestEventTupleUnpack(t *testing.T) {
Currency [3]byte Currency [3]byte
} }
type EventMixedCase struct {
Value1 *big.Int `abi:"value"`
Value2 *big.Int `abi:"_value"`
Value3 *big.Int `abi:"Value"`
}
bigint := new(big.Int) bigint := new(big.Int)
bigintExpected := big.NewInt(1000000) bigintExpected := big.NewInt(1000000)
bigintExpected2 := big.NewInt(2218516807680) bigintExpected2 := big.NewInt(2218516807680)
bigintExpected3 := big.NewInt(1000001)
addr := common.HexToAddress("0x00Ce0d46d924CC8437c806721496599FC3FFA268") addr := common.HexToAddress("0x00Ce0d46d924CC8437c806721496599FC3FFA268")
var testCases = []struct { var testCases = []struct {
data string data string
@ -158,6 +202,34 @@ func TestEventTupleUnpack(t *testing.T) {
jsonEventTransfer, jsonEventTransfer,
"", "",
"Can unpack ERC20 Transfer event into slice", "Can unpack ERC20 Transfer event into slice",
}, {
transferData1,
&EventTransferWithTag{},
&EventTransferWithTag{Value1: bigintExpected},
jsonEventTransfer,
"",
"Can unpack ERC20 Transfer event into structure with abi: tag",
}, {
transferData1,
&BadEventTransferWithDuplicatedTag{},
&BadEventTransferWithDuplicatedTag{},
jsonEventTransfer,
"struct: abi tag in 'Value2' already mapped",
"Can not unpack ERC20 Transfer event with duplicated abi tag",
}, {
transferData1,
&BadEventTransferWithSameFieldAndTag{},
&BadEventTransferWithSameFieldAndTag{},
jsonEventTransfer,
"abi: multiple variables maps to the same abi field 'value'",
"Can not unpack ERC20 Transfer event with a field and a tag mapping to the same abi variable",
}, {
transferData1,
&BadEventTransferWithEmptyTag{},
&BadEventTransferWithEmptyTag{},
jsonEventTransfer,
"struct: abi tag in 'Value' is empty",
"Can not unpack ERC20 Transfer event with an empty tag",
}, { }, {
pledgeData1, pledgeData1,
&EventPledge{}, &EventPledge{},
@ -216,6 +288,13 @@ func TestEventTupleUnpack(t *testing.T) {
jsonEventPledge, jsonEventPledge,
"abi: cannot unmarshal tuple into map[string]interface {}", "abi: cannot unmarshal tuple into map[string]interface {}",
"Can not unpack Pledge event into map", "Can not unpack Pledge event into map",
}, {
mixedCaseData1,
&EventMixedCase{},
&EventMixedCase{Value1: bigintExpected, Value2: bigintExpected2, Value3: bigintExpected3},
jsonEventMixedCase,
"",
"Can unpack abi variables with mixed case",
}} }}
for _, tc := range testCases { for _, tc := range testCases {
@ -227,7 +306,7 @@ func TestEventTupleUnpack(t *testing.T) {
assert.Nil(err, "Should be able to unpack event data.") assert.Nil(err, "Should be able to unpack event data.")
assert.Equal(tc.expected, tc.dest, tc.name) assert.Equal(tc.expected, tc.dest, tc.name)
} else { } else {
assert.EqualError(err, tc.error) assert.EqualError(err, tc.error, tc.name)
} }
}) })
} }

View file

@ -19,6 +19,7 @@ package abi
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"strings"
) )
// indirect recursively dereferences the value until it either gets the value // indirect recursively dereferences the value until it either gets the value
@ -111,18 +112,101 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
return nil return nil
} }
// requireUniqueStructFieldNames makes sure field names don't collide // mapAbiToStringField maps abi to struct fields.
func requireUniqueStructFieldNames(args Arguments) error { // first round: for each Exportable field that contains a `abi:""` tag
exists := make(map[string]bool) // and this field name exists in the arguments, pair them together.
// second round: for each argument field that has not been already linked,
// find what variable is expected to be mapped into, if it exists and has not been
// used, pair them.
func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]string, error) {
typ := value.Type()
abi2struct := make(map[string]string)
struct2abi := make(map[string]string)
// first round ~~~
for i := 0; i < typ.NumField(); i++ {
structFieldName := typ.Field(i).Name
// skip private struct fields.
if structFieldName[:1] != strings.ToUpper(structFieldName[:1]) {
continue
}
// skip fields that have no abi:"" tag.
var ok bool
var tagName string
if tagName, ok = typ.Field(i).Tag.Lookup("abi"); !ok {
continue
}
// check if tag is empty.
if tagName == "" {
return nil, fmt.Errorf("struct: abi tag in '%s' is empty", structFieldName)
}
// check which argument field matches with the abi tag.
found := false
for _, abiField := range args.NonIndexed() {
if abiField.Name == tagName {
if abi2struct[abiField.Name] != "" {
return nil, fmt.Errorf("struct: abi tag in '%s' already mapped", structFieldName)
}
// pair them
abi2struct[abiField.Name] = structFieldName
struct2abi[structFieldName] = abiField.Name
found = true
}
}
// check if this tag has been mapped.
if !found {
return nil, fmt.Errorf("struct: abi tag '%s' defined but not found in abi", tagName)
}
}
// second round ~~~
for _, arg := range args { for _, arg := range args {
field := capitalise(arg.Name)
if field == "" { abiFieldName := arg.Name
return fmt.Errorf("abi: purely underscored output cannot unpack to struct") structFieldName := capitalise(abiFieldName)
if structFieldName == "" {
return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct")
} }
if exists[field] {
return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field) // this abi has already been paired, skip it... unless there exists another, yet unassigned
// struct field with the same field name. If so, raise an error:
// abi: [ { "name": "value" } ]
// struct { Value *big.Int , Value1 *big.Int `abi:"value"`}
if abi2struct[abiFieldName] != "" {
if abi2struct[abiFieldName] != structFieldName &&
struct2abi[structFieldName] == "" &&
value.FieldByName(structFieldName).IsValid() {
return nil, fmt.Errorf("abi: multiple variables maps to the same abi field '%s'", abiFieldName)
} }
exists[field] = true continue
} }
return nil
// return an error if this struct field has already been paired.
if struct2abi[structFieldName] != "" {
return nil, fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", structFieldName)
}
if value.FieldByName(structFieldName).IsValid() {
// pair them
abi2struct[abiFieldName] = structFieldName
struct2abi[structFieldName] = abiFieldName
} else {
// not paired, but annotate as used, to detect cases like
// abi : [ { "name": "value" }, { "name": "_value" } ]
// struct { Value *big.Int }
struct2abi[structFieldName] = abiFieldName
}
}
return abi2struct, nil
} }

View file

@ -23,8 +23,8 @@ environment:
install: install:
- git submodule update --init - git submodule update --init
- rmdir C:\go /s /q - rmdir C:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.1.windows-%GETH_ARCH%.zip - appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.2.windows-%GETH_ARCH%.zip
- 7z x go1.10.1.windows-%GETH_ARCH%.zip -y -oC:\ > NUL - 7z x go1.10.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
- go version - go version
- gcc --version - gcc --version

View file

@ -150,29 +150,29 @@ func NewTreePool(hasher BaseHasher, segmentCount, capacity int) *TreePool {
} }
// Drain drains the pool until it has no more than n resources // Drain drains the pool until it has no more than n resources
func (self *TreePool) Drain(n int) { func (p *TreePool) Drain(n int) {
self.lock.Lock() p.lock.Lock()
defer self.lock.Unlock() defer p.lock.Unlock()
for len(self.c) > n { for len(p.c) > n {
<-self.c <-p.c
self.count-- p.count--
} }
} }
// Reserve is blocking until it returns an available Tree // Reserve is blocking until it returns an available Tree
// it reuses free Trees or creates a new one if size is not reached // it reuses free Trees or creates a new one if size is not reached
func (self *TreePool) Reserve() *Tree { func (p *TreePool) Reserve() *Tree {
self.lock.Lock() p.lock.Lock()
defer self.lock.Unlock() defer p.lock.Unlock()
var t *Tree var t *Tree
if self.count == self.Capacity { if p.count == p.Capacity {
return <-self.c return <-p.c
} }
select { select {
case t = <-self.c: case t = <-p.c:
default: default:
t = NewTree(self.hasher, self.SegmentSize, self.SegmentCount) t = NewTree(p.hasher, p.SegmentSize, p.SegmentCount)
self.count++ p.count++
} }
return t return t
} }
@ -180,8 +180,8 @@ func (self *TreePool) Reserve() *Tree {
// Release gives back a Tree to the pool. // Release gives back a Tree to the pool.
// This Tree is guaranteed to be in reusable state // This Tree is guaranteed to be in reusable state
// does not need locking // does not need locking
func (self *TreePool) Release(t *Tree) { func (p *TreePool) Release(t *Tree) {
self.c <- t // can never fail but... p.c <- t // can never fail but...
} }
// Tree is a reusable control structure representing a BMT // Tree is a reusable control structure representing a BMT
@ -193,17 +193,17 @@ type Tree struct {
} }
// Draw draws the BMT (badly) // Draw draws the BMT (badly)
func (self *Tree) Draw(hash []byte, d int) string { func (t *Tree) Draw(hash []byte, d int) string {
var left, right []string var left, right []string
var anc []*Node var anc []*Node
for i, n := range self.leaves { for i, n := range t.leaves {
left = append(left, fmt.Sprintf("%v", hashstr(n.left))) left = append(left, fmt.Sprintf("%v", hashstr(n.left)))
if i%2 == 0 { if i%2 == 0 {
anc = append(anc, n.parent) anc = append(anc, n.parent)
} }
right = append(right, fmt.Sprintf("%v", hashstr(n.right))) right = append(right, fmt.Sprintf("%v", hashstr(n.right)))
} }
anc = self.leaves anc = t.leaves
var hashes [][]string var hashes [][]string
for l := 0; len(anc) > 0; l++ { for l := 0; len(anc) > 0; l++ {
var nodes []*Node var nodes []*Node
@ -277,42 +277,42 @@ func NewTree(hasher BaseHasher, segmentSize, segmentCount int) *Tree {
// methods needed by hash.Hash // methods needed by hash.Hash
// Size returns the size // Size returns the size
func (self *Hasher) Size() int { func (h *Hasher) Size() int {
return self.size return h.size
} }
// BlockSize returns the block size // BlockSize returns the block size
func (self *Hasher) BlockSize() int { func (h *Hasher) BlockSize() int {
return self.blocksize return h.blocksize
} }
// Sum returns the hash of the buffer // Sum returns the hash of the buffer
// hash.Hash interface Sum method appends the byte slice to the underlying // hash.Hash interface Sum method appends the byte slice to the underlying
// data before it calculates and returns the hash of the chunk // data before it calculates and returns the hash of the chunk
func (self *Hasher) Sum(b []byte) (r []byte) { func (h *Hasher) Sum(b []byte) (r []byte) {
t := self.bmt t := h.bmt
i := self.cur i := h.cur
n := t.leaves[i] n := t.leaves[i]
j := i j := i
// must run strictly before all nodes calculate // must run strictly before all nodes calculate
// datanodes are guaranteed to have a parent // datanodes are guaranteed to have a parent
if len(self.segment) > self.size && i > 0 && n.parent != nil { if len(h.segment) > h.size && i > 0 && n.parent != nil {
n = n.parent n = n.parent
} else { } else {
i *= 2 i *= 2
} }
d := self.finalise(n, i) d := h.finalise(n, i)
self.writeSegment(j, self.segment, d) h.writeSegment(j, h.segment, d)
c := <-self.result c := <-h.result
self.releaseTree() h.releaseTree()
// sha3(length + BMT(pure_chunk)) // sha3(length + BMT(pure_chunk))
if self.blockLength == nil { if h.blockLength == nil {
return c return c
} }
res := self.pool.hasher() res := h.pool.hasher()
res.Reset() res.Reset()
res.Write(self.blockLength) res.Write(h.blockLength)
res.Write(c) res.Write(c)
return res.Sum(nil) return res.Sum(nil)
} }
@ -321,8 +321,8 @@ func (self *Hasher) Sum(b []byte) (r []byte) {
// Hash waits for the hasher result and returns it // Hash waits for the hasher result and returns it
// caller must call this on a BMT Hasher being written to // caller must call this on a BMT Hasher being written to
func (self *Hasher) Hash() []byte { func (h *Hasher) Hash() []byte {
return <-self.result return <-h.result
} }
// Hasher implements the io.Writer interface // Hasher implements the io.Writer interface
@ -330,16 +330,16 @@ func (self *Hasher) Hash() []byte {
// Write fills the buffer to hash // Write fills the buffer to hash
// with every full segment complete launches a hasher go routine // with every full segment complete launches a hasher go routine
// that shoots up the BMT // that shoots up the BMT
func (self *Hasher) Write(b []byte) (int, error) { func (h *Hasher) Write(b []byte) (int, error) {
l := len(b) l := len(b)
if l <= 0 { if l <= 0 {
return 0, nil return 0, nil
} }
s := self.segment s := h.segment
i := self.cur i := h.cur
count := (self.count + 1) / 2 count := (h.count + 1) / 2
need := self.count*self.size - self.cur*2*self.size need := h.count*h.size - h.cur*2*h.size
size := self.size size := h.size
if need > size { if need > size {
size *= 2 size *= 2
} }
@ -356,7 +356,7 @@ func (self *Hasher) Write(b []byte) (int, error) {
// read full segments and the last possibly partial segment // read full segments and the last possibly partial segment
for need > 0 && i < count-1 { for need > 0 && i < count-1 {
// push all finished chunks we read // push all finished chunks we read
self.writeSegment(i, s, self.depth) h.writeSegment(i, s, h.depth)
need -= size need -= size
if need < 0 { if need < 0 {
size += need size += need
@ -365,8 +365,8 @@ func (self *Hasher) Write(b []byte) (int, error) {
rest += size rest += size
i++ i++
} }
self.segment = s h.segment = s
self.cur = i h.cur = i
// otherwise, we can assume len(s) == 0, so all buffer is read and chunk is not yet full // otherwise, we can assume len(s) == 0, so all buffer is read and chunk is not yet full
return l, nil return l, nil
} }
@ -376,8 +376,8 @@ func (self *Hasher) Write(b []byte) (int, error) {
// ReadFrom reads from io.Reader and appends to the data to hash using Write // ReadFrom reads from io.Reader and appends to the data to hash using Write
// it reads so that chunk to hash is maximum length or reader reaches EOF // it reads so that chunk to hash is maximum length or reader reaches EOF
// caller must Reset the hasher prior to call // caller must Reset the hasher prior to call
func (self *Hasher) ReadFrom(r io.Reader) (m int64, err error) { func (h *Hasher) ReadFrom(r io.Reader) (m int64, err error) {
bufsize := self.size*self.count - self.size*self.cur - len(self.segment) bufsize := h.size*h.count - h.size*h.cur - len(h.segment)
buf := make([]byte, bufsize) buf := make([]byte, bufsize)
var read int var read int
for { for {
@ -385,7 +385,7 @@ func (self *Hasher) ReadFrom(r io.Reader) (m int64, err error) {
n, err = r.Read(buf) n, err = r.Read(buf)
read += n read += n
if err == io.EOF || read == len(buf) { if err == io.EOF || read == len(buf) {
hash := self.Sum(buf[:n]) hash := h.Sum(buf[:n])
if read == len(buf) { if read == len(buf) {
err = NewEOC(hash) err = NewEOC(hash)
} }
@ -394,7 +394,7 @@ func (self *Hasher) ReadFrom(r io.Reader) (m int64, err error) {
if err != nil { if err != nil {
break break
} }
n, err = self.Write(buf[:n]) n, err = h.Write(buf[:n])
if err != nil { if err != nil {
break break
} }
@ -403,9 +403,9 @@ func (self *Hasher) ReadFrom(r io.Reader) (m int64, err error) {
} }
// Reset needs to be called before writing to the hasher // Reset needs to be called before writing to the hasher
func (self *Hasher) Reset() { func (h *Hasher) Reset() {
self.getTree() h.getTree()
self.blockLength = nil h.blockLength = nil
} }
// Hasher implements the SwarmHash interface // Hasher implements the SwarmHash interface
@ -413,52 +413,52 @@ func (self *Hasher) Reset() {
// ResetWithLength needs to be called before writing to the hasher // ResetWithLength needs to be called before writing to the hasher
// the argument is supposed to be the byte slice binary representation of // the argument is supposed to be the byte slice binary representation of
// the length of the data subsumed under the hash // the length of the data subsumed under the hash
func (self *Hasher) ResetWithLength(l []byte) { func (h *Hasher) ResetWithLength(l []byte) {
self.Reset() h.Reset()
self.blockLength = l h.blockLength = l
} }
// Release gives back the Tree to the pool whereby it unlocks // Release gives back the Tree to the pool whereby it unlocks
// it resets tree, segment and index // it resets tree, segment and index
func (self *Hasher) releaseTree() { func (h *Hasher) releaseTree() {
if self.bmt != nil { if h.bmt != nil {
n := self.bmt.leaves[self.cur] n := h.bmt.leaves[h.cur]
for ; n != nil; n = n.parent { for ; n != nil; n = n.parent {
n.unbalanced = false n.unbalanced = false
if n.parent != nil { if n.parent != nil {
n.root = false n.root = false
} }
} }
self.pool.Release(self.bmt) h.pool.Release(h.bmt)
self.bmt = nil h.bmt = nil
} }
self.cur = 0 h.cur = 0
self.segment = nil h.segment = nil
} }
func (self *Hasher) writeSegment(i int, s []byte, d int) { func (h *Hasher) writeSegment(i int, s []byte, d int) {
h := self.pool.hasher() hash := h.pool.hasher()
n := self.bmt.leaves[i] n := h.bmt.leaves[i]
if len(s) > self.size && n.parent != nil { if len(s) > h.size && n.parent != nil {
go func() { go func() {
h.Reset() hash.Reset()
h.Write(s) hash.Write(s)
s = h.Sum(nil) s = hash.Sum(nil)
if n.root { if n.root {
self.result <- s h.result <- s
return return
} }
self.run(n.parent, h, d, n.index, s) h.run(n.parent, hash, d, n.index, s)
}() }()
return return
} }
go self.run(n, h, d, i*2, s) go h.run(n, hash, d, i*2, s)
} }
func (self *Hasher) run(n *Node, h hash.Hash, d int, i int, s []byte) { func (h *Hasher) run(n *Node, hash hash.Hash, d int, i int, s []byte) {
isLeft := i%2 == 0 isLeft := i%2 == 0
for { for {
if isLeft { if isLeft {
@ -470,18 +470,18 @@ func (self *Hasher) run(n *Node, h hash.Hash, d int, i int, s []byte) {
return return
} }
if !n.unbalanced || !isLeft || i == 0 && d == 0 { if !n.unbalanced || !isLeft || i == 0 && d == 0 {
h.Reset() hash.Reset()
h.Write(n.left) hash.Write(n.left)
h.Write(n.right) hash.Write(n.right)
s = h.Sum(nil) s = hash.Sum(nil)
} else { } else {
s = append(n.left, n.right...) s = append(n.left, n.right...)
} }
self.hash = s h.hash = s
if n.root { if n.root {
self.result <- s h.result <- s
return return
} }
@ -492,20 +492,20 @@ func (self *Hasher) run(n *Node, h hash.Hash, d int, i int, s []byte) {
} }
// getTree obtains a BMT resource by reserving one from the pool // getTree obtains a BMT resource by reserving one from the pool
func (self *Hasher) getTree() *Tree { func (h *Hasher) getTree() *Tree {
if self.bmt != nil { if h.bmt != nil {
return self.bmt return h.bmt
} }
t := self.pool.Reserve() t := h.pool.Reserve()
self.bmt = t h.bmt = t
return t return t
} }
// atomic bool toggle implementing a concurrent reusable 2-state object // atomic bool toggle implementing a concurrent reusable 2-state object
// atomic addint with %2 implements atomic bool toggle // atomic addint with %2 implements atomic bool toggle
// it returns true if the toggler just put it in the active/waiting state // it returns true if the toggler just put it in the active/waiting state
func (self *Node) toggle() bool { func (n *Node) toggle() bool {
return atomic.AddInt32(&self.state, 1)%2 == 1 return atomic.AddInt32(&n.state, 1)%2 == 1
} }
func hashstr(b []byte) string { func hashstr(b []byte) string {
@ -525,7 +525,7 @@ func depth(n int) (d int) {
// finalise is following the zigzags on the tree belonging // finalise is following the zigzags on the tree belonging
// to the final datasegment // to the final datasegment
func (self *Hasher) finalise(n *Node, i int) (d int) { func (h *Hasher) finalise(n *Node, i int) (d int) {
isLeft := i%2 == 0 isLeft := i%2 == 0
for { for {
// when the final segment's path is going via left segments // when the final segment's path is going via left segments
@ -550,8 +550,8 @@ type EOC struct {
} }
// Error returns the error string // Error returns the error string
func (self *EOC) Error() string { func (e *EOC) Error() string {
return fmt.Sprintf("hasher limit reached, chunk hash: %x", self.Hash) return fmt.Sprintf("hasher limit reached, chunk hash: %x", e.Hash)
} }
// NewEOC creates new end of chunk error with the hash // NewEOC creates new end of chunk error with the hash

View file

@ -755,7 +755,7 @@ func doAndroidArchive(cmdline []string) {
os.Rename(archive, meta.Package+".aar") os.Rename(archive, meta.Package+".aar")
if *signer != "" && *deploy != "" { if *signer != "" && *deploy != "" {
// Import the signing key into the local GPG instance // Import the signing key into the local GPG instance
if b64key := os.Getenv(*signer); b64key != "" { b64key := os.Getenv(*signer)
key, err := base64.StdEncoding.DecodeString(b64key) key, err := base64.StdEncoding.DecodeString(b64key)
if err != nil { if err != nil {
log.Fatalf("invalid base64 %s", *signer) log.Fatalf("invalid base64 %s", *signer)
@ -763,6 +763,10 @@ func doAndroidArchive(cmdline []string) {
gpg := exec.Command("gpg", "--import") gpg := exec.Command("gpg", "--import")
gpg.Stdin = bytes.NewReader(key) gpg.Stdin = bytes.NewReader(key)
build.MustRun(gpg) build.MustRun(gpg)
keyID, err := build.PGPKeyID(string(key))
if err != nil {
log.Fatal(err)
} }
// Upload the artifacts to Sonatype and/or Maven Central // Upload the artifacts to Sonatype and/or Maven Central
repo := *deploy + "/service/local/staging/deploy/maven2" repo := *deploy + "/service/local/staging/deploy/maven2"
@ -771,6 +775,7 @@ func doAndroidArchive(cmdline []string) {
} }
build.MustRunCommand("mvn", "gpg:sign-and-deploy-file", "-e", "-X", build.MustRunCommand("mvn", "gpg:sign-and-deploy-file", "-e", "-X",
"-settings=build/mvn.settings", "-Durl="+repo, "-DrepositoryId=ossrh", "-settings=build/mvn.settings", "-Durl="+repo, "-DrepositoryId=ossrh",
"-Dgpg.keyname="+keyID,
"-DpomFile="+meta.Package+".pom", "-Dfile="+meta.Package+".aar") "-DpomFile="+meta.Package+".pom", "-Dfile="+meta.Package+".aar")
} }
} }

View file

@ -47,11 +47,11 @@ import (
"gopkg.in/urfave/cli.v1" "gopkg.in/urfave/cli.v1"
) )
// ExternalApiVersion -- see extapi_changelog.md // ExternalAPIVersion -- see extapi_changelog.md
const ExternalApiVersion = "2.0.0" const ExternalAPIVersion = "2.0.0"
// InternalApiVersion -- see intapi_changelog.md // InternalAPIVersion -- see intapi_changelog.md
const InternalApiVersion = "2.0.0" const InternalAPIVersion = "2.0.0"
const legalWarning = ` const legalWarning = `
WARNING! WARNING!
@ -398,10 +398,10 @@ func signer(c *cli.Context) error {
} }
// register signer API with server // register signer API with server
var ( var (
extapiUrl = "n/a" extapiURL = "n/a"
ipcApiUrl = "n/a" ipcapiURL = "n/a"
) )
rpcApi := []rpc.API{ rpcAPI := []rpc.API{
{ {
Namespace: "account", Namespace: "account",
Public: true, Public: true,
@ -415,12 +415,12 @@ func signer(c *cli.Context) error {
// start http server // start http server
httpEndpoint := fmt.Sprintf("%s:%d", c.String(utils.RPCListenAddrFlag.Name), c.Int(rpcPortFlag.Name)) httpEndpoint := fmt.Sprintf("%s:%d", c.String(utils.RPCListenAddrFlag.Name), c.Int(rpcPortFlag.Name))
listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcApi, []string{"account"}, cors, vhosts) listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"account"}, cors, vhosts)
if err != nil { if err != nil {
utils.Fatalf("Could not start RPC api: %v", err) utils.Fatalf("Could not start RPC api: %v", err)
} }
extapiUrl = fmt.Sprintf("http://%s", httpEndpoint) extapiURL = fmt.Sprintf("http://%s", httpEndpoint)
log.Info("HTTP endpoint opened", "url", extapiUrl) log.Info("HTTP endpoint opened", "url", extapiURL)
defer func() { defer func() {
listener.Close() listener.Close()
@ -430,19 +430,19 @@ func signer(c *cli.Context) error {
} }
if !c.Bool(utils.IPCDisabledFlag.Name) { if !c.Bool(utils.IPCDisabledFlag.Name) {
if c.IsSet(utils.IPCPathFlag.Name) { if c.IsSet(utils.IPCPathFlag.Name) {
ipcApiUrl = c.String(utils.IPCPathFlag.Name) ipcapiURL = c.String(utils.IPCPathFlag.Name)
} else { } else {
ipcApiUrl = filepath.Join(configDir, "clef.ipc") ipcapiURL = filepath.Join(configDir, "clef.ipc")
} }
listener, _, err := rpc.StartIPCEndpoint(ipcApiUrl, rpcApi) listener, _, err := rpc.StartIPCEndpoint(ipcapiURL, rpcAPI)
if err != nil { if err != nil {
utils.Fatalf("Could not start IPC api: %v", err) utils.Fatalf("Could not start IPC api: %v", err)
} }
log.Info("IPC endpoint opened", "url", ipcApiUrl) log.Info("IPC endpoint opened", "url", ipcapiURL)
defer func() { defer func() {
listener.Close() listener.Close()
log.Info("IPC endpoint closed", "url", ipcApiUrl) log.Info("IPC endpoint closed", "url", ipcapiURL)
}() }()
} }
@ -453,10 +453,10 @@ func signer(c *cli.Context) error {
} }
ui.OnSignerStartup(core.StartupInfo{ ui.OnSignerStartup(core.StartupInfo{
Info: map[string]interface{}{ Info: map[string]interface{}{
"extapi_version": ExternalApiVersion, "extapi_version": ExternalAPIVersion,
"intapi_version": InternalApiVersion, "intapi_version": InternalAPIVersion,
"extapi_http": extapiUrl, "extapi_http": extapiURL,
"extapi_ipc": ipcApiUrl, "extapi_ipc": ipcapiURL,
}, },
}) })

View file

@ -32,6 +32,8 @@ type JSONLogger struct {
cfg *vm.LogConfig cfg *vm.LogConfig
} }
// NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects
// into the provided stream.
func NewJSONLogger(cfg *vm.LogConfig, writer io.Writer) *JSONLogger { func NewJSONLogger(cfg *vm.LogConfig, writer io.Writer) *JSONLogger {
return &JSONLogger{json.NewEncoder(writer), cfg} return &JSONLogger{json.NewEncoder(writer), cfg}
} }

View file

@ -98,14 +98,13 @@ func runCmd(ctx *cli.Context) error {
} }
if ctx.GlobalString(GenesisFlag.Name) != "" { if ctx.GlobalString(GenesisFlag.Name) != "" {
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
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 blockNumber = gen.Number
} else { } else {
db, _ := ethdb.NewMemDatabase() statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ = state.New(common.Hash{}, state.NewDatabase(db))
} }
if ctx.GlobalString(SenderFlag.Name) != "" { if ctx.GlobalString(SenderFlag.Name) != "" {
sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name))

View file

@ -38,6 +38,8 @@ var stateTestCommand = cli.Command{
ArgsUsage: "<file>", ArgsUsage: "<file>",
} }
// StatetestResult contains the execution status after running a state test, any
// error that might have occurred and a dump of the final state if requested.
type StatetestResult struct { type StatetestResult struct {
Name string `json:"name"` Name string `json:"name"`
Pass bool `json:"pass"` Pass bool `json:"pass"`

View file

@ -340,7 +340,7 @@ func importWallet(ctx *cli.Context) error {
if len(keyfile) == 0 { if len(keyfile) == 0 {
utils.Fatalf("keyfile must be given as argument") utils.Fatalf("keyfile must be given as argument")
} }
keyJson, err := ioutil.ReadFile(keyfile) keyJSON, err := ioutil.ReadFile(keyfile)
if err != nil { if err != nil {
utils.Fatalf("Could not read wallet file: %v", err) utils.Fatalf("Could not read wallet file: %v", err)
} }
@ -349,7 +349,7 @@ func importWallet(ctx *cli.Context) error {
passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx)) passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx))
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
acct, err := ks.ImportPreSaleKey(keyJson, passphrase) acct, err := ks.ImportPreSaleKey(keyJSON, passphrase)
if err != nil { if err != nil {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
} }

View file

@ -41,7 +41,7 @@ var bugCommand = cli.Command{
Category: "MISCELLANEOUS COMMANDS", Category: "MISCELLANEOUS COMMANDS",
} }
const issueUrl = "https://github.com/ethereum/go-ethereum/issues/new" const issueURL = "https://github.com/ethereum/go-ethereum/issues/new"
// reportBug reports a bug by opening a new URL to the go-ethereum GH issue // reportBug reports a bug by opening a new URL to the go-ethereum GH issue
// tracker and setting default values as the issue body. // tracker and setting default values as the issue body.
@ -58,8 +58,8 @@ func reportBug(ctx *cli.Context) error {
fmt.Fprintln(&buff, header) fmt.Fprintln(&buff, header)
// open a new GH issue // open a new GH issue
if !browser.Open(issueUrl + "?body=" + url.QueryEscape(buff.String())) { if !browser.Open(issueURL + "?body=" + url.QueryEscape(buff.String())) {
fmt.Printf("Please file a new issue at %s using this template:\n\n%s", issueUrl, buff.String()) fmt.Printf("Please file a new issue at %s using this template:\n\n%s", issueURL, buff.String())
} }
return nil return nil
} }

View file

@ -19,15 +19,20 @@ package common
import "encoding/hex" import "encoding/hex"
// ToHex returns the hex representation of b, prefixed with '0x'.
// For empty slices, the return value is "0x0".
//
// Deprecated: use hexutil.Encode instead.
func ToHex(b []byte) string { func ToHex(b []byte) string {
hex := Bytes2Hex(b) hex := Bytes2Hex(b)
// Prefer output of "0x0" instead of "0x"
if len(hex) == 0 { if len(hex) == 0 {
hex = "0" hex = "0"
} }
return "0x" + hex return "0x" + hex
} }
// FromHex returns the bytes represented by the hexadecimal string s.
// s may be prefixed with "0x".
func FromHex(s string) []byte { func FromHex(s string) []byte {
if len(s) > 1 { if len(s) > 1 {
if s[0:2] == "0x" || s[0:2] == "0X" { if s[0:2] == "0x" || s[0:2] == "0X" {
@ -40,9 +45,7 @@ func FromHex(s string) []byte {
return Hex2Bytes(s) return Hex2Bytes(s)
} }
// Copy bytes // CopyBytes returns an exact copy of the provided bytes.
//
// Returns an exact copy of the provided bytes
func CopyBytes(b []byte) (copiedBytes []byte) { func CopyBytes(b []byte) (copiedBytes []byte) {
if b == nil { if b == nil {
return nil return nil
@ -53,14 +56,17 @@ func CopyBytes(b []byte) (copiedBytes []byte) {
return return
} }
// hasHexPrefix validates str begins with '0x' or '0X'.
func hasHexPrefix(str string) bool { func hasHexPrefix(str string) bool {
return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
} }
// isHexCharacter returns bool of c being a valid hexadecimal.
func isHexCharacter(c byte) bool { func isHexCharacter(c byte) bool {
return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')
} }
// isHex validates whether each byte is valid hexadecimal string.
func isHex(str string) bool { func isHex(str string) bool {
if len(str)%2 != 0 { if len(str)%2 != 0 {
return false return false
@ -73,16 +79,18 @@ func isHex(str string) bool {
return true return true
} }
// Bytes2Hex returns the hexadecimal encoding of d.
func Bytes2Hex(d []byte) string { func Bytes2Hex(d []byte) string {
return hex.EncodeToString(d) return hex.EncodeToString(d)
} }
// Hex2Bytes returns the bytes represented by the hexadecimal string str.
func Hex2Bytes(str string) []byte { func Hex2Bytes(str string) []byte {
h, _ := hex.DecodeString(str) h, _ := hex.DecodeString(str)
return h return h
} }
// Hex2BytesFixed returns bytes of a specified fixed length flen.
func Hex2BytesFixed(str string, flen int) []byte { func Hex2BytesFixed(str string, flen int) []byte {
h, _ := hex.DecodeString(str) h, _ := hex.DecodeString(str)
if len(h) == flen { if len(h) == flen {
@ -96,6 +104,7 @@ func Hex2BytesFixed(str string, flen int) []byte {
return hh return hh
} }
// RightPadBytes zero-pads slice to the right up to length l.
func RightPadBytes(slice []byte, l int) []byte { func RightPadBytes(slice []byte, l int) []byte {
if l <= len(slice) { if l <= len(slice) {
return slice return slice
@ -107,6 +116,7 @@ func RightPadBytes(slice []byte, l int) []byte {
return padded return padded
} }
// LeftPadBytes zero-pads slice to the left up to length l.
func LeftPadBytes(slice []byte, l int) []byte { func LeftPadBytes(slice []byte, l int) []byte {
if l <= len(slice) { if l <= len(slice) {
return slice return slice

View file

@ -78,7 +78,7 @@ func ParseBig256(s string) (*big.Int, bool) {
return bigint, ok return bigint, ok
} }
// MustParseBig parses s as a 256 bit big integer and panics if the string is invalid. // MustParseBig256 parses s as a 256 bit big integer and panics if the string is invalid.
func MustParseBig256(s string) *big.Int { func MustParseBig256(s string) *big.Int {
v, ok := ParseBig256(s) v, ok := ParseBig256(s)
if !ok { if !ok {
@ -186,9 +186,8 @@ func U256(x *big.Int) *big.Int {
func S256(x *big.Int) *big.Int { func S256(x *big.Int) *big.Int {
if x.Cmp(tt255) < 0 { if x.Cmp(tt255) < 0 {
return x return x
} else {
return new(big.Int).Sub(x, tt256)
} }
return new(big.Int).Sub(x, tt256)
} }
// Exp implements exponentiation by squaring. // Exp implements exponentiation by squaring.

View file

@ -34,13 +34,12 @@ func limitUnsigned256(x *Number) *Number {
func limitSigned256(x *Number) *Number { func limitSigned256(x *Number) *Number {
if x.num.Cmp(tt255) < 0 { if x.num.Cmp(tt255) < 0 {
return x return x
} else { }
x.num.Sub(x.num, tt256) x.num.Sub(x.num, tt256)
return x return x
}
} }
// Number function // Initialiser is a Number function
type Initialiser func(n int64) *Number type Initialiser func(n int64) *Number
// A Number represents a generic integer with a bounding function limiter. Limit is called after each operations // A Number represents a generic integer with a bounding function limiter. Limit is called after each operations
@ -51,65 +50,65 @@ type Number struct {
limit func(n *Number) *Number limit func(n *Number) *Number
} }
// Returns a new initialiser for a new *Number without having to expose certain fields // NewInitialiser returns a new initialiser for a new *Number without having to expose certain fields
func NewInitialiser(limiter func(*Number) *Number) Initialiser { func NewInitialiser(limiter func(*Number) *Number) Initialiser {
return func(n int64) *Number { return func(n int64) *Number {
return &Number{big.NewInt(n), limiter} return &Number{big.NewInt(n), limiter}
} }
} }
// Return a Number with a UNSIGNED limiter up to 256 bits // Uint256 returns a Number with a UNSIGNED limiter up to 256 bits
func Uint256(n int64) *Number { func Uint256(n int64) *Number {
return &Number{big.NewInt(n), limitUnsigned256} return &Number{big.NewInt(n), limitUnsigned256}
} }
// Return a Number with a SIGNED limiter up to 256 bits // Int256 returns Number with a SIGNED limiter up to 256 bits
func Int256(n int64) *Number { func Int256(n int64) *Number {
return &Number{big.NewInt(n), limitSigned256} return &Number{big.NewInt(n), limitSigned256}
} }
// Returns a Number with a SIGNED unlimited size // Big returns a Number with a SIGNED unlimited size
func Big(n int64) *Number { func Big(n int64) *Number {
return &Number{big.NewInt(n), func(x *Number) *Number { return x }} return &Number{big.NewInt(n), func(x *Number) *Number { return x }}
} }
// Sets i to sum of x+y // Add sets i to sum of x+y
func (i *Number) Add(x, y *Number) *Number { func (i *Number) Add(x, y *Number) *Number {
i.num.Add(x.num, y.num) i.num.Add(x.num, y.num)
return i.limit(i) return i.limit(i)
} }
// Sets i to difference of x-y // Sub sets i to difference of x-y
func (i *Number) Sub(x, y *Number) *Number { func (i *Number) Sub(x, y *Number) *Number {
i.num.Sub(x.num, y.num) i.num.Sub(x.num, y.num)
return i.limit(i) return i.limit(i)
} }
// Sets i to product of x*y // Mul sets i to product of x*y
func (i *Number) Mul(x, y *Number) *Number { func (i *Number) Mul(x, y *Number) *Number {
i.num.Mul(x.num, y.num) i.num.Mul(x.num, y.num)
return i.limit(i) return i.limit(i)
} }
// Sets i to the quotient prodject of x/y // Div sets i to the quotient prodject of x/y
func (i *Number) Div(x, y *Number) *Number { func (i *Number) Div(x, y *Number) *Number {
i.num.Div(x.num, y.num) i.num.Div(x.num, y.num)
return i.limit(i) return i.limit(i)
} }
// Sets i to x % y // Mod sets i to x % y
func (i *Number) Mod(x, y *Number) *Number { func (i *Number) Mod(x, y *Number) *Number {
i.num.Mod(x.num, y.num) i.num.Mod(x.num, y.num)
return i.limit(i) return i.limit(i)
} }
// Sets i to x << s // Lsh sets i to x << s
func (i *Number) Lsh(x *Number, s uint) *Number { func (i *Number) Lsh(x *Number, s uint) *Number {
i.num.Lsh(x.num, s) i.num.Lsh(x.num, s)
return i.limit(i) return i.limit(i)
} }
// Sets i to x^y // Pow sets i to x^y
func (i *Number) Pow(x, y *Number) *Number { func (i *Number) Pow(x, y *Number) *Number {
i.num.Exp(x.num, y.num, big.NewInt(0)) i.num.Exp(x.num, y.num, big.NewInt(0))
return i.limit(i) return i.limit(i)
@ -117,13 +116,13 @@ func (i *Number) Pow(x, y *Number) *Number {
// Setters // Setters
// Set x to i // Set sets x to i
func (i *Number) Set(x *Number) *Number { func (i *Number) Set(x *Number) *Number {
i.num.Set(x.num) i.num.Set(x.num)
return i.limit(i) return i.limit(i)
} }
// Set x bytes to i // SetBytes sets x bytes to i
func (i *Number) SetBytes(x []byte) *Number { func (i *Number) SetBytes(x []byte) *Number {
i.num.SetBytes(x) i.num.SetBytes(x)
return i.limit(i) return i.limit(i)
@ -140,12 +139,12 @@ func (i *Number) Cmp(x *Number) int {
// Getters // Getters
// Returns the string representation of i // String returns the string representation of i
func (i *Number) String() string { func (i *Number) String() string {
return i.num.String() return i.num.String()
} }
// Returns the byte representation of i // Bytes returns the byte representation of i
func (i *Number) Bytes() []byte { func (i *Number) Bytes() []byte {
return i.num.Bytes() return i.num.Bytes()
} }
@ -160,17 +159,17 @@ func (i *Number) Int64() int64 {
return i.num.Int64() return i.num.Int64()
} }
// Returns the signed version of i // Int256 returns the signed version of i
func (i *Number) Int256() *Number { func (i *Number) Int256() *Number {
return Int(0).Set(i) return Int(0).Set(i)
} }
// Returns the unsigned version of i // Uint256 returns the unsigned version of i
func (i *Number) Uint256() *Number { func (i *Number) Uint256() *Number {
return Uint(0).Set(i) return Uint(0).Set(i)
} }
// Returns the index of the first bit that's set to 1 // FirstBitSet returns the index of the first bit that's set to 1
func (i *Number) FirstBitSet() int { func (i *Number) FirstBitSet() int {
for j := 0; j < i.num.BitLen(); j++ { for j := 0; j < i.num.BitLen(); j++ {
if i.num.Bit(j) > 0 { if i.num.Bit(j) > 0 {

View file

@ -30,6 +30,7 @@ func MakeName(name, version string) string {
return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version()) return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version())
} }
// FileExist checks if a file exists at filePath.
func FileExist(filePath string) bool { func FileExist(filePath string) bool {
_, err := os.Stat(filePath) _, err := os.Stat(filePath)
if err != nil && os.IsNotExist(err) { if err != nil && os.IsNotExist(err) {
@ -39,9 +40,10 @@ func FileExist(filePath string) bool {
return true return true
} }
func AbsolutePath(Datadir string, filename string) string { // AbsolutePath returns datadir + filename, or filename if it is absolute.
func AbsolutePath(datadir string, filename string) string {
if filepath.IsAbs(filename) { if filepath.IsAbs(filename) {
return filename return filename
} }
return filepath.Join(Datadir, filename) return filepath.Join(datadir, filename)
} }

View file

@ -42,18 +42,29 @@ var (
// Hash represents the 32 byte Keccak256 hash of arbitrary data. // Hash represents the 32 byte Keccak256 hash of arbitrary data.
type Hash [HashLength]byte type Hash [HashLength]byte
// BytesToHash sets b to hash.
// If b is larger than len(h), b will be cropped from the left.
func BytesToHash(b []byte) Hash { func BytesToHash(b []byte) Hash {
var h Hash var h Hash
h.SetBytes(b) h.SetBytes(b)
return h return h
} }
// BigToHash sets byte representation of b to hash.
// If b is larger than len(h), b will be cropped from the left.
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
// HexToHash sets byte representation of s to hash.
// If b is larger than len(h), b will be cropped from the left.
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
// Get the string representation of the underlying hash // Bytes gets the byte representation of the underlying hash.
func (h Hash) Str() string { return string(h[:]) }
func (h Hash) Bytes() []byte { return h[:] } func (h Hash) Bytes() []byte { return h[:] }
// Big converts a hash to a big integer.
func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) } func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
// Hex converts a hash to a hex string.
func (h Hash) Hex() string { return hexutil.Encode(h[:]) } func (h Hash) Hex() string { return hexutil.Encode(h[:]) }
// TerminalString implements log.TerminalStringer, formatting a string for console // TerminalString implements log.TerminalStringer, formatting a string for console
@ -89,7 +100,8 @@ func (h Hash) MarshalText() ([]byte, error) {
return hexutil.Bytes(h[:]).MarshalText() return hexutil.Bytes(h[:]).MarshalText()
} }
// Sets the hash to the value of b. If b is larger than len(h), 'b' will be cropped (from the left). // SetBytes sets the hash to the value of b.
// If b is larger than len(h), b will be cropped from the left.
func (h *Hash) SetBytes(b []byte) { func (h *Hash) SetBytes(b []byte) {
if len(b) > len(h) { if len(b) > len(h) {
b = b[len(b)-HashLength:] b = b[len(b)-HashLength:]
@ -98,16 +110,6 @@ func (h *Hash) SetBytes(b []byte) {
copy(h[HashLength-len(b):], b) copy(h[HashLength-len(b):], b)
} }
// Set string `s` to h. If s is larger than len(h) s will be cropped (from left) to fit.
func (h *Hash) SetString(s string) { h.SetBytes([]byte(s)) }
// Sets h to other
func (h *Hash) Set(other Hash) {
for i, v := range other {
h[i] = v
}
}
// Generate implements testing/quick.Generator. // Generate implements testing/quick.Generator.
func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value { func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
m := rand.Intn(len(h)) m := rand.Intn(len(h))
@ -117,10 +119,6 @@ func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
return reflect.ValueOf(h) return reflect.ValueOf(h)
} }
func EmptyHash(h Hash) bool {
return h == Hash{}
}
// UnprefixedHash allows marshaling a Hash without 0x prefix. // UnprefixedHash allows marshaling a Hash without 0x prefix.
type UnprefixedHash Hash type UnprefixedHash Hash
@ -139,12 +137,20 @@ func (h UnprefixedHash) MarshalText() ([]byte, error) {
// Address represents the 20 byte address of an Ethereum account. // Address represents the 20 byte address of an Ethereum account.
type Address [AddressLength]byte type Address [AddressLength]byte
// BytesToAddress returns Address with value b.
// If b is larger than len(h), b will be cropped from the left.
func BytesToAddress(b []byte) Address { func BytesToAddress(b []byte) Address {
var a Address var a Address
a.SetBytes(b) a.SetBytes(b)
return a return a
} }
// BigToAddress returns Address with byte values of b.
// If b is larger than len(h), b will be cropped from the left.
func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
// HexToAddress returns Address with byte values of s.
// If s is larger than len(h), s will be cropped from the left.
func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
// IsHexAddress verifies whether a string can represent a valid hex-encoded // IsHexAddress verifies whether a string can represent a valid hex-encoded
@ -156,10 +162,13 @@ func IsHexAddress(s string) bool {
return len(s) == 2*AddressLength && isHex(s) return len(s) == 2*AddressLength && isHex(s)
} }
// Get the string representation of the underlying address // Bytes gets the string representation of the underlying address.
func (a Address) Str() string { return string(a[:]) }
func (a Address) Bytes() []byte { return a[:] } func (a Address) Bytes() []byte { return a[:] }
// Big converts an address to a big integer.
func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) } func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) }
// Hash converts an address to a hash by left-padding it with zeros.
func (a Address) Hash() Hash { return BytesToHash(a[:]) } func (a Address) Hash() Hash { return BytesToHash(a[:]) }
// Hex returns an EIP55-compliant hex string representation of the address. // Hex returns an EIP55-compliant hex string representation of the address.
@ -184,7 +193,7 @@ func (a Address) Hex() string {
return "0x" + string(result) return "0x" + string(result)
} }
// String implements the stringer interface and is used also by the logger. // String implements fmt.Stringer.
func (a Address) String() string { func (a Address) String() string {
return a.Hex() return a.Hex()
} }
@ -195,7 +204,8 @@ func (a Address) Format(s fmt.State, c rune) {
fmt.Fprintf(s, "%"+string(c), a[:]) fmt.Fprintf(s, "%"+string(c), a[:])
} }
// Sets the address to the value of b. If b is larger than len(a) it will panic // SetBytes sets the address to the value of b.
// If b is larger than len(a) it will panic.
func (a *Address) SetBytes(b []byte) { func (a *Address) SetBytes(b []byte) {
if len(b) > len(a) { if len(b) > len(a) {
b = b[len(b)-AddressLength:] b = b[len(b)-AddressLength:]
@ -203,16 +213,6 @@ func (a *Address) SetBytes(b []byte) {
copy(a[AddressLength-len(b):], b) copy(a[AddressLength-len(b):], b)
} }
// Set string `s` to a. If s is larger than len(a) it will panic
func (a *Address) SetString(s string) { a.SetBytes([]byte(s)) }
// Sets a to other
func (a *Address) Set(other Address) {
for i, v := range other {
a[i] = v
}
}
// MarshalText returns the hex representation of a. // MarshalText returns the hex representation of a.
func (a Address) MarshalText() ([]byte, error) { func (a Address) MarshalText() ([]byte, error) {
return hexutil.Bytes(a[:]).MarshalText() return hexutil.Bytes(a[:]).MarshalText()
@ -228,7 +228,7 @@ func (a *Address) UnmarshalJSON(input []byte) error {
return hexutil.UnmarshalFixedJSON(addressT, input, a[:]) return hexutil.UnmarshalFixedJSON(addressT, input, a[:])
} }
// UnprefixedHash allows marshaling an Address without 0x prefix. // UnprefixedAddress allows marshaling an Address without 0x prefix.
type UnprefixedAddress Address type UnprefixedAddress Address
// UnmarshalText decodes the address from hex. The 0x prefix is optional. // UnmarshalText decodes the address from hex. The 0x prefix is optional.

View file

@ -1,64 +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/>.
// +build none
//sed -e 's/_N_/Hash/g' -e 's/_S_/32/g' -e '1d' types_template.go | gofmt -w hash.go
package common
import "math/big"
type _N_ [_S_]byte
func BytesTo_N_(b []byte) _N_ {
var h _N_
h.SetBytes(b)
return h
}
func StringTo_N_(s string) _N_ { return BytesTo_N_([]byte(s)) }
func BigTo_N_(b *big.Int) _N_ { return BytesTo_N_(b.Bytes()) }
func HexTo_N_(s string) _N_ { return BytesTo_N_(FromHex(s)) }
// Don't use the default 'String' method in case we want to overwrite
// Get the string representation of the underlying hash
func (h _N_) Str() string { return string(h[:]) }
func (h _N_) Bytes() []byte { return h[:] }
func (h _N_) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
func (h _N_) Hex() string { return "0x" + Bytes2Hex(h[:]) }
// Sets the hash to the value of b. If b is larger than len(h) it will panic
func (h *_N_) SetBytes(b []byte) {
// Use the right most bytes
if len(b) > len(h) {
b = b[len(b)-_S_:]
}
// Reverse the loop
for i := len(b) - 1; i >= 0; i-- {
h[_S_-len(b)+i] = b[i]
}
}
// Set string `s` to h. If s is larger than len(h) it will panic
func (h *_N_) SetString(s string) { h.SetBytes([]byte(s)) }
// Sets h to other
func (h *_N_) Set(other _N_) {
for i, v := range other {
h[i] = v
}
}

View file

@ -383,7 +383,7 @@ func (c *Clique) snapshot(chain consensus.ChainReader, number uint64, hash commo
// If an on-disk checkpoint snapshot can be found, use that // If an on-disk checkpoint snapshot can be found, use that
if number%checkpointInterval == 0 { if number%checkpointInterval == 0 {
if s, err := loadSnapshot(c.config, c.signatures, c.db, hash); err == nil { if s, err := loadSnapshot(c.config, c.signatures, c.db, hash); err == nil {
log.Trace("Loaded voting snapshot form disk", "number", number, "hash", hash) log.Trace("Loaded voting snapshot from disk", "number", number, "hash", hash)
snap = s snap = s
break break
} }

View file

@ -352,7 +352,7 @@ func TestVoting(t *testing.T) {
copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:]) copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:])
} }
// Create a pristine blockchain with the genesis injected // Create a pristine blockchain with the genesis injected
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
genesis.Commit(db) genesis.Commit(db)
// Assemble a chain of headers from the cast votes // Assemble a chain of headers from the cast votes

View file

@ -149,7 +149,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
// Create the database in memory or in a temporary directory. // Create the database in memory or in a temporary directory.
var db ethdb.Database var db ethdb.Database
if !disk { if !disk {
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
} else { } else {
dir, err := ioutil.TempDir("", "eth-core-bench") dir, err := ioutil.TempDir("", "eth-core-bench")
if err != nil { if err != nil {

View file

@ -32,7 +32,7 @@ import (
func TestHeaderVerification(t *testing.T) { func TestHeaderVerification(t *testing.T) {
// Create a simple chain to verify // Create a simple chain to verify
var ( var (
testdb, _ = ethdb.NewMemDatabase() testdb = ethdb.NewMemDatabase()
gspec = &Genesis{Config: params.TestChainConfig} gspec = &Genesis{Config: params.TestChainConfig}
genesis = gspec.MustCommit(testdb) genesis = gspec.MustCommit(testdb)
blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil)
@ -84,7 +84,7 @@ func TestHeaderConcurrentVerification32(t *testing.T) { testHeaderConcurrentVeri
func testHeaderConcurrentVerification(t *testing.T, threads int) { func testHeaderConcurrentVerification(t *testing.T, threads int) {
// Create a simple chain to verify // Create a simple chain to verify
var ( var (
testdb, _ = ethdb.NewMemDatabase() testdb = ethdb.NewMemDatabase()
gspec = &Genesis{Config: params.TestChainConfig} gspec = &Genesis{Config: params.TestChainConfig}
genesis = gspec.MustCommit(testdb) genesis = gspec.MustCommit(testdb)
blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil)
@ -156,7 +156,7 @@ func TestHeaderConcurrentAbortion32(t *testing.T) { testHeaderConcurrentAbortion
func testHeaderConcurrentAbortion(t *testing.T, threads int) { func testHeaderConcurrentAbortion(t *testing.T, threads int) {
// Create a simple chain to verify // Create a simple chain to verify
var ( var (
testdb, _ = ethdb.NewMemDatabase() testdb = ethdb.NewMemDatabase()
gspec = &Genesis{Config: params.TestChainConfig} gspec = &Genesis{Config: params.TestChainConfig}
genesis = gspec.MustCommit(testdb) genesis = gspec.MustCommit(testdb)
blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 1024, nil) blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 1024, nil)

View file

@ -569,7 +569,7 @@ func testInsertNonceError(t *testing.T, full bool) {
func TestFastVsFullChains(t *testing.T) { func TestFastVsFullChains(t *testing.T) {
// Configure and generate a sample block chain // Configure and generate a sample block chain
var ( var (
gendb, _ = ethdb.NewMemDatabase() gendb = ethdb.NewMemDatabase()
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
@ -599,7 +599,7 @@ func TestFastVsFullChains(t *testing.T) {
} }
}) })
// Import the chain as an archive node for the comparison baseline // Import the chain as an archive node for the comparison baseline
archiveDb, _ := ethdb.NewMemDatabase() archiveDb := ethdb.NewMemDatabase()
gspec.MustCommit(archiveDb) gspec.MustCommit(archiveDb)
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
defer archive.Stop() defer archive.Stop()
@ -608,7 +608,7 @@ func TestFastVsFullChains(t *testing.T) {
t.Fatalf("failed to process block %d: %v", n, err) t.Fatalf("failed to process block %d: %v", n, err)
} }
// Fast import the chain as a non-archive node to test // Fast import the chain as a non-archive node to test
fastDb, _ := ethdb.NewMemDatabase() fastDb := ethdb.NewMemDatabase()
gspec.MustCommit(fastDb) gspec.MustCommit(fastDb)
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
defer fast.Stop() defer fast.Stop()
@ -657,7 +657,7 @@ func TestFastVsFullChains(t *testing.T) {
func TestLightVsFastVsFullChainHeads(t *testing.T) { func TestLightVsFastVsFullChainHeads(t *testing.T) {
// Configure and generate a sample block chain // Configure and generate a sample block chain
var ( var (
gendb, _ = ethdb.NewMemDatabase() gendb = ethdb.NewMemDatabase()
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
@ -685,7 +685,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
} }
} }
// Import the chain as an archive node and ensure all pointers are updated // Import the chain as an archive node and ensure all pointers are updated
archiveDb, _ := ethdb.NewMemDatabase() archiveDb := ethdb.NewMemDatabase()
gspec.MustCommit(archiveDb) gspec.MustCommit(archiveDb)
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
@ -699,7 +699,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
assert(t, "archive", archive, height/2, height/2, height/2) assert(t, "archive", archive, height/2, height/2, height/2)
// Import the chain as a non-archive node and ensure all pointers are updated // Import the chain as a non-archive node and ensure all pointers are updated
fastDb, _ := ethdb.NewMemDatabase() fastDb := ethdb.NewMemDatabase()
gspec.MustCommit(fastDb) gspec.MustCommit(fastDb)
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
defer fast.Stop() defer fast.Stop()
@ -719,7 +719,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
assert(t, "fast", fast, height/2, height/2, 0) assert(t, "fast", fast, height/2, height/2, 0)
// Import the chain as a light node and ensure all pointers are updated // Import the chain as a light node and ensure all pointers are updated
lightDb, _ := ethdb.NewMemDatabase() lightDb := ethdb.NewMemDatabase()
gspec.MustCommit(lightDb) gspec.MustCommit(lightDb)
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
@ -742,7 +742,7 @@ func TestChainTxReorgs(t *testing.T) {
addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr1 = crypto.PubkeyToAddress(key1.PublicKey)
addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey)
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
gspec = &Genesis{ gspec = &Genesis{
Config: params.TestChainConfig, Config: params.TestChainConfig,
GasLimit: 3141592, GasLimit: 3141592,
@ -854,7 +854,7 @@ func TestLogReorgs(t *testing.T) {
var ( var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr1 = crypto.PubkeyToAddress(key1.PublicKey)
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
// this code generates a log // this code generates a log
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}} gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
@ -898,7 +898,7 @@ func TestLogReorgs(t *testing.T) {
func TestReorgSideEvent(t *testing.T) { func TestReorgSideEvent(t *testing.T) {
var ( var (
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr1 = crypto.PubkeyToAddress(key1.PublicKey)
gspec = &Genesis{ gspec = &Genesis{
@ -1026,7 +1026,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
func TestEIP155Transition(t *testing.T) { func TestEIP155Transition(t *testing.T) {
// Configure and generate a sample block chain // Configure and generate a sample block chain
var ( var (
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
@ -1130,7 +1130,7 @@ func TestEIP155Transition(t *testing.T) {
func TestEIP161AccountRemoval(t *testing.T) { func TestEIP161AccountRemoval(t *testing.T) {
// Configure and generate a sample block chain // Configure and generate a sample block chain
var ( var (
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
@ -1202,7 +1202,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) {
// Generate a canonical chain to act as the main dataset // Generate a canonical chain to act as the main dataset
engine := ethash.NewFaker() engine := ethash.NewFaker()
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
genesis := new(Genesis).MustCommit(db) genesis := new(Genesis).MustCommit(db)
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
@ -1218,7 +1218,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) {
} }
// Import the canonical and fork chain side by side, verifying the current block // Import the canonical and fork chain side by side, verifying the current block
// and current header consistency // and current header consistency
diskdb, _ := ethdb.NewMemDatabase() diskdb := ethdb.NewMemDatabase()
new(Genesis).MustCommit(diskdb) new(Genesis).MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{})
@ -1247,7 +1247,7 @@ func TestTrieForkGC(t *testing.T) {
// Generate a canonical chain to act as the main dataset // Generate a canonical chain to act as the main dataset
engine := ethash.NewFaker() engine := ethash.NewFaker()
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
genesis := new(Genesis).MustCommit(db) genesis := new(Genesis).MustCommit(db)
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
@ -1262,7 +1262,7 @@ func TestTrieForkGC(t *testing.T) {
forks[i] = fork[0] forks[i] = fork[0]
} }
// Import the canonical and fork chain side by side, forcing the trie cache to cache both // Import the canonical and fork chain side by side, forcing the trie cache to cache both
diskdb, _ := ethdb.NewMemDatabase() diskdb := ethdb.NewMemDatabase()
new(Genesis).MustCommit(diskdb) new(Genesis).MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{})
@ -1293,7 +1293,7 @@ func TestLargeReorgTrieGC(t *testing.T) {
// Generate the original common chain segment and the two competing forks // Generate the original common chain segment and the two competing forks
engine := ethash.NewFaker() engine := ethash.NewFaker()
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
genesis := new(Genesis).MustCommit(db) genesis := new(Genesis).MustCommit(db)
shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
@ -1301,7 +1301,7 @@ func TestLargeReorgTrieGC(t *testing.T) {
competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*triesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*triesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) })
// Import the shared chain and the original canonical one // Import the shared chain and the original canonical one
diskdb, _ := ethdb.NewMemDatabase() diskdb := ethdb.NewMemDatabase()
new(Genesis).MustCommit(diskdb) new(Genesis).MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{})
@ -1361,7 +1361,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
) )
// Generate the original common chain segment and the two competing forks // Generate the original common chain segment and the two competing forks
engine := ethash.NewFaker() engine := ethash.NewFaker()
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
genesis := gspec.MustCommit(db) genesis := gspec.MustCommit(db)
blockGenerator := func(i int, block *BlockGen) { blockGenerator := func(i int, block *BlockGen) {
@ -1383,7 +1383,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
// Import the shared chain and the original canonical one // Import the shared chain and the original canonical one
diskdb, _ := ethdb.NewMemDatabase() diskdb := ethdb.NewMemDatabase()
gspec.MustCommit(diskdb) gspec.MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{})

View file

@ -48,7 +48,7 @@ func TestChainIndexerWithChildren(t *testing.T) {
// multiple backends. The section size and required confirmation count parameters // multiple backends. The section size and required confirmation count parameters
// are randomized. // are randomized.
func testChainIndexer(t *testing.T, count int) { func testChainIndexer(t *testing.T, count int) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
defer db.Close() defer db.Close()
// Create a chain of indexers and ensure they all report empty // Create a chain of indexers and ensure they all report empty

View file

@ -256,11 +256,12 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
// chain. Depending on the full flag, if creates either a full block chain or a // chain. Depending on the full flag, if creates either a full block chain or a
// header only chain. // header only chain.
func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) { func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) {
// Initialize a fresh chain with only a genesis block var (
gspec := new(Genesis) db = ethdb.NewMemDatabase()
db, _ := ethdb.NewMemDatabase() genesis = new(Genesis).MustCommit(db)
genesis := gspec.MustCommit(db) )
// Initialize a fresh chain with only a genesis block
blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}) blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{})
// Create and inject the requested chain // Create and inject the requested chain
if n == 0 { if n == 0 {

View file

@ -36,7 +36,7 @@ func ExampleGenerateChain() {
addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr1 = crypto.PubkeyToAddress(key1.PublicKey)
addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey)
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
) )
// Ensure that key1 has some funds in the genesis block. // Ensure that key1 has some funds in the genesis block.

View file

@ -32,13 +32,13 @@ func TestDAOForkRangeExtradata(t *testing.T) {
forkBlock := big.NewInt(32) forkBlock := big.NewInt(32)
// Generate a common prefix for both pro-forkers and non-forkers // Generate a common prefix for both pro-forkers and non-forkers
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
gspec := new(Genesis) gspec := new(Genesis)
genesis := gspec.MustCommit(db) genesis := gspec.MustCommit(db)
prefix, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) prefix, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
// Create the concurrent, conflicting two nodes // Create the concurrent, conflicting two nodes
proDb, _ := ethdb.NewMemDatabase() proDb := ethdb.NewMemDatabase()
gspec.MustCommit(proDb) gspec.MustCommit(proDb)
proConf := *params.TestChainConfig proConf := *params.TestChainConfig
@ -48,7 +48,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}) proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{})
defer proBc.Stop() defer proBc.Stop()
conDb, _ := ethdb.NewMemDatabase() conDb := ethdb.NewMemDatabase()
gspec.MustCommit(conDb) gspec.MustCommit(conDb)
conConf := *params.TestChainConfig conConf := *params.TestChainConfig
@ -67,7 +67,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
// Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks // Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
// Create a pro-fork block, and try to feed into the no-fork chain // Create a pro-fork block, and try to feed into the no-fork chain
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
gspec.MustCommit(db) gspec.MustCommit(db)
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}) bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{})
defer bc.Stop() defer bc.Stop()
@ -92,7 +92,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err) t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err)
} }
// Create a no-fork block, and try to feed into the pro-fork chain // Create a no-fork block, and try to feed into the pro-fork chain
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
gspec.MustCommit(db) gspec.MustCommit(db)
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}) bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{})
defer bc.Stop() defer bc.Stop()
@ -118,7 +118,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
} }
} }
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes // Verify that contra-forkers accept pro-fork extra-datas after forking finishes
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
gspec.MustCommit(db) gspec.MustCommit(db)
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}) bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{})
defer bc.Stop() defer bc.Stop()
@ -138,7 +138,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err) t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err)
} }
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes // Verify that pro-forkers accept contra-fork extra-datas after forking finishes
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
gspec.MustCommit(db) gspec.MustCommit(db)
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}) bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{})
defer bc.Stop() defer bc.Stop()

View file

@ -21,8 +21,8 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
) )
// TxPreEvent is posted when a transaction enters the transaction pool. // NewTxsEvent is posted when a batch of transactions enter the transaction pool.
type TxPreEvent struct{ Tx *types.Transaction } type NewTxsEvent struct{ Txs []*types.Transaction }
// PendingLogsEvent is posted pre mining and notifies of pending logs. // PendingLogsEvent is posted pre mining and notifies of pending logs.
type PendingLogsEvent struct { type PendingLogsEvent struct {
@ -35,9 +35,6 @@ type PendingStateEvent struct{}
// NewMinedBlockEvent is posted when a block has been imported. // NewMinedBlockEvent is posted when a block has been imported.
type NewMinedBlockEvent struct{ Block *types.Block } type NewMinedBlockEvent struct{ Block *types.Block }
// RemovedTransactionEvent is posted when a reorg happens
type RemovedTransactionEvent struct{ Txs types.Transactions }
// RemovedLogsEvent is posted when a reorg happens // RemovedLogsEvent is posted when a reorg happens
type RemovedLogsEvent struct{ Logs []*types.Log } type RemovedLogsEvent struct{ Logs []*types.Log }

View file

@ -222,7 +222,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
// to the given database (or discards it if nil). // to the given database (or discards it if nil).
func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
if db == nil { if db == nil {
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
} }
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
for addr, account := range g.Alloc { for addr, account := range g.Alloc {

View file

@ -141,7 +141,7 @@ func TestSetupGenesis(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
config, hash, err := test.fn(db) config, hash, err := test.fn(db)
// Check the return values. // Check the return values.
if !reflect.DeepEqual(err, test.wantErr) { if !reflect.DeepEqual(err, test.wantErr) {

View file

@ -18,7 +18,6 @@ package core
import ( import (
"container/list" "container/list"
"fmt"
"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"
@ -77,18 +76,11 @@ func (tm *TestManager) Db() ethdb.Database {
} }
func NewTestManager() *TestManager { func NewTestManager() *TestManager {
db, err := ethdb.NewMemDatabase()
if err != nil {
fmt.Println("Could not create mem-db, failing")
return nil
}
testManager := &TestManager{} testManager := &TestManager{}
testManager.eventMux = new(event.TypeMux) testManager.eventMux = new(event.TypeMux)
testManager.db = db testManager.db = ethdb.NewMemDatabase()
// testManager.txPool = NewTxPool(testManager) // testManager.txPool = NewTxPool(testManager)
// testManager.blockChain = NewBlockChain(testManager) // testManager.blockChain = NewBlockChain(testManager)
// testManager.stateManager = NewStateManager(testManager) // testManager.stateManager = NewStateManager(testManager)
return testManager return testManager
} }

View file

@ -30,7 +30,7 @@ import (
// Tests block header storage and retrieval operations. // Tests block header storage and retrieval operations.
func TestHeaderStorage(t *testing.T) { func TestHeaderStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
// 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")}
@ -63,7 +63,7 @@ func TestHeaderStorage(t *testing.T) {
// Tests block body storage and retrieval operations. // Tests block body storage and retrieval operations.
func TestBodyStorage(t *testing.T) { func TestBodyStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
// Create a test body to move around the database and make sure it's really new // Create a test body to move around the database and make sure it's really new
body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}} body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}}
@ -101,7 +101,7 @@ func TestBodyStorage(t *testing.T) {
// Tests block storage and retrieval operations. // Tests block storage and retrieval operations.
func TestBlockStorage(t *testing.T) { func TestBlockStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
// Create a test block to move around the database and make sure it's really new // Create a test block to move around the database and make sure it's really new
block := types.NewBlockWithHeader(&types.Header{ block := types.NewBlockWithHeader(&types.Header{
@ -151,7 +151,7 @@ func TestBlockStorage(t *testing.T) {
// Tests that partial block contents don't get reassembled into full blocks. // Tests that partial block contents don't get reassembled into full blocks.
func TestPartialBlockStorage(t *testing.T) { func TestPartialBlockStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
block := types.NewBlockWithHeader(&types.Header{ block := types.NewBlockWithHeader(&types.Header{
Extra: []byte("test block"), Extra: []byte("test block"),
UncleHash: types.EmptyUncleHash, UncleHash: types.EmptyUncleHash,
@ -185,7 +185,7 @@ func TestPartialBlockStorage(t *testing.T) {
// Tests block total difficulty storage and retrieval operations. // Tests block total difficulty storage and retrieval operations.
func TestTdStorage(t *testing.T) { func TestTdStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
// 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)
@ -208,7 +208,7 @@ func TestTdStorage(t *testing.T) {
// Tests that canonical numbers can be mapped to hashes and retrieved. // Tests that canonical numbers can be mapped to hashes and retrieved.
func TestCanonicalMappingStorage(t *testing.T) { func TestCanonicalMappingStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
// 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)
@ -231,7 +231,7 @@ func TestCanonicalMappingStorage(t *testing.T) {
// Tests that head headers and head blocks can be assigned, individually. // Tests that head headers and head blocks can be assigned, individually.
func TestHeadStorage(t *testing.T) { func TestHeadStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")}) blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")})
blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")}) blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")})
@ -266,7 +266,7 @@ func TestHeadStorage(t *testing.T) {
// 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()
receipt1 := &types.Receipt{ receipt1 := &types.Receipt{
Status: types.ReceiptStatusFailed, Status: types.ReceiptStatusFailed,

View file

@ -27,7 +27,7 @@ import (
// Tests that positional lookup metadata can be stored and retrieved. // Tests that positional lookup metadata can be stored and retrieved.
func TestLookupStorage(t *testing.T) { func TestLookupStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11}) 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}) tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22})

View file

@ -26,8 +26,7 @@ import (
var addr = common.BytesToAddress([]byte("test")) var addr = common.BytesToAddress([]byte("test"))
func create() (*ManagedState, *account) { func create() (*ManagedState, *account) {
db, _ := ethdb.NewMemDatabase() statedb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := New(common.Hash{}, NewDatabase(db))
ms := ManageState(statedb) ms := ManageState(statedb)
ms.StateDB.SetNonce(addr, 100) ms.StateDB.SetNonce(addr, 100)
ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr)) ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr))

View file

@ -87,7 +87,7 @@ func (s *StateSuite) TestDump(c *checker.C) {
} }
func (s *StateSuite) SetUpTest(c *checker.C) { func (s *StateSuite) SetUpTest(c *checker.C) {
s.db, _ = ethdb.NewMemDatabase() s.db = ethdb.NewMemDatabase()
s.state, _ = New(common.Hash{}, NewDatabase(s.db)) s.state, _ = New(common.Hash{}, NewDatabase(s.db))
} }
@ -99,7 +99,7 @@ func (s *StateSuite) TestNull(c *checker.C) {
s.state.SetState(address, common.Hash{}, value) s.state.SetState(address, common.Hash{}, value)
s.state.Commit(false) s.state.Commit(false)
value = s.state.GetState(address, common.Hash{}) value = s.state.GetState(address, common.Hash{})
if !common.EmptyHash(value) { if value != (common.Hash{}) {
c.Errorf("expected empty hash. got %x", value) c.Errorf("expected empty hash. got %x", value)
} }
} }
@ -133,8 +133,7 @@ func (s *StateSuite) TestSnapshotEmpty(c *checker.C) {
// use testing instead of checker because checker does not support // use testing instead of checker because checker does not support
// printing/logging in tests (-check.vv does not work) // printing/logging in tests (-check.vv does not work)
func TestSnapshot2(t *testing.T) { func TestSnapshot2(t *testing.T) {
db, _ := ethdb.NewMemDatabase() state, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
state, _ := New(common.Hash{}, NewDatabase(db))
stateobjaddr0 := toAddr([]byte("so0")) stateobjaddr0 := toAddr([]byte("so0"))
stateobjaddr1 := toAddr([]byte("so1")) stateobjaddr1 := toAddr([]byte("so1"))

View file

@ -39,7 +39,7 @@ import (
// actually committing the state. // actually committing the state.
func TestUpdateLeaks(t *testing.T) { func TestUpdateLeaks(t *testing.T) {
// Create an empty state database // Create an empty state database
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
state, _ := New(common.Hash{}, NewDatabase(db)) state, _ := New(common.Hash{}, NewDatabase(db))
// Update it with some accounts // Update it with some accounts
@ -66,8 +66,8 @@ func TestUpdateLeaks(t *testing.T) {
// only the one right before the commit. // only the one right before the commit.
func TestIntermediateLeaks(t *testing.T) { func TestIntermediateLeaks(t *testing.T) {
// Create two state databases, one transitioning to the final state, the other final from the beginning // Create two state databases, one transitioning to the final state, the other final from the beginning
transDb, _ := ethdb.NewMemDatabase() transDb := ethdb.NewMemDatabase()
finalDb, _ := ethdb.NewMemDatabase() finalDb := ethdb.NewMemDatabase()
transState, _ := New(common.Hash{}, NewDatabase(transDb)) transState, _ := New(common.Hash{}, NewDatabase(transDb))
finalState, _ := New(common.Hash{}, NewDatabase(finalDb)) finalState, _ := New(common.Hash{}, NewDatabase(finalDb))
@ -122,8 +122,7 @@ func TestIntermediateLeaks(t *testing.T) {
// https://github.com/ethereum/go-ethereum/pull/15549. // https://github.com/ethereum/go-ethereum/pull/15549.
func TestCopy(t *testing.T) { func TestCopy(t *testing.T) {
// Create a random state test to copy and modify "independently" // Create a random state test to copy and modify "independently"
db, _ := ethdb.NewMemDatabase() orig, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
orig, _ := New(common.Hash{}, NewDatabase(db))
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
@ -334,8 +333,7 @@ func (test *snapshotTest) String() string {
func (test *snapshotTest) run() bool { func (test *snapshotTest) run() bool {
// Run all actions and create snapshots. // Run all actions and create snapshots.
var ( var (
db, _ = ethdb.NewMemDatabase() state, _ = New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
state, _ = New(common.Hash{}, NewDatabase(db))
snapshotRevs = make([]int, len(test.snapshots)) snapshotRevs = make([]int, len(test.snapshots))
sindex = 0 sindex = 0
) )
@ -426,8 +424,7 @@ func (s *StateSuite) TestTouchDelete(c *check.C) {
// TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy.
// See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512 // See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512
func TestCopyOfCopy(t *testing.T) { func TestCopyOfCopy(t *testing.T) {
db, _ := ethdb.NewMemDatabase() sdb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
sdb, _ := New(common.Hash{}, NewDatabase(db))
addr := common.HexToAddress("aaaa") addr := common.HexToAddress("aaaa")
sdb.SetBalance(addr, big.NewInt(42)) sdb.SetBalance(addr, big.NewInt(42))

View file

@ -25,8 +25,8 @@ import (
) )
// NewStateSync create a new state trie download scheduler. // NewStateSync create a new state trie download scheduler.
func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.TrieSync { func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.Sync {
var syncer *trie.TrieSync var syncer *trie.Sync
callback := func(leaf []byte, parent common.Hash) error { callback := func(leaf []byte, parent common.Hash) error {
var obj Account var obj Account
if err := rlp.Decode(bytes.NewReader(leaf), &obj); err != nil { if err := rlp.Decode(bytes.NewReader(leaf), &obj); err != nil {
@ -36,6 +36,6 @@ func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.TrieSync
syncer.AddRawEntry(common.BytesToHash(obj.CodeHash), 64, parent) syncer.AddRawEntry(common.BytesToHash(obj.CodeHash), 64, parent)
return nil return nil
} }
syncer = trie.NewTrieSync(root, database, callback) syncer = trie.NewSync(root, database, callback)
return syncer return syncer
} }

View file

@ -38,8 +38,7 @@ type testAccount struct {
// makeTestState create a sample test state to test node-wise reconstruction. // makeTestState create a sample test state to test node-wise reconstruction.
func makeTestState() (Database, common.Hash, []*testAccount) { func makeTestState() (Database, common.Hash, []*testAccount) {
// Create an empty state // Create an empty state
diskdb, _ := ethdb.NewMemDatabase() db := NewDatabase(ethdb.NewMemDatabase())
db := NewDatabase(diskdb)
state, _ := New(common.Hash{}, db) state, _ := New(common.Hash{}, db)
// Fill it with some arbitrary data // Fill it with some arbitrary data
@ -125,8 +124,7 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error {
// Tests that an empty state is not scheduled for syncing. // Tests that an empty state is not scheduled for syncing.
func TestEmptyStateSync(t *testing.T) { func TestEmptyStateSync(t *testing.T) {
empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
db, _ := ethdb.NewMemDatabase() if req := NewStateSync(empty, ethdb.NewMemDatabase()).Missing(1); len(req) != 0 {
if req := NewStateSync(empty, db).Missing(1); len(req) != 0 {
t.Errorf("content requested for empty state: %v", req) t.Errorf("content requested for empty state: %v", req)
} }
} }
@ -141,7 +139,7 @@ func testIterativeStateSync(t *testing.T, batch int) {
srcDb, srcRoot, srcAccounts := makeTestState() srcDb, srcRoot, srcAccounts := makeTestState()
// Create a destination state and sync with the scheduler // Create a destination state and sync with the scheduler
dstDb, _ := ethdb.NewMemDatabase() dstDb := ethdb.NewMemDatabase()
sched := NewStateSync(srcRoot, dstDb) sched := NewStateSync(srcRoot, dstDb)
queue := append([]common.Hash{}, sched.Missing(batch)...) queue := append([]common.Hash{}, sched.Missing(batch)...)
@ -173,7 +171,7 @@ func TestIterativeDelayedStateSync(t *testing.T) {
srcDb, srcRoot, srcAccounts := makeTestState() srcDb, srcRoot, srcAccounts := makeTestState()
// Create a destination state and sync with the scheduler // Create a destination state and sync with the scheduler
dstDb, _ := ethdb.NewMemDatabase() dstDb := ethdb.NewMemDatabase()
sched := NewStateSync(srcRoot, dstDb) sched := NewStateSync(srcRoot, dstDb)
queue := append([]common.Hash{}, sched.Missing(0)...) queue := append([]common.Hash{}, sched.Missing(0)...)
@ -210,7 +208,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) {
srcDb, srcRoot, srcAccounts := makeTestState() srcDb, srcRoot, srcAccounts := makeTestState()
// Create a destination state and sync with the scheduler // Create a destination state and sync with the scheduler
dstDb, _ := ethdb.NewMemDatabase() dstDb := ethdb.NewMemDatabase()
sched := NewStateSync(srcRoot, dstDb) sched := NewStateSync(srcRoot, dstDb)
queue := make(map[common.Hash]struct{}) queue := make(map[common.Hash]struct{})
@ -250,7 +248,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
srcDb, srcRoot, srcAccounts := makeTestState() srcDb, srcRoot, srcAccounts := makeTestState()
// Create a destination state and sync with the scheduler // Create a destination state and sync with the scheduler
dstDb, _ := ethdb.NewMemDatabase() dstDb := ethdb.NewMemDatabase()
sched := NewStateSync(srcRoot, dstDb) sched := NewStateSync(srcRoot, dstDb)
queue := make(map[common.Hash]struct{}) queue := make(map[common.Hash]struct{})
@ -297,7 +295,7 @@ func TestIncompleteStateSync(t *testing.T) {
checkTrieConsistency(srcDb.TrieDB().DiskDB().(ethdb.Database), srcRoot) checkTrieConsistency(srcDb.TrieDB().DiskDB().(ethdb.Database), srcRoot)
// Create a destination state and sync with the scheduler // Create a destination state and sync with the scheduler
dstDb, _ := ethdb.NewMemDatabase() dstDb := ethdb.NewMemDatabase()
sched := NewStateSync(srcRoot, dstDb) sched := NewStateSync(srcRoot, dstDb)
added := []common.Hash{} added := []common.Hash{}

View file

@ -56,7 +56,7 @@ func newTxJournal(path string) *txJournal {
// load parses a transaction journal dump from disk, loading its contents into // load parses a transaction journal dump from disk, loading its contents into
// the specified pool. // the specified pool.
func (journal *txJournal) load(add func(*types.Transaction) error) error { func (journal *txJournal) load(add func([]*types.Transaction) []error) error {
// Skip the parsing if the journal file doens't exist at all // Skip the parsing if the journal file doens't exist at all
if _, err := os.Stat(journal.path); os.IsNotExist(err) { if _, err := os.Stat(journal.path); os.IsNotExist(err) {
return nil return nil
@ -76,7 +76,21 @@ func (journal *txJournal) load(add func(*types.Transaction) error) error {
stream := rlp.NewStream(input, 0) stream := rlp.NewStream(input, 0)
total, dropped := 0, 0 total, dropped := 0, 0
var failure error // Create a method to load a limited batch of transactions and bump the
// appropriate progress counters. Then use this method to load all the
// journalled transactions in small-ish batches.
loadBatch := func(txs types.Transactions) {
for _, err := range add(txs) {
if err != nil {
log.Debug("Failed to add journaled transaction", "err", err)
dropped++
}
}
}
var (
failure error
batch types.Transactions
)
for { for {
// Parse the next transaction and terminate on error // Parse the next transaction and terminate on error
tx := new(types.Transaction) tx := new(types.Transaction)
@ -84,14 +98,17 @@ func (journal *txJournal) load(add func(*types.Transaction) error) error {
if err != io.EOF { if err != io.EOF {
failure = err failure = err
} }
if batch.Len() > 0 {
loadBatch(batch)
}
break break
} }
// Import the transaction and bump the appropriate progress counters // New transaction parsed, queue up for later, import if threnshold is reached
total++ total++
if err = add(tx); err != nil {
log.Debug("Failed to add journaled transaction", "err", err) if batch = append(batch, tx); batch.Len() > 1024 {
dropped++ loadBatch(batch)
continue batch = batch[:0]
} }
} }
log.Info("Loaded local transaction journal", "transactions", total, "dropped", dropped) log.Info("Loaded local transaction journal", "transactions", total, "dropped", dropped)

View file

@ -397,13 +397,13 @@ func (h *priceHeap) Pop() interface{} {
// txPricedList is a price-sorted heap to allow operating on transactions pool // txPricedList is a price-sorted heap to allow operating on transactions pool
// contents in a price-incrementing way. // contents in a price-incrementing way.
type txPricedList struct { type txPricedList struct {
all *map[common.Hash]*types.Transaction // Pointer to the map of all transactions all *txLookup // Pointer to the map of all transactions
items *priceHeap // Heap of prices of all the stored transactions items *priceHeap // Heap of prices of all the stored transactions
stales int // Number of stale price points to (re-heap trigger) stales int // Number of stale price points to (re-heap trigger)
} }
// newTxPricedList creates a new price-sorted transaction heap. // newTxPricedList creates a new price-sorted transaction heap.
func newTxPricedList(all *map[common.Hash]*types.Transaction) *txPricedList { func newTxPricedList(all *txLookup) *txPricedList {
return &txPricedList{ return &txPricedList{
all: all, all: all,
items: new(priceHeap), items: new(priceHeap),
@ -425,12 +425,13 @@ func (l *txPricedList) Removed() {
return return
} }
// Seems we've reached a critical number of stale transactions, reheap // Seems we've reached a critical number of stale transactions, reheap
reheap := make(priceHeap, 0, len(*l.all)) reheap := make(priceHeap, 0, l.all.Count())
l.stales, l.items = 0, &reheap l.stales, l.items = 0, &reheap
for _, tx := range *l.all { l.all.Range(func(hash common.Hash, tx *types.Transaction) bool {
*l.items = append(*l.items, tx) *l.items = append(*l.items, tx)
} return true
})
heap.Init(l.items) heap.Init(l.items)
} }
@ -443,7 +444,7 @@ func (l *txPricedList) Cap(threshold *big.Int, local *accountSet) types.Transact
for len(*l.items) > 0 { for len(*l.items) > 0 {
// Discard stale transactions if found during cleanup // Discard stale transactions if found during cleanup
tx := heap.Pop(l.items).(*types.Transaction) tx := heap.Pop(l.items).(*types.Transaction)
if _, ok := (*l.all)[tx.Hash()]; !ok { if l.all.Get(tx.Hash()) == nil {
l.stales-- l.stales--
continue continue
} }
@ -475,7 +476,7 @@ func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) boo
// Discard stale price points if found at the heap start // Discard stale price points if found at the heap start
for len(*l.items) > 0 { for len(*l.items) > 0 {
head := []*types.Transaction(*l.items)[0] head := []*types.Transaction(*l.items)[0]
if _, ok := (*l.all)[head.Hash()]; !ok { if l.all.Get(head.Hash()) == nil {
l.stales-- l.stales--
heap.Pop(l.items) heap.Pop(l.items)
continue continue
@ -500,7 +501,7 @@ func (l *txPricedList) Discard(count int, local *accountSet) types.Transactions
for len(*l.items) > 0 && count > 0 { for len(*l.items) > 0 && count > 0 {
// Discard stale transactions if found during cleanup // Discard stale transactions if found during cleanup
tx := heap.Pop(l.items).(*types.Transaction) tx := heap.Pop(l.items).(*types.Transaction)
if _, ok := (*l.all)[tx.Hash()]; !ok { if l.all.Get(tx.Hash()) == nil {
l.stales-- l.stales--
continue continue
} }

View file

@ -203,7 +203,7 @@ type TxPool struct {
pending map[common.Address]*txList // All currently processable transactions pending map[common.Address]*txList // All currently processable transactions
queue map[common.Address]*txList // Queued but non-processable transactions queue map[common.Address]*txList // Queued but non-processable transactions
beats map[common.Address]time.Time // Last heartbeat from each known account beats map[common.Address]time.Time // Last heartbeat from each known account
all map[common.Hash]*types.Transaction // All transactions to allow lookups all *txLookup // All transactions to allow lookups
priced *txPricedList // All transactions sorted by price priced *txPricedList // All transactions sorted by price
wg sync.WaitGroup // for shutdown sync wg sync.WaitGroup // for shutdown sync
@ -226,19 +226,19 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
pending: make(map[common.Address]*txList), pending: make(map[common.Address]*txList),
queue: make(map[common.Address]*txList), queue: make(map[common.Address]*txList),
beats: make(map[common.Address]time.Time), beats: make(map[common.Address]time.Time),
all: make(map[common.Hash]*types.Transaction), all: newTxLookup(),
chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize), chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize),
gasPrice: new(big.Int).SetUint64(config.PriceLimit), gasPrice: new(big.Int).SetUint64(config.PriceLimit),
} }
pool.locals = newAccountSet(pool.signer) pool.locals = newAccountSet(pool.signer)
pool.priced = newTxPricedList(&pool.all) pool.priced = newTxPricedList(pool.all)
pool.reset(nil, chain.CurrentBlock().Header()) pool.reset(nil, chain.CurrentBlock().Header())
// If local transactions and journaling is enabled, load from disk // If local transactions and journaling is enabled, load from disk
if !config.NoLocals && config.Journal != "" { if !config.NoLocals && config.Journal != "" {
pool.journal = newTxJournal(config.Journal) pool.journal = newTxJournal(config.Journal)
if err := pool.journal.load(pool.AddLocal); err != nil { if err := pool.journal.load(pool.AddLocals); err != nil {
log.Warn("Failed to load transaction journal", "err", err) log.Warn("Failed to load transaction journal", "err", err)
} }
if err := pool.journal.rotate(pool.local()); err != nil { if err := pool.journal.rotate(pool.local()); err != nil {
@ -444,9 +444,9 @@ func (pool *TxPool) Stop() {
log.Info("Transaction pool stopped") log.Info("Transaction pool stopped")
} }
// SubscribeTxPreEvent registers a subscription of TxPreEvent and // SubscribeNewTxsEvent registers a subscription of NewTxsEvent and
// starts sending event to the given channel. // starts sending event to the given channel.
func (pool *TxPool) SubscribeTxPreEvent(ch chan<- TxPreEvent) event.Subscription { func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- NewTxsEvent) event.Subscription {
return pool.scope.Track(pool.txFeed.Subscribe(ch)) return pool.scope.Track(pool.txFeed.Subscribe(ch))
} }
@ -605,7 +605,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
// If the transaction is already known, discard it // If the transaction is already known, discard it
hash := tx.Hash() hash := tx.Hash()
if pool.all[hash] != nil { if pool.all.Get(hash) != nil {
log.Trace("Discarding already known transaction", "hash", hash) log.Trace("Discarding already known transaction", "hash", hash)
return false, fmt.Errorf("known transaction: %x", hash) return false, fmt.Errorf("known transaction: %x", hash)
} }
@ -616,7 +616,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
return false, err return false, err
} }
// 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(pool.all.Count()) >= 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 !local && 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())
@ -624,7 +624,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
return false, ErrUnderpriced return false, ErrUnderpriced
} }
// New transaction is better than our worse ones, make room for it // New transaction is better than our worse ones, make room for it
drop := pool.priced.Discard(len(pool.all)-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals) drop := pool.priced.Discard(pool.all.Count()-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals)
for _, tx := range drop { for _, tx := range drop {
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice()) log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice())
underpricedTxCounter.Inc(1) underpricedTxCounter.Inc(1)
@ -642,18 +642,18 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
} }
// New transaction is better, replace old one // New transaction is better, replace old one
if old != nil { if old != nil {
delete(pool.all, old.Hash()) pool.all.Remove(old.Hash())
pool.priced.Removed() pool.priced.Removed()
pendingReplaceCounter.Inc(1) pendingReplaceCounter.Inc(1)
} }
pool.all[tx.Hash()] = tx pool.all.Add(tx)
pool.priced.Put(tx) pool.priced.Put(tx)
pool.journalTx(from, tx) pool.journalTx(from, tx)
log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To())
// We've directly injected a replacement transaction, notify subsystems // We've directly injected a replacement transaction, notify subsystems
go pool.txFeed.Send(TxPreEvent{tx}) go pool.txFeed.Send(NewTxsEvent{types.Transactions{tx}})
return old != nil, nil return old != nil, nil
} }
@ -689,12 +689,12 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, er
} }
// Discard any previous transaction and mark this // Discard any previous transaction and mark this
if old != nil { if old != nil {
delete(pool.all, old.Hash()) pool.all.Remove(old.Hash())
pool.priced.Removed() pool.priced.Removed()
queuedReplaceCounter.Inc(1) queuedReplaceCounter.Inc(1)
} }
if pool.all[hash] == nil { if pool.all.Get(hash) == nil {
pool.all[hash] = tx pool.all.Add(tx)
pool.priced.Put(tx) pool.priced.Put(tx)
} }
return old != nil, nil return old != nil, nil
@ -712,10 +712,11 @@ func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) {
} }
} }
// promoteTx adds a transaction to the pending (processable) list of transactions. // promoteTx adds a transaction to the pending (processable) list of transactions
// and returns whether it was inserted or an older was better.
// //
// Note, this method assumes the pool lock is held! // Note, this method assumes the pool lock is held!
func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) { func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool {
// Try to insert the transaction into the pending queue // Try to insert the transaction into the pending queue
if pool.pending[addr] == nil { if pool.pending[addr] == nil {
pool.pending[addr] = newTxList(true) pool.pending[addr] = newTxList(true)
@ -725,29 +726,29 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T
inserted, old := list.Add(tx, pool.config.PriceBump) inserted, old := list.Add(tx, pool.config.PriceBump)
if !inserted { if !inserted {
// An older transaction was better, discard this // An older transaction was better, discard this
delete(pool.all, hash) pool.all.Remove(hash)
pool.priced.Removed() pool.priced.Removed()
pendingDiscardCounter.Inc(1) pendingDiscardCounter.Inc(1)
return return false
} }
// Otherwise discard any previous transaction and mark this // Otherwise discard any previous transaction and mark this
if old != nil { if old != nil {
delete(pool.all, old.Hash()) pool.all.Remove(old.Hash())
pool.priced.Removed() pool.priced.Removed()
pendingReplaceCounter.Inc(1) pendingReplaceCounter.Inc(1)
} }
// Failsafe to work around direct pending inserts (tests) // Failsafe to work around direct pending inserts (tests)
if pool.all[hash] == nil { if pool.all.Get(hash) == nil {
pool.all[hash] = tx pool.all.Add(tx)
pool.priced.Put(tx) pool.priced.Put(tx)
} }
// Set the potentially new pending nonce and notify any subsystems of the new tx // Set the potentially new pending nonce and notify any subsystems of the new tx
pool.beats[addr] = time.Now() pool.beats[addr] = time.Now()
pool.pendingState.SetNonce(addr, tx.Nonce()+1) pool.pendingState.SetNonce(addr, tx.Nonce()+1)
go pool.txFeed.Send(TxPreEvent{tx}) return true
} }
// AddLocal enqueues a single transaction into the pool if it is valid, marking // AddLocal enqueues a single transaction into the pool if it is valid, marking
@ -839,7 +840,7 @@ func (pool *TxPool) Status(hashes []common.Hash) []TxStatus {
status := make([]TxStatus, len(hashes)) status := make([]TxStatus, len(hashes))
for i, hash := range hashes { for i, hash := range hashes {
if tx := pool.all[hash]; tx != nil { if tx := pool.all.Get(hash); tx != nil {
from, _ := types.Sender(pool.signer, tx) // already validated from, _ := types.Sender(pool.signer, tx) // already validated
if pool.pending[from] != nil && pool.pending[from].txs.items[tx.Nonce()] != nil { if pool.pending[from] != nil && pool.pending[from].txs.items[tx.Nonce()] != nil {
status[i] = TxStatusPending status[i] = TxStatusPending
@ -854,24 +855,21 @@ func (pool *TxPool) Status(hashes []common.Hash) []TxStatus {
// Get returns a transaction if it is contained in the pool // Get returns a transaction if it is contained in the pool
// and nil otherwise. // and nil otherwise.
func (pool *TxPool) Get(hash common.Hash) *types.Transaction { func (pool *TxPool) Get(hash common.Hash) *types.Transaction {
pool.mu.RLock() return pool.all.Get(hash)
defer pool.mu.RUnlock()
return pool.all[hash]
} }
// removeTx removes a single transaction from the queue, moving all subsequent // removeTx removes a single transaction from the queue, moving all subsequent
// transactions back to the future queue. // transactions back to the future queue.
func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) { func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
// Fetch the transaction we wish to delete // Fetch the transaction we wish to delete
tx, ok := pool.all[hash] tx := pool.all.Get(hash)
if !ok { if tx == nil {
return return
} }
addr, _ := types.Sender(pool.signer, tx) // already validated during insertion addr, _ := types.Sender(pool.signer, tx) // already validated during insertion
// Remove it from the list of known transactions // Remove it from the list of known transactions
delete(pool.all, hash) pool.all.Remove(hash)
if outofbound { if outofbound {
pool.priced.Removed() pool.priced.Removed()
} }
@ -907,6 +905,9 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
// future queue to the set of pending transactions. During this process, all // future queue to the set of pending transactions. During this process, all
// invalidated transactions (low nonce, low balance) are deleted. // invalidated transactions (low nonce, low balance) are deleted.
func (pool *TxPool) promoteExecutables(accounts []common.Address) { func (pool *TxPool) promoteExecutables(accounts []common.Address) {
// Track the promoted transactions to broadcast them at once
var promoted []*types.Transaction
// Gather all the accounts potentially needing updates // Gather all the accounts potentially needing updates
if accounts == nil { if accounts == nil {
accounts = make([]common.Address, 0, len(pool.queue)) accounts = make([]common.Address, 0, len(pool.queue))
@ -924,7 +925,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) {
for _, tx := range list.Forward(pool.currentState.GetNonce(addr)) { for _, tx := range list.Forward(pool.currentState.GetNonce(addr)) {
hash := tx.Hash() hash := tx.Hash()
log.Trace("Removed old queued transaction", "hash", hash) log.Trace("Removed old queued transaction", "hash", hash)
delete(pool.all, hash) pool.all.Remove(hash)
pool.priced.Removed() pool.priced.Removed()
} }
// Drop all transactions that are too costly (low balance or out of gas) // Drop all transactions that are too costly (low balance or out of gas)
@ -932,21 +933,23 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) {
for _, tx := range drops { for _, tx := range drops {
hash := tx.Hash() hash := tx.Hash()
log.Trace("Removed unpayable queued transaction", "hash", hash) log.Trace("Removed unpayable queued transaction", "hash", hash)
delete(pool.all, hash) pool.all.Remove(hash)
pool.priced.Removed() pool.priced.Removed()
queuedNofundsCounter.Inc(1) queuedNofundsCounter.Inc(1)
} }
// Gather all executable transactions and promote them // Gather all executable transactions and promote them
for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) { for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) {
hash := tx.Hash() hash := tx.Hash()
if pool.promoteTx(addr, hash, tx) {
log.Trace("Promoting queued transaction", "hash", hash) log.Trace("Promoting queued transaction", "hash", hash)
pool.promoteTx(addr, hash, tx) promoted = append(promoted, tx)
}
} }
// Drop all transactions over the allowed limit // Drop all transactions over the allowed limit
if !pool.locals.contains(addr) { if !pool.locals.contains(addr) {
for _, tx := range list.Cap(int(pool.config.AccountQueue)) { for _, tx := range list.Cap(int(pool.config.AccountQueue)) {
hash := tx.Hash() hash := tx.Hash()
delete(pool.all, hash) pool.all.Remove(hash)
pool.priced.Removed() pool.priced.Removed()
queuedRateLimitCounter.Inc(1) queuedRateLimitCounter.Inc(1)
log.Trace("Removed cap-exceeding queued transaction", "hash", hash) log.Trace("Removed cap-exceeding queued transaction", "hash", hash)
@ -957,6 +960,10 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) {
delete(pool.queue, addr) delete(pool.queue, addr)
} }
} }
// Notify subsystem for new promoted transactions.
if len(promoted) > 0 {
pool.txFeed.Send(NewTxsEvent{promoted})
}
// If the pending limit is overflown, start equalizing allowances // If the pending limit is overflown, start equalizing allowances
pending := uint64(0) pending := uint64(0)
for _, list := range pool.pending { for _, list := range pool.pending {
@ -991,7 +998,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) {
for _, tx := range list.Cap(list.Len() - 1) { for _, tx := range list.Cap(list.Len() - 1) {
// Drop the transaction from the global pools too // Drop the transaction from the global pools too
hash := tx.Hash() hash := tx.Hash()
delete(pool.all, hash) pool.all.Remove(hash)
pool.priced.Removed() pool.priced.Removed()
// Update the account nonce to the dropped transaction // Update the account nonce to the dropped transaction
@ -1013,7 +1020,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) {
for _, tx := range list.Cap(list.Len() - 1) { for _, tx := range list.Cap(list.Len() - 1) {
// Drop the transaction from the global pools too // Drop the transaction from the global pools too
hash := tx.Hash() hash := tx.Hash()
delete(pool.all, hash) pool.all.Remove(hash)
pool.priced.Removed() pool.priced.Removed()
// Update the account nonce to the dropped transaction // Update the account nonce to the dropped transaction
@ -1082,7 +1089,7 @@ func (pool *TxPool) demoteUnexecutables() {
for _, tx := range list.Forward(nonce) { for _, tx := range list.Forward(nonce) {
hash := tx.Hash() hash := tx.Hash()
log.Trace("Removed old pending transaction", "hash", hash) log.Trace("Removed old pending transaction", "hash", hash)
delete(pool.all, hash) pool.all.Remove(hash)
pool.priced.Removed() pool.priced.Removed()
} }
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later // Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
@ -1090,7 +1097,7 @@ func (pool *TxPool) demoteUnexecutables() {
for _, tx := range drops { for _, tx := range drops {
hash := tx.Hash() hash := tx.Hash()
log.Trace("Removed unpayable pending transaction", "hash", hash) log.Trace("Removed unpayable pending transaction", "hash", hash)
delete(pool.all, hash) pool.all.Remove(hash)
pool.priced.Removed() pool.priced.Removed()
pendingNofundsCounter.Inc(1) pendingNofundsCounter.Inc(1)
} }
@ -1162,3 +1169,68 @@ func (as *accountSet) containsTx(tx *types.Transaction) bool {
func (as *accountSet) add(addr common.Address) { func (as *accountSet) add(addr common.Address) {
as.accounts[addr] = struct{}{} as.accounts[addr] = struct{}{}
} }
// txLookup is used internally by TxPool to track transactions while allowing lookup without
// mutex contention.
//
// Note, although this type is properly protected against concurrent access, it
// is **not** a type that should ever be mutated or even exposed outside of the
// transaction pool, since its internal state is tightly coupled with the pools
// internal mechanisms. The sole purpose of the type is to permit out-of-bound
// peeking into the pool in TxPool.Get without having to acquire the widely scoped
// TxPool.mu mutex.
type txLookup struct {
all map[common.Hash]*types.Transaction
lock sync.RWMutex
}
// newTxLookup returns a new txLookup structure.
func newTxLookup() *txLookup {
return &txLookup{
all: make(map[common.Hash]*types.Transaction),
}
}
// Range calls f on each key and value present in the map.
func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction) bool) {
t.lock.RLock()
defer t.lock.RUnlock()
for key, value := range t.all {
if !f(key, value) {
break
}
}
}
// Get returns a transaction if it exists in the lookup, or nil if not found.
func (t *txLookup) Get(hash common.Hash) *types.Transaction {
t.lock.RLock()
defer t.lock.RUnlock()
return t.all[hash]
}
// Count returns the current number of items in the lookup.
func (t *txLookup) Count() int {
t.lock.RLock()
defer t.lock.RUnlock()
return len(t.all)
}
// Add adds a transaction to the lookup.
func (t *txLookup) Add(tx *types.Transaction) {
t.lock.Lock()
defer t.lock.Unlock()
t.all[tx.Hash()] = tx
}
// Remove removes a transaction from the lookup.
func (t *txLookup) Remove(hash common.Hash) {
t.lock.Lock()
defer t.lock.Unlock()
delete(t.all, hash)
}

View file

@ -78,8 +78,7 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec
} }
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
diskdb, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(diskdb))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
@ -95,7 +94,7 @@ func validateTxPoolInternals(pool *TxPool) error {
// Ensure the total transaction set is consistent with pending + queued // Ensure the total transaction set is consistent with pending + queued
pending, queued := pool.stats() pending, queued := pool.stats()
if total := len(pool.all); total != pending+queued { if total := pool.all.Count(); total != pending+queued {
return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued) return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued)
} }
if priced := pool.priced.items.Len() - pool.priced.stales; priced != pending+queued { if priced := pool.priced.items.Len() - pool.priced.stales; priced != pending+queued {
@ -119,21 +118,27 @@ func validateTxPoolInternals(pool *TxPool) error {
// validateEvents checks that the correct number of transaction addition events // validateEvents checks that the correct number of transaction addition events
// were fired on the pool's event feed. // were fired on the pool's event feed.
func validateEvents(events chan TxPreEvent, count int) error { func validateEvents(events chan NewTxsEvent, count int) error {
for i := 0; i < count; i++ { var received []*types.Transaction
for len(received) < count {
select { select {
case <-events: case ev := <-events:
received = append(received, ev.Txs...)
case <-time.After(time.Second): case <-time.After(time.Second):
return fmt.Errorf("event #%d not fired", i) return fmt.Errorf("event #%d not fired", received)
} }
} }
if len(received) > count {
return fmt.Errorf("more than %d events fired: %v", count, received[count:])
}
select { select {
case tx := <-events: case ev := <-events:
return fmt.Errorf("more than %d events fired: %v", count, tx.Tx) return fmt.Errorf("more than %d events fired: %v", count, ev.Txs)
case <-time.After(50 * time.Millisecond): case <-time.After(50 * time.Millisecond):
// This branch should be "default", but it's a data race between goroutines, // This branch should be "default", but it's a data race between goroutines,
// reading the event channel and pushng into it, so better wait a bit ensuring // reading the event channel and pushing into it, so better wait a bit ensuring
// really nothing gets injected. // really nothing gets injected.
} }
return nil return nil
@ -158,8 +163,7 @@ func (c *testChain) State() (*state.StateDB, error) {
// a state change between those fetches. // a state change between those fetches.
stdb := c.statedb stdb := c.statedb
if *c.trigger { if *c.trigger {
db, _ := ethdb.NewMemDatabase() c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(db))
// simulate that the new head block included tx0 and tx1 // simulate that the new head block included tx0 and tx1
c.statedb.SetNonce(c.address, 2) c.statedb.SetNonce(c.address, 2)
c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether)) c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether))
@ -175,10 +179,9 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) {
t.Parallel() t.Parallel()
var ( var (
db, _ = ethdb.NewMemDatabase()
key, _ = crypto.GenerateKey() key, _ = crypto.GenerateKey()
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
trigger = false trigger = false
) )
@ -332,8 +335,7 @@ func TestTransactionChainFork(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() { resetState := func() {
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
statedb.AddBalance(addr, big.NewInt(100000000000000)) statedb.AddBalance(addr, big.NewInt(100000000000000))
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
@ -362,8 +364,7 @@ func TestTransactionDoubleNonce(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() { resetState := func() {
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
statedb.AddBalance(addr, big.NewInt(100000000000000)) statedb.AddBalance(addr, big.NewInt(100000000000000))
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
@ -400,8 +401,8 @@ func TestTransactionDoubleNonce(t *testing.T) {
t.Errorf("transaction mismatch: have %x, want %x", tx.Hash(), tx2.Hash()) t.Errorf("transaction mismatch: have %x, want %x", tx.Hash(), tx2.Hash())
} }
// Ensure the total transaction count is correct // Ensure the total transaction count is correct
if len(pool.all) != 1 { if pool.all.Count() != 1 {
t.Error("expected 1 total transactions, got", len(pool.all)) t.Error("expected 1 total transactions, got", pool.all.Count())
} }
} }
@ -423,8 +424,8 @@ func TestTransactionMissingNonce(t *testing.T) {
if pool.queue[addr].Len() != 1 { if pool.queue[addr].Len() != 1 {
t.Error("expected 1 queued transaction, got", pool.queue[addr].Len()) t.Error("expected 1 queued transaction, got", pool.queue[addr].Len())
} }
if len(pool.all) != 1 { if pool.all.Count() != 1 {
t.Error("expected 1 total transactions, got", len(pool.all)) t.Error("expected 1 total transactions, got", pool.all.Count())
} }
} }
@ -487,8 +488,8 @@ func TestTransactionDropping(t *testing.T) {
if pool.queue[account].Len() != 3 { if pool.queue[account].Len() != 3 {
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3) t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3)
} }
if len(pool.all) != 6 { if pool.all.Count() != 6 {
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 6) t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 6)
} }
pool.lockedReset(nil, nil) pool.lockedReset(nil, nil)
if pool.pending[account].Len() != 3 { if pool.pending[account].Len() != 3 {
@ -497,8 +498,8 @@ func TestTransactionDropping(t *testing.T) {
if pool.queue[account].Len() != 3 { if pool.queue[account].Len() != 3 {
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3) t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3)
} }
if len(pool.all) != 6 { if pool.all.Count() != 6 {
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 6) t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 6)
} }
// Reduce the balance of the account, and check that invalidated transactions are dropped // Reduce the balance of the account, and check that invalidated transactions are dropped
pool.currentState.AddBalance(account, big.NewInt(-650)) pool.currentState.AddBalance(account, big.NewInt(-650))
@ -522,8 +523,8 @@ func TestTransactionDropping(t *testing.T) {
if _, ok := pool.queue[account].txs.items[tx12.Nonce()]; ok { if _, ok := pool.queue[account].txs.items[tx12.Nonce()]; ok {
t.Errorf("out-of-fund queued transaction present: %v", tx11) t.Errorf("out-of-fund queued transaction present: %v", tx11)
} }
if len(pool.all) != 4 { if pool.all.Count() != 4 {
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 4) t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 4)
} }
// Reduce the block gas limit, check that invalidated transactions are dropped // Reduce the block gas limit, check that invalidated transactions are dropped
pool.chain.(*testBlockChain).gasLimit = 100 pool.chain.(*testBlockChain).gasLimit = 100
@ -541,8 +542,8 @@ func TestTransactionDropping(t *testing.T) {
if _, ok := pool.queue[account].txs.items[tx11.Nonce()]; ok { if _, ok := pool.queue[account].txs.items[tx11.Nonce()]; ok {
t.Errorf("over-gased queued transaction present: %v", tx11) t.Errorf("over-gased queued transaction present: %v", tx11)
} }
if len(pool.all) != 2 { if pool.all.Count() != 2 {
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 2) t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 2)
} }
} }
@ -553,8 +554,7 @@ func TestTransactionPostponing(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the postponing with // Create the pool to test the postponing with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
@ -596,8 +596,8 @@ func TestTransactionPostponing(t *testing.T) {
if len(pool.queue) != 0 { if len(pool.queue) != 0 {
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0) t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
} }
if len(pool.all) != len(txs) { if pool.all.Count() != len(txs) {
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs)) t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs))
} }
pool.lockedReset(nil, nil) pool.lockedReset(nil, nil)
if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) { if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) {
@ -606,8 +606,8 @@ func TestTransactionPostponing(t *testing.T) {
if len(pool.queue) != 0 { if len(pool.queue) != 0 {
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0) t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
} }
if len(pool.all) != len(txs) { if pool.all.Count() != len(txs) {
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs)) t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs))
} }
// Reduce the balance of the account, and check that transactions are reorganised // Reduce the balance of the account, and check that transactions are reorganised
for _, addr := range accs { for _, addr := range accs {
@ -656,8 +656,8 @@ func TestTransactionPostponing(t *testing.T) {
} }
} }
} }
if len(pool.all) != len(txs)/2 { if pool.all.Count() != len(txs)/2 {
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs)/2) t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs)/2)
} }
} }
@ -675,7 +675,7 @@ func TestTransactionGapFilling(t *testing.T) {
pool.currentState.AddBalance(account, big.NewInt(1000000)) pool.currentState.AddBalance(account, big.NewInt(1000000))
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan TxPreEvent, testTxPoolConfig.AccountQueue+5) events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue+5)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -748,8 +748,8 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
} }
} }
} }
if len(pool.all) != int(testTxPoolConfig.AccountQueue) { if pool.all.Count() != int(testTxPoolConfig.AccountQueue) {
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), testTxPoolConfig.AccountQueue) t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), testTxPoolConfig.AccountQueue)
} }
} }
@ -769,8 +769,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) {
t.Parallel() t.Parallel()
// Create the pool to test the limit enforcement with // Create the pool to test the limit enforcement with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig config := testTxPoolConfig
@ -858,8 +857,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
evictionInterval = time.Second evictionInterval = time.Second
// Create the pool to test the non-expiration enforcement // Create the pool to test the non-expiration enforcement
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig config := testTxPoolConfig
@ -928,7 +926,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
pool.currentState.AddBalance(account, big.NewInt(1000000)) pool.currentState.AddBalance(account, big.NewInt(1000000))
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan TxPreEvent, testTxPoolConfig.AccountQueue+5) events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue+5)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -944,8 +942,8 @@ func TestTransactionPendingLimiting(t *testing.T) {
t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), 0) t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), 0)
} }
} }
if len(pool.all) != int(testTxPoolConfig.AccountQueue+5) { if pool.all.Count() != int(testTxPoolConfig.AccountQueue+5) {
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), testTxPoolConfig.AccountQueue+5) t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), testTxPoolConfig.AccountQueue+5)
} }
if err := validateEvents(events, int(testTxPoolConfig.AccountQueue+5)); err != nil { if err := validateEvents(events, int(testTxPoolConfig.AccountQueue+5)); err != nil {
t.Fatalf("event firing failed: %v", err) t.Fatalf("event firing failed: %v", err)
@ -995,8 +993,8 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
if len(pool1.queue) != len(pool2.queue) { if len(pool1.queue) != len(pool2.queue) {
t.Errorf("queued transaction count mismatch: one-by-one algo: %d, batch algo: %d", len(pool1.queue), len(pool2.queue)) t.Errorf("queued transaction count mismatch: one-by-one algo: %d, batch algo: %d", len(pool1.queue), len(pool2.queue))
} }
if len(pool1.all) != len(pool2.all) { if pool1.all.Count() != pool2.all.Count() {
t.Errorf("total transaction count mismatch: one-by-one algo %d, batch algo %d", len(pool1.all), len(pool2.all)) t.Errorf("total transaction count mismatch: one-by-one algo %d, batch algo %d", pool1.all.Count(), pool2.all.Count())
} }
if err := validateTxPoolInternals(pool1); err != nil { if err := validateTxPoolInternals(pool1); err != nil {
t.Errorf("pool 1 internal state corrupted: %v", err) t.Errorf("pool 1 internal state corrupted: %v", err)
@ -1013,8 +1011,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the limit enforcement with // Create the pool to test the limit enforcement with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig config := testTxPoolConfig
@ -1060,8 +1057,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the limit enforcement with // Create the pool to test the limit enforcement with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig config := testTxPoolConfig
@ -1095,8 +1091,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the limit enforcement with // Create the pool to test the limit enforcement with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig config := testTxPoolConfig
@ -1144,15 +1139,14 @@ func TestTransactionPoolRepricing(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
defer pool.Stop() defer pool.Stop()
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan TxPreEvent, 32) events := make(chan NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -1266,8 +1260,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
@ -1329,8 +1322,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig config := testTxPoolConfig
@ -1341,7 +1333,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
defer pool.Stop() defer pool.Stop()
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan TxPreEvent, 32) events := make(chan NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -1436,8 +1428,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig config := testTxPoolConfig
@ -1448,7 +1439,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
defer pool.Stop() defer pool.Stop()
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan TxPreEvent, 32) events := make(chan NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -1503,15 +1494,14 @@ func TestTransactionReplacement(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
defer pool.Stop() defer pool.Stop()
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan TxPreEvent, 32) events := make(chan NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -1598,8 +1588,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
os.Remove(journal) os.Remove(journal)
// Create the original pool to inject transaction into the journal // Create the original pool to inject transaction into the journal
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig config := testTxPoolConfig
@ -1697,8 +1686,7 @@ func TestTransactionStatusCheck(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the status retrievals with // Create the pool to test the status retrievals with
db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)

View file

@ -12,10 +12,11 @@ import (
var _ = (*receiptMarshaling)(nil) var _ = (*receiptMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (r Receipt) MarshalJSON() ([]byte, error) { func (r Receipt) MarshalJSON() ([]byte, error) {
type Receipt struct { type Receipt struct {
PostState hexutil.Bytes `json:"root"` PostState hexutil.Bytes `json:"root"`
Status hexutil.Uint `json:"status"` Status hexutil.Uint64 `json:"status"`
CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"` CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
Bloom Bloom `json:"logsBloom" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"`
Logs []*Log `json:"logs" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"`
@ -25,7 +26,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
} }
var enc Receipt var enc Receipt
enc.PostState = r.PostState enc.PostState = r.PostState
enc.Status = hexutil.Uint(r.Status) enc.Status = hexutil.Uint64(r.Status)
enc.CumulativeGasUsed = hexutil.Uint64(r.CumulativeGasUsed) enc.CumulativeGasUsed = hexutil.Uint64(r.CumulativeGasUsed)
enc.Bloom = r.Bloom enc.Bloom = r.Bloom
enc.Logs = r.Logs enc.Logs = r.Logs
@ -35,10 +36,11 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
return json.Marshal(&enc) return json.Marshal(&enc)
} }
// UnmarshalJSON unmarshals from JSON.
func (r *Receipt) UnmarshalJSON(input []byte) error { func (r *Receipt) UnmarshalJSON(input []byte) error {
type Receipt struct { type Receipt struct {
PostState *hexutil.Bytes `json:"root"` PostState *hexutil.Bytes `json:"root"`
Status *hexutil.Uint `json:"status"` Status *hexutil.Uint64 `json:"status"`
CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"` CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
Bloom *Bloom `json:"logsBloom" gencodec:"required"` Bloom *Bloom `json:"logsBloom" gencodec:"required"`
Logs []*Log `json:"logs" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"`
@ -54,7 +56,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
r.PostState = *dec.PostState r.PostState = *dec.PostState
} }
if dec.Status != nil { if dec.Status != nil {
r.Status = uint(*dec.Status) r.Status = uint64(*dec.Status)
} }
if dec.CumulativeGasUsed == nil { if dec.CumulativeGasUsed == nil {
return errors.New("missing required field 'cumulativeGasUsed' for Receipt") return errors.New("missing required field 'cumulativeGasUsed' for Receipt")

View file

@ -36,17 +36,17 @@ var (
const ( const (
// ReceiptStatusFailed is the status code of a transaction if execution failed. // ReceiptStatusFailed is the status code of a transaction if execution failed.
ReceiptStatusFailed = uint(0) ReceiptStatusFailed = uint64(0)
// ReceiptStatusSuccessful is the status code of a transaction if execution succeeded. // ReceiptStatusSuccessful is the status code of a transaction if execution succeeded.
ReceiptStatusSuccessful = uint(1) ReceiptStatusSuccessful = uint64(1)
) )
// Receipt represents the results of a transaction. // Receipt represents the results of a transaction.
type Receipt struct { type Receipt struct {
// Consensus fields // Consensus fields
PostState []byte `json:"root"` PostState []byte `json:"root"`
Status uint `json:"status"` Status uint64 `json:"status"`
CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"` CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
Bloom Bloom `json:"logsBloom" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"`
Logs []*Log `json:"logs" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"`
@ -59,7 +59,7 @@ type Receipt struct {
type receiptMarshaling struct { type receiptMarshaling struct {
PostState hexutil.Bytes PostState hexutil.Bytes
Status hexutil.Uint Status hexutil.Uint64
CumulativeGasUsed hexutil.Uint64 CumulativeGasUsed hexutil.Uint64
GasUsed hexutil.Uint64 GasUsed hexutil.Uint64
} }

View file

@ -165,28 +165,13 @@ func TestTransactionPriceNonceSort(t *testing.T) {
t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce()) t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce())
} }
} }
// Find the previous and next nonce of this account
prev, next := i-1, i+1 // If the next tx has different from account, the price must be lower than the current one
for j := i - 1; j >= 0; j-- { if i+1 < len(txs) {
if fromj, _ := Sender(signer, txs[j]); fromi == fromj { next := txs[i+1]
prev = j fromNext, _ := Sender(signer, next)
break if fromi != fromNext && txi.GasPrice().Cmp(next.GasPrice()) < 0 {
} t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", i, fromi[:4], txi.GasPrice(), i+1, fromNext[:4], next.GasPrice())
}
for j := i + 1; j < len(txs); j++ {
if fromj, _ := Sender(signer, txs[j]); fromi == fromj {
next = j
break
}
}
// Make sure that in between the neighbor nonces, the transaction is correctly positioned price wise
for j := prev + 1; j < next; j++ {
fromj, _ := Sender(signer, txs[j])
if j < i && txs[j].GasPrice().Cmp(txi.GasPrice()) < 0 {
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice())
}
if j > i && txs[j].GasPrice().Cmp(txi.GasPrice()) > 0 {
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) > tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice())
} }
} }
} }

View file

@ -124,12 +124,12 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m
// 1. From a zero-value address to a non-zero value (NEW VALUE) // 1. From a zero-value address to a non-zero value (NEW VALUE)
// 2. From a non-zero value address to a zero-value address (DELETE) // 2. From a non-zero value address to a zero-value address (DELETE)
// 3. From a non-zero to a non-zero (CHANGE) // 3. From a non-zero to a non-zero (CHANGE)
if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { if val == (common.Hash{}) && y.Sign() != 0 {
// 0 => non 0 // 0 => non 0
return params.SstoreSetGas, nil return params.SstoreSetGas, nil
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { } else if val != (common.Hash{}) && y.Sign() == 0 {
// non 0 => 0
evm.StateDB.AddRefund(params.SstoreRefundGas) evm.StateDB.AddRefund(params.SstoreRefundGas)
return params.SstoreClearGas, nil return params.SstoreClearGas, nil
} else { } else {
// non 0 => non 0 (or 0 => 0) // non 0 => non 0 (or 0 => 0)

View file

@ -850,7 +850,7 @@ func makePush(size uint64, pushByteSize int) executionFunc {
} }
} }
// make push instruction function // make dup instruction function
func makeDup(size int64) executionFunc { func makeDup(size int64) executionFunc {
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.dup(evm.interpreter.intPool, int(size)) stack.dup(evm.interpreter.intPool, int(size))

View file

@ -33,7 +33,7 @@ type (
var errGasUintOverflow = errors.New("gas uint64 overflow") var errGasUintOverflow = errors.New("gas uint64 overflow")
type operation struct { type operation struct {
// op is the operation function // execute is the operation function
execute executionFunc execute executionFunc
// gasCost is the gas function and returns the gas required for execution // gasCost is the gas function and returns the gas required for execution
gasCost gasFunc gasCost gasFunc

View file

@ -99,8 +99,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
setDefaults(cfg) setDefaults(cfg)
if cfg.State == nil { if cfg.State == nil {
db, _ := ethdb.NewMemDatabase() cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db))
} }
var ( var (
address = common.BytesToAddress([]byte("contract")) address = common.BytesToAddress([]byte("contract"))
@ -130,8 +129,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
setDefaults(cfg) setDefaults(cfg)
if cfg.State == nil { if cfg.State == nil {
db, _ := ethdb.NewMemDatabase() cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db))
} }
var ( var (
vmenv = NewEnv(cfg) vmenv = NewEnv(cfg)

View file

@ -94,8 +94,7 @@ func TestExecute(t *testing.T) {
} }
func TestCall(t *testing.T) { func TestCall(t *testing.T) {
db, _ := ethdb.NewMemDatabase() state, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
state, _ := state.New(common.Hash{}, state.NewDatabase(db))
address := common.HexToAddress("0x0a") address := common.HexToAddress("0x0a")
state.SetCode(address, []byte{ state.SetCode(address, []byte{
byte(vm.PUSH1), 10, byte(vm.PUSH1), 10,

View file

@ -35,8 +35,8 @@ import (
) )
var ( var (
secp256k1_N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
secp256k1_halfN = new(big.Int).Div(secp256k1_N, big.NewInt(2)) secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
) )
// Keccak256 calculates and returns the Keccak256 hash of the input data. // Keccak256 calculates and returns the Keccak256 hash of the input data.
@ -68,7 +68,7 @@ func Keccak512(data ...[]byte) []byte {
return d.Sum(nil) return d.Sum(nil)
} }
// Creates an ethereum address given the bytes and the nonce // CreateAddress creates an ethereum address given the bytes and the nonce
func CreateAddress(b common.Address, nonce uint64) common.Address { func CreateAddress(b common.Address, nonce uint64) common.Address {
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce}) data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
return common.BytesToAddress(Keccak256(data)[12:]) return common.BytesToAddress(Keccak256(data)[12:])
@ -99,7 +99,7 @@ func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) {
priv.D = new(big.Int).SetBytes(d) priv.D = new(big.Int).SetBytes(d)
// The priv.D must < N // The priv.D must < N
if priv.D.Cmp(secp256k1_N) >= 0 { if priv.D.Cmp(secp256k1N) >= 0 {
return nil, fmt.Errorf("invalid private key, >=N") return nil, fmt.Errorf("invalid private key, >=N")
} }
// The priv.D must not be zero or negative. // The priv.D must not be zero or negative.
@ -184,11 +184,11 @@ func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
} }
// reject upper range of s values (ECDSA malleability) // reject upper range of s values (ECDSA malleability)
// see discussion in secp256k1/libsecp256k1/include/secp256k1.h // see discussion in secp256k1/libsecp256k1/include/secp256k1.h
if homestead && s.Cmp(secp256k1_halfN) > 0 { if homestead && s.Cmp(secp256k1halfN) > 0 {
return false return false
} }
// Frontier: allow s to be in full N range // Frontier: allow s to be in full N range
return r.Cmp(secp256k1_N) < 0 && s.Cmp(secp256k1_N) < 0 && (v == 0 || v == 1) return r.Cmp(secp256k1N) < 0 && s.Cmp(secp256k1N) < 0 && (v == 0 || v == 1)
} }
func PubkeyToAddress(p ecdsa.PublicKey) common.Address { func PubkeyToAddress(p ecdsa.PublicKey) common.Address {

View file

@ -154,7 +154,7 @@ func TestValidateSignatureValues(t *testing.T) {
minusOne := big.NewInt(-1) minusOne := big.NewInt(-1)
one := common.Big1 one := common.Big1
zero := common.Big0 zero := common.Big0
secp256k1nMinus1 := new(big.Int).Sub(secp256k1_N, common.Big1) secp256k1nMinus1 := new(big.Int).Sub(secp256k1N, common.Big1)
// correct v,r,s // correct v,r,s
check(true, 0, one, one) check(true, 0, one, one)
@ -181,9 +181,9 @@ func TestValidateSignatureValues(t *testing.T) {
// correct sig with max r,s // correct sig with max r,s
check(true, 0, secp256k1nMinus1, secp256k1nMinus1) check(true, 0, secp256k1nMinus1, secp256k1nMinus1)
// correct v, combinations of incorrect r,s at upper limit // correct v, combinations of incorrect r,s at upper limit
check(false, 0, secp256k1_N, secp256k1nMinus1) check(false, 0, secp256k1N, secp256k1nMinus1)
check(false, 0, secp256k1nMinus1, secp256k1_N) check(false, 0, secp256k1nMinus1, secp256k1N)
check(false, 0, secp256k1_N, secp256k1_N) check(false, 0, secp256k1N, secp256k1N)
// current callers ensures r,s cannot be negative, but let's test for that too // current callers ensures r,s cannot be negative, but let's test for that too
// as crypto package could be used stand-alone // as crypto package could be used stand-alone

View file

@ -77,7 +77,7 @@ func (BitCurve *BitCurve) Params() *elliptic.CurveParams {
} }
} }
// IsOnBitCurve returns true if the given (x,y) lies on the BitCurve. // IsOnCurve returns true if the given (x,y) lies on the BitCurve.
func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool {
// y² = x³ + b // y² = x³ + b
y2 := new(big.Int).Mul(y, y) //y² y2 := new(big.Int).Mul(y, y) //y²

View file

@ -49,7 +49,7 @@ func randSig() []byte {
// tests for malleability // tests for malleability
// highest bit of signature ECDSA s value must be 0, in the 33th byte // highest bit of signature ECDSA s value must be 0, in the 33th byte
func compactSigCheck(t *testing.T, sig []byte) { func compactSigCheck(t *testing.T, sig []byte) {
var b int = int(sig[32]) var b = int(sig[32])
if b < 0 { if b < 0 {
t.Errorf("highest bit is negative: %d", b) t.Errorf("highest bit is negative: %d", b)
} }

View file

@ -88,7 +88,7 @@ func VerifySignature(pubkey, hash, signature []byte) bool {
return false return false
} }
// Reject malleable signatures. libsecp256k1 does this check but btcec doesn't. // Reject malleable signatures. libsecp256k1 does this check but btcec doesn't.
if sig.S.Cmp(secp256k1_halfN) > 0 { if sig.S.Cmp(secp256k1halfN) > 0 {
return false return false
} }
return sig.Verify(hash, key) return sig.Verify(hash, key)

View file

@ -37,26 +37,26 @@ import (
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
// EthApiBackend implements ethapi.Backend for full nodes // EthAPIBackend implements ethapi.Backend for full nodes
type EthApiBackend struct { type EthAPIBackend struct {
eth *Ethereum eth *Ethereum
gpo *gasprice.Oracle gpo *gasprice.Oracle
} }
func (b *EthApiBackend) ChainConfig() *params.ChainConfig { func (b *EthAPIBackend) ChainConfig() *params.ChainConfig {
return b.eth.chainConfig return b.eth.chainConfig
} }
func (b *EthApiBackend) CurrentBlock() *types.Block { func (b *EthAPIBackend) CurrentBlock() *types.Block {
return b.eth.blockchain.CurrentBlock() return b.eth.blockchain.CurrentBlock()
} }
func (b *EthApiBackend) SetHead(number uint64) { func (b *EthAPIBackend) SetHead(number uint64) {
b.eth.protocolManager.downloader.Cancel() b.eth.protocolManager.downloader.Cancel()
b.eth.blockchain.SetHead(number) b.eth.blockchain.SetHead(number)
} }
func (b *EthApiBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
// Pending block is only known by the miner // Pending block is only known by the miner
if blockNr == rpc.PendingBlockNumber { if blockNr == rpc.PendingBlockNumber {
block := b.eth.miner.PendingBlock() block := b.eth.miner.PendingBlock()
@ -69,7 +69,7 @@ func (b *EthApiBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNum
return b.eth.blockchain.GetHeaderByNumber(uint64(blockNr)), nil return b.eth.blockchain.GetHeaderByNumber(uint64(blockNr)), nil
} }
func (b *EthApiBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) { func (b *EthAPIBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) {
// Pending block is only known by the miner // Pending block is only known by the miner
if blockNr == rpc.PendingBlockNumber { if blockNr == rpc.PendingBlockNumber {
block := b.eth.miner.PendingBlock() block := b.eth.miner.PendingBlock()
@ -82,7 +82,7 @@ func (b *EthApiBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumb
return b.eth.blockchain.GetBlockByNumber(uint64(blockNr)), nil return b.eth.blockchain.GetBlockByNumber(uint64(blockNr)), nil
} }
func (b *EthApiBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) { func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
// Pending state is only known by the miner // Pending state is only known by the miner
if blockNr == rpc.PendingBlockNumber { if blockNr == rpc.PendingBlockNumber {
block, state := b.eth.miner.Pending() block, state := b.eth.miner.Pending()
@ -97,18 +97,18 @@ func (b *EthApiBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.
return stateDb, header, err return stateDb, header, err
} }
func (b *EthApiBackend) GetBlock(ctx context.Context, hash common.Hash) (*types.Block, error) { func (b *EthAPIBackend) GetBlock(ctx context.Context, hash common.Hash) (*types.Block, error) {
return b.eth.blockchain.GetBlockByHash(hash), nil return b.eth.blockchain.GetBlockByHash(hash), nil
} }
func (b *EthApiBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil { if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil {
return rawdb.ReadReceipts(b.eth.chainDb, hash, *number), nil return rawdb.ReadReceipts(b.eth.chainDb, hash, *number), nil
} }
return nil, nil return nil, nil
} }
func (b *EthApiBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash) number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash)
if number == nil { if number == nil {
return nil, nil return nil, nil
@ -124,11 +124,11 @@ func (b *EthApiBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*typ
return logs, nil return logs, nil
} }
func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int { func (b *EthAPIBackend) GetTd(blockHash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(blockHash) return b.eth.blockchain.GetTdByHash(blockHash)
} }
func (b *EthApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) { func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {
state.SetBalance(msg.From(), math.MaxBig256) state.SetBalance(msg.From(), math.MaxBig256)
vmError := func() error { return nil } vmError := func() error { return nil }
@ -136,31 +136,31 @@ func (b *EthApiBackend) GetEVM(ctx context.Context, msg core.Message, state *sta
return vm.NewEVM(context, state, b.eth.chainConfig, vmCfg), vmError, nil return vm.NewEVM(context, state, b.eth.chainConfig, vmCfg), vmError, nil
} }
func (b *EthApiBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
return b.eth.BlockChain().SubscribeRemovedLogsEvent(ch) return b.eth.BlockChain().SubscribeRemovedLogsEvent(ch)
} }
func (b *EthApiBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { func (b *EthAPIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
return b.eth.BlockChain().SubscribeChainEvent(ch) return b.eth.BlockChain().SubscribeChainEvent(ch)
} }
func (b *EthApiBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { func (b *EthAPIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
return b.eth.BlockChain().SubscribeChainHeadEvent(ch) return b.eth.BlockChain().SubscribeChainHeadEvent(ch)
} }
func (b *EthApiBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { func (b *EthAPIBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
return b.eth.BlockChain().SubscribeChainSideEvent(ch) return b.eth.BlockChain().SubscribeChainSideEvent(ch)
} }
func (b *EthApiBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
return b.eth.BlockChain().SubscribeLogsEvent(ch) return b.eth.BlockChain().SubscribeLogsEvent(ch)
} }
func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
return b.eth.txPool.AddLocal(signedTx) return b.eth.txPool.AddLocal(signedTx)
} }
func (b *EthApiBackend) GetPoolTransactions() (types.Transactions, error) { func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
pending, err := b.eth.txPool.Pending() pending, err := b.eth.txPool.Pending()
if err != nil { if err != nil {
return nil, err return nil, err
@ -172,56 +172,56 @@ func (b *EthApiBackend) GetPoolTransactions() (types.Transactions, error) {
return txs, nil return txs, nil
} }
func (b *EthApiBackend) GetPoolTransaction(hash common.Hash) *types.Transaction { func (b *EthAPIBackend) GetPoolTransaction(hash common.Hash) *types.Transaction {
return b.eth.txPool.Get(hash) return b.eth.txPool.Get(hash)
} }
func (b *EthApiBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
return b.eth.txPool.State().GetNonce(addr), nil return b.eth.txPool.State().GetNonce(addr), nil
} }
func (b *EthApiBackend) Stats() (pending int, queued int) { func (b *EthAPIBackend) Stats() (pending int, queued int) {
return b.eth.txPool.Stats() return b.eth.txPool.Stats()
} }
func (b *EthApiBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { func (b *EthAPIBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
return b.eth.TxPool().Content() return b.eth.TxPool().Content()
} }
func (b *EthApiBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { func (b *EthAPIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return b.eth.TxPool().SubscribeTxPreEvent(ch) return b.eth.TxPool().SubscribeNewTxsEvent(ch)
} }
func (b *EthApiBackend) Downloader() *downloader.Downloader { func (b *EthAPIBackend) Downloader() *downloader.Downloader {
return b.eth.Downloader() return b.eth.Downloader()
} }
func (b *EthApiBackend) ProtocolVersion() int { func (b *EthAPIBackend) ProtocolVersion() int {
return b.eth.EthVersion() return b.eth.EthVersion()
} }
func (b *EthApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) { func (b *EthAPIBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
return b.gpo.SuggestPrice(ctx) return b.gpo.SuggestPrice(ctx)
} }
func (b *EthApiBackend) ChainDb() ethdb.Database { func (b *EthAPIBackend) ChainDb() ethdb.Database {
return b.eth.ChainDb() return b.eth.ChainDb()
} }
func (b *EthApiBackend) EventMux() *event.TypeMux { func (b *EthAPIBackend) EventMux() *event.TypeMux {
return b.eth.EventMux() return b.eth.EventMux()
} }
func (b *EthApiBackend) AccountManager() *accounts.Manager { func (b *EthAPIBackend) AccountManager() *accounts.Manager {
return b.eth.AccountManager() return b.eth.AccountManager()
} }
func (b *EthApiBackend) BloomStatus() (uint64, uint64) { func (b *EthAPIBackend) BloomStatus() (uint64, uint64) {
sections, _, _ := b.eth.bloomIndexer.Sections() sections, _, _ := b.eth.bloomIndexer.Sections()
return params.BloomBitsBlocks, sections return params.BloomBitsBlocks, sections
} }
func (b *EthApiBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
for i := 0; i < bloomFilterThreads; i++ { for i := 0; i < bloomFilterThreads; i++ {
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests) go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
} }

View file

@ -31,8 +31,7 @@ var dumper = spew.ConfigState{Indent: " "}
func TestStorageRangeAt(t *testing.T) { func TestStorageRangeAt(t *testing.T) {
// Create a state where account 0x010000... has a few storage entries. // Create a state where account 0x010000... has a few storage entries.
var ( var (
db, _ = ethdb.NewMemDatabase() state, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
state, _ = state.New(common.Hash{}, state.NewDatabase(db))
addr = common.Address{0x01} addr = common.Address{0x01}
keys = []common.Hash{ // hashes of Keys of storage keys = []common.Hash{ // hashes of Keys of storage
common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"), common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"),

View file

@ -82,7 +82,7 @@ type Ethereum struct {
bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
ApiBackend *EthApiBackend APIBackend *EthAPIBackend
miner *miner.Miner miner *miner.Miner
gasPrice *big.Int gasPrice *big.Int
@ -169,12 +169,12 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine) eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine)
eth.miner.SetExtra(makeExtraData(config.ExtraData)) eth.miner.SetExtra(makeExtraData(config.ExtraData))
eth.ApiBackend = &EthApiBackend{eth, nil} eth.APIBackend = &EthAPIBackend{eth, nil}
gpoParams := config.GPO gpoParams := config.GPO
if gpoParams.Default == nil { if gpoParams.Default == nil {
gpoParams.Default = config.GasPrice gpoParams.Default = config.GasPrice
} }
eth.ApiBackend.gpo = gasprice.NewOracle(eth.ApiBackend, gpoParams) eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
return eth, nil return eth, nil
} }
@ -215,14 +215,14 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chai
return clique.New(chainConfig.Clique, db) return clique.New(chainConfig.Clique, db)
} }
// Otherwise assume proof-of-work // Otherwise assume proof-of-work
switch { switch config.PowMode {
case config.PowMode == ethash.ModeFake: case ethash.ModeFake:
log.Warn("Ethash used in fake mode") log.Warn("Ethash used in fake mode")
return ethash.NewFaker() return ethash.NewFaker()
case config.PowMode == ethash.ModeTest: case ethash.ModeTest:
log.Warn("Ethash used in test mode") log.Warn("Ethash used in test mode")
return ethash.NewTester() return ethash.NewTester()
case config.PowMode == ethash.ModeShared: case ethash.ModeShared:
log.Warn("Ethash used in shared mode") log.Warn("Ethash used in shared mode")
return ethash.NewShared() return ethash.NewShared()
default: default:
@ -239,10 +239,10 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chai
} }
} }
// APIs returns the collection of RPC services the ethereum package offers. // APIs return the collection of RPC services the ethereum package offers.
// NOTE, some of these services probably need to be moved to somewhere else. // NOTE, some of these services probably need to be moved to somewhere else.
func (s *Ethereum) APIs() []rpc.API { func (s *Ethereum) APIs() []rpc.API {
apis := ethapi.GetAPIs(s.ApiBackend) apis := ethapi.GetAPIs(s.APIBackend)
// Append any APIs exposed explicitly by the consensus engine // Append any APIs exposed explicitly by the consensus engine
apis = append(apis, s.engine.APIs(s.BlockChain())...) apis = append(apis, s.engine.APIs(s.BlockChain())...)
@ -272,7 +272,7 @@ func (s *Ethereum) APIs() []rpc.API {
}, { }, {
Namespace: "eth", Namespace: "eth",
Version: "1.0", Version: "1.0",
Service: filters.NewPublicFilterAPI(s.ApiBackend, false), Service: filters.NewPublicFilterAPI(s.APIBackend, false),
Public: true, Public: true,
}, { }, {
Namespace: "admin", Namespace: "admin",

View file

@ -680,7 +680,7 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
} }
} }
// If the head fetch already found an ancestor, return // If the head fetch already found an ancestor, return
if !common.EmptyHash(hash) { if hash != (common.Hash{}) {
if int64(number) <= floor { if int64(number) <= floor {
p.log.Warn("Ancestor below allowance", "number", number, "hash", hash, "allowance", floor) p.log.Warn("Ancestor below allowance", "number", number, "hash", hash, "allowance", floor)
return 0, errInvalidAncestor return 0, errInvalidAncestor

View file

@ -75,7 +75,7 @@ type downloadTester struct {
// newTester creates a new downloader test mocker. // newTester creates a new downloader test mocker.
func newTester() *downloadTester { func newTester() *downloadTester {
testdb, _ := ethdb.NewMemDatabase() testdb := ethdb.NewMemDatabase()
genesis := core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000)) genesis := core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000))
tester := &downloadTester{ tester := &downloadTester{
@ -93,7 +93,7 @@ func newTester() *downloadTester {
peerChainTds: make(map[string]map[common.Hash]*big.Int), peerChainTds: make(map[string]map[common.Hash]*big.Int),
peerMissingStates: make(map[string]map[common.Hash]bool), peerMissingStates: make(map[string]map[common.Hash]bool),
} }
tester.stateDb, _ = ethdb.NewMemDatabase() tester.stateDb = ethdb.NewMemDatabase()
tester.stateDb.Put(genesis.Root().Bytes(), []byte{0x00}) tester.stateDb.Put(genesis.Root().Bytes(), []byte{0x00})
tester.downloader = New(FullSync, tester.stateDb, new(event.TypeMux), tester, nil, tester.dropPeer) tester.downloader = New(FullSync, tester.stateDb, new(event.TypeMux), tester, nil, tester.dropPeer)

View file

@ -214,7 +214,7 @@ func (d *Downloader) runStateSync(s *stateSync) *stateSync {
type stateSync struct { type stateSync struct {
d *Downloader // Downloader instance to access and manage current peerset d *Downloader // Downloader instance to access and manage current peerset
sched *trie.TrieSync // State trie sync scheduler defining the tasks sched *trie.Sync // State trie sync scheduler defining the tasks
keccak hash.Hash // Keccak256 hasher to verify deliveries with keccak hash.Hash // Keccak256 hasher to verify deliveries with
tasks map[common.Hash]*stateTask // Set of tasks currently queued for retrieval tasks map[common.Hash]*stateTask // Set of tasks currently queued for retrieval

View file

@ -292,20 +292,20 @@ func (f *Fetcher) loop() {
height := f.chainHeight() height := f.chainHeight()
for !f.queue.Empty() { for !f.queue.Empty() {
op := f.queue.PopItem().(*inject) op := f.queue.PopItem().(*inject)
hash := op.block.Hash()
if f.queueChangeHook != nil { if f.queueChangeHook != nil {
f.queueChangeHook(op.block.Hash(), false) f.queueChangeHook(hash, false)
} }
// If too high up the chain or phase, continue later // If too high up the chain or phase, continue later
number := op.block.NumberU64() number := op.block.NumberU64()
if number > height+1 { if number > height+1 {
f.queue.Push(op, -float32(op.block.NumberU64())) f.queue.Push(op, -float32(number))
if f.queueChangeHook != nil { if f.queueChangeHook != nil {
f.queueChangeHook(op.block.Hash(), true) f.queueChangeHook(hash, true)
} }
break break
} }
// Otherwise if fresh and still unknown, try and import // Otherwise if fresh and still unknown, try and import
hash := op.block.Hash()
if number+maxUncleDist < height || f.getBlock(hash) != nil { if number+maxUncleDist < height || f.getBlock(hash) != nil {
f.forgetBlock(hash) f.forgetBlock(hash)
continue continue

View file

@ -34,7 +34,7 @@ import (
) )
var ( var (
testdb, _ = ethdb.NewMemDatabase() testdb = ethdb.NewMemDatabase()
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testAddress = crypto.PubkeyToAddress(testKey.PublicKey) testAddress = crypto.PubkeyToAddress(testKey.PublicKey)
genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000)) genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000))

View file

@ -104,8 +104,8 @@ func (api *PublicFilterAPI) timeoutLoop() {
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newpendingtransactionfilter // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newpendingtransactionfilter
func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID { func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID {
var ( var (
pendingTxs = make(chan common.Hash) pendingTxs = make(chan []common.Hash)
pendingTxSub = api.events.SubscribePendingTxEvents(pendingTxs) pendingTxSub = api.events.SubscribePendingTxs(pendingTxs)
) )
api.filtersMu.Lock() api.filtersMu.Lock()
@ -118,7 +118,7 @@ func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID {
case ph := <-pendingTxs: case ph := <-pendingTxs:
api.filtersMu.Lock() api.filtersMu.Lock()
if f, found := api.filters[pendingTxSub.ID]; found { if f, found := api.filters[pendingTxSub.ID]; found {
f.hashes = append(f.hashes, ph) f.hashes = append(f.hashes, ph...)
} }
api.filtersMu.Unlock() api.filtersMu.Unlock()
case <-pendingTxSub.Err(): case <-pendingTxSub.Err():
@ -144,13 +144,17 @@ func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Su
rpcSub := notifier.CreateSubscription() rpcSub := notifier.CreateSubscription()
go func() { go func() {
txHashes := make(chan common.Hash) txHashes := make(chan []common.Hash, 128)
pendingTxSub := api.events.SubscribePendingTxEvents(txHashes) pendingTxSub := api.events.SubscribePendingTxs(txHashes)
for { for {
select { select {
case h := <-txHashes: case hashes := <-txHashes:
// To keep the original behaviour, send a single tx hash in one notification.
// TODO(rjl493456442) Send a batch of tx hashes in one notification
for _, h := range hashes {
notifier.Notify(rpcSub.ID, h) notifier.Notify(rpcSub.ID, h)
}
case <-rpcSub.Err(): case <-rpcSub.Err():
pendingTxSub.Unsubscribe() pendingTxSub.Unsubscribe()
return return
@ -268,14 +272,8 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc
} }
// FilterCriteria represents a request to create a new filter. // FilterCriteria represents a request to create a new filter.
// // Same as ethereum.FilterQuery but with UnmarshalJSON() method.
// TODO(karalabe): Kill this in favor of ethereum.FilterQuery. type FilterCriteria ethereum.FilterQuery
type FilterCriteria struct {
FromBlock *big.Int
ToBlock *big.Int
Addresses []common.Address
Topics [][]common.Hash
}
// NewFilter creates a new filter and returns the filter id. It can be // NewFilter creates a new filter and returns the filter id. It can be
// used to retrieve logs when the state changes. This method cannot be // used to retrieve logs when the state changes. This method cannot be

View file

@ -36,7 +36,7 @@ type Backend interface {
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription

View file

@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "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/log"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -58,7 +59,7 @@ const (
const ( const (
// txChanSize is the size of channel listening to TxPreEvent. // txChanSize is the size of channel listening to NewTxsEvent.
// The number is referenced from the size of tx pool. // The number is referenced from the size of tx pool.
txChanSize = 4096 txChanSize = 4096
// rmLogsChanSize is the size of channel listening to RemovedLogsEvent. // rmLogsChanSize is the size of channel listening to RemovedLogsEvent.
@ -79,7 +80,7 @@ type subscription struct {
created time.Time created time.Time
logsCrit ethereum.FilterQuery logsCrit ethereum.FilterQuery
logs chan []*types.Log logs chan []*types.Log
hashes chan common.Hash hashes chan []common.Hash
headers chan *types.Header headers chan *types.Header
installed chan struct{} // closed when the filter is installed installed chan struct{} // closed when the filter is installed
err chan error // closed when the filter is uninstalled err chan error // closed when the filter is uninstalled
@ -92,8 +93,21 @@ type EventSystem struct {
backend Backend backend Backend
lightMode bool lightMode bool
lastHead *types.Header lastHead *types.Header
// Subscriptions
txsSub event.Subscription // Subscription for new transaction event
logsSub event.Subscription // Subscription for new log event
rmLogsSub event.Subscription // Subscription for removed log event
chainSub event.Subscription // Subscription for new chain event
pendingLogSub *event.TypeMuxSubscription // Subscription for pending log event
// Channels
install chan *subscription // install filter for event notification install chan *subscription // install filter for event notification
uninstall chan *subscription // remove filter for event notification uninstall chan *subscription // remove filter for event notification
txsCh chan core.NewTxsEvent // Channel to receive new transactions event
logsCh chan []*types.Log // Channel to receive new log event
rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event
chainCh chan core.ChainEvent // Channel to receive new chain event
} }
// NewEventSystem creates a new manager that listens for event on the given mux, // NewEventSystem creates a new manager that listens for event on the given mux,
@ -109,10 +123,27 @@ func NewEventSystem(mux *event.TypeMux, backend Backend, lightMode bool) *EventS
lightMode: lightMode, lightMode: lightMode,
install: make(chan *subscription), install: make(chan *subscription),
uninstall: make(chan *subscription), uninstall: make(chan *subscription),
txsCh: make(chan core.NewTxsEvent, txChanSize),
logsCh: make(chan []*types.Log, logsChanSize),
rmLogsCh: make(chan core.RemovedLogsEvent, rmLogsChanSize),
chainCh: make(chan core.ChainEvent, chainEvChanSize),
}
// Subscribe events
m.txsSub = m.backend.SubscribeNewTxsEvent(m.txsCh)
m.logsSub = m.backend.SubscribeLogsEvent(m.logsCh)
m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh)
m.chainSub = m.backend.SubscribeChainEvent(m.chainCh)
// TODO(rjl493456442): use feed to subscribe pending log event
m.pendingLogSub = m.mux.Subscribe(core.PendingLogsEvent{})
// Make sure none of the subscriptions are empty
if m.txsSub == nil || m.logsSub == nil || m.rmLogsSub == nil || m.chainSub == nil ||
m.pendingLogSub.Closed() {
log.Crit("Subscribe for event system failed")
} }
go m.eventLoop() go m.eventLoop()
return m return m
} }
@ -209,7 +240,7 @@ func (es *EventSystem) subscribeMinedPendingLogs(crit ethereum.FilterQuery, logs
logsCrit: crit, logsCrit: crit,
created: time.Now(), created: time.Now(),
logs: logs, logs: logs,
hashes: make(chan common.Hash), hashes: make(chan []common.Hash),
headers: make(chan *types.Header), headers: make(chan *types.Header),
installed: make(chan struct{}), installed: make(chan struct{}),
err: make(chan error), err: make(chan error),
@ -226,7 +257,7 @@ func (es *EventSystem) subscribeLogs(crit ethereum.FilterQuery, logs chan []*typ
logsCrit: crit, logsCrit: crit,
created: time.Now(), created: time.Now(),
logs: logs, logs: logs,
hashes: make(chan common.Hash), hashes: make(chan []common.Hash),
headers: make(chan *types.Header), headers: make(chan *types.Header),
installed: make(chan struct{}), installed: make(chan struct{}),
err: make(chan error), err: make(chan error),
@ -243,7 +274,7 @@ func (es *EventSystem) subscribePendingLogs(crit ethereum.FilterQuery, logs chan
logsCrit: crit, logsCrit: crit,
created: time.Now(), created: time.Now(),
logs: logs, logs: logs,
hashes: make(chan common.Hash), hashes: make(chan []common.Hash),
headers: make(chan *types.Header), headers: make(chan *types.Header),
installed: make(chan struct{}), installed: make(chan struct{}),
err: make(chan error), err: make(chan error),
@ -259,7 +290,7 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti
typ: BlocksSubscription, typ: BlocksSubscription,
created: time.Now(), created: time.Now(),
logs: make(chan []*types.Log), logs: make(chan []*types.Log),
hashes: make(chan common.Hash), hashes: make(chan []common.Hash),
headers: headers, headers: headers,
installed: make(chan struct{}), installed: make(chan struct{}),
err: make(chan error), err: make(chan error),
@ -267,9 +298,9 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti
return es.subscribe(sub) return es.subscribe(sub)
} }
// SubscribePendingTxEvents creates a subscription that writes transaction hashes for // SubscribePendingTxs creates a subscription that writes transaction hashes for
// transactions that enter the transaction pool. // transactions that enter the transaction pool.
func (es *EventSystem) SubscribePendingTxEvents(hashes chan common.Hash) *Subscription { func (es *EventSystem) SubscribePendingTxs(hashes chan []common.Hash) *Subscription {
sub := &subscription{ sub := &subscription{
id: rpc.NewID(), id: rpc.NewID(),
typ: PendingTransactionsSubscription, typ: PendingTransactionsSubscription,
@ -317,9 +348,13 @@ func (es *EventSystem) broadcast(filters filterIndex, ev interface{}) {
} }
} }
} }
case core.TxPreEvent: case core.NewTxsEvent:
hashes := make([]common.Hash, 0, len(e.Txs))
for _, tx := range e.Txs {
hashes = append(hashes, tx.Hash())
}
for _, f := range filters[PendingTransactionsSubscription] { for _, f := range filters[PendingTransactionsSubscription] {
f.hashes <- e.Tx.Hash() f.hashes <- hashes
} }
case core.ChainEvent: case core.ChainEvent:
for _, f := range filters[BlocksSubscription] { for _, f := range filters[BlocksSubscription] {
@ -412,52 +447,37 @@ func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.
// eventLoop (un)installs filters and processes mux events. // eventLoop (un)installs filters and processes mux events.
func (es *EventSystem) eventLoop() { func (es *EventSystem) eventLoop() {
var ( // Ensure all subscriptions get cleaned up
index = make(filterIndex) defer func() {
sub = es.mux.Subscribe(core.PendingLogsEvent{}) es.pendingLogSub.Unsubscribe()
// Subscribe TxPreEvent form txpool es.txsSub.Unsubscribe()
txCh = make(chan core.TxPreEvent, txChanSize) es.logsSub.Unsubscribe()
txSub = es.backend.SubscribeTxPreEvent(txCh) es.rmLogsSub.Unsubscribe()
// Subscribe RemovedLogsEvent es.chainSub.Unsubscribe()
rmLogsCh = make(chan core.RemovedLogsEvent, rmLogsChanSize) }()
rmLogsSub = es.backend.SubscribeRemovedLogsEvent(rmLogsCh)
// Subscribe []*types.Log
logsCh = make(chan []*types.Log, logsChanSize)
logsSub = es.backend.SubscribeLogsEvent(logsCh)
// Subscribe ChainEvent
chainEvCh = make(chan core.ChainEvent, chainEvChanSize)
chainEvSub = es.backend.SubscribeChainEvent(chainEvCh)
)
// Unsubscribe all events
defer sub.Unsubscribe()
defer txSub.Unsubscribe()
defer rmLogsSub.Unsubscribe()
defer logsSub.Unsubscribe()
defer chainEvSub.Unsubscribe()
index := make(filterIndex)
for i := UnknownSubscription; i < LastIndexSubscription; i++ { for i := UnknownSubscription; i < LastIndexSubscription; i++ {
index[i] = make(map[rpc.ID]*subscription) index[i] = make(map[rpc.ID]*subscription)
} }
for { for {
select { select {
case ev, active := <-sub.Chan(): // Handle subscribed events
case ev := <-es.txsCh:
es.broadcast(index, ev)
case ev := <-es.logsCh:
es.broadcast(index, ev)
case ev := <-es.rmLogsCh:
es.broadcast(index, ev)
case ev := <-es.chainCh:
es.broadcast(index, ev)
case ev, active := <-es.pendingLogSub.Chan():
if !active { // system stopped if !active { // system stopped
return return
} }
es.broadcast(index, ev) es.broadcast(index, ev)
// Handle subscribed events
case ev := <-txCh:
es.broadcast(index, ev)
case ev := <-rmLogsCh:
es.broadcast(index, ev)
case ev := <-logsCh:
es.broadcast(index, ev)
case ev := <-chainEvCh:
es.broadcast(index, ev)
case f := <-es.install: case f := <-es.install:
if f.typ == MinedAndPendingLogsSubscription { if f.typ == MinedAndPendingLogsSubscription {
// the type are logs and pending logs subscriptions // the type are logs and pending logs subscriptions
@ -467,6 +487,7 @@ func (es *EventSystem) eventLoop() {
index[f.typ][f.id] = f index[f.typ][f.id] = f
} }
close(f.installed) close(f.installed)
case f := <-es.uninstall: case f := <-es.uninstall:
if f.typ == MinedAndPendingLogsSubscription { if f.typ == MinedAndPendingLogsSubscription {
// the type are logs and pending logs subscriptions // the type are logs and pending logs subscriptions
@ -478,13 +499,13 @@ func (es *EventSystem) eventLoop() {
close(f.err) close(f.err)
// System stopped // System stopped
case <-txSub.Err(): case <-es.txsSub.Err():
return return
case <-rmLogsSub.Err(): case <-es.logsSub.Err():
return return
case <-logsSub.Err(): case <-es.rmLogsSub.Err():
return return
case <-chainEvSub.Err(): case <-es.chainSub.Err():
return return
} }
} }

View file

@ -96,7 +96,7 @@ func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types
return logs, nil return logs, nil
} }
func (b *testBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return b.txFeed.Subscribe(ch) return b.txFeed.Subscribe(ch)
} }
@ -153,7 +153,7 @@ func TestBlockSubscription(t *testing.T) {
var ( var (
mux = new(event.TypeMux) mux = new(event.TypeMux)
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
txFeed = new(event.Feed) txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed) rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed) logsFeed = new(event.Feed)
@ -210,7 +210,7 @@ func TestPendingTxFilter(t *testing.T) {
var ( var (
mux = new(event.TypeMux) mux = new(event.TypeMux)
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
txFeed = new(event.Feed) txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed) rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed) logsFeed = new(event.Feed)
@ -232,10 +232,7 @@ func TestPendingTxFilter(t *testing.T) {
fid0 := api.NewPendingTransactionFilter() fid0 := api.NewPendingTransactionFilter()
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
for _, tx := range transactions { txFeed.Send(core.NewTxsEvent{Txs: transactions})
ev := core.TxPreEvent{Tx: tx}
txFeed.Send(ev)
}
timeout := time.Now().Add(1 * time.Second) timeout := time.Now().Add(1 * time.Second)
for { for {
@ -273,7 +270,7 @@ func TestPendingTxFilter(t *testing.T) {
func TestLogFilterCreation(t *testing.T) { func TestLogFilterCreation(t *testing.T) {
var ( var (
mux = new(event.TypeMux) mux = new(event.TypeMux)
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
txFeed = new(event.Feed) txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed) rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed) logsFeed = new(event.Feed)
@ -322,7 +319,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
var ( var (
mux = new(event.TypeMux) mux = new(event.TypeMux)
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
txFeed = new(event.Feed) txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed) rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed) logsFeed = new(event.Feed)
@ -352,7 +349,7 @@ func TestLogFilter(t *testing.T) {
var ( var (
mux = new(event.TypeMux) mux = new(event.TypeMux)
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
txFeed = new(event.Feed) txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed) rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed) logsFeed = new(event.Feed)
@ -471,7 +468,7 @@ func TestPendingLogsSubscription(t *testing.T) {
var ( var (
mux = new(event.TypeMux) mux = new(event.TypeMux)
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
txFeed = new(event.Feed) txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed) rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed) logsFeed = new(event.Feed)

View file

@ -46,7 +46,7 @@ const (
softResponseLimit = 2 * 1024 * 1024 // Target maximum size of returned blocks, headers or node data. softResponseLimit = 2 * 1024 * 1024 // Target maximum size of returned blocks, headers or node data.
estHeaderRlpSize = 500 // Approximate size of an RLP encoded block header estHeaderRlpSize = 500 // Approximate size of an RLP encoded block header
// txChanSize is the size of channel listening to TxPreEvent. // txChanSize is the size of channel listening to NewTxsEvent.
// The number is referenced from the size of tx pool. // The number is referenced from the size of tx pool.
txChanSize = 4096 txChanSize = 4096
) )
@ -81,8 +81,8 @@ type ProtocolManager struct {
SubProtocols []p2p.Protocol SubProtocols []p2p.Protocol
eventMux *event.TypeMux eventMux *event.TypeMux
txCh chan core.TxPreEvent txsCh chan core.NewTxsEvent
txSub event.Subscription txsSub event.Subscription
minedBlockSub *event.TypeMuxSubscription minedBlockSub *event.TypeMuxSubscription
// channels for fetcher, syncer, txsyncLoop // channels for fetcher, syncer, txsyncLoop
@ -204,8 +204,8 @@ func (pm *ProtocolManager) Start(maxPeers int) {
pm.maxPeers = maxPeers pm.maxPeers = maxPeers
// broadcast transactions // broadcast transactions
pm.txCh = make(chan core.TxPreEvent, txChanSize) pm.txsCh = make(chan core.NewTxsEvent, txChanSize)
pm.txSub = pm.txpool.SubscribeTxPreEvent(pm.txCh) pm.txsSub = pm.txpool.SubscribeNewTxsEvent(pm.txsCh)
go pm.txBroadcastLoop() go pm.txBroadcastLoop()
// broadcast mined blocks // broadcast mined blocks
@ -220,7 +220,7 @@ func (pm *ProtocolManager) Start(maxPeers int) {
func (pm *ProtocolManager) Stop() { func (pm *ProtocolManager) Stop() {
log.Info("Stopping Ethereum protocol") log.Info("Stopping Ethereum protocol")
pm.txSub.Unsubscribe() // quits txBroadcastLoop pm.txsSub.Unsubscribe() // quits txBroadcastLoop
pm.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop pm.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop
// Quit the sync loop. // Quit the sync loop.
@ -698,7 +698,7 @@ func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
// Send the block to a subset of our peers // Send the block to a subset of our peers
transfer := peers[:int(math.Sqrt(float64(len(peers))))] transfer := peers[:int(math.Sqrt(float64(len(peers))))]
for _, peer := range transfer { for _, peer := range transfer {
peer.SendNewBlock(block, td) peer.AsyncSendNewBlock(block, td)
} }
log.Trace("Propagated block", "hash", hash, "recipients", len(transfer), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) log.Trace("Propagated block", "hash", hash, "recipients", len(transfer), "duration", common.PrettyDuration(time.Since(block.ReceivedAt)))
return return
@ -706,22 +706,29 @@ func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
// Otherwise if the block is indeed in out own chain, announce it // Otherwise if the block is indeed in out own chain, announce it
if pm.blockchain.HasBlock(hash, block.NumberU64()) { if pm.blockchain.HasBlock(hash, block.NumberU64()) {
for _, peer := range peers { for _, peer := range peers {
peer.SendNewBlockHashes([]common.Hash{hash}, []uint64{block.NumberU64()}) peer.AsyncSendNewBlockHash(block)
} }
log.Trace("Announced block", "hash", hash, "recipients", len(peers), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) log.Trace("Announced block", "hash", hash, "recipients", len(peers), "duration", common.PrettyDuration(time.Since(block.ReceivedAt)))
} }
} }
// BroadcastTx will propagate a transaction to all peers which are not known to // BroadcastTxs will propagate a batch of transactions to all peers which are not known to
// already have the given transaction. // already have the given transaction.
func (pm *ProtocolManager) BroadcastTx(hash common.Hash, tx *types.Transaction) { func (pm *ProtocolManager) BroadcastTxs(txs types.Transactions) {
// Broadcast transaction to a batch of peers not knowing about it var txset = make(map[*peer]types.Transactions)
peers := pm.peers.PeersWithoutTx(hash)
//FIXME include this again: peers = peers[:int(math.Sqrt(float64(len(peers))))] // Broadcast transactions to a batch of peers not knowing about it
for _, tx := range txs {
peers := pm.peers.PeersWithoutTx(tx.Hash())
for _, peer := range peers { for _, peer := range peers {
peer.SendTransactions(types.Transactions{tx}) txset[peer] = append(txset[peer], tx)
}
log.Trace("Broadcast transaction", "hash", tx.Hash(), "recipients", len(peers))
}
// FIXME include this again: peers = peers[:int(math.Sqrt(float64(len(peers))))]
for peer, txs := range txset {
peer.AsyncSendTransactions(txs)
} }
log.Trace("Broadcast transaction", "hash", hash, "recipients", len(peers))
} }
// Mined broadcast loop // Mined broadcast loop
@ -739,11 +746,11 @@ func (pm *ProtocolManager) minedBroadcastLoop() {
func (pm *ProtocolManager) txBroadcastLoop() { func (pm *ProtocolManager) txBroadcastLoop() {
for { for {
select { select {
case event := <-pm.txCh: case event := <-pm.txsCh:
pm.BroadcastTx(event.Tx.Hash(), event.Tx) pm.BroadcastTxs(event.Txs)
// Err() channel will be closed when unsubscribing. // Err() channel will be closed when unsubscribing.
case <-pm.txSub.Err(): case <-pm.txsSub.Err():
return return
} }
} }

View file

@ -366,7 +366,7 @@ func testGetNodeData(t *testing.T, protocol int) {
t.Errorf("data hash mismatch: have %x, want %x", hash, want) t.Errorf("data hash mismatch: have %x, want %x", hash, want)
} }
} }
statedb, _ := ethdb.NewMemDatabase() statedb := ethdb.NewMemDatabase()
for i := 0; i < len(data); i++ { for i := 0; i < len(data); i++ {
statedb.Put(hashes[i].Bytes(), data[i]) statedb.Put(hashes[i].Bytes(), data[i])
} }
@ -468,7 +468,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
var ( var (
evmux = new(event.TypeMux) evmux = new(event.TypeMux)
pow = ethash.NewFaker() pow = ethash.NewFaker()
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
config = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked} config = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
gspec = &core.Genesis{Config: config} gspec = &core.Genesis{Config: config}
genesis = gspec.MustCommit(db) genesis = gspec.MustCommit(db)

View file

@ -53,7 +53,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func
var ( var (
evmux = new(event.TypeMux) evmux = new(event.TypeMux)
engine = ethash.NewFaker() engine = ethash.NewFaker()
db, _ = ethdb.NewMemDatabase() db = ethdb.NewMemDatabase()
gspec = &core.Genesis{ gspec = &core.Genesis{
Config: params.TestChainConfig, Config: params.TestChainConfig,
Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}}, Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
@ -124,7 +124,7 @@ func (p *testTxPool) Pending() (map[common.Address]types.Transactions, error) {
return batches, nil return batches, nil
} }
func (p *testTxPool) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { func (p *testTxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return p.txFeed.Subscribe(ch) return p.txFeed.Subscribe(ch)
} }

View file

@ -39,6 +39,22 @@ var (
const ( const (
maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS) maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS) maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS)
// maxQueuedTxs is the maximum number of transaction lists to queue up before
// dropping broadcasts. This is a sensitive number as a transaction list might
// contain a single transaction, or thousands.
maxQueuedTxs = 128
// maxQueuedProps is the maximum number of block propagations to queue up before
// dropping broadcasts. There's not much point in queueing stale blocks, so a few
// that might cover uncles should be enough.
maxQueuedProps = 4
// maxQueuedAnns is the maximum number of block announcements to queue up before
// dropping broadcasts. Similarly to block propagations, there's no point to queue
// above some healthy uncle limit, so use that.
maxQueuedAnns = 4
handshakeTimeout = 5 * time.Second handshakeTimeout = 5 * time.Second
) )
@ -50,6 +66,12 @@ type PeerInfo struct {
Head string `json:"head"` // SHA3 hash of the peer's best owned block Head string `json:"head"` // SHA3 hash of the peer's best owned block
} }
// propEvent is a block propagation, waiting for its turn in the broadcast queue.
type propEvent struct {
block *types.Block
td *big.Int
}
type peer struct { type peer struct {
id string id string
@ -65,21 +87,62 @@ type peer struct {
knownTxs *set.Set // Set of transaction hashes known to be known by this peer knownTxs *set.Set // Set of transaction hashes known to be known by this peer
knownBlocks *set.Set // Set of block hashes known to be known by this peer knownBlocks *set.Set // Set of block hashes known to be known by this peer
queuedTxs chan []*types.Transaction // Queue of transactions to broadcast to the peer
queuedProps chan *propEvent // Queue of blocks to broadcast to the peer
queuedAnns chan *types.Block // Queue of blocks to announce to the peer
term chan struct{} // Termination channel to stop the broadcaster
} }
func newPeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { func newPeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
id := p.ID()
return &peer{ return &peer{
Peer: p, Peer: p,
rw: rw, rw: rw,
version: version, version: version,
id: fmt.Sprintf("%x", id[:8]), id: fmt.Sprintf("%x", p.ID().Bytes()[:8]),
knownTxs: set.New(), knownTxs: set.New(),
knownBlocks: set.New(), knownBlocks: set.New(),
queuedTxs: make(chan []*types.Transaction, maxQueuedTxs),
queuedProps: make(chan *propEvent, maxQueuedProps),
queuedAnns: make(chan *types.Block, maxQueuedAnns),
term: make(chan struct{}),
} }
} }
// broadcast is a write loop that multiplexes block propagations, announcements
// and transaction broadcasts into the remote peer. The goal is to have an async
// writer that does not lock up node internals.
func (p *peer) broadcast() {
for {
select {
case txs := <-p.queuedTxs:
if err := p.SendTransactions(txs); err != nil {
return
}
p.Log().Trace("Broadcast transactions", "count", len(txs))
case prop := <-p.queuedProps:
if err := p.SendNewBlock(prop.block, prop.td); err != nil {
return
}
p.Log().Trace("Propagated block", "number", prop.block.Number(), "hash", prop.block.Hash(), "td", prop.td)
case block := <-p.queuedAnns:
if err := p.SendNewBlockHashes([]common.Hash{block.Hash()}, []uint64{block.NumberU64()}); err != nil {
return
}
p.Log().Trace("Announced block", "number", block.Number(), "hash", block.Hash())
case <-p.term:
return
}
}
}
// close signals the broadcast goroutine to terminate.
func (p *peer) close() {
close(p.term)
}
// Info gathers and returns a collection of metadata known about a peer. // Info gathers and returns a collection of metadata known about a peer.
func (p *peer) Info() *PeerInfo { func (p *peer) Info() *PeerInfo {
hash, td := p.Head() hash, td := p.Head()
@ -139,6 +202,19 @@ func (p *peer) SendTransactions(txs types.Transactions) error {
return p2p.Send(p.rw, TxMsg, txs) return p2p.Send(p.rw, TxMsg, txs)
} }
// AsyncSendTransactions queues list of transactions propagation to a remote
// peer. If the peer's broadcast queue is full, the event is silently dropped.
func (p *peer) AsyncSendTransactions(txs []*types.Transaction) {
select {
case p.queuedTxs <- txs:
for _, tx := range txs {
p.knownTxs.Add(tx.Hash())
}
default:
p.Log().Debug("Dropping transaction propagation", "count", len(txs))
}
}
// SendNewBlockHashes announces the availability of a number of blocks through // SendNewBlockHashes announces the availability of a number of blocks through
// a hash notification. // a hash notification.
func (p *peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error { func (p *peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error {
@ -153,12 +229,35 @@ func (p *peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error
return p2p.Send(p.rw, NewBlockHashesMsg, request) return p2p.Send(p.rw, NewBlockHashesMsg, request)
} }
// AsyncSendNewBlockHash queues the availability of a block for propagation to a
// remote peer. If the peer's broadcast queue is full, the event is silently
// dropped.
func (p *peer) AsyncSendNewBlockHash(block *types.Block) {
select {
case p.queuedAnns <- block:
p.knownBlocks.Add(block.Hash())
default:
p.Log().Debug("Dropping block announcement", "number", block.NumberU64(), "hash", block.Hash())
}
}
// SendNewBlock propagates an entire block to a remote peer. // SendNewBlock propagates an entire block to a remote peer.
func (p *peer) SendNewBlock(block *types.Block, td *big.Int) error { func (p *peer) SendNewBlock(block *types.Block, td *big.Int) error {
p.knownBlocks.Add(block.Hash()) p.knownBlocks.Add(block.Hash())
return p2p.Send(p.rw, NewBlockMsg, []interface{}{block, td}) return p2p.Send(p.rw, NewBlockMsg, []interface{}{block, td})
} }
// AsyncSendNewBlock queues an entire block for propagation to a remote peer. If
// the peer's broadcast queue is full, the event is silently dropped.
func (p *peer) AsyncSendNewBlock(block *types.Block, td *big.Int) {
select {
case p.queuedProps <- &propEvent{block: block, td: td}:
p.knownBlocks.Add(block.Hash())
default:
p.Log().Debug("Dropping block propagation", "number", block.NumberU64(), "hash", block.Hash())
}
}
// SendBlockHeaders sends a batch of block headers to the remote peer. // SendBlockHeaders sends a batch of block headers to the remote peer.
func (p *peer) SendBlockHeaders(headers []*types.Header) error { func (p *peer) SendBlockHeaders(headers []*types.Header) error {
return p2p.Send(p.rw, BlockHeadersMsg, headers) return p2p.Send(p.rw, BlockHeadersMsg, headers)
@ -313,7 +412,8 @@ func newPeerSet() *peerSet {
} }
// Register injects a new peer into the working set, or returns an error if the // Register injects a new peer into the working set, or returns an error if the
// peer is already known. // peer is already known. If a new peer it registered, its broadcast loop is also
// started.
func (ps *peerSet) Register(p *peer) error { func (ps *peerSet) Register(p *peer) error {
ps.lock.Lock() ps.lock.Lock()
defer ps.lock.Unlock() defer ps.lock.Unlock()
@ -325,6 +425,8 @@ func (ps *peerSet) Register(p *peer) error {
return errAlreadyRegistered return errAlreadyRegistered
} }
ps.peers[p.id] = p ps.peers[p.id] = p
go p.broadcast()
return nil return nil
} }
@ -334,10 +436,13 @@ func (ps *peerSet) Unregister(id string) error {
ps.lock.Lock() ps.lock.Lock()
defer ps.lock.Unlock() defer ps.lock.Unlock()
if _, ok := ps.peers[id]; !ok { p, ok := ps.peers[id]
if !ok {
return errNotRegistered return errNotRegistered
} }
delete(ps.peers, id) delete(ps.peers, id)
p.close()
return nil return nil
} }

View file

@ -34,13 +34,13 @@ const (
eth63 = 63 eth63 = 63
) )
// Official short name of the protocol used during capability negotiation. // ProtocolName is the official short name of the protocol used during capability negotiation.
var ProtocolName = "eth" var ProtocolName = "eth"
// Supported versions of the eth protocol (first is primary). // ProtocolVersions are the upported versions of the eth protocol (first is primary).
var ProtocolVersions = []uint{eth63, eth62} var ProtocolVersions = []uint{eth63, eth62}
// Number of implemented message corresponding to different protocol versions. // ProtocolLengths are the number of implemented message corresponding to different protocol versions.
var ProtocolLengths = []uint64{17, 8} var ProtocolLengths = []uint64{17, 8}
const ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message const ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message
@ -103,9 +103,9 @@ type txPool interface {
// The slice should be modifiable by the caller. // The slice should be modifiable by the caller.
Pending() (map[common.Address]types.Transactions, error) Pending() (map[common.Address]types.Transactions, error)
// SubscribeTxPreEvent should return an event subscription of // SubscribeNewTxsEvent should return an event subscription of
// TxPreEvent and send events to the given channel. // NewTxsEvent and send events to the given channel.
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
} }
// statusData is the network packet for the status message. // statusData is the network packet for the status message.

View file

@ -116,7 +116,7 @@ func testRecvTransactions(t *testing.T, protocol int) {
t.Errorf("added wrong tx hash: got %v, want %v", added[0].Hash(), tx.Hash()) t.Errorf("added wrong tx hash: got %v, want %v", added[0].Hash(), tx.Hash())
} }
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
t.Errorf("no TxPreEvent received within 2 seconds") t.Errorf("no NewTxsEvent received within 2 seconds")
} }
} }

View file

@ -159,8 +159,7 @@ func TestCallTracer(t *testing.T) {
GasLimit: uint64(test.Context.GasLimit), GasLimit: uint64(test.Context.GasLimit),
GasPrice: tx.GasPrice(), GasPrice: tx.GasPrice(),
} }
db, _ := ethdb.NewMemDatabase() statedb := tests.MakePreState(ethdb.NewMemDatabase(), test.Genesis.Alloc)
statedb := tests.MakePreState(db, test.Genesis.Alloc)
// Create the tracer, the EVM environment and run it // Create the tracer, the EVM environment and run it
tracer, err := New("callTracer") tracer, err := New("callTracer")

View file

@ -207,6 +207,7 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
delaystats [2]int64 delaystats [2]int64
lastWriteDelay time.Time lastWriteDelay time.Time
lastWriteDelayN time.Time lastWriteDelayN time.Time
lastWritePaused time.Time
) )
// Iterate ad infinitum and collect the stats // Iterate ad infinitum and collect the stats
@ -267,8 +268,9 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
delayN int64 delayN int64
delayDuration string delayDuration string
duration time.Duration duration time.Duration
paused bool
) )
if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s", &delayN, &delayDuration); n != 2 || err != nil { if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil {
db.log.Error("Write delay statistic not found") db.log.Error("Write delay statistic not found")
return return
} }
@ -301,6 +303,14 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
lastWriteDelay = time.Now() lastWriteDelay = time.Now()
} }
} }
// If a warning that db is performing compaction has been displayed, any subsequent
// warnings will be withheld for one minute not to overwhelm the user.
if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 &&
time.Now().After(lastWritePaused.Add(writeDelayWarningThrottler)) {
db.log.Warn("Database compacting, degraded performance")
lastWritePaused = time.Now()
}
delaystats[0], delaystats[1] = delayN, duration.Nanoseconds() delaystats[0], delaystats[1] = delayN, duration.Nanoseconds()
// Retrieve the database iostats. // Retrieve the database iostats.

View file

@ -53,8 +53,7 @@ func TestLDB_PutGet(t *testing.T) {
} }
func TestMemoryDB_PutGet(t *testing.T) { func TestMemoryDB_PutGet(t *testing.T) {
db, _ := ethdb.NewMemDatabase() testPutGet(ethdb.NewMemDatabase(), t)
testPutGet(db, t)
} }
func testPutGet(db ethdb.Database, t *testing.T) { func testPutGet(db ethdb.Database, t *testing.T) {
@ -131,8 +130,7 @@ func TestLDB_ParallelPutGet(t *testing.T) {
} }
func TestMemoryDB_ParallelPutGet(t *testing.T) { func TestMemoryDB_ParallelPutGet(t *testing.T) {
db, _ := ethdb.NewMemDatabase() testParallelPutGet(ethdb.NewMemDatabase(), t)
testParallelPutGet(db, t)
} }
func testParallelPutGet(db ethdb.Database, t *testing.T) { func testParallelPutGet(db ethdb.Database, t *testing.T) {

View file

@ -31,16 +31,16 @@ type MemDatabase struct {
lock sync.RWMutex lock sync.RWMutex
} }
func NewMemDatabase() (*MemDatabase, error) { func NewMemDatabase() *MemDatabase {
return &MemDatabase{ return &MemDatabase{
db: make(map[string][]byte), db: make(map[string][]byte),
}, nil }
} }
func NewMemDatabaseWithCap(size int) (*MemDatabase, error) { func NewMemDatabaseWithCap(size int) *MemDatabase {
return &MemDatabase{ return &MemDatabase{
db: make(map[string][]byte, size), db: make(map[string][]byte, size),
}, nil }
} }
func (db *MemDatabase) Put(key []byte, value []byte) error { func (db *MemDatabase) Put(key []byte, value []byte) error {

View file

@ -49,7 +49,7 @@ const (
// history request. // history request.
historyUpdateRange = 50 historyUpdateRange = 50
// txChanSize is the size of channel listening to TxPreEvent. // txChanSize is the size of channel listening to NewTxsEvent.
// The number is referenced from the size of tx pool. // The number is referenced from the size of tx pool.
txChanSize = 4096 txChanSize = 4096
// chainHeadChanSize is the size of channel listening to ChainHeadEvent. // chainHeadChanSize is the size of channel listening to ChainHeadEvent.
@ -57,9 +57,9 @@ const (
) )
type txPool interface { type txPool interface {
// SubscribeTxPreEvent should return an event subscription of // SubscribeNewTxsEvent should return an event subscription of
// TxPreEvent and send events to the given channel. // NewTxsEvent and send events to the given channel.
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
} }
type blockChain interface { type blockChain interface {
@ -150,8 +150,8 @@ func (s *Service) loop() {
headSub := blockchain.SubscribeChainHeadEvent(chainHeadCh) headSub := blockchain.SubscribeChainHeadEvent(chainHeadCh)
defer headSub.Unsubscribe() defer headSub.Unsubscribe()
txEventCh := make(chan core.TxPreEvent, txChanSize) txEventCh := make(chan core.NewTxsEvent, txChanSize)
txSub := txpool.SubscribeTxPreEvent(txEventCh) txSub := txpool.SubscribeNewTxsEvent(txEventCh)
defer txSub.Unsubscribe() defer txSub.Unsubscribe()
// Start a goroutine that exhausts the subsciptions to avoid events piling up // Start a goroutine that exhausts the subsciptions to avoid events piling up
@ -689,7 +689,7 @@ func (s *Service) reportStats(conn *websocket.Conn) error {
sync := s.eth.Downloader().Progress() sync := s.eth.Downloader().Progress()
syncing = s.eth.BlockChain().CurrentHeader().Number.Uint64() >= sync.HighestBlock syncing = s.eth.BlockChain().CurrentHeader().Number.Uint64() >= sync.HighestBlock
price, _ := s.eth.ApiBackend.SuggestPrice(context.Background()) price, _ := s.eth.APIBackend.SuggestPrice(context.Background())
gasprice = int(price.Uint64()) gasprice = int(price.Uint64())
} else { } else {
sync := s.les.Downloader().Progress() sync := s.les.Downloader().Progress()

View file

@ -180,6 +180,12 @@ func (s *TypeMuxSubscription) Unsubscribe() {
s.closewait() s.closewait()
} }
func (s *TypeMuxSubscription) Closed() bool {
s.closeMu.Lock()
defer s.closeMu.Unlock()
return s.closed
}
func (s *TypeMuxSubscription) closewait() { func (s *TypeMuxSubscription) closewait() {
s.closeMu.Lock() s.closeMu.Lock()
defer s.closeMu.Unlock() defer s.closeMu.Unlock()

View file

@ -148,7 +148,9 @@ func (f *Feed) Send(value interface{}) (nsent int) {
f.sendCases[i].Send = rvalue f.sendCases[i].Send = rvalue
} }
// Send until all channels except removeSub have been chosen. // Send until all channels except removeSub have been chosen. 'cases' tracks a prefix
// of sendCases. When a send succeeds, the corresponding case moves to the end of
// 'cases' and it shrinks by one element.
cases := f.sendCases cases := f.sendCases
for { for {
// Fast path: try sending without blocking before adding to the select set. // Fast path: try sending without blocking before adding to the select set.
@ -170,6 +172,7 @@ func (f *Feed) Send(value interface{}) (nsent int) {
index := f.sendCases.find(recv.Interface()) index := f.sendCases.find(recv.Interface())
f.sendCases = f.sendCases.delete(index) f.sendCases = f.sendCases.delete(index)
if index >= 0 && index < len(cases) { if index >= 0 && index < len(cases) {
// Shrink 'cases' too because the removed case was still active.
cases = f.sendCases[:len(cases)-1] cases = f.sendCases[:len(cases)-1]
} }
} else { } else {

View file

@ -235,6 +235,45 @@ func TestFeedUnsubscribeBlockedPost(t *testing.T) {
wg.Wait() wg.Wait()
} }
// Checks that unsubscribing a channel during Send works even if that
// channel has already been sent on.
func TestFeedUnsubscribeSentChan(t *testing.T) {
var (
feed Feed
ch1 = make(chan int)
ch2 = make(chan int)
sub1 = feed.Subscribe(ch1)
sub2 = feed.Subscribe(ch2)
wg sync.WaitGroup
)
defer sub2.Unsubscribe()
wg.Add(1)
go func() {
feed.Send(0)
wg.Done()
}()
// Wait for the value on ch1.
<-ch1
// Unsubscribe ch1, removing it from the send cases.
sub1.Unsubscribe()
// Receive ch2, finishing Send.
<-ch2
wg.Wait()
// Send again. This should send to ch2 only, so the wait group will unblock
// as soon as a value is received on ch2.
wg.Add(1)
go func() {
feed.Send(0)
wg.Done()
}()
<-ch2
wg.Wait()
}
func TestFeedUnsubscribeFromInbox(t *testing.T) { func TestFeedUnsubscribeFromInbox(t *testing.T) {
var ( var (
feed Feed feed Feed

View file

@ -144,7 +144,7 @@ type FilterQuery struct {
// {} or nil matches any topic list // {} or nil matches any topic list
// {{A}} matches topic A in first position // {{A}} matches topic A in first position
// {{}, {B}} matches any topic in first position, B in second position // {{}, {B}} matches any topic in first position, B in second position
// {{A}}, {B}} matches topic A in first position, B in second position // {{A}, {B}} matches topic A in first position, B in second position
// {{A, B}}, {C, D}} matches topic (A OR B) in first position, (C OR D) in second position // {{A, B}}, {C, D}} matches topic (A OR B) in first position, (C OR D) in second position
Topics [][]common.Hash Topics [][]common.Hash
} }

View file

@ -57,3 +57,15 @@ func PGPSignFile(input string, output string, pgpkey string) error {
// Generate the signature and return // Generate the signature and return
return openpgp.ArmoredDetachSign(out, keys[0], in, nil) return openpgp.ArmoredDetachSign(out, keys[0], in, nil)
} }
// PGPKeyID parses an armored key and returns the key ID.
func PGPKeyID(pgpkey string) (string, error) {
keys, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(pgpkey))
if err != nil {
return "", err
}
if len(keys) != 1 {
return "", fmt.Errorf("key count mismatch: have %d, want %d", len(keys), 1)
}
return keys[0].PrimaryKey.KeyIdString(), nil
}

View file

@ -65,7 +65,7 @@ type Backend interface {
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
Stats() (pending int, queued int) Stats() (pending int, queued int)
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
ChainConfig() *params.ChainConfig ChainConfig() *params.ChainConfig
CurrentBlock() *types.Block CurrentBlock() *types.Block

View file

@ -136,8 +136,8 @@ func (b *LesApiBackend) TxPoolContent() (map[common.Address]types.Transactions,
return b.eth.txPool.Content() return b.eth.txPool.Content()
} }
func (b *LesApiBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { func (b *LesApiBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return b.eth.txPool.SubscribeTxPreEvent(ch) return b.eth.txPool.SubscribeNewTxsEvent(ch)
} }
func (b *LesApiBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { func (b *LesApiBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {

View file

@ -51,8 +51,7 @@ func TestGetBlockHeadersLes1(t *testing.T) { testGetBlockHeaders(t, 1) }
func TestGetBlockHeadersLes2(t *testing.T) { testGetBlockHeaders(t, 2) } func TestGetBlockHeadersLes2(t *testing.T) { testGetBlockHeaders(t, 2) }
func testGetBlockHeaders(t *testing.T, protocol int) { func testGetBlockHeaders(t *testing.T, protocol int) {
db, _ := ethdb.NewMemDatabase() pm := newTestProtocolManagerMust(t, false, downloader.MaxHashFetch+15, nil, nil, nil, ethdb.NewMemDatabase())
pm := newTestProtocolManagerMust(t, false, downloader.MaxHashFetch+15, nil, nil, nil, db)
bc := pm.blockchain.(*core.BlockChain) bc := pm.blockchain.(*core.BlockChain)
peer, _ := newTestPeer(t, "peer", protocol, pm, true) peer, _ := newTestPeer(t, "peer", protocol, pm, true)
defer peer.close() defer peer.close()
@ -181,8 +180,7 @@ func TestGetBlockBodiesLes1(t *testing.T) { testGetBlockBodies(t, 1) }
func TestGetBlockBodiesLes2(t *testing.T) { testGetBlockBodies(t, 2) } func TestGetBlockBodiesLes2(t *testing.T) { testGetBlockBodies(t, 2) }
func testGetBlockBodies(t *testing.T, protocol int) { func testGetBlockBodies(t *testing.T, protocol int) {
db, _ := ethdb.NewMemDatabase() pm := newTestProtocolManagerMust(t, false, downloader.MaxBlockFetch+15, nil, nil, nil, ethdb.NewMemDatabase())
pm := newTestProtocolManagerMust(t, false, downloader.MaxBlockFetch+15, nil, nil, nil, db)
bc := pm.blockchain.(*core.BlockChain) bc := pm.blockchain.(*core.BlockChain)
peer, _ := newTestPeer(t, "peer", protocol, pm, true) peer, _ := newTestPeer(t, "peer", protocol, pm, true)
defer peer.close() defer peer.close()
@ -259,8 +257,7 @@ func TestGetCodeLes2(t *testing.T) { testGetCode(t, 2) }
func testGetCode(t *testing.T, protocol int) { func testGetCode(t *testing.T, protocol int) {
// Assemble the test environment // Assemble the test environment
db, _ := ethdb.NewMemDatabase() pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, ethdb.NewMemDatabase())
pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
bc := pm.blockchain.(*core.BlockChain) bc := pm.blockchain.(*core.BlockChain)
peer, _ := newTestPeer(t, "peer", protocol, pm, true) peer, _ := newTestPeer(t, "peer", protocol, pm, true)
defer peer.close() defer peer.close()
@ -293,7 +290,7 @@ func TestGetReceiptLes2(t *testing.T) { testGetReceipt(t, 2) }
func testGetReceipt(t *testing.T, protocol int) { func testGetReceipt(t *testing.T, protocol int) {
// Assemble the test environment // Assemble the test environment
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
bc := pm.blockchain.(*core.BlockChain) bc := pm.blockchain.(*core.BlockChain)
peer, _ := newTestPeer(t, "peer", protocol, pm, true) peer, _ := newTestPeer(t, "peer", protocol, pm, true)
@ -321,7 +318,7 @@ func TestGetProofsLes2(t *testing.T) { testGetProofs(t, 2) }
func testGetProofs(t *testing.T, protocol int) { func testGetProofs(t *testing.T, protocol int) {
// Assemble the test environment // Assemble the test environment
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
bc := pm.blockchain.(*core.BlockChain) bc := pm.blockchain.(*core.BlockChain)
peer, _ := newTestPeer(t, "peer", protocol, pm, true) peer, _ := newTestPeer(t, "peer", protocol, pm, true)
@ -384,7 +381,7 @@ func testGetCHTProofs(t *testing.T, protocol int) {
frequency = uint64(light.CHTFrequencyServer) frequency = uint64(light.CHTFrequencyServer)
} }
// Assemble the test environment // Assemble the test environment
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
pm := newTestProtocolManagerMust(t, false, int(frequency)+light.HelperTrieProcessConfirmations, testChainGen, nil, nil, db) pm := newTestProtocolManagerMust(t, false, int(frequency)+light.HelperTrieProcessConfirmations, testChainGen, nil, nil, db)
bc := pm.blockchain.(*core.BlockChain) bc := pm.blockchain.(*core.BlockChain)
peer, _ := newTestPeer(t, "peer", protocol, pm, true) peer, _ := newTestPeer(t, "peer", protocol, pm, true)
@ -452,7 +449,7 @@ func testGetCHTProofs(t *testing.T, protocol int) {
// Tests that bloombits proofs can be correctly retrieved. // Tests that bloombits proofs can be correctly retrieved.
func TestGetBloombitsProofs(t *testing.T) { func TestGetBloombitsProofs(t *testing.T) {
// Assemble the test environment // Assemble the test environment
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
pm := newTestProtocolManagerMust(t, false, light.BloomTrieFrequency+256, testChainGen, nil, nil, db) pm := newTestProtocolManagerMust(t, false, light.BloomTrieFrequency+256, testChainGen, nil, nil, db)
bc := pm.blockchain.(*core.BlockChain) bc := pm.blockchain.(*core.BlockChain)
peer, _ := newTestPeer(t, "peer", 2, pm, true) peer, _ := newTestPeer(t, "peer", 2, pm, true)
@ -491,7 +488,7 @@ func TestGetBloombitsProofs(t *testing.T) {
} }
func TestTransactionStatusLes2(t *testing.T) { func TestTransactionStatusLes2(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db) pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db)
chain := pm.blockchain.(*core.BlockChain) chain := pm.blockchain.(*core.BlockChain)
config := core.DefaultTxPoolConfig config := core.DefaultTxPoolConfig

View file

@ -230,7 +230,7 @@ func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error {
} }
nodeSet := proofs[0].NodeSet() nodeSet := proofs[0].NodeSet()
// Verify the proof and store if checks out // Verify the proof and store if checks out
if _, err, _ := trie.VerifyProof(r.Id.Root, r.Key, nodeSet); err != nil { if _, _, err := trie.VerifyProof(r.Id.Root, r.Key, nodeSet); err != nil {
return fmt.Errorf("merkle proof verification failed: %v", err) return fmt.Errorf("merkle proof verification failed: %v", err)
} }
r.Proof = nodeSet r.Proof = nodeSet
@ -241,7 +241,7 @@ func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error {
// Verify the proof and store if checks out // Verify the proof and store if checks out
nodeSet := proofs.NodeSet() nodeSet := proofs.NodeSet()
reads := &readTraceDB{db: nodeSet} reads := &readTraceDB{db: nodeSet}
if _, err, _ := trie.VerifyProof(r.Id.Root, r.Key, reads); err != nil { if _, _, err := trie.VerifyProof(r.Id.Root, r.Key, reads); err != nil {
return fmt.Errorf("merkle proof verification failed: %v", err) return fmt.Errorf("merkle proof verification failed: %v", err)
} }
// check if all nodes have been read by VerifyProof // check if all nodes have been read by VerifyProof
@ -400,7 +400,7 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
var encNumber [8]byte var encNumber [8]byte
binary.BigEndian.PutUint64(encNumber[:], r.BlockNum) binary.BigEndian.PutUint64(encNumber[:], r.BlockNum)
value, err, _ := trie.VerifyProof(r.ChtRoot, encNumber[:], light.NodeList(proof.Proof).NodeSet()) value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], light.NodeList(proof.Proof).NodeSet())
if err != nil { if err != nil {
return err return err
} }
@ -435,7 +435,7 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
binary.BigEndian.PutUint64(encNumber[:], r.BlockNum) binary.BigEndian.PutUint64(encNumber[:], r.BlockNum)
reads := &readTraceDB{db: nodeSet} reads := &readTraceDB{db: nodeSet}
value, err, _ := trie.VerifyProof(r.ChtRoot, encNumber[:], reads) value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], reads)
if err != nil { if err != nil {
return fmt.Errorf("merkle proof verification failed: %v", err) return fmt.Errorf("merkle proof verification failed: %v", err)
} }
@ -529,7 +529,7 @@ func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
for i, idx := range r.SectionIdxList { for i, idx := range r.SectionIdxList {
binary.BigEndian.PutUint64(encNumber[2:], idx) binary.BigEndian.PutUint64(encNumber[2:], idx)
value, err, _ := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads) value, _, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads)
if err != nil { if err != nil {
return err return err
} }

View file

@ -165,8 +165,8 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
peers := newPeerSet() peers := newPeerSet()
dist := newRequestDistributor(peers, make(chan struct{})) dist := newRequestDistributor(peers, make(chan struct{}))
rm := newRetrieveManager(peers, dist, nil) rm := newRetrieveManager(peers, dist, nil)
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
ldb, _ := ethdb.NewMemDatabase() ldb := ethdb.NewMemDatabase()
odr := NewLesOdr(ldb, light.NewChtIndexer(db, true), light.NewBloomTrieIndexer(db, true), eth.NewBloomIndexer(db, light.BloomTrieFrequency), rm) odr := NewLesOdr(ldb, light.NewChtIndexer(db, true), light.NewBloomTrieIndexer(db, true), eth.NewBloomIndexer(db, light.BloomTrieFrequency), rm)
pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
lpm := newTestProtocolManagerMust(t, true, 0, nil, peers, odr, ldb) lpm := newTestProtocolManagerMust(t, true, 0, nil, peers, odr, ldb)

View file

@ -87,8 +87,8 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) {
peers := newPeerSet() peers := newPeerSet()
dist := newRequestDistributor(peers, make(chan struct{})) dist := newRequestDistributor(peers, make(chan struct{}))
rm := newRetrieveManager(peers, dist, nil) rm := newRetrieveManager(peers, dist, nil)
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
ldb, _ := ethdb.NewMemDatabase() ldb := ethdb.NewMemDatabase()
odr := NewLesOdr(ldb, light.NewChtIndexer(db, true), light.NewBloomTrieIndexer(db, true), eth.NewBloomIndexer(db, light.BloomTrieFrequency), rm) odr := NewLesOdr(ldb, light.NewChtIndexer(db, true), light.NewBloomTrieIndexer(db, true), eth.NewBloomIndexer(db, light.BloomTrieFrequency), rm)
pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)

View file

@ -52,7 +52,7 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
// chain. Depending on the full flag, if creates either a full block chain or a // chain. Depending on the full flag, if creates either a full block chain or a
// header only chain. // header only chain.
func newCanonical(n int) (ethdb.Database, *LightChain, error) { func newCanonical(n int) (ethdb.Database, *LightChain, error) {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
gspec := core.Genesis{Config: params.TestChainConfig} gspec := core.Genesis{Config: params.TestChainConfig}
genesis := gspec.MustCommit(db) genesis := gspec.MustCommit(db)
blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFaker()) blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFaker())
@ -69,7 +69,7 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) {
// newTestLightChain creates a LightChain that doesn't validate anything. // newTestLightChain creates a LightChain that doesn't validate anything.
func newTestLightChain() *LightChain { func newTestLightChain() *LightChain {
db, _ := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
gspec := &core.Genesis{ gspec := &core.Genesis{
Difficulty: big.NewInt(1), Difficulty: big.NewInt(1),
Config: params.TestChainConfig, Config: params.TestChainConfig,

View file

@ -245,8 +245,8 @@ func testChainGen(i int, block *core.BlockGen) {
func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { func testChainOdr(t *testing.T, protocol int, fn odrTestFn) {
var ( var (
sdb, _ = ethdb.NewMemDatabase() sdb = ethdb.NewMemDatabase()
ldb, _ = ethdb.NewMemDatabase() ldb = ethdb.NewMemDatabase()
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
genesis = gspec.MustCommit(sdb) genesis = gspec.MustCommit(sdb)
) )

View file

@ -59,18 +59,18 @@ type trustedCheckpoint struct {
var ( var (
mainnetCheckpoint = trustedCheckpoint{ mainnetCheckpoint = trustedCheckpoint{
name: "mainnet", name: "mainnet",
sectionIdx: 165, sectionIdx: 170,
sectionHead: common.HexToHash("21028acf9cd9ce80257221adc437c3c58ce046c4d43c21c3e9b1d1349059ec73"), sectionHead: common.HexToHash("3bb2c28bcce463d57968f14f56cdb3fbf35349ab7a701f44c1afb57349c9a356"),
chtRoot: common.HexToHash("26b2458cb7d0080d3a39311c914be92c368777a65ec074e1893b8bdc79e3910a"), chtRoot: common.HexToHash("d92b6d0853455f8439086292338e87f69781921680dd7aa072fb71547b87415e"),
bloomTrieRoot: common.HexToHash("5d06908769179186165a72db7fc3473b25c28ed27efe78a392a9ff2c3fa67f84"), bloomTrieRoot: common.HexToHash("e4e8250a2fefddead7ae42daecd848cbf9b66d748a8270f8bbd4370b764bb9e9"),
} }
ropstenCheckpoint = trustedCheckpoint{ ropstenCheckpoint = trustedCheckpoint{
name: "ropsten", name: "ropsten",
sectionIdx: 92, sectionIdx: 97,
sectionHead: common.HexToHash("21a158f9cc643da13a237cafceb37381072649f7278cf98c5820bfbced7cfcec"), sectionHead: common.HexToHash("719448c67c01eb5b9f27833a36a4e34612f66801316d7ff37daf9e77fb4cd095"),
chtRoot: common.HexToHash("1a8ddb8b086d7a33ca90eea90730225948fa504ae0283b15aff3c15c0e089bf9"), chtRoot: common.HexToHash("a7857afc15930ca6e583b6c3d563a025144011655843d52d28e2fdaadd417bea"),
bloomTrieRoot: common.HexToHash("fd192f92afbcdd0020c81ca0625116b5995509659653b10123bd986fe5129cc1"), bloomTrieRoot: common.HexToHash("9c71d4b50cbec86dfeaa8e08992de8a4667b81d13c54d6522b17ce2fc5d36416"),
} }
) )

View file

@ -34,8 +34,8 @@ import (
func TestNodeIterator(t *testing.T) { func TestNodeIterator(t *testing.T) {
var ( var (
fulldb, _ = ethdb.NewMemDatabase() fulldb = ethdb.NewMemDatabase()
lightdb, _ = ethdb.NewMemDatabase() lightdb = ethdb.NewMemDatabase()
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
genesis = gspec.MustCommit(fulldb) genesis = gspec.MustCommit(fulldb)
) )

View file

@ -321,9 +321,9 @@ func (pool *TxPool) Stop() {
log.Info("Transaction pool stopped") log.Info("Transaction pool stopped")
} }
// SubscribeTxPreEvent registers a subscription of core.TxPreEvent and // SubscribeNewTxsEvent registers a subscription of core.NewTxsEvent and
// starts sending event to the given channel. // starts sending event to the given channel.
func (pool *TxPool) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return pool.scope.Track(pool.txFeed.Subscribe(ch)) return pool.scope.Track(pool.txFeed.Subscribe(ch))
} }
@ -412,7 +412,7 @@ func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error {
// Notify the subscribers. This event is posted in a goroutine // Notify the subscribers. This event is posted in a goroutine
// because it's possible that somewhere during the post "Remove transaction" // because it's possible that somewhere during the post "Remove transaction"
// gets called which will then wait for the global tx pool lock and deadlock. // gets called which will then wait for the global tx pool lock and deadlock.
go self.txFeed.Send(core.TxPreEvent{Tx: tx}) go self.txFeed.Send(core.NewTxsEvent{Txs: types.Transactions{tx}})
} }
// Print a log message if low enough level is set // Print a log message if low enough level is set

View file

@ -81,8 +81,8 @@ func TestTxPool(t *testing.T) {
} }
var ( var (
sdb, _ = ethdb.NewMemDatabase() sdb = ethdb.NewMemDatabase()
ldb, _ = ethdb.NewMemDatabase() ldb = ethdb.NewMemDatabase()
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
genesis = gspec.MustCommit(sdb) genesis = gspec.MustCommit(sdb)
) )

View file

@ -45,7 +45,7 @@ srvlog.SetHandler(log.MultiHandler(
log.StreamHandler(os.Stderr, log.LogfmtFormat()), log.StreamHandler(os.Stderr, log.LogfmtFormat()),
log.LvlFilterHandler( log.LvlFilterHandler(
log.LvlError, log.LvlError,
log.Must.FileHandler("errors.json", log.JsonFormat())))) log.Must.FileHandler("errors.json", log.JSONFormat()))))
``` ```
Will result in output that looks like this: Will result in output that looks like this:

View file

@ -86,7 +86,7 @@ from the rpc package in logfmt to standard out. The other prints records at Erro
or above in JSON formatted output to the file /var/log/service.json or above in JSON formatted output to the file /var/log/service.json
handler := log.MultiHandler( handler := log.MultiHandler(
log.LvlFilterHandler(log.LvlError, log.Must.FileHandler("/var/log/service.json", log.JsonFormat())), log.LvlFilterHandler(log.LvlError, log.Must.FileHandler("/var/log/service.json", log.JSONFormat())),
log.MatchFilterHandler("pkg", "app/rpc" log.StdoutHandler()) log.MatchFilterHandler("pkg", "app/rpc" log.StdoutHandler())
) )
@ -304,8 +304,8 @@ For all Handler functions which can return an error, there is a version of that
function which will return no error but panics on failure. They are all available function which will return no error but panics on failure. They are all available
on the Must object. For example: on the Must object. For example:
log.Must.FileHandler("/path", log.JsonFormat) log.Must.FileHandler("/path", log.JSONFormat)
log.Must.NetHandler("tcp", ":1234", log.JsonFormat) log.Must.NetHandler("tcp", ":1234", log.JSONFormat)
Inspiration and Credit Inspiration and Credit

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