2019-04-18 12:39:37 +00:00
|
|
|
// VulcanizeDB
|
|
|
|
// Copyright © 2019 Vulcanize
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2020-01-17 23:16:01 +00:00
|
|
|
package eth
|
2019-05-21 19:27:24 +00:00
|
|
|
|
|
|
|
import (
|
2020-01-17 23:16:01 +00:00
|
|
|
"fmt"
|
2019-06-18 17:28:57 +00:00
|
|
|
"math/big"
|
|
|
|
|
2020-01-21 19:12:35 +00:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
2021-08-12 06:23:41 +00:00
|
|
|
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
2019-05-21 19:27:24 +00:00
|
|
|
"github.com/jmoiron/sqlx"
|
|
|
|
"github.com/lib/pq"
|
2019-06-07 13:42:10 +00:00
|
|
|
log "github.com/sirupsen/logrus"
|
2022-05-27 13:46:10 +00:00
|
|
|
"github.com/thoas/go-funk"
|
2019-06-07 13:42:10 +00:00
|
|
|
|
2022-05-18 08:05:16 +00:00
|
|
|
"github.com/vulcanize/ipld-eth-server/v3/pkg/shared"
|
2019-05-21 19:27:24 +00:00
|
|
|
)
|
|
|
|
|
2020-08-31 15:47:06 +00:00
|
|
|
// Retriever interface for substituting mocks in tests
|
|
|
|
type Retriever interface {
|
|
|
|
RetrieveFirstBlockNumber() (int64, error)
|
|
|
|
RetrieveLastBlockNumber() (int64, error)
|
2020-10-20 14:42:09 +00:00
|
|
|
Retrieve(filter SubscriptionSettings, blockNumber int64) ([]CIDWrapper, bool, error)
|
2020-08-31 15:47:06 +00:00
|
|
|
}
|
|
|
|
|
2020-01-17 23:16:01 +00:00
|
|
|
// CIDRetriever satisfies the CIDRetriever interface for ethereum
|
|
|
|
type CIDRetriever struct {
|
2022-03-10 09:53:03 +00:00
|
|
|
db *sqlx.DB
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-17 23:16:01 +00:00
|
|
|
// NewCIDRetriever returns a pointer to a new CIDRetriever which supports the CIDRetriever interface
|
2022-03-10 09:53:03 +00:00
|
|
|
func NewCIDRetriever(db *sqlx.DB) *CIDRetriever {
|
2020-01-17 23:16:01 +00:00
|
|
|
return &CIDRetriever{
|
2019-05-21 19:27:24 +00:00
|
|
|
db: db,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-08 19:51:38 +00:00
|
|
|
// RetrieveFirstBlockNumber is used to retrieve the first block number in the db
|
2020-01-17 23:16:01 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveFirstBlockNumber() (int64, error) {
|
2019-07-02 17:38:12 +00:00
|
|
|
var blockNumber int64
|
2020-01-31 19:25:15 +00:00
|
|
|
err := ecr.db.Get(&blockNumber, "SELECT block_number FROM eth.header_cids ORDER BY block_number ASC LIMIT 1")
|
2019-07-02 17:38:12 +00:00
|
|
|
return blockNumber, err
|
|
|
|
}
|
|
|
|
|
2019-10-08 19:51:38 +00:00
|
|
|
// RetrieveLastBlockNumber is used to retrieve the latest block number in the db
|
2020-01-17 23:16:01 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveLastBlockNumber() (int64, error) {
|
2019-05-21 19:27:24 +00:00
|
|
|
var blockNumber int64
|
2020-01-31 19:25:15 +00:00
|
|
|
err := ecr.db.Get(&blockNumber, "SELECT block_number FROM eth.header_cids ORDER BY block_number DESC LIMIT 1 ")
|
2019-05-21 19:27:24 +00:00
|
|
|
return blockNumber, err
|
|
|
|
}
|
2019-06-06 03:50:12 +00:00
|
|
|
|
2020-01-17 23:16:01 +00:00
|
|
|
// Retrieve is used to retrieve all of the CIDs which conform to the passed StreamFilters
|
2020-10-20 14:42:09 +00:00
|
|
|
func (ecr *CIDRetriever) Retrieve(filter SubscriptionSettings, blockNumber int64) ([]CIDWrapper, bool, error) {
|
2019-06-07 13:42:10 +00:00
|
|
|
log.Debug("retrieving cids")
|
2020-05-01 21:25:58 +00:00
|
|
|
|
|
|
|
// Begin new db tx
|
2020-01-16 20:48:38 +00:00
|
|
|
tx, err := ecr.db.Beginx()
|
|
|
|
if err != nil {
|
2020-01-17 23:16:01 +00:00
|
|
|
return nil, true, err
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2020-05-01 21:25:58 +00:00
|
|
|
defer func() {
|
|
|
|
if p := recover(); p != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
panic(p)
|
|
|
|
} else if err != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
} else {
|
|
|
|
err = tx.Commit()
|
|
|
|
}
|
|
|
|
}()
|
2020-01-16 20:48:38 +00:00
|
|
|
|
2020-02-23 23:14:29 +00:00
|
|
|
// Retrieve cached header CIDs at this block height
|
2021-08-12 06:23:41 +00:00
|
|
|
var headers []models.HeaderModel
|
2021-04-19 13:42:09 +00:00
|
|
|
headers, err = ecr.RetrieveHeaderCIDs(tx, blockNumber)
|
2020-02-23 23:14:29 +00:00
|
|
|
if err != nil {
|
2021-08-20 07:37:11 +00:00
|
|
|
log.Error("header cid retrieval error", err)
|
2020-02-23 23:14:29 +00:00
|
|
|
return nil, true, err
|
|
|
|
}
|
2020-10-20 14:42:09 +00:00
|
|
|
cws := make([]CIDWrapper, len(headers))
|
2020-02-23 23:14:29 +00:00
|
|
|
empty := true
|
|
|
|
for i, header := range headers {
|
2020-10-20 14:42:09 +00:00
|
|
|
cw := new(CIDWrapper)
|
2020-02-23 23:14:29 +00:00
|
|
|
cw.BlockNumber = big.NewInt(blockNumber)
|
2020-08-31 15:47:06 +00:00
|
|
|
if !filter.HeaderFilter.Off {
|
2020-02-23 23:14:29 +00:00
|
|
|
cw.Header = header
|
|
|
|
empty = false
|
2020-08-31 15:47:06 +00:00
|
|
|
if filter.HeaderFilter.Uncles {
|
2020-02-23 23:14:29 +00:00
|
|
|
// Retrieve uncle cids for this header id
|
2021-08-12 06:23:41 +00:00
|
|
|
var uncleCIDs []models.UncleModel
|
2022-03-10 12:35:19 +00:00
|
|
|
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, header.BlockHash)
|
2020-01-26 19:55:26 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("uncle cid retrieval error")
|
|
|
|
return nil, true, err
|
2019-08-28 18:41:49 +00:00
|
|
|
}
|
2020-02-23 23:14:29 +00:00
|
|
|
cw.Uncles = uncleCIDs
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-23 23:14:29 +00:00
|
|
|
// Retrieve cached trx CIDs
|
2020-08-31 15:47:06 +00:00
|
|
|
if !filter.TxFilter.Off {
|
2022-03-10 12:35:19 +00:00
|
|
|
cw.Transactions, err = ecr.RetrieveTxCIDs(tx, filter.TxFilter, header.BlockHash)
|
2020-02-23 23:14:29 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("transaction cid retrieval error")
|
|
|
|
return nil, true, err
|
|
|
|
}
|
|
|
|
if len(cw.Transactions) > 0 {
|
|
|
|
empty = false
|
2019-08-28 18:41:49 +00:00
|
|
|
}
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2022-03-10 12:35:19 +00:00
|
|
|
trxHashes := make([]string, len(cw.Transactions))
|
|
|
|
for j, t := range cw.Transactions {
|
|
|
|
trxHashes[j] = t.TxHash
|
2020-02-23 23:14:29 +00:00
|
|
|
}
|
|
|
|
// Retrieve cached receipt CIDs
|
2020-08-31 15:47:06 +00:00
|
|
|
if !filter.ReceiptFilter.Off {
|
2022-03-10 12:35:19 +00:00
|
|
|
cw.Receipts, err = ecr.RetrieveRctCIDsByHeaderID(tx, filter.ReceiptFilter, header.BlockHash, trxHashes)
|
2020-02-23 23:14:29 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("receipt cid retrieval error")
|
|
|
|
return nil, true, err
|
|
|
|
}
|
|
|
|
if len(cw.Receipts) > 0 {
|
|
|
|
empty = false
|
2019-08-28 18:41:49 +00:00
|
|
|
}
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2020-02-23 23:14:29 +00:00
|
|
|
// Retrieve cached state CIDs
|
2020-08-31 15:47:06 +00:00
|
|
|
if !filter.StateFilter.Off {
|
2022-03-10 12:35:19 +00:00
|
|
|
cw.StateNodes, err = ecr.RetrieveStateCIDs(tx, filter.StateFilter, header.BlockHash)
|
2020-02-23 23:14:29 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("state cid retrieval error")
|
|
|
|
return nil, true, err
|
|
|
|
}
|
|
|
|
if len(cw.StateNodes) > 0 {
|
|
|
|
empty = false
|
2019-08-28 18:41:49 +00:00
|
|
|
}
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2020-02-23 23:14:29 +00:00
|
|
|
// Retrieve cached storage CIDs
|
2020-08-31 15:47:06 +00:00
|
|
|
if !filter.StorageFilter.Off {
|
2022-03-10 12:35:19 +00:00
|
|
|
cw.StorageNodes, err = ecr.RetrieveStorageCIDs(tx, filter.StorageFilter, header.BlockHash)
|
2020-02-23 23:14:29 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("storage cid retrieval error")
|
|
|
|
return nil, true, err
|
|
|
|
}
|
|
|
|
if len(cw.StorageNodes) > 0 {
|
|
|
|
empty = false
|
2019-08-28 18:41:49 +00:00
|
|
|
}
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2020-08-31 15:47:06 +00:00
|
|
|
cws[i] = *cw
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
|
|
|
|
2020-05-01 21:25:58 +00:00
|
|
|
return cws, empty, err
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 20:48:38 +00:00
|
|
|
// RetrieveHeaderCIDs retrieves and returns all of the header cids at the provided blockheight
|
2021-08-12 06:23:41 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveHeaderCIDs(tx *sqlx.Tx, blockNumber int64) ([]models.HeaderModel, error) {
|
2019-06-07 16:01:29 +00:00
|
|
|
log.Debug("retrieving header cids for block ", blockNumber)
|
2021-08-12 06:23:41 +00:00
|
|
|
headers := make([]models.HeaderModel, 0)
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr := `SELECT CAST(block_number as Text), block_hash,parent_hash,cid,mh_key,CAST(td as Text),node_id,
|
|
|
|
CAST(reward as Text), state_root,uncle_root,tx_root,receipt_root,bloom,timestamp,times_validated,
|
|
|
|
coinbase FROM eth.header_cids
|
2020-01-26 19:55:26 +00:00
|
|
|
WHERE block_number = $1`
|
|
|
|
return headers, tx.Select(&headers, pgStr, blockNumber)
|
2019-06-18 17:28:57 +00:00
|
|
|
}
|
|
|
|
|
2020-01-26 19:55:26 +00:00
|
|
|
// RetrieveUncleCIDsByHeaderID retrieves and returns all of the uncle cids for the provided header
|
2022-03-10 12:35:19 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveUncleCIDsByHeaderID(tx *sqlx.Tx, headerID string) ([]models.UncleModel, error) {
|
2020-01-26 19:55:26 +00:00
|
|
|
log.Debug("retrieving uncle cids for block id ", headerID)
|
2021-08-12 06:23:41 +00:00
|
|
|
headers := make([]models.UncleModel, 0)
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr := `SELECT header_id,block_hash,parent_hash,cid,mh_key, CAST(reward as text) FROM eth.uncle_cids
|
2020-01-26 19:55:26 +00:00
|
|
|
WHERE header_id = $1`
|
|
|
|
return headers, tx.Select(&headers, pgStr, headerID)
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-26 19:55:26 +00:00
|
|
|
// RetrieveTxCIDs retrieves and returns all of the trx cids at the provided blockheight that conform to the provided filter parameters
|
2020-01-16 20:48:38 +00:00
|
|
|
// also returns the ids for the returned transaction cids
|
2022-03-10 12:35:19 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveTxCIDs(tx *sqlx.Tx, txFilter TxFilter, headerID string) ([]models.TxModel, error) {
|
2020-02-23 23:14:29 +00:00
|
|
|
log.Debug("retrieving transaction cids for header id ", headerID)
|
2019-05-21 19:27:24 +00:00
|
|
|
args := make([]interface{}, 0, 3)
|
2021-08-12 06:23:41 +00:00
|
|
|
results := make([]models.TxModel, 0)
|
2020-02-09 21:28:30 +00:00
|
|
|
id := 1
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr := fmt.Sprintf(`SELECT transaction_cids.tx_hash, transaction_cids.header_id,transaction_cids.cid, transaction_cids.mh_key,
|
|
|
|
transaction_cids.dst, transaction_cids.src, transaction_cids.index, transaction_cids.tx_data
|
|
|
|
FROM eth.transaction_cids INNER JOIN eth.header_cids ON (transaction_cids.header_id = header_cids.block_hash)
|
|
|
|
WHERE header_cids.block_hash = $%d`, id)
|
2020-02-23 23:14:29 +00:00
|
|
|
args = append(args, headerID)
|
2020-02-09 21:28:30 +00:00
|
|
|
id++
|
2020-01-16 20:48:38 +00:00
|
|
|
if len(txFilter.Dst) > 0 {
|
2020-02-09 21:28:30 +00:00
|
|
|
pgStr += fmt.Sprintf(` AND transaction_cids.dst = ANY($%d::VARCHAR(66)[])`, id)
|
2020-01-16 20:48:38 +00:00
|
|
|
args = append(args, pq.Array(txFilter.Dst))
|
2020-02-09 21:28:30 +00:00
|
|
|
id++
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2020-01-16 20:48:38 +00:00
|
|
|
if len(txFilter.Src) > 0 {
|
2020-02-09 21:28:30 +00:00
|
|
|
pgStr += fmt.Sprintf(` AND transaction_cids.src = ANY($%d::VARCHAR(66)[])`, id)
|
2020-01-16 20:48:38 +00:00
|
|
|
args = append(args, pq.Array(txFilter.Src))
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2020-02-20 22:13:19 +00:00
|
|
|
pgStr += ` ORDER BY transaction_cids.index`
|
2020-01-21 19:12:35 +00:00
|
|
|
return results, tx.Select(&results, pgStr, args...)
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
|
|
|
|
2021-08-31 11:32:01 +00:00
|
|
|
func topicFilterCondition(id *int, topics [][]string, args []interface{}, pgStr string, first bool) (string, []interface{}) {
|
2021-08-14 13:50:22 +00:00
|
|
|
for i, topicSet := range topics {
|
|
|
|
if len(topicSet) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if !first {
|
|
|
|
pgStr += " AND"
|
|
|
|
} else {
|
|
|
|
first = false
|
|
|
|
}
|
2021-08-31 11:32:01 +00:00
|
|
|
pgStr += fmt.Sprintf(` eth.log_cids.topic%d = ANY ($%d)`, i, *id)
|
2021-08-14 13:50:22 +00:00
|
|
|
args = append(args, pq.Array(topicSet))
|
2021-08-31 11:32:01 +00:00
|
|
|
*id++
|
2021-08-14 13:50:22 +00:00
|
|
|
}
|
2021-08-31 11:32:01 +00:00
|
|
|
return pgStr, args
|
2021-08-14 13:50:22 +00:00
|
|
|
}
|
|
|
|
|
2021-08-31 11:32:01 +00:00
|
|
|
func logFilterCondition(id *int, pgStr string, args []interface{}, rctFilter ReceiptFilter) (string, []interface{}) {
|
2021-08-20 07:37:11 +00:00
|
|
|
if len(rctFilter.LogAddresses) > 0 {
|
2021-08-31 11:32:01 +00:00
|
|
|
pgStr += fmt.Sprintf(` AND eth.log_cids.address = ANY ($%d)`, *id)
|
2021-08-20 07:37:11 +00:00
|
|
|
args = append(args, pq.Array(rctFilter.LogAddresses))
|
2021-08-31 11:32:01 +00:00
|
|
|
*id++
|
|
|
|
}
|
2021-08-20 07:37:11 +00:00
|
|
|
|
2021-08-31 11:32:01 +00:00
|
|
|
// Filter on topics if there are any
|
|
|
|
if hasTopics(rctFilter.Topics) {
|
|
|
|
pgStr, args = topicFilterCondition(id, rctFilter.Topics, args, pgStr, false)
|
2021-08-20 07:37:11 +00:00
|
|
|
}
|
|
|
|
|
2021-08-31 11:32:01 +00:00
|
|
|
return pgStr, args
|
2021-08-20 07:37:11 +00:00
|
|
|
}
|
|
|
|
|
2022-03-10 12:35:19 +00:00
|
|
|
func receiptFilterConditions(id *int, pgStr string, args []interface{}, rctFilter ReceiptFilter, txHashes []string) (string, []interface{}) {
|
|
|
|
rctCond := " AND (receipt_cids.tx_id = ANY ( "
|
|
|
|
logQuery := "SELECT rct_id FROM eth.log_cids WHERE"
|
2020-04-02 03:34:06 +00:00
|
|
|
if len(rctFilter.LogAddresses) > 0 {
|
|
|
|
// Filter on log contract addresses if there are any
|
2021-08-31 11:32:01 +00:00
|
|
|
pgStr += fmt.Sprintf(`%s %s eth.log_cids.address = ANY ($%d)`, rctCond, logQuery, *id)
|
2020-04-02 03:34:06 +00:00
|
|
|
args = append(args, pq.Array(rctFilter.LogAddresses))
|
2021-08-31 11:32:01 +00:00
|
|
|
*id++
|
2021-08-14 13:50:22 +00:00
|
|
|
|
2020-02-23 23:14:29 +00:00
|
|
|
// Filter on topics if there are any
|
|
|
|
if hasTopics(rctFilter.Topics) {
|
2021-08-31 11:32:01 +00:00
|
|
|
pgStr, args = topicFilterCondition(id, rctFilter.Topics, args, pgStr, false)
|
2020-02-23 23:14:29 +00:00
|
|
|
}
|
2021-08-14 13:50:22 +00:00
|
|
|
|
2020-02-23 23:14:29 +00:00
|
|
|
pgStr += ")"
|
2021-08-14 13:50:22 +00:00
|
|
|
|
2022-03-10 12:35:19 +00:00
|
|
|
// Filter on txHashes if there are any, and we are matching txs
|
|
|
|
if rctFilter.MatchTxs && len(txHashes) > 0 {
|
|
|
|
pgStr += fmt.Sprintf(` OR receipt_cids.tx_id = ANY($%d)`, *id)
|
|
|
|
args = append(args, pq.Array(txHashes))
|
2020-02-23 23:14:29 +00:00
|
|
|
}
|
|
|
|
pgStr += ")"
|
|
|
|
} else { // If there are no contract addresses to filter on
|
|
|
|
// Filter on topics if there are any
|
|
|
|
if hasTopics(rctFilter.Topics) {
|
2021-08-14 13:50:22 +00:00
|
|
|
pgStr += rctCond + logQuery
|
2021-08-31 11:32:01 +00:00
|
|
|
pgStr, args = topicFilterCondition(id, rctFilter.Topics, args, pgStr, true)
|
2020-02-23 23:14:29 +00:00
|
|
|
pgStr += ")"
|
2022-03-10 12:35:19 +00:00
|
|
|
// Filter on txHashes if there are any, and we are matching txs
|
|
|
|
if rctFilter.MatchTxs && len(txHashes) > 0 {
|
|
|
|
pgStr += fmt.Sprintf(` OR receipt_cids.tx_id = ANY($%d)`, *id)
|
|
|
|
args = append(args, pq.Array(txHashes))
|
2020-02-23 23:14:29 +00:00
|
|
|
}
|
|
|
|
pgStr += ")"
|
2022-03-10 12:35:19 +00:00
|
|
|
} else if rctFilter.MatchTxs && len(txHashes) > 0 {
|
2020-02-23 23:14:29 +00:00
|
|
|
// If there are no contract addresses or topics to filter on,
|
2022-03-10 12:35:19 +00:00
|
|
|
// Filter on txHashes if there are any, and we are matching txs
|
|
|
|
pgStr += fmt.Sprintf(` AND receipt_cids.tx_id = ANY($%d)`, *id)
|
|
|
|
args = append(args, pq.Array(txHashes))
|
2020-02-23 23:14:29 +00:00
|
|
|
}
|
|
|
|
}
|
2021-08-14 13:50:22 +00:00
|
|
|
|
2021-08-31 11:32:01 +00:00
|
|
|
return pgStr, args
|
2021-08-14 13:50:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// RetrieveRctCIDsByHeaderID retrieves and returns all of the rct cids at the provided header ID that conform to the provided
|
|
|
|
// filter parameters and correspond to the provided tx ids
|
2022-03-10 12:35:19 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveRctCIDsByHeaderID(tx *sqlx.Tx, rctFilter ReceiptFilter, headerID string, trxHashes []string) ([]models.ReceiptModel, error) {
|
2021-08-14 13:50:22 +00:00
|
|
|
log.Debug("retrieving receipt cids for header id ", headerID)
|
|
|
|
args := make([]interface{}, 0, 4)
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr := `SELECT receipt_cids.tx_id, receipt_cids.leaf_cid, receipt_cids.leaf_mh_key,
|
2021-08-14 13:50:22 +00:00
|
|
|
receipt_cids.contract, receipt_cids.contract_hash
|
|
|
|
FROM eth.receipt_cids, eth.transaction_cids, eth.header_cids
|
2022-03-10 12:35:19 +00:00
|
|
|
WHERE receipt_cids.tx_id = transaction_cids.tx_hash
|
|
|
|
AND transaction_cids.header_id = header_cids.block_hash
|
|
|
|
AND header_cids.block_hash = $1`
|
2021-08-14 13:50:22 +00:00
|
|
|
id := 2
|
|
|
|
args = append(args, headerID)
|
2021-08-31 11:32:01 +00:00
|
|
|
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr, args = receiptFilterConditions(&id, pgStr, args, rctFilter, trxHashes)
|
2021-08-14 13:50:22 +00:00
|
|
|
|
2020-02-23 23:14:29 +00:00
|
|
|
pgStr += ` ORDER BY transaction_cids.index`
|
2021-08-12 06:23:41 +00:00
|
|
|
receiptCids := make([]models.ReceiptModel, 0)
|
2020-02-23 23:14:29 +00:00
|
|
|
return receiptCids, tx.Select(&receiptCids, pgStr, args...)
|
|
|
|
}
|
|
|
|
|
2021-08-20 07:37:11 +00:00
|
|
|
// RetrieveFilteredGQLLogs retrieves and returns all the log cIDs provided blockHash that conform to the provided
|
|
|
|
// filter parameters.
|
2021-09-01 07:02:28 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveFilteredGQLLogs(tx *sqlx.Tx, rctFilter ReceiptFilter, blockHash *common.Hash) ([]LogResult, error) {
|
2021-08-20 07:37:11 +00:00
|
|
|
log.Debug("retrieving log cids for receipt ids")
|
|
|
|
args := make([]interface{}, 0, 4)
|
|
|
|
id := 1
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr := `SELECT eth.log_cids.leaf_cid, eth.log_cids.index, eth.log_cids.rct_id,
|
2022-03-10 09:53:03 +00:00
|
|
|
eth.log_cids.address, eth.log_cids.topic0, eth.log_cids.topic1, eth.log_cids.topic2, eth.log_cids.topic3,
|
2021-09-16 13:45:56 +00:00
|
|
|
eth.log_cids.log_data, eth.transaction_cids.tx_hash, data, eth.receipt_cids.leaf_cid as cid, eth.receipt_cids.post_status
|
2021-08-20 07:37:11 +00:00
|
|
|
FROM eth.log_cids, eth.receipt_cids, eth.transaction_cids, eth.header_cids, public.blocks
|
2022-03-10 12:35:19 +00:00
|
|
|
WHERE eth.log_cids.rct_id = receipt_cids.tx_id
|
|
|
|
AND receipt_cids.tx_id = transaction_cids.tx_hash
|
|
|
|
AND transaction_cids.header_id = header_cids.block_hash
|
2021-09-20 10:31:27 +00:00
|
|
|
AND log_cids.leaf_mh_key = blocks.key AND header_cids.block_hash = $1`
|
2021-08-20 07:37:11 +00:00
|
|
|
|
|
|
|
args = append(args, blockHash.String())
|
|
|
|
id++
|
|
|
|
|
2021-08-31 11:32:01 +00:00
|
|
|
pgStr, args = logFilterCondition(&id, pgStr, args, rctFilter)
|
2021-08-20 07:37:11 +00:00
|
|
|
pgStr += ` ORDER BY log_cids.index`
|
|
|
|
|
2021-09-01 07:02:28 +00:00
|
|
|
logCIDs := make([]LogResult, 0)
|
2021-08-20 07:37:11 +00:00
|
|
|
err := tx.Select(&logCIDs, pgStr, args...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return logCIDs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RetrieveFilteredLog retrieves and returns all the log cIDs provided blockHeight or blockHash that conform to the provided
|
|
|
|
// filter parameters.
|
2021-09-01 07:02:28 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveFilteredLog(tx *sqlx.Tx, rctFilter ReceiptFilter, blockNumber int64, blockHash *common.Hash) ([]LogResult, error) {
|
2021-08-20 07:37:11 +00:00
|
|
|
log.Debug("retrieving log cids for receipt ids")
|
|
|
|
args := make([]interface{}, 0, 4)
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr := `SELECT eth.log_cids.leaf_cid, eth.log_cids.index, eth.log_cids.rct_id,
|
2022-03-10 09:53:03 +00:00
|
|
|
eth.log_cids.address, eth.log_cids.topic0, eth.log_cids.topic1, eth.log_cids.topic2, eth.log_cids.topic3,
|
|
|
|
eth.log_cids.log_data, eth.transaction_cids.tx_hash, eth.transaction_cids.index as txn_index,
|
2022-03-10 12:35:19 +00:00
|
|
|
header_cids.block_hash, CAST(header_cids.block_number as Text)
|
|
|
|
FROM eth.log_cids, eth.receipt_cids, eth.transaction_cids, eth.header_cids
|
|
|
|
WHERE eth.log_cids.rct_id = receipt_cids.tx_id
|
|
|
|
AND receipt_cids.tx_id = transaction_cids.tx_hash
|
|
|
|
AND transaction_cids.header_id = header_cids.block_hash`
|
2021-08-20 07:37:11 +00:00
|
|
|
id := 1
|
|
|
|
if blockNumber > 0 {
|
|
|
|
pgStr += fmt.Sprintf(` AND header_cids.block_number = $%d`, id)
|
|
|
|
args = append(args, blockNumber)
|
|
|
|
id++
|
|
|
|
}
|
|
|
|
if blockHash != nil {
|
|
|
|
pgStr += fmt.Sprintf(` AND header_cids.block_hash = $%d`, id)
|
|
|
|
args = append(args, blockHash.String())
|
|
|
|
id++
|
|
|
|
}
|
|
|
|
|
2021-08-31 11:32:01 +00:00
|
|
|
pgStr, args = logFilterCondition(&id, pgStr, args, rctFilter)
|
2021-08-20 07:37:11 +00:00
|
|
|
pgStr += ` ORDER BY log_cids.index`
|
|
|
|
|
2021-09-01 07:02:28 +00:00
|
|
|
logCIDs := make([]LogResult, 0)
|
2021-08-20 07:37:11 +00:00
|
|
|
err := tx.Select(&logCIDs, pgStr, args...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return logCIDs, nil
|
|
|
|
}
|
|
|
|
|
2021-09-15 11:43:12 +00:00
|
|
|
// RetrieveRctCIDs retrieves and returns all of the rct cids at the provided blockheight or block hash that conform to the provided
|
2020-01-16 20:48:38 +00:00
|
|
|
// filter parameters and correspond to the provided tx ids
|
2022-03-10 12:35:19 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveRctCIDs(tx *sqlx.Tx, rctFilter ReceiptFilter, blockNumber int64, blockHash *common.Hash, txHashes []string) ([]models.ReceiptModel, error) {
|
2019-06-07 16:01:29 +00:00
|
|
|
log.Debug("retrieving receipt cids for block ", blockNumber)
|
2020-02-23 23:14:29 +00:00
|
|
|
args := make([]interface{}, 0, 5)
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr := `SELECT receipt_cids.tx_id, receipt_cids.leaf_cid, receipt_cids.leaf_mh_key, receipt_cids.tx_id
|
2020-01-31 19:25:15 +00:00
|
|
|
FROM eth.receipt_cids, eth.transaction_cids, eth.header_cids
|
2022-03-10 12:35:19 +00:00
|
|
|
WHERE receipt_cids.tx_id = transaction_cids.tx_hash
|
|
|
|
AND transaction_cids.header_id = header_cids.block_hash`
|
2020-02-23 23:14:29 +00:00
|
|
|
id := 1
|
2020-01-21 19:12:35 +00:00
|
|
|
if blockNumber > 0 {
|
|
|
|
pgStr += fmt.Sprintf(` AND header_cids.block_number = $%d`, id)
|
|
|
|
args = append(args, blockNumber)
|
|
|
|
id++
|
|
|
|
}
|
|
|
|
if blockHash != nil {
|
|
|
|
pgStr += fmt.Sprintf(` AND header_cids.block_hash = $%d`, id)
|
|
|
|
args = append(args, blockHash.String())
|
|
|
|
id++
|
|
|
|
}
|
2021-06-09 03:42:46 +00:00
|
|
|
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr, args = receiptFilterConditions(&id, pgStr, args, rctFilter, txHashes)
|
2021-06-09 03:42:46 +00:00
|
|
|
|
2020-02-20 22:13:19 +00:00
|
|
|
pgStr += ` ORDER BY transaction_cids.index`
|
2021-08-12 06:23:41 +00:00
|
|
|
receiptCids := make([]models.ReceiptModel, 0)
|
2020-01-21 19:12:35 +00:00
|
|
|
return receiptCids, tx.Select(&receiptCids, pgStr, args...)
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
|
|
|
|
2020-02-20 22:13:19 +00:00
|
|
|
func hasTopics(topics [][]string) bool {
|
|
|
|
for _, topicSet := range topics {
|
|
|
|
if len(topicSet) > 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-02-23 23:14:29 +00:00
|
|
|
// RetrieveStateCIDs retrieves and returns all of the state node cids at the provided header ID that conform to the provided filter parameters
|
2022-03-10 12:35:19 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveStateCIDs(tx *sqlx.Tx, stateFilter StateFilter, headerID string) ([]models.StateNodeModel, error) {
|
2020-02-23 23:14:29 +00:00
|
|
|
log.Debug("retrieving state cids for header id ", headerID)
|
2019-05-21 19:27:24 +00:00
|
|
|
args := make([]interface{}, 0, 2)
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr := `SELECT state_cids.header_id,
|
2020-08-05 03:34:49 +00:00
|
|
|
state_cids.state_leaf_key, state_cids.node_type, state_cids.cid, state_cids.mh_key, state_cids.state_path
|
2022-03-10 12:35:19 +00:00
|
|
|
FROM eth.state_cids INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.block_hash)
|
|
|
|
WHERE header_cids.block_hash = $1`
|
2020-02-23 23:14:29 +00:00
|
|
|
args = append(args, headerID)
|
2020-01-16 20:48:38 +00:00
|
|
|
addrLen := len(stateFilter.Addresses)
|
2019-05-21 19:27:24 +00:00
|
|
|
if addrLen > 0 {
|
2020-01-21 19:12:35 +00:00
|
|
|
keys := make([]string, addrLen)
|
|
|
|
for i, addr := range stateFilter.Addresses {
|
|
|
|
keys[i] = crypto.Keccak256Hash(common.HexToAddress(addr).Bytes()).String()
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2020-03-26 00:16:12 +00:00
|
|
|
pgStr += ` AND state_cids.state_leaf_key = ANY($2::VARCHAR(66)[])`
|
2019-05-21 19:27:24 +00:00
|
|
|
args = append(args, pq.Array(keys))
|
|
|
|
}
|
2020-01-16 20:48:38 +00:00
|
|
|
if !stateFilter.IntermediateNodes {
|
2020-03-11 18:41:59 +00:00
|
|
|
pgStr += ` AND state_cids.node_type = 2`
|
2019-06-07 13:42:10 +00:00
|
|
|
}
|
2021-08-12 06:23:41 +00:00
|
|
|
stateNodeCIDs := make([]models.StateNodeModel, 0)
|
2020-01-21 19:12:35 +00:00
|
|
|
return stateNodeCIDs, tx.Select(&stateNodeCIDs, pgStr, args...)
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
|
|
|
|
2020-02-23 23:14:29 +00:00
|
|
|
// RetrieveStorageCIDs retrieves and returns all of the storage node cids at the provided header id that conform to the provided filter parameters
|
2022-03-10 12:35:19 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveStorageCIDs(tx *sqlx.Tx, storageFilter StorageFilter, headerID string) ([]models.StorageNodeWithStateKeyModel, error) {
|
2020-02-23 23:14:29 +00:00
|
|
|
log.Debug("retrieving storage cids for header id ", headerID)
|
2019-05-21 19:27:24 +00:00
|
|
|
args := make([]interface{}, 0, 3)
|
2022-03-10 12:35:19 +00:00
|
|
|
pgStr := `SELECT storage_cids.header_id, storage_cids.storage_leaf_key, storage_cids.node_type,
|
|
|
|
storage_cids.cid, storage_cids.mh_key, storage_cids.storage_path, storage_cids.state_path, state_cids.state_leaf_key
|
2020-03-11 18:41:59 +00:00
|
|
|
FROM eth.storage_cids, eth.state_cids, eth.header_cids
|
2022-03-10 12:35:19 +00:00
|
|
|
WHERE storage_cids.header_id = state_cids.header_id AND storage_cids.state_path = state_cids.state_path
|
|
|
|
AND state_cids.header_id = header_cids.block_hash
|
|
|
|
AND header_cids.block_hash = $1`
|
2020-02-23 23:14:29 +00:00
|
|
|
args = append(args, headerID)
|
|
|
|
id := 2
|
2020-01-16 20:48:38 +00:00
|
|
|
addrLen := len(storageFilter.Addresses)
|
2019-05-21 19:27:24 +00:00
|
|
|
if addrLen > 0 {
|
2020-01-21 19:12:35 +00:00
|
|
|
keys := make([]string, addrLen)
|
|
|
|
for i, addr := range storageFilter.Addresses {
|
|
|
|
keys[i] = crypto.Keccak256Hash(common.HexToAddress(addr).Bytes()).String()
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2020-03-26 00:16:12 +00:00
|
|
|
pgStr += fmt.Sprintf(` AND state_cids.state_leaf_key = ANY($%d::VARCHAR(66)[])`, id)
|
2019-05-21 19:27:24 +00:00
|
|
|
args = append(args, pq.Array(keys))
|
2020-02-09 21:28:30 +00:00
|
|
|
id++
|
|
|
|
}
|
|
|
|
if len(storageFilter.StorageKeys) > 0 {
|
2020-03-26 00:16:12 +00:00
|
|
|
pgStr += fmt.Sprintf(` AND storage_cids.storage_leaf_key = ANY($%d::VARCHAR(66)[])`, id)
|
2020-01-16 20:48:38 +00:00
|
|
|
args = append(args, pq.Array(storageFilter.StorageKeys))
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2020-01-16 20:48:38 +00:00
|
|
|
if !storageFilter.IntermediateNodes {
|
2020-03-11 18:41:59 +00:00
|
|
|
pgStr += ` AND storage_cids.node_type = 2`
|
2019-06-07 13:42:10 +00:00
|
|
|
}
|
2021-08-12 06:23:41 +00:00
|
|
|
storageNodeCIDs := make([]models.StorageNodeWithStateKeyModel, 0)
|
2020-01-21 19:12:35 +00:00
|
|
|
return storageNodeCIDs, tx.Select(&storageNodeCIDs, pgStr, args...)
|
2019-05-21 19:27:24 +00:00
|
|
|
}
|
2019-10-02 14:10:37 +00:00
|
|
|
|
2020-01-26 19:55:26 +00:00
|
|
|
// RetrieveBlockByHash returns all of the CIDs needed to compose an entire block, for a given block hash
|
2021-08-12 06:23:41 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveBlockByHash(blockHash common.Hash) (models.HeaderModel, []models.UncleModel, []models.TxModel, []models.ReceiptModel, error) {
|
2020-01-26 19:55:26 +00:00
|
|
|
log.Debug("retrieving block cids for block hash ", blockHash.String())
|
2020-05-01 21:25:58 +00:00
|
|
|
|
|
|
|
// Begin new db tx
|
2020-01-26 19:55:26 +00:00
|
|
|
tx, err := ecr.db.Beginx()
|
|
|
|
if err != nil {
|
2021-08-12 06:23:41 +00:00
|
|
|
return models.HeaderModel{}, nil, nil, nil, err
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
2020-05-01 21:25:58 +00:00
|
|
|
defer func() {
|
|
|
|
if p := recover(); p != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
panic(p)
|
|
|
|
} else if err != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
} else {
|
|
|
|
err = tx.Commit()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-08-12 06:23:41 +00:00
|
|
|
var headerCID models.HeaderModel
|
2021-04-19 13:42:09 +00:00
|
|
|
headerCID, err = ecr.RetrieveHeaderCIDByHash(tx, blockHash)
|
2020-01-26 19:55:26 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("header cid retrieval error")
|
2021-08-12 06:23:41 +00:00
|
|
|
return models.HeaderModel{}, nil, nil, nil, err
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
2021-08-12 06:23:41 +00:00
|
|
|
var uncleCIDs []models.UncleModel
|
2022-03-10 12:35:19 +00:00
|
|
|
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, headerCID.BlockHash)
|
2020-01-26 19:55:26 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("uncle cid retrieval error")
|
2021-08-12 06:23:41 +00:00
|
|
|
return models.HeaderModel{}, nil, nil, nil, err
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
2021-08-12 06:23:41 +00:00
|
|
|
var txCIDs []models.TxModel
|
2022-03-10 12:35:19 +00:00
|
|
|
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID.BlockHash)
|
2020-01-26 19:55:26 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("tx cid retrieval error")
|
2021-08-12 06:23:41 +00:00
|
|
|
return models.HeaderModel{}, nil, nil, nil, err
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
2022-03-10 12:35:19 +00:00
|
|
|
txHashes := make([]string, len(txCIDs))
|
2020-01-26 19:55:26 +00:00
|
|
|
for i, txCID := range txCIDs {
|
2022-03-10 12:35:19 +00:00
|
|
|
txHashes[i] = txCID.TxHash
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
2021-08-12 06:23:41 +00:00
|
|
|
var rctCIDs []models.ReceiptModel
|
2022-03-10 12:35:19 +00:00
|
|
|
rctCIDs, err = ecr.RetrieveReceiptCIDsByTxIDs(tx, txHashes)
|
2020-01-26 19:55:26 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("rct cid retrieval error")
|
|
|
|
}
|
2020-05-01 21:25:58 +00:00
|
|
|
return headerCID, uncleCIDs, txCIDs, rctCIDs, err
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// RetrieveBlockByNumber returns all of the CIDs needed to compose an entire block, for a given block number
|
2021-08-12 06:23:41 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (models.HeaderModel, []models.UncleModel, []models.TxModel, []models.ReceiptModel, error) {
|
2020-01-26 19:55:26 +00:00
|
|
|
log.Debug("retrieving block cids for block number ", blockNumber)
|
2020-05-01 21:25:58 +00:00
|
|
|
|
|
|
|
// Begin new db tx
|
2020-01-26 19:55:26 +00:00
|
|
|
tx, err := ecr.db.Beginx()
|
|
|
|
if err != nil {
|
2021-08-12 06:23:41 +00:00
|
|
|
return models.HeaderModel{}, nil, nil, nil, err
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
2020-05-01 21:25:58 +00:00
|
|
|
defer func() {
|
|
|
|
if p := recover(); p != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
panic(p)
|
|
|
|
} else if err != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
} else {
|
|
|
|
err = tx.Commit()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-08-12 06:23:41 +00:00
|
|
|
var headerCID []models.HeaderModel
|
2021-04-19 13:42:09 +00:00
|
|
|
headerCID, err = ecr.RetrieveHeaderCIDs(tx, blockNumber)
|
2020-01-26 19:55:26 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("header cid retrieval error")
|
2021-08-12 06:23:41 +00:00
|
|
|
return models.HeaderModel{}, nil, nil, nil, err
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
|
|
|
if len(headerCID) < 1 {
|
2021-08-12 06:23:41 +00:00
|
|
|
return models.HeaderModel{}, nil, nil, nil, fmt.Errorf("header cid retrieval error, no header CIDs found at block %d", blockNumber)
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
2021-08-12 06:23:41 +00:00
|
|
|
var uncleCIDs []models.UncleModel
|
2022-03-10 12:35:19 +00:00
|
|
|
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, headerCID[0].BlockHash)
|
2020-01-26 19:55:26 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("uncle cid retrieval error")
|
2021-08-12 06:23:41 +00:00
|
|
|
return models.HeaderModel{}, nil, nil, nil, err
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
2021-08-12 06:23:41 +00:00
|
|
|
var txCIDs []models.TxModel
|
2022-03-10 12:35:19 +00:00
|
|
|
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID[0].BlockHash)
|
2020-01-26 19:55:26 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("tx cid retrieval error")
|
2021-08-12 06:23:41 +00:00
|
|
|
return models.HeaderModel{}, nil, nil, nil, err
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
2022-03-10 12:35:19 +00:00
|
|
|
txHashes := make([]string, len(txCIDs))
|
2020-01-26 19:55:26 +00:00
|
|
|
for i, txCID := range txCIDs {
|
2022-03-10 12:35:19 +00:00
|
|
|
txHashes[i] = txCID.TxHash
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
2021-08-12 06:23:41 +00:00
|
|
|
var rctCIDs []models.ReceiptModel
|
2022-03-10 12:35:19 +00:00
|
|
|
rctCIDs, err = ecr.RetrieveReceiptCIDsByTxIDs(tx, txHashes)
|
2020-01-26 19:55:26 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("rct cid retrieval error")
|
|
|
|
}
|
2020-05-01 21:25:58 +00:00
|
|
|
return headerCID[0], uncleCIDs, txCIDs, rctCIDs, err
|
2020-01-26 19:55:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// RetrieveHeaderCIDByHash returns the header for the given block hash
|
2021-08-12 06:23:41 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveHeaderCIDByHash(tx *sqlx.Tx, blockHash common.Hash) (models.HeaderModel, error) {
|
2020-01-26 19:55:26 +00:00
|
|
|
log.Debug("retrieving header cids for block hash ", blockHash.String())
|
2022-05-30 14:11:03 +00:00
|
|
|
pgStr := `SELECT block_hash, CAST(block_number as Text), parent_hash, cid, mh_key, CAST(td as Text),
|
|
|
|
state_root,uncle_root,tx_root,receipt_root,bloom,timestamp FROM eth.header_cids
|
2020-01-26 19:55:26 +00:00
|
|
|
WHERE block_hash = $1`
|
2021-08-12 06:23:41 +00:00
|
|
|
var headerCID models.HeaderModel
|
2020-01-26 19:55:26 +00:00
|
|
|
return headerCID, tx.Get(&headerCID, pgStr, blockHash.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
// RetrieveTxCIDsByHeaderID retrieves all tx CIDs for the given header id
|
2022-03-10 12:35:19 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveTxCIDsByHeaderID(tx *sqlx.Tx, headerID string) ([]models.TxModel, error) {
|
2020-01-26 19:55:26 +00:00
|
|
|
log.Debug("retrieving tx cids for block id ", headerID)
|
2020-01-31 19:25:15 +00:00
|
|
|
pgStr := `SELECT * FROM eth.transaction_cids
|
2020-02-20 22:13:19 +00:00
|
|
|
WHERE header_id = $1
|
|
|
|
ORDER BY index`
|
2021-08-12 06:23:41 +00:00
|
|
|
var txCIDs []models.TxModel
|
2020-01-26 19:55:26 +00:00
|
|
|
return txCIDs, tx.Select(&txCIDs, pgStr, headerID)
|
|
|
|
}
|
|
|
|
|
2022-05-30 14:11:03 +00:00
|
|
|
// RetrieveTxCIDsByHeaderIDs retrieves all tx CIDs for the given headerIDs
|
|
|
|
func (ecr *CIDRetriever) RetrieveTxCIDsByHeaderIDs(tx *sqlx.Tx, headerIDs []string) ([]models.TxModel, error) {
|
|
|
|
log.Debug("retrieving tx cids for headerIDs ", headerIDs)
|
|
|
|
pgStr := `SELECT header_id, index, tx_hash, cid, mh_key,
|
2022-05-27 13:46:10 +00:00
|
|
|
dst, src, tx_data, tx_type, value
|
|
|
|
FROM eth.transaction_cids
|
2022-05-30 14:11:03 +00:00
|
|
|
WHERE header_id in (?)
|
2022-05-27 13:46:10 +00:00
|
|
|
ORDER BY index`
|
2022-05-30 14:11:03 +00:00
|
|
|
|
2022-05-27 13:46:10 +00:00
|
|
|
var txCIDs []models.TxModel
|
2022-05-30 14:11:03 +00:00
|
|
|
if len(headerIDs) < 1 {
|
|
|
|
return txCIDs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
query, args, err := sqlx.In(pgStr, headerIDs)
|
|
|
|
if err != nil {
|
|
|
|
return txCIDs, err
|
|
|
|
}
|
|
|
|
query = tx.Rebind(query)
|
|
|
|
|
|
|
|
return txCIDs, tx.Select(&txCIDs, query, args...)
|
2022-05-27 13:46:10 +00:00
|
|
|
}
|
|
|
|
|
2020-01-26 19:55:26 +00:00
|
|
|
// RetrieveReceiptCIDsByTxIDs retrieves receipt CIDs by their associated tx IDs
|
2022-03-10 12:35:19 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveReceiptCIDsByTxIDs(tx *sqlx.Tx, txHashes []string) ([]models.ReceiptModel, error) {
|
|
|
|
log.Debugf("retrieving receipt cids for tx hashes %v", txHashes)
|
|
|
|
pgStr := `SELECT receipt_cids.tx_id, receipt_cids.leaf_cid, receipt_cids.leaf_mh_key,
|
2021-08-14 13:50:22 +00:00
|
|
|
receipt_cids.contract, receipt_cids.contract_hash
|
2020-02-20 22:13:19 +00:00
|
|
|
FROM eth.receipt_cids, eth.transaction_cids
|
2022-03-10 12:35:19 +00:00
|
|
|
WHERE tx_id = ANY($1)
|
|
|
|
AND receipt_cids.tx_id = transaction_cids.tx_hash
|
2020-02-20 22:13:19 +00:00
|
|
|
ORDER BY transaction_cids.index`
|
2021-08-12 06:23:41 +00:00
|
|
|
var rctCIDs []models.ReceiptModel
|
2022-03-10 12:35:19 +00:00
|
|
|
return rctCIDs, tx.Select(&rctCIDs, pgStr, pq.Array(txHashes))
|
2020-01-16 20:48:38 +00:00
|
|
|
}
|
2022-05-25 13:13:53 +00:00
|
|
|
|
2022-05-30 06:31:27 +00:00
|
|
|
// RetrieveHeaderAndTxCIDsByBlockNumber retrieves header CIDs and their associated tx CIDs by block number
|
2022-05-25 13:13:53 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveHeaderAndTxCIDsByBlockNumber(blockNumber int64) ([]models.HeaderModel, [][]models.TxModel, error) {
|
|
|
|
log.Debug("retrieving header cids and tx cids for block number ", blockNumber)
|
|
|
|
|
|
|
|
// Begin new db tx
|
|
|
|
tx, err := ecr.db.Beginx()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if p := recover(); p != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
panic(p)
|
|
|
|
} else if err != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
} else {
|
|
|
|
err = tx.Commit()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
var headerCIDs []models.HeaderModel
|
|
|
|
headerCIDs, err = ecr.RetrieveHeaderCIDs(tx, blockNumber)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("header cid retrieval error")
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var allTxCIDs [][]models.TxModel
|
2022-05-30 14:11:03 +00:00
|
|
|
txHeaderIDs := funk.Map(
|
|
|
|
headerCIDs,
|
|
|
|
func(headerCID models.HeaderModel) string {
|
|
|
|
return headerCID.BlockHash
|
|
|
|
},
|
|
|
|
)
|
|
|
|
txCIDs, err := ecr.RetrieveTxCIDsByHeaderIDs(tx, txHeaderIDs.([]string))
|
2022-05-27 13:46:10 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("tx cid retrieval error")
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
txCIDsByHeaderID := funk.Reduce(
|
|
|
|
txCIDs,
|
|
|
|
func(acc map[string][]models.TxModel, txCID models.TxModel) map[string][]models.TxModel {
|
|
|
|
if _, ok := acc[txCID.HeaderID]; !ok {
|
|
|
|
acc[txCID.HeaderID] = []models.TxModel{}
|
|
|
|
}
|
|
|
|
|
|
|
|
txCIDs = append(acc[txCID.HeaderID], txCID)
|
|
|
|
acc[txCID.HeaderID] = txCIDs
|
|
|
|
return acc
|
|
|
|
},
|
|
|
|
make(map[string][]models.TxModel),
|
|
|
|
)
|
|
|
|
|
|
|
|
txCIDsByHeaderIDMap := txCIDsByHeaderID.(map[string][]models.TxModel)
|
|
|
|
|
2022-05-25 13:13:53 +00:00
|
|
|
for _, headerCID := range headerCIDs {
|
2022-05-27 13:46:10 +00:00
|
|
|
txCIDs := txCIDsByHeaderIDMap[headerCID.BlockHash]
|
2022-05-25 13:13:53 +00:00
|
|
|
allTxCIDs = append(allTxCIDs, txCIDs)
|
|
|
|
}
|
|
|
|
|
|
|
|
return headerCIDs, allTxCIDs, nil
|
|
|
|
}
|
|
|
|
|
2022-05-30 06:31:27 +00:00
|
|
|
// RetrieveHeaderAndTxCIDsByBlockHash retrieves header CID and their associated tx CIDs by block hash
|
2022-05-25 13:13:53 +00:00
|
|
|
func (ecr *CIDRetriever) RetrieveHeaderAndTxCIDsByBlockHash(blockHash common.Hash) (models.HeaderModel, []models.TxModel, error) {
|
|
|
|
log.Debug("retrieving header cid and tx cids for block hash ", blockHash.String())
|
|
|
|
|
|
|
|
// Begin new db tx
|
|
|
|
tx, err := ecr.db.Beginx()
|
|
|
|
if err != nil {
|
|
|
|
return models.HeaderModel{}, nil, err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if p := recover(); p != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
panic(p)
|
|
|
|
} else if err != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
} else {
|
|
|
|
err = tx.Commit()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
var headerCID models.HeaderModel
|
|
|
|
headerCID, err = ecr.RetrieveHeaderCIDByHash(tx, blockHash)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("header cid retrieval error")
|
|
|
|
return models.HeaderModel{}, nil, err
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return models.HeaderModel{}, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var txCIDs []models.TxModel
|
|
|
|
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID.BlockHash)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("tx cid retrieval error")
|
|
|
|
return models.HeaderModel{}, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return headerCID, txCIDs, nil
|
|
|
|
}
|
2022-05-30 06:31:27 +00:00
|
|
|
|
|
|
|
// RetrieveTxCIDByHash returns the tx for the given tx hash
|
|
|
|
func (ecr *CIDRetriever) RetrieveTxCIDByHash(txHash string) (models.TxModel, error) {
|
|
|
|
log.Debug("retrieving tx cid for tx hash ", txHash)
|
|
|
|
|
|
|
|
// Begin new db tx
|
|
|
|
tx, err := ecr.db.Beginx()
|
|
|
|
if err != nil {
|
|
|
|
return models.TxModel{}, err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if p := recover(); p != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
panic(p)
|
|
|
|
} else if err != nil {
|
|
|
|
shared.Rollback(tx)
|
|
|
|
} else {
|
|
|
|
err = tx.Commit()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2022-05-30 14:11:03 +00:00
|
|
|
pgStr := `SELECT header_id, index, tx_hash, cid, mh_key,
|
2022-05-30 06:31:27 +00:00
|
|
|
dst, src, tx_data, tx_type, value
|
|
|
|
FROM eth.transaction_cids
|
|
|
|
WHERE tx_hash = $1
|
|
|
|
ORDER BY index`
|
|
|
|
var txCID models.TxModel
|
|
|
|
return txCID, tx.Get(&txCID, pgStr, txHash)
|
|
|
|
}
|