diff --git a/accounts/abi/bind/backends/bor_simulated.go b/accounts/abi/bind/backends/bor_simulated.go index 3f5480d6a57b0a7b7a158543eb5c3aeece017f0b..ef5a7202ca1af5261b073ea090ef8f3f3c36db44 100644 --- a/accounts/abi/bind/backends/bor_simulated.go +++ b/accounts/abi/bind/backends/bor_simulated.go @@ -8,7 +8,7 @@ import ( "github.com/maticnetwork/bor/core/types" ) -func (fb *filterBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { +func (fb *filterBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { number := rawdb.ReadHeaderNumber(fb.db, hash) if number == nil { return nil, nil diff --git a/core/blockchain.go b/core/blockchain.go index 2fd91de3ab38a11421a76e41bcdbbc550c3acb22..bb9c130178eefe2785fd696ebaa5b79525945579 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -497,6 +497,7 @@ func (bc *BlockChain) SetHead(head uint64) error { // removed in the hc.SetHead function. rawdb.DeleteBody(db, hash, num) rawdb.DeleteReceipts(db, hash, num) + rawdb.DeleteBorReceipt(db, hash, num) } // Todo(rjl493456442) txlookup, bloombits, etc } @@ -509,6 +510,7 @@ func (bc *BlockChain) SetHead(head uint64) error { bc.blockCache.Purge() bc.txLookupCache.Purge() bc.futureBlocks.Purge() + bc.borReceiptsCache.Purge() return bc.loadLastState() } @@ -1460,8 +1462,9 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. }) if len(blockLogs) > len(logs) { - rawdb.WriteBorReceipt(blockBatch, block.Hash(), block.NumberU64(), &types.BorReceiptForStorage{ - Logs: blockLogs[len(logs):], // get state-sync logs from `state.Logs()` + rawdb.WriteBorReceipt(blockBatch, block.Hash(), block.NumberU64(), &types.ReceiptForStorage{ + Status: types.ReceiptStatusSuccessful, // make receipt status successful + Logs: blockLogs[len(logs):], // get state-sync logs from `state.Logs()` }) } } diff --git a/core/bor_blockchain.go b/core/bor_blockchain.go index 21e5b73fbd19f546558eaba3f0d011d5b6498276..1fe518c4828ebe7fa32fb69952cdf461a7899506 100644 --- a/core/bor_blockchain.go +++ b/core/bor_blockchain.go @@ -7,9 +7,9 @@ import ( ) // GetBorReceiptByHash retrieves the bor block receipt in a given block. -func (bc *BlockChain) GetBorReceiptByHash(hash common.Hash) *types.BorReceipt { +func (bc *BlockChain) GetBorReceiptByHash(hash common.Hash) *types.Receipt { if receipt, ok := bc.borReceiptsCache.Get(hash); ok { - return receipt.(*types.BorReceipt) + return receipt.(*types.Receipt) } // read header from hash diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index d863e2408814850354c685ac176dd2122036ffbd..f0a964f0e37c7a3a8428e0fdbc445683acfba387 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -596,7 +596,7 @@ func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) { } // WriteAncientBlock writes entire block data into ancient store and returns the total written size. -func WriteAncientBlock(db ethdb.AncientWriter, block *types.Block, receipts types.Receipts, td *big.Int, borReceipt *types.BorReceipt) int { +func WriteAncientBlock(db ethdb.AncientWriter, block *types.Block, receipts types.Receipts, td *big.Int, borReceipt *types.Receipt) int { // Encode all block components to RLP format. headerBlob, err := rlp.EncodeToBytes(block.Header()) if err != nil { diff --git a/core/rawdb/bor_receipt.go b/core/rawdb/bor_receipt.go index f5fed74326141334ca9dc5cd941fe494de0fb5dd..8a58d20506c6b5c967d2c9f862a890095322e14a 100644 --- a/core/rawdb/bor_receipt.go +++ b/core/rawdb/bor_receipt.go @@ -1,6 +1,8 @@ package rawdb import ( + "math/big" + "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/core/types" "github.com/maticnetwork/bor/ethdb" @@ -9,15 +11,19 @@ import ( ) var ( - borReceiptPrefix = []byte("bor-receipt-") // borReceiptPrefix + number + block hash -> bor block receipt + // bor receipt key + borReceiptKey = types.BorReceiptKey + + // borTxLookupPrefix + hash -> transaction/receipt lookup metadata + borTxLookupPrefix = []byte("matic-bor-tx-lookup-") // freezerBorReceiptTable indicates the name of the freezer bor receipts table. - freezerBorReceiptTable = "bor-receipts" + freezerBorReceiptTable = "matic-bor-receipts" ) -// borReceiptKey = borReceiptPrefix + num (uint64 big endian) + hash -func borReceiptKey(number uint64, hash common.Hash) []byte { - return append(append(borReceiptPrefix, encodeBlockNumber(number)...), hash.Bytes()...) +// borTxLookupKey = borTxLookupPrefix + hash +func borTxLookupKey(hash common.Hash) []byte { + return append(borTxLookupPrefix, hash.Bytes()...) } // HasBorReceipt verifies the existence of all block receipt belonging @@ -68,7 +74,7 @@ func ReadBorReceiptRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.Raw // ReadRawBorReceipt retrieves the block receipt belonging to a block. // The receipt metadata fields are not guaranteed to be populated, so they // should not be used. Use ReadBorReceipt instead if the metadata is needed. -func ReadRawBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.BorReceipt { +func ReadRawBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.Receipt { // Retrieve the flattened receipt slice data := ReadBorReceiptRLP(db, hash, number) if data == nil || len(data) == 0 { @@ -76,32 +82,38 @@ func ReadRawBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types. } // Convert the receipts from their storage form to their internal representation - var storageReceipt types.BorReceiptForStorage + var storageReceipt types.ReceiptForStorage if err := rlp.DecodeBytes(data, &storageReceipt); err != nil { log.Error("Invalid receipt array RLP", "hash", hash, "err", err) return nil } - return (*types.BorReceipt)(&storageReceipt) + return (*types.Receipt)(&storageReceipt) } // ReadBorReceipt retrieves all the bor block receipts belonging to a block, including // its correspoinding metadata fields. If it is unable to populate these metadata // fields then nil is returned. -func ReadBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.BorReceipt { +func ReadBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.Receipt { // We're deriving many fields from the block body, retrieve beside the receipt borReceipt := ReadRawBorReceipt(db, hash, number) if borReceipt == nil { return nil } + // We're deriving many fields from the block body, retrieve beside the receipt + receipts := ReadRawReceipts(db, hash, number) + if receipts == nil { + return nil + } + body := ReadBody(db, hash, number) if body == nil { log.Error("Missing body but have bor receipt", "hash", hash, "number", number) return nil } - if err := borReceipt.DeriveFields(hash, number); err != nil { + if err := types.DeriveFieldsForBorReceipt(borReceipt, hash, number, receipts); err != nil { log.Error("Failed to derive bor receipt fields", "hash", hash, "number", number, "err", err) return nil } @@ -109,7 +121,7 @@ func ReadBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.Bor } // WriteBorReceipt stores all the bor receipt belonging to a block. -func WriteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64, borReceipt *types.BorReceiptForStorage) { +func WriteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64, borReceipt *types.ReceiptForStorage) { // Convert the bor receipt into their storage form and serialize them bytes, err := rlp.EncodeToBytes(borReceipt) if err != nil { @@ -117,14 +129,73 @@ func WriteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64, b } // Store the flattened receipt slice - if err := db.Put(borReceiptKey(number, hash), bytes); err != nil { + key := borReceiptKey(number, hash) + if err := db.Put(key, bytes); err != nil { log.Crit("Failed to store bor receipt", "err", err) } + + // Write bor tx reverse lookup + WriteBorTxLookupEntry(db, types.GetDerivedBorTxHash(key), big.NewInt(0).SetUint64(number)) } // DeleteBorReceipt removes receipt data associated with a block hash. func DeleteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { - if err := db.Delete(borReceiptKey(number, hash)); err != nil { + key := borReceiptKey(number, hash) + + if err := db.Delete(key); err != nil { log.Crit("Failed to delete bor receipt", "err", err) } } + +// ReadBorTransaction retrieves a specific bor (fake) transaction, along with +// its added positional metadata. +func ReadBorTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) { + blockNumber := ReadBorTxLookupEntry(db, hash) + if blockNumber == nil { + return nil, common.Hash{}, 0, 0 + } + + blockHash := ReadCanonicalHash(db, *blockNumber) + if blockHash == (common.Hash{}) { + return nil, common.Hash{}, 0, 0 + } + + body := ReadBody(db, blockHash, *blockNumber) + if body == nil { + log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash) + return nil, common.Hash{}, 0, 0 + } + + // fetch receipt and return it + return types.NewBorTransaction(), blockHash, *blockNumber, uint64(len(body.Transactions)) +} + +// +// Indexes for reverse lookup +// + +// ReadBorTxLookupEntry retrieves the positional metadata associated with a transaction +// hash to allow retrieving the bor transaction or bor receipt by hash. +func ReadBorTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 { + data, _ := db.Get(borTxLookupKey(hash)) + if len(data) == 0 { + return nil + } + + number := new(big.Int).SetBytes(data).Uint64() + return &number +} + +// WriteBorTxLookupEntry stores a positional metadata for bor transaction. +func WriteBorTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash, number *big.Int) { + if err := db.Put(borTxLookupKey(hash), number.Bytes()); err != nil { + log.Crit("Failed to store bor transaction lookup entry", "err", err) + } +} + +// DeleteBorTxLookupEntry removes bor transaction data associated with a hash. +func DeleteBorTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash) { + if err := db.Delete(borTxLookupKey(hash)); err != nil { + log.Crit("Failed to delete bor transaction lookup entry", "err", err) + } +} diff --git a/core/types/bor_receipt.go b/core/types/bor_receipt.go index d88a3baa055642226f30fde7be9c5fa2397e5e3d..e00739f094a6f3f0b805680369441859211b6ddd 100644 --- a/core/types/bor_receipt.go +++ b/core/types/bor_receipt.go @@ -1,109 +1,73 @@ package types import ( - "io" + "encoding/binary" "math/big" + "sort" "github.com/maticnetwork/bor/common" - "github.com/maticnetwork/bor/rlp" + "github.com/maticnetwork/bor/crypto" ) -// BorReceipt represents the results of a block state syncs -type BorReceipt struct { - // Consensus fields - Bloom Bloom `json:"logsBloom" gencodec:"required"` - Logs []*Log `json:"logs" gencodec:"required"` +var ( + borReceiptPrefix = []byte("matic-bor-receipt-") // borReceiptPrefix + number + block hash -> bor block receipt - // Inclusion information: These fields provide information about the inclusion of the - // transaction corresponding to this receipt. - BlockHash common.Hash `json:"blockHash,omitempty"` - BlockNumber *big.Int `json:"blockNumber,omitempty"` -} - -// borReceiptRLP is the consensus encoding of a block receipt. -type borReceiptRLP struct { - Bloom Bloom - Logs []*Log -} - -// storedBorReceiptRLP is the storage encoding of a block receipt. -type storedBorReceiptRLP struct { - Logs []*LogForStorage -} - -// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a block receipt -// into an RLP stream. If no post state is present, byzantium fork is assumed. -func (r *BorReceipt) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, &borReceiptRLP{r.Bloom, r.Logs}) -} + // SystemAddress address for system sender + SystemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE") +) -// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a block receipt -// from an RLP stream. -func (r *BorReceipt) DecodeRLP(s *rlp.Stream) error { - var dec receiptRLP - if err := s.Decode(&dec); err != nil { - return err - } - r.Bloom, r.Logs = dec.Bloom, dec.Logs - return nil +// BorReceiptKey = borReceiptPrefix + num (uint64 big endian) + hash +func BorReceiptKey(number uint64, hash common.Hash) []byte { + enc := make([]byte, 8) + binary.BigEndian.PutUint64(enc, number) + return append(append(borReceiptPrefix, enc...), hash.Bytes()...) } -// BorReceiptForStorage is a wrapper around a Bor Receipt that flattens and parses the -// entire content of a receipt, as opposed to only the consensus fields originally. -type BorReceiptForStorage BorReceipt - -// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt -// into an RLP stream. -func (r *BorReceiptForStorage) EncodeRLP(w io.Writer) error { - enc := &storedBorReceiptRLP{ - Logs: make([]*LogForStorage, len(r.Logs)), - } - - for i, log := range r.Logs { - enc.Logs[i] = (*LogForStorage)(log) - } - return rlp.Encode(w, enc) +// GetDerivedBorTxHash get derived tx hash from receipt key +func GetDerivedBorTxHash(receiptKey []byte) common.Hash { + return common.BytesToHash(crypto.Keccak256(receiptKey)) } -// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation -// fields of a receipt from an RLP stream. -func (r *BorReceiptForStorage) DecodeRLP(s *rlp.Stream) error { - // Retrieve the entire receipt blob as we need to try multiple decoders - blob, err := s.Raw() - if err != nil { - return err - } - - return decodeStoredBorReceiptRLP(r, blob) +// NewBorTransaction create new bor transaction for bor receipt +func NewBorTransaction() *Transaction { + return NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), make([]byte, 0)) } -func decodeStoredBorReceiptRLP(r *BorReceiptForStorage, blob []byte) error { - var stored storedBorReceiptRLP - if err := rlp.DecodeBytes(blob, &stored); err != nil { - return err +// DeriveFieldsForBorReceipt fills the receipts with their computed fields based on consensus +// data and contextual infos like containing block and transactions. +func DeriveFieldsForBorReceipt(receipt *Receipt, hash common.Hash, number uint64, receipts Receipts) error { + // get derived tx hash + txHash := GetDerivedBorTxHash(BorReceiptKey(number, hash)) + txIndex := uint(len(receipts)) + + // set tx hash and tx index + receipt.TxHash = txHash + receipt.TransactionIndex = txIndex + receipt.BlockHash = hash + receipt.BlockNumber = big.NewInt(0).SetUint64(number) + + logIndex := 0 + for i := 0; i < len(receipts); i++ { + logIndex += len(receipts[i].Logs) } - r.Logs = make([]*Log, len(stored.Logs)) - for i, log := range stored.Logs { - r.Logs[i] = (*Log)(log) + // The derived log fields can simply be set from the block and transaction + for j := 0; j < len(receipt.Logs); j++ { + receipt.Logs[j].BlockNumber = number + receipt.Logs[j].BlockHash = hash + receipt.Logs[j].TxHash = txHash + receipt.Logs[j].TxIndex = txIndex + receipt.Logs[j].Index = uint(logIndex) + logIndex++ } - r.Bloom = BytesToBloom(LogsBloom(r.Logs).Bytes()) - return nil } -// DeriveFields fills the receipts with their computed fields based on consensus -// data and contextual infos like containing block and transactions. -func (r *BorReceipt) DeriveFields(hash common.Hash, number uint64) error { - // txHash := common.BytesToHash(crypto.Keccak256(append([]byte("bor-receipt-"), hash.Bytes()...))) - - // The derived log fields can simply be set from the block and transaction - for j := 0; j < len(r.Logs); j++ { - r.Logs[j].BlockNumber = number - r.Logs[j].BlockHash = hash - // r.Logs[j].TxHash = txHash - r.Logs[j].TxIndex = uint(0) - r.Logs[j].Index = uint(j) - } - return nil +// MergeBorLogs merges receipt logs and block receipt logs +func MergeBorLogs(logs []*Log, borLogs []*Log) []*Log { + result := append(logs, borLogs...) + sort.SliceStable(result, func(i int, j int) bool { + return (result[i].BlockNumber*100000 + uint64(result[i].Index)) < (result[j].BlockNumber*100000 + uint64(result[j].Index)) + }) + return result } diff --git a/eth/api_tracer.go b/eth/api_tracer.go index d91e81e9a69f1709ec91945c0fc06bce22e2797a..d48f68092186ba94ed6ff6f296c94fcedfe1a984 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -704,6 +704,16 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (* func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { // Retrieve the transaction and assemble its EVM context tx, blockHash, _, index := rawdb.ReadTransaction(api.eth.ChainDb(), hash) + if tx == nil { + // For BorTransaction, there will be no trace available + tx, _, _, _ = rawdb.ReadBorTransaction(api.eth.ChainDb(), hash) + if tx != nil { + return ðapi.ExecutionResult{ + StructLogs: make([]ethapi.StructLogRes, 0), + }, nil + } + } + if tx == nil { return nil, fmt.Errorf("transaction %#x not found", hash) } diff --git a/eth/bor_api_backend.go b/eth/bor_api_backend.go index 5a13ea1a6034ed191df75b3170ea9d6dbfad33a4..497a7509478c34d5e09654ece5b8cce71058172d 100644 --- a/eth/bor_api_backend.go +++ b/eth/bor_api_backend.go @@ -6,6 +6,7 @@ import ( ethereum "github.com/maticnetwork/bor" "github.com/maticnetwork/bor/common" "github.com/maticnetwork/bor/consensus/bor" + "github.com/maticnetwork/bor/core/rawdb" "github.com/maticnetwork/bor/core/types" ) @@ -24,7 +25,7 @@ func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, end return root, nil } -func (b *EthAPIBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { +func (b *EthAPIBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { receipt := b.eth.blockchain.GetBorReceiptByHash(hash) if receipt == nil { return nil, ethereum.NotFound @@ -40,3 +41,8 @@ func (b *EthAPIBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ( } return receipt.Logs, nil } + +func (b *EthAPIBackend) GetBorBlockTransaction(ctx context.Context, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { + tx, blockHash, blockNumber, index := rawdb.ReadBorTransaction(b.eth.ChainDb(), hash) + return tx, blockHash, blockNumber, index, nil +} diff --git a/eth/filters/api.go b/eth/filters/api.go index 66aa2d43696691a4ac721775b7adfb20a233b6e6..5c53e41390988b70bcda9c1a74ad0a686694fd8d 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -357,9 +357,12 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) { var filter *Filter + var borLogsFilter *BorBlockLogsFilter if crit.BlockHash != nil { // Block filter requested, construct a single-shot filter filter = NewBlockFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics) + // Block bor filter + borLogsFilter = NewBorBlockLogsFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics) } else { // Convert the RPC block numbers into internal representations begin := rpc.LatestBlockNumber.Int64() @@ -372,13 +375,23 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([ } // Construct the range filter filter = NewRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics) + // Block bor filter + borLogsFilter = NewBorBlockLogsRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics) } + // Run the filter and return all the logs logs, err := filter.Logs(ctx) if err != nil { return nil, err } - return returnLogs(logs), err + // Run the filter and return all the logs + borBlockLogs, err := borLogsFilter.Logs(ctx) + if err != nil { + return nil, err + } + + // merge bor block logs and receipt logs and return it + return returnLogs(types.MergeBorLogs(logs, borBlockLogs)), err } // UninstallFilter removes the filter with the given filter id. diff --git a/eth/filters/bor_filter.go b/eth/filters/bor_filter.go index 3d7e7a62fae87420af1c761973b3548dea149948..7c011463519c015e56a3053b81a9d3ba02aa3e60 100644 --- a/eth/filters/bor_filter.go +++ b/eth/filters/bor_filter.go @@ -97,7 +97,7 @@ func (f *BorBlockLogsFilter) Logs(ctx context.Context) ([]*types.Log, error) { } // adjust begin for sprint - f.begin = nextSprintEnd(f.begin) + f.begin = currentSprintEnd(f.begin) end := f.end if f.end == -1 { @@ -136,15 +136,14 @@ func (f *BorBlockLogsFilter) unindexedLogs(ctx context.Context, end uint64) ([]* } // borBlockLogs returns the logs matching the filter criteria within a single block. -func (f *BorBlockLogsFilter) borBlockLogs(ctx context.Context, receipt *types.BorReceipt) (logs []*types.Log, err error) { +func (f *BorBlockLogsFilter) borBlockLogs(ctx context.Context, receipt *types.Receipt) (logs []*types.Log, err error) { if bloomFilter(receipt.Bloom, f.addresses, f.topics) { - found := filterLogs(receipt.Logs, nil, nil, f.addresses, f.topics) - logs = append(logs, found...) + logs = filterLogs(receipt.Logs, nil, nil, f.addresses, f.topics) } return logs, nil } -func nextSprintEnd(n int64) int64 { +func currentSprintEnd(n int64) int64 { m := n % 64 if m == 0 { return n diff --git a/eth/filters/bor_filter_system_test.go b/eth/filters/bor_filter_system_test.go index d1c6fbd07d97d8f27d47f3dbcf91113cb4da147b..a6eebfa198b19885049e32d693b0bb13d21e0a3a 100644 --- a/eth/filters/bor_filter_system_test.go +++ b/eth/filters/bor_filter_system_test.go @@ -8,7 +8,7 @@ import ( "github.com/maticnetwork/bor/core/types" ) -func (b *testBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { +func (b *testBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { number := rawdb.ReadHeaderNumber(b.db, hash) if number == nil { return nil, nil diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 1b91e06eddf10520aa6a12700f41684ef308b0f9..d15f2635681b13f9228433410f5a4fbb540c79b7 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -36,7 +36,7 @@ type Backend interface { HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) - GetBorBlockReceipt(ctx context.Context, blockHash common.Hash) (*types.BorReceipt, error) + GetBorBlockReceipt(ctx context.Context, blockHash common.Hash) (*types.Receipt, error) GetBorBlockLogs(ctx context.Context, blockHash common.Hash) ([]*types.Log, error) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription diff --git a/ethclient/bor_ethclient.go b/ethclient/bor_ethclient.go index 4b1a01a26a657e917d316b18096eac039451264b..dc19fb1795691f33a01f2203f2620f21f8be1028 100644 --- a/ethclient/bor_ethclient.go +++ b/ethclient/bor_ethclient.go @@ -18,8 +18,8 @@ func (ec *Client) GetRootHash(ctx context.Context, startBlockNumber uint64, endB } // GetBorBlockReceipt returns bor block receipt -func (ec *Client) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { - var r *types.BorReceipt +func (ec *Client) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { + var r *types.Receipt err := ec.c.CallContext(ctx, &r, "eth_getBorBlockReceipt", hash) if err == nil { if r == nil { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 09a3e0c473ee2ff9e862bdfe8db3242fefb56efe..eb41aade310094dc3d66c93f94242ffb5563e7e7 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -661,6 +661,12 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B response[field] = nil } } + + // append marshalled bor transaction + if err == nil && response != nil { + response = s.appendRPCMarshalBorTransaction(ctx, block, response, fullTx) + } + return response, err } return nil, err @@ -671,7 +677,12 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { block, err := s.b.BlockByHash(ctx, hash) if block != nil { - return s.rpcMarshalBlock(block, true, fullTx) + response, err := s.rpcMarshalBlock(block, true, fullTx) + // append marshalled bor transaction + if err == nil && response != nil { + return s.appendRPCMarshalBorTransaction(ctx, block, response, fullTx), err + } + return response, err } return nil, err } @@ -1357,14 +1368,33 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr // GetTransactionByHash returns the transaction for the given hash func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { + borTx := false + // Try to return an already finalized transaction tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) if err != nil { return nil, err } + + // fetch bor block tx if necessary + if tx == nil { + if tx, blockHash, blockNumber, index, err = s.b.GetBorBlockTransaction(ctx, hash); err != nil { + return nil, err + } + + borTx = true + } + if tx != nil { - return newRPCTransaction(tx, blockHash, blockNumber, index), nil + resultTx := newRPCTransaction(tx, blockHash, blockNumber, index) + if borTx { + // newRPCTransaction calculates hash based on RLP of the transaction data. + // In case of bor block tx, we need simple derived tx hash (same as function argument) instead of RLP hash + resultTx.Hash = hash + } + return resultTx, nil } + // No finalized transaction, try to retrieve it from the pool if tx := s.b.GetPoolTransaction(hash); tx != nil { return newRPCPendingTransaction(tx), nil @@ -1393,18 +1423,33 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, // GetTransactionReceipt returns the transaction receipt for the given transaction hash. func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { + borTx := false + tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash) if tx == nil { - return nil, nil - } - receipts, err := s.b.GetReceipts(ctx, blockHash) - if err != nil { - return nil, err + tx, blockHash, blockNumber, index = rawdb.ReadBorTransaction(s.b.ChainDb(), hash) + borTx = true } - if len(receipts) <= int(index) { + + if tx == nil { return nil, nil } - receipt := receipts[index] + + var receipt *types.Receipt + + if borTx { + // Fetch bor block receipt + receipt = rawdb.ReadBorReceipt(s.b.ChainDb(), blockHash, blockNumber) + } else { + receipts, err := s.b.GetReceipts(ctx, blockHash) + if err != nil { + return nil, err + } + if len(receipts) <= int(index) { + return nil, nil + } + receipt = receipts[index] + } var signer types.Signer = types.FrontierSigner{} if tx.Protected() { diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index a8a6c4b9e74d37542adf3b060d9f146b26dbbe1a..fc4950623917ad53fbe0261c31e51a3f82d138ec 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -68,8 +68,9 @@ type Backend interface { // Bor API GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) - GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) + GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) + GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) // Transaction pool API SendTx(ctx context.Context, signedTx *types.Transaction) error diff --git a/internal/ethapi/bor_api.go b/internal/ethapi/bor_api.go index 3cf1347a4839c013a83665aa8d14fe727851aa80..624f6d70dde1f4c3522b87e2ebeeecbae03a07aa 100644 --- a/internal/ethapi/bor_api.go +++ b/internal/ethapi/bor_api.go @@ -15,6 +15,30 @@ func (s *PublicBlockChainAPI) GetRootHash(ctx context.Context, starBlockNr uint6 return root, nil } -func (s *PublicBlockChainAPI) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { +func (s *PublicBlockChainAPI) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { return s.b.GetBorBlockReceipt(ctx, hash) } + +// +// Bor transaction utils +// + +func (s *PublicBlockChainAPI) appendRPCMarshalBorTransaction(ctx context.Context, block *types.Block, fields map[string]interface{}, fullTx bool) map[string]interface{} { + if block != nil { + txHash := types.GetDerivedBorTxHash(types.BorReceiptKey(block.Number().Uint64(), block.Hash())) + borTx, blockHash, blockNumber, txIndex, _ := s.b.GetBorBlockTransaction(ctx, txHash) + if borTx != nil { + formattedTxs := fields["transactions"].([]interface{}) + if fullTx { + marshalledTx := newRPCTransaction(borTx, blockHash, blockNumber, txIndex) + // newRPCTransaction calculates hash based on RLP of the transaction data. + // In case of bor block tx, we need simple derived tx hash (same as function argument) instead of RLP hash + marshalledTx.Hash = txHash + fields["transactions"] = append(formattedTxs, marshalledTx) + } else { + fields["transactions"] = append(formattedTxs, txHash) + } + } + } + return fields +} diff --git a/les/api_backend.go b/les/api_backend.go index 1f0dc8abf0b4ff58f9f3e59cbc3eacec4adac0fa..defe86ba2e9048812c96df38a8b0d026df6ac00d 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -288,10 +288,14 @@ func (b *LesApiBackend) GetRootHash(ctx context.Context, starBlockNr uint64, end return "", errors.New("Not implemented") } -func (b *LesApiBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { +func (b *LesApiBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { return nil, errors.New("Not implemented") } func (b *LesApiBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) { return nil, errors.New("Not implemented") } + +func (b *LesApiBackend) GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { + return nil, common.Hash{}, 0, 0, errors.New("Not implemented") +}