diff --git a/core/state_transition.go b/core/state_transition.go
index 148a319d5047c885d95832027ffa5798c45bd176..58bf689ebdd73ebcb56487d298f94d866123c2bc 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -203,12 +203,21 @@ func (st *StateTransition) to() common.Address {
 func (st *StateTransition) buyGas(gasBailout bool) error {
 	mgval := st.sharedBuyGas
 	mgval.SetUint64(st.msg.Gas())
-	mgval = mgval.Mul(mgval, st.gasPrice)
+	mgval, overflow := mgval.MulOverflow(mgval, st.gasPrice)
+	if overflow {
+		return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex())
+	}
 	balanceCheck := mgval
 	if st.gasFeeCap != nil {
 		balanceCheck = st.sharedBuyGasBalance.SetUint64(st.msg.Gas())
-		balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap)
-		balanceCheck.Add(balanceCheck, st.value)
+		balanceCheck, overflow = balanceCheck.MulOverflow(balanceCheck, st.gasFeeCap)
+		if overflow {
+			return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex())
+		}
+		balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, st.value)
+		if overflow {
+			return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex())
+		}
 	}
 	if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
 		if !gasBailout {
diff --git a/core/types/access_list_tx.go b/core/types/access_list_tx.go
index 0dd411854457fe685a65acc91055033ac2c598e4..d46031efdb072abd4bf67629d7a9989607b45d57 100644
--- a/core/types/access_list_tx.go
+++ b/core/types/access_list_tx.go
@@ -465,22 +465,16 @@ func (tx *AccessListTx) DecodeRLP(s *rlp.Stream) error {
 		return err
 	}
 	var b []byte
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read ChainID: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for ChainID: %d", len(b))
-	}
 	tx.ChainID = new(uint256.Int).SetBytes(b)
 	if tx.Nonce, err = s.Uint(); err != nil {
 		return fmt.Errorf("read Nonce: %w", err)
 	}
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read GasPrice: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for GasPrice: %d", len(b))
-	}
 	tx.GasPrice = new(uint256.Int).SetBytes(b)
 	if tx.Gas, err = s.Uint(); err != nil {
 		return fmt.Errorf("read Gas: %w", err)
@@ -495,12 +489,9 @@ func (tx *AccessListTx) DecodeRLP(s *rlp.Stream) error {
 		tx.To = &common.Address{}
 		copy((*tx.To)[:], b)
 	}
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read Value: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for Value: %d", len(b))
-	}
 	tx.Value = new(uint256.Int).SetBytes(b)
 	if tx.Data, err = s.Bytes(); err != nil {
 		return fmt.Errorf("read Data: %w", err)
@@ -511,26 +502,17 @@ func (tx *AccessListTx) DecodeRLP(s *rlp.Stream) error {
 		return fmt.Errorf("read AccessList: %w", err)
 	}
 	// decode V
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read V: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for V: %d", len(b))
-	}
 	tx.V.SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read R: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for R: %d", len(b))
-	}
 	tx.R.SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read S: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for S: %d", len(b))
-	}
 	tx.S.SetBytes(b)
 	if err := s.ListEnd(); err != nil {
 		return fmt.Errorf("close AccessListTx: %w", err)
diff --git a/core/types/block.go b/core/types/block.go
index 2e99de7d501cbf74528821d0bb20b70be2e8001c..969b9cdbb893222e3668d61339ea53be6e863f09 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -486,19 +486,13 @@ func (h *Header) DecodeRLP(s *rlp.Stream) error {
 		return fmt.Errorf("wrong size for Bloom: %d", len(b))
 	}
 	copy(h.Bloom[:], b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read Difficulty: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for Difficulty: %d", len(b))
-	}
 	h.Difficulty = new(big.Int).SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read Number: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for Number: %d", len(b))
-	}
 	h.Number = new(big.Int).SetBytes(b)
 	if h.GasLimit, err = s.Uint(); err != nil {
 		return fmt.Errorf("read GasLimit: %w", err)
@@ -536,7 +530,7 @@ func (h *Header) DecodeRLP(s *rlp.Stream) error {
 			return fmt.Errorf("wrong size for Nonce: %d", len(b))
 		}
 		copy(h.Nonce[:], b)
-		if b, err = s.Bytes(); err != nil {
+		if b, err = s.Uint256Bytes(); err != nil {
 			if errors.Is(err, rlp.EOL) {
 				h.BaseFee = nil
 				h.Eip1559 = false
@@ -547,9 +541,6 @@ func (h *Header) DecodeRLP(s *rlp.Stream) error {
 			}
 			return fmt.Errorf("read BaseFee: %w", err)
 		}
-		if len(b) > 32 {
-			return fmt.Errorf("wrong size for BaseFee: %d", len(b))
-		}
 		h.Eip1559 = true
 		h.BaseFee = new(big.Int).SetBytes(b)
 	}
diff --git a/core/types/dynamic_fee_tx.go b/core/types/dynamic_fee_tx.go
index fce6d6197d1a450c7ddcf4a7bcc885399b3288a5..ed8b99d446ff64b7fefef04ff4f4354478b2b661 100644
--- a/core/types/dynamic_fee_tx.go
+++ b/core/types/dynamic_fee_tx.go
@@ -378,29 +378,20 @@ func (tx *DynamicFeeTransaction) DecodeRLP(s *rlp.Stream) error {
 		return err
 	}
 	var b []byte
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for ChainID: %d", len(b))
-	}
 	tx.ChainID = new(uint256.Int).SetBytes(b)
 	if tx.Nonce, err = s.Uint(); err != nil {
 		return err
 	}
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for MaxPriorityFeePerGas: %d", len(b))
-	}
 	tx.Tip = new(uint256.Int).SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for MaxFeePerGas: %d", len(b))
