aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2015-03-10 00:55:01 +0800
committerobscuren <geffobscura@gmail.com>2015-03-10 00:55:01 +0800
commit8560004f380dc688a1171ad5aeffa593aae41193 (patch)
treefea395acf042b51e97a86e2c4cbcf8c16b2912b7 /core
parent9723191b19f6ddc12f0c3376ede7529b2d72e6a2 (diff)
parent676a0de58d3d7c508b0eeeff192d2095a46f7382 (diff)
downloaddexon-8560004f380dc688a1171ad5aeffa593aae41193.tar.gz
dexon-8560004f380dc688a1171ad5aeffa593aae41193.tar.zst
dexon-8560004f380dc688a1171ad5aeffa593aae41193.zip
wip
Diffstat (limited to 'core')
-rw-r--r--core/block_processor.go68
-rw-r--r--core/block_processor_test.go9
-rw-r--r--core/chain_makers.go142
-rw-r--r--core/chain_manager.go163
-rw-r--r--core/chain_manager_test.go204
-rw-r--r--core/error.go36
-rw-r--r--core/events.go10
-rw-r--r--core/execution.go10
-rw-r--r--core/filter.go37
-rw-r--r--core/genesis.go17
-rw-r--r--core/manager.go3
-rw-r--r--core/state_transition.go30
-rw-r--r--core/transaction_pool.go9
-rw-r--r--core/types/block.go58
-rw-r--r--core/types/bloom9.go7
15 files changed, 675 insertions, 128 deletions
diff --git a/core/block_processor.go b/core/block_processor.go
index 7eaeb5be0..34c12729c 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -12,7 +12,6 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/pow"
- "github.com/ethereum/go-ethereum/pow/ezp"
"github.com/ethereum/go-ethereum/state"
"gopkg.in/fatih/set.v0"
)
@@ -46,11 +45,11 @@ type BlockProcessor struct {
eventMux *event.TypeMux
}
-func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
+func NewBlockProcessor(db ethutil.Database, pow pow.PoW, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
sm := &BlockProcessor{
db: db,
mem: make(map[string]*big.Int),
- Pow: ezp.New(),
+ Pow: pow,
bc: chainManager,
eventMux: eventMux,
txpool: txpool,
@@ -105,6 +104,9 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
return receipt, txGas, err
}
+func (self *BlockProcessor) ChainManager() *ChainManager {
+ return self.bc
+}
func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
var (
@@ -174,10 +176,15 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
state := state.New(parent.Root(), sm.db)
// Block validation
- if err = sm.ValidateBlock(block, parent); err != nil {
+ if err = sm.ValidateHeader(block.Header(), parent.Header()); err != nil {
return
}
+ // There can be at most two uncles
+ if len(block.Uncles()) > 2 {
+ return nil, ValidationError("Block can only contain one uncle (contained %v)", len(block.Uncles()))
+ }
+
receipts, err := sm.TransitionState(state, parent, block, false)
if err != nil {
return
@@ -204,7 +211,6 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
receiptSha := types.DeriveSha(receipts)
if bytes.Compare(receiptSha, header.ReceiptHash) != 0 {
- fmt.Println("receipts", receipts)
err = fmt.Errorf("validating receipt root. received=%x got=%x", header.ReceiptHash, receiptSha)
return
}
@@ -237,36 +243,38 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
// Validates the current block. Returns an error if the block was invalid,
// an uncle or anything that isn't on the current block chain.
// Validation validates easy over difficult (dagger takes longer time = difficult)
-func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
- if len(block.Header().Extra) > 1024 {
- return fmt.Errorf("Block extra data too long (%d)", len(block.Header().Extra))
+func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error {
+ if len(block.Extra) > 1024 {
+ return fmt.Errorf("Block extra data too long (%d)", len(block.Extra))
}
expd := CalcDifficulty(block, parent)
- if expd.Cmp(block.Header().Difficulty) != 0 {
- return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd)
+ if expd.Cmp(block.Difficulty) != 0 {
+ return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
}
- expl := CalcGasLimit(parent, block)
- if expl.Cmp(block.Header().GasLimit) != 0 {
- return fmt.Errorf("GasLimit check failed for block %v, %v", block.Header().GasLimit, expl)
+ // block.gasLimit - parent.gasLimit <= parent.gasLimit / 1024
+ a := new(big.Int).Sub(block.GasLimit, parent.GasLimit)
+ b := new(big.Int).Div(parent.GasLimit, big.NewInt(1024))
+ if a.Cmp(b) > 0 {
+ return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b)
}
- if block.Time() < parent.Time() {
- return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time)
+ if block.Time <= parent.Time {
+ return ValidationError("Block timestamp not after or equal to prev block (%v - %v)", block.Time, parent.Time)
}
- if block.Time() > time.Now().Unix() {
+ if int64(block.Time) > time.Now().Unix() {
return BlockFutureErr
}
- if new(big.Int).Sub(block.Number(), parent.Number()).Cmp(big.NewInt(1)) != 0 {
+ if new(big.Int).Sub(block.Number, parent.Number).Cmp(big.NewInt(1)) != 0 {
return BlockNumberErr
}
// Verify the nonce of the block. Return an error if it's not valid
- if !sm.Pow.Verify(block) {
- return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Header().Nonce))
+ if !sm.Pow.Verify(types.NewBlockWithHeader(block)) {
+ return ValidationError("Block's nonce is invalid (= %x)", block.Nonce)
}
return nil
@@ -276,25 +284,41 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren
reward := new(big.Int).Set(BlockReward)
ancestors := set.New()
+ uncles := set.New()
+ ancestorHeaders := make(map[string]*types.Header)
for _, ancestor := range sm.bc.GetAncestors(block, 7) {
- ancestors.Add(string(ancestor.Hash()))
+ hash := string(ancestor.Hash())
+ ancestorHeaders[hash] = ancestor.Header()
+ ancestors.Add(hash)
+ // Include ancestors uncles in the uncle set. Uncles must be unique.
+ for _, uncle := range ancestor.Uncles() {
+ uncles.Add(string(uncle.Hash()))
+ }
}
- uncles := set.New()
uncles.Add(string(block.Hash()))
for _, uncle := range block.Uncles() {
if uncles.Has(string(uncle.Hash())) {
// Error not unique
return UncleError("Uncle not unique")
}
+
uncles.Add(string(uncle.Hash()))
+ if ancestors.Has(string(uncle.Hash())) {
+ return UncleError("Uncle is ancestor")
+ }
+
if !ancestors.Has(string(uncle.ParentHash)) {
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
}
+ if err := sm.ValidateHeader(uncle, ancestorHeaders[string(uncle.ParentHash)]); err != nil {
+ return ValidationError(fmt.Sprintf("%v", err))
+ }
+
if !sm.Pow.Verify(types.NewBlockWithHeader(uncle)) {
- return ValidationError("Uncle's nonce is invalid (= %v)", ethutil.Bytes2Hex(uncle.Nonce))
+ return ValidationError("Uncle's nonce is invalid (= %x)", uncle.Nonce)
}
r := new(big.Int)
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
new file mode 100644
index 000000000..b5c50dc3d
--- /dev/null
+++ b/core/chain_makers.go
@@ -0,0 +1,142 @@
+package core
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/pow"
+ "github.com/ethereum/go-ethereum/state"
+)
+
+// So we can generate blocks easily
+type FakePow struct{}
+
+func (f FakePow) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte, []byte) {
+ return 0, nil, nil
+}
+func (f FakePow) Verify(block pow.Block) bool { return true }
+func (f FakePow) GetHashrate() int64 { return 0 }
+func (f FakePow) Turbo(bool) {}
+
+// So we can deterministically seed different blockchains
+var (
+ CanonicalSeed = 1
+ ForkSeed = 2
+)
+
+// Utility functions for making chains on the fly
+// Exposed for sake of testing from other packages (eg. go-ethash)
+func NewBlockFromParent(addr []byte, parent *types.Block) *types.Block {
+ return newBlockFromParent(addr, parent)
+}
+
+func MakeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database, seed int) *types.Block {
+ return makeBlock(bman, parent, i, db, seed)
+}
+
+func MakeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database, seed int) types.Blocks {
+ return makeChain(bman, parent, max, db, seed)
+}
+
+func NewChainMan(block *types.Block, eventMux *event.TypeMux, db ethutil.Database) *ChainManager {
+ return newChainManager(block, eventMux, db)
+}
+
+func NewBlockProc(db ethutil.Database, txpool *TxPool, cman *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
+ return newBlockProcessor(db, txpool, cman, eventMux)
+}
+
+func NewCanonical(n int, db ethutil.Database) (*BlockProcessor, error) {
+ return newCanonical(n, db)
+}
+
+// block time is fixed at 10 seconds
+func newBlockFromParent(addr []byte, parent *types.Block) *types.Block {
+ block := types.NewBlock(parent.Hash(), addr, parent.Root(), ethutil.BigPow(2, 32), 0, "")
+ block.SetUncles(nil)
+ block.SetTransactions(nil)
+ block.SetReceipts(nil)
+
+ header := block.Header()
+ header.Difficulty = CalcDifficulty(block.Header(), parent.Header())
+ header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
+ header.Time = parent.Header().Time + 10
+ header.GasLimit = CalcGasLimit(parent, block)
+
+ block.Td = parent.Td
+
+ return block
+}
+
+// Actually make a block by simulating what miner would do
+// we seed chains by the first byte of the coinbase
+func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database, seed int) *types.Block {
+ addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20)
+ addr[0] = byte(seed)
+ block := newBlockFromParent(addr, parent)
+ state := state.New(block.Root(), db)
+ cbase := state.GetOrNewStateObject(addr)
+ cbase.SetGasPool(CalcGasLimit(parent, block))
+ cbase.AddBalance(BlockReward)
+ state.Update(ethutil.Big0)
+ block.SetRoot(state.Root())
+ return block
+}
+
+// Make a chain with real blocks
+// Runs ProcessWithParent to get proper state roots
+func makeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database, seed int) types.Blocks {
+ bman.bc.currentBlock = parent
+ blocks := make(types.Blocks, max)
+ for i := 0; i < max; i++ {
+ block := makeBlock(bman, parent, i, db, seed)
+ td, err := bman.processWithParent(block, parent)
+ if err != nil {
+ fmt.Println("process with parent failed", err)
+ panic(err)
+ }
+ block.Td = td
+ blocks[i] = block
+ parent = block
+ }
+ return blocks
+}
+
+// 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{blockDb: db, stateDb: db, genesisBlock: GenesisBlock(db), eventMux: eventMux}
+ if block == nil {
+ bc.Reset()
+ } else {
+ bc.currentBlock = block
+ bc.td = block.Td
+ }
+ return bc
+}
+
+// block processor with fake pow
+func newBlockProcessor(db ethutil.Database, txpool *TxPool, cman *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
+ bman := NewBlockProcessor(db, FakePow{}, txpool, newChainManager(nil, eventMux, db), eventMux)
+ return bman
+}
+
+// Make a new, deterministic canonical chain by running InsertChain
+// on result of makeChain
+func newCanonical(n int, db ethutil.Database) (*BlockProcessor, error) {
+ eventMux := &event.TypeMux{}
+ txpool := NewTxPool(eventMux)
+
+ bman := newBlockProcessor(db, txpool, newChainManager(nil, eventMux, db), eventMux)
+ bman.bc.SetProcessor(bman)
+ parent := bman.bc.CurrentBlock()
+ if n == 0 {
+ return bman, nil
+ }
+ lchain := makeChain(bman, parent, n, db, CanonicalSeed)
+ err := bman.bc.InsertChain(lchain)
+ return bman, err
+}
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 959bfd398..9dc41f421 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -14,25 +14,28 @@ import (
"github.com/ethereum/go-ethereum/state"
)
-var chainlogger = logger.NewLogger("CHAIN")
-
-type ChainEvent struct {
- Block *types.Block
- Td *big.Int
-}
+var (
+ chainlogger = logger.NewLogger("CHAIN")
+ jsonlogger = logger.NewJsonLogger()
+)
type StateQuery interface {
GetAccount(addr []byte) *state.StateObject
}
-func CalcDifficulty(block, parent *types.Block) *big.Int {
+func CalcDifficulty(block, parent *types.Header) *big.Int {
diff := new(big.Int)
- adjust := new(big.Int).Rsh(parent.Difficulty(), 10)
- if block.Time() >= parent.Time()+8 {
- diff.Sub(parent.Difficulty(), adjust)
+ min := big.NewInt(2048)
+ adjust := new(big.Int).Div(parent.Difficulty, min)
+ if (block.Time - parent.Time) < 8 {
+ diff.Add(parent.Difficulty, adjust)
} else {
- diff.Add(parent.Difficulty(), adjust)
+ diff.Sub(parent.Difficulty, adjust)
+ }
+
+ if diff.Cmp(GenesisDiff) < 0 {
+ return GenesisDiff
}
return diff
@@ -58,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())
@@ -73,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
@@ -86,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
}
@@ -122,7 +128,7 @@ func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlo
self.mu.RLock()
defer self.mu.RUnlock()
- return self.td, self.currentBlock.Hash(), self.Genesis().Hash()
+ return self.td, self.currentBlock.Hash(), self.genesisBlock.Hash()
}
func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
@@ -130,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 {
@@ -158,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)
@@ -166,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()
}
@@ -192,7 +198,7 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
coinbase,
root,
ethutil.BigPow(2, 32),
- nil,
+ 0,
"")
block.SetUncles(nil)
block.SetTransactions(nil)
@@ -201,7 +207,7 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
parent := bc.currentBlock
if parent != nil {
header := block.Header()
- header.Difficulty = CalcDifficulty(block, parent)
+ header.Difficulty = CalcDifficulty(block.Header(), parent.Header())
header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
header.GasLimit = CalcGasLimit(parent, block)
@@ -215,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
@@ -226,6 +232,21 @@ func (bc *ChainManager) Reset() {
bc.setTotalDifficulty(ethutil.Big("0"))
}
+func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
+ bc.mu.Lock()
+ defer bc.mu.Unlock()
+
+ for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
+ bc.blockDb.Delete(block.Hash())
+ }
+
+ // Prepare the genesis block
+ bc.genesisBlock = gb
+ bc.write(bc.genesisBlock)
+ bc.insert(bc.genesisBlock)
+ bc.currentBlock = bc.genesisBlock
+}
+
func (self *ChainManager) Export() []byte {
self.mu.RLock()
defer self.mu.RUnlock()
@@ -242,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
@@ -259,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
}
@@ -268,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
@@ -288,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
}
@@ -342,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
}
@@ -367,16 +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)
+}
+
+type queueEvent struct {
+ queue []interface{}
+ canonicalCount int
+ sideCount int
+ splitCount int
}
func (self *ChainManager) InsertChain(chain types.Blocks) error {
- self.tsmu.Lock()
- defer self.tsmu.Unlock()
+ //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)
@@ -393,43 +421,84 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
}
block.Td = td
- var canonical, split bool
self.mu.Lock()
+ cblock := self.currentBlock
{
// Write block to database. Eventually we'll have to improve on this and throw away blocks that are
// not in the canonical chain.
self.write(block)
- cblock := self.currentBlock
// Compare the TD of the last known block in the canonical chain to make sure it's greater.
// At this point it's possible that a different chain (fork) becomes the new canonical chain.
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
+ 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.stateDb))
+ queue[i] = ChainEvent{block}
+ queueEvent.canonicalCount++
+ } else {
+ queue[i] = ChainSideEvent{block}
+ queueEvent.sideCount++
}
}
self.mu.Unlock()
- if canonical {
- self.setTransState(state.New(block.Root(), self.db))
- self.eventMux.Post(ChainEvent{block, td})
- }
-
- if split {
- self.setTxState(state.New(block.Root(), self.db))
- self.eventMux.Post(ChainSplitEvent{block})
- }
}
+ // 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 bc3a264d1..e78c2e980 100644
--- a/core/chain_manager_test.go
+++ b/core/chain_manager_test.go
@@ -3,6 +3,7 @@ package core
import (
"bytes"
"fmt"
+ "math/big"
"os"
"path"
"runtime"
@@ -21,6 +22,75 @@ func init() {
ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH")
}
+// Test fork of length N starting from block i
+func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big.Int)) {
+ // switch databases to process the new chain
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ // copy old chain up to i into new db with deterministic canonical
+ bman2, err := newCanonical(i, db)
+ if err != nil {
+ t.Fatal("could not make new canonical in testFork", err)
+ }
+ // asert the bmans have the same block at i
+ bi1 := bman.bc.GetBlockByNumber(uint64(i)).Hash()
+ bi2 := bman2.bc.GetBlockByNumber(uint64(i)).Hash()
+ if bytes.Compare(bi1, bi2) != 0 {
+ t.Fatal("chains do not have the same hash at height", i)
+ }
+
+ bman2.bc.SetProcessor(bman2)
+
+ // extend the fork
+ parent := bman2.bc.CurrentBlock()
+ chainB := makeChain(bman2, parent, N, db, ForkSeed)
+ err = bman2.bc.InsertChain(chainB)
+ if err != nil {
+ t.Fatal("Insert chain error for fork:", err)
+ }
+
+ tdpre := bman.bc.Td()
+ // Test the fork's blocks on the original chain
+ td, err := testChain(chainB, bman)
+ if err != nil {
+ t.Fatal("expected chainB not to give errors:", err)
+ }
+ // Compare difficulties
+ f(tdpre, td)
+}
+
+func printChain(bc *ChainManager) {
+ for i := bc.CurrentBlock().Number().Uint64(); i > 0; i-- {
+ b := bc.GetBlockByNumber(uint64(i))
+ fmt.Printf("\t%x\n", b.Hash())
+ }
+}
+
+// process blocks against a chain
+func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
+ td := new(big.Int)
+ for _, block := range chainB {
+ td2, err := bman.bc.processor.Process(block)
+ if err != nil {
+ if IsKnownBlockErr(err) {
+ continue
+ }
+ return nil, err
+ }
+ block.Td = td2
+ td = td2
+
+ bman.bc.mu.Lock()
+ {
+ bman.bc.write(block)
+ }
+ bman.bc.mu.Unlock()
+ }
+ return td, nil
+}
+
func loadChain(fn string, t *testing.T) (types.Blocks, error) {
fh, err := os.OpenFile(path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "_data", fn), os.O_RDONLY, os.ModePerm)
if err != nil {
@@ -45,6 +115,130 @@ func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *
done <- true
}
+func TestExtendCanonical(t *testing.T) {
+ CanonicalLength := 5
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ // make first chain starting from genesis
+ bman, err := newCanonical(CanonicalLength, db)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ f := func(td1, td2 *big.Int) {
+ if td2.Cmp(td1) <= 0 {
+ t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
+ }
+ }
+ // Start fork from current height (CanonicalLength)
+ testFork(t, bman, CanonicalLength, 1, f)
+ testFork(t, bman, CanonicalLength, 2, f)
+ testFork(t, bman, CanonicalLength, 5, f)
+ testFork(t, bman, CanonicalLength, 10, f)
+}
+
+func TestShorterFork(t *testing.T) {
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ // make first chain starting from genesis
+ bman, err := newCanonical(10, db)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ f := func(td1, td2 *big.Int) {
+ if td2.Cmp(td1) >= 0 {
+ t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", td1)
+ }
+ }
+ // Sum of numbers must be less than 10
+ // for this to be a shorter fork
+ testFork(t, bman, 0, 3, f)
+ testFork(t, bman, 0, 7, f)
+ testFork(t, bman, 1, 1, f)
+ testFork(t, bman, 1, 7, f)
+ testFork(t, bman, 5, 3, f)
+ testFork(t, bman, 5, 4, f)
+}
+
+func TestLongerFork(t *testing.T) {
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ // make first chain starting from genesis
+ bman, err := newCanonical(10, db)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ f := func(td1, td2 *big.Int) {
+ if td2.Cmp(td1) <= 0 {
+ t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
+ }
+ }
+ // Sum of numbers must be greater than 10
+ // for this to be a longer fork
+ testFork(t, bman, 0, 11, f)
+ testFork(t, bman, 0, 15, f)
+ testFork(t, bman, 1, 10, f)
+ testFork(t, bman, 1, 12, f)
+ testFork(t, bman, 5, 6, f)
+ testFork(t, bman, 5, 8, f)
+}
+
+func TestEqualFork(t *testing.T) {
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ bman, err := newCanonical(10, db)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ f := func(td1, td2 *big.Int) {
+ if td2.Cmp(td1) != 0 {
+ t.Error("expected chainB to have equal difficulty. Got", td2, "expected ", td1)
+ }
+ }
+ // Sum of numbers must be equal to 10
+ // for this to be an equal fork
+ testFork(t, bman, 0, 10, f)
+ testFork(t, bman, 1, 9, f)
+ testFork(t, bman, 2, 8, f)
+ testFork(t, bman, 5, 5, f)
+ testFork(t, bman, 6, 4, f)
+ testFork(t, bman, 9, 1, f)
+}
+
+func TestBrokenChain(t *testing.T) {
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ bman, err := newCanonical(10, db)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ db2, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ bman2, err := newCanonical(10, db2)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ bman2.bc.SetProcessor(bman2)
+ parent := bman2.bc.CurrentBlock()
+ chainB := makeChain(bman2, parent, 5, db2, ForkSeed)
+ chainB = chainB[1:]
+ _, err = testChain(chainB, bman)
+ if err == nil {
+ t.Error("expected broken chain to return error")
+ }
+}
+
func TestChainInsertions(t *testing.T) {
t.Skip() // travil fails.
@@ -63,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
@@ -109,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 {
@@ -138,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 e86bacb2d..04e40646c 100644
--- a/core/error.go
+++ b/core/error.go
@@ -22,7 +22,7 @@ func (err *ParentErr) Error() string {
}
func ParentError(hash []byte) error {
- return &ParentErr{Message: fmt.Sprintf("Block's parent unkown %x", hash)}
+ return &ParentErr{Message: fmt.Sprintf("Block's parent unknown %x", hash)}
}
func IsParentErr(err error) bool {
@@ -87,6 +87,24 @@ func IsNonceErr(err error) bool {
return ok
}
+type InvalidTxErr struct {
+ Message string
+}
+
+func (err *InvalidTxErr) Error() string {
+ return err.Message
+}
+
+func InvalidTxError(err error) *InvalidTxErr {
+ return &InvalidTxErr{fmt.Sprintf("%v", err)}
+}
+
+func IsInvalidTxErr(err error) bool {
+ _, ok := err.(*InvalidTxErr)
+
+ return ok
+}
+
type OutOfGasErr struct {
Message string
}
@@ -128,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 5e0cbd37e..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,16 +57,16 @@ 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()
start := time.Now()
ret, err = evm.Run(to, caller, code, self.value, self.Gas, self.price, self.input)
+ chainlogger.Debugf("vm took %v\n", time.Since(start))
if err != nil {
env.State().Set(snapshot)
}
- chainlogger.Debugf("vm took %v\n", time.Since(start))
return
}
diff --git a/core/filter.go b/core/filter.go
index cdf7b282d..d58aa8d7c 100644
--- a/core/filter.go
+++ b/core/filter.go
@@ -17,7 +17,7 @@ type FilterOptions struct {
Latest int64
Address [][]byte
- Topics [][]byte
+ Topics [][][]byte
Skip int
Max int
@@ -31,7 +31,7 @@ type Filter struct {
skip int
address [][]byte
max int
- topics [][]byte
+ topics [][][]byte
BlockCallback func(*types.Block)
PendingCallback func(*types.Block)
@@ -44,6 +44,8 @@ func NewFilter(eth Backend) *Filter {
return &Filter{eth: eth}
}
+// SetOptions copies the filter options to the filter it self. The reason for this "silly" copy
+// is simply because named arguments in this case is extremely nice and readable.
func (self *Filter) SetOptions(options FilterOptions) {
self.earliest = options.Earliest
self.latest = options.Latest
@@ -69,7 +71,7 @@ func (self *Filter) SetAddress(addr [][]byte) {
self.address = addr
}
-func (self *Filter) SetTopics(topics [][]byte) {
+func (self *Filter) SetTopics(topics [][][]byte) {
self.topics = topics
}
@@ -145,14 +147,22 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs {
// Filter the logs for interesting stuff
Logs:
for _, log := range logs {
- if !includes(self.address, log.Address()) {
+ if len(self.address) > 0 && !includes(self.address, log.Address()) {
continue
}
- max := int(math.Min(float64(len(self.topics)), float64(len(log.Topics()))))
- for i := 0; i < max; i++ {
- if !bytes.Equal(log.Topics()[i], self.topics[i]) {
- continue Logs
+ logTopics := make([][]byte, len(self.topics))
+ copy(logTopics, log.Topics())
+
+ for i, topics := range self.topics {
+ for _, topic := range topics {
+ var match bool
+ if bytes.Equal(log.Topics()[i], topic) {
+ match = true
+ }
+ if !match {
+ continue Logs
+ }
}
}
@@ -177,8 +187,15 @@ func (self *Filter) bloomFilter(block *types.Block) bool {
}
}
- for _, topic := range self.topics {
- if !types.BloomLookup(block.Bloom(), topic) {
+ for _, sub := range self.topics {
+ var included bool
+ for _, topic := range sub {
+ if types.BloomLookup(block.Bloom(), topic) {
+ included = true
+ break
+ }
+ }
+ if !included {
return false
}
}
diff --git a/core/genesis.go b/core/genesis.go
index decffc541..a3f5dfb38 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -22,12 +22,17 @@ var ZeroHash512 = make([]byte, 64)
var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{}))
var EmptyListRoot = crypto.Sha3(ethutil.Encode(""))
+var GenesisDiff = big.NewInt(131072)
+
func GenesisBlock(db ethutil.Database) *types.Block {
- genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, big.NewInt(131072), crypto.Sha3(big.NewInt(42).Bytes()), "")
+ genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, GenesisDiff, 42, "")
genesis.Header().Number = ethutil.Big0
genesis.Header().GasLimit = big.NewInt(1000000)
genesis.Header().GasUsed = ethutil.Big0
genesis.Header().Time = 0
+ genesis.Header().SeedHash = make([]byte, 32)
+ genesis.Header().MixDigest = make([]byte, 32)
+
genesis.Td = ethutil.Big0
genesis.SetUncles([]*types.Header{})
@@ -55,6 +60,10 @@ func GenesisBlock(db ethutil.Database) *types.Block {
}
var genesisData = []byte(`{
+ "0000000000000000000000000000000000000001": {"balance": "1"},
+ "0000000000000000000000000000000000000002": {"balance": "1"},
+ "0000000000000000000000000000000000000003": {"balance": "1"},
+ "0000000000000000000000000000000000000004": {"balance": "1"},
"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
@@ -62,9 +71,5 @@ var genesisData = []byte(`{
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
- "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
- "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": {"balance": "154162184000000000000000"},
- "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": {"balance": "102774789000000000000000"},
- "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": {"balance": "51387394000000000000000"},
- "b7576e9d314df41ec5506494293afb1bd5d3f65d": {"balance": "69423399000000000000000"}
+ "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}
}`)
diff --git a/core/manager.go b/core/manager.go
index bb039d063..803069377 100644
--- a/core/manager.go
+++ b/core/manager.go
@@ -15,6 +15,7 @@ type Backend interface {
IsListening() bool
Peers() []*p2p.Peer
KeyManager() *crypto.KeyManager
- 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 7331fdd4a..f54acd6ee 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -12,6 +12,8 @@ import (
const tryJit = false
+var ()
+
/*
* The State transitioning model
*
@@ -144,7 +146,7 @@ func (self *StateTransition) preCheck() (err error) {
// Pre-pay gas / Buy gas of the coinbase account
if err = self.BuyGas(); err != nil {
- return err
+ return InvalidTxError(err)
}
return nil
@@ -165,26 +167,26 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
defer self.RefundGas()
- // Increment the nonce for the next transaction
- self.state.SetNonce(sender.Address(), sender.Nonce()+1)
- //sender.Nonce += 1
-
// Transaction gas
if err = self.UseGas(vm.GasTx); err != nil {
- return
+ return nil, InvalidTxError(err)
}
+ // Increment the nonce for the next transaction
+ self.state.SetNonce(sender.Address(), sender.Nonce()+1)
+ //sender.Nonce += 1
+
// Pay data gas
var dgas int64
for _, byt := range self.data {
if byt != 0 {
- dgas += vm.GasData.Int64()
+ dgas += vm.GasTxDataNonzeroByte.Int64()
} else {
- dgas += 1 // This is 1/5. If GasData changes this fails
+ dgas += vm.GasTxDataZeroByte.Int64()
}
}
if err = self.UseGas(big.NewInt(dgas)); err != nil {
- return
+ return nil, InvalidTxError(err)
}
//stateCopy := self.env.State().Copy()
@@ -230,10 +232,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
}
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
index 050cff3d8..bd377f679 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -117,8 +117,13 @@ func (self *TxPool) add(tx *types.Transaction) error {
} else {
to = "[NEW_CONTRACT]"
}
-
- txplogger.Debugf("(t) %x => %s (%v) %x\n", tx.From()[:4], to, tx.Value, tx.Hash())
+ var from string
+ if len(tx.From()) > 0 {
+ from = ethutil.Bytes2Hex(tx.From()[:4])
+ } else {
+ return errors.New(fmt.Sprintf("FROM ADDRESS MUST BE POSITIVE (was %v)", tx.From()))
+ }
+ txplogger.Debugf("(t) %x => %s (%v) %x\n", from, to, tx.Value, tx.Hash())
// Notify the subscribers
go self.eventMux.Post(TxPreEvent{tx})
diff --git a/core/types/block.go b/core/types/block.go
index d57de1311..31c7c2b87 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -2,6 +2,7 @@ package types
import (
"bytes"
+ "encoding/binary"
"fmt"
"math/big"
"sort"
@@ -39,14 +40,33 @@ type Header struct {
Time uint64
// Extra data
Extra string
- // Block Nonce for verification
- Nonce ethutil.Bytes
+ // SeedHash used for light client verification
+ SeedHash ethutil.Bytes
+ // Mix digest for quick checking to prevent DOS
+ MixDigest ethutil.Bytes
+ // Nonce
+ Nonce []byte
}
func (self *Header) rlpData(withNonce bool) []interface{} {
- fields := []interface{}{self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra}
+ fields := []interface{}{
+ self.ParentHash,
+ self.UncleHash,
+ self.Coinbase,
+ self.Root,
+ self.TxHash,
+ self.ReceiptHash,
+ self.Bloom,
+ self.Difficulty,
+ self.Number,
+ self.GasLimit,
+ self.GasUsed,
+ self.Time,
+ self.Extra,
+ self.SeedHash,
+ }
if withNonce {
- fields = append(fields, self.Nonce)
+ fields = append(fields, self.MixDigest, self.Nonce)
}
return fields
@@ -77,24 +97,29 @@ type Block struct {
Reward *big.Int
}
-func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.Int, nonce []byte, extra string) *Block {
+func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.Int, nonce uint64, extra string) *Block {
header := &Header{
Root: root,
ParentHash: parentHash,
Coinbase: coinbase,
Difficulty: difficulty,
- Nonce: nonce,
Time: uint64(time.Now().Unix()),
Extra: extra,
GasUsed: new(big.Int),
GasLimit: new(big.Int),
}
+ header.setNonce(nonce)
block := &Block{header: header, Reward: new(big.Int)}
return block
}
+func (self *Header) setNonce(nonce uint64) {
+ self.Nonce = make([]byte, 8)
+ binary.BigEndian.PutUint64(self.Nonce, nonce)
+}
+
func NewBlockWithHeader(header *Header) *Block {
return &Block{header: header}
}
@@ -174,9 +199,17 @@ func (self *Block) RlpDataForStorage() interface{} {
}
// Header accessors (add as you need them)
-func (self *Block) Number() *big.Int { return self.header.Number }
-func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() }
-func (self *Block) Nonce() []byte { return self.header.Nonce }
+func (self *Block) Number() *big.Int { return self.header.Number }
+func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() }
+func (self *Block) MixDigest() []byte { return self.header.MixDigest }
+func (self *Block) SeedHash() []byte { return self.header.SeedHash }
+func (self *Block) Nonce() uint64 {
+ return binary.BigEndian.Uint64(self.header.Nonce)
+}
+func (self *Block) SetNonce(nonce uint64) {
+ self.header.setNonce(nonce)
+}
+
func (self *Block) Bloom() []byte { return self.header.Bloom }
func (self *Block) Coinbase() []byte { return self.header.Coinbase }
func (self *Block) Time() int64 { return int64(self.header.Time) }
@@ -200,7 +233,6 @@ func (self *Block) GetUncle(i int) *Header {
// Implement pow.Block
func (self *Block) Difficulty() *big.Int { return self.header.Difficulty }
-func (self *Block) N() []byte { return self.header.Nonce }
func (self *Block) HashNoNonce() []byte { return self.header.HashNoNonce() }
func (self *Block) Hash() []byte {
@@ -249,8 +281,10 @@ func (self *Header) String() string {
GasUsed: %v
Time: %v
Extra: %v
- Nonce: %x
-`, self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.Nonce)
+ SeedHash: %x
+ MixDigest: %x
+ Nonce: %x`,
+ self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.SeedHash, self.MixDigest, self.Nonce)
}
type Blocks []*Block
diff --git a/core/types/bloom9.go b/core/types/bloom9.go
index c1841e553..578265a34 100644
--- a/core/types/bloom9.go
+++ b/core/types/bloom9.go
@@ -14,7 +14,7 @@ func CreateBloom(receipts Receipts) []byte {
bin.Or(bin, LogsBloom(receipt.logs))
}
- return ethutil.LeftPadBytes(bin.Bytes(), 64)
+ return ethutil.LeftPadBytes(bin.Bytes(), 256)
}
func LogsBloom(logs state.Logs) *big.Int {
@@ -37,9 +37,10 @@ func LogsBloom(logs state.Logs) *big.Int {
func bloom9(b []byte) *big.Int {
r := new(big.Int)
- for _, i := range []int{0, 2, 4} {
+
+ for i := 0; i < 16; i += 2 {
t := big.NewInt(1)
- b := uint(b[i+1]) + 256*(uint(b[i])&1)
+ b := uint(b[i+1]) + 1024*(uint(b[i])&1)
r.Or(r, t.Lsh(t, b))
}