fixed mined tx detection and storage

This commit is contained in:
zsfelfoldi 2016-06-29 22:50:44 +02:00
parent 68ae0c411d
commit 5937563956
4 changed files with 71 additions and 29 deletions

View file

@ -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 // InsertReceiptChain attempts to complete an already existing header chain with
// transaction and receipt data. // transaction and receipt data.
func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) { 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 continue
} }
// Compute all the non-consensus fields of the receipts // Compute all the non-consensus fields of the receipts
transactions, logIndex := block.Transactions(), uint(0) SetReceiptsData(block, receipts)
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++
}
}
// Write all the data out into the database // Write all the data out into the database
if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil { if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil {
errs[index] = fmt.Errorf("failed to write block body: %v", err) errs[index] = fmt.Errorf("failed to write block body: %v", err)

View file

@ -447,6 +447,16 @@ func WriteTransactions(db ethdb.Database, block *types.Block) error {
return nil 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. // WriteReceipts stores a batch of transaction receipts into the database.
func WriteReceipts(db ethdb.Database, receipts types.Receipts) error { func WriteReceipts(db ethdb.Database, receipts types.Receipts) error {
batch := db.NewBatch() batch := db.NewBatch()

View file

@ -1024,6 +1024,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, txH
// GetTransactionReceipt returns the transaction receipt for the given transaction hash. // GetTransactionReceipt returns the transaction receipt for the given transaction hash.
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (map[string]interface{}, error) { func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (map[string]interface{}, error) {
//fmt.Println("API GetTransactionReceipt", txHash)
receipt := core.GetReceipt(s.b.ChainDb(), txHash) receipt := core.GetReceipt(s.b.ChainDb(), txHash)
if receipt == nil { if receipt == nil {
glog.V(logger.Debug).Infof("receipt not found for transaction %s", txHash.Hex()) 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) tx, _, err := getTransaction(s.b.ChainDb(), s.b, txHash)
//fmt.Println("getTransaction", err)
if err != nil { if err != nil {
glog.V(logger.Debug).Infof("%v\n", err) glog.V(logger.Debug).Infof("%v\n", err)
return nil, nil return nil, nil
} }
txBlock, blockIndex, index, err := getTransactionBlockData(s.b.ChainDb(), txHash) txBlock, blockIndex, index, err := getTransactionBlockData(s.b.ChainDb(), txHash)
//fmt.Println("getTransactionBlockData", txBlock, blockIndex, index, err)
if err != nil { if err != nil {
glog.V(logger.Debug).Infof("%v\n", err) glog.V(logger.Debug).Infof("%v\n", err)
return nil, nil return nil, nil

View file

@ -128,12 +128,14 @@ type txBlockData struct {
// storeTxBlockData stores the block position of a mined tx in the local db // storeTxBlockData stores the block position of a mined tx in the local db
func (pool *TxPool) storeTxBlockData(txh common.Hash, tbd txBlockData) { func (pool *TxPool) storeTxBlockData(txh common.Hash, tbd txBlockData) {
//fmt.Println("storeTxBlockData", txh, tbd)
data, _ := rlp.EncodeToBytes(tbd) data, _ := rlp.EncodeToBytes(tbd)
pool.chainDb.Put(append(txh[:], byte(1)), data) pool.chainDb.Put(append(txh[:], byte(1)), data)
} }
// removeTxBlockData removes the stored block position of a rolled back tx // removeTxBlockData removes the stored block position of a rolled back tx
func (pool *TxPool) removeTxBlockData(txh common.Hash) { func (pool *TxPool) removeTxBlockData(txh common.Hash) {
//fmt.Println("removeTxBlockData", txh)
pool.chainDb.Delete(append(txh[:], byte(1))) 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 marks them as mined if necessary. It also stores block position in the db
// and adds them to the received txStateChanges map. // and adds them to the received txStateChanges map.
func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, idx uint64, txc txStateChanges) error { func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, idx uint64, txc txStateChanges) error {
//fmt.Println("checkMinedTxs")
if len(pool.pending) == 0 { if len(pool.pending) == 0 {
return nil 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 { if err != nil {
//fmt.Println(err)
return err return err
} }
//fmt.Println("len(block.Transactions()) =", len(block.Transactions()))
list := pool.mined[hash] list := pool.mined[hash]
for i, receipt := range receipts { for i, tx := range block.Transactions() {
txHash := receipt.TxHash txHash := tx.Hash()
//fmt.Println(" txHash:", txHash)
if tx, ok := pool.pending[txHash]; ok { 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)}) pool.storeTxBlockData(txHash, txBlockData{hash, idx, uint64(i)})
delete(pool.pending, txHash) delete(pool.pending, txHash)
list = append(list, tx) 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 { if err := self.add(ctx, tx); err != nil {
return err return err
} }
//fmt.Println("Send", tx.Hash())
self.relay.Send(types.Transactions{tx}) self.relay.Send(types.Transactions{tx})
self.chainDb.Put(tx.Hash().Bytes(), data) self.chainDb.Put(tx.Hash().Bytes(), data)