-	}
 	tx.FeeCap = new(uint256.Int).SetBytes(b)
 	if tx.Gas, err = s.Uint(); err != nil {
 		return err
@@ -415,12 +406,9 @@ func (tx *DynamicFeeTransaction) DecodeRLP(s *rlp.Stream) error {
 		tx.To = &common.Address{}
 		copy((*tx.To)[:], b)
 	}
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for Value: %d", len(b))
-	}
 	tx.Value = new(uint256.Int).SetBytes(b)
 	if tx.Data, err = s.Bytes(); err != nil {
 		return err
@@ -431,26 +419,17 @@ func (tx *DynamicFeeTransaction) DecodeRLP(s *rlp.Stream) error {
 		return err
 	}
 	// decode V
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for V: %d", len(b))
-	}
 	tx.V.SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for R: %d", len(b))
-	}
 	tx.R.SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for S: %d", len(b))
-	}
 	tx.S.SetBytes(b)
 	return s.ListEnd()
 
diff --git a/core/types/legacy_tx.go b/core/types/legacy_tx.go
index 36f8566d815c09163417bb1660c32fe390a74b02..24a4db88b6b3d41fce6f8aaaabe33bfd99b1eea2 100644
--- a/core/types/legacy_tx.go
+++ b/core/types/legacy_tx.go
@@ -369,12 +369,9 @@ func (tx *LegacyTx) DecodeRLP(s *rlp.Stream, encodingSize uint64) error {
 		return fmt.Errorf("read Nonce: %w", err)
 	}
 	var b []byte
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read GasPrice: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for GasPrice: %d", len(b))
-	}
 	tx.GasPrice = new(uint256.Int).SetBytes(b)
 	if tx.Gas, err = s.Uint(); err != nil {
 		return fmt.Errorf("read Gas: %w", err)
@@ -389,36 +386,24 @@ func (tx *LegacyTx) DecodeRLP(s *rlp.Stream, encodingSize uint64) error {
 		tx.To = &common.Address{}
 		copy((*tx.To)[:], b)
 	}
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read Value: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for Value: %d", len(b))
-	}
 	tx.Value = new(uint256.Int).SetBytes(b)
 	if tx.Data, err = s.Bytes(); err != nil {
 		return fmt.Errorf("read Data: %w", err)
 	}
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read V: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for V: %d", len(b))
-	}
 	tx.V.SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read R: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for R: %d", len(b))
-	}
 	tx.R.SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read S: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for S: %d", len(b))
