Changed how logs are being recorded
Logs are now recorded per transactions instead of tossing them out after each transaction. This should also fix an issue with `eth_getFilterLogs` (#629) Also now implemented are the `transactionHash, blockHash, transactionIndex, logIndex` on logs. Closes #654.
This commit is contained in:
parent
6284604b52
commit
1c872ddf4b
@ -73,7 +73,7 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block
|
|||||||
|
|
||||||
func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
|
func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *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
|
// If we are mining this block and validating we want to set the logs back to 0
|
||||||
statedb.EmptyLogs()
|
//statedb.EmptyLogs()
|
||||||
|
|
||||||
cb := statedb.GetStateObject(coinbase.Address())
|
cb := statedb.GetStateObject(coinbase.Address())
|
||||||
_, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, block), tx, cb)
|
_, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, block), tx, cb)
|
||||||
@ -89,7 +89,9 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
|
|||||||
|
|
||||||
cumulative := new(big.Int).Set(usedGas.Add(usedGas, gas))
|
cumulative := new(big.Int).Set(usedGas.Add(usedGas, gas))
|
||||||
receipt := types.NewReceipt(statedb.Root().Bytes(), cumulative)
|
receipt := types.NewReceipt(statedb.Root().Bytes(), cumulative)
|
||||||
receipt.SetLogs(statedb.Logs())
|
|
||||||
|
logs := statedb.GetLogs(tx.Hash())
|
||||||
|
receipt.SetLogs(logs)
|
||||||
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
||||||
|
|
||||||
glog.V(logger.Debug).Infoln(receipt)
|
glog.V(logger.Debug).Infoln(receipt)
|
||||||
@ -97,7 +99,6 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
|
|||||||
// Notify all subscribers
|
// Notify all subscribers
|
||||||
if !transientProcess {
|
if !transientProcess {
|
||||||
go self.eventMux.Post(TxPostEvent{tx})
|
go self.eventMux.Post(TxPostEvent{tx})
|
||||||
logs := statedb.Logs()
|
|
||||||
go self.eventMux.Post(logs)
|
go self.eventMux.Post(logs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +116,9 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
|
|||||||
cumulativeSum = new(big.Int)
|
cumulativeSum = new(big.Int)
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, tx := range txs {
|
for i, tx := range txs {
|
||||||
|
statedb.StartRecord(tx.Hash(), block.Hash(), i)
|
||||||
|
|
||||||
receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess)
|
receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess)
|
||||||
if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
|
if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -124,17 +124,17 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs {
|
|||||||
// Filter the logs for interesting stuff
|
// Filter the logs for interesting stuff
|
||||||
Logs:
|
Logs:
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
if len(self.address) > 0 && !includes(self.address, log.Address()) {
|
if len(self.address) > 0 && !includes(self.address, log.Address) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
logTopics := make([]common.Hash, len(self.topics))
|
logTopics := make([]common.Hash, len(self.topics))
|
||||||
copy(logTopics, log.Topics())
|
copy(logTopics, log.Topics)
|
||||||
|
|
||||||
for i, topics := range self.topics {
|
for i, topics := range self.topics {
|
||||||
for _, topic := range topics {
|
for _, topic := range topics {
|
||||||
var match bool
|
var match bool
|
||||||
if log.Topics()[i] == topic {
|
if log.Topics[i] == topic {
|
||||||
match = true
|
match = true
|
||||||
}
|
}
|
||||||
if !match {
|
if !match {
|
||||||
|
@ -8,87 +8,31 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Log interface {
|
type Log struct {
|
||||||
Address() common.Address
|
Address common.Address
|
||||||
Topics() []common.Hash
|
Topics []common.Hash
|
||||||
Data() []byte
|
Data []byte
|
||||||
|
Number uint64
|
||||||
|
|
||||||
Number() uint64
|
TxHash common.Hash
|
||||||
|
TxIndex uint
|
||||||
|
BlockHash common.Hash
|
||||||
|
Index uint
|
||||||
}
|
}
|
||||||
|
|
||||||
type StateLog struct {
|
func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *Log {
|
||||||
address common.Address
|
return &Log{Address: address, Topics: topics, Data: data, Number: number}
|
||||||
topics []common.Hash
|
|
||||||
data []byte
|
|
||||||
number uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *StateLog {
|
func (self *Log) EncodeRLP(w io.Writer) error {
|
||||||
return &StateLog{address, topics, data, number}
|
return rlp.Encode(w, []interface{}{self.Address, self.Topics, self.Data})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateLog) Address() common.Address {
|
func (self *Log) String() string {
|
||||||
return self.address
|
return fmt.Sprintf(`log: %x %x %x`, self.Address, self.Topics, self.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateLog) Topics() []common.Hash {
|
type Logs []*Log
|
||||||
return self.topics
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *StateLog) Data() []byte {
|
|
||||||
return self.data
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *StateLog) Number() uint64 {
|
|
||||||
return self.number
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
func NewLogFromValue(decoder *common.Value) *StateLog {
|
|
||||||
var extlog struct {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
log := &StateLog{
|
|
||||||
address: decoder.Get(0).Bytes(),
|
|
||||||
data: decoder.Get(2).Bytes(),
|
|
||||||
}
|
|
||||||
|
|
||||||
it := decoder.Get(1).NewIterator()
|
|
||||||
for it.Next() {
|
|
||||||
log.topics = append(log.topics, it.Value().Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
return log
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (self *StateLog) EncodeRLP(w io.Writer) error {
|
|
||||||
return rlp.Encode(w, []interface{}{self.address, self.topics, self.data})
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
func (self *StateLog) RlpData() interface{} {
|
|
||||||
return []interface{}{self.address, common.ByteSliceToInterface(self.topics), self.data}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (self *StateLog) String() string {
|
|
||||||
return fmt.Sprintf(`log: %x %x %x`, self.address, self.topics, self.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Logs []Log
|
|
||||||
|
|
||||||
/*
|
|
||||||
func (self Logs) RlpData() interface{} {
|
|
||||||
data := make([]interface{}, len(self))
|
|
||||||
for i, log := range self {
|
|
||||||
data[i] = log.RlpData()
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (self Logs) String() (ret string) {
|
func (self Logs) String() (ret string) {
|
||||||
for _, log := range self {
|
for _, log := range self {
|
||||||
|
@ -23,30 +23,53 @@ type StateDB struct {
|
|||||||
|
|
||||||
refund map[string]*big.Int
|
refund map[string]*big.Int
|
||||||
|
|
||||||
logs Logs
|
thash, bhash common.Hash
|
||||||
|
txIndex int
|
||||||
|
logs map[common.Hash]Logs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new state from a given trie
|
// Create a new state from a given trie
|
||||||
func New(root common.Hash, db common.Database) *StateDB {
|
func New(root common.Hash, db common.Database) *StateDB {
|
||||||
trie := trie.NewSecure(root[:], db)
|
trie := trie.NewSecure(root[:], db)
|
||||||
return &StateDB{db: db, trie: trie, stateObjects: make(map[string]*StateObject), refund: make(map[string]*big.Int)}
|
return &StateDB{db: db, trie: trie, stateObjects: make(map[string]*StateObject), refund: make(map[string]*big.Int), logs: make(map[common.Hash]Logs)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) PrintRoot() {
|
func (self *StateDB) PrintRoot() {
|
||||||
self.trie.Trie.PrintRoot()
|
self.trie.Trie.PrintRoot()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) EmptyLogs() {
|
func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) {
|
||||||
self.logs = nil
|
self.thash = thash
|
||||||
|
self.bhash = bhash
|
||||||
|
self.txIndex = ti
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) AddLog(log Log) {
|
func (self *StateDB) AddLog(log *Log) {
|
||||||
self.logs = append(self.logs, log)
|
log.TxHash = self.thash
|
||||||
|
log.BlockHash = self.bhash
|
||||||
|
log.TxIndex = uint(self.txIndex)
|
||||||
|
self.logs[self.thash] = append(self.logs[self.thash], log)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *StateDB) GetLogs(hash common.Hash) Logs {
|
||||||
|
return self.logs[hash]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) Logs() Logs {
|
func (self *StateDB) Logs() Logs {
|
||||||
|
var logs Logs
|
||||||
|
for _, lgs := range self.logs {
|
||||||
|
logs = append(logs, lgs...)
|
||||||
|
}
|
||||||
|
return logs
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (self *StateDB) Logs(txHash, blockHash common.Hash, txIndex uint) Logs {
|
||||||
|
self.logs.SetInfo(txHash, blockHash, txIndex)
|
||||||
|
|
||||||
return self.logs
|
return self.logs
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (self *StateDB) Refund(address common.Address, gas *big.Int) {
|
func (self *StateDB) Refund(address common.Address, gas *big.Int) {
|
||||||
addr := address.Str()
|
addr := address.Str()
|
||||||
@ -253,9 +276,10 @@ func (self *StateDB) Copy() *StateDB {
|
|||||||
state.refund[addr] = new(big.Int).Set(refund)
|
state.refund[addr] = new(big.Int).Set(refund)
|
||||||
}
|
}
|
||||||
|
|
||||||
logs := make(Logs, len(self.logs))
|
for hash, logs := range self.logs {
|
||||||
copy(logs, self.logs)
|
state.logs[hash] = make(Logs, len(logs))
|
||||||
state.logs = logs
|
copy(state.logs[hash], logs)
|
||||||
|
}
|
||||||
|
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateBloom(receipts Receipts) Bloom {
|
func CreateBloom(receipts Receipts) Bloom {
|
||||||
@ -20,10 +20,10 @@ func CreateBloom(receipts Receipts) Bloom {
|
|||||||
func LogsBloom(logs state.Logs) *big.Int {
|
func LogsBloom(logs state.Logs) *big.Int {
|
||||||
bin := new(big.Int)
|
bin := new(big.Int)
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
data := make([]common.Hash, len(log.Topics()))
|
data := make([]common.Hash, len(log.Topics))
|
||||||
bin.Or(bin, bloom9(log.Address().Bytes()))
|
bin.Or(bin, bloom9(log.Address.Bytes()))
|
||||||
|
|
||||||
for i, topic := range log.Topics() {
|
for i, topic := range log.Topics {
|
||||||
data[i] = topic
|
data[i] = topic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Receipt struct {
|
type Receipt struct {
|
||||||
@ -30,12 +30,6 @@ func (self *Receipt) EncodeRLP(w io.Writer) error {
|
|||||||
return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs})
|
return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs})
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func (self *Receipt) RlpData() interface{} {
|
|
||||||
return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (self *Receipt) RlpEncode() []byte {
|
func (self *Receipt) RlpEncode() []byte {
|
||||||
bytes, err := rlp.EncodeToBytes(self)
|
bytes, err := rlp.EncodeToBytes(self)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -58,17 +52,6 @@ func (self *Receipt) String() string {
|
|||||||
|
|
||||||
type Receipts []*Receipt
|
type Receipts []*Receipt
|
||||||
|
|
||||||
/*
|
|
||||||
func (self Receipts) RlpData() interface{} {
|
|
||||||
data := make([]interface{}, len(self))
|
|
||||||
for i, receipt := range self {
|
|
||||||
data[i] = receipt.RlpData()
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (self Receipts) RlpEncode() []byte {
|
func (self Receipts) RlpEncode() []byte {
|
||||||
bytes, err := rlp.EncodeToBytes(self)
|
bytes, err := rlp.EncodeToBytes(self)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -22,7 +22,7 @@ type Environment interface {
|
|||||||
Difficulty() *big.Int
|
Difficulty() *big.Int
|
||||||
GasLimit() *big.Int
|
GasLimit() *big.Int
|
||||||
Transfer(from, to Account, amount *big.Int) error
|
Transfer(from, to Account, amount *big.Int) error
|
||||||
AddLog(state.Log)
|
AddLog(*state.Log)
|
||||||
|
|
||||||
VmType() Type
|
VmType() Type
|
||||||
|
|
||||||
|
@ -557,7 +557,8 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data := mem.Get(mStart.Int64(), mSize.Int64())
|
data := mem.Get(mStart.Int64(), mSize.Int64())
|
||||||
log := &Log{context.Address(), topics, data, self.env.BlockNumber().Uint64()}
|
log := state.NewLog(context.Address(), topics, data, self.env.BlockNumber().Uint64())
|
||||||
|
//log := &Log{context.Address(), topics, data, self.env.BlockNumber().Uint64()}
|
||||||
self.env.AddLog(log)
|
self.env.AddLog(log)
|
||||||
|
|
||||||
self.Printf(" => %v", log)
|
self.Printf(" => %v", log)
|
||||||
|
@ -47,7 +47,7 @@ func (self *VMEnv) GetHash(n uint64) common.Hash {
|
|||||||
|
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
func (self *VMEnv) AddLog(log state.Log) {
|
func (self *VMEnv) AddLog(log *state.Log) {
|
||||||
self.state.AddLog(log)
|
self.state.AddLog(log)
|
||||||
}
|
}
|
||||||
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
|
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
|
||||||
|
@ -266,6 +266,8 @@ func (self *worker) commitNewWork() {
|
|||||||
)
|
)
|
||||||
gasLimit:
|
gasLimit:
|
||||||
for i, tx := range transactions {
|
for i, tx := range transactions {
|
||||||
|
self.current.state.StartRecord(tx.Hash(), common.Hash{}, 0)
|
||||||
|
|
||||||
err := self.commitTransaction(tx)
|
err := self.commitTransaction(tx)
|
||||||
switch {
|
switch {
|
||||||
case core.IsNonceErr(err) || core.IsInvalidTxErr(err):
|
case core.IsNonceErr(err) || core.IsInvalidTxErr(err):
|
||||||
|
@ -284,15 +284,19 @@ type LogRes struct {
|
|||||||
TransactionIndex *hexnum `json:"transactionIndex"`
|
TransactionIndex *hexnum `json:"transactionIndex"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogRes(log state.Log) LogRes {
|
func NewLogRes(log *state.Log) LogRes {
|
||||||
var l LogRes
|
var l LogRes
|
||||||
l.Topics = make([]*hexdata, len(log.Topics()))
|
l.Topics = make([]*hexdata, len(log.Topics))
|
||||||
for j, topic := range log.Topics() {
|
for j, topic := range log.Topics {
|
||||||
l.Topics[j] = newHexData(topic)
|
l.Topics[j] = newHexData(topic)
|
||||||
}
|
}
|
||||||
l.Address = newHexData(log.Address())
|
l.Address = newHexData(log.Address)
|
||||||
l.Data = newHexData(log.Data())
|
l.Data = newHexData(log.Data)
|
||||||
l.BlockNumber = newHexNum(log.Number())
|
l.BlockNumber = newHexNum(log.Number)
|
||||||
|
l.LogIndex = newHexNum(log.Index)
|
||||||
|
l.TransactionHash = newHexData(log.TxHash)
|
||||||
|
l.TransactionIndex = newHexNum(log.TxIndex)
|
||||||
|
l.BlockHash = newHexData(log.BlockHash)
|
||||||
|
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
@ -393,7 +393,7 @@ func (self *XEth) NewFilterString(word string) int {
|
|||||||
self.logMut.Lock()
|
self.logMut.Lock()
|
||||||
defer self.logMut.Unlock()
|
defer self.logMut.Unlock()
|
||||||
|
|
||||||
self.logs[id].add(&state.StateLog{})
|
self.logs[id].add(&state.Log{})
|
||||||
}
|
}
|
||||||
case "latest":
|
case "latest":
|
||||||
filter.BlockCallback = func(block *types.Block, logs state.Logs) {
|
filter.BlockCallback = func(block *types.Block, logs state.Logs) {
|
||||||
@ -403,7 +403,7 @@ func (self *XEth) NewFilterString(word string) int {
|
|||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
self.logs[id].add(log)
|
self.logs[id].add(log)
|
||||||
}
|
}
|
||||||
self.logs[id].add(&state.StateLog{})
|
self.logs[id].add(&state.Log{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,7 +729,7 @@ type logFilter struct {
|
|||||||
id int
|
id int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *logFilter) add(logs ...state.Log) {
|
func (l *logFilter) add(logs ...*state.Log) {
|
||||||
l.logs = append(l.logs, logs...)
|
l.logs = append(l.logs, logs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user