From 5937563956f9ba6ddc62b24eb51c7dcee11714fb Mon Sep 17 00:00:00 2001 From: zsfelfoldi Date: Wed, 29 Jun 2016 22:50:44 +0200 Subject: [PATCH] fixed mined tx detection and storage --- core/blockchain.go | 58 +++++++++++++++++++++++------------------- core/database_util.go | 10 ++++++++ internal/ethapi/api.go | 3 +++ light/txpool.go | 29 ++++++++++++++++++--- 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 95bada5eed..62ebecaf1c 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -618,6 +618,37 @@ func (self *BlockChain) Rollback(chain []common.Hash) { } } +// SetReceiptsData computes all the non-consensus fields of the receipts +func SetReceiptsData(block *types.Block, receipts types.Receipts) { + transactions, logIndex := block.Transactions(), uint(0) + + for j := 0; j < len(receipts); j++ { + // The transaction hash can be retrieved from the transaction itself + receipts[j].TxHash = transactions[j].Hash() + + // The contract address can be derived from the transaction itself + if MessageCreatesContract(transactions[j]) { + from, _ := transactions[j].From() + receipts[j].ContractAddress = crypto.CreateAddress(from, transactions[j].Nonce()) + } + // The used gas can be calculated based on previous receipts + if j == 0 { + receipts[j].GasUsed = new(big.Int).Set(receipts[j].CumulativeGasUsed) + } else { + receipts[j].GasUsed = new(big.Int).Sub(receipts[j].CumulativeGasUsed, receipts[j-1].CumulativeGasUsed) + } + // The derived log fields can simply be set from the block and transaction + for k := 0; k < len(receipts[j].Logs); k++ { + receipts[j].Logs[k].BlockNumber = block.NumberU64() + receipts[j].Logs[k].BlockHash = block.Hash() + receipts[j].Logs[k].TxHash = receipts[j].TxHash + receipts[j].Logs[k].TxIndex = uint(j) + receipts[j].Logs[k].Index = logIndex + logIndex++ + } + } +} + // InsertReceiptChain attempts to complete an already existing header chain with // transaction and receipt data. func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) { @@ -659,32 +690,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain continue } // Compute all the non-consensus fields of the receipts - transactions, logIndex := block.Transactions(), uint(0) - for j := 0; j < len(receipts); j++ { - // The transaction hash can be retrieved from the transaction itself - receipts[j].TxHash = transactions[j].Hash() - - // The contract address can be derived from the transaction itself - if MessageCreatesContract(transactions[j]) { - from, _ := transactions[j].From() - receipts[j].ContractAddress = crypto.CreateAddress(from, transactions[j].Nonce()) - } - // The used gas can be calculated based on previous receipts - if j == 0 { - receipts[j].GasUsed = new(big.Int).Set(receipts[j].CumulativeGasUsed) - } else { - receipts[j].GasUsed = new(big.Int).Sub(receipts[j].CumulativeGasUsed, receipts[j-1].CumulativeGasUsed) - } - // The derived log fields can simply be set from the block and transaction - for k := 0; k < len(receipts[j].Logs); k++ { - receipts[j].Logs[k].BlockNumber = block.NumberU64() - receipts[j].Logs[k].BlockHash = block.Hash() - receipts[j].Logs[k].TxHash = receipts[j].TxHash - receipts[j].Logs[k].TxIndex = uint(j) - receipts[j].Logs[k].Index = logIndex - logIndex++ - } - } + SetReceiptsData(block, receipts) // Write all the data out into the database if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil { errs[index] = fmt.Errorf("failed to write block body: %v", err) diff --git a/core/database_util.go b/core/database_util.go index 8c7aaa0ee8..7456d32dd2 100644 --- a/core/database_util.go +++ b/core/database_util.go @@ -447,6 +447,16 @@ func WriteTransactions(db ethdb.Database, block *types.Block) error { return nil } +// WriteReceipt stores a single transaction receipt into the database. +func WriteReceipt(db ethdb.Database, receipt *types.Receipt) error { + storageReceipt := (*types.ReceiptForStorage)(receipt) + data, err := rlp.EncodeToBytes(storageReceipt) + if err != nil { + return err + } + return db.Put(append(receiptsPrefix, receipt.TxHash.Bytes()...), data) +} + // WriteReceipts stores a batch of transaction receipts into the database. func WriteReceipts(db ethdb.Database, receipts types.Receipts) error { batch := db.NewBatch() diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index adb97e4070..eb81919280 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1024,6 +1024,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, txH // GetTransactionReceipt returns the transaction receipt for the given transaction hash. func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (map[string]interface{}, error) { +//fmt.Println("API GetTransactionReceipt", txHash) receipt := core.GetReceipt(s.b.ChainDb(), txHash) if receipt == nil { glog.V(logger.Debug).Infof("receipt not found for transaction %s", txHash.Hex()) @@ -1031,12 +1032,14 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma } tx, _, err := getTransaction(s.b.ChainDb(), s.b, txHash) +//fmt.Println("getTransaction", err) if err != nil { glog.V(logger.Debug).Infof("%v\n", err) return nil, nil } txBlock, blockIndex, index, err := getTransactionBlockData(s.b.ChainDb(), txHash) +//fmt.Println("getTransactionBlockData", txBlock, blockIndex, index, err) if err != nil { glog.V(logger.Debug).Infof("%v\n", err) return nil, nil diff --git a/light/txpool.go b/light/txpool.go index 5b2e8d58dd..8b33b22506 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -128,12 +128,14 @@ type txBlockData struct { // storeTxBlockData stores the block position of a mined tx in the local db func (pool *TxPool) storeTxBlockData(txh common.Hash, tbd txBlockData) { +//fmt.Println("storeTxBlockData", txh, tbd) data, _ := rlp.EncodeToBytes(tbd) pool.chainDb.Put(append(txh[:], byte(1)), data) } // removeTxBlockData removes the stored block position of a rolled back tx func (pool *TxPool) removeTxBlockData(txh common.Hash) { +//fmt.Println("removeTxBlockData", txh) pool.chainDb.Delete(append(txh[:], byte(1))) } @@ -167,18 +169,38 @@ func (txc txStateChanges) getLists() (mined []common.Hash, rollback []common.Has // and marks them as mined if necessary. It also stores block position in the db // and adds them to the received txStateChanges map. func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, idx uint64, txc txStateChanges) error { +//fmt.Println("checkMinedTxs") if len(pool.pending) == 0 { return nil } +//fmt.Println("len(pool) =", len(pool.pending)) - receipts, err := GetBlockReceipts(ctx, pool.odr, hash, idx) + block, err := GetBlock(ctx, pool.odr, hash, idx) + var receipts types.Receipts if err != nil { +//fmt.Println(err) return err } +//fmt.Println("len(block.Transactions()) =", len(block.Transactions())) + list := pool.mined[hash] - for i, receipt := range receipts { - txHash := receipt.TxHash + for i, tx := range block.Transactions() { + txHash := tx.Hash() +//fmt.Println(" txHash:", txHash) if tx, ok := pool.pending[txHash]; ok { +//fmt.Println("TX FOUND") + if receipts == nil { + receipts, err = GetBlockReceipts(ctx, pool.odr, hash, idx) + if err != nil { + return err + } + if len(receipts) != len(block.Transactions()) { + panic(nil) // should never happen if hashes did match + } + core.SetReceiptsData(block, receipts) + } +//fmt.Println("WriteReceipt", receipts[i].TxHash) + core.WriteReceipt(pool.chainDb, receipts[i]) pool.storeTxBlockData(txHash, txBlockData{hash, idx, uint64(i)}) delete(pool.pending, txHash) list = append(list, tx) @@ -428,6 +450,7 @@ func (self *TxPool) Add(ctx context.Context, tx *types.Transaction) error { if err := self.add(ctx, tx); err != nil { return err } +//fmt.Println("Send", tx.Hash()) self.relay.Send(types.Transactions{tx}) self.chainDb.Put(tx.Hash().Bytes(), data)