aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/block_processor_test.go9
-rw-r--r--core/chain_makers.go2
-rw-r--r--core/chain_manager.go127
-rw-r--r--core/chain_manager_test.go10
-rw-r--r--core/error.go16
-rw-r--r--core/events.go10
-rw-r--r--core/execution.go8
-rw-r--r--core/manager.go3
-rw-r--r--core/state_transition.go12
9 files changed, 133 insertions, 64 deletions
diff --git a/core/block_processor_test.go b/core/block_processor_test.go
index 35aeaa714..a031c2669 100644
--- a/core/block_processor_test.go
+++ b/core/block_processor_test.go
@@ -6,14 +6,15 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/pow/ezp"
)
func proc() (*BlockProcessor, *ChainManager) {
db, _ := ethdb.NewMemDatabase()
var mux event.TypeMux
- chainMan := NewChainManager(db, &mux)
- return NewBlockProcessor(db, nil, chainMan, &mux), chainMan
+ chainMan := NewChainManager(db, db, &mux)
+ return NewBlockProcessor(db, ezp.New(), nil, chainMan, &mux), chainMan
}
func TestNumber(t *testing.T) {
@@ -21,13 +22,13 @@ func TestNumber(t *testing.T) {
block1 := chain.NewBlock(nil)
block1.Header().Number = big.NewInt(3)
- err := bp.ValidateBlock(block1, chain.Genesis())
+ err := bp.ValidateHeader(block1.Header(), chain.Genesis().Header())
if err != BlockNumberErr {
t.Errorf("expected block number error")
}
block1 = chain.NewBlock(nil)
- err = bp.ValidateBlock(block1, chain.Genesis())
+ err = bp.ValidateHeader(block1.Header(), chain.Genesis().Header())
if err == BlockNumberErr {
t.Errorf("didn't expect block number error")
}
diff --git a/core/chain_makers.go b/core/chain_makers.go
index fad9ac97b..b5c50dc3d 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -108,7 +108,7 @@ func makeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Da
// Create a new chain manager starting from given block
// Effectively a fork factory
func newChainManager(block *types.Block, eventMux *event.TypeMux, db ethutil.Database) *ChainManager {
- bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: eventMux}
+ bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: GenesisBlock(db), eventMux: eventMux}
if block == nil {
bc.Reset()
} else {
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 1152e3fa2..9dc41f421 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -19,11 +19,6 @@ var (
jsonlogger = logger.NewJsonLogger()
)
-type ChainEvent struct {
- Block *types.Block
- Td *big.Int
-}
-
type StateQuery interface {
GetAccount(addr []byte) *state.StateObject
}
@@ -66,7 +61,6 @@ func CalcGasLimit(parent, block *types.Block) *big.Int {
}
// ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024
-
previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit())
current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed()), big.NewRat(6, 5))
curInt := new(big.Int).Div(current.Num(), current.Denom())
@@ -81,7 +75,8 @@ func CalcGasLimit(parent, block *types.Block) *big.Int {
type ChainManager struct {
//eth EthManager
- db ethutil.Database
+ blockDb ethutil.Database
+ stateDb ethutil.Database
processor types.BlockProcessor
eventMux *event.TypeMux
genesisBlock *types.Block
@@ -94,13 +89,16 @@ type ChainManager struct {
transState *state.StateDB
txState *state.StateDB
+
+ quit chan struct{}
}
-func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
- bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
+func NewChainManager(blockDb, stateDb ethutil.Database, mux *event.TypeMux) *ChainManager {
+ bc := &ChainManager{blockDb: blockDb, stateDb: stateDb, genesisBlock: GenesisBlock(stateDb), eventMux: mux, quit: make(chan struct{})}
bc.setLastBlock()
bc.transState = bc.State().Copy()
bc.txState = bc.State().Copy()
+ go bc.update()
return bc
}
@@ -138,7 +136,7 @@ func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
}
func (self *ChainManager) State() *state.StateDB {
- return state.New(self.CurrentBlock().Root(), self.db)
+ return state.New(self.CurrentBlock().Root(), self.stateDb)
}
func (self *ChainManager) TransState() *state.StateDB {
@@ -166,7 +164,7 @@ func (self *ChainManager) setTransState(statedb *state.StateDB) {
}
func (bc *ChainManager) setLastBlock() {
- data, _ := bc.db.Get([]byte("LastBlock"))
+ data, _ := bc.blockDb.Get([]byte("LastBlock"))
if len(data) != 0 {
var block types.Block
rlp.Decode(bytes.NewReader(data), &block)
@@ -174,7 +172,7 @@ func (bc *ChainManager) setLastBlock() {
bc.lastBlockHash = block.Hash()
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
- bc.td = ethutil.BigD(bc.db.LastKnownTD())
+ bc.td = ethutil.BigD(bc.blockDb.LastKnownTD())
} else {
bc.Reset()
}
@@ -223,7 +221,7 @@ func (bc *ChainManager) Reset() {
defer bc.mu.Unlock()
for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
- bc.db.Delete(block.Hash())
+ bc.blockDb.Delete(block.Hash())
}
// Prepare the genesis block
@@ -239,7 +237,7 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
defer bc.mu.Unlock()
for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
- bc.db.Delete(block.Hash())
+ bc.blockDb.Delete(block.Hash())
}
// Prepare the genesis block
@@ -265,14 +263,14 @@ func (self *ChainManager) Export() []byte {
func (bc *ChainManager) insert(block *types.Block) {
encodedBlock := ethutil.Encode(block)
- bc.db.Put([]byte("LastBlock"), encodedBlock)
+ bc.blockDb.Put([]byte("LastBlock"), encodedBlock)
bc.currentBlock = block
bc.lastBlockHash = block.Hash()
}
func (bc *ChainManager) write(block *types.Block) {
encodedBlock := ethutil.Encode(block.RlpDataForStorage())
- bc.db.Put(block.Hash(), encodedBlock)
+ bc.blockDb.Put(block.Hash(), encodedBlock)
}
// Accessors
@@ -282,7 +280,7 @@ func (bc *ChainManager) Genesis() *types.Block {
// Block fetching methods
func (bc *ChainManager) HasBlock(hash []byte) bool {
- data, _ := bc.db.Get(hash)
+ data, _ := bc.blockDb.Get(hash)
return len(data) != 0
}
@@ -291,7 +289,6 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain
if block == nil {
return
}
-
// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
for i := uint64(0); i < max; i++ {
parentHash := block.Header().ParentHash
@@ -311,7 +308,7 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain
}
func (self *ChainManager) GetBlock(hash []byte) *types.Block {
- data, _ := self.db.Get(hash)
+ data, _ := self.blockDb.Get(hash)
if len(data) == 0 {
return nil
}
@@ -365,7 +362,7 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
}
func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
- bc.db.Put([]byte("LTD"), td.Bytes())
+ bc.blockDb.Put([]byte("LTD"), td.Bytes())
bc.td = td
}
@@ -390,19 +387,24 @@ func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
}
func (bc *ChainManager) Stop() {
- if bc.CurrentBlock != nil {
- chainlogger.Infoln("Stopped")
- }
+ close(bc.quit)
}
-func (self *ChainManager) InsertChain(chain types.Blocks) error {
- println("insert chain start")
- self.tsmu.Lock()
- defer self.tsmu.Unlock()
+type queueEvent struct {
+ queue []interface{}
+ canonicalCount int
+ sideCount int
+ splitCount int
+}
- defer println("insert chain end")
+func (self *ChainManager) InsertChain(chain types.Blocks) error {
+ //self.tsmu.Lock()
+ //defer self.tsmu.Unlock()
- for _, block := range chain {
+ // A queued approach to delivering events. This is generally faster than direct delivery and requires much less mutex acquiring.
+ var queue = make([]interface{}, len(chain))
+ var queueEvent = queueEvent{queue: queue}
+ for i, block := range chain {
// Call in to the block processor and check for errors. It's likely that if one block fails
// all others will fail too (unless a known block is returned).
td, err := self.processor.Process(block)
@@ -419,7 +421,6 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
}
block.Td = td
- var canonical, split bool
self.mu.Lock()
cblock := self.currentBlock
{
@@ -431,41 +432,73 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
if td.Cmp(self.td) > 0 {
if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 {
chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td)
- split = true
+
+ queue[i] = ChainSplitEvent{block}
+ queueEvent.splitCount++
}
self.setTotalDifficulty(td)
self.insert(block)
- canonical = true
- }
- }
- self.mu.Unlock()
-
- if canonical {
- /*
jsonlogger.LogJson(&logger.EthChainNewHead{
BlockHash: ethutil.Bytes2Hex(block.Hash()),
BlockNumber: block.Number(),
ChainHeadHash: ethutil.Bytes2Hex(cblock.Hash()),
BlockPrevHash: ethutil.Bytes2Hex(block.ParentHash()),
})
- */
- self.setTransState(state.New(block.Root(), self.db))
- self.eventMux.Post(ChainEvent{block, td})
- } else {
- //self.eventMux.
- }
- if split {
- self.setTxState(state.New(block.Root(), self.db))
- self.eventMux.Post(ChainSplitEvent{block})
+ self.setTransState(state.New(block.Root(), self.stateDb))
+ queue[i] = ChainEvent{block}
+ queueEvent.canonicalCount++
+ } else {
+ queue[i] = ChainSideEvent{block}
+ queueEvent.sideCount++
+ }
}
+ self.mu.Unlock()
+
}
+ // XXX put this in a goroutine?
+ go self.eventMux.Post(queueEvent)
+
return nil
}
+func (self *ChainManager) update() {
+ events := self.eventMux.Subscribe(queueEvent{})
+
+out:
+ for {
+ select {
+ case ev := <-events.Chan():
+ switch ev := ev.(type) {
+ case queueEvent:
+ for i, event := range ev.queue {
+ switch event := event.(type) {
+ case ChainEvent:
+ // We need some control over the mining operation. Acquiring locks and waiting for the miner to create new block takes too long
+ // and in most cases isn't even necessary.
+ if i == ev.canonicalCount {
+ self.eventMux.Post(ChainHeadEvent{event.Block})
+ }
+ case ChainSplitEvent:
+ // On chain splits we need to reset the transaction state. We can't be sure whether the actual
+ // state of the accounts are still valid.
+ if i == ev.splitCount {
+ self.setTxState(state.New(event.Block.Root(), self.stateDb))
+ }
+ }
+
+ self.eventMux.Post(event)
+ }
+ }
+ case <-self.quit:
+ break out
+ }
+ }
+}
+
// Satisfy state query interface
func (self *ChainManager) GetAccount(addr []byte) *state.StateObject {
return self.State().GetAccount(addr)
diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go
index b562b677d..e78c2e980 100644
--- a/core/chain_manager_test.go
+++ b/core/chain_manager_test.go
@@ -257,9 +257,9 @@ func TestChainInsertions(t *testing.T) {
}
var eventMux event.TypeMux
- chainMan := NewChainManager(db, &eventMux)
+ chainMan := NewChainManager(db, db, &eventMux)
txPool := NewTxPool(&eventMux)
- blockMan := NewBlockProcessor(db, txPool, chainMan, &eventMux)
+ blockMan := NewBlockProcessor(db, nil, txPool, chainMan, &eventMux)
chainMan.SetProcessor(blockMan)
const max = 2
@@ -303,9 +303,9 @@ func TestChainMultipleInsertions(t *testing.T) {
}
}
var eventMux event.TypeMux
- chainMan := NewChainManager(db, &eventMux)
+ chainMan := NewChainManager(db, db, &eventMux)
txPool := NewTxPool(&eventMux)
- blockMan := NewBlockProcessor(db, txPool, chainMan, &eventMux)
+ blockMan := NewBlockProcessor(db, nil, txPool, chainMan, &eventMux)
chainMan.SetProcessor(blockMan)
done := make(chan bool, max)
for i, chain := range chains {
@@ -332,7 +332,7 @@ func TestGetAncestors(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
var eventMux event.TypeMux
- chainMan := NewChainManager(db, &eventMux)
+ chainMan := NewChainManager(db, db, &eventMux)
chain, err := loadChain("valid1", t)
if err != nil {
fmt.Println(err)
diff --git a/core/error.go b/core/error.go
index 514cd076b..04e40646c 100644
--- a/core/error.go
+++ b/core/error.go
@@ -146,3 +146,19 @@ func IsKnownBlockErr(e error) bool {
_, ok := e.(*KnownBlockError)
return ok
}
+
+type ValueTransferError struct {
+ message string
+}
+
+func ValueTransferErr(str string, v ...interface{}) *ValueTransferError {
+ return &ValueTransferError{fmt.Sprintf(str, v...)}
+}
+
+func (self *ValueTransferError) Error() string {
+ return self.message
+}
+func IsValueTransferErr(e error) bool {
+ _, ok := e.(*ValueTransferError)
+ return ok
+}
diff --git a/core/events.go b/core/events.go
index 4cbbc609c..23678ef60 100644
--- a/core/events.go
+++ b/core/events.go
@@ -16,3 +16,13 @@ type NewMinedBlockEvent struct{ Block *types.Block }
// ChainSplit is posted when a new head is detected
type ChainSplitEvent struct{ Block *types.Block }
+
+type ChainEvent struct{ Block *types.Block }
+
+type ChainSideEvent struct{ Block *types.Block }
+
+type ChainHeadEvent struct{ Block *types.Block }
+
+// Mining operation events
+type StartMining struct{}
+type TopMining struct{}
diff --git a/core/execution.go b/core/execution.go
index f7d5a8945..4a69cce09 100644
--- a/core/execution.go
+++ b/core/execution.go
@@ -1,7 +1,6 @@
package core
import (
- "fmt"
"math/big"
"time"
@@ -26,7 +25,10 @@ func (self *Execution) Addr() []byte {
func (self *Execution) Call(codeAddr []byte, caller vm.ContextRef) ([]byte, error) {
// Retrieve the executing code
- code := self.env.State().GetCode(codeAddr)
+ var code []byte
+ if self.env.State().GetStateObject(codeAddr) != nil {
+ code = self.env.State().GetCode(codeAddr)
+ }
return self.exec(code, codeAddr, caller)
}
@@ -55,7 +57,7 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret
caller.ReturnGas(self.Gas, self.price)
- return nil, fmt.Errorf("insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance())
+ return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance())
}
snapshot := env.State().Copy()
diff --git a/core/manager.go b/core/manager.go
index 29f786653..c4052cc05 100644
--- a/core/manager.go
+++ b/core/manager.go
@@ -13,6 +13,7 @@ type Backend interface {
PeerCount() int
IsListening() bool
Peers() []*p2p.Peer
- Db() ethutil.Database
+ BlockDb() ethutil.Database
+ StateDb() ethutil.Database
EventMux() *event.TypeMux
}
diff --git a/core/state_transition.go b/core/state_transition.go
index c487f8514..9b67de149 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -184,7 +184,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
}
}
if err = self.UseGas(big.NewInt(dgas)); err != nil {
- return
+ return nil, InvalidTxError(err)
}
//stateCopy := self.env.State().Copy()
@@ -230,10 +230,16 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
*/
}
- if err != nil {
- self.UseGas(self.gas)
+ if err != nil && IsValueTransferErr(err) {
+ return nil, InvalidTxError(err)
}
+ /*
+ if err != nil {
+ self.UseGas(self.gas)
+ }
+ */
+
return
}