Browse Source

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.
obscuren 10 years ago
parent
commit
1c872ddf4b
12 changed files with 83 additions and 122 deletions
  1. 7 4
      core/block_processor.go
  2. 3 3
      core/filter.go
  3. 16 72
      core/state/log.go
  4. 33 9
      core/state/statedb.go
  5. 4 4
      core/types/bloom9.go
  6. 1 18
      core/types/receipt.go
  7. 1 1
      core/vm/environment.go
  8. 2 1
      core/vm/vm.go
  9. 1 1
      core/vm_env.go
  10. 2 0
      miner/worker.go
  11. 10 6
      rpc/responses.go
  12. 3 3
      xeth/xeth.go

+ 7 - 4
core/block_processor.go

@@ -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) {
 	// 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())
 	_, 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))
 	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})
 
 	glog.V(logger.Debug).Infoln(receipt)
@@ -97,7 +99,6 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
 	// Notify all subscribers
 	if !transientProcess {
 		go self.eventMux.Post(TxPostEvent{tx})
-		logs := statedb.Logs()
 		go self.eventMux.Post(logs)
 	}
 
@@ -115,7 +116,9 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
 		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)
 		if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
 			return nil, err

+ 3 - 3
core/filter.go

@@ -124,17 +124,17 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs {
 	// Filter the logs for interesting stuff
 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
 		}
 
 		logTopics := make([]common.Hash, len(self.topics))
