ソースを参照

core, eth, miner, xeth: receipt storage fix

* Added GetReceiptsFromBlock, GetReceipt, PutReceipts
* Added ContractAddress to receipt. See #1042
Jeffrey Wilcke 10 年 前
コミット
2feb23c1da

+ 15 - 19
core/block_processor.go

@@ -9,12 +9,12 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
-	"github.com/ethereum/go-ethereum/rlp"
 	"gopkg.in/fatih/set.v0"
 )
 
@@ -24,8 +24,6 @@ const (
 	BlockChainVersion = 3
 )
 
-var receiptsPre = []byte("receipts-")
-
 type BlockProcessor struct {
 	db      common.Database
 	extraDb common.Database
@@ -83,6 +81,12 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
 
 	usedGas.Add(usedGas, gas)
 	receipt := types.NewReceipt(statedb.Root().Bytes(), usedGas)
+	receipt.TxHash = tx.Hash()
+	if MessageCreatesContract(tx) {
+		from, _ := tx.From()
+		receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
+	}
+
 	logs := statedb.GetLogs(tx.Hash())
 	receipt.SetLogs(logs)
 	receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
@@ -319,16 +323,20 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
 }
 
 // GetBlockReceipts returns the receipts beloniging to the block hash
-func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) (receipts types.Receipts, err error) {
-	return getBlockReceipts(sm.extraDb, bhash)
+func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts {
+	if block := sm.ChainManager().GetBlock(bhash); block != nil {
+		return GetReceiptsFromBlock(sm.extraDb, block)
+	}
+
+	return nil
 }
 
 // GetLogs returns the logs of the given block. This method is using a two step approach
 // where it tries to get it from the (updated) method which gets them from the receipts or
 // the depricated way by re-processing the block.
 func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) {
-	receipts, err := sm.GetBlockReceipts(block.Hash())
-	if err == nil && len(receipts) > 0 {
+	receipts := GetReceiptsFromBlock(sm.extraDb, block)
+	if len(receipts) > 0 {
 		// coalesce logs
 		for _, receipt := range receipts {
 			logs = append(logs, receipt.Logs()...)
@@ -391,15 +399,3 @@ func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, check
 
 	return nil
 }
-
-func getBlockReceipts(db common.Database, bhash common.Hash) (receipts types.Receipts, err error) {
-	var rdata []byte
-	rdata, err = db.Get(append(receiptsPre, bhash[:]...))
-
-	if err == nil {
-		err = rlp.DecodeBytes(rdata, &receipts)
-	} else {
-		glog.V(logger.Detail).Infof("getBlockReceipts error %v\n", err)
-	}
-	return
-}

+ 4 - 7
core/block_processor_test.go

@@ -64,12 +64,9 @@ func TestPutReceipt(t *testing.T) {
 		Index:     0,
 	}})
 
-	PutReceipts(db, hash, types.Receipts{receipt})
-	receipts, err := getBlockReceipts(db, hash)
-	if err != nil {
-		t.Error("got err:", err)
-	}
-	if len(receipts) != 1 {
-		t.Error("expected to get 1 receipt, got", len(receipts))
+	PutReceipts(db, types.Receipts{receipt})
+	receipt = GetReceipt(db, common.Hash{})
+	if receipt == nil {
+		t.Error("expected to get 1 receipt, got none.")
 	}
 }

+ 1 - 1
core/chain_manager.go

@@ -632,7 +632,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
 			// This puts transactions in a extra db for rpc
 			PutTransactions(self.extraDb, block, block.Transactions())
 			// store the receipts
-			PutReceipts(self.extraDb, block.Hash(), receipts)
+			PutReceipts(self.extraDb, receipts)
 		case SideStatTy:
 			if glog.V(logger.Detail) {
 				glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))

+ 42 - 8
core/transaction_util.go

@@ -8,6 +8,9 @@ import (
 	"github.com/ethereum/go-ethereum/rlp"
 )
 
