Merge branch 'develop' of https://github.com/ethereum/go-ethereum into develop
This commit is contained in:
@ -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: ðash.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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
157
core/filter.go
157
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
|
||||
func (self *Filter) FilterLogs(logs state.Logs) state.Logs {
|
||||
var ret state.Logs
|
||||
|
||||
// Filter the messages for interesting stuff
|
||||
for _, message := range msgs {
|
||||
if len(self.to) > 0 && !includes(self.to, message.To) {
|
||||
// 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
|
||||
}
|
||||
|
||||
if len(self.from) > 0 && !includes(self.from, message.From) {
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
if len(accountChange.StateAddress) > 0 && !includes(message.ChangedAddresses, accountChange.StateAddress) {
|
||||
continue
|
||||
}
|
||||
|
||||
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 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
|
||||
}
|
||||
if !included {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
toIncluded = true
|
||||
}
|
||||
|
||||
return fromIncluded && toIncluded
|
||||
for _, topic := range self.topics {
|
||||
if !types.BloomLookup(block.Bloom(), topic) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
}
|
||||
|
20
core/manager.go
Normal file
20
core/manager.go
Normal file
@ -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
|
||||
}
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
Reference in New Issue
Block a user