-		copy(logTopics, log.Topics())
+		copy(logTopics, log.Topics)
 
 		for i, topics := range self.topics {
 			for _, topic := range topics {
 				var match bool
-				if log.Topics()[i] == topic {
+				if log.Topics[i] == topic {
 					match = true
 				}
 				if !match {

+ 16 - 72
core/state/log.go

@@ -8,87 +8,31 @@ import (
 	"github.com/ethereum/go-ethereum/rlp"
 )
 
-type Log interface {
-	Address() common.Address
-	Topics() []common.Hash
-	Data() []byte
+type Log struct {
+	Address common.Address
+	Topics  []common.Hash
+	Data    []byte
+	Number  uint64
 
-	Number() uint64
+	TxHash    common.Hash
+	TxIndex   uint
+	BlockHash common.Hash
+	Index     uint
 }
 
-type StateLog struct {
-	address common.Address
-	topics  []common.Hash
-	data    []byte
-	number  uint64
+func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *Log {
+	return &Log{Address: address, Topics: topics, Data: data, Number: number}
 }
 
-func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *StateLog {
-	return &StateLog{address, topics, data, number}
+func (self *Log) EncodeRLP(w io.Writer) error {
+	return rlp.Encode(w, []interface{}{self.Address, self.Topics, self.Data})
 }
 
-func (self *StateLog) Address() common.Address {
-	return self.address
+func (self *Log) String() string {
+	return fmt.Sprintf(`log: %x %x %x`, self.Address, self.Topics, self.Data)
 }
 
-func (self *StateLog) Topics() []common.Hash {
-	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
-}
-*/
+type Logs []*Log
 
 func (self Logs) String() (ret string) {
 	for _, log := range self {

+ 33 - 9
core/state/statedb.go

@@ -23,30 +23,53 @@ type StateDB struct {
 
 	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
 func New(root common.Hash, db common.Database) *StateDB {
 	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() {
 	self.trie.Trie.PrintRoot()
 }
 
-func (self *StateDB) EmptyLogs() {
-	self.logs = nil
+func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) {
+	self.thash = thash
+	self.bhash = bhash
+	self.txIndex = ti
 }
 
-func (self *StateDB) AddLog(log Log) {
-	self.logs = append(self.logs, log)
+func (self *StateDB) AddLog(log *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 {
+	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
 }
+*/
 
 func (self *StateDB) Refund(address common.Address, gas *big.Int) {
 	addr := address.Str()
@@ -253,9 +276,10 @@ func (self *StateDB) Copy() *StateDB {
 		state.refund[addr] = new(big.Int).Set(refund)
 	}
 
-	logs := make(Logs, len(self.logs))
-	copy(logs, self.logs)
-	state.logs = logs
+	for hash, logs := range self.logs {
+		state.logs[hash] = make(Logs, len(logs))
+		copy(state.logs[hash], logs)
+	}
 
 	return state
 }

+ 4 - 4
core/types/bloom9.go

@@ -4,8 +4,8 @@ import (
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/core/state"
+	"github.com/ethereum/go-ethereum/crypto"
 )
 
 func CreateBloom(receipts Receipts) Bloom {
@@ -20,10 +20,10 @@ func CreateBloom(receipts Receipts) Bloom {
 func LogsBloom(logs state.Logs) *big.Int {
 	bin := new(big.Int)
 	for _, log := range logs {
-		data := make([]common.Hash, len(log.Topics()))
-		bin.Or(bin, bloom9(log.Address().Bytes()))
+		data := make([]common.Hash, len(log.Topics))
+		bin.Or(bin, bloom9(log.Address.Bytes()))
 
-		for i, topic := range log.Topics() {
+		for i, topic := range log.Topics {
 			data[i] = topic
 		}
 

+ 1 - 18
core/types/receipt.go

@@ -7,8 +7,8 @@ import (
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/core/state"
+	"github.com/ethereum/go-ethereum/rlp"
 )
 
 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})
 }
 
-/*
-func (self *Receipt) RlpData() interface{} {
-	return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()}
-}
-*/
-
 func (self *Receipt) RlpEncode() []byte {
 	bytes, err := rlp.EncodeToBytes(self)
 	if err != nil {
@@ -58,17 +52,6 @@ func (self *Receipt) String() string {
 
 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 {
 	bytes, err := rlp.EncodeToBytes(self)
 	if err != nil {

+ 1 - 1
core/vm/environment.go

@@ -22,7 +22,7 @@ type Environment interface {
 	Difficulty() *big.Int
 	GasLimit() *big.Int
 	Transfer(from, to Account, amount *big.Int) error
-	AddLog(state.Log)
+	AddLog(*state.Log)
 
 	VmType() Type
 

+ 2 - 1
core/vm/vm.go

@@ -557,7 +557,8 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
 			}
 
 			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.Printf(" => %v", log)

+ 1 - 1
core/vm_env.go

@@ -47,7 +47,7 @@ func (self *VMEnv) GetHash(n uint64) common.Hash {
 
 	return common.Hash{}
 }
-func (self *VMEnv) AddLog(log state.Log) {
+func (self *VMEnv) AddLog(log *state.Log) {
 	self.state.AddLog(log)
 }
 func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {

+ 2 - 0
miner/worker.go

@@ -266,6 +266,8 @@ func (self *worker) commitNewWork() {
 	)
 gasLimit:
 	for i, tx := range transactions {
+		self.current.state.StartRecord(tx.Hash(), common.Hash{}, 0)
+
 		err := self.commitTransaction(tx)
 		switch {
 		case core.IsNonceErr(err) || core.IsInvalidTxErr(err):

+ 10 - 6
rpc/responses.go

@@ -284,15 +284,19 @@ type LogRes struct {
 	TransactionIndex *hexnum    `json:"transactionIndex"`
 }
 
-func NewLogRes(log state.Log) LogRes {
+func NewLogRes(log *state.Log) LogRes {
 	var l LogRes
-	l.Topics = make([]*hexdata, len(log.Topics()))
-	for j, topic := range log.Topics() {
+	l.Topics = make([]*hexdata, len(log.Topics))
+	for j, topic := range log.Topics {
 		l.Topics[j] = newHexData(topic)
 	}
-	l.Address = newHexData(log.Address())
-	l.Data = newHexData(log.Data())
-	l.BlockNumber = newHexNum(log.Number())
+	l.Address = newHexData(log.Address)
+	l.Data = newHexData(log.Data)
+	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
 }

+ 3 - 3
xeth/xeth.go

@@ -393,7 +393,7 @@ func (self *XEth) NewFilterString(word string) int {
 			self.logMut.Lock()
 			defer self.logMut.Unlock()
 
-			self.logs[id].add(&state.StateLog{})
+			self.logs[id].add(&state.Log{})
 		}
 	case "latest":
 		filter.BlockCallback = func(block *types.Block, logs state.Logs) {
@@ -403,7 +403,7 @@ func (self *XEth) NewFilterString(word string) int {
 			for _, log := range logs {
 				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
 }
 
-func (l *logFilter) add(logs ...state.Log) {
+func (l *logFilter) add(logs ...*state.Log) {
 	l.logs = append(l.logs, logs...)
 }