+var receiptsPre = []byte("receipts-")
+
+// PutTransactions stores the transactions in the given database
 func PutTransactions(db common.Database, block *types.Block, txs types.Transactions) {
 	for i, tx := range block.Transactions() {
 		rlpEnc, err := rlp.EncodeToBytes(tx)
@@ -34,18 +37,49 @@ func PutTransactions(db common.Database, block *types.Block, txs types.Transacti
 	}
 }
 
-func PutReceipts(db common.Database, hash common.Hash, receipts types.Receipts) error {
-	storageReceipts := make([]*types.ReceiptForStorage, len(receipts))
-	for i, receipt := range receipts {
-		storageReceipts[i] = (*types.ReceiptForStorage)(receipt)
+// PutReceipts stores the receipts in the current database
+func PutReceipts(db common.Database, receipts types.Receipts) error {
+	for _, receipt := range receipts {
+		storageReceipt := (*types.ReceiptForStorage)(receipt)
+		bytes, err := rlp.EncodeToBytes(storageReceipt)
+		if err != nil {
+			return err
+		}
+		err = db.Put(append(receiptsPre, receipt.TxHash[:]...), bytes)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// GetReceipt returns a receipt by hash
+func GetReceipt(db common.Database, txHash common.Hash) *types.Receipt {
+	data, _ := db.Get(append(receiptsPre, txHash[:]...))
+	if len(data) == 0 {
+		return nil
 	}
 
-	bytes, err := rlp.EncodeToBytes(storageReceipts)
+	var receipt types.Receipt
+	err := rlp.DecodeBytes(data, &receipt)
 	if err != nil {
-		return err
+		glog.V(logger.Error).Infoln("GetReceipt err:", err)
 	}
+	return &receipt
+}
 
-	db.Put(append(receiptsPre, hash[:]...), bytes)
+// GetReceiptFromBlock returns all receipts with the given block
+func GetReceiptsFromBlock(db common.Database, block *types.Block) types.Receipts {
+	// at some point we want:
+	//receipts := make(types.Receipts, len(block.Transactions()))
+	// but since we need to support legacy, we can't (yet)
+	var receipts types.Receipts
+	for _, tx := range block.Transactions() {
+		if receipt := GetReceipt(db, tx.Hash()); receipt != nil {
+			receipts = append(receipts, receipt)
+		}
+	}
 
-	return nil
+	return receipts
 }

+ 6 - 2
core/types/receipt.go

@@ -15,6 +15,8 @@ type Receipt struct {
 	PostState         []byte
 	CumulativeGasUsed *big.Int
 	Bloom             Bloom
+	TxHash            common.Hash
+	ContractAddress   common.Address
 	logs              state.Logs
 }
 
@@ -39,12 +41,14 @@ func (self *Receipt) DecodeRLP(s *rlp.Stream) error {
 		PostState         []byte
 		CumulativeGasUsed *big.Int
 		Bloom             Bloom
+		TxHash            common.Hash
+		ContractAddress   common.Address
 		Logs              state.Logs
 	}
 	if err := s.Decode(&r); err != nil {
 		return err
 	}
-	self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs = r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs
+	self.PostState, self.CumulativeGasUsed, self.Bloom, self.TxHash, self.ContractAddress, self.logs = r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, r.Logs
 
 	return nil
 }
@@ -56,7 +60,7 @@ func (self *ReceiptForStorage) EncodeRLP(w io.Writer) error {
 	for i, log := range self.logs {
 		storageLogs[i] = (*state.LogForStorage)(log)
 	}
-	return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, storageLogs})
+	return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.TxHash, self.ContractAddress, storageLogs})
 }
 
 func (self *Receipt) RlpEncode() []byte {

+ 3 - 6
eth/gasprice.go

@@ -131,13 +131,10 @@ func (self *GasPriceOracle) processBlock(block *types.Block) {
 // returns the lowers possible price with which a tx was or could have been included
 func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int {
 	gasUsed := new(big.Int)
-	recepits, err := self.eth.BlockProcessor().GetBlockReceipts(block.Hash())
-	if err != nil {
-		return self.eth.GpoMinGasPrice
-	}
 
-	if len(recepits) > 0 {
-		gasUsed = recepits[len(recepits)-1].CumulativeGasUsed
+	receipts := self.eth.BlockProcessor().GetBlockReceipts(block.Hash())
+	if len(receipts) > 0 {
+		gasUsed = receipts[len(receipts)-1].CumulativeGasUsed
 	}
 
 	if new(big.Int).Mul(gasUsed, big.NewInt(100)).Cmp(new(big.Int).Mul(block.GasLimit(),

+ 1 - 1
miner/worker.go

@@ -255,7 +255,7 @@ func (self *worker) wait() {
 				// This puts transactions in a extra db for rpc
 				core.PutTransactions(self.extraDb, block, block.Transactions())
 				// store the receipts
-				core.PutReceipts(self.extraDb, block.Hash(), self.current.receipts)
+				core.PutReceipts(self.extraDb, self.current.receipts)
 			}
 
 			// check staleness and display confirmation

+ 3 - 13
xeth/xeth.go

@@ -364,22 +364,12 @@ func (self *XEth) CurrentBlock() *types.Block {
 	return self.backend.ChainManager().CurrentBlock()
 }
 
-func (self *XEth) GetBlockReceipts(bhash common.Hash) (receipts types.Receipts, err error) {
+func (self *XEth) GetBlockReceipts(bhash common.Hash) types.Receipts {
 	return self.backend.BlockProcessor().GetBlockReceipts(bhash)
 }
 
-func (self *XEth) GetTxReceipt(txhash common.Hash) (receipt *types.Receipt, err error) {
-	_, bhash, _, txi := self.EthTransactionByHash(common.ToHex(txhash[:]))
-	var receipts types.Receipts
-	receipts, err = self.backend.BlockProcessor().GetBlockReceipts(bhash)
-	if err == nil {
-		if txi < uint64(len(receipts)) {
-			receipt = receipts[txi]
-		} else {
-			err = fmt.Errorf("Invalid tx index")
-		}
-	}
-	return
+func (self *XEth) GetTxReceipt(txhash common.Hash) *types.Receipt {
+	return core.GetReceipt(self.backend.ExtraDb(), txhash)
 }
 
 func (self *XEth) GasLimit() *big.Int {