core: fixed an issue with storing receipts
This commit is contained in:
		| @@ -102,7 +102,7 @@ window.filter = filter; | |||||||
| 		var amount = parseInt( value.value ); | 		var amount = parseInt( value.value ); | ||||||
| 		console.log("transact: ", to.value, " => ", amount) | 		console.log("transact: ", to.value, " => ", amount) | ||||||
|  |  | ||||||
| 		contract.sendTransaction({from: eth.accounts[0]}).send( to.value, amount ); | 		contract.send.sendTransaction(to.value, amount ,{from: eth.accounts[0]}); | ||||||
|  |  | ||||||
| 		to.value = ""; | 		to.value = ""; | ||||||
| 		value.value = ""; | 		value.value = ""; | ||||||
|   | |||||||
| @@ -40,11 +40,6 @@ type BlockProcessor struct { | |||||||
|  |  | ||||||
| 	txpool *TxPool | 	txpool *TxPool | ||||||
|  |  | ||||||
| 	// The last attempted block is mainly used for debugging purposes |  | ||||||
| 	// This does not have to be a valid block and will be set during |  | ||||||
| 	// 'Process' & canonical validation. |  | ||||||
| 	lastAttemptedBlock *types.Block |  | ||||||
|  |  | ||||||
| 	events event.Subscription | 	events event.Subscription | ||||||
|  |  | ||||||
| 	eventMux *event.TypeMux | 	eventMux *event.TypeMux | ||||||
| @@ -188,8 +183,6 @@ func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, err erro | |||||||
| } | } | ||||||
|  |  | ||||||
| func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, err error) { | func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, err error) { | ||||||
| 	sm.lastAttemptedBlock = block |  | ||||||
|  |  | ||||||
| 	// Create a new state based on the parent's root (e.g., create copy) | 	// Create a new state based on the parent's root (e.g., create copy) | ||||||
| 	state := state.New(parent.Root(), sm.db) | 	state := state.New(parent.Root(), sm.db) | ||||||
|  |  | ||||||
| @@ -255,6 +248,12 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// store the receipts | ||||||
|  | 	err = putReceipts(sm.extraDb, block.Hash(), receipts) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// Calculate the td for this block | 	// Calculate the td for this block | ||||||
| 	//td = CalculateTD(block, parent) | 	//td = CalculateTD(block, parent) | ||||||
| 	// Sync the current block's state to the database | 	// Sync the current block's state to the database | ||||||
| @@ -268,23 +267,9 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st | |||||||
| 		putTx(sm.extraDb, tx, block, uint64(i)) | 		putTx(sm.extraDb, tx, block, uint64(i)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	receiptsRlp := block.Receipts().RlpEncode() |  | ||||||
| 	sm.extraDb.Put(append(receiptsPre, block.Hash().Bytes()...), receiptsRlp) |  | ||||||
|  |  | ||||||
| 	return state.Logs(), nil | 	return state.Logs(), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self *BlockProcessor) GetBlockReceipts(bhash common.Hash) (receipts types.Receipts, err error) { |  | ||||||
| 	var rdata []byte |  | ||||||
| 	rdata, err = self.extraDb.Get(append(receiptsPre, bhash[:]...)) |  | ||||||
|  |  | ||||||
| 	if err == nil { |  | ||||||
| 		err = rlp.DecodeBytes(rdata, &receipts) |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // See YP section 4.3.4. "Block Header Validity" | // See YP section 4.3.4. "Block Header Validity" | ||||||
| // Validates a block. Returns an error if the block is invalid. | // Validates a block. Returns an error if the block is invalid. | ||||||
| func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header, checkPow bool) error { | func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header, checkPow bool) error { | ||||||
| @@ -391,13 +376,25 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // 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) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 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) { | func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) { | ||||||
| 	if !sm.bc.HasBlock(block.Header().ParentHash) { | 	receipts, err := sm.GetBlockReceipts(block.Hash()) | ||||||
| 		return nil, ParentError(block.Header().ParentHash) | 	if err == nil && len(receipts) > 0 { | ||||||
|  | 		// coalesce logs | ||||||
|  | 		for _, receipt := range receipts { | ||||||
|  | 			logs = append(logs, receipt.Logs()...) | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	sm.lastAttemptedBlock = block | 	// TODO: remove backward compatibility | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
| 		parent = sm.bc.GetBlock(block.Header().ParentHash) | 		parent = sm.bc.GetBlock(block.Header().ParentHash) | ||||||
| 		state  = state.New(parent.Root(), sm.db) | 		state  = state.New(parent.Root(), sm.db) | ||||||
| @@ -408,6 +405,16 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro | |||||||
| 	return state.Logs(), nil | 	return state.Logs(), 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) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
| func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint64) { | func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint64) { | ||||||
| 	rlpEnc, err := rlp.EncodeToBytes(tx) | 	rlpEnc, err := rlp.EncodeToBytes(tx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -431,3 +438,19 @@ func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint | |||||||
| 	} | 	} | ||||||
| 	db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta) | 	db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bytes, err := rlp.EncodeToBytes(storageReceipts) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	db.Put(append(receiptsPre, hash[:]...), bytes) | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|   | |||||||
| @@ -5,6 +5,8 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"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/ethdb" | 	"github.com/ethereum/go-ethereum/ethdb" | ||||||
| 	"github.com/ethereum/go-ethereum/event" | 	"github.com/ethereum/go-ethereum/event" | ||||||
| 	"github.com/ethereum/go-ethereum/pow/ezp" | 	"github.com/ethereum/go-ethereum/pow/ezp" | ||||||
| @@ -35,3 +37,33 @@ func TestNumber(t *testing.T) { | |||||||
| 		t.Errorf("didn't expect block number error") | 		t.Errorf("didn't expect block number error") | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestPutReceipt(t *testing.T) { | ||||||
|  | 	db, _ := ethdb.NewMemDatabase() | ||||||
|  |  | ||||||
|  | 	var addr common.Address | ||||||
|  | 	addr[0] = 1 | ||||||
|  | 	var hash common.Hash | ||||||
|  | 	hash[0] = 2 | ||||||
|  |  | ||||||
|  | 	receipt := new(types.Receipt) | ||||||
|  | 	receipt.SetLogs(state.Logs{&state.Log{ | ||||||
|  | 		Address:   addr, | ||||||
|  | 		Topics:    []common.Hash{hash}, | ||||||
|  | 		Data:      []byte("hi"), | ||||||
|  | 		Number:    42, | ||||||
|  | 		TxHash:    hash, | ||||||
|  | 		TxIndex:   0, | ||||||
|  | 		BlockHash: hash, | ||||||
|  | 		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)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -29,15 +29,22 @@ func (self *Log) EncodeRLP(w io.Writer) error { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (self *Log) String() string { | func (self *Log) String() string { | ||||||
| 	return fmt.Sprintf(`log: %x %x %x`, self.Address, self.Topics, self.Data) | 	return fmt.Sprintf(`log: %x %x %x %x %d %x %d`, self.Address, self.Topics, self.Data, self.TxHash, self.TxIndex, self.BlockHash, self.Index) | ||||||
| } | } | ||||||
|  |  | ||||||
| type Logs []*Log | type Logs []*Log | ||||||
|  |  | ||||||
| func (self Logs) String() (ret string) { | type LogForStorage Log | ||||||
| 	for _, log := range self { |  | ||||||
| 		ret += fmt.Sprintf("%v", log) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return "[" + ret + "]" | func (self *LogForStorage) EncodeRLP(w io.Writer) error { | ||||||
|  | 	return rlp.Encode(w, []interface{}{ | ||||||
|  | 		self.Address, | ||||||
|  | 		self.Topics, | ||||||
|  | 		self.Data, | ||||||
|  | 		self.Number, | ||||||
|  | 		self.TxHash, | ||||||
|  | 		self.TxIndex, | ||||||
|  | 		self.BlockHash, | ||||||
|  | 		self.Index, | ||||||
|  | 	}) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -26,10 +26,39 @@ func (self *Receipt) SetLogs(logs state.Logs) { | |||||||
| 	self.logs = logs | 	self.logs = logs | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (self *Receipt) Logs() state.Logs { | ||||||
|  | 	return self.logs | ||||||
|  | } | ||||||
|  |  | ||||||
| func (self *Receipt) EncodeRLP(w io.Writer) error { | 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) DecodeRLP(s *rlp.Stream) error { | ||||||
|  | 	var r struct { | ||||||
|  | 		PostState         []byte | ||||||
|  | 		CumulativeGasUsed *big.Int | ||||||
|  | 		Bloom             Bloom | ||||||
|  | 		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 | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ReceiptForStorage Receipt | ||||||
|  |  | ||||||
|  | func (self *ReceiptForStorage) EncodeRLP(w io.Writer) error { | ||||||
|  | 	storageLogs := make([]*state.LogForStorage, len(self.logs)) | ||||||
|  | 	for i, log := range self.logs { | ||||||
|  | 		storageLogs[i] = (*state.LogForStorage)(log) | ||||||
|  | 	} | ||||||
|  | 	return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, storageLogs}) | ||||||
|  | } | ||||||
|  |  | ||||||
| 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 { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user