plugeth/chain/filter.go

201 lines
4.3 KiB
Go
Raw Normal View History

2014-10-31 09:59:17 +00:00
package chain
import (
"bytes"
2014-09-26 11:32:54 +00:00
"math"
"math/big"
"github.com/ethereum/go-ethereum/chain/types"
"github.com/ethereum/go-ethereum/ethutil"
2014-10-31 13:43:14 +00:00
"github.com/ethereum/go-ethereum/state"
)
type AccountChange struct {
Address, StateAddress []byte
}
// Filtering interface
type Filter struct {
eth EthManager
2014-09-26 11:32:54 +00:00
earliest int64
latest int64
skip int
from, to [][]byte
max int
Altered []AccountChange
2014-09-13 22:13:23 +00:00
BlockCallback func(*types.Block)
2014-10-31 13:43:14 +00:00
MessageCallback func(state.Messages)
}
// 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 {
return &Filter{eth: eth}
}
func (self *Filter) AddAltered(address, stateAddress []byte) {
self.Altered = append(self.Altered, AccountChange{address, stateAddress})
}
// Set the earliest and latest block for filtering.
// -1 = latest block (i.e., the current block)
// hash = particular hash from-to
2014-09-26 11:32:54 +00:00
func (self *Filter) SetEarliestBlock(earliest int64) {
self.earliest = earliest
}
2014-09-26 11:32:54 +00:00
func (self *Filter) SetLatestBlock(latest int64) {
self.latest = latest
}
func (self *Filter) SetFrom(addr [][]byte) {
self.from = 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) {
2014-08-20 11:05:26 +00:00
self.to = append(self.to, addr)
}
func (self *Filter) SetMax(max int) {
self.max = max
}
func (self *Filter) SetSkip(skip int) {
self.skip = skip
}
// Run filters messages with the current parameters set
2014-10-31 13:43:14 +00:00
func (self *Filter) Find() []*state.Message {
2014-09-26 11:32:54 +00:00
var earliestBlockNo uint64 = uint64(self.earliest)
if self.earliest == -1 {
2014-10-20 09:53:11 +00:00
earliestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64()
2014-09-26 11:32:54 +00:00
}
var latestBlockNo uint64 = uint64(self.latest)
if self.latest == -1 {
2014-10-20 09:53:11 +00:00
latestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64()
}
2014-09-26 11:32:54 +00:00
var (
2014-10-31 13:43:14 +00:00
messages []*state.Message
2014-10-20 09:53:11 +00:00
block = self.eth.ChainManager().GetBlockByNumber(latestBlockNo)
2014-09-26 11:32:54 +00:00
quit bool
)
for i := 0; !quit && block != nil; i++ {
// Quit on latest
switch {
2014-10-31 09:50:16 +00:00
case block.Number.Uint64() == earliestBlockNo, block.Number.Uint64() == 0:
quit = true
2014-09-26 11:32:54 +00:00
case self.max <= len(messages):
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
2014-11-04 09:57:02 +00:00
msgs, err := self.eth.BlockManager().GetMessages(block)
if err != nil {
chainlogger.Warnln("err: filter get messages ", err)
break
}
2014-08-14 22:24:37 +00:00
messages = append(messages, self.FilterMessages(msgs)...)
}
2014-10-20 09:53:11 +00:00
block = self.eth.ChainManager().GetBlock(block.PrevHash)
2014-08-14 22:24:37 +00:00
}
2014-09-26 11:32:54 +00:00
skip := int(math.Min(float64(len(messages)), float64(self.skip)))
return messages[skip:]
2014-08-14 22:24:37 +00:00
}
func includes(addresses [][]byte, a []byte) (found bool) {
for _, addr := range addresses {
if bytes.Compare(addr, a) == 0 {
return true
}
}
return
}
2014-10-31 13:43:14 +00:00
func (self *Filter) FilterMessages(msgs []*state.Message) []*state.Message {
var messages []*state.Message
2014-08-14 22:24:37 +00:00
// Filter the messages for interesting stuff
for _, message := range msgs {
if len(self.to) > 0 && !includes(self.to, message.To) {
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
}
if len(accountChange.StateAddress) > 0 && !includes(message.ChangedAddresses, accountChange.StateAddress) {
continue
}
match = true
break
}
if !match {
continue
}
2014-08-14 22:24:37 +00:00
messages = append(messages, message)
}
return messages
}
func (self *Filter) bloomFilter(block *types.Block) bool {
var fromIncluded, toIncluded bool
if len(self.from) > 0 {
for _, from := range self.from {
2014-12-03 12:50:51 +00:00
if types.BloomLookup(block.LogsBloom, from) || bytes.Equal(block.Coinbase, from) {
fromIncluded = true
break
}
}
} else {
fromIncluded = true
}
if len(self.to) > 0 {
for _, to := range self.to {
2014-12-03 12:50:51 +00:00
if types.BloomLookup(block.LogsBloom, ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) || bytes.Equal(block.Coinbase, to) {
toIncluded = true
break
}
}
} else {
toIncluded = true
}
return fromIncluded && toIncluded
}