-	}
 	tx.S.SetBytes(b)
 	if err = s.ListEnd(); err != nil {
 		return fmt.Errorf("close tx struct: %w", err)
diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go
index 3efba04159ba795c51643fa9ad44f16614b8cb3b..a8338662bcbba9d552551d6afa45b3cbb3ec6fdc 100644
--- a/eth/protocols/eth/protocol.go
+++ b/eth/protocols/eth/protocol.go
@@ -373,12 +373,9 @@ func (nbp *NewBlockPacket) DecodeRLP(s *rlp.Stream) error {
 	}
 	// decode TD
 	var b []byte
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return fmt.Errorf("read TD: %w", err)
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for TD: %d", len(b))
-	}
 	nbp.TD = new(big.Int).SetBytes(b)
 	if err = s.ListEnd(); err != nil {
 		return err
diff --git a/rlp/decode.go b/rlp/decode.go
index fefca41ff3c6421c6c1ceccf29be645c00fa9d9e..1568bb60e1d4cfa66de0c996db98e1328f5ebccb 100644
--- a/rlp/decode.go
+++ b/rlp/decode.go
@@ -242,19 +242,17 @@ func decodeBigIntNoPtr(s *Stream, val reflect.Value) error {
 }
 
 func decodeBigInt(s *Stream, val reflect.Value) error {
-	b, err := s.Bytes()
+	b, err := s.bigIntBytes()
 	if err != nil {
 		return wrapStreamError(err, val.Type())
 	}
+
+	// Set the integer bytes.
 	i := val.Interface().(*big.Int)
 	if i == nil {
 		i = new(big.Int)
 		val.Set(reflect.ValueOf(i))
 	}
-	// Reject leading zero bytes
-	if len(b) > 0 && b[0] == 0 {
-		return wrapStreamError(ErrCanonInt, val.Type())
-	}
 	i.SetBytes(b)
 	return nil
 }
@@ -264,22 +262,17 @@ func decodeUint256NoPtr(s *Stream, val reflect.Value) error {
 }
 
 func decodeUint256(s *Stream, val reflect.Value) error {
-	b, err := s.Bytes()
+	b, err := s.Uint256Bytes()
 	if err != nil {
 		return wrapStreamError(err, val.Type())
 	}
-	if len(b) > 32 {
-		return wrapStreamError(errUintOverflow, val.Type())
-	}
+
+	// Set the integer bytes.
 	i := val.Interface().(*uint256.Int)
 	if i == nil {
 		i = new(uint256.Int)
 		val.Set(reflect.ValueOf(i))
 	}
-	// Reject leading zero bytes
-	if len(b) > 0 && b[0] == 0 {
-		return wrapStreamError(ErrCanonInt, val.Type())
-	}
 	i.SetBytes(b)
 	return nil
 }
@@ -599,7 +592,7 @@ type Stream struct {
 	limited   bool
 
 	// auxiliary buffer for integer decoding
-	uintbuf []byte
+	uintbuf [32]byte
 
 	kind    Kind   // kind of value ahead
 	size    uint64 // size of value ahead
@@ -734,6 +727,59 @@ func (s *Stream) uint(maxbits int) (uint64, error) {
 	}
 }
 
+func (s *Stream) Uint256Bytes() ([]byte, error) {
+	b, err := s.bigIntBytes()
+	if err != nil {
+		return nil, err
+	}
+	if len(b) > 32 {
+		return nil, errUintOverflow
+	}
+	return b, nil
+}
+
+func (s *Stream) bigIntBytes() ([]byte, error) {
+	var buffer []byte
+	kind, size, err := s.Kind()
+	switch {
+	case err != nil:
+		return nil, err
+	case kind == List:
+		return nil, ErrExpectedString
+	case kind == Byte:
+		buffer = s.uintbuf[:1]
+		buffer[0] = s.byteval
+		s.kind = -1 // re-arm Kind
+	case size == 0:
+		// Avoid zero-length read.
+		s.kind = -1
+	case size <= uint64(len(s.uintbuf)):
+		// For integers smaller than s.uintbuf, allocating a buffer
+		// can be avoided.
+		buffer = s.uintbuf[:size]
+		if err := s.readFull(buffer); err != nil {
+			return nil, err
+		}
+		// Reject inputs where single byte encoding should have been used.
+		if size == 1 && buffer[0] < 128 {
+			return nil, ErrCanonSize
+		}
+	default:
+		// For large integers, a temporary buffer is needed.
+		buffer = make([]byte, size)
+		if err := s.readFull(buffer); err != nil {
+			return nil, err
+		}
+	}
+
+	// Reject leading zero bytes.
+	if len(buffer) > 0 && buffer[0] == 0 {
+		return nil, ErrCanonInt
+	}
+
+	return buffer, nil
+}
+
 // Bool reads an RLP string of up to 1 byte and returns its contents
 // as a boolean. If the input does not contain an RLP string, the
 // returned error will be ErrExpectedString.
@@ -856,9 +902,7 @@ func (s *Stream) Reset(r io.Reader, inputLimit uint64) {
 	s.size = 0
 	s.kind = -1
 	s.kinderr = nil
-	if s.uintbuf == nil {
-		s.uintbuf = make([]byte, 8)
-	}
+	s.uintbuf = [32]byte{}
 	s.byteval = 0
 }
 
@@ -977,20 +1021,20 @@ func (s *Stream) readUint(size byte) (uint64, error) {
 		b, err := s.readByte()
 		return uint64(b), err
 	default:
-		start := int(8 - size)
-		for i := 0; i < start; i++ {
-			s.uintbuf[i] = 0
+		buffer := s.uintbuf[:8]
+		for i := range buffer {
+			buffer[i] = 0
 		}
-		if err := s.readFull(s.uintbuf[start:]); err != nil {
+		start := int(8 - size)
+		if err := s.readFull(buffer[start:]); err != nil {
 			return 0, err
 		}
-		if s.uintbuf[start] == 0 {
-			// Note: readUint is also used to decode integer
-			// values. The error needs to be adjusted to become
-			// ErrCanonInt in this case.
+		if buffer[start] == 0 {
+			// Note: readUint is also used to decode integer values.
+			// The error needs to be adjusted to become ErrCanonInt in this case.
 			return 0, ErrCanonSize
 		}
-		return binary.BigEndian.Uint64(s.uintbuf), nil
+		return binary.BigEndian.Uint64(buffer), nil
 	}
 }
 
diff --git a/rlp/decode_test.go b/rlp/decode_test.go
index 4e308324426c008ba4e219f97d4bc275edf89e94..c91e4865d5df0b10050888a7ad6d90e9f8e6da65 100644
--- a/rlp/decode_test.go
+++ b/rlp/decode_test.go
@@ -327,6 +327,11 @@ type recstruct struct {
 	Child *recstruct `rlp:"nil"`
 }
 
+type bigIntStruct struct {
+	I *big.Int
+	B string
+}
+
 type invalidNilTag struct {
 	X []byte `rlp:"nil"`
 }
@@ -374,7 +379,8 @@ var (
 		uint256.NewInt(0).Lsh(uint256.NewInt(0xFFFFFFFFFFFFFF), 16),
 		uint256.NewInt(0xFFFF),
 	)
-	realBigInt = big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000"))
+	realBigInt     = big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000"))
+	veryVeryBigInt = new(big.Int).Exp(veryBigInt.ToBig(), big.NewInt(8), nil)
 )
 
 type hasIgnoredField struct {
@@ -451,13 +457,16 @@ var decodeTests = []decodeTest{
 	{input: "C0", ptr: new(string), error: "rlp: expected input string or byte for string"},
 
 	// big ints
+	{input: "80", ptr: new(*big.Int), value: big.NewInt(0)},
 	{input: "01", ptr: new(*big.Int), value: big.NewInt(1)},
 	{input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*big.Int), value: veryBigInt.ToBig()},
 	{input: "A1010000000000000000000000000000000000000000000000000000000000000000", ptr: new(*big.Int), value: realBigInt},
+	{input: "B848FFFFFFFFFFFFFFFFF800000000000000001BFFFFFFFFFFFFFFFFC8000000000000000045FFFFFFFFFFFFFFFFC800000000000000001BFFFFFFFFFFFFFFFFF8000000000000000001", ptr: new(*big.Int), value: veryVeryBigInt},
 	{input: "10", ptr: new(big.Int), value: *big.NewInt(16)}, // non-pointer also works
 	{input: "C0", ptr: new(*big.Int), error: "rlp: expected input string or byte for *big.Int"},
-	{input: "820001", ptr: new(big.Int), error: "rlp: non-canonical integer (leading zero bytes) for *big.Int"},
-	{input: "8105", ptr: new(big.Int), error: "rlp: non-canonical size information for *big.Int"},
+	{input: "00", ptr: new(*big.Int), error: "rlp: non-canonical integer (leading zero bytes) for *big.Int"},
+	{input: "820001", ptr: new(*big.Int), error: "rlp: non-canonical integer (leading zero bytes) for *big.Int"},
+	{input: "8105", ptr: new(*big.Int), error: "rlp: non-canonical size information for *big.Int"},
 
 	// uint256
 	{input: "01", ptr: new(*uint256.Int), value: uint256.NewInt(1)},
@@ -479,6 +488,13 @@ var decodeTests = []decodeTest{
 		ptr:   new(recstruct),
 		value: recstruct{1, &recstruct{2, &recstruct{3, nil}}},
 	},
+	{
+		// This checks that empty big.Int works correctly in struct context. It's easy to
+		// miss the update of s.kind for this case, so it needs its own test.
+		input: "C58083343434",
+		ptr:   new(bigIntStruct),
+		value: bigIntStruct{new(big.Int), "444"},
+	},
 
 	// struct errors
 	{
diff --git a/rlp/encode_test.go b/rlp/encode_test.go
index f3bd5e02887a6ba5b1b9104b54f2423ed47c1ca2..722d8b6d82753586cb88741755b7270911acbe85 100644
--- a/rlp/encode_test.go
+++ b/rlp/encode_test.go
@@ -134,6 +134,14 @@ var encTests = []encTest{
 		val:    big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000")),
 		output: "A1010000000000000000000000000000000000000000000000000000000000000000",
 	},
+	{
+		val:    veryBigInt,
+		output: "89FFFFFFFFFFFFFFFFFF",
+	},
+	{
+		val:    veryVeryBigInt,
+		output: "B848FFFFFFFFFFFFFFFFF800000000000000001BFFFFFFFFFFFFFFFFC8000000000000000045FFFFFFFFFFFFFFFFC800000000000000001BFFFFFFFFFFFFFFFFF8000000000000000001",
+	},
 
 	// non-pointer big.Int
 	{val: *big.NewInt(0), output: "80"},
diff --git a/tests/block_test.go b/tests/block_test.go
index c04a4088a10ce0341ced88b4d17879362e446d55..ecc5c653c312b9e3454c579fab0f1f43a6bc2957 100644
--- a/tests/block_test.go
+++ b/tests/block_test.go
@@ -32,33 +32,8 @@ func TestBlockchain(t *testing.T) {
 
 	bt := new(testMatcher)
 	// General state tests are 'exported' as blockchain tests, but we can run them natively.
-	// For speedier CI-runs, the line below can be uncommented, so those are skipped.
-	// For now, in hardfork-times (Berlin), we run the tests both as StateTests and
-	// as blockchain tests, since the latter also covers things like receipt root
-	//bt.skipLoad(`^GeneralStateTests/`)
-
-	// Skip random failures due to selfish mining test
-	bt.skipLoad(`.*bcForgedTest/bcForkUncle\.json`)
-
-	// Slow tests
-	bt.slow(`.*bcExploitTest/DelegateCallSpam.json`)
-	bt.slow(`.*bcExploitTest/ShanghaiLove.json`)
-	bt.slow(`.*bcExploitTest/SuicideIssue.json`)
-	bt.slow(`.*/bcForkStressTest/`)
-	bt.slow(`.*/bcGasPricerTest/RPC_API_Test.json`)
-	bt.slow(`.*/bcWalletTest/`)
-
-	// Very slow test
-	bt.skipLoad(`.*/stTimeConsuming/.*`)
-
-	// test takes a lot for time and goes easily OOM because of sha3 calculation on a huge range,
-	// using 4.6 TGas
-	bt.skipLoad(`.*randomStatetest94.json.*`)
-
-	bt.fails(`(?m)^TestBlockchain/InvalidBlocks/bcInvalidHeaderTest/wrongReceiptTrie.json/wrongReceiptTrie_EIP150`, "No receipt validation before Byzantium")
-	bt.fails(`(?m)^TestBlockchain/InvalidBlocks/bcInvalidHeaderTest/wrongReceiptTrie.json/wrongReceiptTrie_EIP158`, "No receipt validation before Byzantium")
-	bt.fails(`(?m)^TestBlockchain/InvalidBlocks/bcInvalidHeaderTest/wrongReceiptTrie.json/wrongReceiptTrie_Frontier`, "No receipt validation before Byzantium")
-	bt.fails(`(?m)^TestBlockchain/InvalidBlocks/bcInvalidHeaderTest/wrongReceiptTrie.json/wrongReceiptTrie_Homestead`, "No receipt validation before Byzantium")
+	// For speedier CI-runs those are skipped.
+	bt.skipLoad(`^GeneralStateTests/`)
 
 	bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) {
 		// import pre accounts & construct test genesis block & state root
@@ -66,8 +41,4 @@ func TestBlockchain(t *testing.T) {
 			t.Error(err)
 		}
 	})
-
-	// There is also a LegacyTests folder, containing blockchain tests generated
-	// prior to Istanbul. However, they are all derived from GeneralStateTests,
-	// which run natively, so there's no reason to run them here.
 }
diff --git a/tests/init_test.go b/tests/init_test.go
index 547720a06fc3aab7206ad0062f475be58d86d47a..fdc478add74bc18a497cbec4d7ca7aad3eff0bf8 100644
--- a/tests/init_test.go
+++ b/tests/init_test.go
@@ -37,8 +37,6 @@ var (
 	baseDir            = filepath.Join(".", "testdata")
 	blockTestDir       = filepath.Join(baseDir, "BlockchainTests")
 	stateTestDir       = filepath.Join(baseDir, "GeneralStateTests")
-	legacyStateTestDir = filepath.Join(baseDir, "LegacyTests", "Constantinople", "GeneralStateTests")
-	vmTestDir          = filepath.Join(baseDir, "LegacyTests", "Constantinople", "VMTests")
 	transactionTestDir = filepath.Join(baseDir, "TransactionTests")
 	rlpTestDir         = filepath.Join(baseDir, "RLPTests")
 	difficultyTestDir  = filepath.Join(baseDir, "BasicTests")
diff --git a/tests/state_test.go b/tests/state_test.go
index 59ebaa88fb77581a772738436d108e6a5d9291f8..72d3c317d5009ce916ebcd59ff5dd22023f6637f 100644
--- a/tests/state_test.go
+++ b/tests/state_test.go
@@ -39,21 +39,10 @@ func TestState(t *testing.T) {
 	t.Parallel()
 
 	st := new(testMatcher)
-	// Long tests:
-	st.slow(`^stAttackTest/ContractCreationSpam`)
-	st.slow(`^stBadOpcode/badOpcodes`)
-	st.slow(`^stPreCompiledContracts/modexp`)
-	st.slow(`^stQuadraticComplexityTest/`)
-	st.slow(`^stStaticCall/static_Call50000`)
-	st.slow(`^stStaticCall/static_Return50000`)
-	st.slow(`^stSystemOperationsTest/CallRecursiveBomb`)
-	st.slow(`^stTransactionTest/Opcodes_TransactionInit`)
 
 	// Very time consuming
 	st.skipLoad(`^stTimeConsuming/`)
-
-	// Uses 1GB RAM per tested fork
-	st.skipLoad(`^stStaticCall/static_Call1MB`)
+	st.skipLoad(`.*vmPerformance/loop.*`)
 
 	// Broken tests:
 	st.skipLoad(`^stCreate2/create2collisionStorage.json`)
@@ -61,44 +50,33 @@ func TestState(t *testing.T) {
 	st.skipLoad(`^stSStoreTest/InitCollision.json`)
 	st.skipLoad(`^stEIP1559/typeTwoBerlin.json`)
 
-	// Expected failures:
-	//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test")
-	//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/3`, "bug in test")
-	//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/0`, "bug in test")
-	//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/3`, "bug in test")
-	//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/0`, "bug in test")
-	//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/3`, "bug in test")
+	// https://github.com/ethereum/tests/issues/1001
+	st.skipLoad(`^stTransactionTest/ValueOverflow.json`)
 
-	// For Istanbul, older tests were moved into LegacyTests
-	for _, dir := range []string{
-		stateTestDir,
-		legacyStateTestDir,
-	} {
-		st.walk(t, dir, func(t *testing.T, name string, test *StateTest) {
-			db := memdb.NewTestDB(t)
-			for _, subtest := range test.Subtests() {
-				subtest := subtest
-				key := fmt.Sprintf("%s/%d", subtest.Fork, subtest.Index)
-				t.Run(key, func(t *testing.T) {
-					withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error {
-						config, ok := Forks[subtest.Fork]
-						if !ok {
-							return UnsupportedForkError{subtest.Fork}
-						}
-						rules := config.Rules(1)
-						tx, err := db.BeginRw(context.Background())
-						if err != nil {
-							t.Fatal(err)
-						}
-						defer tx.Rollback()
-						_, err = test.Run(rules, tx, subtest, vmconfig)
-						tx.Rollback()
-						return st.checkFailure(t, err)
-					})
+	st.walk(t, stateTestDir, func(t *testing.T, name string, test *StateTest) {
+		db := memdb.NewTestDB(t)
+		for _, subtest := range test.Subtests() {
+			subtest := subtest
+			key := fmt.Sprintf("%s/%d", subtest.Fork, subtest.Index)
+			t.Run(key, func(t *testing.T) {
+				withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error {
+					config, ok := Forks[subtest.Fork]
+					if !ok {
+						return UnsupportedForkError{subtest.Fork}
+					}
+					rules := config.Rules(1)
+					tx, err := db.BeginRw(context.Background())
+					if err != nil {
+						t.Fatal(err)
+					}
+					defer tx.Rollback()
+					_, err = test.Run(rules, tx, subtest, vmconfig)
+					tx.Rollback()
+					return st.checkFailure(t, err)
 				})
-			}
-		})
-	}
+			})
+		}
+	})
 }
 
 // Transactions with gasLimit above this value will not get a VM trace on failure.
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index 4529bbfdfdd030c966d74ca6b675740b168a0b1b..ccfc363b8063b710bbff1cdc315ad7d55870b3c9 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -230,13 +230,6 @@ func (t *StateTest) RunNoVerify(rules params.Rules, tx kv.RwTx, subtest StateSub
 		statedb.RevertToSnapshot(snapshot)
 	}
 
-	// And _now_ get the state root
-	// Add 0-value mining reward. This only makes a difference in the cases
-	// where
-	// - the coinbase suicided, or
-	// - there are only 'bad' transactions, which aren't executed. In those cases,
-	//   the coinbase gets no txfee, so isn't created, and thus needs to be touched
-	statedb.AddBalance(block.Coinbase(), new(uint256.Int))
 	if err = statedb.FinalizeTx(evm.ChainRules, w); err != nil {
 		return nil, common.Hash{}, err
 	}
diff --git a/tests/testdata b/tests/testdata
index 52cb3b3e724d13943bd8a457ed70929f98b9b8bf..fbff6fee061ade2358280a8d6f98f67b4ae2b60e 160000
--- a/tests/testdata
+++ b/tests/testdata
@@ -1 +1 @@
-Subproject commit 52cb3b3e724d13943bd8a457ed70929f98b9b8bf
+Subproject commit fbff6fee061ade2358280a8d6f98f67b4ae2b60e
diff --git a/tests/transaction_test.go b/tests/transaction_test.go
index f4a2d2950083535586ebff1e80d250aa70df5f51..2d528b720e48237e0ad03b00e66f23f47819a536 100644
--- a/tests/transaction_test.go
+++ b/tests/transaction_test.go
@@ -26,25 +26,16 @@ func TestTransaction(t *testing.T) {
 	t.Parallel()
 
 	txt := new(testMatcher)
-	// These can't be parsed, invalid hex in RLP
-	txt.skipLoad("^ttWrongRLP/.*")
+
 	// We don't allow more than uint64 in gas amount
 	// This is a pseudo-consensus vulnerability, but not in practice
 	// because of the gas limit
 	txt.skipLoad("^ttGasLimit/TransactionWithGasLimitxPriceOverflow.json")
-	// We _do_ allow more than uint64 in gas price, as opposed to the tests
-	// This is also not a concern, as long as tx.Cost() uses big.Int for
-	// calculating the final cozt
-	txt.skipLoad(".*TransactionWithGasPriceOverflow.*")
 
 	// The nonce is too large for uint64. Not a concern, it means geth won't
 	// accept transactions at a certain point in the distant future
 	txt.skipLoad("^ttNonce/TransactionWithHighNonce256.json")
 
-	// The value is larger than uint64, which according to the test is invalid.
-	// Geth accepts it, which is not a consensus issue since we use big.Int's
-	// internally to calculate the cost
-	txt.skipLoad("^ttValue/TransactionWithHighValueOverflow.json")
 	txt.walk(t, transactionTestDir, func(t *testing.T, name string, test *TransactionTest) {
 		cfg := params.MainnetChainConfig
 		if err := txt.checkFailure(t, test.Run(cfg)); err != nil {
diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go
index 9c70b008cd6833196c0e6a289e5d675328d0207b..60e79cc5a0c2d633ac55557c758a1fe1e2d0c0e5 100644
--- a/tests/transaction_test_util.go
+++ b/tests/transaction_test_util.go
@@ -30,19 +30,27 @@ import (
 
 // TransactionTest checks RLP decoding and sender derivation of transactions.
 type TransactionTest struct {
-	RLP            hexutil.Bytes `json:"rlp"`
-	Byzantium      ttFork
-	Constantinople ttFork
-	Istanbul       ttFork
-	EIP150         ttFork
-	EIP158         ttFork
-	Frontier       ttFork
-	Homestead      ttFork
+	RLP   hexutil.Bytes `json:"txbytes"`
+	Forks ttForks       `json:"result"`
+}
+
+type ttForks struct {
+	Berlin            ttFork
+	Byzantium         ttFork
+	Constantinople    ttFork
+	ConstantinopleFix ttFork
+	EIP150            ttFork
+	EIP158            ttFork
+	Frontier          ttFork
+	Homestead         ttFork
+	Istanbul          ttFork
+	London            ttFork
 }
 
 type ttFork struct {
-	Sender common.UnprefixedAddress `json:"sender"`
-	Hash   common.UnprefixedHash    `json:"hash"`
+	Exception string         `json:"exception"`
+	Sender    common.Address `json:"sender"`
+	Hash      common.Hash    `json:"hash"`
 }
 
 func (tt *TransactionTest) Run(config *params.ChainConfig) error {
@@ -74,19 +82,22 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error {
 		isHomestead bool
 		isIstanbul  bool
 	}{
-		{"Frontier", types.MakeFrontierSigner(), tt.Frontier, false, false},
-		{"Homestead", types.LatestSignerForChainID(nil), tt.Homestead, true, false},
-		{"EIP150", types.LatestSignerForChainID(nil), tt.EIP150, true, false},
-		{"EIP158", types.LatestSignerForChainID(config.ChainID), tt.EIP158, true, false},
-		{"Byzantium", types.LatestSignerForChainID(config.ChainID), tt.Byzantium, true, false},
-		{"Constantinople", types.LatestSignerForChainID(config.ChainID), tt.Constantinople, true, false},
-		{"Istanbul", types.LatestSignerForChainID(config.ChainID), tt.Istanbul, true, true},
+		{"Frontier", types.MakeFrontierSigner(), tt.Forks.Frontier, false, false},
+		{"Homestead", types.LatestSignerForChainID(nil), tt.Forks.Homestead, true, false},
+		{"EIP150", types.LatestSignerForChainID(nil), tt.Forks.EIP150, true, false},
+		{"EIP158", types.LatestSignerForChainID(config.ChainID), tt.Forks.EIP158, true, false},
+		{"Byzantium", types.LatestSignerForChainID(config.ChainID), tt.Forks.Byzantium, true, false},
+		{"Constantinople", types.LatestSignerForChainID(config.ChainID), tt.Forks.Constantinople, true, false},
+		{"ConstantinopleFix", types.LatestSignerForChainID(config.ChainID), tt.Forks.ConstantinopleFix, true, false},
+		{"Istanbul", types.LatestSignerForChainID(config.ChainID), tt.Forks.Istanbul, true, true},
+		{"Berlin", types.LatestSignerForChainID(config.ChainID), tt.Forks.Berlin, true, true},
+		{"London", types.LatestSignerForChainID(config.ChainID), tt.Forks.London, true, true},
 	} {
 		sender, txhash, err := validateTx(tt.RLP, *testcase.signer, testcase.isHomestead, testcase.isIstanbul)
 
-		if testcase.fork.Sender == (common.UnprefixedAddress{}) {
+		if testcase.fork.Exception != "" {
 			if err == nil {
-				return fmt.Errorf("expected error, got none (address %v)[%v]", sender.String(), testcase.name)
+				return fmt.Errorf("expected error %v, got none [%v]", testcase.fork.Exception, testcase.name)
 			}
 			continue
 		}
diff --git a/tests/vm_test.go b/tests/vm_test.go
deleted file mode 100644
index 55768bcf71c9b744cca8af098b6f93d57e6bb665..0000000000000000000000000000000000000000
--- a/tests/vm_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package tests
-
-import (
-	"context"
-	"testing"
-
-	"github.com/ledgerwatch/erigon-lib/kv/memdb"
-	"github.com/ledgerwatch/erigon/core/vm"
-	"github.com/ledgerwatch/log/v3"
-)
-
-func TestVM(t *testing.T) {
-	defer log.Root().SetHandler(log.Root().GetHandler())
-	log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StderrHandler))
-	t.Parallel()
-	vmt := new(testMatcher)
-	vmt.slow("^vmPerformance")
-	vmt.fails("^vmSystemOperationsTest.json/createNameRegistrator$", "fails without parallel execution")
-
-	db := memdb.NewTestDB(t)
-
-	vmt.walk(t, vmTestDir, func(t *testing.T, name string, test *VMTest) {
-		withTrace(t, test.json.Exec.GasLimit, func(vmconfig vm.Config) error {
-			tx, err := db.BeginRw(context.Background())
-			if err != nil {
-				t.Fatal(err)
-			}
-			defer tx.Rollback()
-			return vmt.checkFailure(t, test.Run(tx, vmconfig, 0))
-		})
-	})
-}