refactor: remove directive errors comparision

This commit is contained in:
kien6034 2024-05-10 23:36:54 +07:00
parent e5f5eaebc4
commit c4f1afa3af
No known key found for this signature in database
GPG key ID: 6C36B30C35146F95
87 changed files with 272 additions and 249 deletions

View file

@ -87,7 +87,7 @@ func TestWaitDeployed(t *testing.T) {
select {
case <-mined:
if err != test.wantErr {
if !errors.Is(err, test.wantErr) {
t.Errorf("test %q: error mismatch: want %q, got %q", name, test.wantErr, err)
}
if address != test.wantAddress {

View file

@ -19,6 +19,7 @@ package abi
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"math"
"math/big"
@ -1106,7 +1107,7 @@ func TestPackAndUnpackIncompatibleNumber(t *testing.T) {
{Type: ty},
}
decoded, err := decodeABI.Unpack(packed)
if err != testCase.err {
if !errors.Is(err, testCase.err) {
t.Fatalf("Expected error %v, actual error %v. case %d", testCase.err, err, i)
}
if err != nil {

View file

@ -17,6 +17,7 @@
package keystore
import (
"errors"
"math/rand"
"os"
"runtime"
@ -127,7 +128,7 @@ func TestTimedUnlock(t *testing.T) {
// Signing without passphrase fails because account is locked
_, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
if err != ErrLocked {
if !errors.Is(err, ErrLocked) {
t.Fatal("Signing should've failed with ErrLocked before unlocking, got ", err)
}
@ -145,7 +146,7 @@ func TestTimedUnlock(t *testing.T) {
// Signing fails again after automatic locking
time.Sleep(250 * time.Millisecond)
_, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
if err != ErrLocked {
if !errors.Is(err, ErrLocked) {
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
}
}
@ -185,7 +186,7 @@ func TestOverrideUnlock(t *testing.T) {
// Signing fails again after automatic locking
time.Sleep(250 * time.Millisecond)
_, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
if err != ErrLocked {
if !errors.Is(err, ErrLocked) {
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
}
}
@ -206,7 +207,7 @@ func TestSignRace(t *testing.T) {
}
end := time.Now().Add(500 * time.Millisecond)
for time.Now().Before(end) {
if _, err := ks.SignHash(accounts.Account{Address: a1.Address}, testSigData); err == ErrLocked {
if _, err := ks.SignHash(accounts.Account{Address: a1.Address}, testSigData); errors.Is(err, ErrLocked) {
return
} else if err != nil {
t.Errorf("Sign error: %v", err)

View file

@ -19,6 +19,7 @@ package keystore
import (
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"path/filepath"
"reflect"
@ -90,7 +91,7 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if _, err = ks.GetKey(k1.Address, account.URL.Path, "bar"); err != ErrDecrypt {
if _, err = ks.GetKey(k1.Address, account.URL.Path, "bar"); !errors.Is(err, ErrDecrypt) {
t.Fatalf("wrong error for invalid password\ngot %q\nwant %q", err, ErrDecrypt)
}
}

View file

@ -119,7 +119,7 @@ func (w *ledgerDriver) Open(device io.ReadWriter, passphrase string) error {
_, err := w.ledgerDerive(accounts.DefaultBaseDerivationPath)
if err != nil {
// Ethereum app is not running or in browser mode, nothing more to do, return
if err == errLedgerReplyInvalidHeader {
if errors.Is(err, errLedgerReplyInvalidHeader) {
w.browser = true
}
return nil
@ -141,7 +141,7 @@ func (w *ledgerDriver) Close() error {
// Heartbeat implements usbwallet.driver, performing a sanity check against the
// Ledger to see if it's still online.
func (w *ledgerDriver) Heartbeat() error {
if _, err := w.ledgerVersion(); err != nil && err != errLedgerInvalidVersionReply {
if _, err := w.ledgerVersion(); err != nil && !errors.Is(err, errLedgerInvalidVersionReply) {
w.failure = err
return err
}

View file

@ -18,6 +18,7 @@ package light
import (
"crypto/rand"
"errors"
"testing"
"time"
@ -259,13 +260,13 @@ func (c *committeeChainTest) setClockPeriod(period float64) {
}
func (c *committeeChainTest) addFixedCommitteeRoot(tc *testCommitteeChain, period uint64, expErr error) {
if err := c.chain.addFixedCommitteeRoot(period, tc.periods[period].committee.Root()); err != expErr {
if err := c.chain.addFixedCommitteeRoot(period, tc.periods[period].committee.Root()); !errors.Is(err, expErr) {
c.t.Errorf("Incorrect error output from addFixedCommitteeRoot at period %d (expected %v, got %v)", period, expErr, err)
}
}
func (c *committeeChainTest) addCommittee(tc *testCommitteeChain, period uint64, expErr error) {
if err := c.chain.addCommittee(period, tc.periods[period].committee); err != expErr {
if err := c.chain.addCommittee(period, tc.periods[period].committee); !errors.Is(err, expErr) {
c.t.Errorf("Incorrect error output from addCommittee at period %d (expected %v, got %v)", period, expErr, err)
}
}
@ -275,7 +276,7 @@ func (c *committeeChainTest) insertUpdate(tc *testCommitteeChain, period uint64,
if addCommittee {
committee = tc.periods[period+1].committee
}
if err := c.chain.InsertUpdate(tc.periods[period].update, committee); err != expErr {
if err := c.chain.InsertUpdate(tc.periods[period].update, committee); !errors.Is(err, expErr) {
c.t.Errorf("Incorrect error output from InsertUpdate at period %d (expected %v, got %v)", period, expErr, err)
}
}

View file

@ -17,6 +17,7 @@
package sync
import (
"errors"
"sort"
"github.com/ethereum/go-ethereum/beacon/light"
@ -380,12 +381,12 @@ func (s *ForwardUpdateSync) Process(requester request.Requester, events []reques
func (s *ForwardUpdateSync) processResponse(requester request.Requester, u updateResponse) (success bool) {
for i, update := range u.response.Updates {
if err := s.chain.InsertUpdate(update, u.response.Committees[i]); err != nil {
if err == light.ErrInvalidPeriod {
if errors.Is(err, light.ErrInvalidPeriod) {
// there is a gap in the update periods; stop processing without
// failing and try again next time
return
}
if err == light.ErrInvalidUpdate || err == light.ErrWrongCommitteeRoot || err == light.ErrCannotReorg {
if errors.Is(err, light.ErrInvalidUpdate) || errors.Is(err, light.ErrWrongCommitteeRoot) || errors.Is(err, light.ErrCannotReorg) {
requester.Fail(u.sid.Server, "invalid update received")
} else {
log.Error("Unexpected InsertUpdate error", "error", err)

View file

@ -923,13 +923,13 @@ func testExternalUI(api *core.SignerAPI) {
}
}
expectApprove := func(testcase string, err error) {
if err == nil || err == accounts.ErrUnknownAccount {
if err == nil || errors.Is(err, accounts.ErrUnknownAccount) {
return
}
addErr(fmt.Sprintf("%v: expected no error, got %v", testcase, err.Error()))
}
expectDeny := func(testcase string, err error) {
if err == nil || err != core.ErrRequestDenied {
if err == nil || !errors.Is(err, core.ErrRequestDenied) {
addErr(fmt.Sprintf("%v: expected ErrRequestDenied, got %v", testcase, err))
}
}

View file

@ -295,7 +295,7 @@ func blocksFromFile(chainfile string, gblock *types.Block) ([]*types.Block, erro
blocks[0] = gblock
for i := 0; ; i++ {
var b types.Block
if err := stream.Decode(&b); err == io.EOF {
if err := stream.Decode(&b); errors.Is(err, io.EOF) {
break
} else if err != nil {
return nil, fmt.Errorf("at block index %d: %v", i, err)

View file

@ -18,6 +18,7 @@ package v5test
import (
"bytes"
"errors"
"net"
"slices"
"sync"
@ -96,7 +97,7 @@ func (s *Suite) TestPingLargeRequestID(t *utesting.T) {
case *v5wire.Pong:
t.Errorf("PONG response with unknown request ID %x", resp.ReqID)
case *readError:
if resp.err == v5wire.ErrInvalidReqID {
if errors.Is(resp.err, v5wire.ErrInvalidReqID) {
t.Error("response with oversized request ID")
} else if !netutil.IsTimeout(resp.err) {
t.Error(resp)

View file

@ -17,6 +17,7 @@
package main
import (
"errors"
"fmt"
"os"
@ -237,7 +238,7 @@ func unlockAccount(ks *keystore.KeyStore, address string, i int, passwords []str
log.Info("Unlocked account", "address", account.Address.Hex())
return ambiguousAddrRecovery(ks, err, password), password
}
if err != keystore.ErrDecrypt {
if !errors.Is(err, keystore.ErrDecrypt) {
// No need to prompt again if the error is not decryption-related.
break
}

View file

@ -22,6 +22,7 @@ import (
"bytes"
"container/list"
"encoding/hex"
"errors"
"flag"
"fmt"
"io"
@ -106,7 +107,7 @@ func rlpToText(in *inStream, out io.Writer) error {
stream := rlp.NewStream(in, 0)
for {
if err := dump(in, stream, 0, out); err != nil {
if err != io.EOF {
if !errors.Is(err, io.EOF) {
return err
}
break
@ -149,7 +150,7 @@ func dump(in *inStream, s *rlp.Stream, depth int, out io.Writer) error {
if i > 0 {
fmt.Fprint(out, ",\n")
}
if err := dump(in, s, depth+1, out); err == rlp.EOL {
if err := dump(in, s, depth+1, out); errors.Is(err, rlp.EOL) {
break
} else if err != nil {
return err

View file

@ -195,7 +195,7 @@ func ImportChain(chain *core.BlockChain, fn string) error {
i := 0
for ; i < importBatchSize; i++ {
var b types.Block
if err := stream.Decode(&b); err == io.EOF {
if err := stream.Decode(&b); errors.Is(err, io.EOF) {
break
} else if err != nil {
return fmt.Errorf("at block %d: %v", n, err)
@ -516,7 +516,7 @@ func ImportPreimages(db ethdb.Database, fn string) error {
var blob []byte
if err := stream.Decode(&blob); err != nil {
if err == io.EOF {
if errors.Is(err, io.EOF) {
break
}
return err
@ -726,7 +726,7 @@ func ImportLDBData(db ethdb.Database, f string, startIndex int64, interrupt chan
key, val []byte
)
if err := stream.Decode(&op); err != nil {
if err == io.EOF {
if errors.Is(err, io.EOF) {
break
}
return err

View file

@ -18,6 +18,7 @@ package bitutil
import (
"bytes"
"errors"
"fmt"
"math/rand"
"testing"
@ -107,7 +108,7 @@ func TestDecodingCycle(t *testing.T) {
data := hexutil.MustDecode(tt.input)
orig, err := bitsetDecodeBytes(data, tt.size)
if err != tt.fail {
if !errors.Is(err, tt.fail) {
t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.fail)
}
if err != nil {
@ -143,7 +144,7 @@ func TestCompression(t *testing.T) {
t.Errorf("decoding mismatch for dense data: have %x, want %x, error %v", data, in, err)
}
// Check that decompressing a longer input than the target fails
if _, err := DecompressBytes([]byte{0xc0, 0x01, 0x01}, 2); err != errExceededTarget {
if _, err := DecompressBytes([]byte{0xc0, 0x01, 0x01}, 2); !errors.Is(err, errExceededTarget) {
t.Errorf("decoding error mismatch for long data: have %v, want %v", err, errExceededTarget)
}
}

View file

@ -32,6 +32,7 @@ package hexutil
import (
"encoding/hex"
"errors"
"fmt"
"math/big"
"strconv"
@ -234,7 +235,7 @@ func mapError(err error) error {
if _, ok := err.(hex.InvalidByteError); ok {
return ErrSyntax
}
if err == hex.ErrLength {
if errors.Is(err, hex.ErrLength) {
return ErrOddLength
}
return err

View file

@ -19,6 +19,7 @@ package hexutil
import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"math/big"
"reflect"
@ -355,7 +356,7 @@ func (b *Uint) UnmarshalJSON(input []byte) error {
func (b *Uint) UnmarshalText(input []byte) error {
var u64 Uint64
err := u64.UnmarshalText(input)
if u64 > Uint64(^uint(0)) || err == ErrUint64Range {
if u64 > Uint64(^uint(0)) || errors.Is(err, ErrUint64Range) {
return ErrUintRange
} else if err != nil {
return err

View file

@ -19,6 +19,7 @@ package clique
import (
"bytes"
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
"slices"
@ -470,7 +471,7 @@ func (tt *cliqueTest) run(t *testing.T) {
break
}
}
if _, err = chain.InsertChain(batches[len(batches)-1]); err != tt.failure {
if _, err = chain.InsertChain(batches[len(batches)-1]); !errors.Is(err, tt.failure) {
t.Errorf("failure mismatch: have %v, want %v", err, tt.failure)
}
if tt.failure != nil {

View file

@ -448,7 +448,7 @@ func (c *Console) Interactive() {
return
case err := <-inputErr:
if err == liner.ErrPromptAborted {
if errors.Is(err, liner.ErrPromptAborted) {
// When prompting for multi-line input, the first Ctrl-C resets
// the multi-line state.
prompt, indents, input = c.prompt, 0, ""

View file

@ -17,6 +17,7 @@
package asm
import (
"errors"
"testing"
"encoding/hex"
@ -47,7 +48,7 @@ func TestInstructionIterator(t *testing.T) {
if it.Error() != nil {
haveErr = it.Error().Error()
}
if haveErr != tc.wantErr {
if !errors.Is(haveErr, tc.wantErr) {
t.Errorf("test %d: encountered error: %q want %q", i, haveErr, tc.wantErr)
continue
}

View file

@ -1390,7 +1390,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
// Write downloaded chain data and corresponding receipt chain data
if len(ancientBlocks) > 0 {
if n, err := writeAncient(ancientBlocks, ancientReceipts); err != nil {
if err == errInsertionInterrupted {
if errors.Is(err, errInsertionInterrupted) {
return 0, nil
}
return n, err
@ -1398,7 +1398,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
}
if len(liveBlocks) > 0 {
if n, err := writeLive(liveBlocks, liveReceipts); err != nil {
if err == errInsertionInterrupted {
if errors.Is(err, errInsertionInterrupted) {
return 0, nil
}
return n, err

View file

@ -154,7 +154,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
err = blockchain.validator.ValidateBody(block)
}
if err != nil {
if err == ErrKnownBlock {
if errors.Is(err, ErrKnownBlock) {
continue
}
return err

View file

@ -18,6 +18,7 @@ package forkid
import (
"bytes"
"errors"
"hash/crc32"
"math"
"math/big"
@ -359,7 +360,7 @@ func TestValidation(t *testing.T) {
genesis := core.DefaultGenesisBlock().ToBlock()
for i, tt := range tests {
filter := newFilter(tt.config, genesis, func() (uint64, uint64) { return tt.head, tt.time })
if err := filter(tt.id); err != tt.err {
if err := filter(tt.id); !errors.Is(err, tt.err) {
t.Errorf("test %d: validation error mismatch: have %v, want %v", i, err, tt.err)
}
}

View file

@ -19,6 +19,7 @@ package rawdb
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"math/rand"
"os"
@ -68,7 +69,7 @@ func TestFreezerBasics(t *testing.T) {
}
// Check that we cannot read too far
_, err = f.Retrieve(uint64(255))
if err != errOutOfBounds {
if !errors.Is(err, errOutOfBounds) {
t.Fatal(err)
}
}
@ -878,7 +879,7 @@ func checkRetrieveError(t *testing.T, f *freezerTable, items map[uint64]error) {
if err == nil {
t.Fatalf("unexpected value %x for item %d, want error %v", item, value, wantError)
}
if err != wantError {
if !errors.Is(err, wantError) {
t.Fatalf("wrong error for item %d: %v", item, err)
}
}

View file

@ -106,7 +106,7 @@ func TestFreezerModifyRollback(t *testing.T) {
require.NoError(t, op.AppendRaw("test", 2, make([]byte, 2048)))
return theError
})
if err != theError {
if !errors.Is(err, theError) {
t.Errorf("ModifyAncients returned wrong error %q", err)
}
checkAncientCount(t, f, "test", 0)
@ -374,7 +374,7 @@ func checkAncientCount(t *testing.T, f *Freezer, kind string, n uint64) {
}
if _, err := f.Ancient(kind, index); err == nil {
t.Errorf("Ancient(%q, %d) didn't return expected error", kind, index)
} else if err != errOutOfBounds {
} else if !errors.Is(err, errOutOfBounds) {
t.Errorf("Ancient(%q, %d) returned unexpected error %q", kind, index, err)
}
}

View file

@ -18,6 +18,7 @@ package snapshot
import (
"bytes"
"errors"
"testing"
"github.com/VictoriaMetrics/fastcache"
@ -311,7 +312,7 @@ func TestDiskPartialMerge(t *testing.T) {
assertAccount := func(account common.Hash, data []byte) {
t.Helper()
blob, err := base.AccountRLP(account)
if bytes.Compare(account[:], genMarker) > 0 && err != ErrNotCoveredYet {
if bytes.Compare(account[:], genMarker) > 0 && !errors.Is(err, ErrNotCoveredYet) {
t.Fatalf("test %d: post-marker (%x) account access (%x) succeeded: %x", i, genMarker, account, blob)
}
if bytes.Compare(account[:], genMarker) <= 0 && !bytes.Equal(blob, data) {
@ -327,7 +328,7 @@ func TestDiskPartialMerge(t *testing.T) {
assertStorage := func(account common.Hash, slot common.Hash, data []byte) {
t.Helper()
blob, err := base.Storage(account, slot)
if bytes.Compare(append(account[:], slot[:]...), genMarker) > 0 && err != ErrNotCoveredYet {
if bytes.Compare(append(account[:], slot[:]...), genMarker) > 0 && !errors.Is(err, ErrNotCoveredYet) {
t.Fatalf("test %d: post-marker (%x) storage access (%x:%x) succeeded: %x", i, genMarker, account, slot, blob)
}
if bytes.Compare(append(account[:], slot[:]...), genMarker) <= 0 && !bytes.Equal(blob, data) {

View file

@ -19,6 +19,7 @@ package snapshot
import (
crand "crypto/rand"
"encoding/binary"
"errors"
"fmt"
"math/rand"
"testing"
@ -118,10 +119,10 @@ func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) {
t.Fatalf("failed to merge diff layer onto disk: %v", err)
}
// Since the base layer was modified, ensure that data retrievals on the external reference fail
if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale {
if acc, err := ref.Account(common.HexToHash("0x01")); !errors.Is(err, ErrSnapshotStale) {
t.Errorf("stale reference returned account: %#x (err: %v)", acc, err)
}
if slot, err := ref.Storage(common.HexToHash("0xa1"), common.HexToHash("0xb1")); err != ErrSnapshotStale {
if slot, err := ref.Storage(common.HexToHash("0xa1"), common.HexToHash("0xb1")); !errors.Is(err, ErrSnapshotStale) {
t.Errorf("stale reference returned storage slot: %#x (err: %v)", slot, err)
}
if n := len(snaps.layers); n != 1 {
@ -168,10 +169,10 @@ func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) {
t.Fatalf("failed to merge accumulator onto disk: %v", err)
}
// Since the base layer was modified, ensure that data retrievals on the external reference fail
if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale {
if acc, err := ref.Account(common.HexToHash("0x01")); !errors.Is(err, ErrSnapshotStale) {
t.Errorf("stale reference returned account: %#x (err: %v)", acc, err)
}
if slot, err := ref.Storage(common.HexToHash("0xa1"), common.HexToHash("0xb1")); err != ErrSnapshotStale {
if slot, err := ref.Storage(common.HexToHash("0xa1"), common.HexToHash("0xb1")); !errors.Is(err, ErrSnapshotStale) {
t.Errorf("stale reference returned storage slot: %#x (err: %v)", slot, err)
}
if n := len(snaps.layers); n != 2 {
@ -230,10 +231,10 @@ func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) {
t.Fatalf("failed to flatten diff layer into accumulator: %v", err)
}
// Since the accumulator diff layer was modified, ensure that data retrievals on the external reference fail
if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale {
if acc, err := ref.Account(common.HexToHash("0x01")); !errors.Is(err, ErrSnapshotStale) {
t.Errorf("stale reference returned account: %#x (err: %v)", acc, err)
}
if slot, err := ref.Storage(common.HexToHash("0xa1"), common.HexToHash("0xb1")); err != ErrSnapshotStale {
if slot, err := ref.Storage(common.HexToHash("0xa1"), common.HexToHash("0xb1")); !errors.Is(err, ErrSnapshotStale) {
t.Errorf("stale reference returned storage slot: %#x (err: %v)", slot, err)
}
if n := len(snaps.layers); n != 3 {

View file

@ -17,6 +17,7 @@
package core
import (
"errors"
"fmt"
"math"
"math/big"
@ -61,7 +62,7 @@ func (result *ExecutionResult) Return() []byte {
// Revert returns the concrete revert reason if the execution is aborted by `REVERT`
// opcode. Note the reason can be nil if no data supplied with revert opcode.
func (result *ExecutionResult) Revert() []byte {
if result.Err != vm.ErrExecutionReverted {
if !errors.Is(result.Err, vm.ErrExecutionReverted) {
return nil
}
return common.CopyBytes(result.ReturnData)

View file

@ -92,7 +92,7 @@ type (
// Exceptionally, before the homestead hardfork a contract creation that
// ran out of gas when attempting to persist the code to database did not
// count as a call failure and did not cause a revert of the call. This will
// be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`.
// be indicated by `reverted == false` and `errors.Is(err, ErrCodeStoreOutOfGas)`.
//
// Take note that ExitHook, when in the context of a live tracer, can be invoked
// outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls,

View file

@ -96,7 +96,7 @@ func (journal *journal) load(add func([]*types.Transaction) []error) error {
// Parse the next transaction and terminate on error
tx := new(types.Transaction)
if err = stream.Decode(tx); err != nil {
if err != io.EOF {
if !errors.Is(err, io.EOF) {
failure = err
}
if batch.Len() > 0 {

View file

@ -422,7 +422,7 @@ func TestNegativeValue(t *testing.T) {
tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key)
from, _ := deriveSender(tx)
testAddBalance(pool, from, big.NewInt(1))
if err := pool.addRemote(tx); err != txpool.ErrNegativeValue {
if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrNegativeValue) {
t.Error("expected", txpool.ErrNegativeValue, "got", err)
}
}
@ -435,7 +435,7 @@ func TestTipAboveFeeCap(t *testing.T) {
tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key)
if err := pool.addRemote(tx); err != core.ErrTipAboveFeeCap {
if err := pool.addRemote(tx); !errors.Is(err, core.ErrTipAboveFeeCap) {
t.Error("expected", core.ErrTipAboveFeeCap, "got", err)
}
}
@ -450,12 +450,12 @@ func TestVeryHighValues(t *testing.T) {
veryBigNumber.Lsh(veryBigNumber, 300)
tx := dynamicFeeTx(0, 100, big.NewInt(1), veryBigNumber, key)
if err := pool.addRemote(tx); err != core.ErrTipVeryHigh {
if err := pool.addRemote(tx); !errors.Is(err, core.ErrTipVeryHigh) {
t.Error("expected", core.ErrTipVeryHigh, "got", err)
}
tx2 := dynamicFeeTx(0, 100, veryBigNumber, big.NewInt(1), key)
if err := pool.addRemote(tx2); err != core.ErrFeeCapVeryHigh {
if err := pool.addRemote(tx2); !errors.Is(err, core.ErrFeeCapVeryHigh) {
t.Error("expected", core.ErrFeeCapVeryHigh, "got", err)
}
}
@ -1810,7 +1810,7 @@ func TestUnderpricing(t *testing.T) {
t.Fatalf("failed to add well priced transaction: %v", err)
}
// Ensure that replacing a pending transaction with a future transaction fails
if err := pool.addRemote(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != txpool.ErrFutureReplacePending {
if err := pool.addRemote(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); !errors.Is(err, txpool.ErrFutureReplacePending) {
t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, txpool.ErrFutureReplacePending)
}
pending, queued = pool.Stats()
@ -2180,7 +2180,7 @@ func TestReplacement(t *testing.T) {
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), key)); err != nil {
t.Fatalf("failed to add original cheap pending transaction: %v", err)
}
if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(1), key)); err != txpool.ErrReplaceUnderpriced {
if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) {
t.Fatalf("original cheap pending transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced)
}
if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(2), key)); err != nil {
@ -2193,7 +2193,7 @@ func TestReplacement(t *testing.T) {
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(price), key)); err != nil {
t.Fatalf("failed to add original proper pending transaction: %v", err)
}
if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(threshold-1), key)); err != txpool.ErrReplaceUnderpriced {
if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(threshold-1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) {
t.Fatalf("original proper pending transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced)
}
if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(threshold), key)); err != nil {
@ -2207,7 +2207,7 @@ func TestReplacement(t *testing.T) {
if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(1), key)); err != nil {
t.Fatalf("failed to add original cheap queued transaction: %v", err)
}
if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(1), key)); err != txpool.ErrReplaceUnderpriced {
if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) {
t.Fatalf("original cheap queued transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced)
}
if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(2), key)); err != nil {
@ -2217,7 +2217,7 @@ func TestReplacement(t *testing.T) {
if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(price), key)); err != nil {
t.Fatalf("failed to add original proper queued transaction: %v", err)
}
if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(threshold-1), key)); err != txpool.ErrReplaceUnderpriced {
if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(threshold-1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) {
t.Fatalf("original proper queued transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced)
}
if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(threshold), key)); err != nil {
@ -2281,7 +2281,7 @@ func TestReplacementDynamicFee(t *testing.T) {
}
// 2. Don't bump tip or feecap => discard
tx = dynamicFeeTx(nonce, 100001, big.NewInt(2), big.NewInt(1), key)
if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced {
if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) {
t.Fatalf("original cheap %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced)
}
// 3. Bump both more than min => accept
@ -2304,22 +2304,22 @@ func TestReplacementDynamicFee(t *testing.T) {
}
// 6. Bump tip max allowed so it's still underpriced => discard
tx = dynamicFeeTx(nonce, 100000, big.NewInt(gasFeeCap), big.NewInt(tipThreshold-1), key)
if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced {
if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) {
t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced)
}
// 7. Bump fee cap max allowed so it's still underpriced => discard
tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold-1), big.NewInt(gasTipCap), key)
if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced {
if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) {
t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced)
}
// 8. Bump tip min for acceptance => accept
tx = dynamicFeeTx(nonce, 100000, big.NewInt(gasFeeCap), big.NewInt(tipThreshold), key)
if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced {
if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) {
t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced)
}
// 9. Bump fee cap min for acceptance => accept
tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold), big.NewInt(gasTipCap), key)
if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced {
if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) {
t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced)
}
// 10. Check events match expected (3 new executable txs during pending, 0 during queue)

View file

@ -19,6 +19,7 @@ package types
import (
"bytes"
"encoding/json"
"errors"
"math"
"math/big"
"reflect"
@ -300,7 +301,7 @@ func TestDecodeEmptyTypedReceipt(t *testing.T) {
input := []byte{0x80}
var r Receipt
err := rlp.DecodeBytes(input, &r)
if err != errShortTypedReceipt {
if !errors.Is(err, errShortTypedReceipt) {
t.Fatal("wrong error:", err)
}
}

View file

@ -76,7 +76,7 @@ func TestDecodeEmptyTypedTx(t *testing.T) {
input := []byte{0x80}
var tx Transaction
err := rlp.DecodeBytes(input, &tx)
if err != errShortTypedTx {
if !errors.Is(err, errShortTypedTx) {
t.Fatal("wrong error:", err)
}
}
@ -536,7 +536,7 @@ func TestYParityJSONUnmarshalling(t *testing.T) {
// Unmarshal the tx
var tx Transaction
err = tx.UnmarshalJSON(jsonBytes)
if err != test.wantErr {
if !errors.Is(err, test.wantErr) {
t.Fatalf("wrong error: got %v, want %v", err, test.wantErr)
}
})

View file

@ -231,7 +231,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
// when we're in homestead this also counts for code storage gas errors.
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
if !errors.Is(err, ErrExecutionReverted) {
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
}
@ -287,7 +287,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
}
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
if !errors.Is(err, ErrExecutionReverted) {
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
}
@ -334,7 +334,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
}
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
if !errors.Is(err, ErrExecutionReverted) {
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
}
@ -392,7 +392,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
}
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
if !errors.Is(err, ErrExecutionReverted) {
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
}
@ -508,9 +508,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally,
// when we're in homestead this also counts for code storage gas errors.
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
if err != nil && (evm.chainRules.IsHomestead || !errors.Is(err, ErrCodeStoreOutOfGas)) {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
if !errors.Is(err, ErrExecutionReverted) {
contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution)
}
}

View file

@ -44,8 +44,8 @@ func TestMemoryGasCost(t *testing.T) {
}
for i, tt := range tests {
v, err := memoryGasCost(&Memory{}, tt.size)
if (err == ErrGasUintOverflow) != tt.overflow {
t.Errorf("test %d: overflow mismatch: have %v, want %v", i, err == ErrGasUintOverflow, tt.overflow)
if (errors.Is(err, ErrGasUintOverflow)) != tt.overflow {
t.Errorf("test %d: overflow mismatch: have %v, want %v", i, errors.Is(err, ErrGasUintOverflow), tt.overflow)
}
if v != tt.cost {
t.Errorf("test %d: gas cost mismatch: have %v, want %v", i, v, tt.cost)

View file

@ -17,6 +17,7 @@
package vm
import (
"errors"
"math"
"github.com/ethereum/go-ethereum/common"
@ -593,9 +594,9 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
// homestead we must check for CodeStoreOutOfGasError (homestead only
// rule) and treat as an error, if the ruleset is frontier we must
// ignore this error and pretend the operation was successful.
if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
if interpreter.evm.chainRules.IsHomestead && errors.Is(suberr, ErrCodeStoreOutOfGas) {
stackvalue.Clear()
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
} else if suberr != nil && !errors.Is(suberr, ErrCodeStoreOutOfGas) {
stackvalue.Clear()
} else {
stackvalue.SetBytes(addr.Bytes())
@ -604,7 +605,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
if suberr == ErrExecutionReverted {
if errors.Is(suberr, ErrExecutionReverted) {
interpreter.returnData = res // set REVERT data to return data buffer
return res, nil
}
@ -640,7 +641,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
if suberr == ErrExecutionReverted {
if errors.Is(suberr, ErrExecutionReverted) {
interpreter.returnData = res // set REVERT data to return data buffer
return res, nil
}
@ -674,7 +675,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
temp.SetOne()
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
if err == nil || errors.Is(err, ErrExecutionReverted) {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
@ -707,7 +708,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
temp.SetOne()
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
if err == nil || errors.Is(err, ErrExecutionReverted) {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
@ -736,7 +737,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
temp.SetOne()
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
if err == nil || errors.Is(err, ErrExecutionReverted) {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
@ -765,7 +766,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
temp.SetOne()
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
if err == nil || errors.Is(err, ErrExecutionReverted) {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}

View file

@ -17,6 +17,7 @@
package vm
import (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/common"
@ -295,7 +296,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
pc++
}
if err == errStopToken {
if errors.Is(err, ErrExecutionReverted) {
err = nil // clear stop token error
}

View file

@ -8,6 +8,7 @@ import (
"bytes"
"encoding"
"encoding/hex"
"errors"
"fmt"
"hash"
"io"
@ -166,7 +167,7 @@ func testHashes2X(t *testing.T) {
if _, err := h.Read(sum); err != nil {
t.Fatalf("#%d (single write): error from Read: %v", i, err)
}
if n, err := h.Read(sum); n != 0 || err != io.EOF {
if n, err := h.Read(sum); n != 0 || !errors.Is(err, io.EOF) {
t.Fatalf("#%d (single write): Read did not return (0, io.EOF) after exhaustion, got (%v, %v)", i, n, err)
}
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {

View file

@ -228,7 +228,7 @@ func readASCII(buf []byte, r *bufio.Reader) (n int, err error) {
for ; n < len(buf); n++ {
buf[n], err = r.ReadByte()
switch {
case err == io.EOF || buf[n] < '!':
case errors.Is(err, io.EOF) || buf[n] < '!':
return n, nil
case err != nil:
return n, err
@ -242,7 +242,7 @@ func checkKeyFileEnd(r *bufio.Reader) error {
for i := 0; ; i++ {
b, err := r.ReadByte()
switch {
case err == io.EOF:
case errors.Is(err, io.EOF):
return nil
case err != nil:
return err

View file

@ -20,6 +20,7 @@ import (
"bytes"
"crypto/ecdsa"
"encoding/hex"
"errors"
"math/big"
"os"
"reflect"
@ -66,11 +67,11 @@ func BenchmarkSha3(b *testing.B) {
func TestUnmarshalPubkey(t *testing.T) {
key, err := UnmarshalPubkey(nil)
if err != errInvalidPubkey || key != nil {
if !errors.Is(err, errInvalidPubkey) || key != nil {
t.Fatalf("expected error, got %v, %v", err, key)
}
key, err = UnmarshalPubkey([]byte{1, 2, 3})
if err != errInvalidPubkey || key != nil {
if !errors.Is(err, errInvalidPubkey) || key != nil {
t.Fatalf("expected error, got %v, %v", err, key)
}

View file

@ -152,12 +152,12 @@ func TestTooBigSharedKey(t *testing.T) {
}
_, err = prv1.GenerateShared(&prv2.PublicKey, 32, 32)
if err != ErrSharedKeyTooBig {
if !errors.Is(err, ErrSharedKeyTooBig) {
t.Fatal("ecdh: shared key should be too large for curve")
}
_, err = prv2.GenerateShared(&prv1.PublicKey, 32, 32)
if err != ErrSharedKeyTooBig {
if !errors.Is(err, ErrSharedKeyTooBig) {
t.Fatal("ecdh: shared key should be too large for curve")
}
}
@ -355,7 +355,7 @@ func TestBasicKeyValidation(t *testing.T) {
for _, b := range badBytes {
ct[0] = b
_, err := prv.Decrypt(ct, nil, nil)
if err != ErrInvalidPublicKey {
if !errors.Is(err, ErrInvalidPublicKey) {
t.Fatal("ecies: validated an invalid key")
}
}

View file

@ -12,6 +12,7 @@ import (
"crypto/ecdsa"
"crypto/rand"
"encoding/hex"
"errors"
"io"
"testing"
)
@ -91,7 +92,7 @@ func TestInvalidRecoveryID(t *testing.T) {
sig, _ := Sign(msg, seckey)
sig[64] = 99
_, err := RecoverPubkey(msg, sig)
if err != ErrInvalidRecoveryID {
if !errors.Is(err, ErrInvalidRecoveryID) {
t.Fatalf("got %q, want %q", err, ErrInvalidRecoveryID)
}
}

View file

@ -4,29 +4,25 @@ This is a post-mortem concerning the minority split that occurred on Ethereum ma
## Timeline
- 2021-08-17: Guido Vranken submitted a bounty report. Investigation started, root cause identified, patch variations discussed.
- 2021-08-17: Guido Vranken submitted a bounty report. Investigation started, root cause identified, patch variations discussed.
- 2021-08-18: Made public announcement over twitter about upcoming security release upcoming Tuesday. Downstream projects were also notified about the upcoming patch-release.
- 2021-08-24: Released [v1.10.8](https://github.com/ethereum/go-ethereum/releases/tag/v1.10.8) containing the fix on Tuesday morning (CET). Erigon released [v2021.08.04](https://github.com/ledgerwatch/erigon/releases/tag/v2021.08.04).
- 2021-08-27: At 12:50:07 UTC, issue exploited. Analysis started roughly 30m later,
- 2021-08-27: At 12:50:07 UTC, issue exploited. Analysis started roughly 30m later,
## Bounty report
### 2021-08-17 RETURNDATA corruption via datacopy
### 2021-08-17 RETURNDATA corruption via datacopy
On 2021-08-17, Guido Vranken submitted a report to bounty@ethereum.org. This coincided with a geth-meetup in Berlin, so the geth team could fairly quickly analyse the issue.
On 2021-08-17, Guido Vranken submitted a report to bounty@ethereum.org. This coincided with a geth-meetup in Berlin, so the geth team could fairly quickly analyse the issue.
He submitted a proof of concept which called the `dataCopy` precompile, where the input slice and output slice were overlapping but shifted. Doing a `copy` where the `src` and `dest` overlaps is not a problem in itself, however, the `returnData`slice was _also_ using the same memory as a backing-array.
#### Technical details
During CALL-variants, `geth` does not copy the input. This was changed at one point, to avoid a DoS attack reported by Hubert Ritzdorf, to avoid copying data a lot on repeated `CALL`s -- essentially combating a DoS via `malloc`. Further, the datacopy precompile also does not copy the data, but just returns the same slice. This is fine so far.
During CALL-variants, `geth` does not copy the input. This was changed at one point, to avoid a DoS attack reported by Hubert Ritzdorf, to avoid copying data a lot on repeated `CALL`s -- essentially combating a DoS via `malloc`. Further, the datacopy precompile also does not copy the data, but just returns the same slice. This is fine so far.
After the execution of `dataCopy`, we copy the `ret` into the designated memory area, and this is what causes a problem. Because we're copying a slice of memory over a slice of memory, and this operation modifies (shifts) the data in the source -- the `ret`. So this means we wind up with corrupted returndata.
```
1. Calling datacopy
@ -37,62 +33,56 @@ After the execution of `dataCopy`, we copy the `ret` into the designated memory
2. dataCopy returns
returndata (==in, mem[0:4]): [0,1,2,3]
3. Copy in -> out
=> memory: [0,0,1,2,3]
=> returndata: [0,0,1,2]
```
#### Summary
A memory-corruption bug within the EVM can cause a consensus error, where vulnerable nodes obtain a different `stateRoot` when processing a maliciously crafted transaction. This, in turn, would lead to the chain being split: mainnet splitting in two forks.
#### Handling
On the evening of 17th, we discussed options on how to handle it. We made a state test to reproduce the issue, and verified that neither `openethereum`, `nethermind` nor `besu` were affected by the same vulnerability, and started a full-sync with a patched version of `geth`.
On the evening of 17th, we discussed options on how to handle it. We made a state test to reproduce the issue, and verified that neither `openethereum`, `nethermind` nor `besu` were affected by the same vulnerability, and started a full-sync with a patched version of `geth`.
It was decided that in this specific instance, it would be possible to make a public announcement and a patch release:
It was decided that in this specific instance, it would be possible to make a public announcement and a patch release:
- The fix can be made pretty 'generically', e.g. always copying data on input to precompiles.
- The flaw is pretty difficult to find, given a generic fix in the call. The attacker needs to figure out that it concerns the precompiles, specifically the datcopy, and that it concerns the `RETURNDATA` buffer rather than the regular memory, and lastly the special circumstances to trigger it (overlapping but shifted input/output).
- The fix can be made pretty 'generically', e.g. always copying data on input to precompiles.
- The flaw is pretty difficult to find, given a generic fix in the call. The attacker needs to figure out that it concerns the precompiles, specifically the datcopy, and that it concerns the `RETURNDATA` buffer rather than the regular memory, and lastly the special circumstances to trigger it (overlapping but shifted input/output).
Since we had merged the removal of `ETH65`, if the entire network were to upgrade, then nodes which have not yet implemented `ETH66` would be cut off from the network. After further discussions, we decided to:
- Announce an upcoming security release on Tuesday (August 24th), via Twitter and official channels, plus reach out to downstream projects.
- Temporarily revert the `ETH65`-removal.
- Place the fix into the PR optimizing the jumpdest analysis [233381](https://github.com/ethereum/go-ethereum/pull/23381).
- After 4-8 weeks, release details about the vulnerability.
- Place the fix into the PR optimizing the jumpdest analysis [233381](https://github.com/ethereum/go-ethereum/pull/23381).
- After 4-8 weeks, release details about the vulnerability.
## Exploit
At block [13107518](https://etherscan.io/block/13107518), mined at Aug-27-2021 12:50:07 PM +UTC, a minority chain split occurred. The discord user @AlexSSD7 notified the allcoredevs-channel on the Eth R&D discord, on Aug 27 13:09 UTC.
At block [13107518](https://etherscan.io/block/13107518), mined at Aug-27-2021 12:50:07 PM +UTC, a minority chain split occurred. The discord user @AlexSSD7 notified the allcoredevs-channel on the Eth R&D discord, on Aug 27 13:09 UTC.
At 14:09 UTC, it was confirmed that the transaction `0x1cb6fb36633d270edefc04d048145b4298e67b8aa82a9e5ec4aa1435dd770ce4` had triggered the bug, leading to a minority-split of the chain. The term 'minority split' means that the majority of miners continued to mine on the correct chain.
At 14:17 UTC, @mhswende tweeted out about the issue [2].
At 14:17 UTC, @mhswende tweeted out about the issue [2].
The attack was sent from an account funded from Tornado cash.
The attack was sent from an account funded from Tornado cash.
It was also found that the same attack had been carried out on the BSC chain at roughly the same time -- at a block mined [12 minutes earlier](https://bscscan.com/tx/0xf667f820631f6adbd04a4c92274374034a3e41fa9057dc42cb4e787535136dce), at Aug-27-2021 12:38:30 PM +UTC.
The blocks on the 'bad' chain were investigated, and Tim Beiko reached out to those mining operators on the minority chain who could be identified via block extradata.
It was also found that the same attack had been carried out on the BSC chain at roughly the same time -- at a block mined [12 minutes earlier](https://bscscan.com/tx/0xf667f820631f6adbd04a4c92274374034a3e41fa9057dc42cb4e787535136dce), at Aug-27-2021 12:38:30 PM +UTC.
The blocks on the 'bad' chain were investigated, and Tim Beiko reached out to those mining operators on the minority chain who could be identified via block extradata.
## Lessons learned
### Disclosure decision
The geth-team have an official policy regarding [vulnerability disclosure](https://geth.ethereum.org/docs/developers/geth-developer/disclosures).
The geth-team have an official policy regarding [vulnerability disclosure](https://geth.ethereum.org/docs/developers/geth-developer/disclosures).
> The primary goal for the Geth team is the health of the Ethereum network as a whole, and the decision whether or not to publish details about a serious vulnerability boils down to minimizing the risk and/or impact of discovery and exploitation.
In this case, it was decided that public pre-announce + patch would likely lead to sufficient update-window for a critical mass of nodes/miners to upgrade in time before it could be exploited. In hindsight, this was a dangerous decision, and it's unlikely that the same decision would be reached were a similar incident to happen again.
In this case, it was decided that public pre-announce + patch would likely lead to sufficient update-window for a critical mass of nodes/miners to upgrade in time before it could be exploited. In hindsight, this was a dangerous decision, and it's unlikely that the same decision would be reached were a similar incident to happen again.
### Disclosure path
@ -102,7 +92,7 @@ Several subprojects were informed about the upcoming security patch:
- MEV
- Avalanche
- Erigon
- BSC
- BSC
- EWF
- Quorum
- ETC
@ -114,30 +104,29 @@ However, some were 'lost', and only notified later
- Summa
- Harmony
Action point: create a low-volume geth-announce@ethereum.org email list where dependent projects/operators can receive public announcements.
Action point: create a low-volume geth-announce@ethereum.org email list where dependent projects/operators can receive public announcements.
- This has been done. If you wish to receive release- and security announcements, sign up [here](https://groups.google.com/a/ethereum.org/g/geth-announce/about)
### Fork monitoring
The fork monitor behaved 'ok' during the incident, but had to be restarted during the evening.
The fork monitor behaved 'ok' during the incident, but had to be restarted during the evening.
Action point: improve the resiliency of the forkmon, which is currently not performing great when many nodes are connected.
Action point: improve the resiliency of the forkmon, which is currently not performing great when many nodes are connected.
Action point: enable push-based alerts to be sent from the forkmon, to speed up the fork detection.
## Links
- [1] https://twitter.com/go_ethereum/status/1428051458763763721
- [2] https://twitter.com/mhswende/status/1431259601530458112
## Appendix
### Subprojects
The projects were sent variations of the following text:
The projects were sent variations of the following text:
```
We have identified a security issue with go-ethereum, and will issue a
new release (v1.10.8) on Tuesday next week.
@ -150,6 +139,7 @@ issue will be disclosed at a later date.
https://twitter.com/go_ethereum/status/1428051458763763721
```
### Patch
```diff
@ -160,7 +150,7 @@ index f7ef2f900e..6c8c6e6e6f 100644
@@ -669,6 +669,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
if err == nil || errors.Is(err, ErrExecutionReverted) {
+ ret = common.CopyBytes(ret)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
@ -168,7 +158,7 @@ index f7ef2f900e..6c8c6e6e6f 100644
@@ -703,6 +704,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
if err == nil || errors.Is(err, ErrExecutionReverted) {
+ ret = common.CopyBytes(ret)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
@ -176,7 +166,7 @@ index f7ef2f900e..6c8c6e6e6f 100644
@@ -730,6 +732,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
if err == nil || errors.Is(err, ErrExecutionReverted) {
+ ret = common.CopyBytes(ret)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
@ -184,7 +174,7 @@ index f7ef2f900e..6c8c6e6e6f 100644
@@ -757,6 +760,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
if err == nil || errors.Is(err, ErrExecutionReverted) {
+ ret = common.CopyBytes(ret)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
@ -200,7 +190,7 @@ index 9cf0c4e2c1..9fb83799c9 100644
- in.returnData = common.CopyBytes(res)
+ in.returnData = res
}
switch {
```
@ -235,15 +225,9 @@ index 9cf0c4e2c1..9fb83799c9 100644
"gasPrice": "0x1",
"nonce": "0x0",
"to": "0x00000000000000000000000000000000000000bb",
"data": [
"0x"
],
"gasLimit": [
"0x7a1200"
],
"value": [
"0x01"
],
"data": ["0x"],
"gasLimit": ["0x7a1200"],
"value": ["0x01"],
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
},
"out": "0x",
@ -263,4 +247,3 @@ index 9cf0c4e2c1..9fb83799c9 100644
}
}
```

View file

@ -113,7 +113,7 @@ func (api *AdminAPI) ImportChain(file string) (bool, error) {
// Load a batch of blocks from the input file
for len(blocks) < cap(blocks) {
block := new(types.Block)
if err := stream.Decode(block); err == io.EOF {
if err := stream.Decode(block); errors.Is(err, io.EOF) {
break
} else if err != nil {
return false, fmt.Errorf("block %d: failed to parse: %v", index, err)

View file

@ -821,7 +821,7 @@ func (d *Downloader) processSnapSyncContent() error {
}()
closeOnErr := func(s *stateSync) {
if err := s.Wait(); err != nil && err != errCancelStateFetch && err != errCanceled && err != snap.ErrCancelled {
if err := s.Wait(); err != nil && !errors.Is(err, errCancelStateFetch) && !errors.Is(err, errCanceled) && !errors.Is(err, snap.ErrCancelled) {
d.queue.Close() // wake up Results
}
}

View file

@ -278,25 +278,25 @@ func (s *skeleton) startup() {
// signalling as the sync loop should never terminate (TM).
newhead, err := s.sync(head)
switch {
case err == errSyncLinked:
case errors.Is(err, errSyncLinked):
// Sync cycle linked up to the genesis block, or the existent chain
// segment. Tear down the loop and restart it so, it can properly
// notify the backfiller. Don't account a new head.
head = nil
case err == errSyncMerged:
case errors.Is(err, errSyncMerged):
// Subchains were merged, we just need to reinit the internal
// start to continue on the tail of the merged chain. Don't
// announce a new head,
head = nil
case err == errSyncReorged:
case errors.Is(err, errSyncReorged):
// The subchain being synced got modified at the head in a
// way that requires resyncing it. Restart sync with the new
// head to force a cleanup.
head = newhead
case err == errTerminated:
case errors.Is(err, errTerminated):
// Sync was requested to be terminated from within, stop and
// return (no need to pass a message, was already done internally)
return

View file

@ -459,7 +459,7 @@ func TestInvalidGetRangeLogsRequest(t *testing.T) {
api = NewFilterAPI(sys)
)
if _, err := api.GetLogs(context.Background(), FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}); err != errInvalidBlockRange {
if _, err := api.GetLogs(context.Background(), FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}); !errors.Is(err, errInvalidBlockRange) {
t.Errorf("Expected Logs for invalid range return error, but got: %v", err)
}
}

View file

@ -19,6 +19,7 @@ package filters
import (
"context"
"encoding/json"
"errors"
"math/big"
"strings"
"testing"
@ -382,7 +383,7 @@ func TestFilters(t *testing.T) {
if err == nil {
t.Fatal("expected error")
}
if err != context.DeadlineExceeded {
if !errors.Is(err, context.DeadlineExceeded) {
t.Fatalf("expected context.DeadlineExceeded, got %v", err)
}
})

View file

@ -19,6 +19,7 @@ package logger
import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"math/big"
@ -239,7 +240,7 @@ func (l *StructLogger) GetResult() (json.RawMessage, error) {
returnData := common.CopyBytes(l.output)
// Return data when successful and revert reason when reverted, otherwise empty.
returnVal := fmt.Sprintf("%x", returnData)
if failed && l.err != vm.ErrExecutionReverted {
if failed && !errors.Is(l.err, vm.ErrExecutionReverted) {
returnVal = ""
}
return json.Marshal(&ExecutionResult{

View file

@ -398,7 +398,7 @@ func testTransactionInBlock(t *testing.T, client *rpc.Client) {
}
// Test tx in block not found.
if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 20); err != ethereum.NotFound {
if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 20); !errors.Is(err, ethereum.NotFound) {
t.Fatal("error should be ethereum.NotFound")
}

View file

@ -19,6 +19,7 @@ package pebble
import (
"bytes"
"errors"
"fmt"
"runtime"
"sync"
@ -288,7 +289,7 @@ func (d *Database) Has(key []byte) (bool, error) {
return false, pebble.ErrClosed
}
_, closer, err := d.db.Get(key)
if err == pebble.ErrNotFound {
if errors.Is(err, pebble.ErrNotFound) {
return false, nil
} else if err != nil {
return false, err
@ -371,7 +372,7 @@ func (d *Database) NewSnapshot() (ethdb.Snapshot, error) {
func (snap *snapshot) Has(key []byte) (bool, error) {
_, closer, err := snap.db.Get(key)
if err != nil {
if err != pebble.ErrNotFound {
if !errors.Is(err, pebble.ErrNotFound) {
return false, err
} else {
return false, nil

View file

@ -17,6 +17,7 @@
package event
import (
"errors"
"math/rand"
"sync"
"testing"
@ -59,7 +60,7 @@ func TestMuxErrorAfterStop(t *testing.T) {
if _, isopen := <-sub.Chan(); isopen {
t.Errorf("subscription channel was not closed")
}
if err := mux.Post(testEvent(0)); err != ErrMuxClosed {
if err := mux.Post(testEvent(0)); !errors.Is(err, ErrMuxClosed) {
t.Errorf("Post error mismatch, got: %s, expected: %s", err, ErrMuxClosed)
}
}
@ -92,7 +93,7 @@ func TestSubscribeDuplicateType(t *testing.T) {
err := recover()
if err == nil {
t.Errorf("Subscribe didn't panic for duplicate type")
} else if err != expected {
} else if !errors.Is(err, expected) {
t.Errorf("panic mismatch: got %#v, expected %#v", err, expected)
}
}()

View file

@ -56,7 +56,7 @@ loop:
t.Fatalf("wrong int %d, want %d", got, want)
}
case err := <-sub.Err():
if err != errInts {
if !errors.Is(err, errInts) {
t.Fatalf("wrong error: got %q, want %q", err, errInts)
}
if want != 2 {

View file

@ -218,7 +218,7 @@ func extractTarball(ar io.Reader, dest string) error {
// Move to the next file header.
header, err := tr.Next()
if err != nil {
if err == io.EOF {
if errors.Is(err, io.EOF) {
return nil
}
return err

View file

@ -19,6 +19,7 @@ package build
import (
"bufio"
"bytes"
"errors"
"flag"
"fmt"
"go/parser"
@ -97,7 +98,7 @@ func RunGit(args ...string) string {
var stdout, stderr bytes.Buffer
cmd.Stdout, cmd.Stderr = &stdout, &stderr
if err := cmd.Run(); err != nil {
if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound {
if e, ok := err.(*exec.Error); ok && errors.Is(e.Err, exec.ErrNotFound) {
if !warnedAboutGit {
log.Println("Warning: can't find 'git' in PATH")
warnedAboutGit = true

View file

@ -110,7 +110,7 @@ func (r *Reader) ReadAt(entry *Entry, off int64) (int, error) {
n += headerSize
// An entry with a non-zero length should not return EOF when
// reading the value.
if err == io.EOF {
if errors.Is(err, io.EOF) {
return n, io.ErrUnexpectedEOF
}
return n, err
@ -151,7 +151,7 @@ func (r *Reader) LengthAt(off int64) (int64, error) {
func (r *Reader) ReadMetadataAt(off int64) (typ uint16, length uint32, err error) {
b := make([]byte, headerSize)
if n, err := r.r.ReadAt(b, off); err != nil {
if err == io.EOF && n > 0 {
if errors.Is(err, io.EOF) && n > 0 {
return 0, 0, io.ErrUnexpectedEOF
}
return 0, 0, err
@ -177,7 +177,7 @@ func (r *Reader) Find(want uint16) (*Entry, error) {
)
for {
typ, length, err = r.ReadMetadataAt(off)
if err == io.EOF {
if errors.Is(err, io.EOF) {
return nil, io.EOF
} else if err != nil {
return nil, err
@ -204,7 +204,7 @@ func (r *Reader) FindAll(want uint16) ([]*Entry, error) {
)
for {
typ, length, err = r.ReadMetadataAt(off)
if err == io.EOF {
if errors.Is(err, io.EOF) {
return entries, nil
} else if err != nil {
return entries, err

View file

@ -182,7 +182,7 @@ func (it *RawIterator) Number() uint64 {
// Error returns the error status of the iterator. It should be called before
// reading from any of the iterator's values.
func (it *RawIterator) Error() error {
if it.err == io.EOF {
if errors.Is(it.err, io.EOF) {
return nil
}
return it.err

View file

@ -20,6 +20,7 @@ package metrics
import (
"bufio"
"errors"
"fmt"
"io"
"os"
@ -42,7 +43,7 @@ func ReadDiskStats(stats *DiskStats) error {
// Read the next line and split to key and value
line, err := in.ReadString('\n')
if err != nil {
if err == io.EOF {
if errors.Is(err, io.EOF) {
return nil
}
return err

View file

@ -56,7 +56,7 @@ func TestNodeCloseMultipleTimes(t *testing.T) {
// Ensure that a stopped node can be stopped again
for i := 0; i < 3; i++ {
if err := stack.Close(); err != ErrNodeStopped {
if err := stack.Close(); !errors.Is(err, ErrNodeStopped) {
t.Fatalf("iter %d: stop failure mismatch: have %v, want %v", i, err, ErrNodeStopped)
}
}
@ -72,14 +72,14 @@ func TestNodeStartMultipleTimes(t *testing.T) {
if err := stack.Start(); err != nil {
t.Fatalf("failed to start node: %v", err)
}
if err := stack.Start(); err != ErrNodeRunning {
if err := stack.Start(); !errors.Is(err, ErrNodeRunning) {
t.Fatalf("start failure mismatch: have %v, want %v ", err, ErrNodeRunning)
}
// Ensure that a node can be stopped, but only once
if err := stack.Close(); err != nil {
t.Fatalf("failed to stop node: %v", err)
}
if err := stack.Close(); err != ErrNodeStopped {
if err := stack.Close(); !errors.Is(err, ErrNodeStopped) {
t.Fatalf("stop failure mismatch: have %v, want %v ", err, ErrNodeStopped)
}
}
@ -101,7 +101,7 @@ func TestNodeUsedDataDir(t *testing.T) {
// Create a second node based on the same data directory and ensure failure
_, err = New(&Config{DataDir: dir})
if err != ErrDatadirUsed {
if !errors.Is(err, ErrDatadirUsed) {
t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed)
}
}
@ -297,7 +297,7 @@ func TestLifecycleStartupError(t *testing.T) {
stack.RegisterLifecycle(failer)
// Start the protocol stack and ensure all started services stop
if err := stack.Start(); err != failure {
if err := stack.Start(); !errors.Is(err, failure) {
t.Fatalf("stack startup failure mismatch: have %v, want %v", err, failure)
}
for id := range lifecycles {

View file

@ -281,7 +281,7 @@ func (h *httpServer) doStop() {
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
err := h.server.Shutdown(ctx)
if err != nil && err == ctx.Err() {
if err != nil && !errors.Is(err, ctx.Err()) {
h.log.Warn("HTTP server graceful shutdown timed out")
h.server.Close()
}

View file

@ -100,7 +100,7 @@ func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr *
test.t.Errorf("%s encode error: %v", data.Name(), err)
}
test.sent = append(test.sent, enc)
if err = test.udp.handlePacket(addr, enc); err != wantError {
if err = test.udp.handlePacket(addr, enc); !errors.Is(err, wantError) {
test.t.Errorf("error mismatch: got %q, want %q", err, wantError)
}
}
@ -111,7 +111,7 @@ func (test *udpTest) waitPacketOut(validate interface{}) (closed bool) {
test.t.Helper()
dgram, err := test.pipe.receive()
if err == errClosed {
if errors.Is(err, errClosed) {
return true
} else if err != nil {
test.t.Error("packet receive error:", err)
@ -150,7 +150,7 @@ func TestUDPv4_pingTimeout(t *testing.T) {
key := newkey()
toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222}
node := enode.NewV4(&key.PublicKey, toaddr.IP, 0, toaddr.Port)
if _, err := test.udp.ping(node); err != errTimeout {
if _, err := test.udp.ping(node); !errors.Is(err, errTimeout) {
t.Error("expected timeout error, got", err)
}
}
@ -210,7 +210,7 @@ func TestUDPv4_responseTimeouts(t *testing.T) {
for i := 0; i < nReqs; i++ {
select {
case err := <-timeoutErr:
if err != errTimeout {
if !errors.Is(err, errTimeout) {
t.Fatalf("got non-timeout error on timeoutErr %d: %v", i, err)
}
nTimeoutsRecv++
@ -240,7 +240,7 @@ func TestUDPv4_findnodeTimeout(t *testing.T) {
toid := enode.ID{1, 2, 3, 4}
target := v4wire.Pubkey{4, 5, 6, 7}
result, err := test.udp.findnode(toid, toaddr, target)
if err != errTimeout {
if !errors.Is(err, errTimeout) {
t.Error("expected timeout error, got", err)
}
if len(result) > 0 {

View file

@ -20,6 +20,7 @@ import (
"bytes"
"crypto/ecdsa"
"encoding/binary"
"errors"
"fmt"
"math/rand"
"net"
@ -239,7 +240,7 @@ func TestUDPv5_pingCall(t *testing.T) {
done <- err
}()
test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) {})
if err := <-done; err != errTimeout {
if err := <-done; !errors.Is(err, errTimeout) {
t.Fatalf("want errTimeout, got %q", err)
}
@ -264,7 +265,7 @@ func TestUDPv5_pingCall(t *testing.T) {
wrongAddr := &net.UDPAddr{IP: net.IP{33, 44, 55, 22}, Port: 10101}
test.packetInFrom(test.remotekey, wrongAddr, &v5wire.Pong{ReqID: p.ReqID})
})
if err := <-done; err != errTimeout {
if err := <-done; !errors.Is(err, errTimeout) {
t.Fatalf("want errTimeout for reply from wrong IP, got %q", err)
}
}
@ -377,7 +378,7 @@ func TestUDPv5_multipleHandshakeRounds(t *testing.T) {
test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, nonce v5wire.Nonce) {
test.packetIn(&v5wire.Whoareyou{Nonce: nonce})
})
if err := <-done; err != errTimeout {
if err := <-done; !errors.Is(err, errTimeout) {
t.Fatalf("unexpected ping error: %q", err)
}
}
@ -486,7 +487,7 @@ func TestUDPv5_talkRequest(t *testing.T) {
done <- err
}()
test.waitPacketOut(func(p *v5wire.TalkRequest, addr *net.UDPAddr, _ v5wire.Nonce) {})
if err := <-done; err != errTimeout {
if err := <-done; !errors.Is(err, errTimeout) {
t.Fatalf("want errTimeout, got %q", err)
}
@ -817,10 +818,10 @@ func (test *udpV5Test) waitPacketOut(validate interface{}) (closed bool) {
exptype := fn.Type().In(0)
dgram, err := test.pipe.receive()
if err == errClosed {
if errors.Is(err, errClosed) {
return true
}
if err == errTimeout {
if errors.Is(err, errTimeout) {
test.t.Fatalf("timed out waiting for %v", exptype)
return false
}

View file

@ -128,7 +128,7 @@ var (
// returns false, it is pretty certain that the packet causing the error does not belong
// to discv5.
func IsInvalidHeader(err error) bool {
return err == errTooShort || err == errInvalidHeader || err == errMsgTooShort
return errors.Is(err, errTooShort) || errors.Is(err, errInvalidHeader) || errors.Is(err, errMsgTooShort)
}
// Packet sizes.

View file

@ -95,7 +95,7 @@ func TestClientSyncTreeBadNode(t *testing.T) {
c := NewClient(Config{Resolver: r, Logger: testlog.Logger(t, log.LvlTrace)})
_, err := c.SyncTree("enrtree://AKPYQIUQIL7PSIACI32J7FGZW56E5FKHEFCCOFHILBIMW3M6LWXS2@n")
wantErr := nameError{name: "INDMVBZEEQ4ESVYAKGIYU74EAA.n", err: entryError{typ: "enr", err: errInvalidENR}}
if err != wantErr {
if !errors.Is(err, wantErr) {
t.Fatalf("expected sync error %q, got %q", wantErr, err)
}
}

View file

@ -17,6 +17,7 @@
package dnsdisc
import (
"errors"
"reflect"
"testing"
@ -54,7 +55,7 @@ func TestParseRoot(t *testing.T) {
if !reflect.DeepEqual(e, test.e) {
t.Errorf("test %d: wrong entry %s, want %s", i, spew.Sdump(e), spew.Sdump(test.e))
}
if err != test.err {
if !errors.Is(err, test.err) {
t.Errorf("test %d: wrong error %q, want %q", i, err, test.err)
}
}
@ -131,7 +132,7 @@ func TestParseEntry(t *testing.T) {
if !reflect.DeepEqual(e, test.e) {
t.Errorf("test %d: wrong entry %s, want %s", i, spew.Sdump(e), spew.Sdump(test.e))
}
if err != test.err {
if !errors.Is(err, test.err) {
t.Errorf("test %d: wrong error %q, want %q", i, err, test.err)
}
}

View file

@ -228,13 +228,13 @@ func decodeRecord(s *rlp.Stream) (dec Record, raw []byte, err error) {
return dec, raw, err
}
if err = s.Decode(&dec.signature); err != nil {
if err == rlp.EOL {
if errors.Is(err, rlp.EOL) {
err = errIncompleteList
}
return dec, raw, err
}
if err = s.Decode(&dec.seq); err != nil {
if err == rlp.EOL {
if errors.Is(err, rlp.EOL) {
err = errIncompleteList
}
return dec, raw, err
@ -244,13 +244,13 @@ func decodeRecord(s *rlp.Stream) (dec Record, raw []byte, err error) {
for i := 0; ; i++ {
var kv pair
if err := s.Decode(&kv.k); err != nil {
if err == rlp.EOL {
if errors.Is(err, rlp.EOL) {
break
}
return dec, raw, err
}
if err := s.Decode(&kv.v); err != nil {
if err == rlp.EOL {
if errors.Is(err, rlp.EOL) {
return dec, raw, errIncompletePair
}
return dec, raw, err

View file

@ -19,6 +19,7 @@ package enr
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"math/rand"
"testing"
@ -149,7 +150,7 @@ func TestSortedGetAndSet(t *testing.T) {
func TestDirty(t *testing.T) {
var r Record
if _, err := rlp.EncodeToBytes(r); err != errEncodeUnsigned {
if _, err := rlp.EncodeToBytes(r); !errors.Is(err, errEncodeUnsigned) {
t.Errorf("expected errEncodeUnsigned, got %#v", err)
}
@ -164,7 +165,7 @@ func TestDirty(t *testing.T) {
if len(r.signature) != 0 {
t.Error("signature still set after modification")
}
if _, err := rlp.EncodeToBytes(r); err != errEncodeUnsigned {
if _, err := rlp.EncodeToBytes(r); !errors.Is(err, errEncodeUnsigned) {
t.Errorf("expected errEncodeUnsigned, got %#v", err)
}
}
@ -248,7 +249,7 @@ func TestRecordTooBig(t *testing.T) {
// set a big value for random key, expect error
r.Set(WithEntry(key, randomString(SizeLimit)))
if err := signTest([]byte{5}, &r); err != errTooBig {
if err := signTest([]byte{5}, &r); !errors.Is(err, errTooBig) {
t.Fatalf("expected to get errTooBig, got %#v", err)
}
@ -274,7 +275,7 @@ func TestDecodeIncomplete(t *testing.T) {
for _, test := range tests {
var r Record
err := rlp.DecodeBytes(test.input, &r)
if err != test.err {
if !errors.Is(err, test.err) {
t.Errorf("wrong error for %X: %v", test.input, err)
}
}

View file

@ -175,7 +175,7 @@ type KeyError struct {
// Error implements error.
func (err *KeyError) Error() string {
if err.Err == errNotFound {
if errors.Is(err.Err, errNotFound) {
return fmt.Sprintf("missing ENR key %q", err.Key)
}
return fmt.Sprintf("ENR key %q: %v", err.Key, err.Err)
@ -190,7 +190,7 @@ func (err *KeyError) Unwrap() error {
func IsNotFound(err error) bool {
var ke *KeyError
if errors.As(err, &ke) {
return ke.Err == errNotFound
return errors.Is(ke.Err, errNotFound)
}
return false
}

View file

@ -18,6 +18,7 @@ package p2p
import (
"bytes"
"errors"
"fmt"
"io"
"runtime"
@ -55,7 +56,7 @@ loop:
go func() {
if err := SendItems(rw1, 1); err == nil {
t.Error("EncodeMsg returned nil error")
} else if err != ErrPipeClosed {
} else if !errors.Is(err, ErrPipeClosed) {
t.Errorf("EncodeMsg returned wrong error: got %v, want %v", err, ErrPipeClosed)
}
close(done)
@ -91,7 +92,7 @@ func TestEOFSignal(t *testing.T) {
// empty reader
eof := make(chan struct{}, 1)
sig := &eofSignal{new(bytes.Buffer), 0, eof}
if n, err := sig.Read(rb); n != 0 || err != io.EOF {
if n, err := sig.Read(rb); n != 0 || !errors.Is(err, io.EOF) {
t.Errorf("Read returned unexpected values: (%v, %v)", n, err)
}
select {
@ -118,7 +119,7 @@ func TestEOFSignal(t *testing.T) {
if n, err := sig.Read(rb); n != 4 || err != nil {
t.Errorf("Read returned unexpected values: (%v, %v)", n, err)
}
if n, err := sig.Read(rb); n != 0 || err != io.EOF {
if n, err := sig.Read(rb); n != 0 || !errors.Is(err, io.EOF) {
t.Errorf("Read returned unexpected values: (%v, %v)", n, err)
}
select {

View file

@ -17,6 +17,7 @@
package netutil
import (
"errors"
"fmt"
"net"
"reflect"
@ -160,7 +161,7 @@ func TestCheckRelayIP(t *testing.T) {
for _, test := range tests {
err := CheckRelayIP(parseIP(test.sender), parseIP(test.addr))
if err != test.want {
if !errors.Is(err, test.want) {
t.Errorf("%s from %s: got %q, want %q", test.addr, test.sender, err, test.want)
}
}

View file

@ -20,6 +20,7 @@
package netutil
import (
"errors"
"net"
"os"
"syscall"
@ -33,9 +34,9 @@ const _WSAEMSGSIZE = syscall.Errno(10040)
func isPacketTooBig(err error) bool {
if opErr, ok := err.(*net.OpError); ok {
if scErr, ok := opErr.Err.(*os.SyscallError); ok {
return scErr.Err == _WSAEMSGSIZE
return errors.Is(scErr.Err, _WSAEMSGSIZE)
}
return opErr.Err == _WSAEMSGSIZE
return errors.Is(opErr.Err, _WSAEMSGSIZE)
}
return false
}

View file

@ -138,7 +138,7 @@ func TestPeerProtoReadMsg(t *testing.T) {
select {
case err := <-errc:
if err != errProtocolReturned {
if !errors.Is(err, errProtocolReturned) {
t.Errorf("peer returned error: %v", err)
}
case <-time.After(2 * time.Second):

View file

@ -280,7 +280,7 @@ func TestServerAtCap(t *testing.T) {
// Try inserting a non-trusted connection.
anotherID := randomID()
c := newconn(anotherID)
if err := srv.checkpoint(c, srv.checkpointPostHandshake); err != DiscTooManyPeers {
if err := srv.checkpoint(c, srv.checkpointPostHandshake); !errors.Is(err, DiscTooManyPeers) {
t.Error("wrong error for insert:", err)
}
// Try inserting a trusted connection.
@ -295,7 +295,7 @@ func TestServerAtCap(t *testing.T) {
// Remove from trusted set and try again
srv.RemoveTrustedPeer(newNode(trustedID, ""))
c = newconn(trustedID)
if err := srv.checkpoint(c, srv.checkpointPostHandshake); err != DiscTooManyPeers {
if err := srv.checkpoint(c, srv.checkpointPostHandshake); !errors.Is(err, DiscTooManyPeers) {
t.Error("wrong error for insert:", err)
}
@ -345,7 +345,7 @@ func TestServerPeerLimits(t *testing.T) {
dialDest := clientnode
conn, _ := net.Pipe()
srv.SetupConn(conn, flags, dialDest)
if tp.closeErr != DiscTooManyPeers {
if !errors.Is(tp.closeErr, DiscTooManyPeers) {
t.Errorf("unexpected close error: %q", tp.closeErr)
}
conn.Close()
@ -355,11 +355,11 @@ func TestServerPeerLimits(t *testing.T) {
// Check that server allows a trusted peer despite being full.
conn, _ = net.Pipe()
srv.SetupConn(conn, flags, dialDest)
if tp.closeErr == DiscTooManyPeers {
if errors.Is(tp.closeErr, DiscTooManyPeers) {
t.Errorf("failed to bypass MaxPeers with trusted node: %q", tp.closeErr)
}
if tp.closeErr != DiscUselessPeer {
if !errors.Is(tp.closeErr, DiscUselessPeer) {
t.Errorf("unexpected close error: %q", tp.closeErr)
}
conn.Close()
@ -369,7 +369,7 @@ func TestServerPeerLimits(t *testing.T) {
// Check that server is full again.
conn, _ = net.Pipe()
srv.SetupConn(conn, flags, dialDest)
if tp.closeErr != DiscTooManyPeers {
if !errors.Is(tp.closeErr, DiscTooManyPeers) {
t.Errorf("unexpected close error: %q", tp.closeErr)
}
conn.Close()
@ -564,7 +564,7 @@ func TestServerInboundThrottle(t *testing.T) {
go func() {
conn.SetDeadline(time.Now().Add(timeout))
buf := make([]byte, 10)
if n, err := conn.Read(buf); err != io.EOF || n != 0 {
if n, err := conn.Read(buf); !errors.Is(err, io.EOF) || n != 0 {
t.Errorf("expected io.EOF and n == 0, got error %q and n == %d", err, n)
}
connClosed <- struct{}{}

View file

@ -326,7 +326,7 @@ func decodeSliceElems(s *Stream, val reflect.Value, elemdec decoder) error {
val.SetLen(i + 1)
}
// decode into element
if err := elemdec(s, val.Index(i)); err == EOL {
if err := elemdec(s, val.Index(i)); errors.Is(err, EOL) {
break
} else if err != nil {
return addErrorContext(err, fmt.Sprint("[", i, "]"))
@ -345,7 +345,7 @@ func decodeListArray(s *Stream, val reflect.Value, elemdec decoder) error {
vlen := val.Len()
i := 0
for ; i < vlen; i++ {
if err := elemdec(s, val.Index(i)); err == EOL {
if err := elemdec(s, val.Index(i)); errors.Is(err, EOL) {
break
} else if err != nil {
return addErrorContext(err, fmt.Sprint("[", i, "]"))
@ -417,7 +417,7 @@ func makeStructDecoder(typ reflect.Type) (decoder, error) {
}
for i, f := range fields {
err := f.info.decoder(s, val.Field(f.index))
if err == EOL {
if errors.Is(err, EOL) {
if f.optional {
// The field is optional, so reaching the end of the list before
// reaching the last field is acceptable. All remaining undecoded
@ -757,7 +757,7 @@ func (s *Stream) uint(maxbits int) (uint64, error) {
}
v, err := s.readUint(byte(size))
switch {
case err == ErrCanonSize:
case errors.Is(err, ErrCanonSize):
// Adjust error because we're not reading a size right now.
return 0, ErrCanonInt
case err != nil:
@ -1129,7 +1129,7 @@ func (s *Stream) readFull(buf []byte) (err error) {
nn, err = s.r.Read(buf[n:])
n += nn
}
if err == io.EOF {
if errors.Is(err, io.EOF) {
if n < len(buf) {
err = io.ErrUnexpectedEOF
} else {
@ -1147,7 +1147,7 @@ func (s *Stream) readByte() (byte, error) {
return 0, err
}
b, err := s.r.ReadByte()
if err == io.EOF {
if errors.Is(err, io.EOF) {
err = io.ErrUnexpectedEOF
}
return b, err

View file

@ -250,7 +250,7 @@ func TestStreamList(t *testing.T) {
}
}
if _, err := s.Uint(); err != EOL {
if _, err := s.Uint(); !errors.Is(err, EOL) {
t.Errorf("Uint error mismatch, got %v, want %v", err, EOL)
}
if err = s.ListEnd(); err != nil {
@ -331,25 +331,25 @@ func TestStreamReadBytes(t *testing.T) {
func TestDecodeErrors(t *testing.T) {
r := bytes.NewReader(nil)
if err := Decode(r, nil); err != errDecodeIntoNil {
if err := Decode(r, nil); !errors.Is(err, errDecodeIntoNil) {
t.Errorf("Decode(r, nil) error mismatch, got %q, want %q", err, errDecodeIntoNil)
}
var nilptr *struct{}
if err := Decode(r, nilptr); err != errDecodeIntoNil {
if err := Decode(r, nilptr); !errors.Is(err, errDecodeIntoNil) {
t.Errorf("Decode(r, nilptr) error mismatch, got %q, want %q", err, errDecodeIntoNil)
}
if err := Decode(r, struct{}{}); err != errNoPointer {
if err := Decode(r, struct{}{}); !errors.Is(err, errNoPointer) {
t.Errorf("Decode(r, struct{}{}) error mismatch, got %q, want %q", err, errNoPointer)
}
expectErr := "rlp: type chan bool is not RLP-serializable"
if err := Decode(r, new(chan bool)); err == nil || err.Error() != expectErr {
expectErr := errors.New("rlp: type chan bool is not RLP-serializable")
if err := Decode(r, new(chan bool)); !errors.Is(err, expectErr) {
t.Errorf("Decode(r, new(chan bool)) error mismatch, got %q, want %q", err, expectErr)
}
if err := Decode(r, new(uint)); err != io.EOF {
if err := Decode(r, new(uint)); !errors.Is(err, io.EOF) {
t.Errorf("Decode(r, new(int)) error mismatch, got %q, want %q", err, io.EOF)
}
}

View file

@ -476,7 +476,7 @@ func TestEncodeToReaderPiecewise(t *testing.T) {
}
n, err := r.Read(output[start:end])
end = start + n
if err == io.EOF {
if errors.Is(err, io.EOF) {
break
} else if err != nil {
return nil, err

View file

@ -129,7 +129,7 @@ func TestSplitUint64(t *testing.T) {
if !bytes.Equal(rest, unhex(test.rest)) {
t.Errorf("test %d: rest mismatch: got %x, want %s (input %q)", i, rest, test.rest, test.input)
}
if err != test.err {
if !errors.Is(err, test.err) {
t.Errorf("test %d: error mismatch: got %q, want %q", i, err, test.err)
}
}
@ -213,7 +213,7 @@ func TestSplit(t *testing.T) {
if !bytes.Equal(rest, unhex(test.rest)) {
t.Errorf("test %d: rest mismatch: got %x, want %s", i, rest, test.rest)
}
if err != test.err {
if !errors.Is(err, test.err) {
t.Errorf("test %d: error mismatch: got %q, want %q", i, err, test.err)
}
}
@ -251,7 +251,7 @@ func TestReadSize(t *testing.T) {
for _, test := range tests {
size, err := readSize(unhex(test.input), test.slen)
if err != test.err {
if !errors.Is(err, test.err) {
t.Errorf("readSize(%s, %d): error mismatch: got %q, want %q", test.input, test.slen, err, test.err)
continue
}

View file

@ -636,7 +636,7 @@ func TestClientNotificationStorm(t *testing.T) {
t.Fatalf("(%d/%d) unexpected value %d", i, count, val)
}
case err := <-sub.Err():
if wantError && err != ErrSubscriptionQueueOverflow {
if wantError && !errors.Is(err, ErrSubscriptionQueueOverflow) {
t.Fatalf("(%d/%d) got error %q, want %q", i, count, err, ErrSubscriptionQueueOverflow)
} else if !wantError {
t.Fatalf("(%d/%d) got unexpected error %q", i, count, err)

View file

@ -18,6 +18,7 @@ package rpc
import (
"context"
"errors"
"fmt"
"net/http"
"net/http/httptest"
@ -234,12 +235,12 @@ func TestNewContextWithHeaders(t *testing.T) {
ctx3 := NewContextWithHeaders(ctx2, newHdr("key-2", "val-2"))
expectedHeaders = 3
if err := client.CallContext(ctx3, nil, "test"); err != ErrNoResult {
if err := client.CallContext(ctx3, nil, "test"); !errors.Is(err, ErrNoResult) {
t.Error("call failed", err)
}
expectedHeaders = 2
if err := client.CallContext(ctx2, nil, "test"); err != ErrNoResult {
if err := client.CallContext(ctx2, nil, "test"); !errors.Is(err, ErrNoResult) {
t.Error("call failed:", err)
}
}

View file

@ -311,7 +311,7 @@ func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]
var args []reflect.Value
tok, err := dec.Token()
switch {
case err == io.EOF || tok == nil && err == nil:
case errors.Is(err, io.EOF) || tok == nil && err == nil:
// "params" is optional and may be empty. Also allow "params":null even though it's
// not in the spec because our own client used to send it.
case err != nil:

View file

@ -18,6 +18,7 @@ package rpc
import (
"context"
"errors"
"io"
"sync"
"sync/atomic"
@ -151,7 +152,7 @@ func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) {
reqs, batch, err := codec.readBatch()
if err != nil {
if err != io.EOF {
if !errors.Is(err, io.EOF) {
resp := errorMessage(&invalidMessageError{"parse error"})
codec.writeJSON(ctx, resp, true)
}

View file

@ -304,7 +304,7 @@ func (sub *ClientSubscription) run() {
// Send the error.
if err != nil {
if err == ErrClientQuit {
if errors.Is(err, ErrClientQuit) {
// ErrClientQuit gets here when Client.Close is called. This is reported as a
// nil error because it's not an error, but we can't close sub.err here.
err = nil
@ -340,7 +340,7 @@ func (sub *ClientSubscription) forward() (unsubscribeServer bool, err error) {
if !recv.IsNil() {
err = recv.Interface().(error)
}
if err == errUnsubscribed {
if errors.Is(err, errUnsubscribed) {
// Exiting because Unsubscribe was called, unsubscribe on server.
return true, nil
}

View file

@ -159,7 +159,7 @@ func TestWebsocketLargeRead(t *testing.T) {
// Check over limit
if overLimit > 0 {
err = client.Call(&res, "test_repeat", "A", expLimit+1)
if err == nil || err != websocket.ErrReadLimit {
if err == nil || !errors.Is(err, websocket.ErrReadLimit) {
t.Fatalf("wrong error with limit %d: %v expecting %v", expLimit, err, websocket.ErrReadLimit)
}
}

View file

@ -332,7 +332,7 @@ func (api *SignerAPI) startUSBListener() {
for _, wallet := range am.Wallets() {
if err := wallet.Open(""); err != nil {
log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
if err == usbwallet.ErrTrezorPINNeeded {
if errors.Is(err, usbwallet.ErrTrezorPINNeeded) {
go api.openTrezor(wallet.URL())
}
}
@ -348,7 +348,7 @@ func (api *SignerAPI) derivationLoop(events chan accounts.WalletEvent) {
case accounts.WalletArrived:
if err := event.Wallet.Open(""); err != nil {
log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
if err == usbwallet.ErrTrezorPINNeeded {
if errors.Is(err, usbwallet.ErrTrezorPINNeeded) {
go api.openTrezor(event.Wallet.URL())
}
}

View file

@ -19,6 +19,7 @@ package core_test
import (
"bytes"
"context"
"errors"
"fmt"
"math/big"
"os"
@ -155,7 +156,7 @@ func failCreateAccountWithPassword(ui *headlessUi, api *core.SignerAPI, password
func failCreateAccount(ui *headlessUi, api *core.SignerAPI, t *testing.T) {
ui.approveCh <- "N"
addr, err := api.New(context.Background())
if err != core.ErrRequestDenied {
if !errors.Is(err, core.ErrRequestDenied) {
t.Fatal(err)
}
if addr != (common.Address{}) {
@ -212,7 +213,7 @@ func TestNewAcc(t *testing.T) {
if len(list) != 0 {
t.Fatalf("List should be empty")
}
if err != core.ErrRequestDenied {
if !errors.Is(err, core.ErrRequestDenied) {
t.Fatal("Expected deny")
}
}
@ -264,7 +265,7 @@ func TestSignTx(t *testing.T) {
if res != nil {
t.Errorf("Expected nil-response, got %v", res)
}
if err != keystore.ErrDecrypt {
if !errors.Is(err, keystore.ErrDecrypt) {
t.Errorf("Expected ErrLocked! %v", err)
}
control.approveCh <- "No way"
@ -272,7 +273,7 @@ func TestSignTx(t *testing.T) {
if res != nil {
t.Errorf("Expected nil-response, got %v", res)
}
if err != core.ErrRequestDenied {
if !errors.Is(err, core.ErrRequestDenied) {
t.Errorf("Expected ErrRequestDenied! %v", err)
}
// Sign with correct password

View file

@ -20,6 +20,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"math/big"
"os"
@ -201,7 +202,7 @@ func TestSignData(t *testing.T) {
if signature != nil {
t.Errorf("Expected nil-data, got %x", signature)
}
if err != keystore.ErrDecrypt {
if !errors.Is(err, keystore.ErrDecrypt) {
t.Errorf("Expected ErrLocked! '%v'", err)
}
control.approveCh <- "No way"
@ -209,7 +210,7 @@ func TestSignData(t *testing.T) {
if signature != nil {
t.Errorf("Expected nil-data, got %x", signature)
}
if err != core.ErrRequestDenied {
if !errors.Is(err, core.ErrRequestDenied) {
t.Errorf("Expected ErrRequestDenied! '%v'", err)
}
// text/plain

View file

@ -268,7 +268,7 @@ func (it *nodeIterator) NodeBlob() []byte {
}
func (it *nodeIterator) Error() error {
if it.err == errIteratorEnd {
if errors.Is(it.err, errIteratorEnd) {
return nil
}
if seek, ok := it.err.(seekError); ok {
@ -282,7 +282,7 @@ func (it *nodeIterator) Error() error {
// sets the Error field to the encountered failure. If `descend` is false,
// skips iterating over any subnodes of the current node.
func (it *nodeIterator) Next(descend bool) bool {
if it.err == errIteratorEnd {
if errors.Is(it.err, errIteratorEnd) {
return false
}
if seek, ok := it.err.(seekError); ok {
@ -307,7 +307,7 @@ func (it *nodeIterator) seek(prefix []byte) error {
// Move forward until we're just before the closest match to key.
for {
state, parentIndex, path, err := it.peekSeek(key)
if err == errIteratorEnd {
if errors.Is(err, errIteratorEnd) {
return errIteratorEnd
} else if err != nil {
return seekError{prefix, err}

View file

@ -187,7 +187,7 @@ func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) {
var root common.Hash
if err := r.Decode(&root); err != nil {
// The first read may fail with EOF, marking the end of the journal
if err == io.EOF {
if errors.Is(err, io.EOF) {
return parent, nil
}
return nil, fmt.Errorf("load diff root: %v", err)