2020-06-04 10:40:21 +00:00
|
|
|
package types
|
|
|
|
|
|
|
|
import (
|
2021-04-18 15:54:18 +00:00
|
|
|
"bytes"
|
2020-06-04 10:40:21 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
log "github.com/xlab/suplog"
|
|
|
|
|
2020-06-04 10:40:21 +00:00
|
|
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
|
|
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
2021-05-17 10:13:08 +00:00
|
|
|
|
|
|
|
ethermint "github.com/cosmos/ethermint/types"
|
2020-06-04 10:40:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// NewTransactionLogs creates a new NewTransactionLogs instance.
|
2021-04-17 10:00:07 +00:00
|
|
|
func NewTransactionLogs(hash ethcmn.Hash, logs []*Log) TransactionLogs { // nolint: interfacer
|
2020-06-04 10:40:21 +00:00
|
|
|
return TransactionLogs{
|
2021-01-06 20:56:40 +00:00
|
|
|
Hash: hash.String(),
|
2020-06-04 10:40:21 +00:00
|
|
|
Logs: logs,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
// NewTransactionLogsFromEth creates a new NewTransactionLogs instance using []*ethtypes.Log.
|
|
|
|
func NewTransactionLogsFromEth(hash ethcmn.Hash, ethlogs []*ethtypes.Log) TransactionLogs { // nolint: interfacer
|
|
|
|
logs := make([]*Log, len(ethlogs))
|
|
|
|
for i := range ethlogs {
|
|
|
|
logs[i] = NewLogFromEth(ethlogs[i])
|
|
|
|
}
|
2020-06-04 10:40:21 +00:00
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
return TransactionLogs{
|
|
|
|
Hash: hash.String(),
|
|
|
|
Logs: logs,
|
|
|
|
}
|
2020-06-04 10:40:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Validate performs a basic validation of a GenesisAccount fields.
|
|
|
|
func (tx TransactionLogs) Validate() error {
|
2021-04-18 15:54:18 +00:00
|
|
|
if bytes.Equal(ethcmn.Hex2Bytes(tx.Hash), ethcmn.Hash{}.Bytes()) {
|
2021-01-06 20:56:40 +00:00
|
|
|
return fmt.Errorf("hash cannot be the empty %s", tx.Hash)
|
2020-06-04 10:40:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for i, log := range tx.Logs {
|
2021-04-17 10:00:07 +00:00
|
|
|
if log == nil {
|
|
|
|
return fmt.Errorf("log %d cannot be nil", i)
|
|
|
|
}
|
|
|
|
if err := log.Validate(); err != nil {
|
2020-06-04 10:40:21 +00:00
|
|
|
return fmt.Errorf("invalid log %d: %w", i, err)
|
|
|
|
}
|
2021-04-17 10:00:07 +00:00
|
|
|
if log.TxHash != tx.Hash {
|
|
|
|
return fmt.Errorf("log tx hash mismatch (%s ≠ %s)", log.TxHash, tx.Hash)
|
2020-06-04 10:40:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
// EthLogs returns the Ethereum type Logs from the Transaction Logs.
|
|
|
|
func (tx TransactionLogs) EthLogs() []*ethtypes.Log {
|
|
|
|
return LogsToEthereum(tx.Logs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate performs a basic validation of an ethereum Log fields.
|
|
|
|
func (log *Log) Validate() error {
|
2021-05-17 10:13:08 +00:00
|
|
|
if err := ethermint.ValidateAddress(log.Address); err != nil {
|
|
|
|
return fmt.Errorf("invalid log address %w", err)
|
2020-06-04 10:40:21 +00:00
|
|
|
}
|
2021-05-17 10:13:08 +00:00
|
|
|
if ethermint.IsEmptyHash(log.BlockHash) {
|
2021-04-17 10:00:07 +00:00
|
|
|
return fmt.Errorf("block hash cannot be the empty %s", log.BlockHash)
|
2020-06-04 10:40:21 +00:00
|
|
|
}
|
|
|
|
if log.BlockNumber == 0 {
|
|
|
|
return errors.New("block number cannot be zero")
|
|
|
|
}
|
2021-05-17 10:13:08 +00:00
|
|
|
if ethermint.IsEmptyHash(log.TxHash) {
|
2021-04-17 10:00:07 +00:00
|
|
|
return fmt.Errorf("tx hash cannot be the empty %s", log.TxHash)
|
2020-06-04 10:40:21 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2021-04-17 10:00:07 +00:00
|
|
|
|
|
|
|
// ToEthereum returns the Ethereum type Log from a Ethermint-proto compatible Log.
|
|
|
|
func (log *Log) ToEthereum() *ethtypes.Log {
|
|
|
|
topics := make([]ethcmn.Hash, len(log.Topics))
|
|
|
|
for i := range log.Topics {
|
|
|
|
topics[i] = ethcmn.HexToHash(log.Topics[i])
|
|
|
|
}
|
|
|
|
|
|
|
|
return ðtypes.Log{
|
|
|
|
Address: ethcmn.HexToAddress(log.Address),
|
|
|
|
Topics: topics,
|
|
|
|
Data: log.Data,
|
|
|
|
BlockNumber: log.BlockNumber,
|
|
|
|
TxHash: ethcmn.HexToHash(log.TxHash),
|
|
|
|
TxIndex: uint(log.TxIndex),
|
2021-04-18 15:54:18 +00:00
|
|
|
Index: uint(log.Index),
|
2021-04-17 10:00:07 +00:00
|
|
|
BlockHash: ethcmn.HexToHash(log.BlockHash),
|
|
|
|
Removed: log.Removed,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// LogsToEthereum casts the Ethermint Logs to a slice of Ethereum Logs.
|
|
|
|
func LogsToEthereum(logs []*Log) []*ethtypes.Log {
|
|
|
|
ethLogs := make([]*ethtypes.Log, len(logs))
|
|
|
|
for i := range logs {
|
2021-04-18 15:54:18 +00:00
|
|
|
err := logs[i].Validate()
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Errorln("failed log validation", logs[i].String())
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
ethLogs[i] = logs[i].ToEthereum()
|
|
|
|
}
|
|
|
|
return ethLogs
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewLogFromEth creates a new Log instance from a Ethereum type Log.
|
|
|
|
func NewLogFromEth(log *ethtypes.Log) *Log {
|
|
|
|
topics := make([]string, len(log.Topics))
|
|
|
|
for i := range log.Topics {
|
|
|
|
topics[i] = log.Topics[i].String()
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Log{
|
|
|
|
Address: log.Address.String(),
|
|
|
|
Topics: topics,
|
|
|
|
Data: log.Data,
|
|
|
|
BlockNumber: log.BlockNumber,
|
|
|
|
TxHash: log.TxHash.String(),
|
|
|
|
TxIndex: uint64(log.TxIndex),
|
|
|
|
BlockHash: log.BlockHash.String(),
|
|
|
|
Removed: log.Removed,
|
|
|
|
}
|
|
|
|
}
|