2022-10-06 19:06:03 +00:00
|
|
|
package devnetutils
|
2022-09-30 20:04:34 +00:00
|
|
|
|
|
|
|
import (
|
2023-03-02 10:25:11 +00:00
|
|
|
"crypto/rand"
|
2022-10-11 12:34:32 +00:00
|
|
|
"encoding/json"
|
2022-09-30 20:04:34 +00:00
|
|
|
"fmt"
|
2023-03-07 04:19:00 +00:00
|
|
|
"math/big"
|
2023-05-15 14:30:56 +00:00
|
|
|
"os"
|
2023-05-21 14:33:11 +00:00
|
|
|
"path/filepath"
|
2023-03-07 04:19:00 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
2023-01-13 18:12:18 +00:00
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
2023-04-13 11:19:02 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/common/hexutility"
|
|
|
|
|
2023-05-31 18:47:32 +00:00
|
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/models"
|
2023-01-10 17:43:58 +00:00
|
|
|
"github.com/ledgerwatch/erigon/common/hexutil"
|
|
|
|
"github.com/ledgerwatch/erigon/crypto"
|
2023-05-15 14:30:56 +00:00
|
|
|
"github.com/ledgerwatch/log/v3"
|
2022-09-30 20:04:34 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ClearDevDB cleans up the dev folder used for the operations
|
2023-05-15 14:30:56 +00:00
|
|
|
func ClearDevDB(dataDir string, logger log.Logger) error {
|
2023-05-31 19:29:36 +00:00
|
|
|
logger.Info("Deleting nodes' data folders")
|
2022-09-30 20:04:34 +00:00
|
|
|
|
2023-05-21 14:33:11 +00:00
|
|
|
nodeNumber := 1
|
|
|
|
for {
|
|
|
|
nodeDataDir := filepath.Join(dataDir, fmt.Sprintf("%d", nodeNumber))
|
|
|
|
fileInfo, err := os.Stat(nodeDataDir)
|
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if fileInfo.IsDir() {
|
2023-05-31 19:29:36 +00:00
|
|
|
if err := os.RemoveAll(nodeDataDir); err != nil {
|
2023-05-21 14:33:11 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
logger.Info("SUCCESS => Deleted", "datadir", nodeDataDir)
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
nodeNumber++
|
2022-09-30 20:04:34 +00:00
|
|
|
}
|
2023-05-15 14:30:56 +00:00
|
|
|
return nil
|
2022-10-06 19:06:03 +00:00
|
|
|
}
|
|
|
|
|
2022-09-30 20:04:34 +00:00
|
|
|
// UniqueIDFromEnode returns the unique ID from a node's enode, removing the `?discport=0` part
|
|
|
|
func UniqueIDFromEnode(enode string) (string, error) {
|
|
|
|
if len(enode) == 0 {
|
|
|
|
return "", fmt.Errorf("invalid enode string")
|
|
|
|
}
|
|
|
|
|
|
|
|
// iterate through characters in the string until we reach '?'
|
|
|
|
// using index iteration because enode characters have single codepoints
|
|
|
|
var i int
|
|
|
|
for i < len(enode) && enode[i] != byte('?') {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
// if '?' is not found in the enode, return an error
|
|
|
|
if i == len(enode) {
|
|
|
|
return "", fmt.Errorf("invalid enode string")
|
|
|
|
}
|
|
|
|
|
|
|
|
return enode[:i], nil
|
|
|
|
}
|
2022-10-11 12:34:32 +00:00
|
|
|
|
2023-05-31 18:47:32 +00:00
|
|
|
// ParseResponse converts any of the models interfaces to a string for readability
|
2022-10-11 12:34:32 +00:00
|
|
|
func ParseResponse(resp interface{}) (string, error) {
|
|
|
|
result, err := json.Marshal(resp)
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("error trying to marshal response: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(result), nil
|
|
|
|
}
|
2022-11-03 02:45:36 +00:00
|
|
|
|
|
|
|
// HexToInt converts a hexadecimal string to uint64
|
|
|
|
func HexToInt(hexStr string) uint64 {
|
|
|
|
cleaned := strings.ReplaceAll(hexStr, "0x", "") // remove the 0x prefix
|
|
|
|
result, _ := strconv.ParseUint(cleaned, 16, 64)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
// NamespaceAndSubMethodFromMethod splits a parent method into namespace and the actual method
|
|
|
|
func NamespaceAndSubMethodFromMethod(method string) (string, string, error) {
|
|
|
|
parts := strings.SplitN(method, "_", 2)
|
|
|
|
if len(parts) != 2 {
|
|
|
|
return "", "", fmt.Errorf("invalid string to split")
|
|
|
|
}
|
|
|
|
return parts[0], parts[1], nil
|
|
|
|
}
|
2023-01-10 17:43:58 +00:00
|
|
|
|
2023-01-13 18:12:18 +00:00
|
|
|
func HashSlicesAreEqual(s1, s2 []libcommon.Hash) bool {
|
2023-01-10 17:43:58 +00:00
|
|
|
if len(s1) != len(s2) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < len(s1); i++ {
|
|
|
|
if s1[i] != s2[i] {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-05-31 18:47:32 +00:00
|
|
|
func BuildLog(hash libcommon.Hash, blockNum string, address libcommon.Address, topics []libcommon.Hash, data hexutility.Bytes, txIndex hexutil.Uint, blockHash libcommon.Hash, index hexutil.Uint, removed bool) models.Log {
|
|
|
|
return models.Log{
|
2023-01-10 17:43:58 +00:00
|
|
|
Address: address,
|
|
|
|
Topics: topics,
|
|
|
|
Data: data,
|
|
|
|
BlockNumber: hexutil.Uint64(HexToInt(blockNum)),
|
|
|
|
TxHash: hash,
|
|
|
|
TxIndex: txIndex,
|
|
|
|
BlockHash: blockHash,
|
|
|
|
Index: index,
|
|
|
|
Removed: removed,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-31 18:47:32 +00:00
|
|
|
func CompareLogEvents(expected, actual models.Log) ([]error, bool) {
|
2023-01-10 17:43:58 +00:00
|
|
|
var errs []error
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case expected.Address != actual.Address:
|
|
|
|
errs = append(errs, fmt.Errorf("expected address: %v, actual address %v", expected.Address, actual.Address))
|
|
|
|
case expected.TxHash != actual.TxHash:
|
|
|
|
errs = append(errs, fmt.Errorf("expected txhash: %v, actual txhash %v", expected.TxHash, actual.TxHash))
|
|
|
|
case expected.BlockHash != actual.BlockHash:
|
|
|
|
errs = append(errs, fmt.Errorf("expected blockHash: %v, actual blockHash %v", expected.BlockHash, actual.BlockHash))
|
|
|
|
case expected.BlockNumber != actual.BlockNumber:
|
|
|
|
errs = append(errs, fmt.Errorf("expected blockNumber: %v, actual blockNumber %v", expected.BlockNumber, actual.BlockNumber))
|
|
|
|
case expected.TxIndex != actual.TxIndex:
|
|
|
|
errs = append(errs, fmt.Errorf("expected txIndex: %v, actual txIndex %v", expected.TxIndex, actual.TxIndex))
|
|
|
|
case !HashSlicesAreEqual(expected.Topics, actual.Topics):
|
|
|
|
errs = append(errs, fmt.Errorf("expected topics: %v, actual topics %v", expected.Topics, actual.Topics))
|
|
|
|
}
|
|
|
|
|
|
|
|
return errs, len(errs) == 0
|
|
|
|
}
|
|
|
|
|
2023-01-13 18:12:18 +00:00
|
|
|
func GenerateTopic(signature string) []libcommon.Hash {
|
2023-01-10 17:43:58 +00:00
|
|
|
hashed := crypto.Keccak256([]byte(signature))
|
2023-01-13 18:12:18 +00:00
|
|
|
return []libcommon.Hash{libcommon.BytesToHash(hashed)}
|
2023-01-10 17:43:58 +00:00
|
|
|
}
|
2023-03-02 10:25:11 +00:00
|
|
|
|
|
|
|
// RandomNumberInRange returns a random number between min and max NOT inclusive
|
|
|
|
func RandomNumberInRange(min, max uint64) (uint64, error) {
|
2023-03-03 16:20:45 +00:00
|
|
|
if max <= min {
|
|
|
|
return 0, fmt.Errorf("Invalid range: upper bound %d less or equal than lower bound %d", max, min)
|
|
|
|
}
|
|
|
|
|
2023-03-02 10:25:11 +00:00
|
|
|
diff := int64(max - min)
|
|
|
|
|
|
|
|
n, err := rand.Int(rand.Reader, big.NewInt(diff))
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return uint64(n.Int64() + int64(min)), nil
|
|
|
|
}
|