Skip to content

Commit f59d805

Browse files
committed
more error message fixes
1 parent 94430b7 commit f59d805

File tree

9 files changed

+325
-136
lines changed

9 files changed

+325
-136
lines changed

seth/abi_finder.go

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package seth
22

33
import (
4-
"errors"
54
"fmt"
65
"strings"
76

@@ -47,11 +46,21 @@ func (a *ABIFinder) FindABIByMethod(address string, signature []byte) (ABIFinder
4746
contractName := a.ContractMap.GetContractName(address)
4847
abiInstanceCandidate, ok := a.ContractStore.ABIs[contractName+".abi"]
4948
if !ok {
50-
err := errors.New(ErrNoAbiFound)
49+
err := fmt.Errorf("no ABI found for contract '%s' at address %s, even though it's registered in the contract map. "+
50+
"This happens when:\n"+
51+
" 1. Contract address is in the contract map but ABI file is missing from abi_dir\n"+
52+
" 2. ABI files were moved or deleted after contract deployment\n"+
53+
" 3. Contract map is corrupted or out of sync\n"+
54+
"Troubleshooting:\n"+
55+
" 1. Verify ABI file '%s.abi' exists in the configured abi_dir\n"+
56+
" 2. Check if save_deployed_contracts_map = true in config\n"+
57+
" 3. Re-deploy the contract or manually add ABI with ContractStore.AddABI()\n"+
58+
" 4. For external contracts, obtain and add the ABI manually",
59+
contractName, address, contractName)
5160
L.Err(err).
5261
Str("Contract", contractName).
5362
Str("Address", address).
54-
Msg("ABI not found, even though contract is known. This should not happen. Contract map might be corrupted")
63+
Msg("ABI not found for known contract")
5564
return ABIFinderResult{}, err
5665
}
5766

@@ -150,14 +159,17 @@ func (a *ABIFinder) FindABIByMethod(address string, signature []byte) (ABIFinder
150159

151160
return ABIFinderResult{}, fmt.Errorf("no ABI found with method signature %s for contract at address %s.\n"+
152161
"Checked %d ABIs but none matched.%s\n"+
153-
"This usually means:\n"+
154-
" 1. The contract ABI wasn't loaded into Seth's contract store\n"+
155-
" 2. The method signature doesn't match any known ABI\n"+
156-
" 3. You're calling a non-existent contract address\n"+
157-
"Solutions:\n"+
158-
" 1. Add the contract's ABI to the directory specified by 'abi_dir'\n"+
159-
" 2. Use ContractStore.AddABI() to add it programmatically\n"+
160-
" 3. Deploy the contract via Seth so it's automatically registered",
162+
"Possible causes:\n"+
163+
" 1. Contract ABI not loaded (check abi_dir and contract_map_file)\n"+
164+
" 2. Method signature doesn't match any function in loaded ABIs\n"+
165+
" 3. Contract address not registered in contract map\n"+
166+
" 4. Wrong contract address (check deployment logs)\n"+
167+
"Troubleshooting:\n"+
168+
" 1. Verify contract was deployed with DeployContract() or loaded with LoadContract()\n"+
169+
" 2. Check the method signature is correct (case-sensitive, including parameter types)\n"+
170+
" 3. Ensure ABI file exists in the directory specified by 'abi_dir'\n"+
171+
" 4. Review contract_map_file for address-to-name mappings\n"+
172+
" 5. Use ContractStore.AddABI() to manually add the ABI",
161173
stringSignature, address, abiCount, abiSample)
162174
}
163175

seth/block_stats.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,14 @@ func (cs *BlockStats) Stats(startBlock *big.Int, endBlock *big.Int) error {
4848
if endBlock == nil || startBlock.Sign() < 0 {
4949
header, err := cs.Client.Client.HeaderByNumber(context.Background(), nil)
5050
if err != nil {
51-
return fmt.Errorf("failed to get the latest block header: %v", err)
51+
return fmt.Errorf("failed to get the latest block header for block stats: %w\n"+
52+
"This indicates RPC connectivity issues.\n"+
53+
"Troubleshooting:\n"+
54+
" 1. Verify RPC endpoint is accessible\n"+
55+
" 2. Check network connectivity\n"+
56+
" 3. Ensure the node is synced\n"+
57+
" 4. Try increasing dial_timeout in config",
58+
err)
5259
}
5360
latestBlockNumber = header.Number
5461
}
@@ -62,8 +69,12 @@ func (cs *BlockStats) Stats(startBlock *big.Int, endBlock *big.Int) error {
6269
endBlock = latestBlockNumber
6370
}
6471
if endBlock != nil && startBlock.Int64() > endBlock.Int64() {
65-
return fmt.Errorf("start block (%d) is greater than end block (%d). "+
66-
"Ensure start block comes before end block in the range",
72+
return fmt.Errorf("invalid block range for statistics: start block %d > end block %d.\n"+
73+
"This is a bug in Seth's block stats calculation logic.\n"+
74+
"Please open a GitHub issue at https://github.com/smartcontractkit/chainlink-testing-framework/issues with:\n"+
75+
" 1. Your configuration file\n"+
76+
" 2. The operation you were performing\n"+
77+
" 3. Network name and chain ID",
6778
startBlock.Int64(), endBlock.Int64())
6879
}
6980
L.Info().
@@ -109,7 +120,12 @@ func (cs *BlockStats) Stats(startBlock *big.Int, endBlock *big.Int) error {
109120
// CalculateBlockDurations calculates and logs the duration, TPS, gas used, and gas limit between each consecutive block
110121
func (cs *BlockStats) CalculateBlockDurations(blocks []*types.Block) error {
111122
if len(blocks) == 0 {
112-
return fmt.Errorf("no blocks to analyze. Cannot calculate block durations without block data")
123+
return fmt.Errorf("no block data available for duration analysis. " +
124+
"This happens when:\n" +
125+
" 1. No blocks were provided for analysis\n" +
126+
" 2. All block fetch attempts failed\n" +
127+
" 3. Block range is invalid\n" +
128+
"Check RPC connectivity and ensure blocks exist in the specified range")
113129
}
114130
var (
115131
durations []time.Duration

seth/contract_store.go

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,16 @@ func (c *ContractStore) loadABIs(abiPath string) error {
149149
}
150150
}
151151
if !foundABI {
152-
return fmt.Errorf("no ABI files found in '%s'. "+
153-
"Ensure:\n"+
154-
" 1. The directory exists and is readable\n"+
155-
" 2. Files have .abi extension\n"+
156-
" 3. Path is correct (should be relative to config file or absolute)\n"+
157-
"Or comment out 'abi_dir' in config if not using ABI files",
158-
abiPath)
152+
absPath, _ := filepath.Abs(abiPath)
153+
return fmt.Errorf("no ABI files (*.abi) found in directory '%s'.\n"+
154+
"ABI files are JSON files describing contract interfaces.\n"+
155+
"Solutions:\n"+
156+
" 1. Verify the path is correct: %s\n"+
157+
" 2. Ensure .abi files exist in this directory\n"+
158+
" 3. Check directory permissions (must be readable)\n"+
159+
" 4. If deploying contracts without ABIs, remove 'abi_dir' from config\n"+
160+
" 5. Generate ABIs from Solidity: solc --abi YourContract.sol -o abi_dir/",
161+
abiPath, absPath)
159162
}
160163
}
161164

@@ -183,14 +186,16 @@ func (c *ContractStore) loadBINs(binPath string) error {
183186
}
184187
}
185188
if !foundBIN {
186-
return fmt.Errorf("no BIN files (bytecode) found in '%s'. "+
187-
"BIN files are needed for contract deployment. "+
188-
"Ensure:\n"+
189-
" 1. Files have .bin extension\n"+
190-
" 2. They contain compiled contract bytecode (hex-encoded)\n"+
191-
" 3. Path is correct (should be relative to config file or absolute)\n"+
192-
"Or comment out 'bin_dir' in config if deploying contracts via other means",
193-
binPath)
189+
absPath, _ := filepath.Abs(binPath)
190+
return fmt.Errorf("no BIN files (*.bin) found in directory '%s'.\n"+
191+
"BIN files contain compiled contract bytecode needed for deployment.\n"+
192+
"Solutions:\n"+
193+
" 1. Verify the path is correct: %s\n"+
194+
" 2. Ensure .bin files exist (should contain hex-encoded bytecode)\n"+
195+
" 3. Check directory permissions (must be readable)\n"+
196+
" 4. If deploying contracts without BIN files, remove 'bin_dir' from config\n"+
197+
" 5. Generate BINs from Solidity: solc --bin YourContract.sol -o bin_dir/",
198+
binPath, absPath)
194199
}
195200
}
196201

@@ -231,7 +236,15 @@ func (c *ContractStore) loadGethWrappers(gethWrappersPaths []string) error {
231236
}
232237

233238
if len(gethWrappersPaths) > 0 && !foundWrappers {
234-
return fmt.Errorf("no geth wrappers found in '%v'. Fix the path or comment out 'geth_wrappers_dirs' setting", gethWrappersPaths)
239+
return fmt.Errorf("no geth wrapper files found in directories: %v\n"+
240+
"Geth wrappers are Go files generated by abigen containing contract ABIs.\n"+
241+
"Solutions:\n"+
242+
" 1. Verify all paths exist and are readable\n"+
243+
" 2. Generate wrappers using abigen:\n"+
244+
" abigen --abi contract.abi --bin contract.bin --pkg wrappers --out contract_wrapper.go\n"+
245+
" 3. Ensure wrapper files contain ABI metadata (check for 'ABI' variable)\n"+
246+
" 4. If not using geth wrappers, remove 'geth_wrappers_dirs' from config",
247+
gethWrappersPaths)
235248
}
236249

237250
return nil

seth/decode.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,13 @@ func (m *Client) decodeTransaction(l zerolog.Logger, tx *types.Transaction, rece
415415

416416
sig := txData[:4]
417417
if m.ABIFinder == nil {
418-
l.Err(errors.New("ABIFInder is nil")).Msg("ABIFinder is required for transaction decoding")
418+
err := fmt.Errorf("ABIFinder is not initialized, cannot decode transaction. " +
419+
"This is an internal error - ABIFinder should be set during client initialization.\n" +
420+
"If you see this error:\n" +
421+
" 1. Ensure you're using NewClient() or NewClientWithConfig() to create the client\n" +
422+
" 2. Don't manually modify client.ABIFinder\n" +
423+
" 3. If the issue persists, please open a GitHub issue at https://github.com/smartcontractkit/chainlink-testing-framework/issues")
424+
l.Err(err).Msg("ABIFinder is required for transaction decoding")
419425
return defaultTxn, nil
420426
}
421427

@@ -499,7 +505,13 @@ func (m *Client) DecodeCustomABIErr(txErr error) (string, error) {
499505
//nolint
500506
cerr, ok := txErr.(rpc.DataError)
501507
if !ok {
502-
return "", errors.New(ErrRPCJSONCastError)
508+
return "", fmt.Errorf("failed to extract revert reason from RPC error response. " +
509+
"The RPC response format is not recognized.\n" +
510+
"This could mean:\n" +
511+
" 1. Your RPC node uses a non-standard error format\n" +
512+
" 2. The transaction didn't revert (unexpected state)\n" +
513+
" 3. RPC node is experiencing issues\n" +
514+
"The transaction trace may still contain useful information")
503515
}
504516
if m.ContractStore == nil {
505517
L.Warn().Msg(WarnNoContractStore)
@@ -605,7 +617,13 @@ func (m *Client) callAndGetRevertReason(tx *types.Transaction, rc *types.Receipt
605617
return err
606618
}
607619
if decodedABIErrString != "" {
608-
return errors.New(decodedABIErrString)
620+
return fmt.Errorf("failed to decode ABI from contract code: %s\n"+
621+
"This happens when:\n"+
622+
" 1. Contract bytecode doesn't contain valid ABI metadata\n"+
623+
" 2. Contract wasn't compiled with metadata (--metadata-hash none)\n"+
624+
" 3. Contract code at the address is not a valid contract\n"+
625+
"For third-party contracts, manually load the ABI instead of relying on auto-detection",
626+
decodedABIErrString)
609627
}
610628

611629
if plainStringErr != nil {
@@ -637,7 +655,13 @@ func (m *Client) callAndGetRevertReason(tx *types.Transaction, rc *types.Receipt
637655
func decodeTxInputs(l zerolog.Logger, txData []byte, method *abi.Method) (map[string]interface{}, error) {
638656
l.Trace().Msg("Parsing tx inputs")
639657
if (len(txData)) < 4 {
640-
return nil, errors.New(ErrTooShortTxData)
658+
return nil, fmt.Errorf("transaction data is too short to contain a valid function call. "+
659+
"Expected at least 4 bytes for function selector, got %d bytes.\n"+
660+
"This might indicate:\n"+
661+
" 1. Plain ETH transfer (no function call)\n"+
662+
" 2. Invalid/corrupted transaction data\n"+
663+
" 3. Contract deployment (not a function call)",
664+
len(txData))
641665
}
642666

643667
inputMap := make(map[string]interface{})

seth/gas_adjuster.go

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package seth
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76
"math"
87
"math/big"
@@ -44,7 +43,9 @@ var (
4443
// according to selected strategy.
4544
func (m *Client) CalculateNetworkCongestionMetric(blocksNumber uint64, strategy string) (float64, error) {
4645
if m.HeaderCache == nil {
47-
return 0, fmt.Errorf("header cache is nil")
46+
return 0, fmt.Errorf("header cache is not initialized. " +
47+
"This is an internal error that shouldn't happen. " +
48+
"If you see this, please open a GitHub issue at https://github.com/smartcontractkit/chainlink-testing-framework/issues with your configuration details")
4849
}
4950
var getHeaderData = func(bn *big.Int) (*types.Header, error) {
5051
if bn == nil {
@@ -128,7 +129,18 @@ func (m *Client) CalculateNetworkCongestionMetric(blocksNumber uint64, strategy
128129

129130
minBlockCount := int(float64(blocksNumber) * 0.8)
130131
if len(headers) < minBlockCount {
131-
return 0, fmt.Errorf("%s. Wanted at least %d, got %d", BlockFetchingErr, minBlockCount, len(headers))
132+
return 0, fmt.Errorf("failed to fetch sufficient block headers for gas estimation. "+
133+
"Needed at least %d blocks, but only got %d (%.1f%% success rate).\n"+
134+
"This usually indicates:\n"+
135+
" 1. RPC node is experiencing high latency or load\n"+
136+
" 2. Network connectivity issues\n"+
137+
" 3. RPC rate limiting\n"+
138+
"Solutions:\n"+
139+
" 1. Retry the transaction (temporary RPC issue)\n"+
140+
" 2. Use a different RPC endpoint\n"+
141+
" 3. Disable gas estimation: set gas_price_estimation_enabled = false\n"+
142+
" 4. Reduce gas_price_estimation_blocks to fetch fewer blocks",
143+
minBlockCount, len(headers), float64(len(headers))/float64(blocksNumber)*100)
132144
}
133145

134146
switch strategy {
@@ -137,7 +149,10 @@ func (m *Client) CalculateNetworkCongestionMetric(blocksNumber uint64, strategy
137149
case CongestionStrategy_NewestFirst:
138150
return calculateNewestFirstNetworkCongestionMetric(headers), nil
139151
default:
140-
return 0, fmt.Errorf("unknown congestion strategy: %s", strategy)
152+
return 0, fmt.Errorf("unknown network congestion strategy '%s'. "+
153+
"Valid strategies are: 'simple' (equal weight) or 'newest_first' (recent blocks weighted more).\n"+
154+
"This is likely a configuration error. Check your gas estimation settings",
155+
strategy)
141156
}
142157
}
143158

@@ -202,7 +217,12 @@ func (m *Client) GetSuggestedEIP1559Fees(ctx context.Context, priority string) (
202217
}
203218
// defensive programming
204219
if baseFee == nil || currentGasTip == nil {
205-
err = errors.New(ZeroGasSuggestedErr)
220+
err = fmt.Errorf("RPC node returned nil gas price or zero gas tip. " +
221+
"This indicates the node's gas estimation is not working properly.\n" +
222+
"Solutions:\n" +
223+
" 1. Use a different RPC endpoint\n" +
224+
" 2. Disable gas estimation: set gas_price_estimation_enabled = false in config\n" +
225+
" 3. Set explicit gas values: gas_price, gas_fee_cap, and gas_tip_cap (in your config (seth.toml or ClientBuilder)")
206226
return
207227
}
208228

@@ -606,7 +626,10 @@ func getAdjustmentFactor(priority string) (float64, error) {
606626
case Priority_Slow:
607627
return 0.8, nil
608628
default:
609-
return 0, fmt.Errorf("unsupported priority: %s", priority)
629+
return 0, fmt.Errorf("unsupported transaction priority '%s'. "+
630+
"Valid priorities: 'fast', 'standard', 'slow', 'auto'. "+
631+
"Set 'gas_price_estimation_tx_priority' in your config (seth.toml or ClientBuilder)",
632+
priority)
610633
}
611634
}
612635

@@ -621,7 +644,10 @@ func getCongestionFactor(congestionClassification string) (float64, error) {
621644
case Congestion_VeryHigh:
622645
return 1.40, nil
623646
default:
624-
return 0, fmt.Errorf("unsupported congestion classification: %s", congestionClassification)
647+
return 0, fmt.Errorf("unsupported congestion classification '%s'. "+
648+
"Valid classifications: 'low', 'medium', 'high', 'extreme'. "+
649+
"This is likely an internal error. Please open a GitHub issue at https://github.com/smartcontractkit/chainlink-testing-framework/issues",
650+
congestionClassification)
625651
}
626652
}
627653

@@ -652,7 +678,10 @@ func (m *Client) HistoricalFeeData(ctx context.Context, priority string) (baseFe
652678
case Priority_Slow:
653679
percentileTip = 25
654680
default:
655-
err = fmt.Errorf("unknown priority: %s", priority)
681+
err = fmt.Errorf("unsupported transaction priority '%s'. "+
682+
"Valid priorities: 'fast', 'standard', 'slow'. "+
683+
"Set 'gas_price_estimation_tx_priority' in your config (seth.toml or ClientBuilder)",
684+
priority)
656685
L.Debug().
657686
Str("Priority", priority).
658687
Msgf("Unknown priority: %s", err.Error())
@@ -682,7 +711,10 @@ func (m *Client) HistoricalFeeData(ctx context.Context, priority string) (baseFe
682711
case Priority_Slow:
683712
baseFee = stats.BaseFeePerc.Perc25
684713
default:
685-
err = fmt.Errorf("unsupported priority: %s", priority)
714+
err = fmt.Errorf("unsupported transaction priority '%s'. "+
715+
"Valid priorities: 'fast', 'standard', 'slow'. "+
716+
"Set 'gas_price_estimation_tx_priority' in your config (seth.toml or ClientBuilder)",
717+
priority)
686718
L.Debug().
687719
Str("Priority", priority).
688720
Msgf("Unsupported priority: %s", err.Error())

seth/keyfile.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package seth
33
import (
44
"context"
55
"crypto/ecdsa"
6-
"errors"
6+
"fmt"
77
"math/big"
88

99
"github.com/ethereum/go-ethereum/common"
@@ -22,7 +22,11 @@ func NewAddress() (string, string, error) {
2222
publicKey := privateKey.Public()
2323
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
2424
if !ok {
25-
return "", "", errors.New("error casting public key to ECDSA")
25+
return "", "", fmt.Errorf("failed to cast generated public key to ECDSA type.\n"+
26+
"This is an internal error in the crypto.GenerateKey() function.\n"+
27+
"Expected type: *ecdsa.PublicKey, got: %T\n"+
28+
"Please report this issue: https://github.com/smartcontractkit/chainlink-testing-framework/issues",
29+
publicKey)
2630
}
2731
address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
2832
L.Info().
@@ -49,7 +53,13 @@ func ReturnFunds(c *Client, toAddr string) error {
4953
}
5054

5155
if len(c.Addresses) == 1 {
52-
return errors.New("No addresses to return funds from. Have you passed correct key file?")
56+
return fmt.Errorf("no ephemeral addresses found to return funds from.\n"+
57+
"Current addresses count: %d (only root key present)\n"+
58+
"This indicates either:\n"+
59+
" 1. Key file doesn't contain ephemeral addresses\n"+
60+
" 2. Wrong key file was loaded\n"+
61+
" 3. Ephemeral keys were never created (set 'ephemeral_addresses_number' > 0 in config)",
62+
len(c.Addresses))
5363
}
5464

5565
eg, egCtx := errgroup.WithContext(ctx)

0 commit comments

Comments
 (0)