aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorEthan Buchman <ethan@coinculture.info>2015-02-18 08:25:18 +0800
committerEthan Buchman <ethan@coinculture.info>2015-02-18 08:25:18 +0800
commit2ba65f4fbaea49c1e0d99959b0331e09b153f931 (patch)
treeadd8cabb05cd7fbf0ba4b4bbaf9460dacfc2082d /core
parent2da367a2bee84d74d1bb0ea1b42d4c22fae486dd (diff)
parent60318c96d03bcaaf731802b1080a3d87cb482124 (diff)
downloadgo-tangerine-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar
go-tangerine-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar.gz
go-tangerine-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar.bz2
go-tangerine-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar.lz
go-tangerine-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar.xz
go-tangerine-2ba65f4fbaea49c1e0d99959b0331e09b153f931.tar.zst
go-tangerine-2ba65f4fbaea49c1e0d99959b0331e09b153f931.zip
Merge branch 'develop' of https://github.com/ethereum/go-ethereum into develop
Diffstat (limited to 'core')
-rw-r--r--core/block_processor.go161
-rw-r--r--core/chain_manager.go65
-rw-r--r--core/execution.go3
-rw-r--r--core/filter.go155
-rw-r--r--core/genesis.go3
-rw-r--r--core/helper_test.go8
-rw-r--r--core/manager.go20
-rw-r--r--core/state_transition.go29
-rw-r--r--core/transaction_pool.go20
-rw-r--r--core/transaction_pool_test.go10
-rw-r--r--core/types/block.go29
-rw-r--r--core/types/common.go8
-rw-r--r--core/types/receipt.go2
-rw-r--r--core/vm_env.go4
14 files changed, 283 insertions, 234 deletions
diff --git a/core/block_processor.go b/core/block_processor.go
index 37acc4f72..893c586dd 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -8,33 +8,21 @@ import (
"time"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/pow/ezp"
"github.com/ethereum/go-ethereum/state"
"gopkg.in/fatih/set.v0"
)
-var statelogger = logger.NewLogger("BLOCK")
-
-type EthManager interface {
- BlockProcessor() *BlockProcessor
- ChainManager() *ChainManager
- TxPool() *TxPool
- PeerCount() int
- IsMining() bool
- IsListening() bool
- Peers() []*p2p.Peer
- KeyManager() *crypto.KeyManager
- ClientIdentity() p2p.ClientIdentity
- Db() ethutil.Database
- EventMux() *event.TypeMux
+type PendingBlockEvent struct {
+ Block *types.Block
}
+var statelogger = logger.NewLogger("BLOCK")
+
type BlockProcessor struct {
db ethutil.Database
// Mutex for locking the block processor. Blocks can only be handled one at a time
@@ -60,8 +48,9 @@ type BlockProcessor struct {
func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
sm := &BlockProcessor{
- db: db,
- mem: make(map[string]*big.Int),
+ db: db,
+ mem: make(map[string]*big.Int),
+ //Pow: &ethash.Ethash{},
Pow: ezp.New(),
bc: chainManager,
eventMux: eventMux,
@@ -84,6 +73,37 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block
return receipts, nil
}
+func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, state *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
+ // If we are mining this block and validating we want to set the logs back to 0
+ state.EmptyLogs()
+
+ txGas := new(big.Int).Set(tx.Gas())
+
+ cb := state.GetStateObject(coinbase.Address())
+ st := NewStateTransition(NewEnv(state, self.bc, tx, block), tx, cb)
+ _, err := st.TransitionState()
+
+ txGas.Sub(txGas, st.gas)
+
+ // Update the state with pending changes
+ state.Update(txGas)
+
+ cumulative := new(big.Int).Set(usedGas.Add(usedGas, txGas))
+ receipt := types.NewReceipt(state.Root(), cumulative)
+ receipt.SetLogs(state.Logs())
+ receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
+ chainlogger.Debugln(receipt)
+
+ // Notify all subscribers
+ if !transientProcess {
+ go self.eventMux.Post(TxPostEvent{tx})
+ }
+
+ go self.eventMux.Post(state.Logs())
+
+ return receipt, txGas, err
+}
+
func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
var (
receipts types.Receipts
@@ -94,86 +114,62 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
cumulativeSum = new(big.Int)
)
-done:
- for i, tx := range txs {
- // If we are mining this block and validating we want to set the logs back to 0
- state.EmptyLogs()
-
- txGas := new(big.Int).Set(tx.Gas())
-
- cb := state.GetStateObject(coinbase.Address())
- st := NewStateTransition(NewEnv(state, self.bc, tx, block), tx, cb)
- _, err = st.TransitionState()
+ for _, tx := range txs {
+ receipt, txGas, err := self.ApplyTransaction(coinbase, state, block, tx, totalUsedGas, transientProcess)
if err != nil {
switch {
case IsNonceErr(err):
- err = nil // ignore error
- continue
+ return nil, nil, nil, nil, err
case IsGasLimitErr(err):
- unhandled = txs[i:]
-
- break done
+ return nil, nil, nil, nil, err
default:
statelogger.Infoln(err)
erroneous = append(erroneous, tx)
err = nil
}
}
-
- txGas.Sub(txGas, st.gas)
- cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice()))
-
- // Update the state with pending changes
- state.Update(txGas)
-
- cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas))
- receipt := types.NewReceipt(state.Root(), cumulative)
- receipt.SetLogs(state.Logs())
- receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
- chainlogger.Debugln(receipt)
-
- // Notify all subscribers
- if !transientProcess {
- go self.eventMux.Post(TxPostEvent{tx})
- }
-
receipts = append(receipts, receipt)
handled = append(handled, tx)
- if ethutil.Config.Diff && ethutil.Config.DiffType == "all" {
- state.CreateOutputForDiff()
- }
+ cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice()))
}
block.Reward = cumulativeSum
block.Header().GasUsed = totalUsedGas
+ if transientProcess {
+ go self.eventMux.Post(PendingBlockEvent{block})
+ }
+
return receipts, handled, unhandled, erroneous, err
}
-func (sm *BlockProcessor) Process(block *types.Block) (td *big.Int, msgs state.Messages, err error) {
+// Process block will attempt to process the given block's transactions and applies them
+// on top of the block's parent state (given it exists) and will return wether it was
+// successful or not.
+func (sm *BlockProcessor) Process(block *types.Block) (td *big.Int, err error) {
// Processing a blocks may never happen simultaneously
sm.mutex.Lock()
defer sm.mutex.Unlock()
header := block.Header()
if sm.bc.HasBlock(header.Hash()) {
- return nil, nil, &KnownBlockError{header.Number, header.Hash()}
+ return nil, &KnownBlockError{header.Number, header.Hash()}
}
if !sm.bc.HasBlock(header.ParentHash) {
- return nil, nil, ParentError(header.ParentHash)
+ return nil, ParentError(header.ParentHash)
}
parent := sm.bc.GetBlock(header.ParentHash)
- return sm.ProcessWithParent(block, parent)
+ return sm.processWithParent(block, parent)
}
-func (sm *BlockProcessor) ProcessWithParent(block, parent *types.Block) (td *big.Int, messages state.Messages, err error) {
+func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big.Int, err error) {
sm.lastAttemptedBlock = block
+ // Create a new state based on the parent's root (e.g., create copy)
state := state.New(parent.Root(), sm.db)
- //state := state.New(parent.Trie().Copy())
// Block validation
if err = sm.ValidateBlock(block, parent); err != nil {
@@ -187,18 +183,23 @@ func (sm *BlockProcessor) ProcessWithParent(block, parent *types.Block) (td *big
header := block.Header()
+ // Validate the received block's bloom with the one derived from the generated receipts.
+ // For valid blocks this should always validate to true.
rbloom := types.CreateBloom(receipts)
if bytes.Compare(rbloom, header.Bloom) != 0 {
err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
return
}
+ // The transactions Trie's root (R = (Tr [[H1, T1], [H2, T2], ... [Hn, Tn]]))
+ // can be used by light clients to make sure they've received the correct Txs
txSha := types.DeriveSha(block.Transactions())
if bytes.Compare(txSha, header.TxHash) != 0 {
err = fmt.Errorf("validating transaction root. received=%x got=%x", header.TxHash, txSha)
return
}
+ // 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)
@@ -206,12 +207,14 @@ func (sm *BlockProcessor) ProcessWithParent(block, parent *types.Block) (td *big
return
}
- if err = sm.AccumelateRewards(state, block, parent); err != nil {
+ // Accumulate static rewards; block reward, uncle's and uncle inclusion.
+ if err = sm.AccumulateRewards(state, block, parent); err != nil {
return
}
+ // Commit state objects/accounts to a temporary trie (does not save)
+ // used to calculate the state root.
state.Update(ethutil.Big0)
-
if !bytes.Equal(header.Root, state.Root()) {
err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root())
return
@@ -219,19 +222,14 @@ func (sm *BlockProcessor) ProcessWithParent(block, parent *types.Block) (td *big
// Calculate the td for this block
td = CalculateTD(block, parent)
- // Sync the current block's state to the database and cancelling out the deferred Undo
+ // Sync the current block's state to the database
state.Sync()
- // Set the block hashes for the current messages
- state.Manifest().SetHash(block.Hash())
- messages = state.Manifest().Messages
- // Reset the manifest XXX We need this?
- state.Manifest().Reset()
// Remove transactions from the pool
sm.txpool.RemoveSet(block.Transactions())
chainlogger.Infof("processed block #%d (%x...)\n", header.Number, block.Hash()[0:4])
- return td, messages, nil
+ return td, nil
}
// Validates the current block. Returns an error if the block was invalid,
@@ -247,9 +245,8 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd)
}
- diff := block.Header().Time - parent.Header().Time
- if diff < 0 {
- return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Header().Time, sm.bc.CurrentBlock().Header().Time)
+ if block.Time() < parent.Time() {
+ return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time)
}
if block.Time() > time.Now().Unix() {
@@ -264,7 +261,7 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
return nil
}
-func (sm *BlockProcessor) AccumelateRewards(statedb *state.StateDB, block, parent *types.Block) error {
+func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, parent *types.Block) error {
reward := new(big.Int).Set(BlockReward)
ancestors := set.New()
@@ -285,6 +282,10 @@ func (sm *BlockProcessor) AccumelateRewards(statedb *state.StateDB, block, paren
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
}
+ if !sm.Pow.Verify(types.NewBlockWithHeader(uncle)) {
+ return ValidationError("Uncle's nonce is invalid (= %v)", ethutil.Bytes2Hex(uncle.Nonce))
+ }
+
r := new(big.Int)
r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
@@ -299,18 +300,10 @@ func (sm *BlockProcessor) AccumelateRewards(statedb *state.StateDB, block, paren
// Reward amount of ether to the coinbase address
account.AddAmount(reward)
- statedb.Manifest().AddMessage(&state.Message{
- To: block.Header().Coinbase,
- Input: nil,
- Origin: nil,
- Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number,
- Value: new(big.Int).Add(reward, block.Reward),
- })
-
return nil
}
-func (sm *BlockProcessor) GetMessages(block *types.Block) (messages []*state.Message, err error) {
+func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) {
if !sm.bc.HasBlock(block.Header().ParentHash) {
return nil, ParentError(block.Header().ParentHash)
}
@@ -326,7 +319,7 @@ func (sm *BlockProcessor) GetMessages(block *types.Block) (messages []*state.Mes
defer state.Reset()
sm.TransitionState(state, parent, block)
- sm.AccumelateRewards(state, block, parent)
+ sm.AccumulateRewards(state, block, parent)
- return state.Manifest().Messages, nil
+ return state.Logs(), nil
}
diff --git a/core/chain_manager.go b/core/chain_manager.go
index c68b7cfc2..22d54be03 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -16,6 +16,11 @@ import (
var chainlogger = logger.NewLogger("CHAIN")
+type ChainEvent struct {
+ Block *types.Block
+ Td *big.Int
+}
+
type StateQuery interface {
GetAccount(addr []byte) *state.StateObject
}
@@ -73,11 +78,11 @@ type ChainManager struct {
eventMux *event.TypeMux
genesisBlock *types.Block
// Last known total difficulty
- mu sync.RWMutex
- td *big.Int
- lastBlockNumber uint64
- currentBlock *types.Block
- lastBlockHash []byte
+ mu sync.RWMutex
+ tsmu sync.RWMutex
+ td *big.Int
+ currentBlock *types.Block
+ lastBlockHash []byte
transState *state.StateDB
}
@@ -89,13 +94,6 @@ func (self *ChainManager) Td() *big.Int {
return self.td
}
-func (self *ChainManager) LastBlockNumber() uint64 {
- self.mu.RLock()
- defer self.mu.RUnlock()
-
- return self.lastBlockNumber
-}
-
func (self *ChainManager) LastBlockHash() []byte {
self.mu.RLock()
defer self.mu.RUnlock()
@@ -134,9 +132,19 @@ func (self *ChainManager) State() *state.StateDB {
}
func (self *ChainManager) TransState() *state.StateDB {
+ self.tsmu.RLock()
+ defer self.tsmu.RUnlock()
+ //tmp := self.transState
+
return self.transState
}
+func (self *ChainManager) setTransState(statedb *state.StateDB) {
+ self.tsmu.Lock()
+ defer self.tsmu.Unlock()
+ self.transState = statedb
+}
+
func (bc *ChainManager) setLastBlock() {
data, _ := bc.db.Get([]byte("LastBlock"))
if len(data) != 0 {
@@ -144,7 +152,6 @@ func (bc *ChainManager) setLastBlock() {
rlp.Decode(bytes.NewReader(data), &block)
bc.currentBlock = &block
bc.lastBlockHash = block.Hash()
- bc.lastBlockNumber = block.Header().Number.Uint64()
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc.td = ethutil.BigD(bc.db.LastKnownTD())
@@ -152,7 +159,7 @@ func (bc *ChainManager) setLastBlock() {
bc.Reset()
}
- chainlogger.Infof("Last block (#%d) %x TD=%v\n", bc.lastBlockNumber, bc.currentBlock.Hash(), bc.td)
+ chainlogger.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td)
}
// Block creation & chain handling
@@ -163,7 +170,7 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
var root []byte
parentHash := ZeroHash256
- if bc.CurrentBlock != nil {
+ if bc.currentBlock != nil {
root = bc.currentBlock.Header().Root
parentHash = bc.lastBlockHash
}
@@ -175,6 +182,9 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
ethutil.BigPow(2, 32),
nil,
"")
+ block.SetUncles(nil)
+ block.SetTransactions(nil)
+ block.SetReceipts(nil)
parent := bc.currentBlock
if parent != nil {
@@ -226,8 +236,6 @@ func (bc *ChainManager) insert(block *types.Block) {
}
func (bc *ChainManager) write(block *types.Block) {
- bc.writeBlockInfo(block)
-
encodedBlock := ethutil.Encode(block.RlpDataForStorage())
bc.db.Put(block.Hash(), encodedBlock)
}
@@ -251,7 +259,13 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain
// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
for i := uint64(0); i < max; i++ {
- block = self.GetBlock(block.Header().ParentHash)
+ parentHash := block.Header().ParentHash
+ block = self.GetBlock(parentHash)
+ if block == nil {
+ chainlogger.Infof("GetBlockHashesFromHash Parent UNKNOWN %x\n", parentHash)
+ break
+ }
+
chain = append(chain, block.Hash())
if block.Header().Number.Cmp(ethutil.Big0) <= 0 {
break
@@ -340,11 +354,6 @@ func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
return td, nil
}
-// Unexported method for writing extra non-essential block info to the db
-func (bc *ChainManager) writeBlockInfo(block *types.Block) {
- bc.lastBlockNumber++
-}
-
func (bc *ChainManager) Stop() {
if bc.CurrentBlock != nil {
chainlogger.Infoln("Stopped")
@@ -353,7 +362,7 @@ func (bc *ChainManager) Stop() {
func (self *ChainManager) InsertChain(chain types.Blocks) error {
for _, block := range chain {
- td, messages, err := self.processor.Process(block)
+ td, err := self.processor.Process(block)
if err != nil {
if IsKnownBlockErr(err) {
continue
@@ -378,14 +387,12 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
self.setTotalDifficulty(td)
self.insert(block)
- self.transState = state.New(cblock.Root(), self.db) //state.New(cblock.Trie().Copy())
- }
+ self.setTransState(state.New(cblock.Root(), self.db))
+ self.eventMux.Post(ChainEvent{block, td})
+ }
}
self.mu.Unlock()
-
- self.eventMux.Post(NewBlockEvent{block})
- self.eventMux.Post(messages)
}
return nil
diff --git a/core/execution.go b/core/execution.go
index cad4e84aa..5e0cbd37e 100644
--- a/core/execution.go
+++ b/core/execution.go
@@ -33,8 +33,7 @@ func (self *Execution) Call(codeAddr []byte, caller vm.ContextRef) ([]byte, erro
func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret []byte, err error) {
env := self.env
- evm := vm.New(env)
-
+ evm := vm.NewVm(env)
if env.Depth() == vm.MaxCallDepth {
caller.ReturnGas(self.Gas, self.price)
diff --git a/core/filter.go b/core/filter.go
index 29be8841c..88f12a67c 100644
--- a/core/filter.go
+++ b/core/filter.go
@@ -3,10 +3,8 @@ package core
import (
"bytes"
"math"
- "math/big"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state"
)
@@ -14,29 +12,46 @@ type AccountChange struct {
Address, StateAddress []byte
}
+type FilterOptions struct {
+ Earliest int64
+ Latest int64
+
+ Address [][]byte
+ Topics [][]byte
+
+ Skip int
+ Max int
+}
+
// Filtering interface
type Filter struct {
- eth EthManager
+ eth Backend
earliest int64
latest int64
skip int
- from, to [][]byte
+ address [][]byte
max int
-
- Altered []AccountChange
+ topics [][]byte
BlockCallback func(*types.Block)
- MessageCallback func(state.Messages)
+ PendingCallback func(*types.Block)
+ LogsCallback func(state.Logs)
}
// Create a new filter which uses a bloom filter on blocks to figure out whether a particular block
// is interesting or not.
-func NewFilter(eth EthManager) *Filter {
+func NewFilter(eth Backend) *Filter {
return &Filter{eth: eth}
}
-func (self *Filter) AddAltered(address, stateAddress []byte) {
- self.Altered = append(self.Altered, AccountChange{address, stateAddress})
+func (self *Filter) SetOptions(options FilterOptions) {
+ self.earliest = options.Earliest
+ self.latest = options.Latest
+ self.skip = options.Skip
+ self.max = options.Max
+ self.address = options.Address
+ self.topics = options.Topics
+
}
// Set the earliest and latest block for filtering.
@@ -50,20 +65,12 @@ func (self *Filter) SetLatestBlock(latest int64) {
self.latest = latest
}
-func (self *Filter) SetFrom(addr [][]byte) {
- self.from = addr
+func (self *Filter) SetAddress(addr [][]byte) {
+ self.address = addr
}
-func (self *Filter) AddFrom(addr []byte) {
- self.from = append(self.from, addr)
-}
-
-func (self *Filter) SetTo(addr [][]byte) {
- self.to = addr
-}
-
-func (self *Filter) AddTo(addr []byte) {
- self.to = append(self.to, addr)
+func (self *Filter) SetTopics(topics [][]byte) {
+ self.topics = topics
}
func (self *Filter) SetMax(max int) {
@@ -74,8 +81,8 @@ func (self *Filter) SetSkip(skip int) {
self.skip = skip
}
-// Run filters messages with the current parameters set
-func (self *Filter) Find() []*state.Message {
+// Run filters logs with the current parameters set
+func (self *Filter) Find() state.Logs {
earliestBlock := self.eth.ChainManager().CurrentBlock()
var earliestBlockNo uint64 = uint64(self.earliest)
if self.earliest == -1 {
@@ -87,115 +94,95 @@ func (self *Filter) Find() []*state.Message {
}
var (
- messages []*state.Message
- block = self.eth.ChainManager().GetBlockByNumber(latestBlockNo)
- quit bool
+ logs state.Logs
+ block = self.eth.ChainManager().GetBlockByNumber(latestBlockNo)
+ quit bool
)
for i := 0; !quit && block != nil; i++ {
// Quit on latest
switch {
case block.NumberU64() == earliestBlockNo, block.NumberU64() == 0:
quit = true
- case self.max <= len(messages):
+ case self.max <= len(logs):
break
}
// Use bloom filtering to see if this block is interesting given the
// current parameters
if self.bloomFilter(block) {
- // Get the messages of the block
- msgs, err := self.eth.BlockProcessor().GetMessages(block)
+ // Get the logs of the block
+ logs, err := self.eth.BlockProcessor().GetLogs(block)
if err != nil {
- chainlogger.Warnln("err: filter get messages ", err)
+ chainlogger.Warnln("err: filter get logs ", err)
break
}
- messages = append(messages, self.FilterMessages(msgs)...)
+ logs = append(logs, self.FilterLogs(logs)...)
}
block = self.eth.ChainManager().GetBlock(block.ParentHash())
}
- skip := int(math.Min(float64(len(messages)), float64(self.skip)))
+ skip := int(math.Min(float64(len(logs)), float64(self.skip)))
- return messages[skip:]
+ return logs[skip:]
}
-func includes(addresses [][]byte, a []byte) (found bool) {
+func includes(addresses [][]byte, a []byte) bool {
for _, addr := range addresses {
- if bytes.Compare(addr, a) == 0 {
- return true
+ if !bytes.Equal(addr, a) {
+ return false
}
}
- return
+ return true
}
-func (self *Filter) FilterMessages(msgs []*state.Message) []*state.Message {
- var messages []*state.Message
-
- // Filter the messages for interesting stuff
- for _, message := range msgs {
- if len(self.to) > 0 && !includes(self.to, message.To) {
- continue
- }
+func (self *Filter) FilterLogs(logs state.Logs) state.Logs {
+ var ret state.Logs
- if len(self.from) > 0 && !includes(self.from, message.From) {
+ // Filter the logs for interesting stuff
+Logs:
+ for _, log := range logs {
+ if !includes(self.address, log.Address()) {
+ //if !bytes.Equal(self.address, log.Address()) {
continue
}
- var match bool
- if len(self.Altered) == 0 {
- match = true
- }
-
- for _, accountChange := range self.Altered {
- if len(accountChange.Address) > 0 && bytes.Compare(message.To, accountChange.Address) != 0 {
- continue
- }
-
- if len(accountChange.StateAddress) > 0 && !includes(message.ChangedAddresses, accountChange.StateAddress) {
- 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
}
-
- match = true
- break
}
- if !match {
- continue
- }
-
- messages = append(messages, message)
+ ret = append(ret, log)
}
- return messages
+ return ret
}
func (self *Filter) bloomFilter(block *types.Block) bool {
- var fromIncluded, toIncluded bool
- if len(self.from) > 0 {
- for _, from := range self.from {
- if types.BloomLookup(block.Bloom(), from) || bytes.Equal(block.Coinbase(), from) {
- fromIncluded = true
+ if len(self.address) > 0 {
+ var included bool
+ for _, addr := range self.address {
+ if types.BloomLookup(block.Bloom(), addr) {
+ included = true
break
}
}
- } else {
- fromIncluded = true
+
+ if !included {
+ return false
+ }
}
- if len(self.to) > 0 {
- for _, to := range self.to {
- if types.BloomLookup(block.Bloom(), ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) || bytes.Equal(block.Coinbase(), to) {
- toIncluded = true
- break
- }
+ for _, topic := range self.topics {
+ if !types.BloomLookup(block.Bloom(), topic) {
+ return false
}
- } else {
- toIncluded = true
}
- return fromIncluded && toIncluded
+ return true
}
diff --git a/core/genesis.go b/core/genesis.go
index d9edaace2..c870ce61e 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -32,9 +32,8 @@ func GenesisBlock(db ethutil.Database) *types.Block {
genesis.SetReceipts(types.Receipts{})
statedb := state.New(genesis.Root(), db)
- //statedb := state.New(genesis.Trie())
for _, addr := range []string{
- "51ba59315b3a95761d0863b05ccc7a7f54703d99",
+ "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6",
"e4157b34ea9615cfbde6b4fda419828124b70c78",
"b9c015918bdaba24b4ff057a92a3873d6eb201be",
"6c386a4b26f73c802f34673f7248bb118f97424a",
diff --git a/core/helper_test.go b/core/helper_test.go
index 7b41b86f1..473576e3f 100644
--- a/core/helper_test.go
+++ b/core/helper_test.go
@@ -9,7 +9,6 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/p2p"
)
// Implement our EthTest Manager
@@ -54,13 +53,6 @@ func (tm *TestManager) TxPool() *TxPool {
func (tm *TestManager) EventMux() *event.TypeMux {
return tm.eventMux
}
-func (tm *TestManager) Broadcast(msgType p2p.Msg, data []interface{}) {
- fmt.Println("Broadcast not implemented")
-}
-
-func (tm *TestManager) ClientIdentity() p2p.ClientIdentity {
- return nil
-}
func (tm *TestManager) KeyManager() *crypto.KeyManager {
return nil
}
diff --git a/core/manager.go b/core/manager.go
new file mode 100644
index 000000000..bb039d063
--- /dev/null
+++ b/core/manager.go
@@ -0,0 +1,20 @@
+package core
+
+import (
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/p2p"
+)
+
+type Backend interface {
+ BlockProcessor() *BlockProcessor
+ ChainManager() *ChainManager
+ TxPool() *TxPool
+ PeerCount() int
+ IsListening() bool
+ Peers() []*p2p.Peer
+ KeyManager() *crypto.KeyManager
+ Db() ethutil.Database
+ EventMux() *event.TypeMux
+}
diff --git a/core/state_transition.go b/core/state_transition.go
index 8b0ca2ac4..33dd45f02 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -10,6 +10,8 @@ import (
"github.com/ethereum/go-ethereum/vm"
)
+const tryJit = false
+
/*
* The State transitioning model
*
@@ -184,6 +186,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
return
}
+ //stateCopy := self.env.State().Copy()
vmenv := self.env
var ref vm.ContextRef
if MessageCreatesContract(msg) {
@@ -196,8 +199,34 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
ref.SetCode(ret)
}
}
+
+ /*
+ if vmenv, ok := vmenv.(*VMEnv); ok && tryJit {
+ statelogger.Infof("CREATE: re-running using JIT (PH=%x)\n", stateCopy.Root()[:4])
+ // re-run using the JIT (validation for the JIT)
+ goodState := vmenv.State().Copy()
+ vmenv.state = stateCopy
+ vmenv.SetVmType(vm.JitVmTy)
+ vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
+ statelogger.Infof("DONE PH=%x STD_H=%x JIT_H=%x\n", stateCopy.Root()[:4], goodState.Root()[:4], vmenv.State().Root()[:4])
+ self.state.Set(goodState)
+ }
+ */
} else {
ret, err = vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
+
+ /*
+ if vmenv, ok := vmenv.(*VMEnv); ok && tryJit {
+ statelogger.Infof("CALL: re-running using JIT (PH=%x)\n", stateCopy.Root()[:4])
+ // re-run using the JIT (validation for the JIT)
+ goodState := vmenv.State().Copy()
+ vmenv.state = stateCopy
+ vmenv.SetVmType(vm.JitVmTy)
+ vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
+ statelogger.Infof("DONE PH=%x STD_H=%x JIT_H=%x\n", stateCopy.Root()[:4], goodState.Root()[:4], vmenv.State().Root()[:4])
+ self.state.Set(goodState)
+ }
+ */
}
if err != nil {
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
index 193db45ed..c617e6cb6 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -1,6 +1,7 @@
package core
import (
+ "errors"
"fmt"
"github.com/ethereum/go-ethereum/core/types"
@@ -9,7 +10,11 @@ import (
"github.com/ethereum/go-ethereum/logger"
)
-var txplogger = logger.NewLogger("TXP")
+var (
+ txplogger = logger.NewLogger("TXP")
+
+ ErrInvalidSender = errors.New("Invalid sender")
+)
const txPoolQueueSize = 50
@@ -60,22 +65,23 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
return fmt.Errorf("Invalid recipient. len = %d", len(tx.To()))
}
+ // Validate curve param
v, _, _ := tx.Curve()
if v > 28 || v < 27 {
return fmt.Errorf("tx.v != (28 || 27) => %v", v)
}
+ // Validate sender address
+ senderAddr := tx.From()
+ if senderAddr == nil || len(senderAddr) != 20 {
+ return ErrInvalidSender
+ }
+
/* XXX this kind of validation needs to happen elsewhere in the gui when sending txs.
Other clients should do their own validation. Value transfer could throw error
but doesn't necessarily invalidate the tx. Gas can still be payed for and miner
can still be rewarded for their inclusion and processing.
- // Get the sender
- senderAddr := tx.From()
- if senderAddr == nil {
- return fmt.Errorf("invalid sender")
- }
sender := pool.stateQuery.GetAccount(senderAddr)
-
totAmount := new(big.Int).Set(tx.Value())
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
diff --git a/core/transaction_pool_test.go b/core/transaction_pool_test.go
index 7f192fc4d..b2d981f01 100644
--- a/core/transaction_pool_test.go
+++ b/core/transaction_pool_test.go
@@ -85,3 +85,13 @@ func TestRemoveInvalid(t *testing.T) {
t.Error("expected pool size to be 1, is", pool.Size())
}
}
+
+func TestInvalidSender(t *testing.T) {
+ pool, _ := setup()
+ tx := new(types.Transaction)
+ tx.V = 28
+ err := pool.ValidateTransaction(tx)
+ if err != ErrInvalidSender {
+ t.Error("expected %v, got %v", ErrInvalidSender, err)
+ }
+}
diff --git a/core/types/block.go b/core/types/block.go
index be57e86a6..fa28f5cc7 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -146,6 +146,10 @@ func (self *Block) SetTransactions(transactions Transactions) {
self.transactions = transactions
self.header.TxHash = DeriveSha(transactions)
}
+func (self *Block) AddTransaction(transaction *Transaction) {
+ self.transactions = append(self.transactions, transaction)
+ self.SetTransactions(self.transactions)
+}
func (self *Block) Receipts() Receipts {
return self.receipts
@@ -156,6 +160,10 @@ func (self *Block) SetReceipts(receipts Receipts) {
self.header.ReceiptHash = DeriveSha(receipts)
self.header.Bloom = CreateBloom(receipts)
}
+func (self *Block) AddReceipt(receipt *Receipt) {
+ self.receipts = append(self.receipts, receipt)
+ self.SetReceipts(self.receipts)
+}
func (self *Block) RlpData() interface{} {
return []interface{}{self.header, self.transactions, self.uncles}
@@ -166,16 +174,14 @@ 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) 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) }
-func (self *Block) GasLimit() *big.Int { return self.header.GasLimit }
-func (self *Block) GasUsed() *big.Int { return self.header.GasUsed }
-
-//func (self *Block) Trie() *ptrie.Trie { return ptrie.New(self.header.Root, ethutil.Config.Db) }
-//func (self *Block) State() *state.StateDB { return state.New(self.Trie()) }
+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) 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) }
+func (self *Block) GasLimit() *big.Int { return self.header.GasLimit }
+func (self *Block) GasUsed() *big.Int { return self.header.GasUsed }
func (self *Block) Root() []byte { return self.header.Root }
func (self *Block) SetRoot(root []byte) { self.header.Root = root }
func (self *Block) Size() ethutil.StorageSize { return ethutil.StorageSize(len(ethutil.Encode(self))) }
@@ -203,6 +209,7 @@ func (self *Block) ParentHash() []byte {
func (self *Block) String() string {
return fmt.Sprintf(`BLOCK(%x): Size: %v TD: %v {
+NoNonce: %x
Header:
[
%v
@@ -212,7 +219,7 @@ Transactions:
Uncles:
%v
}
-`, self.header.Hash(), self.Size(), self.Td, self.header, self.transactions, self.uncles)
+`, self.header.Hash(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles)
}
func (self *Header) String() string {
diff --git a/core/types/common.go b/core/types/common.go
index ba88b77e1..795374959 100644
--- a/core/types/common.go
+++ b/core/types/common.go
@@ -1,11 +1,7 @@
package types
-import (
- "math/big"
-
- "github.com/ethereum/go-ethereum/state"
-)
+import "math/big"
type BlockProcessor interface {
- Process(*Block) (*big.Int, state.Messages, error)
+ Process(*Block) (*big.Int, error)
}
diff --git a/core/types/receipt.go b/core/types/receipt.go
index bac64e41d..49e68e233 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -17,7 +17,7 @@ type Receipt struct {
}
func NewReceipt(root []byte, cumalativeGasUsed *big.Int) *Receipt {
- return &Receipt{PostState: ethutil.CopyBytes(root), CumulativeGasUsed: cumalativeGasUsed}
+ return &Receipt{PostState: ethutil.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumalativeGasUsed)}
}
func NewRecieptFromValue(val *ethutil.Value) *Receipt {
diff --git a/core/vm_env.go b/core/vm_env.go
index 624a63333..c7491bcdc 100644
--- a/core/vm_env.go
+++ b/core/vm_env.go
@@ -14,6 +14,7 @@ type VMEnv struct {
msg Message
depth int
chain *ChainManager
+ typ vm.Type
}
func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types.Block) *VMEnv {
@@ -22,6 +23,7 @@ func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types
state: state,
block: block,
msg: msg,
+ typ: vm.StdVmTy,
}
}
@@ -35,6 +37,8 @@ func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
func (self *VMEnv) State() *state.StateDB { return self.state }
func (self *VMEnv) Depth() int { return self.depth }
func (self *VMEnv) SetDepth(i int) { self.depth = i }
+func (self *VMEnv) VmType() vm.Type { return self.typ }
+func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t }
func (self *VMEnv) GetHash(n uint64) []byte {
if block := self.chain.GetBlockByNumber(n); block != nil {
return block.Hash()